From 83192e246294e233b1a09f222c56c1387181bf73 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:48:10 -0400 Subject: [PATCH 01/61] docs: restore missing AI agent images to fix 404 errors (#18780) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #18767 This PR restores the missing `landing.png` and `duplicate.png` images that were accidentally deleted in commit b26c9e24320c7207717772f206999263223d8c8c. ## Problem The images were deleted during a documentation restructure, but external links and cached website content are still referencing these image URLs, causing 404 errors: - `https://raw.githubusercontent.com/coder/coder/main/docs/images/guides/ai-agents/landing.png` - `https://raw.githubusercontent.com/coder/coder/main/docs/images/guides/ai-agents/duplicate.png` ## Solution Restore the original images from the git history to maintain backward compatibility for external references while preserving the current documentation structure. ## Testing ✅ Verified images are restored to correct location ✅ Confirmed file sizes match original images ✅ No conflicts with current documentation structure Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> Co-authored-by: kylecarbs <7122116+kylecarbs@users.noreply.github.com> --- docs/images/guides/ai-agents/duplicate.png | Bin 0 -> 203140 bytes docs/images/guides/ai-agents/landing.png | Bin 0 -> 178952 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/guides/ai-agents/duplicate.png create mode 100644 docs/images/guides/ai-agents/landing.png diff --git a/docs/images/guides/ai-agents/duplicate.png b/docs/images/guides/ai-agents/duplicate.png new file mode 100644 index 0000000000000000000000000000000000000000..0122671424792d95f391f76621692915f9be6ddd GIT binary patch literal 203140 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%0Dc)2^jMPtp9BRQ#Yrgm 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

UhAprwJoZ6-QKC_8jZ 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 F{~rt&j1&L> literal 0 HcmV?d00001 diff --git a/docs/images/guides/ai-agents/landing.png b/docs/images/guides/ai-agents/landing.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c09a4f222c7415867f27a85e1f021be3788890 GIT binary patch literal 178952 zcmeFZbz7C~`Yk*WP(cX=Q5uy_X=xBa0j0Ye>266;6aCd@zYWI7oGCa zbn%lT@6XkL)@a2QWO6dKksf>ckyYPpd++g;Cnks>IyruJeqK0zsyr$RWhvgZmm)P) zAMw}+`^D}5`5$TF?*bJ!{^O~?uQ;%6{7LtpuY{-B(LZV2`|oEnWu9&L{nxuQ3Ya)JE#_fyF5PFura$~zPyUw~zLlZ@+ zaqB;~9|`e|TtY?VOSA4nT-?x5+=z&X>lK1xGBXY}Sy^#K#ggRYi}g`@uf!Kk#Jf2h z5Bizv9r>3rYB&*=L1(62<5$Hx{}ntY_g)7NSJ-DKC;yq6iY3*EzA6`k2QH!)dt;PiwpYx zetv6Hk9tjPGcWI7)Y)q0yCUx#y^B4I-_#;m$`JjZp*fU#`w!>Ys9kDmsxm#tCy$q* zF)@w0ztU1uO=j=*n(Y5ry??P|%lM}ni6Jqo7SZ2(wC(xdo3paqVv#{+oJ2Vyqw=-$ zaTqyT0nLZ+3`7)(C@K^N?amhwS`sM&5w(_17ow`F>4}MnXzNFvbkx+}!oz788S@MX z;dZkoB>L|6lv5wyEc%*tb>k)PWG(W4rJ)Jg4|mmprw6Y^+W$PnM`cdv$g9e2qe<#O z5vb6d#d<7SfJ@%Ywm^P>`{0%edVz!=BPE{i4uN!NYAShPMRr7Ru&%T7=|pLL;Y3bW zH44LAtiO$=U}xqUlVDTfB~RUd=BFFgOFr8HS=`|l==pxrl3w#OXyoJ0jv;;t8Jy{v z2?Pq1)V!0F0m2jh$r#G zh6{%gJlM_uCVI8&wMKrH@WF}U-+|xP`&v^|=IvVz z$-KuOy!Q5O1w5``gD!>9^S^|C2yAGu7|)nTZy;pJ*?*{b!CQUeTw%tPw>DG5<-t#L z#Us{4yiUme>aI7Li3xX0;hEcQEpI&g9@BEp#E%Mx52eq?uijn+>L@|@I6DWHm7xeu zCs3n%-k@HNSXf#L3)NO#OP9~Tv&-by%hYV@_3!I)e?mYIO-q|A;Qq$>cq>3qS|;C3 zEEs|&CpR}HD(Y%iZ_SahijpOT=QY;o+u1YEgjluwr&s*w4bB$}>We?(ZmaAj7g~DQ z*~5FfVbyAkDQIeXG0;RPNaBUq;HvrQOMIi}sDE-hvFWupIpVbhc7KIB7dH_^uor`qobpPO#NLf`0rR}NT{kx z_7h((D;q0daYuG|c$=1mwHEI45rG3eJ$()veX+`&e=X~Q)$~`spiWjl0;|5+TLN61 zdcAtXY_B2pDEOY{E+-H=MK9CRHMZMvdOpTt2E}Qd>B1A;Yud_`;T>Nr{bC>R0XlQU)7y}d}I=XDBt_O(B zf`WqN9T`y-{OkEvTz2-uZ55~Du}xfDJco0a1=JRG z5t(?IgTuBvA3sjR)9!W}u(a%zOBj_$Yr};~`SIN@pIyF3EH8wicZga0=_85VCl|s- zX=Y;RJyHK2x2Qec{Vki{JrU!3gj{%-P+0hF&-(}wBvh1osr$6buUw|MTx9c1O3dA;Q4uCe^s(og}PKY)pfZryZvTrH+}$HbbK z+aMvZajGGCo@&`JA#lFT@yyHqTSNpYr$tVFesBGUTMnBO%tk$CdV2Gu%A`K-6!Gz$ z!O=b*aqF-RpKF>;K{}5xO&u z5<@{I=1u06Op9)lIi>DRMxL7brZV#DBi_W!vdj?c^OaY@tq6%sf0i9F=D{=NG5@LqjfI-=**9>FE&@$ElTC?4G`t3HRXS=60c=XigCD$T1+a zw%)C(x@aLv%gIp}&)VwG3k(co&lP|3=BvNI=^J8`q`bVDT(#1#U%&cdk+R&ex3l{i z5MXOlkdnN`d}p%AcrZ;OLR`(St*Pmyn%a4L2vq{Vn@P0G(|>x;+gHNEgI!%Op8t+c zNQejzKRdCub9dLQ_FEgyrV_%|(V1(wbAGr^_4u*%<(d85M@7Z(fdQ7sj~^fA=GM6T z!dlK&ITuz{Rn?qdDObB56Yx0XWMmjUB~*JyOG}G~hu1wck(icN?64UPms#UHxUsL! z{rvfkQOMauLqNu|4G9y)vuD_dGWEQ| zeJ6ACynq0Vpw{_ar+fEg4rqN4b-k8Bg@yY*Xg$O{4p;s5r*E5^tCNxQU~`X-Fa;{O zyYU>-^zsnjV!KQqGb?$MA#Ni{cMJ}pO)fS!B9o9s5(?K3LBEc3{vB;i}oEweQi=a|nI+Hbl)%~vZuf_;c! z(n`{jjOR68>cTglTr)5*K(kaF+}r*@F7_Zyk(9qG-+=J!#ph_XvH)g-^)A11Mkk!Z zYb9yK%ec`e&z>cwE4Ut?IXmZK|G-pmaw;=5Ha-jS~dtIKBQ%OmwbbpzN?Y9QmKQYnW+SN7C z)pg?vqZki&p|hi-*f_;lTYD%yU@3;vnwc5vB~y2Iw|SlC6*qUq8z$Qa55n#|>_PHO zGr*d2AAS`?;(X1YgruWHMU?>`W@2m|L+*6S_ZA|r?OVN3Z+x{YXVGq2ROF*uH*d0) z6(`A_4|^gZpB-%$T1=k>2j53L;ZMW89(v5~)A7LU^VR|kUq%%5@_omB;*XF~QLHbH zd3-g7hlT=41q^liFNc04K7AGV@|B0F*U-QK1Z@|jWpZr#-x2r8@4UuqHq2OF zaR1_R!h2+IZ7ri?!674a6IVortgVMU%>a$Y7=efFL;dRoXQ}bQJ0&P6)0K{K0v=wc zJcpW1|6FdksJxKt2wi(MEU&%AxTh1Mn-m8 zT3B%K3#Oui0u%(Sg01a71V;ZI1_lNsGB&oH`Y@q?nvZI9lJG0zckh;#mo>_5Y6j{Q zp}_OI-HePIZG1HcYCQz}lKuSrZekME`DpMsY-FaV zJ1n&Ir@PV#cu`1%lW^Ijis|MBDE+w1a&@%D!g3@fCFSO|{asg&MH<}D@DqQ*sM#Vz zkX9T|K+3X4`0o1r@5*-=`votgcj*}&YJx@^$Edok%SJk~kX^?3ovv1Rd^G$MGU&dp z)LCRmUtOJxO#h7}Lql$Zjv@btOlV9}Vq)VpmqCe%gSW6qo;z%;e0wasPQ+d8QhZ$H zY}?$_v=X6J^IoOQYPZ;Q6j9gFVYAYgwA>TtadBeJTK#=HsB^KUg@4(moS(m@rbf*t zf`=#QcyF)h*Dq_w1Y&%A6<4kh%C`qQRz{lWDBfjdWeV9<+f(I}KmC4WWihH2J)@*d z*NM|>2_hZ+A(x?g6F13acTW`)5f~_ZadG72%#g1%Hr&;fv-a~>S=n=mPLj7O&1u0~5%46VKLPwzZqmsvHi`^HLzJUlvVdiM3 z^vd$IaW`CA_Ri^*SD~Rur1nep^tRz|W{#uviuD`$k z@!IfUU0veZmKn!nQ&TGB7o~+KHNm|ggzJ-7nhZl^|@76TAH4gHYf9)w;6BRNJzoNq_-gA zhTna}j{#BLU@5mdIz7CXbOJm)zA8_qa7yGdB%zBb6ym`Z4UT%ZcQH~>EUv6jQ?()? z)Fx+;Z{E#Z?fd>+2GLh)sdbhHVfOud|M@Z6-+z;)zh`9~OioU&bi6)i=$x~HswKA? zo1LA_!_7_bXhlLy41!e8!b0=#^PfL|;3DBsP{6`IOo|vYD}lQUB2h#nW@Sxe1eq6e z-V_U_q@?_C6QiIc?@Dc^si|qA!ndrJi6K!pMZEbShDCmSJo|@Gz%n~k#Ylm~f1M8#tt5oU)mrdP1 zhI6wSW)u_@a|817@vkQSa zZ;@}WS8a64PL`jR{%hq-w*)<;y0zgMJiO`YsdNRuau!)RIq0?LS8fgA3^m0M*=?7; zHv2#P==@BB8gCsRH&~M&)u?o^EuUx&B$ksi{T-K>nfZHeu7{0hGy>AV z*S9h>)UMItRYT;xJYJICR--!+orecG$G`ibIC1e*KD!QQIyMW;QVb3W8LYh)Qi)Q z+mfmf^ZA<1q9P*dWmZ?4lP7={fHXN=9i)2pOz_2vhM5`uXV0`3+P)`~TAUpii-~L7cIiVhlmgH{+5Zr(imd(9yN>Qzp2m*=I-%t4V< zc_e%}H;|E+dK0eC4m(Xp^B7eMGS}_}k?;{cdi3nwH(?gqh9Q{-t> zF2Ns1FlxLJKeJkTgT3E{jM&;Lgndj-ej*vi?R@F7vpIQvTi`SYAO!^l7cK3dv%}v_ zO(=6Q;xaP32di?%#x(Fg0e*h3Upp;t@YckSqWm9{u}|s^!2i0smHAfrx$ilKhT+1# zfx4Q|iKnYw?;zg1Wmt*twilO>@DB=l82D3FMTO7p?4Ug)qf3qhaj>FuxY+rSyII~B zb5r<*MZeVemoM8-pEmM1UU94v#JzHyYd}Rq+h)|Pdgib(mi3DF{Yf7n--U%5)EyHO z?W7p#PZ)&JkYg6^mdEJThbau5KS$0MC_xEG{nb%6-!m)$jwY6Ezr5{1n=W{(` z1iB`b#}Nky=MxsG;-=}BVX^+x1OZ&_j05*~>f_@$Gm{+|3>f4Qv6}!~ zU7Ey0f%mT?*^HBGYZJ29hfHQAGbH0y_TQiGrD2iYr+Q?4 z))szJ9*4WtCNov#zL>!RVwPKb(&?j9;}19XRv5U#zr!e|rD^%ygCW zQ(j&+jw7z=v4OqAwc(KV`mslUC_B>7o*0x5j`Zz0Xt`KjVwwl6oj>`UoS3<@)!4>f z`JQcfbX9<%Dx5)0e7oTNDa#yl8N;h#xwrE+5F06B85AsaD5+6=q~aczMmih!W+dLLZ)z zGXJMp0=P4+DyPRCb4|?@sc8l_w(D^^&pkdHeOix?Mf12(f5V%8i=V$Tj^Q>nwsc27 zm9ocn3X0&hsVcPC{iW^ze}A;G>A+ z8C~zh1OZ}2rXK*SQBUmFMDhCOWa(dE4^0(92O4%t<=1}EKqBk)kxee!CCzf1;(@sm z%h{!s6{q=@00`6}Sr0>3*ifa>AF$H9N1B&&!okqi^S4Xun^Hsr4h|2+#Lu2t{~2=IAoj>Qt+jtDBZJ|}R%b2dN=MoW&m6fhe zuKA4g^cU;-0;b!a|Iw#blm?PMJVpR7G+LtqjL*9j1}?6^nwm^xO~}y-yVVz1`a{F! z+1Zmvz?nfoMn^{n6m`G>B&dwc@$Xp&thaBwVZJAP^r$4+s349mYcVQ*z`5Bb!E>;(MyrL$9Jc{bdhq+z)#B~`#wC~`c^tPgqi64!y!)U# zQc+%RF;ylbm46ALLE|@3<*XO?Fw^8*q0}PXjt=fNqI39%L;mi3>vXy8XkVXG)93F1 zT>SAEQU|NP`1?aNz0uTkzq9K%*8%xb#aU59E0F!0xI=`QoZx4wA3+T!!c z$;t2J&hsr8XB7U;(QL-S{+%z~+!`Ty-o1P0_wZ^;Oyb5ISy}1WWftL}Nj${eiIRk67QOu!+qNFWanJR; zFqsm*J&g!`fNQEnLGzfo*Wgo9y!&PhlBaO*)$V9AC({lImv-Bsn~`FVIve~pr%%a` zx`Tho-`Ia>GEHQOzh{-(xeaSu=pH8nNDGdMWd z*Y`YCjPc&RIml;V0bjimh~%;rWsUU|h2gmSVt;pB)|_&#uCA`Ft!<)lco@VgRK(ex zw@Rg(A8s9cd*6WMK5iwQB<1rX;V`4F9)~vC&?wAlIiqiBS!zB1DKqo+9sjMC7D@;l z6a>HopbT6_#=2uT`P_+wTW7+VwD1UAG9aIJw#Va{_0B%tS&pDrF|)8(`orQCXj@rc z&dn8&_2ZL(A5f42wR{Rs$JH4lYAiio=lb;9UP?y(?pm|~=E&{+dt&12^WS}qi9jU* z)(;2>C@i$KvRX8Je=mS!^I++1Z0$Awt5>b~tm(7Wge>kC&k@+SQQ*d5Zq+G?<#&tr z^>q~!V;;IFNA{$VqYNVCJenw`)6|SV@Qu^Ffl%1?Q?=*}&k=KZ$o_@$P9+QT=)%H6 z6swW(XxfiJH7(rs8)RPOw}Z*OWWzpbZmI=wvOap(m!9ywM{vG`Z^BrOuw+zD!IQjptLHZAjK^1( zx1*qM9t=8ZDFqSek}spV{1T3W7FZT-y5++5=;#522aYj?2H&#c$7w6M?>&qw%|Ee4e|gh~oZODvbI!`9U4hnrkIk<8gZmOOtRDfu0j zfWTp0F(9N*-_Wqe#4AsEo|_yr9a;R%m4T>g5DPL{%2kHxbX+ zH$}IfL!p6;(P9%5y!gqYi|4GK+$RKmSSPA1De8n#Pa zVc)(*@;FKkYOwuZra?7^Bl`5znN%Qsq}%|+7{t4GpQ9&e+1TXO)u%>A@DM9v9#A@= z33dZN!tZv5@PuZFii+yu(op|_7~}5Ua7GOWpxfZKQBh)HNfl!_%qb=9bkKQWJz4@{ z?&AnFwbpuhBov_DsK2_r(rfv8ba0TIP?I!r6K}!``Ih6>RP+3*wBzXDe3HR_Gp#+Wwa)b z>B!exSjkjxqlt(wcOW|FTexankK^%ERB%858WSW7$i+-e3ID}c=UGfbpCRUR zVPjx0zrI4wR&*W>9daD|nZ(V_-5Jgx;BxRzT->kr`byyX!vBQRG%h%Jpv+ni8ruu4 zEg;Oed3cr~8lzYV5%AeJ5JyK22yHX792fvr`sTK#8CJf8n3-3Rv`+7^G7{?SEiYok&blXQJLz)TTzbN z?TUCF~0AR{M-6Q~b@b48`=J7a68 z4|Z!qA4x8!l0FE{)?BW8=te7P|E3`c;?(gjv|0!YET0$~J2^4?VKBS>Azm39!R@fI zvBj_EG@wNg)N1RPu(|TwC(k@i?z*A2{0#pTd*-DgPn&$6(Q=cVl2E3~X`Wb9t^j`Dk^8 z06(&=gO-*qi#=T5c__}uL*wB^EeZ((w1_h4JY#Y6$h3*cvD1YbaQad9!wu&~SngM+Ki zMyrAw&_JVfq4r`T8k}8cs=hqrXS}?4X0y-+`~$zsLEHFvRPXX&_F9gI?w?zR6Gt#- ze*4B_#u1Yz?BL*_{rg8zQ4vs{FpvrwO(az!4_Yp)4jS$5&YA$y=Q9~vv0ooS7TlgG zL69*rN+w8Edyizh*?;CXp}c0d#NHVbMmt_bR_TgaZp#rE#*^~I+3U0YZrFZZ2zT_jYYv{;=U z$Q?oZg&C#Lc+k+}`m!ral|cDj!)fD-7hCTy&%z|#=&^5W*1SJm?2G`isl4pX*spmh zH8nNErrfkN5xaxNg9AH5E%-~d5;If;GytfoK0YYv(=9zcTaCU=fyC>tsSp2%2(&#uWlTB$v+>k$zGyiZ7VEiK#vwPepv zxC@Uu!m`=fxm8qEE)3Nnt4XR|xna|wL^Ov(h8G%;(R$C|Q zJ|;Ydg*1NBBnXXpM*bsKO??A=Olu@D-- z1{oTr3zF^ZPagjkIsk5Dg$;qg#>W@IYJ4j$4ueZ!S=q@-za)lxMz@d?n-zmo6)t0h znw+M(4)C0{w#!FxJf(Vi36o>W*O$k$0DRe=^_BiyaR<>1)L(?4nc2qCrbk<6=it*6 zbo4#Yt3(3`+6@c$_x4%>Z28}xSPch*r347OnM%h5fFa0&78Z;mG6V$I(=#y2@!Hc; zGv&|drPT;<8`2OtL*)VG=_Q&D2Pb#hvxv@sfZW`txB1K>+6B}r?>+ql((kkD6)Vq( zQFOiez~gNJgy-Jg9w-C$_UwQ0F67D3&`_%7ePF)C#lWNS~kkI3_$gr*rsz#5aAh zU;IW(q3Ewg@Fk6P=FYKx)aiDLx3vXJ-@L(Je=`%2^~+ibDluZL=!cCiApV*@fw6He zfKe6;ZTCPH8Y{CFhEiYAny})V=)p6<$2R}x4-v6%j!K~msCWSKTmcr3{nCRO^9BNh z7Eq<@>N>{ru00Yyo>gn1qBa*5-JC(osghbukQI`<(Ud9}Cb6({8$hHfO-*fr#p~(2-I#lQ3;3*7>JCu|LMZc#FX1!%}p2C#m+QhJ7R9fB%y674XKIwO8f{L1pDK zkSf3j7#60Wu1-YUEU&28)7zVkn+7g}`|cg-S*FX@HUtW)swM^o6jeXNZ{iUQ{uDkx zWA}IOiUU;4er|FS58aFL^B@0uhTfTr;kiE03hzfUn;6;mKyb+sIb^tQF(&QP$jhFGK{dqQD{QNgfqoXWdJWu6Fjbd$S;aNu=om)p1r_F^`)pNi;Uj`x~hi8r;!l{i90SS)Z&8oboHyB z7Y4AQ2^WZtEfnuQqJ}KsFv&uAR9u^DZUs_x4~z( z_^a&$MfR^6I3gkxP`Mz^d*gUWVP-N%SUDyvZt+Vvv2s_|!EGB@Sk&0BhXaBEP6t+I zvc%j~Qj#5`aA|1?=)Iznk~yn|llS~0G7Yn12k){IP>G!n_a}v~&(_BW(-)i6jSn=0 zjMngao^@G4G2GjOE}G+DuJDjalN(yY{vOB&h&}+25RJedcm^gueDHv|`UyZ!evsQ_ zQbd8MaRedhh8G#xZ}OqD@)RCzg|}`pxf7P1c+~$}-u_ZTNkw%%b|yIZQ6mHcBVhiI zX1~DXB$f%(83k!PI6o<{g0B$>`$H_**LneiV#nw{U{KQOOnuL8D zn==QFA%%r1`WxuVK8a|_9(Goyb%;uEVJTMDFZU)Gbw!rH>rd{9;{k;K{>TgqR!*fb zD@rhwF$<);Fuy-G#gHJ8)&b1S%)+1UDkvyyf~f)+Jq|PFgpd%|i<8})oSdntspzHQ zcOVGi2`tM9k&=Fm@z~gfPnCyo6gQohWQYnLfa|iedR11DWF{*Mq zAAzQ|(%*P=^Z{<`9e?)VhbjOUIoqfWgeB-uH$w;|`RH!Z)_*9%*SM=pe zA0S$6ZU35&e*S#sqNA)l_NUpu!jW?uZd+O!yLty^eWE~KvEYWJ=TM7D@&kF(BGOYAo%*kOFq3m+Y-dy%goCkHv~H4e%91(WG&C|AWm8#=V8ZX~d$lo`(F<&hsFc)bLxXO;H!9p8Gv~G@dkvinVd%4pFQU)K z^PwOBhoo*|k_AJ`*ROAM=1LitU?2<*9yT%pnk37v95y}*pL#Vt3`$qjlm;R(Il1A$ z?fQJX7Vxy5PXBaQm)T;60s@CMNttL^R9zPOHA;8v1`pyNnUVH!2;*EwY{FB zzA9@Sn5l9X-#y2vjq6&es8vMYVn_A8OXAUuBZmAF z4q8E{mz4g^SyG3Dd6{L(;LN$|f5{Eo(l+lB|>17JpI0v9mz#t9ku1M*2 zf0B@4x)@^w9Z@R_GjmdHiV2I=Z$bWAHa51q2xv+0L&E1`x6)S+&Mqa4O1y^;!EONv zf(0Y&;M-pd03_oQ1=y_c5i3zNYJs0`f2TCx93Lcjd8g9FHNVDrKRqjJErg2s!!4|% zBh8SI5aC-dq3(FhHHgdwtg;~h$U1I}jYHLyi0Hw@JOUzPq^~cMd$?G(9ehfF-P=1m zp#Z79c%iF4weEVH{L&+X0UO8paBmOA6Yqg-TK{(?ru+`uz5$n`B0N5@xj<;zC1Zjq z1L{rRu=)BnOzW4oz=)|?Xjoi+TFRD|58dNvBkIG4YS_%#8n?!VhSgpthJ;F&>Pjdv z;WT8wQ~f(p%*{8uW8AYsdHg+@eR5iF2Z zS*;FG9PnbRGdlJse}q8{74;)90l>N70r^qm#^b{3C0J*8eH_swa6NSc0ZLJWhxO5_ zo+;23_jYp|Rgbr(p-A0AKzjo)7|T73fmm7n4wNJ~%FmClnY>&lOStdgby->^0H_z? zuPw^Vd`$D*mL~w=7u>$UNm054<^u=RGl{WbEvabRqnc2c*094*RL+a|FPzZChN;3E$uM z!66~ZOHT)VgjhvPk`+G&_xEPN^`^85?nC8ZCe7at@9X;s>bS+^5kt)TP0-9i zjsT@%P@vRgxTC&4sj4cr=WTvg))Va8c#P_AJhU9whQ5sZ^Bc!;+pkTXs-1*4&VkH7 zTfWbPC~hY(j$LV#g_`<)5xDddfGE9cE-y ztq@;0)fWH;P=tUbg!3A#SVQ;jeTR|NPHz~m6Sl^xO%Oh7^eGoF z?+Y^QzRhQB`1pT)K+Lw9q9W50QZQ4xRm8?l!61i3M!paj74-wKoW6eQ=f)52I0jX` z%otqvIJe9#F1NNHSstgs09EYx42N%t)~s2JaMId-Su#?xmY$YIQ9)McW|jkMj-lsE z+p^=0$Nu`=kNBe8#ex?eov&ql%8iTsq>i6YqU91`eQZIEc!u+0@KiF2yb=6yZ_eaE zfgBm(TNzo328-z2!73T%a&5k&i;L13t0qlx9l$eXdc2TSB?X0I@THUTlc%M-uN&!^ zPR7u5v>W3hs$32URD;{vsG)@MHoj9(X9S^IrRmBs9M~l|lz#RzZIL z_)&!YP&$cS+plgrD6ncEB(v);FYv&R%VyXyQiHG^}?1Gy>3028TRgQKG(J4+sG>tBGm4!5RVK>+yj1&xuB zQB+ja%Aef|;2MbhVb|YRNYjJ778C{zQt8Z+*JA2v{GYXYkZ;H2*r>K^O!X z7-xVO2RAP*9UZIXjJjX)%3RoJ9%^fA>-O00a*f*+R9_&ORBPRH!S}N>^zg7@j+(7~d za!ABC0fw|rU`Io~e~;pI4o;aTqJaF7I4raw025YI@0va$of zQ;P;U_yyLG;@U+w>jLi1e}$C|JT&tMmw!$tUhXX{Jcpw+VV{11ucx_**J*#LxTXfE zBq{-c-mb3u2!0PqoazODF9!PhU-4O&fJy3Nv%lf>`|9!>jLkr#Ic~e(sT|lOfh*S# z6FY4QAS@}VuCA&A{`{pGX#$U(PeTn+t40LNy8GJLW@~G9N#Fgsm+2^-HtZ zWDyj&-dHY-Ye~{d^T}{<3nzhR((R0mkB^V?Ybp2_Ag`c8O_pA7gKG}@IULJ~s;6*w zKR?=<2IKA(9O(l22#RY@f`H{L|F!98R{Nu_pM`~l9A=T>;UmDNL18Zf>q$-yJ-1%c z&xy%IlY6AsORy@CF7vyxKx66Z>6z;vTpw3a8kR|c1sEs+PR`Md zjlcFiD7y)qmU-UZ4bYmR?gI*H2_)W!gm8Jc0Tcag@0H2Y-o3^6aR%+vtkLGK&*Y+`@rk%^j8>GIq61>70PYp+?cUy! zgVqrslA6>a!`>l0d*oC@pz6?TR4jm^ceJ^Gy|*Y)>+Uu^r9KF>Cr9t!W3rE)X$wLG zNcXL}onL^Fsla)^1(SG!ih=^Rf`*RnPSA@GkihmQZNWnUCQ zrYnkx0^c8R;Q=oO_8ZWw0QtHfZ&fEH2|Ma{5i7fCHK!Z0nV?U?mzrXd2w*mIPG5eVu`_QiTJ&?R$(zc0q`mbC-bDc?H722O6pqtuT&3ISU}-N`@mZ5VT>K4{_}# zCczhLYys=hm4IRIzGWh_nwPm)V%Bwj=Ek<0bCpTS|dFsx$|0z4^;?AF+^hyRE6!i_=1A&DOTIhlkS*`90A;ARkH37{fEp@5}w-Ti}FEd*N&-TZA73l|H^MN2>}k6j-Oe(0AE+L!lX zoOM37$Sgh1Qp(rujpys0vx<#v`8;r(L>o*FT-mDp3yjB^+8{FsNP7}3sOj(C83 zI}=^(6zF+$1pIwGdncbjt@e>w5RAQFNjB{uPF(!Fp&m%ZaA>Hiy3F#|!fzsDViKO; z`@O~;Fk=m<9V#3QoX#$cO0roDDQ%EDU}6$8yv>4`s&o`!VoD(UoSAujwF1r{J3FHL zxOOhT>%8FRY#c~D0Bhdz6?)Qx@hvQj-N277q4#>f_u3wc?a>)>9l&1jByoUf_BMv2 z#5Cg}KK|nBsz|2i=}}S5 ztwBF_cMl2Y?6zmzAilXZaGpMSA`4Ea{**_Q1EQs_Q#HhU;8&Qb2{_)LgmXhUuIEB; zewH`@t+pD%ijk4uK8r4HaC>9i7KCNVD3-N*7#T+8E< z2`s&^Do%lFnFH?jOI_o@x`9h5p2snLz~_}cfq=Vr>G2u}{Pgq{%gf7BQGZki$#TIf z53W*KToC?xpvStnx`M7P{#>-uX*U>rAV4$8ej5Gqj~Czp;rT_wM_c$KNd15>UvxOi z?AP&bcRO_~@00R=PN!a*DAqoqFq_#JtUFb|t{qtEm5qB@9Ts;D_#w2(@cLZ*>*qPb!W;t*o~fw-aS6j)Nn1_0SYIOi0jGY$3h-QR8sMF*H<5Q z=c)QM=qz9?+x?RU)c5)MHY*2*q?DASy*(W*t&L+sv4OuOD3_Q-&z*LDKTavrJn-JL@y@d9o5vg)p{IWMzP)qQY&7ux?Gusaa?s|S zxza=~Orubp7Z+3Ea0t@vj)@nBCbapxasdV7W{|uT6b2Ou={vMA?cTZL58XU^$s_mW zt5?2~tI|-UfQ!lU@C4WnrL?8Bm4cjHaau!BG2Qiei@e?M>sNge$u*F~Wwd5j#tR?u z*PdzmHmuxv+|f67-`qczUt%Fm*-zb#mM(YU#O%ps?Fzl`(^>M-8;HAi4-O9|ppOAm z6?fwDZTwYG0JBDg<95x?XDI}k7#zfdBl*92%9Ymr8|NaUqFP#Na_scjax$|Hm#r3L zWt|{Vi%PbPb#;?-b2a4UUmFqY0BZ$jZ6tuXr=giC3UA-ORgjk_5pY*`%@%Q+OmwG*X)`o*q1yFQF?TP|0U3Hcm`kux z?g6SaXL7K%wgwOmu;ku(8Rr9UGBBv?>6*lfW@!Qw>EmxQ(vY22HOavgsFGm5(o??+I~Hv&FOJ5>#`+o=pFT-m5%LAk z7B9*6LVMlBKAB$+I9J}j&8@29Wnqy$X@cWWm5xl_WLwjfTCRh98ZX{H_S{Y!pm?{( zQ(kXU%bA#@5D?&oi8#nqBneucFZ|d!oNRfQBA}svL@cBDGf{NRVh=iH>Ua zaKcwPI5;gB&cT<9B=ARsg?oE@f32EILDAF~b$9;gnMixv3xV=rVuvF4%L}*K`w9x| zTwLW%O^)`KstG^o5TPX;-u$fNSds<7v;qh=ow38xCqxdH{r3Ny|2r^cVJ&21Eo|%U zb^SNVo04w{Vigi1DXDagXQ&uew;}IIV2a2Sli{r4FF38+)0NBf^PS84NZLSs!esh3 zZmok{{zBzKS4ZiGyZVpsn>7~?rpaGjsC*-L)>+pupHMM$v?_ zF-L?cb=Z5W`Qgk%-yysJi$HA!IPhI+w#&}K;&Qy@W@l#yOd>=(q))Lu7Gei#ym6OH zAzaM<62rR&-58n;^jS(P;@QFs3|1Ygpw<+s4s$1a50P56u`rUYH@!lgK1!>V%|H|( z78V~6%55eLVWCyB{CXW-bPz5 zwhI?TICJ4QqvpugC}tmJnGhJ8Sqq7LO!aQKRLX~WP38d%g3`ErzvvEgi4Lyy_22ij zVHeBYcYC~I?65wi{N$1yr90mO14(f1--qZ`6C)#Up`tpcr{ftK;@MrWgO@;9I7BlB zNUr0p+$EA_KX((DQvqy%)s;xVeG0%DSh**P2f;4U&J=QZysSXf5JHgpbW);{?4q^w z*qsv;m%ZH&&Wxx7-3@kk^9KiHCyV;!yE9|c?Y}bv zhAR=7M$TDhsF*5O0(_H-zl(zKCUgHS9bQx<4{q@UX6i%M5q$Op)va4q3N-@4!t?MA z2Z-NIUpz@Q9(pcGuuQRtiHo;WXB&9G;reON(dnWPI`)E#^tM+hd6DUHdgjXIsF{ii zzJfv8iN2;fjf_wMwO=CQHhR;K`)SvD+dcCsSzF+}v)%3@4~a6<$AA5LEW#TFJ3u@~ z^_hGcL+((Re6CcknnZ5V7=P_@zhW-b3f_{DiDo=@`SpactiRm;C%tTGZvMrQSd58%I1Uc9 zO-eslHQ`O^ID4AZ7R-n%L@Y>48X5R(2 z&z;QYch(7f(L426g3Wf?twO7~=W-w3^fX_;i}$X0V_{=sdH+556vX)zGTs3)C~NoSR)AkI7NCveNNZMYM6qm!I-Y3pDYZ zYArRLCMdMFCNJCA*hEDgwRJ6xiqqz&vlw>H{r*f>4}+&j{6Re_3f=Uz5`o55JKr0i z(^2oB=W?W?3OsOZkzLy3t`IwlT_vO(DYDC}QB8IcKT|#FWE4b**NXN2Y(7cC^RF2E zX0mp~r8ieD0Pv*V?W#(b%e+yiB(5|G_?qy4ztwZ!mAQf5jt*hRkvH#5xpl^|U+kBL zLtK{&_?g@H&M6X{*mt{hm>U?sa9ON>93f-nj^maUII z#rsARw)eigarxMeNVT&~MTWn9za523{-%>_qpYjsse7rh7uq}d zw6)9WjoVvq%$ok*?5r5S`Jsi+;Bw;gY8>UBN9wHDFOVH1m-yStT2yD`r1QRmw_Adw zMCI@7ccv5)>#hE+_s_ARpwRzAa_W)fR7{mI%eKzD#N!@<^DtFaRGdXGT#%po%^%fq z(-ne1q&lIjvz=21PgKRSxZ4KQ9GRpuu`l%Bc@n$x&!?r>&mVo^+4j@;v9VJ~3`^}^ z)M;Odbd_k9SfqOqk#LrYPgW$tTt0%&&m!mD703hxvYyLZbpk#sU( zI5x(^mNK4gB{FV?L#?zw-Yw)uFH?YkPI@CQ&ULf16?Cnho`d`M3`-~N8nPGD(Cjxt z7A14(XuFCrObUGs)eSm4tSnUTWV>F%;pP!(ZeHkr;b$|hp0O>G*v=nc0-fOh?OeXS~l zWZWOG|5v^Z(aAx2My=;x13*FX{Gydr*HKv==-96`C%crC8>>34qMvI#C=}^l-|Y@M z0K`|~rGEV(ra9)^gP*+!HoL&ueeEAjprCl`XY>EWH?#5kWmbB3^|}7>LB2m@qq}BG z@65Zd^YqZl&W`M-t2{rSWxw@heCJ^GxU~8sKD##mVnWxL_QBkSij>S z@bfwWNFAH9$slknPEIl{U$8s3|F8cuxf=L6WJfG)b<-Ap`u#`AA|_Bb;V z)dP3eEoqor1veAGdnyNvbxTfP;r?4!t_5}$T0>YoT-#`Lbz{qi1Ru2Y^;wb+`C0xS zjG`u`x)E5}@8l^HE8`3BlKW)W2CV=T=C#h>zbKP{Ou7U4Sx*M$khwnZN=tisC}8fw zT-KfXb3-LJOa1m%o+01qS6~f~+dz{XM*~M2?IsEdnU&RV*|=WP$`niV3GnjL%jsZ2 zGym~=xb}YgR5fl!!@EcX^?Rm%;q(~9099qDKkn7mzIg_?n}|gXjcCR=!RMW>`pZ9i zkm3Z_RBtZvf|XWh^gO=sRYXD-H)M1`Lvp#7F(qJ?k9%f;2Y@&W@O~RGF>Pkj<}d$k z2+zIW?#=}t2&LWYD-|tTh|w%M&dobr^S$)`m8sOO*^mU9ZD4kLzt`Vn#lzyfZ7WPe zgBFobcR8mWJ~T!QXlQArBD4`_v#`0Dddch)gmpl}AW@5_w}i@*w{5FeGQarJMW?kw zaPb0Uky?_YjQ{?@r@Dxb;$JYl)-X@Q#3 zwG#)Q$a98X{kJ#ukWUITow)#RIC=8?rVj$bC2M{;|R&>qiLz39?`XXs-E(m-p z4o6x3YL|)11DRgu(FR6%E}URiX4g0@cfE4l>IRUPfE)4^f0^#L#RcGQSjyWiQ^zAk zth;v7Zu$(>>?1}%m}YI5U3{`$coe{&6bnmkTf~lQAf;>a3>KR*(s3 z94#FV?yV$t)-T;Nvh$wv92j_S zraVo>DjZ?pxR43FHb&^N=9tC?8I~5rdgIgC;^CE{p*tKvVAgv`P0GDpWq@Yajs+Ip zpKX(4z}_uRy7Qz0Z#BO=n|K@A7%Ew?V(}^|vBC(Mo;jJgxw)CDTzMV>gzajw!-9zQ zDgL4}l`B2g)pb&f_0f=SOd1odlwKbZ$H$kMOm*>BZjK5bKEp#R8(f{Zy^KVZ%$8aY zAP{v8;j(38(RNrTw4g7Y?Dj$ko9Fa9+hpQ8noqFO>+@)YwgF;m87)hy>MJqN*3}%f ze{)X}>l$`}s3%ocod~HtLq(Na%`tWry4u=I>;30j#I{5$ODaoB%oc`_s*oiH4p8M+ z2HTCs+nkrKu$AX=&(+(+OS>z!1k(E4tsOq+7-O!64b2;R#ICzg{H$-R`=#qh_S&H0 zEhz!6BKMV%W8!==YoUxGjsN@4E<4t$1XLAfRe0(FPy&P~u~A=H>7I^E(?QD%rvrx` zl%|C3WD`ehZvy3w=WGf7<6d^+$V)W{NkcG|7E%WgwTz6!={Sc^M`7k}j|$F}&lIwI z&wtDX@Nl0OVHLKN+~T3Y`QgoRMcLDQF&mX6h+g82?J~-QrZ^bg2*Xla_?{5ohxyAd`zq)i9UMAawY~Y2ycws>~V?yl+ zhp;li#jBRTDJE^70zKSKX_ZlQO$^5<>S?rfKd{Zawz(;0+dwM^kQa=ivUbE5&c+U0 zA%{waUX7_3pX=;FP4ML!55F4AX$*{EMyxSoBAPZ)aXJpvgf!Q=!l8R(Gc_W%F4(1X zkCDKb*rH)fae@0&0|&V4W`^wwDwHo*R=XLk4|f&Wo)^JRaj`^-Ca*5UyKgaL5+=#l zRddcGyh>SJn6F<>FZFXDmciQ8(x6#Z9oh+>ybX-c5#TL$qxi{!6FV)k_%obf>wzr} zabg!0x9h9RX<}Jj7`Fc4-8YVMU>B9P`(vYcP{!5@&fxCz?qis6@x1Oj36ZEAgOVyd zVZxZWwate_H7wpv`>ug9aT{$~bGpdjudl|5J9WvD)L>UHk; zH3BS;u_p1+YFgP@){;}c+oQ5w4%>>q#WIQ9E1z1o6X%3SsVoNCR>cJCGfv^t8=Xla{St} z!XQTpy9*zmw$?Z82y7=UE$eC4dtD2LcDE(2Oslg<_+U|Jew`cfadGALxGD%mlIHzM zNJ11w8tYJZ?4!xNYo+H!Sw%>9rMm+gVO8C#$UW(Dw*|lS*mH{P-BISR%N*B;I~EN7ut?`TX-=t`bjP+E5J@u{F28vOXEe{2Mt_^=`MpDsXkttbjiH|q;u ziSOfMt8~v3bNm=sXFl@ZwJ-i6pFpaR02SGB0m5yx(K^{VlDA=@=vr`}P4Kmi4o$TZ z+~X-fy5BFFfS1qKwV^e+oVD_P_j^BT!L`q7vmR49h$+*?rY1T$VPRIyu;IGv2{Kzu zmBrkBtB@4OWVF^f-@tF+cIoc#f~ff_i1b%^o9Yd}E=ZNCus1?#Q$nIao6RxUrh&*c z{LtL*$4F;?t*Cw1eb{cz)R&L{reNMH5-jmFC|ms0OgJB6g^-}F8gpR=7I)dkY=Y0M zQ$md7YLji+Zfa{B$r=rnJ<XRx%8v<} z#!0ZN+zO_<0|6vl)5!>f2OBd*!16iUV~w0zp@hC@03a2NC0|L2ct0EPg1mspH6Vo) zP@@l417+6l0?Ihy8Jo03SNMTD(`RlTf}c171Awl%_l3pCbpm?XO==2L$u{TkYX#Kb zNtk1z$k2~Y4)Ba-tIy&#wJS^4)DU`36R8otgv?B@31wpjx%*g@0{V5bWqaJnJbb_2wW9DB2xbldp@{)D}UNYCCS-h@7ccdKpW>rrx?uYKAz}rSH7%Bbd3<$>N@7yhn<@Ds`#U;>(%_Qf&IsI z&Wr2D1hdG zS4I2QO1J$OwXx1xdjb}6uTJ<<@tT8$gu^cWm2 z8`aWs5Mw>ul7&bF%`o$D3*YF%Y+%w6sS5K3oc(Df)ltiRstW9EzTIih741l=k%QOl!%)A3KmEHTWLjo~li zhrU%VJv@hFE~P0y`oe~7XA%_2$Y=si1T4v)b*>`cDTKbm~0LX{W@ zl-sLNN5zS9$SVc*4lfiI7CsI+E8|mcAJNE2nXemJ)RJDBM!vg-h5^pHufyGsP9whf zli!!77X3A5+Fd&ikEsY6G#tVJ9kZ)UXNd7|+L($`RCF|R#i!<$n4~whs|(hBRVY8? zf{BpDZR}DNP!|CrylLC(3(_H^uD8cylUY>6E-)!AHLjTalWN?OTd?u4T%>2bvilG- zt)JXIgv?dv!``1qA=zC-5N91FFc?ZyNvi!IT*sru=hs+*rvUK)$a!%nql0 zLW9ySwz}{eyFa`+Xns@T;R9DlwYSvaRfnUq<`oULv36m#L(nE=euwU{nsPD6Fan#T%H!gx#_~L~uc^v{VHJ8w(o1DPb)MB3IB^ zir%$g{NO8FpU0^=Qxi@xDm<3!_Ypec!KxJwN1X7Ca#t8&hD#(&Dy=btiNu`?tvO{D zVcoasoGG6TE2y2Cc2AkX@F{#wqlm57CNYu=>F|=!HOee1X@|2$Z7|y2!KU~mT1A(* zPi^AJ$IshosFxZHkIgC8Aswh!ljlWpdCm=ys`q0`jcA`~%ibGE&-o+o)?tDc@{#x)F=~T71mL%mma7?_(lA;bzGhtpji_Gry?WYtdv)=z+!zx%fY7$ zt1lDI0nJFju&h#{;6!vR#!~+T;3; zrt`ntG|%d_zDWVUHJ#q|_ zkzdzQ0q72kLbnF@iefN(eZSmmigaG6jlhqN?&AQbtV;8gmR8oIkAugb$%ZD4N0Azh z*}#-bIgggwFeZU_DkUw=$fX-|4=vL@szgtg{-ANygQGTu9Z^j)U{to!S;w}aIl}df zRoAVWMwzr$H&C%YHig>^5*3j4S_3p`jA#4;A)#^*ML1mAZ%MSky5n;;=18gAhUx7K z1xW8L@Wwfa#mWT$a$aVABw@hEGkLoon60q()nw>k`S4it92P+;2bi&P1UB0oas&%4 z+aFb0S<`+iunoAbC*Ud=Rb zLX2n=bh;l?eEDoCQqYiC-a_N{m%Dkt;^je=$9`#+^zY0+-2(pDB$Kz^)sIE>^rC55 z=Seu)$}*ThMMXufk{f&3r~68s3D8>5*&SE931D~;%Le+>Eu+((tP>hxn*iyzgAh*+=0!@XYJ!;XXQY_ z)FUw6mJb2kJbH5mx&iFde%AqM6_p_B!v@EF?IjFB z0z*P97HnBPJw2@VYEHuDNFib?t2CkXp#AoL3JJ5IW6m)c&74ks79f4TaIwr4F>Nn~ z*c>jyx|sqk5Ry&G?QKbkx@_81cSw<7>G=EB6($R;k9=SH+o9F)s1*qsuVlam7=YUeUC3%97t^ctjc?BiGx-8H+u zMr5&4<~8=5NnKnds7mHck4BI(cp75GQ^9b5RUyLW?xmzO8F_Yin~34&BB)6(N6KUZ z9z7$I*riW8z|OvZ4+K7i%^J*o>1Jkto9w_D9sBJ!>bvbKO17bwu$2g7lJm*I&0iRR ze~Ed~cu}+Q@*a_fg&@(ceprz?IX3tNlAq+Pj{9(ss7iv-!IH{j?p|PNyAv7`+=g2F z%VeqW(roBrhePDd-fcTvmEb-OU?eh?SlsojJXaeixQ>76`eJ{*JzqC(Y;$lg$xwGa zYYItfd3H2!b6ZV*fHZV5V0Z=|*lP{97yO8&X_n{BTU^Tek(Jwe=;3lBBwbQQ#ygB6 zWOg!<{ZUVwM1_S@(#^+bU=MNIS}uSr_u{c=me~r=&LoAW(rk9J&h)GkOr=jhB#{|;Ow`tULGg$R zZ_l~1x%iLl?n$-rT3MMA-o$6eB(d$nDoXAXsmdu~V5E9ORDf#N4gd%{;e85`2#4b} zPgbUo$g<5vK1U~ls;sxIVSge_+hwVWckk36*jB7;+Fri=h>lZQdiYD?Bb*mtIV+3K~=YWZVqb8Kg zA8_;YU_L9rj+RVSdJG^sxs}^#j~^!kHBoMFk;}B3U0VudL-XRAfYGl-if~5Z=q8w_oWLi| zP*TgEidt$zGBPlrh?B}Nz2h#-q`-Zy$GE(}#0dDhO{7|BX;m!e#6a8X3|N1c)*?Rpeg=hwIsyc$4r>T|}R(NctICS$LP!j)rNkwDfDg3q!& zJpv|PQ;fDxt3rfgt|P`Jq7E#Nxr&Xh&Gpd({!UPU$U6vE%VZ3Zpejb~O-1$A$WSgt zqX(^K=?O+%Sgb%QM9_81R>GkJVqLLS03Cu=+y^^hzA&0vP>L`0ffy@5S}TZ?c90q) zBI#MfR53pa(gx^wGi4Wn9@eWu9RgWLrAx(r8;km-+u%r?MeKtz=`@KGVQp>iqobYA zO8ZsgiWeK~VxbXolq&5o@W@Q7<==PuaMZM=4iG%bUHg~0IBLpQw_9-I+riDN*p12< z(MmpF9-brKI6q_QiIgZ0NOZJ;X z!3PmO# z*DWn!hxDAYK}=@U$!xDxx6~!LG>c$7rHnY_0S)H7On@68h(!R(g{O}JM^*uXgzdE> z&AqwK^kcG7yr`$^b_v(;mBn;jEwhWJE5C05wbSn1z3a2o>YtOt58ZZ%xKfxwNJ~v+ zWD2pdvH}s$MQz&EOU%ew?o`a>DK8XJ2;DixCAvJ*|lrS{qSLp+$2SiqZPo2E#x8-1@}+#9B&#@JU3#caV8b7A<1y)G{n- zXD}>BnY*w}Fc`jom#X;ne*+=yCkV>s*5FuD83xu{R$)g&H1dn?-jU2Eb@0Kt-{gN!v&8ZEcJW{KsmB9{#zL1q z%dPBULIK9;n(xB%zjmyD|G>V(UDK`L?})S{iMU+1kdLKRRYQ<8qBA~j|HjfX-sEk0 z-Iao_x?W+|&t(Rx0HdR$)DbI4st0bj^!83HTmBbAtyamBcZ8TIf3Srd+Ea4HV-DF<}Pj@#LY&a~; z!Bq6;oQ-(>+M}Qv!_-0wSTd7nbxp#n=;-JKSq(}+&E^T&0mBBD;$dMC5$6ZH%GhM> z^|d;ur?XK~1Mf_i@9H_z zq>mTD9&re246rW2569NK8Vy$jSohU{TcxG14+S6lP$m7A^qArjd`VKk($cdQYgF>o z!uyaq@z9XsPY@t2!NWCXpA>&mc_s@jlpSDl2#Se;igQgMd!3DjL+kjwrCOe#GAGrX zx0sp0+ru`two~t-%&LL*eRWGL!1JEnu zFyPd1D$|riF5JpPJAMA<$pNPh*$GGX;I;hYfk)2lq5=^706r6&f}*arw)?jS^xK7b z%@h^iWMp(V^hzjm_*&T6fmcbSx5$YCa->qr%lkF#GAub7{ir!EC*A-a62B^E4_w!n zN;_aovI-D99KIdGz;7td@LtDFQBlz;FPstMeAqUp$f&rPaZYGJTTm*66q)zHr4`He z)}XkYk*N^55PYKYlM2!e8jH_h3uqS+cmd9=cMd_;`|N}CC$J?$T~thcbRm3Q^q^WDht-D?W;iO*|8`2zR*`Gy_F|DSoURf778Bkz~px_JgN zImVauA@P$8%(5mxX$>--5g(&?=$Fdk6S9%HPaW&ByzbTbs^36EBMG5vXqYqi7ARN& zL70H%_I(2ieYOE(cpRqX?}*WW7z^7nqF2RUc7vQEa&#HOdy=mq9h;2*S@#$X*X|y0 zAMMQj2Y3G23$4Cz0l?uT0e)?6RS>Xh#`>AKi0TzYOxV6of0HFD3&-Ms`eMPm-D-O5_DInMJj8gFf7m7UXn7oXziR|~0u zhm#r=dsbSzO2-Ohf<+@SM6rnO&Exq6KKPIKv12Hjdu6?`*50gkLUvBrJ$c9a@tMu; zEKL_MZb-rhkrw#F_Vn9#F-&pj`jb|aLlCW8jCHJaU;So{1-AIp-o$1&$@Z?#9bwp5 z9(@^O#xskalRX;^+tDQpry!>wmZ*dy%`BL;*R1yH$&yQ~Y1zG%h_5r(uq>!7MI1`O&3axB>HcIZit!{T4$E?O&S~1x3GQ z&xbl+2w`h!8yebdns|p4rrdp;VI=Kbu{-bAq1uB_YQ_}~-7mkDpLFLl0WG__NkC7q zcj&3BCn9t;G!DA!K==wqFzyhIyb`YjU;3}0jz8OLvte`SW_r6>uA(mh5#<7GW3tJB zN_~Bn?Y24D*LGzvZ#%kxzSpXa039ilFt>~`#<15!!^Q~g+teJs&*d!QEdLQy`Tb6X z-4`yE_Oodo^T>RolT_KGwe;1AhKw|Y(nkqsCYix?e8Lpo?a`m8*4YC;`)H-xljy1^6czSSYzg{0+CtT9}7tK1{WbBN&ll!;_+rztLnJomM0=vxbPXx$OSP z{H&u(-n*$cL*f7~6J;q24*VI!I&=rC^B2xZivG$!U_k0DM$+VQow*V)0aiC?*wzOh zW%<#Orx}1gV)H|^%dS+cMf?M1{D<8K^7gRM%L(IVfxCpSQE*o}2R0}Z8W#!u!aW=U5n&+9EXzSonZ}U3B#2l z*=mppnOP8X2T_K^WZ4y~MhbnLTAti{6T0J8?zuJIw>yE&b9>~abTs(?DLEJwETV4! z#op}s1o&wL9@arC7{45&3tXukoIT}uMg_x=q&dVZ8q$4ck|F;hp+aw1Dg5=nVW(XL{wVCsR+ z0}{5s<(x^F2JqiQ`c6vNv12p;9Sr8rS-`fzD0=CvbN(e53^{SjE{DWMAXu?C~Chq6eo`V`E>vIu)W8k!GpqHdmV0?`fn| zizldn%V*RP5)KyKjM{y}IFtH4Wkfn5_vxmNn4VUg+&Hbzo!G6S)DB3V{d!|K1k8-% z6xZZ0-F!EEk*gWeaZbDi)6?|e0#{WgT;*+Qi3w}_ z_Hf;!jw>Y8q)0;a+B0gttSKSTa zRw0SsvBEMajNvz+*&`21i3p?RXtiq&jE4_{buG^N{R(mxMo8DD$ORzBBO4MsTf{M9 z|MefY`=DGUZJw%rl%1b{zxwfVoV6*Z1Z!s9Fl3ock5fj?@TJ;|#R3Kge5w0xmmg<565i-2i;G>Fg?z^`-a;&8J|DzMx215N6*7FSa>fXM+0N$w~ z=^wd0AaSepu0tN60HFV1Q7I8mKu^)fk+Ja)Mc>nq!V?K}>&-W~!^Dji*bT}XU z|2-}K=ZyR)TX3muW+igwrP%i^xz>~6=U_iBNSyzB>O%n6-_xQ#yt-WqF7caMB1Zj; z5Kex2UNH40gO-wIiKHK`k1JJ?ixpK-S6tQJN=ZL`NfAH&DOKE~fw-!ixag`J=k)oH zbE>#5FqgYZHP;4R)9tO()9kJLdA;V#G{Ja)f3plSYyG@nV(|9qxk_?{2s0EK@_R|- z)(yvrIlONiegDOfGAdjI7=Eu2iBU7N_F@ErVlcDTSH!9en<5am0ka6yPxv|6{+e~a z{NR>NEy@Fyn3h&hUwLp}!z_0~c(|c~lmLG-SE_KYp;kCqM^Ac3+z~kw58(#K5uOCQ zFaV<9-@@%c@c!{fQg$}|&)F-p=9iuV7XCjzz}o!jzT*J5ZCbg;`dx9)UIs$ZeSlVQ z$pip{5|nR(O3E`Gpb`bPVX?M3W$hFD{p6q&DRf$~Uj>8hOb3H)4)ibd?O~$EkAC}h zXk7V6_maEPHc{}eQTWFna|6Qm@!a3Ca46&z+A2Q_{hSgtOg~dKDJV>+|HHS&8vq*5 zuP?lJ!fyWUrCD2fjK4})D0y73+;EeFWuN0L`bX6vs}X2H89hV%4KA1i{XwtieVN6f zLAJa6xI5~}L(jz{l?Y;?tCZyuZl8!FOsalLDz!I1FXd&yVEY_gn)fzN1b=sFF0lPA z@9DM;52}apXB&nB{_ExYpHltI-q@5`MIUaRJrC_W;#`!BoMph0V6qNU@=BfVpLspc z=1!G9Zv@UBdtU~&@L87|ZXr_ODH3$25*3r93Q=;E7ia-gCqA?+&f~=l*St0`drSIG)3et`c!ZNQ|B_ zZ#d}s;JhjTq!a{YRnyz`V7bCl<$nz$aOk!D(>bXG3O`StzB5!s56O#_yf9%T{^i^1 z2|=%~+b$RGYsXfpB->N-zzIH?$Up0Cu z3S!;cv{NF2so-}Kbr@pM(xPz*fimPk*$mt@**V5~dOe_qC_bxCoR8;0;h*#L4c7A- zP;#W6yCXllw(v5CarS|PVi0IAJo&eZduId$*ka8-XdQ7H z6E4;dc0D>wjUiQ*Cs*IW1twWVr&%7Rb`^^SNdv>n4>N#|Jib&#Um|`8@NaWM&X_Fc zclx=Kp1wFNakj;mIFnr@>$ALGpZ!hh{BQhVfUQ zyTh|-AqV_-940N(!POsfTz3$cGF7~b<`r1m>@d;XXc@@OLAVYK(sD^lm%p{YFZA`6 zG2#TBMZ54vkc>L7D}5R#9+;V%OS1BAtax{P`9e2$>9-GbDL);_-Ww}5u#Y}x4Xlu` zCL(;cheb%(!o}L;nAN?L(fJ3S+I>rbHL+-yko&zf4Gzz3S?Amgf4RMZ3V!wBT~5M* zu_Im;p?*-uX#K98rlu(m!;5|yYibIU$ZalR1}bo4UJw;!WDI(#0e;y}o(2>`9d99f zyIQVQ+nkX(9O!*L?v6D=(U4jn>D zpSQk;J02?l6qvGzuz^ZrrESOE6s_qz4e1H9jg2hf@$qbP?wPSzlQU zHSQ62_JS?`_5AN383`Q=Gi=@QYt8Rh5ernF-_ml=SZ~hHZ&bRO!Jr9uHul(=Lq~vr zv^k!Sq9!mhb6=XAs{Zh{-N1mTxKvAQ+u2WLI%_j$V0In3 zPwgjh{}}^?&|4FsudVceUpR;Lt1MZzfbD$sMY?@Vda&JU1(mQxq%BOc`A|el&6eQ( zkneiq{@pOu;^9zaJg20my!TdUWc&__;{d*7lkpORBdEPQC@$|M&-xlOG^;mEO1BWQ z&+fwwd-yyZm2Bz}xU|%C@il*1It9fzpfD#UqR6}2{$u1hO^0WT>s+Ewm?UfU$El)a zB&OMHhGuy9?MpQ7`$#ZRd?*GH??(F@#p468ADHmG41At>kZRYkG zpS_}x$`F{uLxp&|4Een8udnB>gY+B7PP5iO|DuRsBzj?h zn>(DqxB1t+X z9Dwd?X>OjHdHXv$m&eM(!{f@8wA6Rh{?$?8;WI8}{7b3!R3U4J{b+GjPF#R!xI^xj zn)(lwwvnWn>%&DyC<0#UfONh?md^Edu#>o=Y1gZ0l!!Lk3TF-f2;-ELG@tC4fKViF zYIn%)TMV^$7GMuGk5x4fsoo>wsif2ZW!eG*KaEeBzrsu%ll9S1Rb}&IQN%H@E#xE` zuZ8ip_s{0r`jMCOhrzu0-YB}wQ#&d4Sw)hXgQ{R8-0-){$Nar;doonh8}BF7sO#vU z>;~AVkEMns-WVTmPk_?6^L0v<;GW~$|~*PlF`%GZ(d=9?Q#rO z=6Z!(P04()Y2Bn6gFx+C7W(V5zvvk$W^${SgtsTpyKLc{c~e9AHK;4&!2HK_9?KWK zLh(>tT-=>(I`yk9+xEX)x3guiO_lVEnd1XZP9JB;)-bd3)hj^kG(UgVH^VtI6BOB3 zYBuR*VH(DA)?h@m3O84^t15ms6TWF3Wx)oAG-5Y;ng!$6WxLpD$j?wJ?mFX|)p(j_ z`*)+rjb)`naNa3*ytV@-Nbi0Gj^bm3zZ)o*ab5DGSn}m5TB`(kDTKo2MT@?fC^w2l7;H7$5Fq@I2E z%y*k706`sbG7G7ph*CX!BLTj`ia=V#PQ1;w7V$+UL_XJ zWLk1=x^Cy%@S}cvZ7CNZV7%h2^Q@Gm_sNms4;70HY|Gyib_Ux^&!|EY+0uoIdwXWq zX6JeYyT6eX9MpT}Bl&dJZU?X~Ly`vMfjA9+DiSCe8G?Mie2;>}W9=1E8`Dl`nGJ(8 z2lhNa15dX-ESozORS6lpE}s0JNdJ8tT}a~%NC{h6UIQLPKnkq`Kx}H9az*wcVlj!owQXn?&n33 zz!v>TuibJ7}_16TwE zWSXwk`t={EZ)hkbwDdwku-#mFQ9;_+GUN+sL$-DPvdJi)89gXmetS&KiY0(g|P z=;^~xeWiX)x#DFSaX=|LSY=Nu%cdSUV9Ltub_LBLfdB_UB! zpx3>lp-~0sPOTWIn#~Ud6V5Gq?Kav)@kYnNp$MQfxkPS(Sr;WG$Ir{v;fzonIh$xE zF0Rc9DSxwVsWDfV3e%NwQTprYR|c7b>3-L~>g0WV-mzhswdAptKG|5qz8I?XQ97X# ze)QJqVKv@$?PZ_mf09{9FHJIDl!rWNC`NtX$H%A4Wd<<5DSEf3x|)I69t!VNAY^&D zxw(1XtU^sNC~CyOz)(|T;J&_ilK$i=Y{-+6q(TV?pvwkQo;Pl%Fof z4!pSq)f3IGH$jDu9h^Ws?Qy+{u>@t`TX^hTR1>Di8)z=WL>@ibplgkn-Z;IfL2>b< zW#8AX?vn0zrg~~NOq4o%_txbadICb@TB=6Hm(EVW!^8!6tn6PROw}_%l?Y%k&C^B> ze)w>lCFY9R3XnNC21%9Z_tTzpG#a4q39hRD37W4O{@+e zLgn)zIqvy$AE=zFK7{}he0hc=N8X&77^sx376L4ZcFYoRS}(vEf<~wlNq{Kv^<8SL zufMLWEa`dSIuFBR-z8ku6Zs^lN@>r!iZMoLwVeFzVIUJ7UD%5kP-{;sNAFtdYqJj{HQ4~-rVR@YCv6lKpJrNh61ch)HE7|A-2B?=1-UT>I%Udz(QNwa)X zJ1-3^`1H#Y1P@26t5=2Sp)@atq-2bsZjtR4X>mt@R zR*xq^i3BULDu8^@t6#iGK{7KjdHCeXHK0_HlS_ImO>wc)3P$zw=k@VcM1jp3*7GtW zRqY?UoqULvpR4?g6J*)XI*#aMbO;GA)jT<*_+)%_05jcJ5)_b~WAoxAyP)y*)@;8d z5H8a(IwyL24g`kmqM$fU`E8t2wRzQ-WBC}>ieEV1<2!qXK%`AJxE{&-%1g^7sZ0Fa z+i#70E$w681#+CYL4JWBi;sZ{aw;#_^sQ3`2M5bP05qA|%PN=-ctI#>W9b$MOyF%< zH*<4rOtrN!DJgq_A(Qz6X?36)$o^Ls7e_Eh$2PhvNp>_bJ1>S)@1K78;sq;lMq(GkEj(2FP6wQ9iL}bFs>5Xvo$Ei{gNqVF5a?!av`I>e4%YzexJHlj5S8 zTd%$oyz{5LaPkhf_tt7*$f|N^;JOpQbw?~X0C(h$*iZl>d^qzsG@CqP3Y(i=ETXp8 z>0FjgzwjZQ;d>e?&|*Dh7U(-oJa1jw)diX#UXe4J13v;;e!X|q+`_7;NR)I;%_NKHw3{o1t(hs$Ldx$-Aojvfk?=hWg4yL#fB z?j=j}eUojez3T)V@LH-UmCjA~O>eFGPf6W_p1xneG1K6Hj7S|3Q;piklOB6D*~%`l z#OEWY{jT5-^u<@WkPocHwO_f1+w;dqk7iXgq@44L4mUj#ET*s^j{G)UH_9#D2uU+D zT7F(bFU-0>TtsjZmoedFDZxM2SMm}nD1l%BsqV6P_f1g|2Fd_$Z>`!J8L`nXPcgl} zQ;PPnKYhdnUAxX5#poFw>+tv z3$#%B<*Gp+vQkP4>58{u7YfHMKRJ^2ES9g@{MHlxVRRN%L!g3w`J!R@q;bMi-F`7i z$<*}pwDfcV{lfgrx*b~nx4(KE{5_f1^vvnJzziJ|y9T|h*s)>?ia|qDJ3CQGwLn(J zOZsg3S5(Yod5DEuLqQ3sFwrL71kn|*rPdM4cA15Rg?qZo={yIYKwX>MJafba_!&^g zWK=*|cfc2Rpxm7bPBll11KX*%q~yef_{q!FF-$gg$eT<}t-2QPFampFQ6)g5kQzTV zfS?8PsdHk*wDiZs>|e*KL(YFpz!(~;Kwu4^-n-fQ0D}D>l^@7UH>i0FrTCTuSSYaZ z4<8zpsyLtIgcUm0#A|0apc+>i9T}N_zuW4|>s2T~KimJ5J863QKBv`}51*>40t4b@ zyn)HDKjq1>#`jRaz{p63ktIOm$4IT|Tj%oc$|Ysc7wd`8bUyBe9q|Uun^A)&=$yrF zor1s`2iD6q^t@tsjyx6%Hap_?p5b-d%s?g58Y2)Dr3>4Nk2N=AVTRz*?q_FDd#s*B z#J;SQH1gR>eZRxnh9~N)hKZqY+#kvjpXJy;AK)%8px;69q3q)6@LZ$vOuGTP&izAB zLjus8by{MXqE>(@tqt)7C817Ca|TL97=`bR0%snD)40!gJxxT!5!rdKm7G&?^s&>Ox#SHb0 z=udKUBlQZPn6$UoC~(xcOm%evr4$w`!_AF{(ljU05NEcBs;EFv3()M@UTvcu=kE6j z(V});iI0r^5BMY|ro*nWz6c}gv(lZ;8EQfDnVzJ&abDPF(!_4=t$Ut;rlI@o+vzOA zZx2vW?W3aNNCHZ0SyEq3B?CJ}_EH86<~UhWW3@kRFgvMrauVpBYSu?92Z?bH6Cg^s?7Ch+vSgY&W?w#@WqeN(R1CQVRCzW zWe8>C;P)=$+0EmV9XD9Nh#{O}&uo6~J$izI0!0lPc0Y78_?Orvme8G9+EB*$>@aCD^Fx6i@RQOa%p%RG)Nz@qL5xp3i0P*CUp#n@ZNRk?Ouqih6QDM3;s1Oe%81e6w}8zrQ>TNIEG5Gm>IlI~Et zLAsId?mTnpe%|jn=l$b+_Ye10V6An>bB>X}$jN=U1U=2DpJQXqjg88QGL0?Mt{3~sC>{a^`uftsw{F=lSRKT_K7~8&`}uBu zO#CVm(iUMSB(q2tj4!UJRB4WFyA@3P-jI^!8K5b7;|7{HVKA!q{bR`ZJ4|mB6y`X& zxIhkL8qNx2TaGpj_rE~v1rG4}g>68Zd|~fCJ9`bV@QkCvBnXT|PGX;wS9{r>3=;%6|XLI?E3VdB385nOCQRTVb| zj8Tb!c<|wEFF|^GX*fthE#fB#@q`7reGUi!;YdMYu(lwaVFY%#&drrGklSir)aAV9 z>&4lzLseCknus&`Y$b)VtVK^E&FPV0SL7?TckEh^sP=LgMOc)f63bT`48C7oJrP1F6y^niS#52tps5=Tll?z(CS5^$+hvGFL!|Mk7iBj5oms6hf6b3@sZ(U}?6M%92ywFpS z@ch~nOkblzo6$l&cs{F>RT06#!K*JmuF^xM#8cfFbO50A+w7pH5B!#wC5*g?T^M9Z zgJZbuA8{(Zx9Ri?XVH2%DZv-7rxbqdj4F|WPkZa5gFDMn z(n!<5km@$y-_W45(5@wa)IQ6x*%?^`Q6g0&>$AR6MCX&B@STTlRk~t*ud?|sk3R+l zv16cKKSb!GVBirDY>XX52s{P@Guxl{tmE>0Z})A3Hx!i@!~hlIdDqFIr)kmT7f--y zWOHaT0)D3XGoFwz*rcbd8>)3~7j;*BGt0{|GBOM%%6)Uy&@V@;vWw_*3me45#NxpXrbHt*AbC~jY|8=T2 zK!Jl3J{Vx}Aq2?E>}_mp1c@0m+}=7piHDaDwPBtP&a-dRDPmZp(3gC5@sQK)+!Ndi zdT_q^**yX`twP<*PoG3U)8n{|6qFq_%D2baYsH0OZ^4|G)uCL1EACSe6|i1(DKQdmEtSpT`eul>ja@)a?1zQ>1S$(POK4Ngdk-6 zURr8rZ7nTMEgl5nmDP_AClH|f`*1*Py9_!JptKgQmEZvHq2+dxnwfb^i13CM_{CZ)DIlQf+C=jD*%4Tj7C` zWf%wso17i;1DMclsqWy=2=~=|va*RmGJ-C)?&RGMf={l?z5FgtUweu$gQ1BJZ0PYE zfHiwJE-x=#oDQIk4ic8II?#@heT;5FXb&=r73$p#k}%Q_fY!uHZhQ=&&h2sz7vkdK zZA@K6Bqx6qO#H^Aw+i8>Z!5%|T~UJ|2p7?@px@(7#A!v&&p+Lrw-QJ+zOk_(AAJJ_ zS9?nsj%-7PY4XmmHM1LGc@jMM_gM1Gk-$|Sz1jL6IKx?GC`;~e1 z0Dhn@M7Q2(#LZd|3=+5N76LWvV7X5yHycjb{pvznNT>m#2P^X+Z(s2FX#Eu%l}4w`;Qg>~K2uPm~CQYaU+S2n$%Yt?oZh#XNFMg(&?<@L?X z%pmrLJts?Z1*z|3W0iewTr}`5ojU!Zx#wz7Ww9b0pNdEQ3sf%HzAa6`hA@9&-B6E-w#{-PR>InekVzy0avnvKuc}yPQb#UzU?|b8|m_ z{O00xT2e|1o_IOT)&n(WGP2}}i5TZ2%%4BIso4$HYF$>oG3vy`#`5s+9P4xOUlex^ z3<%Rj^u%49z{=2LiiCv+r}!-@s{0$GD=aQy$i6YLu;xHp_sf^sGV>OUVA#KX$)5m% zhNy|xZoPb$zJ!7dB%1JfPp^?Wf%o}D9LVp;1caP<80!$l@V44W3CxRD@iI3l1kL9# zda$Ul(AVJn7|s2B=MzA1f%vSuN7L+2X`CG#0AY>+MJo4GMcnl|zgeke2GL4zO2q4+;Z5=Y1EC$#GXC z%L^nX)vJ%47YL_U#p0`qRLy^U@KWFfGMV%ru{K2LvDS;@G2B>B6C*&Lu{M~Z>!`6s z5p-X(Uq2LPJOS}Vj`sD_2P-Rh!n$T=bPsNyX!U@}lQ%vFalLCdE-8|FdwUNzTw&n@ zAPlvP6TCbGFbFk_Pa@oW57*}AgoKYapKPP8hhho9Kwc1{3q~ME2xU}&TK$@4K~5_p zO#?K|r|Pbd2JLUPyLNB{s?}YV(P?mD_4V-QA48rHW*h2m59sV18rZ&(;!M{z8uW+u z`Y;CAu?DQ!WVz+sK&BiyrWmM;+HIZ#m&kd!_qUOhtepQl1yvOljNqCYNHR8jmf^f1 zT#a*w%y|#gSg`$@&Y3#exd_3e8b1?yV zbM%?~D7&uKR{85CAfg676m-A)e*J>PWqx5HtUAs-q_;tESux0`e8A;o&O{rR`qEtS zjXCwEo`kS^V$$|Y>RZZ5!_iaNn$B%Y>b|1EUtSPpZa1&3eD_g+GiQMINIAx5yYw1;G& zo#Ad>%J(QRGyt9u5D-8N(F6&$&<%c4kPC}%YX>b|Nr+6UYii&oj=|7BfKBcZ^L0+v z9E4KEZ(}Rwsh8+=DDv~yP1Ric_~Aoy(3QnRc>z2V@XgYCl%NXm`gPMgM%ZnN6^nk0 zkj=u-MRDQw&b36L8xZ1uht+8mXP0Zn4h}v6jmNq_mlJt7krpyG)l9yg!RfwYnoORt zJj*WQ&DH}GO>2=n{kd(yQ~=_Q6c0}>-d z+;-)58m4FE-?!OLe`4}%EU>G&=;Yn*R=x=-Zi!;y|73cBX25m4wnf9ChD zOVgYZ_?JUP`e;xarKC)M8DOGXX4VyP#|xR%sPE^3g3{|Ojhzs6$966NAg_>-&%+j6 zDq&?-f(3Qkp7~MlaZTj2OiyleQxg@tF0DIxJ0s0QYYM=CF)%D&v2J9k_aDP~WV@LJ z)O|yEJ$?7>$6^N`Z9%Ayg4Fx%-Fx@4c{ZZX)@(5g!4m|RrRrv28B-~AD=f4H@`uJc zw5p1u-nS(ui+Pc|`p(^X<)FiF_^O$6*2m}dgDa&gBYdal^KyylsXrb&zh3g*ZIpC$ zaeC{(MA^T9<&Idxpf3&m_pAoJfa``c{~nx};Gv>-t;)9?`Yp5)3? zMU{M2*)lA@jkR$%NF24?dFjC)@bkOF%6yXT=b zQ*pS0MTmowXR2hbRZ=Mi>=RxnoCg^Huk{(lqvUSi53u<*j&36_t8M8sl??qd?E(i# zt6k5$pIS#kVOLaA5}a6O;VW1a@Kguz0YTiov9oiuITc`UV`I?YJUK8>3{#kId(Ezo zeh1Np{q<1@#QT5!`nmN9S?)LUy7UbEdD0h>+p=g7LNS`u2?TyXtqX%u*PFSgjDSPGsbrAr^U-f2mP$vlTu#O~^{y9$@Q zkdKxELN%1Q2d32ZX!0k3$PkM!%+Bs^)#YQwXVsqXN|>AH!y}`t zXEsDSjhlmGbeuaYcj^#?gAX?@1}-x;y=?)&B(<`)N7MiTVe{wV;tW0N&fTT{>D zUD=#B#%#}7xoM407dKs^^I>GnWBzme5?iy7V7_)gqD<7}#X@NWnkYJwZ&E zjxO(sh_?Bbvf_h5&-y<3nKxOAPo+C`@1lGz@bN*pch8G%@$>f)XXd60Nm6avRIYd> zH+C|2YxSW{>xyh0yv*J=Z&vVZkdPcia#V`E=gR48kAFgIN&YSQ_8T><{{gKwBOgKJMJD?61C4^`DtR%|og{zk!Blt_crBzV33KkX59nE;140*Ry z49D}5?@+7|wz+b{#Bg+S0`+ji-h|<6IQ~swQ%E8I5qCsWC%FV8bLEZ0sf1V(?~QI6 z!e4q}B+WM(t{M4Sm*T7TScTtsW&VpVbtl}M^c9YiFO)*1IGiSBY8nc`4*to}KYSDd zCE?@q6Km4Kf`UGyV;G+DBPK0$TB&KH54uCkrk$)z$KAP}UuUggE34E8#772B-a}dWnE%=bINS z+%TW2ZX@27eisH#Qe()?#9Y2RdHl9ML;a6!Is2hmTjVfCoLf=RmMW;~X`g*i;=+F! znhDZ}jsCuSi}#t2=;dRHPt1OmY@we`U+<%ectyn1XwEaIY4d)78;(y;Iy-^Je-48k z9%5izuI1MuMC`%R0-51~ukf@>(HD2=5~~I3NJ%#PO(jSRJMe2jJAJ3wt-%nDK60P@Ig_a@pamo2!Qq4pPB0ARd^G4}tZ)+-^7mZjLNeKmf(V zdaXWTN(zAaaMFt_7+t7lbOreD<0Ldb+_0D!5Q0sVU4yZ2(R!oPZffi{%U{6AT^x>& z72@Dc73vuSUll?T2>VVO(5A28oq>mN@766hn9B(2@;(M#Q6*Lt=h5ak>(g~$ovzM+ zf7l)C|Gl69u0j+THgUsQgzlFWxvz+<=hYE}N~EmBu`hNC8XPjV*gve=S#uP<5MdZb zx!HgIH@%xlgXZ3>y);{%lvs`58{(ed(mCPG=CCn3Q^Lr6#CLMUHSO)JP~`9_zlv7m z-Mi};U=$I2f{4!q>_fw4HHshk9e1H7ii2?vm*I;Kz**wL5S*G#2No58Za{Oa4_r}N zP90F6_)x1{PGm3NYQeCjOGs?%aCRW&F6KHbn|1@00anu0aduts?k>N_N{rde&UM

_sOhHQkk#jT4v(nD6nq!fc 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 literal 0 HcmV?d00001 From 2f42b6418209f72488122661282e48488d9dfddc Mon Sep 17 00:00:00 2001 From: Edward Angert Date: Mon, 7 Jul 2025 20:46:34 -0400 Subject: [PATCH 02/61] docs: update dynamic parameters for beta release (#18512) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: EdwardAngert <17991901+EdwardAngert@users.noreply.github.com> Co-authored-by: Stephen Kirby Co-authored-by: Stephen Kirby <58410745+stirby@users.noreply.github.com> Co-authored-by: Atif Ali Co-authored-by: Jaayden Halko Co-authored-by: Mathias Fredriksson Co-authored-by: Steven Masley Co-authored-by: Thomas Kosiewski Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> Co-authored-by: bpmct <22407953+bpmct@users.noreply.github.com> Co-authored-by: Bruno Quaresma Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com> Co-authored-by: Claude Co-authored-by: Ethan <39577870+ethanndickson@users.noreply.github.com> Co-authored-by: kylecarbs <7122116+kylecarbs@users.noreply.github.com> Co-authored-by: Ben Potter Co-authored-by: Hugo Dutka Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ケイラ --- .../extending-templates/dynamic-parameters.md | 833 ++++++++++++++++++ .../extending-templates/parameters.md | 546 +----------- .../dyn-params/dynamic-params-compare.png | Bin 0 -> 116646 bytes .../dyn-params/enable-dynamic-parameters.png | Bin 0 -> 24365 bytes docs/manifest.json | 6 + 5 files changed, 845 insertions(+), 540 deletions(-) create mode 100644 docs/admin/templates/extending-templates/dynamic-parameters.md create mode 100644 docs/images/admin/templates/extend-templates/dyn-params/dynamic-params-compare.png create mode 100644 docs/images/admin/templates/extend-templates/dyn-params/enable-dynamic-parameters.png diff --git a/docs/admin/templates/extending-templates/dynamic-parameters.md b/docs/admin/templates/extending-templates/dynamic-parameters.md new file mode 100644 index 0000000000000..d676c3bcf3148 --- /dev/null +++ b/docs/admin/templates/extending-templates/dynamic-parameters.md @@ -0,0 +1,833 @@ +# Dynamic Parameters + +Coder v2.24.0 introduces Dynamic Parameters to extend Coder [parameters](./parameters.md) with conditional form controls, +enriched input types, and user identity awareness. +This allows template authors to create interactive workspace creation forms with more environment customization, +and that means fewer templates to maintain. + +![Dynamic Parameters in Action](https://i.imgur.com/uR8mpRJ.gif) + +All parameters are parsed from Terraform, so your workspace creation forms live in the same location as your provisioning code. +You can use all the native Terraform functions and conditionality to create a self-service tooling catalog for every template. + +Administrators can use Dynamic Parameters to: + +- Create parameters which respond to the inputs of others. +- Only show parameters when other input criteria are met. +- Only show select parameters to target Coder roles or groups. + +You can try the Dynamic Parameter syntax and any of the code examples below in the +[Parameters Playground](https://playground.coder.app/parameters). +You should experiment with parameters in the playground before you upgrade live templates. + +## When You Should Upgrade to Dynamic Parameters + +While Dynamic parameters introduce a variety of new powerful tools, all functionality is backwards compatible with +existing coder templates. +When you opt-in to the new experience, no functional changes will be applied to your production parameters. + +Some reasons Coder template admins should try Dynamic Parameters: + +- You maintain or support many templates for teams with unique expectations or use cases. +- You want to selectively expose privileged workspace options to admins, power users, or personas. +- You want to make the workspace creation flow more ergonomic for developers. + +Dynamic Parameters help you reduce template duplication by setting the conditions for which users should see specific parameters. +They reduce the potential complexity of user-facing configuration by allowing administrators to organize a long list of options into interactive, branching paths for workspace customization. +They allow you to set resource guardrails by referencing Coder identity in the `coder_workspace_owner` data source. + +## How to enable Dynamic Parameters + +In Coder v2.24.0, you can opt-in to Dynamic Parameters on a per-template basis. + +1. Go to your template's settings and enable the **Enable dynamic parameters for workspace creation** option. + + ![Enable dynamic parameters for workspace creation](../../../images/admin/templates/extend-templates/dyn-params/enable-dynamic-parameters.png) + +1. Update your template to use version >=2.4.0 of the Coder provider with the following Terraform block. + + ```terraform + terraform { + required_providers { + coder = { + source = "coder/coder" + version = ">=2.4.0" + } + } + } + ``` + +1. This enables Dynamic Parameters in the template. + Add some [conditional parameters](#available-form-input-types). + + Note that these new features must be declared in your Terraform to start leveraging Dynamic Parameters. + +1. Save and publish the template. + +1. Users should see the updated workspace creation form. + +Dynamic Parameters features are backwards compatible, so all existing templates may be upgraded in-place. +If you decide to revert to the legacy flow later, disable Dynamic Parameters in the template's settings. + +## Features and Capabilities + +Dynamic Parameters introduces three primary enhancements to the standard parameter system: + +- **Conditional Parameters** + + - Parameters can respond to changes in other parameters + - Show or hide parameters based on other selections + - Modify validation rules conditionally + - Create branching paths in workspace creation forms + +- **Reference User Properties** + + - Read user data at build time from [`coder_workspace_owner`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner) + - Conditionally hide parameters based on user's role + - Change parameter options based on user groups + - Reference user name, groups, and roles in parameter text + +- **Additional Form Inputs** + + - Searchable dropdown lists for easier selection + - Multi-select options for choosing multiple items + - Secret text inputs for sensitive information + - Slider input for disk size, model temperature + - Disabled parameters to display immutable data + +> [!IMPORTANT] +> Dynamic Parameters does not support external data fetching via HTTP endpoints at workspace build time. +> +> External fetching would introduce unpredictability in workspace builds after publishing a template. +> Instead, we recommend that template administrators pull in any required data for a workspace build as a +> [locals](https://developer.hashicorp.com/terraform/tutorials/configuration-language/locals) or JSON file, +> then reference that data in Terraform. +> +> If you have a use case for external data fetching, please file an issue or create a discussion in the +> [Coder GitHub repository](https://github.com/coder/coder). + +## Available Form Input Types + +Dynamic Parameters supports a variety of form types to create rich, interactive user experiences. + +![Old vs New Parameters](../../../images/admin/templates/extend-templates/dyn-params/dynamic-params-compare.png) + +Different parameter types support different form types. +You can specify the form type using the +[`form_type`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/parameter#form_type-1) attribute. + +The **Options** column in the table below indicates whether the form type supports options (**Yes**) or doesn't support them (**No**). +When supported, you can specify options using one or more `option` blocks in your parameter definition, +where each option has a `name` (displayed to the user) and a `value` (used in your template logic). + +| Form Type | Parameter Types | Options | Notes | +|----------------|--------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------| +| `radio` | `string`, `number`, `bool`, `list(string)` | Yes | Radio buttons for selecting a single option with all choices visible at once.
The classic parameter option. | +| `dropdown` | `string`, `number` | Yes | Choose a single option from a searchable dropdown list.
Default for `string` or `number` parameters with options. | +| `multi-select` | `list(string)` | Yes | Select multiple items from a list with checkboxes. | +| `tag-select` | `list(string)` | No | Default for `list(string)` parameters without options. | +| `input` | `string`, `number` | No | Standard single-line text input field.
Default for `string/number` parameters without options. | +| `textarea` | `string` | No | Multi-line text input field for longer content. | +| `slider` | `number` | No | Slider selection with min/max validation for numeric values. | +| `checkbox` | `bool` | No | A single checkbox for boolean parameters.
Default for boolean parameters. | + +### Available Styling Options + +The `coder_parameter` resource supports an additional `styling` attribute for special cosmetic changes that can be used +to further customize the workspace creation form. + +This can be used for: + +- Masking private inputs +- Marking inputs as read-only +- Setting placeholder text + +Note that the `styling` attribute should not be used as a governance tool, since it only changes how the interactive +form is displayed. +Users can avoid restrictions like `disabled` if they create a workspace via the CLI. + +This attribute accepts JSON like so: + +```terraform +data "coder_parameter" "styled_parameter" { + ... + styling = jsonencode({ + disabled = true + }) +} +``` + +Not all styling attributes are supported by all form types, use the reference below for syntax: + +| Styling Option | Compatible parameter types | Compatible form types | Notes | +|----------------|----------------------------|-----------------------|-------------------------------------------------------------------------------------| +| `disabled` | All parameter types | All form types | Disables the form control when `true`. | +| `placeholder` | `string` | `input`, `textarea` | Sets placeholder text.
This is overwritten by user entry. | +| `mask_input` | `string`, `number` | `input`, `textarea` | Masks inputs as asterisks (`*`). Used to cosmetically hide token or password entry. | + +## Use Case Examples + +### New Form Types + +The following examples show some basic usage of the +[`form_type`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/parameter#form_type-1) +attribute [explained above](#available-form-input-types). +These are used to change the input style of form controls in the create workspace form. + +

+ +### Dropdowns + +Single-select parameters with options can use the `form_type="dropdown"` attribute for better organization. + +[Try dropdown lists on the Parameter Playground](https://playground.coder.app/parameters/kgNBpjnz7x) + +```terraform +locals { + ides = [ + "VS Code", + "JetBrains IntelliJ", + "PyCharm", + "GoLand", + "WebStorm", + "Vim", + "Emacs", + "Neovim" + ] +} + +data "coder_parameter" "ides_dropdown" { + name = "ides_dropdown" + display_name = "Select your IDEs" + type = "string" + + form_type = "dropdown" + + dynamic "option" { + for_each = local.ides + content { + name = option.value + value = option.value + } + } +} +``` + +### Text Area + +The large text entry option can be used to enter long strings like AI prompts, scripts, or natural language. + +[Try textarea parameters on the Parameter Playground](https://playground.coder.app/parameters/RCAHA1Oi1_) + +```terraform + +data "coder_parameter" "text_area" { + name = "text_area" + description = "Enter multi-line text." + mutable = true + display_name = "Textarea" + + form_type = "textarea" + type = "string" + + default = <<-EOT + This is an example of multi-line text entry. + + The 'textarea' form_type is useful for + - AI prompts + - Scripts + - Read-only info (try the 'disabled' styling option) + EOT +} + +``` + +### Multi-select + +Multi-select parameters allow users to select one or many options from a single list of options. +For example, adding multiple IDEs with a single parameter. + +[Try multi-select parameters on the Parameter Playground](https://playground.coder.app/parameters/XogX54JV_f) + +```terraform +locals { + ides = [ + "VS Code", "JetBrains IntelliJ", + "GoLand", "WebStorm", + "Vim", "Emacs", + "Neovim", "PyCharm", + "Databricks", "Jupyter Notebook", + ] +} + +data "coder_parameter" "ide_selector" { + name = "ide_selector" + description = "Choose any IDEs for your workspace." + mutable = true + display_name = "Select multiple IDEs" + + + # Allows users to select multiple IDEs from the list. + form_type = "multi-select" + type = "list(string)" + + + dynamic "option" { + for_each = local.ides + content { + name = option.value + value = option.value + } + } +} +``` + +### Radio + +Radio buttons are used to select a single option with high visibility. +This is the original styling for list parameters. + +[Try radio parameters on the Parameter Playground](https://playground.coder.app/parameters/3OMDp5ANZI). + +```terraform +data "coder_parameter" "environment" { + name = "environment" + display_name = "Environment" + description = "An example of environment listing with the radio form type." + type = "string" + default = "dev" + + form_type = "radio" + + option { + name = "Development" + value = "dev" + } + option { + name = "Experimental" + value = "exp" + } + option { + name = "Staging" + value = "staging" + } + option { + name = "Production" + value = "prod" + } +} +``` + +### Checkboxes + +A single checkbox for boolean values. +This can be used for a TOS confirmation or to expose advanced options. + +[Try checkbox parameters on the Parameters Playground](https://playground.coder.app/parameters/ycWuQJk2Py). + +```terraform +data "coder_parameter" "enable_gpu" { + name = "enable_gpu" + display_name = "Enable GPU" + type = "bool" + form_type = "checkbox" # This is the default for boolean parameters + default = false +} +``` + +### Slider + +Sliders can be used for configuration on a linear scale, like resource allocation. +The `validation` block is used to constrain (or clamp) the minimum and maximum values for the parameter. + +[Try slider parameters on the Parameters Playground](https://playground.coder.app/parameters/RsBNcWVvfm). + +```terraform +data "coder_parameter" "cpu_cores" { + name = "cpu_cores" + display_name = "CPU Cores" + type = "number" + form_type = "slider" + default = 2 + validation { + min = 1 + max = 8 + } +} +``` + +### Masked Input + +Masked input parameters can be used to visually hide secret values in the workspace creation form. +Note that this does not secure information on the backend and is purely cosmetic. + +[Try private parameters on the Parameters Playground](https://playground.coder.app/parameters/wmiP7FM3Za). + +Note: This text may not be properly hidden in the Playground. +The `mask_input` styling attribute is supported in v2.24.0 and later. + +```terraform +data "coder_parameter" "private_api_key" { + name = "private_api_key" + display_name = "Your super secret API key" + type = "string" + + form_type = "input" # | "textarea" + + # Will render as "**********" + default = "privatekey" + + styling = jsonencode({ + mask_input = true + }) +} +``` + +
+ +### Conditional Parameters + +Using native Terraform syntax and parameter attributes like `count`, we can allow some parameters to react to user inputs. + +This means: + +- Hiding parameters unless activated +- Conditionally setting default values +- Changing available options based on other parameter inputs + +Use these in conjunction to build intuitive, reactive forms for workspace creation. + +
+ +### Hide/Show Options + +Use Terraform conditionals and the `count` block to allow a checkbox to expose or hide a subsequent parameter. + +[Try conditional parameters on the Parameter Playground](https://playground.coder.app/parameters/xmG5MKEGNM). + +```terraform +data "coder_parameter" "show_cpu_cores" { + name = "show_cpu_cores" + display_name = "Toggles next parameter" + description = "Select this checkbox to show the CPU cores parameter." + type = "bool" + form_type = "checkbox" + default = false + order = 1 +} + +data "coder_parameter" "cpu_cores" { + # Only show this parameter if the previous box is selected. + count = data.coder_parameter.show_cpu_cores.value ? 1 : 0 + + name = "cpu_cores" + display_name = "CPU Cores" + type = "number" + form_type = "slider" + default = 2 + order = 2 + validation { + min = 1 + max = 8 + } +} +``` + +### Dynamic Defaults + +Influence which option is selected by default for one parameter based on the selection of another. +This allows you to suggest an option dynamically without strict enforcement. + +[Try dynamic defaults in the Parameter Playground](https://playground.coder.app/parameters/DEi-Bi6DVe). + +```terraform +locals { + ides = [ + "VS Code", + "IntelliJ", "GoLand", + "WebStorm", "PyCharm", + "Databricks", "Jupyter Notebook", + ] + mlkit_ides = jsonencode(["Databricks", "PyCharm"]) + core_ides = jsonencode(["VS Code", "GoLand"]) +} + +data "coder_parameter" "git_repo" { + name = "git_repo" + display_name = "Git repo" + description = "Select a git repo to work on." + order = 1 + mutable = true + type = "string" + form_type = "dropdown" + + option { + # A Go-heavy repository + name = "coder/coder" + value = "coder/coder" + } + + option { + # A python-heavy repository + name = "coder/mlkit" + value = "coder/mlkit" + } +} + +data "coder_parameter" "ide_selector" { + # Conditionally expose this parameter + count = try(data.coder_parameter.git_repo.value, "") != "" ? 1 : 0 + + name = "ide_selector" + description = "Choose any IDEs for your workspace." + order = 2 + mutable = true + + display_name = "Select IDEs" + form_type = "multi-select" + type = "list(string)" + default = try(data.coder_parameter.git_repo.value, "") == "coder/mlkit" ? local.mlkit_ides : local.core_ides + + + dynamic "option" { + for_each = local.ides + content { + name = option.value + value = option.value + } + } +} +``` + +## Dynamic Validation + +A parameter's validation block can leverage inputs from other parameters. + +[Try dynamic validation in the Parameter Playground](https://playground.coder.app/parameters/sdbzXxagJ4). + +```terraform +data "coder_parameter" "git_repo" { + name = "git_repo" + display_name = "Git repo" + description = "Select a git repo to work on." + order = 1 + mutable = true + type = "string" + form_type = "dropdown" + + option { + # A Go-heavy repository + name = "coder/coder" + value = "coder/coder" + } + + option { + # A python-heavy repository + name = "coder/mlkit" + value = "coder/mlkit" + } +} + +data "coder_parameter" "cpu_cores" { + # Only show this parameter if the previous box is selected. + count = data.coder_parameter.show_cpu_cores.value ? 1 : 0 + + name = "cpu_cores" + display_name = "CPU Cores" + type = "number" + form_type = "slider" + order = 2 + + # Dynamically set default + default = try(data.coder_parameter.git_repo.value, "") == "coder/mlkit" ? 12 : 6 + + validation { + min = 1 + + # Dynamically set max validation + max = try(data.coder_parameter.git_repo.value, "") == "coder/mlkit" ? 16 : 8 + } +} +``` + + + +
+ +## Identity-Aware Parameters (Premium) + +Premium users can leverage our roles and groups to conditionally expose or change parameters based on user identity. +This is helpful for establishing governance policy directly in the workspace creation form, +rather than creating multiple templates to manage RBAC. + +User identity is referenced in Terraform by reading the +[`coder_workspace_owner`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner) data source. + +
+ +### Role-aware Options + +Template administrators often want to expose certain experimental or unstable options only to those with elevated roles. +You can now do this by setting `count` based on a user's group or role, referencing the +[`coder_workspace_owner`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner) +data source. + +[Try out admin-only options in the Playground](https://playground.coder.app/parameters/5Gn9W3hYs7). + +```terraform + +locals { + roles = [for r in data.coder_workspace_owner.me.rbac_roles: r.name] + is_admin = contains(data.coder_workspace_owner.me.groups, "admin") + has_admin_role = contains(local.roles, "owner") +} + +data "coder_workspace_owner" "me" {} + +data "coder_parameter" "advanced_settings" { + # This parameter is only visible when the user is an administrator + count = local.is_admin ? 1 : 0 + + name = "advanced_settings" + display_name = "Add an arbitrary script" + description = "An advanced configuration option only available to admins." + type = "string" + form_type = "textarea" + mutable = true + order = 5 + + styling = jsonencode({ + placeholder = <<-EOT + #!/usr/bin/env bash + while true; do + echo "hello world" + sleep 1 + done + EOT + }) +} + +``` + +### Group-aware Regions + +You can expose regions depending on which group a user belongs to. +This way developers can't accidentally induce low-latency with world-spanning connections. + +[Try user-aware regions in the parameter playground](https://playground.coder.app/parameters/tBD-mbZRGm) + +```terraform + +locals { + eu_regions = [ + "eu-west-1 (Ireland)", + "eu-central-1 (Frankfurt)", + "eu-north-1 (Stockholm)", + "eu-west-3 (Paris)", + "eu-south-1 (Milan)" + ] + + us_regions = [ + "us-east-1 (N. Virginia)", + "us-west-1 (California)", + "us-west-2 (Oregon)", + "us-east-2 (Ohio)", + "us-central-1 (Iowa)" + ] + + eu_group_name = "eu-helsinki" + is_eu_dev = contains(data.coder_workspace_owner.me.groups, local.eu_group_name) + region_desc_tag = local.is_eu_dev ? "european" : "american" +} + +data "coder_parameter" "region" { + name = "region" + display_name = "Select a Region" + description = "Select from ${local.region_desc_tag} region options." + type = "string" + form_type = "dropdown" + order = 5 + default = local.is_eu_dev ? local.eu_regions[0] : local.us_regions[0] + + dynamic "option" { + for_each = local.is_eu_dev ? local.eu_regions : local.us_regions + content { + name = option.value + value = option.value + description = "Use ${option.value}" + } + } +} +``` + +### Groups As Namespaces + +A slightly unorthodox way to leverage this is by filling the selections of a parameter from the user's groups. +Some users associate groups with namespaces, such as Kubernetes, then allow users to target that namespace with a parameter. + +[Try groups as options in the Parameter Playground](https://playground.coder.app/parameters/lKbU53nYjl). + +```terraform +locals { + groups = data.coder_workspace_owner.me.groups +} + +data "coder_workspace_owner" "me" {} + +data "coder_parameter" "your_groups" { + type = "string" + name = "your_groups" + display_name = "Your Coder Groups" + description = "Select your namespace..." + default = "target-${local.groups[0]}" + mutable = true + form_type = "dropdown" + + dynamic "option" { + # options populated directly from groups + for_each = local.groups + content { + name = option.value + # Native terraform be used to decorate output + value = "target-${option.value}" + } + } +} +``` + +
+ +## Troubleshooting + +Dynamic Parameters is still in Beta as we continue to polish and improve the workflow. +If you have any issues during upgrade, please file an issue in our +[GitHub repository](https://github.com/coder/coder/issues/new?labels=parameters) and include a +[Playground link](https://playground.coder.app/parameters) where applicable. +We appreciate the feedback and look forward to what the community creates with this system! + +You can also [search or track the list of known issues](https://github.com/coder/coder/issues?q=is%3Aissue%20state%3Aopen%20label%3Aparameters). + +You can share anything you build with Dynamic Parameters in our [Discord](https://coder.com/chat). + +### Enabled Dynamic Parameters, but my template looks the same + +Ensure that the following version requirements are met: + +- `coder/coder`: >= [v2.24.0](https://github.com/coder/coder/releases/tag/v2.24.0) +- `coder/terraform-provider-coder`: >= [v2.5.3](https://github.com/coder/terraform-provider-coder/releases/tag/v2.5.3) + +Enabling Dynamic Parameters on an existing template requires administrators to publish a new template version. +This will resolve the necessary template metadata to render the form. + +### Reverting to classic parameters + +To revert Dynamic Parameters on a template: + +1. Prepare your template by removing any conditional logic or user data references in parameters. +1. As a template administrator or owner, go to your template's settings: + + **Templates** > **Your template** > **Settings** + +1. Uncheck the **Enable dynamic parameters for workspace creation** option. +1. Create a new template version and publish to the active version. + +### Template variables not showing up + +In beta, template variables are not supported in Dynamic Parameters. + +This issue will be resolved by the next minor release of `coder/coder`. +If this is issue is blocking your usage of Dynamic Parameters, please let us know in [this thread](https://github.com/coder/coder/issues/18671). + +### Can I use registry modules with Dynamic Parameters? + +Yes, registry modules are supported with Dynamic Parameters. + +Unless explicitly mentioned, no registry modules require Dynamic Parameters. +Later in 2025, more registry modules will be converted to Dynamic Parameters to improve their UX. + +In the meantime, you can safely convert existing templates and build new parameters on top of the functionality provided in the registry. diff --git a/docs/admin/templates/extending-templates/parameters.md b/docs/admin/templates/extending-templates/parameters.md index 6977d4d3b4c0b..d29cf8c29c194 100644 --- a/docs/admin/templates/extending-templates/parameters.md +++ b/docs/admin/templates/extending-templates/parameters.md @@ -394,544 +394,10 @@ parameters in one of two ways: ## Dynamic Parameters (beta) -Dynamic Parameters enhances Coder's existing parameter system with real-time validation, -conditional parameter behavior, and richer input types. -This feature allows template authors to create more interactive and responsive workspace creation experiences. +Coder v2.24.0 introduces [Dynamic Parameters](./dynamic-parameters.md) to extend the existing parameter system with +conditional form controls, enriched input types, and user identity awareness. +This feature allows template authors to create interactive workspace creation forms, meaning more environment +customization and fewer templates to maintain. -### Enable Dynamic Parameters - -To use Dynamic Parameters, enable the experiment flag or set the environment variable. - -Note that as of v2.22.0, Dynamic parameters are an unsafe experiment and will not be enabled with the experiment wildcard. - -
- -#### Flag - -```shell -coder server --experiments=dynamic-parameters -``` - -#### Env Variable - -```shell -CODER_EXPERIMENTS=dynamic-parameters -``` - -
- -Dynamic Parameters also require version >=2.4.0 of the Coder provider. - -Enable the experiment, then include the following at the top of your template: - -```terraform -terraform { - required_providers { - coder = { - source = "coder/coder" - version = ">=2.4.0" - } - } -} -``` - -Once enabled, users can toggle between the experimental and classic interfaces during -workspace creation using an escape hatch in the workspace creation form. - -## Features and Capabilities - -Dynamic Parameters introduces three primary enhancements to the standard parameter system: - -- **Conditional Parameters** - - - Parameters can respond to changes in other parameters - - Show or hide parameters based on other selections - - Modify validation rules conditionally - - Create branching paths in workspace creation forms - -- **Reference User Properties** - - - Read user data at build time from [`coder_workspace_owner`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner) - - Conditionally hide parameters based on user's role - - Change parameter options based on user groups - - Reference user name in parameters - -- **Additional Form Inputs** - - - Searchable dropdown lists for easier selection - - Multi-select options for choosing multiple items - - Secret text inputs for sensitive information - - Key-value pair inputs for complex data - - Button parameters for toggling sections - -## Available Form Input Types - -Dynamic Parameters supports a variety of form types to create rich, interactive user experiences. - -You can specify the form type using the `form_type` property. -Different parameter types support different form types. - -The "Options" column in the table below indicates whether the form type requires options to be defined (Yes) or doesn't support/require them (No). When required, options are specified using one or more `option` blocks in your parameter definition, where each option has a `name` (displayed to the user) and a `value` (used in your template logic). - -| Form Type | Parameter Types | Options | Notes | -|----------------|--------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------| -| `checkbox` | `bool` | No | A single checkbox for boolean parameters. Default for boolean parameters. | -| `dropdown` | `string`, `number` | Yes | Searchable dropdown list for choosing a single option from a list. Default for `string` or `number` parameters with options. | -| `input` | `string`, `number` | No | Standard single-line text input field. Default for string/number parameters without options. | -| `multi-select` | `list(string)` | Yes | Select multiple items from a list with checkboxes. | -| `radio` | `string`, `number`, `bool`, `list(string)` | Yes | Radio buttons for selecting a single option with all choices visible at once. | -| `slider` | `number` | No | Slider selection with min/max validation for numeric values. | -| `switch` | `bool` | No | Toggle switch alternative for boolean parameters. | -| `tag-select` | `list(string)` | No | Default for list(string) parameters without options. | -| `textarea` | `string` | No | Multi-line text input field for longer content. | -| `error` | | No | Used to display an error message when a parameter form_type is unknown | - -### Form Type Examples - -
checkbox: A single checkbox for boolean values - -```tf -data "coder_parameter" "enable_gpu" { - name = "enable_gpu" - display_name = "Enable GPU" - type = "bool" - form_type = "checkbox" # This is the default for boolean parameters - default = false -} -``` - -
- -
dropdown: A searchable select menu for choosing a single option from a list - -```tf -data "coder_parameter" "region" { - name = "region" - display_name = "Region" - description = "Select a region" - type = "string" - form_type = "dropdown" # This is the default for string parameters with options - - option { - name = "US East" - value = "us-east-1" - } - option { - name = "US West" - value = "us-west-2" - } -} -``` - -
- -
input: A standard text input field - -```tf -data "coder_parameter" "custom_domain" { - name = "custom_domain" - display_name = "Custom Domain" - type = "string" - form_type = "input" # This is the default for string parameters without options - default = "" -} -``` - -
- -
key-value: Input for entering key-value pairs - -```tf -data "coder_parameter" "environment_vars" { - name = "environment_vars" - display_name = "Environment Variables" - type = "string" - form_type = "key-value" - default = jsonencode({"NODE_ENV": "development"}) -} -``` - -
- -
multi-select: Checkboxes for selecting multiple options from a list - -```tf -data "coder_parameter" "tools" { - name = "tools" - display_name = "Developer Tools" - type = "list(string)" - form_type = "multi-select" - default = jsonencode(["git", "docker"]) - - option { - name = "Git" - value = "git" - } - option { - name = "Docker" - value = "docker" - } - option { - name = "Kubernetes CLI" - value = "kubectl" - } -} -``` - -
- -
password: A text input that masks sensitive information - -```tf -data "coder_parameter" "api_key" { - name = "api_key" - display_name = "API Key" - type = "string" - form_type = "password" - secret = true -} -``` - -
- -
radio: Radio buttons for selecting a single option with high visibility - -```tf -data "coder_parameter" "environment" { - name = "environment" - display_name = "Environment" - type = "string" - form_type = "radio" - default = "dev" - - option { - name = "Development" - value = "dev" - } - option { - name = "Staging" - value = "staging" - } -} -``` - -
- -
slider: A slider for selecting numeric values within a range - -```tf -data "coder_parameter" "cpu_cores" { - name = "cpu_cores" - display_name = "CPU Cores" - type = "number" - form_type = "slider" - default = 2 - validation { - min = 1 - max = 8 - } -} -``` - -
- -
switch: A toggle switch for boolean values - -```tf -data "coder_parameter" "advanced_mode" { - name = "advanced_mode" - display_name = "Advanced Mode" - type = "bool" - form_type = "switch" - default = false -} -``` - -
- -
textarea: A multi-line text input field for longer content - -```tf -data "coder_parameter" "init_script" { - name = "init_script" - display_name = "Initialization Script" - type = "string" - form_type = "textarea" - default = "#!/bin/bash\necho 'Hello World'" -} -``` - -
- -## Dynamic Parameter Use Case Examples - -
Conditional Parameters: Region and Instance Types - -This example shows instance types based on the selected region: - -```tf -data "coder_parameter" "region" { - name = "region" - display_name = "Region" - description = "Select a region for your workspace" - type = "string" - default = "us-east-1" - - option { - name = "US East (N. Virginia)" - value = "us-east-1" - } - - option { - name = "US West (Oregon)" - value = "us-west-2" - } -} - -data "coder_parameter" "instance_type" { - name = "instance_type" - display_name = "Instance Type" - description = "Select an instance type available in the selected region" - type = "string" - - # This option will only appear when us-east-1 is selected - dynamic "option" { - for_each = data.coder_parameter.region.value == "us-east-1" ? [1] : [] - content { - name = "t3.large (US East)" - value = "t3.large" - } - } - - # This option will only appear when us-west-2 is selected - dynamic "option" { - for_each = data.coder_parameter.region.value == "us-west-2" ? [1] : [] - content { - name = "t3.medium (US West)" - value = "t3.medium" - } - } -} -``` - -
- -
Advanced Options Toggle - -This example shows how to create an advanced options section: - -```tf -data "coder_parameter" "show_advanced" { - name = "show_advanced" - display_name = "Show Advanced Options" - description = "Enable to show advanced configuration options" - type = "bool" - default = false - order = 0 -} - -data "coder_parameter" "advanced_setting" { - # This parameter is only visible when show_advanced is true - count = data.coder_parameter.show_advanced.value ? 1 : 0 - name = "advanced_setting" - display_name = "Advanced Setting" - description = "An advanced configuration option" - type = "string" - default = "default_value" - mutable = true - order = 1 -} - -
- -
Multi-select IDE Options - -This example allows selecting multiple IDEs to install: - -```tf -data "coder_parameter" "ides" { - name = "ides" - display_name = "IDEs to Install" - description = "Select which IDEs to install in your workspace" - type = "list(string)" - default = jsonencode(["vscode"]) - mutable = true - form_type = "multi-select" - - option { - name = "VS Code" - value = "vscode" - icon = "/icon/vscode.png" - } - - option { - name = "JetBrains IntelliJ" - value = "intellij" - icon = "/icon/intellij.png" - } - - option { - name = "JupyterLab" - value = "jupyter" - icon = "/icon/jupyter.png" - } -} -``` - -
- -
Team-specific Resources - -This example filters resources based on user group membership: - -```tf -data "coder_parameter" "instance_type" { - name = "instance_type" - display_name = "Instance Type" - description = "Select an instance type for your workspace" - type = "string" - - # Show GPU options only if user belongs to the "data-science" group - dynamic "option" { - for_each = contains(data.coder_workspace_owner.me.groups, "data-science") ? [1] : [] - content { - name = "p3.2xlarge (GPU)" - value = "p3.2xlarge" - } - } - - # Standard options for all users - option { - name = "t3.medium (Standard)" - value = "t3.medium" - } -} -``` - -### Advanced Usage Patterns - -
Creating Branching Paths - -For templates serving multiple teams or use cases, you can create comprehensive branching paths: - -```tf -data "coder_parameter" "environment_type" { - name = "environment_type" - display_name = "Environment Type" - description = "Select your preferred development environment" - type = "string" - default = "container" - - option { - name = "Container" - value = "container" - } - - option { - name = "Virtual Machine" - value = "vm" - } -} - -# Container-specific parameters -data "coder_parameter" "container_image" { - name = "container_image" - display_name = "Container Image" - description = "Select a container image for your environment" - type = "string" - default = "ubuntu:latest" - - # Only show when container environment is selected - condition { - field = data.coder_parameter.environment_type.name - value = "container" - } - - option { - name = "Ubuntu" - value = "ubuntu:latest" - } - - option { - name = "Python" - value = "python:3.9" - } -} - -# VM-specific parameters -data "coder_parameter" "vm_image" { - name = "vm_image" - display_name = "VM Image" - description = "Select a VM image for your environment" - type = "string" - default = "ubuntu-20.04" - - # Only show when VM environment is selected - condition { - field = data.coder_parameter.environment_type.name - value = "vm" - } - - option { - name = "Ubuntu 20.04" - value = "ubuntu-20.04" - } - - option { - name = "Debian 11" - value = "debian-11" - } -} -``` - -
- -
Conditional Validation - -Adjust validation rules dynamically based on parameter values: - -```tf -data "coder_parameter" "team" { - name = "team" - display_name = "Team" - type = "string" - default = "engineering" - - option { - name = "Engineering" - value = "engineering" - } - - option { - name = "Data Science" - value = "data-science" - } -} - -data "coder_parameter" "cpu_count" { - name = "cpu_count" - display_name = "CPU Count" - type = "number" - default = 2 - - # Engineering team has lower limits - dynamic "validation" { - for_each = data.coder_parameter.team.value == "engineering" ? [1] : [] - content { - min = 1 - max = 4 - } - } - - # Data Science team has higher limits - dynamic "validation" { - for_each = data.coder_parameter.team.value == "data-science" ? [1] : [] - content { - min = 2 - max = 8 - } - } -} -``` - -
+You can read more in the [Dynamic Parameters documentation](./dynamic-parameters.md) and try it out in the +[Parameters Playground](https://playground.coder.app/parameters). diff --git a/docs/images/admin/templates/extend-templates/dyn-params/dynamic-params-compare.png b/docs/images/admin/templates/extend-templates/dyn-params/dynamic-params-compare.png new file mode 100644 index 0000000000000000000000000000000000000000..31f02506bfb22ac8fcc7e278d19fe8e2c40a3798 GIT binary patch literal 116646 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
lsnyOAEnPhDS$QLhh=1jfkfVR7BKdKVRw*J0B z{!Pli8HTYvt!r`wv2OOva2sh@KKa@k_V~))x9zy`z@OOpVcE}DNN1Ak%xpt=Wv@6H z>En4Q2Bno({elt4Z@!^}Q<2((dZUcfjqMjsddSx-Ym%68<;zZw_g8g_M9g==@cZ1S zBvrU>??RGaAW%)z1&)_{4y%|nydUxxyJIoAgrAR~+mX+{TgCo^ctgP}YzazQ=d8Tr zysfS@*Ei7^K91Nr1|QQ+<=Yr%jvf#4rb%vn5)L;Z+L0G8 z37l0iFEQFG!Q)34G=F|-Jvyr@`OJ?q&!*J5W{mldr2eeV3%d`iU%y?(+f|>x^U*hY z_t!O2)N*h`AufXM4T}QI=>x&3G8|?W4S*;pTz*EuS`4L5L9?}be>lKa?hZ-e4A@gX z7R8Qy>j%;4b9-4V)pq}Qa)^HzNfq$DW$-52ZG4@gJpvEigAv5sUhk3ic<8kXx z+a=Cl!8h&h(bHhJHs7))jvnck+iwL?Zl953Jk~?*zeR`c`wmX&ac7mJGxjf~y+{VX zNxpkACEy5NId-x^er_1u4iS9izs-7^2h619UkKU^C0XQs#8vsF_i~NA5U~TdmmxJ7 zB6Z=`Ig9*2qUut$31Q zG1hZ)%Er`Fx?Qc56Xy@Vd%r3oS;le}$8VyY^=fnV-HNChpOxiGEtWdi+NKmTnq0p+ z`zWKe6{+d;>cnAJ{hUQ2n8Hxo@1xWh1@@a6f+cFOrPpQW?}9>~9)*TS=mW z6HlL%ARUH%;hT_@7?D2pfw=`QyY5_{Wj4t>=O(h5RY0D!2EsN?ct_srz*NQ=fK&&a zp_zD}3yRBeJrj>=5v#WzSh8|Z&6s7RhhrWBLyH}nPHKyruQw02bPuk?zC3P9+Mvz$ zOmJSDLj;&kswYRH5S)a|Y!90#n|1>bY6ir!hylH+up$vrd3*t`Exk@k5>aI9xb89d8XcK(UEM;wen^R(P9_7d@ICP-chUalw(L6N)sxutzd3>{ zLo8ee#1c03Yx(ntqWwn0PDECYa|X9iAn-CRgQyzfZLo+>+1{umSy#8fW(UDU^x^7q zEN75gUT&N7uw_Ih$pBu^K^|?iDnVb}T^M)giK>S2&~sbfn-g)3Odb`PvD44op^*pP zuotpl5wPy-qV_vnb0l)HD2T9zHn6=?{ZTJ`LQq>HsxxXk54gsn+s3~jyRoNJd0W7 z3?ylJV6DVZzo&5WyV*N3<}M6iIh* zp_sj87s$^3?o|k)x)d#~u!V~bbL|GBXEP`K^R@PRi54yJpIQl&Z+wifm{;6X<+)bB z2^bYUNNE`L-x*5bF`Mj(Or1*CSpnL^hE?LYwv+-2RWm*jQ8I;ZT;foPc#knf@K`T1 zv`=^L_pNR_{j)#zYW}>C>gPrJ!p@vPv+NGS*v+Fs z@lBWG7?E=z2MGd*-{W@X_O6@tUUU>!=kZfwG4g4ElZvOo-S4o#wprM~x#UB$A&?=` z?a#0pu${mtPa?1VPmTogElJo&k}8LSLFESSD)QGK(%*Q2WBn|@MBQBv&%F}UM7{E6 zD3cN2p*`fV0p4i>PC6-S$qrrvQ7xbWsT75X_ZR>X z8se7O*j%|8rJY!31ZemdneX24qn{rf1}1Xu!$e^tSFy^*1CU5y7Hx}q0A84zkdL9m zrE2z8NcaH3N@4Z+WC=+-wQokPAAOPqU4HDX(OtnEplj_-G5Rzv@mx8B28E=ju{OcC3K5qA35oj*OKYF9*!gKGvKyuGV93Sz)uND9 z^ZhKe8uE@{&j@IobhtwFHIw>4Z;pA@sJXSw81<%fR?cD?|2`Lo>TVxVqm(cVfe1mP z3wfX2pr+c>im+QIncqAlte@g?O9TN%b{39=^BX~H<9q%aiTtY77vDQ*lujYj6+Hlu zRCQz97zd8=?**3o29E9g7Q21dw?+@psXHV6Pd$tDC>)%ar%PwUMywbhx$)C;x`Am! zasXjtO0oeG1424N6F?Cxz=RxIk;@NIKsu}+*@G9;Rp~HDbdqnnJc5OVj|>fRW8XOaL3ELNS(p-(h}U{&6;*WzU%z!yV(cpkj0o z(7D%2kn#>6mpq35L=h;iWv$VWAyzPubNWP``i7u0%R4@N(oDkz!BjdcZk-URRz+>B zWed!$Mr9R(5-wb*o0yP5HW%zz&CDCToF`8`HUL$AT7-y2oln3!AR!v_udueZQ$!2{ zf{}i|o0VF(_ig>fsp+=+tvmf3!l5HR;}ioo+I-=q@L+-hub7u9xOAZ)$j#46wZnYwi4of62gp{^td4bpenoCAayKgozQg?+SP9_%Vn- zx0Hnhg5D|&6T0Kkpl7$^ObD+UFYk-++m(k3g2i3fv>vC7yTy~z5euj&jxC6Y7{ zZpEBISNE5{QN9M!q0pg}DPhVGXGAQP?CK$X7ARRUWkrDhj1@Xz50$WIFi2>csQ==c zY5}RR5s?c)0&u*({t<~4;J^UgjiGlyIYdkrOn4bH%!(iZY?n$cT8MY#;G@z2i)gyE zxXHl!0elkVKD3Xhn-v(}T@k+lG&aM;0a%J`TWcxA004t+EXUgQ(UP^MOWt^L zr8EpP*|62WVGFH(fsTda6VnvRZ#QAj<02!`FHbqj=3MZ}`SY{izz}VaI4WLuRXh(vQB<+KkIPR8zP=#pC zj4!Y0l&v?v#>yF}9mqBgvEmjJsU+H{XMNB1+`1V9-5iVR%&-FL2cm(zR*dLGfeIA} zqsa%kYT#`oR;=nZ0DJJlSnQL8ILfYHAT8B^av+Mov=)=F3P(0VKyvv0H)1vwa&>XT z8rK9>m6#E?&u_9*9?35Kw9OLP1A1Ycta20r4qUK_Kn1Lt60gJ-^IvvgPZ-|T$`4|c zUHQx~-f-Jlv3a{rnRrFSV!9F-mydazv>&%dp3_*E4Kt{kHV(8uggF4aI&gUZ`6Ltr z8N$ebl0EbjlfTb;%6c(HuYH)hPdn^1>Lo?IWXgxtfWb=pd7AYSFw!e6jbB z((WRYi{adX#9}|n$DoJXO3mII>8!3S!H2?=PT{YEN}JSYe;6WVvNADfTyEdoF;WJg zwRQ@_XsiU!HhO>I1f)AvmmJo2GBR01FtF|o@?7({tHOFw#NvahZ(pKYOJV=SJ^xN` za(+?O)kLa(Yy4q&^ZqSEt3rlCgi{amO$|hUIzdE%0vcOeI0&MgDB!3jz)fXX(QcSV z2wd-yzGdW{w$QsW|BLSjM#Uyg){tJZcJY=M%2W1vMR9cvSF%6Ey_ZJDKYclIRTax| zdBJTUT%2BwKop>DMrIx7sXh^Mb41Wq5+lx5aeCcF7#hQ|W#-@Q;{BrzWs8opEItTm z#=@q19ww)Qm*3@gUZ~dn!cM$ zqio1ajt0n?rBQjPf0*bx8xd*~BW$ORa*zGQO?n=5Ch79os`dQ3zWWP7hk}`J-U%)X zf0W2~mc2|7``;8>+J@-?MbO~4#)L)^B+UKW+e|L~St5!N=P@t0E~3FOjh753f)8e? z>0DTobYfRwih$#B+AtO_0vb_Lx0#+fDafn zVwQ3(;T=(8h=6ON6wyE@tujGUzN@^W-N{Bi`G)hWs74K-PDsU&bSl_s-x4ghm75vQ zo?~5gmLM1(>+h{jEtfR)vrSP=aRtr+ujUNsJ-~{r-=XrjJc)F^z4zL*wKNG&@|-gg zuPeSc-qkf~?1tFq@La0F6r{33Z4?3<;5gEw1?!Ka)MQNAMVsSzb68cjlT1kU8@Qh>F)o8B| zzAn>v5n1Pb@~bK@R0G&8PYN?TnEu2C4BU@2MWVsQ&!q;q>5Sp8XD_3j06x%u*qbbj z#&DTqt9E=8LK2xu@|sEsFoIjs(eu-kx(=M0KNX(Garki0@Ax6CR(-4W9M(^>uc$)d zT%$m9)+)0+d994hCG45354^HE!9&Eg`Q9*QoeAo>jZ__A{4NEMFbu}a`|Y`;ZxGM} zOr?)8(;U5#tH+_>5B5805fHiCgd}EK~P$-zoE&S^Q2> zxG;$KPE7E2c+}$+3rA&Zs3*YEdX(}$W|zWhRr)gT@y;_jx%q0wpnzK`OHwqRzcUba zHQCjiv@_q05=67McXP>iY^#3me{?l#FaF}bW_7K5rzw|u3d4+kg|LS%k=?**1*h6V zmg@CoJ2Q1fi=PUwGrDlNJf)4Q;O?en7HfMf!rZb$%HjH{$p3U8k`(%Xzo5iPxg-Tfn5&G+X&mV;%bWQE)Dze*eD;XOuPBi3`VPucD7&riTGu_5)r^tg8~ zijL6bTj4u!xSDY-)}8Kc4rpv-&lG-2|M`O3%_u^supfIFX3@F5M;PYUE_#_G77r0S zh-$Uls`4Gb!79a`BIZfERHk$}&0PUJ^lQ)SuY_&Osf+Gx_v`-60fJ^o-m47+0rzNY zF5S-x?Z<*DriKSf1qGo|{HvmSE{q~)*+(HwJ?jj2tb=(=HLL`sy9_JT{>Y74g9!;# zSS`q_073=XdBKqzV@<=4*%7TlFVarHq5=lhurE0XnF!VZBPP_MWl1kEb3nT4?V*_& zV|V~pk32&PvNl3?tRZ4!EQ9CK%=CJk05~>5`kV$^BJGg_JZ#+JtJkO?h;Soc12+rx zP*X5%TykC$B2=wfAKI>^ZHN|YmPk~7`jc6VLm@E7N}SevvCQK9Vk5K7

U&NXO2Q>hVf*q(>fh+f0MG$R2(ryv4J@Td5@+8yA^w9hO}4} zM8)!!H`ozi0jAnQo!b~SGXrS!kmw-Wn!oOhWd<0e+S9{>0()DgaN|=Nb2$12 zm{wjDC&wq8B*Qv|0o~0P{VyRH04BCyCCH?0THZ`9hh`r&Yar+1{bO(?{Y0yd{%zUVKk+Jy@@sD zbBA5-@k{2ksN3X|)2L8F(}X5;RG3b`6sYLz^{T`HrYh6cvA?r>$WkmNg*y%^%0)#T5XuG zPb>8$$X@aIr6yO5IVHcV{QLbWVg_)v4*J{r$X{Td9&~GD`6kkHvCb))EOHL+<}RJe zQByYAytnu~rno|3e(6}cf3eiQumT(vBk66Z@Y=+~%XQMM?YW%~$zS%~b&HTEj|NIN z<6)jwj-3Liz-TuLuU&Av&yf0PL-O3bt@9yc^FB-*R4MMa<36Tp$MtnyV5yL;T-I6n z5c=2R=N-|0%Ub*sR_$wO?esXEYo}d4AJEcXn$V=4Yoc`;_y@fr<;CsC^ogZDLGJ=1 zyD^$f1fL-^J7+T6Zj91^H{QlNGhcr0;2L`~P8&$+f+79EW)qZ$gyWz66+VUo4yNHG}w2BuBwxk9gDoyE&eiLHnx`ekS?}tl^FWqGb)_?8dNP1b!kfh z5?qFe2ZV9EI6ZYw<3WW=a|mw6<`3kcc_;zsC%Az&@(q1o1QleQZ>6ORBMKEsk3~g0 zAxvwp+Gf*Sc8XguggG#+H`9uM#0whmFS8^+b ztmLO$;~emej`j<@^OXYlEp}rtv4j}I^PZUN#9ku4QIfe3Zv~SL>yYQiNPNP%1X@YX zTh*UD)jYmM_F(_Ky>4d8Jq?q6+*OoI2(b}kN?7Py_9CgXZP~{C_)^1)Jp93*`0Yf9=&SmauXb$s#Dx+APqc*5_ z%qDGbTiPz1se8-8HtFJS9^wxyX~N6-fwqCiEMB!2?q@rhTn{2t=jU9<@+qPwok9U3 z4(h%66;I2PwCTOQoB=03-uihbraV-@o^GC#rL**c!kvQ?pCmP;K=rPJLlAXuO4E*f zY9^Y?gstldhAZxDcIy9i|=`x z35osSG>(a=DKEiFM8q(Nb`7j>)!J@B{CSyZCuc%02%+#inzz&(a!9lEPy)Yvyy8ck z7xlZ*zN^JV&QxT`HmJoqwV%S2!<&Arz7{Ht3HD45Cb>h^iN+{7dwX@DMG37v#)tpP z%%|O{e62o`BK?L3Dug!AHTMShjR-V!LFyS$+54Qj*Wp(Xi<>I}<2nqq#4`S09AUCq zx$;qZV&J0MIH?O!B%Pc$;7nqC0FwwDN$i5In0WtT#cHC{Vh~*a3Cpw#_R;}^#v<^= zp7(vupu?)k5jMUR5NB__H!r9b>oR&&76%Gs>P& zvB?-lwwm`q`%Q;2(?p)b+(OSc4FAYS`x2V*6^*mb=4*J{wqz+BYdD*@AV24ZwKQ9T z4Tg3%)*8HK@B?_7p=rWYJ(l<$2}&#mf9?|MVtkNZkg#L&iEnuWx;7)>+g}Zwdl9)O ziz$Q2Yk+B?j#-sOL5IyosDUP)vdLA?R9ridn=0x)Wg{*#~3%!84S>Uu+OGI4Q@hQ6Sb+>U9Ay8|*7 zV~b`YuwOr!{#}Q#MO;j1XS}&k`<}u~oFN~om0z{9#l)6znTGfiw)zU~641>Z)UWk8 zlKvCB6dAFq>*w?K!jl+sINv7}8QR z&R4ALLdW@$uDr+a!C$Y5s76<8)0fp{1fgKqTJup0yPgZGVQxW{@0Ak5R^m)S@KqHA zk4Q;9%d5oKuW1s^*%q1{_M|-ubQ+uH4@w8d(iUe$eUJ3q&{fS0_DFh!*TO{v~4>&;72*GBj zwWNp##x(ueuPEV%;PJBri8G#=Q{B(~#dUnU4I(0hSaWK*NFFPpO=)lS{Cz7W5+$@N zfsGhf6|iY}R`ZhVT-!LU9ld{tEIV#fBb1;>3nW%tlA65RMyC8O^Yfx7Ilm=}jRxB8 zA7Us(T%3s_o;b;o4ccytJm%Th1RPCFoCsyYSQVz&^rKWZ44hbNxZywdPXWZejJibM zcm#-dZX~HC`8jzl-}6{rixfqu&%Mr20d@e}2V}rvF~`7WX{jh>C^rwn@DzpkHD82LUf!`&DEe(gvip!z{tk-qVbU6_wqOL*|Hp=mROY0u~9*_sByi(U}i!FFs? z2HcSj0>EdlP4l>M?7sDsTU+roL4YPY8%?(#h=UB}@SP5t%q9Z*Zo4Ry50?#}qM2E6HVU_)^7TwJF^ z5yMCEKRuJF%32b?Cuh9Hkj*BcL5*2czM8Kd09lz@S6FAGi3qmSvp*~$cmnWLFclWs z6VGYW>mWhM`Mo?hf=N1vOaP-I#~2bYDKT6NhbV&U3EyCGxK{}8VlxZVu6Hu42tq41 zH!O$y36lGZKBQ}>un4Ph^)eAHnqv$O;_UMGTce^k_@bJUiEcs2Y(ZubdCQ*_nJQ)F zn`K*Hr(sO3p=DbmW|IXCyoQ7iG%2vMPF2FNw^aDib^BkqxIbstl~()RM1I^V^JE8X z@MQq~KT~_29)|%YAZp3QNz)?8A2NV7MShx~J(^ztSek^P;d{0?sUy9M+$72#1|Mpw zL7-R`8-N?!2aUpyZZvUn=SUAkg>u>H7|88Fu#p}_fh+|-hFMeY!kYUB1|k}}hS-EG z_xF7AiEiSTihmn4eXu^%In1(X>&%iWSi2RxwooXQ8-J-UdDyf~IdzzvKaV+l4|$>Jh;V>-KaF^1{VC?PTVow=m=vG<`1soB=rqd& zl6)wA?*RVf0B5kYpXaOe5%_;!z>M0NdS3gMLeQ;`aa1Yc;0qS~e_ms+P-5~nV*HU} zVx4m*f__ToUCrU3d8@ZL{+g#m6QO^9z@RJ`Oi!ICRB;~kp2$AU{0(xpny=$Qnn=Ys z4nA6Xu4_<+9~0UfH`)-=lMzaYw+d+=QraQlCaMZ&l!p*B@$rIg&1xjwk_b_Sl+IH8 zR~M)VjsK?5Q270XuY=MHn-g(wZBlWE#CA{`m*vcoSs&k|bcAP%w55-+%~C@a!(Z;` zY!($^8y)4|e2NjwueZnQ^SjO=WBG%NQeJiBx|7 zkF2*2YO9Ohg%g5nu>!>l4K4+WI}|BSai_QyDDI(HX|dw2!HO1#;z5ejAO%_^xVsbJ zrtk0j?!7a2&P@KvOp-bKWbd_}^+;rub`>FD*a-?+H_J5Cn2Ch8L!wVM*sH}UOmvR<^EgkAMx%F#XEKEDt z_9nventqxITF^a-N6#fyf7#lMLN?z@P)WQgxxYMoN&a*{!^5AYX;Fmv6U?{v7_Drx zn?=2EJ-;|tG~02ptr2rqq=zhPk!LJm2n?Xv47W*NO?+2BG$tbhe?pXu^Y-)lh!`A9 z=fE^?juJ@BSJ|OKT2-Boj}}@v@KJ$pU_zSCaQdX=56V*&hQ$fHqo`;HSaJcW?Di!8 zI$jICcpFQ@5uC^KP?rWX86O*qkfyfHWw}$rV!-XsfLDQOu&(dfg+5I4mtFTK_ky72 z2g{?v2+O~fB7C}KZ*BBBn}!CDiLGp!?^{yr{?2LD?R2qonx8i5p+VECKXe|$@d`|T zn~|(gMC2jQ?Fv*k2|aB36`jDD!ORuZ`pzt$G2+Qu-mpFSWkV|D%uTJ!=O1g`Ujh!^ z7I6%k=43wZ^B|dBX6c;K<=ZIEbAkU#KIo zcnwawQ5CfAA@1&L0(|G~e^anVC5xSn2klJ9lk}QE5Hmzzcd4|9I)1Wzj8_ z#%V~R5KrYIop(KVGLT6mIIH#OcQz(8HZC$NS9>%DMgOs{A$8VpT`72z`?WFaW44>` z#CYx1@euD_+z;!lK)JHY$)S#*+lZbbaD-`;=M#OIJGXTmbxM(7BjImOLkU`<>rU~j z`jL!9)i^wzl2V*cxZ3uhaJ@{3_``^KlnktfU=2KhKQR%&)qX!*QP5rprV%lt`n=%% zH8@T^zdBL!Vdpd-RQk#!C8GE&gr0rmGGdm?OH_be`UCth`oG)92mQypXw*WF>BqkT z9=h)r^uEZKYSnn$fQpz$+O|@a6HOo~mE5Y$aksstu+~j*RMJsIH;}S;5Y~P>iz%Ux zWf+A+Eq?4-PjUbz$Lfj_Q7!#HM#n!+M?y`A3e@-rt4u9Q*b$zYoFW+WNP!pc^PuTa^ zb*Srk75?H&n*Bz8sg95B0=jKFq0ugPPzYN`)L7PR#7id3D7fy3oTXU`ipnpybE{im zT-t=_UOKQG8JH=M`_o(7=vk!)!0o+sDORXZ%hHR=5Hg_v$2_C)cKwq-hRy=}`{RLO z{}&MDgl$UxK1YH>waxt-`lTrLn>Ug#L=DPom8kulJZtr`QbpaH;yL#|rE-mjJ1G$A znOf((wtD^FX_Ur;QHUB@&kEvLsN4AnmQCb35liaN;>|htLsIeIkS8vDk@_#Oa;fOIyZ9dW?;FjidV5)sp(==hG_ zgXTrL;8Sy{?=8raAwbD*k~5bf={-o7phbH$nf(Bn+wl(bu`XXo@X@QA!y@vWaK1^R z0$DjdPv5-bitxw$#I-Cv;DJ(ifN~XPj=wr9hHBCCuwg6Q3=dL-}r*b%dm;NtfJxs4d)7`ync8eymLs>*DAQg`guEsQ{KPc zcxeAIv*^yp@WBoWW?~H3E>AL7-fL06a;`Yd7B+lp{ z?w21WR5SQq{PnsrMWB+8gRU1ny6}h|5MhFDyibDGsF$&YmVAr2cplH~q#8rl;>0$? z&5^4VmMDR}x4APwydm8gz zC~=wzB|6~|*59ue6I7y1qs&QtrhQldSNN+$Zw#NKDu9C*8+l#nr zRl)EfKLsOh%89V0Xu-bU*hTg$@9#E}^h->hfBwiE#l5i$;UEzEJk0)Scj}`L4Gk2O zd@2%}ismu*7LFR$&uB%wWgh-oG3D%$9Ldcd1|L=ZR%Z9#es)w0Sbnw4AJ|9qEx@&` zbZmMt;aftMir2Ssi?X?#q$t^w8&zUvd#@&=gHE;Zt1v>*V&vqbd^4GZ zUuwqJ+z(xn4^z-ERW>xTQ^d911`q|<&ZlXA&&VSA&(E1 zYmu=exU=CB0p3w4x=Ga9U|bXi9!0v&14_R(SyCR1Kq=lek@5dco!hT_zaSzg%(2by zclBYPzB2Vb1l_@ELe8A{LBE?!jqA}vt=-R3#{^rCr=Dk}2fn;f3gyT~i!I2<@6+Z5 zPicMRdBQ>bL5>7DAPR!ld9)5J*$ujIBC&#&-Ga}ll^@S}^w$(lNfpz=Y1snm$VPW- zO>p}I`~Vx3G)$q2pB06x%(oR-=7yurKc%iqlT?DNtG)BeST}rwKO0+BOe(jf=8{6xLJq!%N4~sa}EC1^$Wm z@w=kzIAXCtO;Y8XD2a*t@Cb)9D(n7^PkHj!*+ zjZSHXx%qTU4nYn#a!h)vtlBHMrGRCHg?_ar2SsJQfyM9nt#*k{Ug|c(4Ij{cN^n(sT}&v=@!u0`#$N~u4y`7p05WuEr6!oL z=UC!6q(W~@42OHNJz~){PN!H?ukG4eOIarVYeMQ+-O9a=nYt$&6H0tN!Q9oD9lR~b?`5jp{R4tinOU=VKyNf*t49_Qf#eCrvtd>(oV6Hti0Wxyb@| z3B(g4ds>6Xq&TQtBunxA8xv)ooXwlQXv^mqnRpm=T~+&Ak=svDW8CCWGYYh0>cXv= zt)rE!mk4AIUizrOnV;fW`=^y%X|Mdp_M~Va6Go;82KTFOjgXT-X`E z4KS)oFVZoOJ6xj1Jl`emZS#R0+PFq$y6p9)E=v)&UG5PR(kExerb^lf$*7do89}($ z=Q$qqrFz~G{GU$$f5RDxIRf;o(UdoVY>gi-A+-W1h&#W#HK-#Q%KE|9Q<6!g!8yjlE3kN81Puy3>Q3*OZlG z7uVc#pHoSQs6La_q0ajt*FUsoc~aj6KS4y*{%M}y4 zJH(pahJtKFJzm>0W({svwJq8anj<8GYH_hjSIo!C9oa!o-H;Mdeb)%CIj?~juxM@g z3%bkGdn)QNnzCNyrq*N>N8^5yvMZA-q=Sim7_osE#eppu zvR32JSUIlfA5Ac?aX4*7S|qKL9(&A6$OW4rN_|uN&>&blY!u2#iyb#&B>MqfWb-A9 zd4NkgG^||o=j=Vo9|&Wzq8DAl=Ljy6oX6fgW%oTTo?61OVSbzk&K9xw!>9SJTl4!r zj(T3TZLk8vB(Qp2SY7S-RGY5TnOLFKxZP;F>J z+BjBo$EW_naY2`3^#?6JgztOyH|uOhJgxmT>fs(M-9S9Ci^y`@k&uV1Gr9Q_zN{w( zjB9!SHk<$Z0v7;!H?}h&Xb_L!Mm=on@owfb+u8i*WQ}Es&&QQBIylqh#f8YQC!5)O z$qa4ts=%OEtu&><;J|ez`tNcT!=Bl~aDRYgl!@2gESJSn9ja2bTpNhBM7d0PqX(qK zanpN@Q3iC`oTa+0tc3Eu>-)s(c+Q%IpP)ElCc&j%8kfV_!59`5&h}d!hi4*Se$-Yy zU6_$Z+?RL%Z!7=5;_-ZUk)!=~p~CV!{a0rAdL+sLDE($M42v)`Cn(O7CH|rR9`=tQ z1ZsVs=ka5s1BE|ic`_{izw7G2_HSL`&4L#V8GM4jHh=3xr25&R@4slR;ZDPy$dC_u zEqY}KjXL6%l45DEn6fetzS#hLY9h7v8s;M85FU)DZ+`3iJuE(g8hTg;<0bAsr(;=u z2kJ6zK71NnvA z79y0f+q5rsmm16dYHiMPK@e8Ja)}pp{nP}s$aT5%Qt~1Czir^(R$%`L?Pt&5K07(f z!jONRWGmYfjXDXTprtG0@T;Mk!)i=7&JcAXGP7A8za~{?@(E&#t&Xh1(TNdK-|A_` zw_>uf(m}DzD>G<+6pP<@oLU>sHT%R9_QD;S6Zg|lENKhHvBUvm_p1%5L{Ug{zXp?mBM zy3@%mDhP_YwDj27)a1+WQ(ybrX%%45;-<9?t~EC>piJd7O)SHsm2{qoMNyM8u`ryQ z+rMQ7-W+xG(kK2_EnHJ>ie5oOyiS>Zl0yNO{~S^yhznS~K}(!DTp#9t^DQRMZhzhM zCV%a74^C{sQ^xuE)DwO5=N<9%T5!S&A7wLT$@!xx%e5e=v=teo6b9?I#(u*iDD?%) z^wq4a8ghv$%T6xJ%}0U6_lV)<*|D3_(hjpy-;RLN4$d02k>3`z9nQp1v(og}Q6BTo zzpM3(P1>Ybt55RA8l7`(tT^4z8irB{8u9CBrXg0cE3~gPNQq9ZPkSQ&II2mevo=gF zeJp@QVorY?R;T&h3AqH)hO7clQJ|*}stnZUz<@9Fc*U^Hn;EFcb@@)tMEu%+LwKO= zZ;r67>>icRjTLJZy*IT=>A6pfcHE5cw)px*1j;WE)abHVwA=kfHt5AwwTk(r zO31m)k$Ab~aybL*m$Ceo{Q?tPO%ik%P$j`WlbbBY^v}XBK62Bdd;7-C z!k4rz@PODLuew@1@bfi_@fYXVt!^_J^>(U>u9A`kwNckB+AE(6QD{q=y9Y4ca9*)6 zLar??nPx{~T)OiR2P>?uf|3GZLezzkZ${#itw93V5ng2|j+#G-yEc&!-&w()2=A`h zRGeQo!o4Pq6R2$8tZ27@zrhOuKUX@Omy-_u^>1|fKbLfR-S+q) zYklK^3JVM~P%hL0`xj9YtzOLb%=G{hPqG z`Z7*i-!cgm0%8PiZ_LN17*DZ6F*vgNUJ&V;!mr$><2|F-JU{r?506l;9EnSM zF_`uul)lg-w66MOmTAJ(WOukee3NVTu96eO$yrdkX!vF%%dS^&rc7UuH2t>1Q&6Q- zN8&;?xKTRw*%H}8Z(hj!*qgzF^Wj1_(J*@Gu7POE*ms7{Q zHV*%{;JC%81=qKS^}kd6Z)F68Z~?f$c!(f?S(@Mpeha4RYW(Nt42f=pbsUYK)62;8 z418A+*dPNiS2cH^TS}~v8wUe!!i&5lKIiVG5;KVa!`r*7qqj)w2@;0{LCZyvTDzLW znmB)9BA9ikZ}MR1t0R0e4xSjc>2J#4;&Q>3fN$BZXxKuH!!frnjsj1uE`CZ_?Ie`^ zrWZYlvm2Ifo4>ik<$8cv!OwX&$V)vt->6jZAOhcQBw^+~ndDYAt8I%!LEfoDveZ#* zjtitl%G=WlUA@Df-AW2ou_T)&(G~96)g4{ax`UQ7o_>qPD{ z>fU|BdRX55d|pIN;01?mc)l!v?02IR1*jCoamC5Ioh}`nn6h+zqJSl=-v`D-iv+ks zk2lad+MOz7V2Gb$%bJZMfinudluwAp()NOfl>(ve zd3VUIUa#M#rN@JEgX*+ne_tNG%$1e^-a&gLS$37gA^bL0bdVPq1Lxbb| z@USY4&a3b3kyIN|^ucq(atr3yy%hVZWW%Ui_sofM#C)3SUdpV{T4p3zIA$P$w||o!rS7MsB3vI2n&rNatCqjh22aNBY@;Cmo}Pzc3zf!a2_)kWCdB&nHHx9(hz>YKWL#G0bUaE-W*UbapP z`qrQqaJ5F#eSh28RLe-7>}qM$rn zp}%f&*LPiyceU0-iM7`U{Rk9-RhiRG0C-4}x=A`l8GfWwA?O1iu`E$W6y6I$7Flw) zfL(sO@rFHAEc>F{UR87CP!c%m@h0!_dvt%$)iOo!-Lpe&ucXi@iYJ{+mX_ZCodbH$0O4V~vn9jMDn480*i{N@0VTcwC*ZN%Sq4$>7kN zN{Czj1|kW$88LrWHW2u7D>*rjlPK?TZNm5lxMKcjZr%(cKoz#cwo3y1;#WVGBbJf3 zzZFyn-&(KsghtUg`yQ_pxFz*k2H$*Dq{sPZR|0#hAz?E>df0xZUPM4zg^~b9)jaIz z%RL6)!$KamLX3EIjd4kUdjhFg1uy+As7 z#e6kVUK=4bMA(3xflSa#?}9#4QcZxkz2;j>WPx&AGb;C3zaVtL0WpmC!v2!Q0lx|$ zJ5;_NhXF~Vdg47z(BuQ58taPBO#BpSg7Irj7V~P`x1yNh2ARxzzevOs+OQUKBSD1dzIq3ZXRfKPjFpR-pimeerz2wDSOP zf87T4`W!6TTxIW^{4Fp03u?-ugj)IB(4u#6LoEEzuUmU@K(is{pL z@oo|h7wJ31VyGkre1#cOZtG-$uBFaQk@479i$3Oa^#SqaV+;j$tC}X-&PgCJWmG&3 zVf_8(cemq7U{FS9yo}rRcz>kZmC5T4m(R)%ynDQBs(M-rKdDd*Ax9am zy1GZAOmIkJP&&29=P}Z}n+2Cizk8t%$M@BXqK+Sa366%`zlse*yL+*ytAT#FQDE0x zUEniOT~Nh*cYljwo(#k#8tKW{FIVfP3k2&>NFlEPQcY6l z`@ghE6J{-YTfW}L>Sg%P|IXmKD9%>~lr}iwNO#Fg48LDRb#olaXv8b#n*>;tl3w5b zrV0T&l~@cMCHzjI$_a@+gT43f_Bp?=hV0L2RghzG)Sep|>RM_i8`j%pB!>wcc5Im? zu@;aHCGrL113*}WywsP_&?WXTEdLz*r<}k%;c~gghUww>QyLyITfftohZiaff73V? z|EW68x94G}=;!swKR%F*8>ouacrsnZJ&q|iKn_K%3W%U<* zm6GK@`AxUN`87ZSiIO=!lS087q_ZKRmX^C)>Q7RHz@? zeI}NU`$#qB*3omvcYz3l1L44Jx9gjUkm~5!(pNV>>p`ScUkum^)Ej^#9;deN_eZaK3^dr`!%44b95mIL~_~qxBj>kX?XuAlAd+OgY<}KmLS-%?(4FfzH#5>eVwin@^`@rOFmJf(MJey$ z!u(+dOt2?Z*^HzV{)(ygBRG?bt^OQ!^okM`I#+*2ZPvs20BOd9y1c0)_?2qhcS3lv z$`+*0_bPYs@*sceZ+142>x5PC0~&+j&4_onyBSViy8?vvI5t<5BfBg)->lARkPviG zcGA5D$jF`ob}x1Y{Ro{UW{Qfq*!xY*BU@~Bvf7VG%0pUjqx?uum~;aDuXddR$s6gQ z4`m~@Z&viY=ce)8FyuATd3%`Wu~mLjSPr7hkvoo&XA@C*_xoM4DEHAS(Ww%3{+0W~ z;SIg_(DSp+v3gxC$c0bm87*iKWiUkK@|NPBU_Eh;rYxkoJl=8zAIk)OUJJMA=!@Sm|i8Of684~HUneN)4}c8=zV{q|(~+AeiA%8w|? z5Q_LWr3cU`kH!l9rCc&PPR$7X=VsflxbV>{?B;BX`V7;)1)WYp2l`4deaI0_6si<- z*tvJuZM~WsaD+3W&-t6rAs`Fgt(&}pNXZqfmPs~@axvYj>5{B8YBU1%hq|r*{K^~L zd(C^%R*o3Eaa~v$v2C7s_+{r}VFk#Sl>8LTiXIm&k84s*#;f_<>3O2jscC(ow|wH@ z=G-IIlbeFiNt@9GuNIqJj8#7bBIn%Kgery6tPuq$vI{TmL2TCS7gW#_!8frNx>Ag^ zUehGaF3aqVlo_pLyK<+wl?k~5bf0v(Lv+Gf|5PuELEp)BG+{`i2-g8u2aPjx zAZ;00V1wtG!b~&#RE)WYxINV$Fl(r0F$!2g!BNHy6})aC+B<-z-<76ZnREg(WA|8> zQD`~VoyNNwH?n`XuZs?qvt+Is_w+c3)LO`LJ4jL1%k_emfxU3Gci)wy&BD2K7E$5@ zoxo6E3H=HJr|{zu1F!Pr3r53Mk)o|#8a3Y(ebi%DHtX@;QtRi?Z--qGStMV9VG$DT z_Pnk%uV|0zSG&}Kk;z8UW`=dgqtO1Tpkj!`%{qA#?qGww8}u{=3Dqe@j)^{E zph_EDId6MJd&g zlhG9g;Z!QBebYKv;!6@5Pl{5Fy!ZaOO6ruK5{|D>k(!k+7`T8m`8=QLSXF+CgO;L+ z5|-O->bdp^>BQ%l`L=E*Z zpOAf7++L7>bo^mR@E5^G2jaAb9F2{2CHd@A(CDehRy*z8A@s||)6?fcJVYz$V@;4N z&jl#L>jde$IcV?^W<)q%d1Zac#w`78dEImbX-y8KACbFBh@46}!NGF*z?VbBkA z%fY0Pq@|?F_GQYP#FjfHV5ZZ__2q1ZYNMx)0`8jgqeusZyU0$` zaZTZlB+n3Y!`H&GEoP8q?*<19z(qkr(dgC(b-7;V3zge%cOF#}Hv#cmmd|jHj@Djj zub7a10z8^bJACwc__h3DWDFDfYs#AKs@RXmA^HkZ4n5YYZvgQJ-tLsbmXTx2lr0Je z7(=7W_lwIJ=-IJGfUTOK11DQ!-zAkZXNOjwyrri7nDhA1nBpxav}w)?IuU&T|nFJ+j$%uY>1GbpME_B?8V??yVr&JDgl2SDuJa>nEmQIk`oqi5x7y3aQTlq#zvwAIsm zW@}JS94`uqp3aU&%gW+aZnC_`Owy~B{~{?dQiG&)tF?vr6Q~U56jKcKFhK&qWZMpj zPZPaq;4D^}3zdD$08>8IYT~?5@@Q;$Ak{48aK-zL znkwMI7~UA@;nf~?qnDNnx}ofD^pZXk2+liv1b6;dk`S2 zF1RWYs7?bYUUQC5sppac9C_*fcUml_k)p~}y<*VqzLbN}B!p~{Es7|F+3ggE8hHcJ@rcy+AbdgU*dEeK5%k2%Yi~mEbN6+E_s;1`h+wydpY`*Xzv@KsK232~ zK3SXN2$ed(MrpD;YP;9suIzw;v0R-*vZaR6v)V4J=_VqVX$V~YwQ7lN4FdExBD>p3 z=&pD*q!ZI=?gSu;{UB+jC@q|DD>H?}Gr_WsZ=4Px0h9C-MVIq434hnbYmSr^ZDOl; z*t)L**?_@+t^f47jB3-;zoeIp!QSy3B&2O*^fKgny9tY8J3pNH%}K<07DUdcclKf7$O=V&{0&0&%r-^$;h6-SH+p zYwlaR>o@1N!IL;OE2T9<*(y_`v30~~Y^*^aiwnI;>!2THh~UID{g))m-bwt-l{(m2 z_Cea4lFM1xP2=V3%}DVwp>ddX>7LCc?^EFihZ3@UDL!AJ^AY?8e>D_m#+lSXu)VZX zt!bR1fE*bvA+!H-cfP*VMRG%4cT^4yDeM;AA-VthUCQa4Rz^dz7mXfu!CBeYB52%{ zy5py)hIee#CsA=f18s?_9KDGXriU6!)&E5PUPDWAM#U1+Y0shTeCq$g%$R-6pSEGJb4p8!cDx*h)rE=c9OhX(d*kx6NsG=}PU?ZI0s zaFhTCl(PR^yUOi9l##BXIr6-C@dA@((2Rd}0Bd`;q^j~4tH$WZcVk#m19ZMj9Q84; z{>t&6(y@u2Pui}Cmw(S@6=QQ-c$?*+LFHmViIA+J%wlcn3OV zv5gWso3m95bLj@fW6h>Nyz9N$r>tY##Y^m7b4wk!tT}H5cdUyG1DX$;LgL!DS!^;5 z;J*#L6iice-7W{c4&bjm58?B}6S(35J9BPhI6bAF-aX+bq`gg5f1G3bPKggh{7$X$ zgxn^(Yh8~do#?}ZQNtzrA}O`j_n+0owJIW(Cdn3lDLy$heEe-4A+Qs_{v{INCu7bl zf9X4;N_FltY2`&{&lk13`hE~a@$eW6>9Z*>BH$0_^Bw_1)Y$yuC3rNCcbmMh zL$73 z=v>zz9@8;Rk4a(9COy1<;<#+rT_+{hfz03tBi>2WYqF9K{c70xT&=A=d@Oi8ZlXRd z5k&y;h*dJ4Y4E5z-_Qz~?j^rFD_NErVglP6fC$H8?iHF#LziMZG8D3rznIDy-qGvCO~mMfu{uoNBsChI)MYZ=%_BPfJzBeBL*= zcT{Bvub6#BV5`=@bN<)_xF!W(X;!Oovtl_a(oUyluSrubgg+>WO%7aJ(SS0gskfym z;Tsw5@tx={8JZS0M7P($!l!-2Q7LrG_%6988uj_z0mN_X%P#xNp<%DF!UNlR#nZ1# zB`?^lM0ul8u^Jh<5?NZ7O1!%1;t)Dp+@j6leW@JVpetT~q?(Ol7~0BQ2wi8v!d(E- z@?6SsGP%Mk!|y5Ky>By7^||B|dC_SPtzG6+F>b2PKPx)(UjD!YOU`@!tQG^6Zfzv` z^{#BWPhEk(!o_Hgst(&$)BF5rx)#2m##$)ip)xC=3mw157`Po}vzO~iG6~yh1n7m+ z8K8rZ7Vi>+WFcJpt3TGKFnH!{2R{>3RE8_!;uEb(1jMgk92;~qL`hk`NpD9mK`zRt zN{kHPSmM1|ZV;YfSwo@se<_=s7vFVf@x7Jg%p*?4!PGX87O?_ZP$@1bbpku5G1w$5 zGH|dQdMSYG?Sm#S+do~UPoa08%ApZm7fJSErOQc4Gh5{FfqLiTUmJz@%Thb64$7lN z`y2PaCdU$WU2L0yh*nIf8qBF+B!FEn!@p8oSit4|C!b0IxGg9r39%y&lYi+L>u`6A z0di`gFy=TM%((Bd(Re2Y7zKxwZelL>K47!S)bA0#_h0V*3=`e}e9QB2rsY{yr#kyz z^m~V_r{Qd6F&(F`VixA z?R7Zazm0ic=p;$@iCt7}ZZ`1v(Be7LKzj{j*5^>yl@8oK26AB8oLxglBsNZw*@kbuX>K3!H#zrE-H)(bkv!i(06c%R zQZpenZFxa2SgGik$rO_g{4ST`_dZgIzim?p5Ok2(loK;x&?~ z`8-8#+5egR(&fWPj&35}Xl9DZ^V_|eEa=nPsGK`)(;t+RAR6H0O57#GG_ym zPisTQ2v>Ub?geM}ERfv=L*v~C$U3<)F9XRFOjJ9c#EoDj6Al9^>fc3q84Efq@oSp_SvO&r1cb&7qB5;i@qpC3%OgA#GKZIKukx(yBj7J^0-zbL z1~EDXweT4(v^W$Qx`5`Mf3?$Y@H?{&FmEfLwvW!lzOcfFazmV;6J>{$CXMjn{&m0t zFvbBino{>Mva|8OiZDKkzHBS_llwnHx9y7sooS*Oz-H^}ldI znPL^01G=xiR9{auRmK@mHQ0rB!scM>u^#5z{K;Q})yx$eBYn<^h6kh>6P#;y0_Dx6F?9z8HgzohCZ<5e3t2hN@w=Kl&Dm% zyG1UZVt&zyJXXT9fbycJUw+=;kgZwjP+b5d$$stztc?6xAIt|#F@y{QJuq2Gb43|9 z7{p1RrN&axOb*HW_XE0jP-;gDZPbv953JHQiN;1q!ma*iL%QnUBv+5lz5!*h#UXW7 zA;7De>sj?uIsF-&m|30Ia~N~Yj@O#O#)6BDjWKiat!t_z5KReDMr0G}oqV@;6(a72 z%QTuN6AC0*kkLr>waiqqrsQ?Uzw}x1vRhdH|yy6kcs%vmSMa)$9kHA9T&;RVZgft-s;_|#Q$p@3*D6+x zJlfHNIFmghN9~xLLdr*J(C_`W1VTJ!@TH|3m}jXKme;Vdr<8hS3!Q$*{owC+Y^Ca^ z&$Q#&bmp(4pO@;{5?`L&tzvqs<~x9MEeIjC@a4AS7-p|gGuXvZGIH=qrFzrxlbdM= zk=^+>YeilkUFjks%544UU`u~>74DK$LUa@;$9dJjv-4KrYLMsP3AET$?cLJgDTDdM zpR>N%;04D0H$R;BWIL79uBX3TPH@YK248lhO*m{G)sN`rNm**{DT~!8F7Pac_>utz zfB9q}KL&6Mb`%jlMEy=BD4EtQI_>GP1{Mh)*2DO)fweezZ!t~K=%Qf|K&>JL873hU z7P6igTbZ!UUlq5S+CPV@ztCx@j_={il9{z1U#$t#{ZLU|Jkgm=$q<7~E<{g{%7ELJ zulwab9jGL(u5ExMAT7Whf$WP9bZ+?5(hHKONWk&jMybh2 z8jp~KIz*JZxC~FFySO-u)FC@Hf{i+ncQm~7W;5%JT)qhGIwPIeJv8+DezZVDJ7qVk z&^cNR|25Nzd5e8$Ty~x<=`(wk)?aJ#+Oh^<3`oH4xHY=exx=039_jn^U^!nDQNZ~) zJXILXI|*$2eiDyE>0ZV$+M+#JbGIAw`hUDaC3!LGZeGCMq_WvpQBNXg=$KNI$44|GVoBn3$N`EaM1F74OOpVY(b(q7%?1_ZyNO5mI# zIVv|66>s>EmQyWdHNF$Slf-yX~B}xUwyj z&KT}U*~z`vxZigYrBxB)$zb;Hm>@L0k{2gh``y-ja_Cqpy-4BF`1_o%lAfMkN`FU* zpO=Rlj@iut$>Uz;MSV<^W@ionAPrEKm(lsLpJRh| z6aYh6)T#a^(;Vd!8A-N2UG|OC~GmYtP7g1L;zjNy$*fJ;;(AYb5+TPk$G&-5Xd#**46{I$(wrm%5=1F~e zbroC{Z~MS)R%3=MPm3JMce!V}C_LWBFG%uyF!Q@1r>>n;>7xgXsRw(CqIfBe;L)et z29#jb;4uaSm~aG)dp%#&M$>kHu-#@FH^_YMiAVvQ%eq4~Xws#q2cB{nS*t`V^#Z>e zyaPxV84rJ86ph{{Y>T66D~Fg&e^AA(>4{VZu(K=mTQ)$>;!$+xlDoE66u6U^xSwLk z%g+V&qJ*yb`Q0=*6VzhzTFK(Sbx{>f@3Ts?n<69)}!-6 z#}&@Ak{dSB{mT3kkj2jUwyJP2Y8~F5324@wUF`_BYltlw-j;I&m&GJBpLlK@Sc-Fn zb5;uid3`QuHR8ovG{oYKm&whrYkEYw&)c9QCgy){k%`H>4<%FGR}$`Z+gbOW+{N`r zb+8)`(d0WBew4S;n0Mn*-7x5WisXF3?M>L-{-ve5^^RTVM0gXfiurT(P5F26zYSX9 z_d^a2J9g|A4z|PE%RyE*(7PWOcdGX}lDT$r6NmIQ^n@6w44=bm)~pA5b#8)E60c+G zk};bT@cqf#{C&cYeYU62AR6O&JBF_ z?eV6B7-mXE_Ve)V`~<`^O>=WCl zZ?$7HI6=5P7r@hO&Lhx1_~rLMTAp;sJFi?Pt7W~QlcMDaEeH;kCkkSvP-wO#6%By= ztQNj4aUBg=t0WQ((EJ&f6fCKKJAlrYH71^2dN8rm(6S|Q1o%Y|p*+YKQyOg+)QahK zu4*aUa;D6bLzft6XHj-q>;AOy8D=p2w0O@myQH&gQdGdp@7*nmX^e;A=r!` zzRE^QNY8caH9>?EXUG2aJc2qPFXt#Caw3jCj|l@#CM|*8y~BYsf6q@VxMY4qCLEwR zoMN75YY4&wO6u5tX(8Gxy6{B$clJeuYNnpW4l<1Gf(VBs0QZ4wwrNAf58Le?U5crm z>AadH=bvT0+plTZ=@4VYiZg%sf zy&vr>^_=Z(`$zQJ_^G|9zmP7QxBeTF47-SNh@ceO^PEoR+k?T9x)XGo<19o_bhxLp zfS(3lxhQ~U3()cFCjt6#=+aEM(bE@t-09K@QCsuU=i9XZenEsL#I?0eVaw85#{<75 zKWr(SJBwa0RoCj@9T=;5hPQ0sw|cj!1{_eNciJ)jE@irS&xnTPXb+la{^G>G<9P{~ zqHM(uVcZqDD87)v5T0Je@_aGLgfL1pgE zF%n-vLTJQCZpf~XxJEzUw{u$E@H56d);Kflz2|v8^*9u6%u+K;5B<+)Ba9`?79&msgUs?*o~kHx z1EH9iS;&aD513pl2b)f%w=00-U1j2Opyv77-4a)XzJc2?K6e}9G(I{ImrO$I=P&ek z?2+0)5td5#-{_IKApGc5KpeKaYmIhVm|@4JY){R`9bVZrBo!J_JxKJ zbA}tsd(Ojl1?%h|b~o12WJlA4`4fu_Bq4+QN4ouSKJnwu;x$BeSOKH(voNKGjg5rY zS|kly3Tj9XYut`-U}V;@1;Wdc+u1su<@1*b4?x7(gW)&T(b$ny(-ppA$~$$EoMDdw zSS65k>TSkLR#m&VtZ6cWGsRBLMze{%4k>K|?g0DpCpf80{NGJ@nY99LN1W@ozczDq z8tmLiA%*gBXRBU|}M!gcRlYEue^d?Pj_Ej$*e%YH>ZcX`+V26>%Y$IXt_X zNXX=I@*O$u{7iFmppc~68OgHV9iM9gmu&3`$wR|KBcA9aGN~IwG(E67qHJ@of(TuXN$SV*o{I(mRgVq>isa5>EiUaU~5OP2#CB}}v7W*H+TTI7w) z*sR;!dL)~SsoS$8eLX*#qwGsMio1AJBgb3JYt)m>GN;dn9LvURQl6U6iQ8t#VR{Ux z0}8qmXN|a`Ie1)vGN%y63VZinZ@#W&?uS$W409lEp1(m3oV2s%3Sju*QXcM~Bx>ir ziRP2v-kvwluIs*snY&Z@v%iw>jR(vCOq*J+_KXO$Q+)cHOU~{xr_9%CH}+j*J=

uMXnh67Bwqj5#rdyPOjU{7B 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 Imoy3dKP@Uv5&!@I literal 0 HcmV?d00001 diff --git a/docs/manifest.json b/docs/manifest.json index 9b85e634dce14..65555caa0df4f 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -527,6 +527,12 @@ "description": "Use parameters to customize workspaces at build", "path": "./admin/templates/extending-templates/parameters.md" }, + { + "title": "Dynamic Parameters", + "description": "Conditional, identity-aware parameter syntax for advanced users.", + "path": "./admin/templates/extending-templates/dynamic-parameters.md", + "state": ["beta"] + }, { "title": "Prebuilt workspaces", "description": "Pre-provision a ready-to-deploy workspace with a defined set of parameters", From 8202514ce0c978ac15d1eb1fd49ff33adc3ad77e Mon Sep 17 00:00:00 2001 From: Kacper Sawicki Date: Tue, 8 Jul 2025 11:02:58 +0200 Subject: [PATCH 03/61] feat!: add ability to cancel pending workspace build (#18713) Closes #17791 This PR adds ability to cancel workspace builds that are in "pending" status. Breaking changes: - CancelWorkspaceBuild method in codersdk now accepts an optional request parameter API: - Added `expect_status` query parameter to the cancel workspace build endpoint - This parameter ensures the job hasn't changed state before canceling - API returns `412 Precondition Failed` if the job is not in the expected status - Valid values: `running` or `pending` - Wrapped the entire cancel method in a database transaction UI: - Added confirmation dialog to the `Cancel` button, since it's a destructive operation ![image](https://github.com/user-attachments/assets/437aa5f4-5669-45b6-82a0-e46f277114bf) ![image](https://github.com/user-attachments/assets/423b5cb1-a4fb-4a10-933b-c1c73f4b838c) - Enabled cancel action for pending workspaces (`expect_status=pending` is sent if workspace is in pending status) ![image](https://github.com/user-attachments/assets/32d35ff1-12e6-4f7b-9f6c-fde9da9de6cf) --------- Co-authored-by: Dean Sheather --- cli/provisionerjobs.go | 2 +- coderd/apidoc/docs.go | 10 + coderd/apidoc/swagger.json | 7 + coderd/database/dbauthz/dbauthz.go | 49 +++-- coderd/database/dbauthz/dbauthz_test.go | 55 ++++- coderd/workspacebuilds.go | 142 ++++++++----- coderd/workspacebuilds_test.go | 194 +++++++++++++++++- coderd/workspaces_test.go | 2 +- codersdk/toolsdk/toolsdk_test.go | 8 +- codersdk/workspacebuilds.go | 24 ++- docs/reference/api/builds.md | 14 +- scaletest/workspacebuild/run.go | 2 +- site/src/api/api.ts | 3 + site/src/api/queries/workspaces.ts | 7 +- site/src/api/typesGenerated.ts | 13 ++ .../WorkspaceBuildCancelDialog.tsx | 32 +++ site/src/modules/workspaces/actions.ts | 2 +- .../WorkspacePage/WorkspacePage.test.tsx | 51 ++++- .../WorkspacePage/WorkspaceReadyPage.tsx | 15 +- .../pages/WorkspacesPage/WorkspacesTable.tsx | 15 +- 20 files changed, 555 insertions(+), 92 deletions(-) create mode 100644 site/src/modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog.tsx diff --git a/cli/provisionerjobs.go b/cli/provisionerjobs.go index c2b6b78658447..2ddd04c5b6a29 100644 --- a/cli/provisionerjobs.go +++ b/cli/provisionerjobs.go @@ -166,7 +166,7 @@ func (r *RootCmd) provisionerJobsCancel() *serpent.Command { err = client.CancelTemplateVersion(ctx, ptr.NilToEmpty(job.Input.TemplateVersionID)) case codersdk.ProvisionerJobTypeWorkspaceBuild: _, _ = fmt.Fprintf(inv.Stdout, "Canceling workspace build job %s...\n", job.ID) - err = client.CancelWorkspaceBuild(ctx, ptr.NilToEmpty(job.Input.WorkspaceBuildID)) + err = client.CancelWorkspaceBuild(ctx, ptr.NilToEmpty(job.Input.WorkspaceBuildID), codersdk.CancelWorkspaceBuildParams{}) } if err != nil { return xerrors.Errorf("cancel provisioner job: %w", err) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 1ee6ea77af5d9..433a3797daaaa 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -9122,6 +9122,16 @@ const docTemplate = `{ "name": "workspacebuild", "in": "path", "required": true + }, + { + "enum": [ + "running", + "pending" + ], + "type": "string", + "description": "Expected status of the job. If expect_status is supplied, the request will be rejected with 412 Precondition Failed if the job doesn't match the state when performing the cancellation.", + "name": "expect_status", + "in": "query" } ], "responses": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index b55a08caa8ec6..adac5bf344cbe 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -8065,6 +8065,13 @@ "name": "workspacebuild", "in": "path", "required": true + }, + { + "enum": ["running", "pending"], + "type": "string", + "description": "Expected status of the job. If expect_status is supplied, the request will be rejected with 412 Precondition Failed if the job doesn't match the state when performing the cancellation.", + "name": "expect_status", + "in": "query" } ], "responses": { diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index eea1b04a51fc5..b4162f0db59d7 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1182,6 +1182,27 @@ func (q *querier) customRoleCheck(ctx context.Context, role database.CustomRole) return nil } +func (q *querier) authorizeProvisionerJob(ctx context.Context, job database.ProvisionerJob) error { + switch job.Type { + case database.ProvisionerJobTypeWorkspaceBuild: + // Authorized call to get workspace build. If we can read the build, we + // can read the job. + _, err := q.GetWorkspaceBuildByJobID(ctx, job.ID) + if err != nil { + return xerrors.Errorf("fetch related workspace build: %w", err) + } + case database.ProvisionerJobTypeTemplateVersionDryRun, database.ProvisionerJobTypeTemplateVersionImport: + // Authorized call to get template version. + _, err := authorizedTemplateVersionFromJob(ctx, q, job) + if err != nil { + return xerrors.Errorf("fetch related template version: %w", err) + } + default: + return xerrors.Errorf("unknown job type: %q", job.Type) + } + return nil +} + func (q *querier) AcquireLock(ctx context.Context, id int64) error { return q.db.AcquireLock(ctx, id) } @@ -2445,32 +2466,24 @@ func (q *querier) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (data return database.ProvisionerJob{}, err } - switch job.Type { - case database.ProvisionerJobTypeWorkspaceBuild: - // Authorized call to get workspace build. If we can read the build, we - // can read the job. - _, err := q.GetWorkspaceBuildByJobID(ctx, id) - if err != nil { - return database.ProvisionerJob{}, xerrors.Errorf("fetch related workspace build: %w", err) - } - case database.ProvisionerJobTypeTemplateVersionDryRun, database.ProvisionerJobTypeTemplateVersionImport: - // Authorized call to get template version. - _, err := authorizedTemplateVersionFromJob(ctx, q, job) - if err != nil { - return database.ProvisionerJob{}, xerrors.Errorf("fetch related template version: %w", err) - } - default: - return database.ProvisionerJob{}, xerrors.Errorf("unknown job type: %q", job.Type) + if err := q.authorizeProvisionerJob(ctx, job); err != nil { + return database.ProvisionerJob{}, err } return job, nil } func (q *querier) GetProvisionerJobByIDForUpdate(ctx context.Context, id uuid.UUID) (database.ProvisionerJob, error) { - if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceProvisionerJobs); err != nil { + job, err := q.db.GetProvisionerJobByIDForUpdate(ctx, id) + if err != nil { return database.ProvisionerJob{}, err } - return q.db.GetProvisionerJobByIDForUpdate(ctx, id) + + if err := q.authorizeProvisionerJob(ctx, job); err != nil { + return database.ProvisionerJob{}, err + } + + return job, nil } func (q *querier) GetProvisionerJobTimingsByJobID(ctx context.Context, jobID uuid.UUID) ([]database.ProvisionerJobTiming, error) { diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 006320ef459a4..bcbe6bb881dde 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -4655,8 +4655,59 @@ func (s *MethodTestSuite) TestSystemFunctions() { VapidPrivateKey: "test", }).Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate) })) - s.Run("GetProvisionerJobByIDForUpdate", s.Subtest(func(db database.Store, check *expects) { - check.Args(uuid.New()).Asserts(rbac.ResourceProvisionerJobs, policy.ActionRead).Errors(sql.ErrNoRows) + s.Run("Build/GetProvisionerJobByIDForUpdate", s.Subtest(func(db database.Store, check *expects) { + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: o.ID, + TemplateID: tpl.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + JobID: j.ID, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + check.Args(j.ID).Asserts(w, policy.ActionRead).Returns(j) + })) + s.Run("TemplateVersion/GetProvisionerJobByIDForUpdate", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeTemplateVersionImport, + }) + tpl := dbgen.Template(s.T(), db, database.Template{}) + v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + JobID: j.ID, + }) + check.Args(j.ID).Asserts(v.RBACObject(tpl), policy.ActionRead).Returns(j) + })) + s.Run("TemplateVersionDryRun/GetProvisionerJobByIDForUpdate", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + tpl := dbgen.Template(s.T(), db, database.Template{}) + v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeTemplateVersionDryRun, + Input: must(json.Marshal(struct { + TemplateVersionID uuid.UUID `json:"template_version_id"` + }{TemplateVersionID: v.ID})), + }) + check.Args(j.ID).Asserts(v.RBACObject(tpl), policy.ActionRead).Returns(j) })) s.Run("HasTemplateVersionsWithAITask", s.Subtest(func(db database.Store, check *expects) { check.Args().Asserts() diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 6c3321625c9b3..c8b1008280b09 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -581,10 +581,24 @@ func (api *API) notifyWorkspaceUpdated( // @Produce json // @Tags Builds // @Param workspacebuild path string true "Workspace build ID" +// @Param expect_status query string false "Expected status of the job. If expect_status is supplied, the request will be rejected with 412 Precondition Failed if the job doesn't match the state when performing the cancellation." Enums(running, pending) // @Success 200 {object} codersdk.Response // @Router /workspacebuilds/{workspacebuild}/cancel [patch] func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() + + var expectStatus database.ProvisionerJobStatus + expectStatusParam := r.URL.Query().Get("expect_status") + if expectStatusParam != "" { + if expectStatusParam != "running" && expectStatusParam != "pending" { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: fmt.Sprintf("Invalid expect_status %q. Only 'running' or 'pending' are allowed.", expectStatusParam), + }) + return + } + expectStatus = database.ProvisionerJobStatus(expectStatusParam) + } + workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace, err := api.Database.GetWorkspaceByID(ctx, workspaceBuild.WorkspaceID) if err != nil { @@ -594,58 +608,78 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques return } - valid, err := api.verifyUserCanCancelWorkspaceBuilds(ctx, httpmw.APIKey(r).UserID, workspace.TemplateID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error verifying permission to cancel workspace build.", - Detail: err.Error(), - }) - return - } - if !valid { - httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{ - Message: "User is not allowed to cancel workspace builds. Owner role is required.", - }) - return + code := http.StatusInternalServerError + resp := codersdk.Response{ + Message: "Internal error canceling workspace build.", } + err = api.Database.InTx(func(db database.Store) error { + valid, err := verifyUserCanCancelWorkspaceBuilds(ctx, db, httpmw.APIKey(r).UserID, workspace.TemplateID, expectStatus) + if err != nil { + code = http.StatusInternalServerError + resp.Message = "Internal error verifying permission to cancel workspace build." + resp.Detail = err.Error() - job, err := api.Database.GetProvisionerJobByID(ctx, workspaceBuild.JobID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching provisioner job.", - Detail: err.Error(), - }) - return - } - if job.CompletedAt.Valid { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Job has already completed!", - }) - return - } - if job.CanceledAt.Valid { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Job has already been marked as canceled!", + return xerrors.Errorf("verify user can cancel workspace builds: %w", err) + } + if !valid { + code = http.StatusForbidden + resp.Message = "User is not allowed to cancel workspace builds. Owner role is required." + + return xerrors.New("user is not allowed to cancel workspace builds") + } + + job, err := db.GetProvisionerJobByIDForUpdate(ctx, workspaceBuild.JobID) + if err != nil { + code = http.StatusInternalServerError + resp.Message = "Internal error fetching provisioner job." + resp.Detail = err.Error() + + return xerrors.Errorf("get provisioner job: %w", err) + } + if job.CompletedAt.Valid { + code = http.StatusBadRequest + resp.Message = "Job has already completed!" + + return xerrors.New("job has already completed") + } + if job.CanceledAt.Valid { + code = http.StatusBadRequest + resp.Message = "Job has already been marked as canceled!" + + return xerrors.New("job has already been marked as canceled") + } + + if expectStatus != "" && job.JobStatus != expectStatus { + code = http.StatusPreconditionFailed + resp.Message = "Job is not in the expected state." + + return xerrors.Errorf("job is not in the expected state: expected: %q, got %q", expectStatus, job.JobStatus) + } + + err = db.UpdateProvisionerJobWithCancelByID(ctx, database.UpdateProvisionerJobWithCancelByIDParams{ + ID: job.ID, + CanceledAt: sql.NullTime{ + Time: dbtime.Now(), + Valid: true, + }, + CompletedAt: sql.NullTime{ + Time: dbtime.Now(), + // If the job is running, don't mark it completed! + Valid: !job.WorkerID.Valid, + }, }) - return - } - err = api.Database.UpdateProvisionerJobWithCancelByID(ctx, database.UpdateProvisionerJobWithCancelByIDParams{ - ID: job.ID, - CanceledAt: sql.NullTime{ - Time: dbtime.Now(), - Valid: true, - }, - CompletedAt: sql.NullTime{ - Time: dbtime.Now(), - // If the job is running, don't mark it completed! - Valid: !job.WorkerID.Valid, - }, - }) + if err != nil { + code = http.StatusInternalServerError + resp.Message = "Internal error updating provisioner job." + resp.Detail = err.Error() + + return xerrors.Errorf("update provisioner job: %w", err) + } + + return nil + }, nil) if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error updating provisioner job.", - Detail: err.Error(), - }) + httpapi.Write(ctx, rw, code, resp) return } @@ -659,8 +693,14 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques }) } -func (api *API) verifyUserCanCancelWorkspaceBuilds(ctx context.Context, userID uuid.UUID, templateID uuid.UUID) (bool, error) { - template, err := api.Database.GetTemplateByID(ctx, templateID) +func verifyUserCanCancelWorkspaceBuilds(ctx context.Context, store database.Store, userID uuid.UUID, templateID uuid.UUID, jobStatus database.ProvisionerJobStatus) (bool, error) { + // If the jobStatus is pending, we always allow cancellation regardless of + // the template setting as it's non-destructive to Terraform resources. + if jobStatus == database.ProvisionerJobStatusPending { + return true, nil + } + + template, err := store.GetTemplateByID(ctx, templateID) if err != nil { return false, xerrors.New("no template exists for this workspace") } @@ -669,7 +709,7 @@ func (api *API) verifyUserCanCancelWorkspaceBuilds(ctx context.Context, userID u return true, nil // all users can cancel workspace builds } - user, err := api.Database.GetUserByID(ctx, userID) + user, err := store.GetUserByID(ctx, userID) if err != nil { return false, xerrors.New("user does not exist") } diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index b9d32a00b139a..ebab0770b71b4 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -573,7 +573,7 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { build, err = client.WorkspaceBuild(ctx, workspace.LatestBuild.ID) return assert.NoError(t, err) && build.Job.Status == codersdk.ProvisionerJobRunning }, testutil.WaitShort, testutil.IntervalFast) - err := client.CancelWorkspaceBuild(ctx, build.ID) + err := client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{}) require.NoError(t, err) require.Eventually(t, func() bool { var err error @@ -618,11 +618,199 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { build, err = userClient.WorkspaceBuild(ctx, workspace.LatestBuild.ID) return assert.NoError(t, err) && build.Job.Status == codersdk.ProvisionerJobRunning }, testutil.WaitShort, testutil.IntervalFast) - err := userClient.CancelWorkspaceBuild(ctx, build.ID) + err := userClient.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{}) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusForbidden, apiErr.StatusCode()) }) + + t.Run("Cancel with expect_state=pending", func(t *testing.T) { + t.Parallel() + if !dbtestutil.WillUsePostgres() { + t.Skip("this test requires postgres") + } + // Given: a coderd instance with a provisioner daemon + store, ps, db := dbtestutil.NewDBWithSQLDB(t) + client, closeDaemon := coderdtest.NewWithProvisionerCloser(t, &coderdtest.Options{ + Database: store, + Pubsub: ps, + IncludeProvisionerDaemon: true, + }) + defer closeDaemon.Close() + // Given: a user, template, and workspace + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + + // Stop the provisioner daemon. + require.NoError(t, closeDaemon.Close()) + ctx := testutil.Context(t, testutil.WaitLong) + // Given: no provisioner daemons exist. + _, err := db.ExecContext(ctx, `DELETE FROM provisioner_daemons;`) + require.NoError(t, err) + + // When: a new workspace build is created + build, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + TemplateVersionID: template.ActiveVersionID, + Transition: codersdk.WorkspaceTransitionStart, + }) + // Then: the request should succeed. + require.NoError(t, err) + // Then: the provisioner job should remain pending. + require.Equal(t, codersdk.ProvisionerJobPending, build.Job.Status) + + // Then: the response should indicate no provisioners are available. + if assert.NotNil(t, build.MatchedProvisioners) { + assert.Zero(t, build.MatchedProvisioners.Count) + assert.Zero(t, build.MatchedProvisioners.Available) + assert.Zero(t, build.MatchedProvisioners.MostRecentlySeen.Time) + assert.False(t, build.MatchedProvisioners.MostRecentlySeen.Valid) + } + + // When: the workspace build is canceled + err = client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{ + ExpectStatus: codersdk.CancelWorkspaceBuildStatusPending, + }) + require.NoError(t, err) + + // Then: the workspace build should be canceled. + build, err = client.WorkspaceBuild(ctx, build.ID) + require.NoError(t, err) + require.Equal(t, codersdk.ProvisionerJobCanceled, build.Job.Status) + }) + + t.Run("Cancel with expect_state=pending when job is running - should fail with 412", func(t *testing.T) { + t.Parallel() + + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ + Log: &proto.Log{}, + }, + }}, + ProvisionPlan: echo.PlanComplete, + }) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + var build codersdk.WorkspaceBuild + require.Eventually(t, func() bool { + var err error + build, err = client.WorkspaceBuild(ctx, workspace.LatestBuild.ID) + return assert.NoError(t, err) && build.Job.Status == codersdk.ProvisionerJobRunning + }, testutil.WaitShort, testutil.IntervalFast) + + // When: a cancel request is made with expect_state=pending + err := client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{ + ExpectStatus: codersdk.CancelWorkspaceBuildStatusPending, + }) + // Then: the request should fail with 412. + require.Error(t, err) + + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode()) + }) + + t.Run("Cancel with expect_state=running when job is pending - should fail with 412", func(t *testing.T) { + t.Parallel() + if !dbtestutil.WillUsePostgres() { + t.Skip("this test requires postgres") + } + // Given: a coderd instance with a provisioner daemon + store, ps, db := dbtestutil.NewDBWithSQLDB(t) + client, closeDaemon := coderdtest.NewWithProvisionerCloser(t, &coderdtest.Options{ + Database: store, + Pubsub: ps, + IncludeProvisionerDaemon: true, + }) + defer closeDaemon.Close() + // Given: a user, template, and workspace + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + + // Stop the provisioner daemon. + require.NoError(t, closeDaemon.Close()) + ctx := testutil.Context(t, testutil.WaitLong) + // Given: no provisioner daemons exist. + _, err := db.ExecContext(ctx, `DELETE FROM provisioner_daemons;`) + require.NoError(t, err) + + // When: a new workspace build is created + build, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + TemplateVersionID: template.ActiveVersionID, + Transition: codersdk.WorkspaceTransitionStart, + }) + // Then: the request should succeed. + require.NoError(t, err) + // Then: the provisioner job should remain pending. + require.Equal(t, codersdk.ProvisionerJobPending, build.Job.Status) + + // Then: the response should indicate no provisioners are available. + if assert.NotNil(t, build.MatchedProvisioners) { + assert.Zero(t, build.MatchedProvisioners.Count) + assert.Zero(t, build.MatchedProvisioners.Available) + assert.Zero(t, build.MatchedProvisioners.MostRecentlySeen.Time) + assert.False(t, build.MatchedProvisioners.MostRecentlySeen.Valid) + } + + // When: a cancel request is made with expect_state=running + err = client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{ + ExpectStatus: codersdk.CancelWorkspaceBuildStatusRunning, + }) + // Then: the request should fail with 412. + require.Error(t, err) + + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode()) + }) + + t.Run("Cancel with expect_state - invalid status", func(t *testing.T) { + t.Parallel() + + // Given: a coderd instance with a provisioner daemon + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ + Log: &proto.Log{}, + }, + }}, + ProvisionPlan: echo.PlanComplete, + }) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + + ctx := testutil.Context(t, testutil.WaitLong) + + // When: a cancel request is made with invalid expect_state + err := client.CancelWorkspaceBuild(ctx, workspace.LatestBuild.ID, codersdk.CancelWorkspaceBuildParams{ + ExpectStatus: "invalid_status", + }) + // Then: the request should fail with 400. + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) + require.Contains(t, apiErr.Message, "Invalid expect_status") + }) } func TestWorkspaceBuildResources(t *testing.T) { @@ -968,7 +1156,7 @@ func TestWorkspaceBuildStatus(t *testing.T) { _ = closeDaemon.Close() // after successful cancel is "canceled" build = coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart) - err = client.CancelWorkspaceBuild(ctx, build.ID) + err = client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{}) require.NoError(t, err) workspace, err = client.Workspace(ctx, workspace.ID) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index d51a228a3f7a1..3a50f850da5e7 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -3245,7 +3245,7 @@ func TestWorkspaceWatcher(t *testing.T) { closeFunc.Close() build := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart) wait("first is for the workspace build itself", nil) - err = client.CancelWorkspaceBuild(ctx, build.ID) + err = client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{}) require.NoError(t, err) wait("second is for the build cancel", nil) } diff --git a/codersdk/toolsdk/toolsdk_test.go b/codersdk/toolsdk/toolsdk_test.go index d08191a614a99..09b919a428a84 100644 --- a/codersdk/toolsdk/toolsdk_test.go +++ b/codersdk/toolsdk/toolsdk_test.go @@ -164,7 +164,7 @@ func TestTools(t *testing.T) { // Important: cancel the build. We don't run any provisioners, so this // will remain in the 'pending' state indefinitely. - require.NoError(t, client.CancelWorkspaceBuild(ctx, result.ID)) + require.NoError(t, client.CancelWorkspaceBuild(ctx, result.ID, codersdk.CancelWorkspaceBuildParams{})) }) t.Run("Start", func(t *testing.T) { @@ -184,7 +184,7 @@ func TestTools(t *testing.T) { // Important: cancel the build. We don't run any provisioners, so this // will remain in the 'pending' state indefinitely. - require.NoError(t, client.CancelWorkspaceBuild(ctx, result.ID)) + require.NoError(t, client.CancelWorkspaceBuild(ctx, result.ID, codersdk.CancelWorkspaceBuildParams{})) }) t.Run("TemplateVersionChange", func(t *testing.T) { @@ -216,7 +216,7 @@ func TestTools(t *testing.T) { require.Equal(t, r.Workspace.ID.String(), updateBuild.WorkspaceID.String()) require.Equal(t, newVersion.TemplateVersion.ID.String(), updateBuild.TemplateVersionID.String()) // Cancel the build so it doesn't remain in the 'pending' state indefinitely. - require.NoError(t, client.CancelWorkspaceBuild(ctx, updateBuild.ID)) + require.NoError(t, client.CancelWorkspaceBuild(ctx, updateBuild.ID, codersdk.CancelWorkspaceBuildParams{})) // Roll back to the original version rollbackBuild, err := testTool(t, toolsdk.CreateWorkspaceBuild, tb, toolsdk.CreateWorkspaceBuildArgs{ @@ -229,7 +229,7 @@ func TestTools(t *testing.T) { require.Equal(t, r.Workspace.ID.String(), rollbackBuild.WorkspaceID.String()) require.Equal(t, originalVersionID.String(), rollbackBuild.TemplateVersionID.String()) // Cancel the build so it doesn't remain in the 'pending' state indefinitely. - require.NoError(t, client.CancelWorkspaceBuild(ctx, rollbackBuild.ID)) + require.NoError(t, client.CancelWorkspaceBuild(ctx, rollbackBuild.ID, codersdk.CancelWorkspaceBuildParams{})) }) }) diff --git a/codersdk/workspacebuilds.go b/codersdk/workspacebuilds.go index 328b8bc26566f..4066341773994 100644 --- a/codersdk/workspacebuilds.go +++ b/codersdk/workspacebuilds.go @@ -123,9 +123,29 @@ func (c *Client) WorkspaceBuild(ctx context.Context, id uuid.UUID) (WorkspaceBui return workspaceBuild, json.NewDecoder(res.Body).Decode(&workspaceBuild) } +type CancelWorkspaceBuildStatus string + +const ( + CancelWorkspaceBuildStatusRunning CancelWorkspaceBuildStatus = "running" + CancelWorkspaceBuildStatusPending CancelWorkspaceBuildStatus = "pending" +) + +type CancelWorkspaceBuildParams struct { + // ExpectStatus ensures the build is in the expected status before canceling. + ExpectStatus CancelWorkspaceBuildStatus `json:"expect_status,omitempty"` +} + +func (c *CancelWorkspaceBuildParams) asRequestOption() RequestOption { + return func(r *http.Request) { + q := r.URL.Query() + q.Set("expect_status", string(c.ExpectStatus)) + r.URL.RawQuery = q.Encode() + } +} + // CancelWorkspaceBuild marks a workspace build job as canceled. -func (c *Client) CancelWorkspaceBuild(ctx context.Context, id uuid.UUID) error { - res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/workspacebuilds/%s/cancel", id), nil) +func (c *Client) CancelWorkspaceBuild(ctx context.Context, id uuid.UUID, req CancelWorkspaceBuildParams) error { + res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/workspacebuilds/%s/cancel", id), nil, req.asRequestOption()) if err != nil { return err } diff --git a/docs/reference/api/builds.md b/docs/reference/api/builds.md index bb279f5825f6e..686f19316a8c0 100644 --- a/docs/reference/api/builds.md +++ b/docs/reference/api/builds.md @@ -491,9 +491,17 @@ curl -X PATCH http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/c ### Parameters -| Name | In | Type | Required | Description | -|------------------|------|--------|----------|--------------------| -| `workspacebuild` | path | string | true | Workspace build ID | +| Name | In | Type | Required | Description | +|------------------|-------|--------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `workspacebuild` | path | string | true | Workspace build ID | +| `expect_status` | query | string | false | Expected status of the job. If expect_status is supplied, the request will be rejected with 412 Precondition Failed if the job doesn't match the state when performing the cancellation. | + +#### Enumerated Values + +| Parameter | Value | +|-----------------|-----------| +| `expect_status` | `running` | +| `expect_status` | `pending` | ### Example responses diff --git a/scaletest/workspacebuild/run.go b/scaletest/workspacebuild/run.go index f19c556823faf..3b369a4e48a72 100644 --- a/scaletest/workspacebuild/run.go +++ b/scaletest/workspacebuild/run.go @@ -150,7 +150,7 @@ func (r *CleanupRunner) Run(ctx context.Context, _ string, logs io.Writer) error if err == nil && build.Job.Status.Active() { // mark the build as canceled logger.Info(ctx, "canceling workspace build", slog.F("build_id", build.ID), slog.F("workspace_id", r.workspaceID)) - if err = r.client.CancelWorkspaceBuild(ctx, build.ID); err == nil { + if err = r.client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{}); err == nil { // Wait for the job to cancel before we delete it _ = waitForBuild(ctx, logs, r.client, build.ID) // it will return a "build canceled" error } else { diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 2b13c77faffa1..dd8d3d77998d2 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1277,9 +1277,12 @@ class ApiMethods { cancelWorkspaceBuild = async ( workspaceBuildId: TypesGen.WorkspaceBuild["id"], + params?: TypesGen.CancelWorkspaceBuildParams, ): Promise => { const response = await this.axios.patch( `/api/v2/workspacebuilds/${workspaceBuildId}/cancel`, + null, + { params }, ); return response.data; diff --git a/site/src/api/queries/workspaces.ts b/site/src/api/queries/workspaces.ts index 5a4cdb46dd4e9..05fb09314d741 100644 --- a/site/src/api/queries/workspaces.ts +++ b/site/src/api/queries/workspaces.ts @@ -266,7 +266,12 @@ export const startWorkspace = ( export const cancelBuild = (workspace: Workspace, queryClient: QueryClient) => { return { mutationFn: () => { - return API.cancelWorkspaceBuild(workspace.latest_build.id); + const { status } = workspace.latest_build; + const params = + status === "pending" || status === "running" + ? { expect_status: status } + : undefined; + return API.cancelWorkspaceBuild(workspace.latest_build.id, params); }, onSuccess: async () => { await queryClient.invalidateQueries({ diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 4ab5403081a60..399b79499edd9 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -292,6 +292,19 @@ export const BypassRatelimitHeader = "X-Coder-Bypass-Ratelimit"; // From codersdk/client.go export const CLITelemetryHeader = "Coder-CLI-Telemetry"; +// From codersdk/workspacebuilds.go +export interface CancelWorkspaceBuildParams { + readonly expect_status?: CancelWorkspaceBuildStatus; +} + +// From codersdk/workspacebuilds.go +export type CancelWorkspaceBuildStatus = "pending" | "running"; + +export const CancelWorkspaceBuildStatuses: CancelWorkspaceBuildStatus[] = [ + "pending", + "running", +]; + // From codersdk/users.go export interface ChangePasswordWithOneTimePasscodeRequest { readonly email: string; diff --git a/site/src/modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog.tsx b/site/src/modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog.tsx new file mode 100644 index 0000000000000..cbd7eb7d0c1ed --- /dev/null +++ b/site/src/modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog.tsx @@ -0,0 +1,32 @@ +import type { Workspace } from "api/typesGenerated"; +import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog"; +import type { FC } from "react"; + +interface WorkspaceBuildCancelDialogProps { + open: boolean; + onClose: () => void; + onConfirm: () => void; + workspace: Workspace; +} + +export const WorkspaceBuildCancelDialog: FC< + WorkspaceBuildCancelDialogProps +> = ({ open, onClose, onConfirm, workspace }) => { + const action = + workspace.latest_build.status === "pending" + ? "remove the current build from the build queue" + : "stop the current build process"; + + return ( + + ); +}; diff --git a/site/src/modules/workspaces/actions.ts b/site/src/modules/workspaces/actions.ts index f109c4d9ad1b9..8b17d3e937c74 100644 --- a/site/src/modules/workspaces/actions.ts +++ b/site/src/modules/workspaces/actions.ts @@ -145,7 +145,7 @@ export const abilitiesByWorkspaceStatus = ( case "pending": { return { actions: ["pending"], - canCancel: false, + canCancel: true, canAcceptJobs: false, }; } diff --git a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx index ad320018da9fb..645c03380501a 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx @@ -19,6 +19,7 @@ import { MockFailedWorkspace, MockOrganization, MockOutdatedWorkspace, + MockPendingWorkspace, MockStartingWorkspace, MockStoppedWorkspace, MockTemplate, @@ -224,11 +225,59 @@ describe("WorkspacePage", () => { }), ); + const user = userEvent.setup({ delay: 0 }); const cancelWorkspaceMock = jest .spyOn(API, "cancelWorkspaceBuild") .mockImplementation(() => Promise.resolve({ message: "job canceled" })); + await renderWorkspacePage(MockStartingWorkspace); + + // Click on Cancel + const cancelButton = await screen.findByRole("button", { name: "Cancel" }); + await user.click(cancelButton); + + // Get dialog and confirm + const dialog = await screen.findByTestId("dialog"); + const confirmButton = within(dialog).getByRole("button", { + name: "Confirm", + hidden: false, + }); + await user.click(confirmButton); + + expect(cancelWorkspaceMock).toHaveBeenCalledWith( + MockStartingWorkspace.latest_build.id, + undefined, + ); + }); - await testButton(MockStartingWorkspace, "Cancel", cancelWorkspaceMock); + it("requests cancellation when the user presses Cancel and the workspace is pending", async () => { + server.use( + http.get("/api/v2/users/:userId/workspace/:workspaceName", () => { + return HttpResponse.json(MockPendingWorkspace); + }), + ); + + const user = userEvent.setup({ delay: 0 }); + const cancelWorkspaceMock = jest + .spyOn(API, "cancelWorkspaceBuild") + .mockImplementation(() => Promise.resolve({ message: "job canceled" })); + await renderWorkspacePage(MockPendingWorkspace); + + // Click on Cancel + const cancelButton = await screen.findByRole("button", { name: "Cancel" }); + await user.click(cancelButton); + + // Get dialog and confirm + const dialog = await screen.findByTestId("dialog"); + const confirmButton = within(dialog).getByRole("button", { + name: "Confirm", + hidden: false, + }); + await user.click(confirmButton); + + expect(cancelWorkspaceMock).toHaveBeenCalledWith( + MockPendingWorkspace.latest_build.id, + { expect_status: "pending" }, + ); }); it("requests an update when the user presses Update", async () => { diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index 79ec5ad11a2b5..4034cc144e127 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -20,6 +20,7 @@ import { displayError } from "components/GlobalSnackbar/utils"; import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs"; import { EphemeralParametersDialog } from "modules/workspaces/EphemeralParametersDialog/EphemeralParametersDialog"; import { WorkspaceErrorDialog } from "modules/workspaces/ErrorDialog/WorkspaceErrorDialog"; +import { WorkspaceBuildCancelDialog } from "modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog"; import { WorkspaceUpdateDialogs, useWorkspaceUpdate, @@ -80,6 +81,8 @@ export const WorkspaceReadyPage: FC = ({ ephemeralParameters: TypesGen.TemplateVersionParameter[]; }>({ open: false, action: "start", ephemeralParameters: [] }); + const [isCancelConfirmOpen, setIsCancelConfirmOpen] = useState(false); + const { mutate: mutateRestartWorkspace, isPending: isRestarting } = useMutation({ mutationFn: API.restartWorkspace, @@ -316,7 +319,7 @@ export const WorkspaceReadyPage: FC = ({ } }} handleUpdate={workspaceUpdate.update} - handleCancel={cancelBuildMutation.mutate} + handleCancel={() => setIsCancelConfirmOpen(true)} handleRetry={handleRetry} handleDebug={handleDebug} handleDormantActivate={async () => { @@ -352,6 +355,16 @@ export const WorkspaceReadyPage: FC = ({ } /> + setIsCancelConfirmOpen(false)} + onConfirm={() => { + cancelBuildMutation.mutate(); + setIsCancelConfirmOpen(false); + }} + workspace={workspace} + /> + diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx index 6213224dea602..23695d8fbc591 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx @@ -62,6 +62,7 @@ import { import { useAppLink } from "modules/apps/useAppLink"; import { useDashboard } from "modules/dashboard/useDashboard"; import { WorkspaceAppStatus } from "modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus"; +import { WorkspaceBuildCancelDialog } from "modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog"; import { WorkspaceDormantBadge } from "modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge"; import { WorkspaceMoreActions } from "modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions"; import { WorkspaceOutdatedTooltip } from "modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip"; @@ -495,8 +496,8 @@ const WorkspaceActionsCell: FC = ({ onError: onActionError, }); - // State for stop confirmation dialog const [isStopConfirmOpen, setIsStopConfirmOpen] = useState(false); + const [isCancelConfirmOpen, setIsCancelConfirmOpen] = useState(false); const isRetrying = startWorkspaceMutation.isPending || @@ -606,7 +607,7 @@ const WorkspaceActionsCell: FC = ({ {abilities.canCancel && ( setIsCancelConfirmOpen(true)} isLoading={cancelBuildMutation.isPending} label="Cancel build" > @@ -643,6 +644,16 @@ const WorkspaceActionsCell: FC = ({ }} type="delete" /> + + setIsCancelConfirmOpen(false)} + onConfirm={() => { + cancelBuildMutation.mutate(); + setIsCancelConfirmOpen(false); + }} + workspace={workspace} + /> ); }; From 1195f31025366850ce17357170576265ab89741f Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Tue, 8 Jul 2025 11:00:05 +0100 Subject: [PATCH 04/61] chore(site): reduce fetch interval on workspaces page (#18725) Relates to https://github.com/coder/internal/issues/720 * Reduces workspaces data refetch interval if no builds are pending * Sets `refetchOnWindowFocus: always` to mitigate impact of reduced polling duration --- .../pages/WorkspacesPage/WorkspacesPage.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index 22ba0d15f1f9a..fa96191501379 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -2,7 +2,7 @@ import { getErrorDetail, getErrorMessage } from "api/errors"; import { workspacePermissionsByOrganization } from "api/queries/organizations"; import { templates } from "api/queries/templates"; import { workspaces } from "api/queries/workspaces"; -import type { Workspace } from "api/typesGenerated"; +import type { Workspace, WorkspaceStatus } from "api/typesGenerated"; import { useFilter } from "components/Filter/Filter"; import { useUserFilterMenu } from "components/Filter/UserFilter"; import { displayError } from "components/GlobalSnackbar/utils"; @@ -22,6 +22,18 @@ import { WorkspacesPageView } from "./WorkspacesPageView"; import { useBatchActions } from "./batchActions"; import { useStatusFilterMenu, useTemplateFilterMenu } from "./filter/menus"; +// To reduce the number of fetches, we reduce the fetch interval if there are no +// active workspace builds. +const ACTIVE_BUILD_STATUSES: WorkspaceStatus[] = [ + "canceling", + "deleting", + "pending", + "starting", + "stopping", +]; +const ACTIVE_BUILDS_REFRESH_INTERVAL = 5_000; +const NO_ACTIVE_BUILDS_REFRESH_INTERVAL = 30_000; + function useSafeSearchParams() { // Have to wrap setSearchParams because React Router doesn't make sure that // the function's memory reference stays stable on each render, even though @@ -78,8 +90,23 @@ const WorkspacesPage: FC = () => { const { data, error, refetch } = useQuery({ ...workspacesQueryOptions, refetchInterval: ({ state }) => { - return state.error ? false : 5_000; + if (state.error) return false; + + // Default to 5s interval until first fetch completes + if (!state.data) return ACTIVE_BUILDS_REFRESH_INTERVAL; + + // Check if any workspace has an active build + const hasActiveBuilds = state.data.workspaces?.some((workspace) => { + const status = workspace.latest_build.status; + return ACTIVE_BUILD_STATUSES.includes(status); + }); + + // Poll every 5s if there are active builds, otherwise every 30s + return hasActiveBuilds + ? ACTIVE_BUILDS_REFRESH_INTERVAL + : NO_ACTIVE_BUILDS_REFRESH_INTERVAL; }, + refetchOnWindowFocus: "always", }); const [checkedWorkspaces, setCheckedWorkspaces] = useState< From 0118e75009349be26242a274c6f79aa58a07f3c6 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Tue, 8 Jul 2025 11:05:30 +0100 Subject: [PATCH 05/61] fix(agent): disable dev container integration inside sub agents (#18781) It appears we accidentally broke this logic in a previous PR. This should now correctly disable the agent api as we'd expect. --- agent/agent.go | 30 +++++++++++++----------------- agent/agent_test.go | 7 ++++--- agent/api.go | 12 ++++++++++-- cli/ssh_test.go | 2 +- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 3c02b5f2790f0..75117769d8e2d 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -336,18 +336,16 @@ func (a *agent) init() { // will not report anywhere. a.scriptRunner.RegisterMetrics(a.prometheusRegistry) - if a.devcontainers { - containerAPIOpts := []agentcontainers.Option{ - agentcontainers.WithExecer(a.execer), - agentcontainers.WithCommandEnv(a.sshServer.CommandEnv), - agentcontainers.WithScriptLogger(func(logSourceID uuid.UUID) agentcontainers.ScriptLogger { - return a.logSender.GetScriptLogger(logSourceID) - }), - } - containerAPIOpts = append(containerAPIOpts, a.containerAPIOptions...) - - a.containerAPI = agentcontainers.NewAPI(a.logger.Named("containers"), containerAPIOpts...) + containerAPIOpts := []agentcontainers.Option{ + agentcontainers.WithExecer(a.execer), + agentcontainers.WithCommandEnv(a.sshServer.CommandEnv), + agentcontainers.WithScriptLogger(func(logSourceID uuid.UUID) agentcontainers.ScriptLogger { + return a.logSender.GetScriptLogger(logSourceID) + }), } + containerAPIOpts = append(containerAPIOpts, a.containerAPIOptions...) + + a.containerAPI = agentcontainers.NewAPI(a.logger.Named("containers"), containerAPIOpts...) a.reconnectingPTYServer = reconnectingpty.NewServer( a.logger.Named("reconnecting-pty"), @@ -1162,7 +1160,7 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, scripts = manifest.Scripts devcontainerScripts map[uuid.UUID]codersdk.WorkspaceAgentScript ) - if a.containerAPI != nil { + if a.devcontainers { // Init the container API with the manifest and client so that // we can start accepting requests. The final start of the API // happens after the startup scripts have been executed to @@ -1197,7 +1195,7 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, // autostarted devcontainer will be included in this time. err := a.scriptRunner.Execute(a.gracefulCtx, agentscripts.ExecuteStartScripts) - if a.containerAPI != nil { + if a.devcontainers { // Start the container API after the startup scripts have // been executed to ensure that the required tools can be // installed. @@ -1928,10 +1926,8 @@ func (a *agent) Close() error { a.logger.Error(a.hardCtx, "script runner close", slog.Error(err)) } - if a.containerAPI != nil { - if err := a.containerAPI.Close(); err != nil { - a.logger.Error(a.hardCtx, "container API close", slog.Error(err)) - } + if err := a.containerAPI.Close(); err != nil { + a.logger.Error(a.hardCtx, "container API close", slog.Error(err)) } // Wait for the graceful shutdown to complete, but don't wait forever so diff --git a/agent/agent_test.go b/agent/agent_test.go index 4a9141bd37f9e..d87148be9ad15 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -2441,7 +2441,8 @@ func TestAgent_DevcontainersDisabledForSubAgent(t *testing.T) { // Setup the agent with devcontainers enabled initially. //nolint:dogsled - conn, _, _, _, _ := setupAgent(t, manifest, 0, func(*agenttest.Client, *agent.Options) { + conn, _, _, _, _ := setupAgent(t, manifest, 0, func(_ *agenttest.Client, o *agent.Options) { + o.Devcontainers = true }) // Query the containers API endpoint. This should fail because @@ -2453,8 +2454,8 @@ func TestAgent_DevcontainersDisabledForSubAgent(t *testing.T) { require.Error(t, err) // Verify the error message contains the expected text. - require.Contains(t, err.Error(), "The agent dev containers feature is experimental and not enabled by default.") - require.Contains(t, err.Error(), "To enable this feature, set CODER_AGENT_DEVCONTAINERS_ENABLE=true in your template.") + require.Contains(t, err.Error(), "Dev Container feature not supported.") + require.Contains(t, err.Error(), "Dev Container integration inside other Dev Containers is explicitly not supported.") } func TestAgent_Dial(t *testing.T) { diff --git a/agent/api.go b/agent/api.go index 0458df7c58e1f..ca0760e130ffe 100644 --- a/agent/api.go +++ b/agent/api.go @@ -6,6 +6,7 @@ import ( "time" "github.com/go-chi/chi/v5" + "github.com/google/uuid" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/codersdk" @@ -36,12 +37,19 @@ func (a *agent) apiHandler() http.Handler { cacheDuration: cacheDuration, } - if a.containerAPI != nil { + if a.devcontainers { r.Mount("/api/v0/containers", a.containerAPI.Routes()) + } else if manifest := a.manifest.Load(); manifest != nil && manifest.ParentID != uuid.Nil { + r.HandleFunc("/api/v0/containers", func(w http.ResponseWriter, r *http.Request) { + httpapi.Write(r.Context(), w, http.StatusForbidden, codersdk.Response{ + Message: "Dev Container feature not supported.", + Detail: "Dev Container integration inside other Dev Containers is explicitly not supported.", + }) + }) } else { r.HandleFunc("/api/v0/containers", func(w http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), w, http.StatusForbidden, codersdk.Response{ - Message: "The agent dev containers feature is experimental and not enabled by default.", + Message: "Dev Container feature not enabled.", Detail: "To enable this feature, set CODER_AGENT_DEVCONTAINERS_ENABLE=true in your template.", }) }) diff --git a/cli/ssh_test.go b/cli/ssh_test.go index 582f8a3fdf691..7a91cfa3ce365 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -2104,7 +2104,7 @@ func TestSSH_Container(t *testing.T) { clitest.SetupConfig(t, client, root) err := inv.WithContext(ctx).Run() - require.ErrorContains(t, err, "The agent dev containers feature is experimental and not enabled by default.") + require.ErrorContains(t, err, "Dev Container feature not enabled.") }) } From 211393a69c7f78768ce79dccbbf92473c1477c62 Mon Sep 17 00:00:00 2001 From: Susana Ferreira Date: Tue, 8 Jul 2025 11:35:28 +0100 Subject: [PATCH 06/61] fix: exclude prebuilt workspaces from lifecycle executor (#18762) ## Description This PR updates the lifecycle executor to explicitly exclude prebuilt workspaces from being considered for lifecycle operations such as `autostart`, `autostop`, `dormancy`, `default TTL` and `failure TTL`. Prebuilt workspaces (i.e., those owned by the prebuild system user) are handled separately by the prebuild reconciliation loop. Including them in the lifecycle executor could lead to unintended behavior such as incorrect scheduling or state transitions. ## Changes * Updated the lifecycle executor query `GetWorkspacesEligibleForTransition` to exclude workspaces with `owner_id = 'c42fdf75-3097-471c-8c33-fb52454d81c0'` (prebuilds). * Added tests to verify prebuilt workspaces are not considered in: * Autostop * Autostart * Default TTL * Dormancy * Failure TTL Fixes: https://github.com/coder/coder/issues/18740 Related to: https://github.com/coder/coder/issues/18658 --- coderd/apidoc/docs.go | 6 +- coderd/apidoc/swagger.json | 5 +- coderd/autobuild/lifecycle_executor.go | 2 + coderd/autobuild/lifecycle_executor_test.go | 349 ++++++++ coderd/database/dbgen/dbgen.go | 22 + coderd/database/queries.sql.go | 7 +- coderd/database/queries/workspaces.sql | 7 +- coderd/schedule/autostart.go | 2 + codersdk/workspacebuilds.go | 9 +- .../prebuilt-workspaces.md | 11 +- docs/reference/api/schemas.md | 1 + enterprise/coderd/workspaces_test.go | 794 ++++++++++++++++++ site/src/api/typesGenerated.ts | 3 +- site/src/utils/workspace.tsx | 4 +- 14 files changed, 1204 insertions(+), 18 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 433a3797daaaa..8dea791f7b763 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -11366,12 +11366,14 @@ const docTemplate = `{ "enum": [ "initiator", "autostart", - "autostop" + "autostop", + "dormancy" ], "x-enum-varnames": [ "BuildReasonInitiator", "BuildReasonAutostart", - "BuildReasonAutostop" + "BuildReasonAutostop", + "BuildReasonDormancy" ] }, "codersdk.ChangePasswordWithOneTimePasscodeRequest": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index adac5bf344cbe..143342c1c2147 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -10106,11 +10106,12 @@ }, "codersdk.BuildReason": { "type": "string", - "enum": ["initiator", "autostart", "autostop"], + "enum": ["initiator", "autostart", "autostop", "dormancy"], "x-enum-varnames": [ "BuildReasonInitiator", "BuildReasonAutostart", - "BuildReasonAutostop" + "BuildReasonAutostop", + "BuildReasonDormancy" ] }, "codersdk.ChangePasswordWithOneTimePasscodeRequest": { diff --git a/coderd/autobuild/lifecycle_executor.go b/coderd/autobuild/lifecycle_executor.go index 1846b1ea18284..d49bf831515d0 100644 --- a/coderd/autobuild/lifecycle_executor.go +++ b/coderd/autobuild/lifecycle_executor.go @@ -520,6 +520,8 @@ func isEligibleForAutostart(user database.User, ws database.Workspace, build dat return false } + // Get the next allowed autostart time after the build's creation time, + // based on the workspace's schedule and the template's allowed days. nextTransition, err := schedule.NextAllowedAutostart(build.CreatedAt, ws.AutostartSchedule.String, templateSchedule) if err != nil { return false diff --git a/coderd/autobuild/lifecycle_executor_test.go b/coderd/autobuild/lifecycle_executor_test.go index 3bca6856534fa..0229a907cbb2e 100644 --- a/coderd/autobuild/lifecycle_executor_test.go +++ b/coderd/autobuild/lifecycle_executor_test.go @@ -2,9 +2,16 @@ package autobuild_test import ( "context" + "database/sql" + "errors" "testing" "time" + "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/pubsub" + "github.com/coder/coder/v2/coderd/rbac" + "github.com/coder/quartz" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1183,6 +1190,348 @@ func TestNotifications(t *testing.T) { }) } +// TestExecutorPrebuilds verifies AGPL behavior for prebuilt workspaces. +// It ensures that workspace schedules do not trigger while the workspace +// is still in a prebuilt state. Scheduling behavior only applies after the +// workspace has been claimed and becomes a regular user workspace. +// For enterprise-related functionality, see enterprise/coderd/workspaces_test.go. +func TestExecutorPrebuilds(t *testing.T) { + t.Parallel() + + if !dbtestutil.WillUsePostgres() { + t.Skip("this test requires postgres") + } + + // Prebuild workspaces should not be autostopped when the deadline is reached. + // After being claimed, the workspace should stop at the deadline. + t.Run("OnlyStopsAfterClaimed", func(t *testing.T) { + t.Parallel() + + // Setup + ctx := testutil.Context(t, testutil.WaitShort) + clock := quartz.NewMock(t) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + var ( + tickCh = make(chan time.Time) + statsCh = make(chan autobuild.Stats) + client = coderdtest.New(t, &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + }) + ) + + // Setup user, template and template version + owner := coderdtest.CreateFirstUser(t, client) + _, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleMember()) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) + + // Database setup of a preset with a prebuild instance + preset := setupTestDBPreset(t, db, version.ID, int32(1)) + + // Given: a running prebuilt workspace with a deadline and ready to be claimed + dbPrebuild := setupTestDBPrebuiltWorkspace( + ctx, t, clock, db, pb, + owner.OrganizationID, + template.ID, + version.ID, + preset.ID, + ) + prebuild := coderdtest.MustWorkspace(t, client, dbPrebuild.ID) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + require.NotZero(t, prebuild.LatestBuild.Deadline) + + // When: the autobuild executor ticks *after* the deadline: + go func() { + tickCh <- prebuild.LatestBuild.Deadline.Time.Add(time.Minute) + }() + + // Then: the prebuilt workspace should remain in a start transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + + // Given: a user claims the prebuilt workspace + dbWorkspace := dbgen.ClaimPrebuild(t, db, user.ID, "claimedWorkspace-autostop", preset.ID) + workspace := coderdtest.MustWorkspace(t, client, dbWorkspace.ID) + + // When: the autobuild executor ticks *after* the deadline: + go func() { + tickCh <- workspace.LatestBuild.Deadline.Time.Add(time.Minute) + close(tickCh) + }() + + // Then: the workspace should be stopped + workspaceStats := <-statsCh + require.Len(t, workspaceStats.Errors, 0) + require.Len(t, workspaceStats.Transitions, 1) + require.Contains(t, workspaceStats.Transitions, workspace.ID) + require.Equal(t, database.WorkspaceTransitionStop, workspaceStats.Transitions[workspace.ID]) + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.Equal(t, codersdk.BuildReasonAutostop, workspace.LatestBuild.Reason) + }) + + // Prebuild workspaces should not be autostarted when the autostart scheduled is reached. + // After being claimed, the workspace should autostart at the schedule. + t.Run("OnlyStartsAfterClaimed", func(t *testing.T) { + t.Parallel() + + // Setup + ctx := testutil.Context(t, testutil.WaitShort) + clock := quartz.NewMock(t) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + var ( + tickCh = make(chan time.Time) + statsCh = make(chan autobuild.Stats) + client = coderdtest.New(t, &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + }) + ) + + // Setup user, template and template version + owner := coderdtest.CreateFirstUser(t, client) + _, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleMember()) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) + + // Database setup of a preset with a prebuild instance + preset := setupTestDBPreset(t, db, version.ID, int32(1)) + + // Given: prebuilt workspace is stopped and set to autostart daily at midnight + sched := mustSchedule(t, "CRON_TZ=UTC 0 0 * * *") + autostartSched := sql.NullString{ + String: sched.String(), + Valid: true, + } + dbPrebuild := setupTestDBPrebuiltWorkspace( + ctx, t, clock, db, pb, + owner.OrganizationID, + template.ID, + version.ID, + preset.ID, + WithAutostartSchedule(autostartSched), + WithIsStopped(true), + ) + prebuild := coderdtest.MustWorkspace(t, client, dbPrebuild.ID) + require.Equal(t, codersdk.WorkspaceTransitionStop, prebuild.LatestBuild.Transition) + require.NotNil(t, prebuild.AutostartSchedule) + + // Tick at the next scheduled time after the prebuild’s LatestBuild.CreatedAt, + // since the next allowed autostart is calculated starting from that point. + // When: the autobuild executor ticks after the scheduled time + go func() { + tickCh <- sched.Next(prebuild.LatestBuild.CreatedAt).Add(time.Minute) + }() + + // Then: the prebuilt workspace should remain in a stop transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStop, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + + // Given: prebuilt workspace is in a start status + setupTestDBWorkspaceBuild( + ctx, t, clock, db, pb, + owner.OrganizationID, + prebuild.ID, + version.ID, + preset.ID, + database.WorkspaceTransitionStart) + + // Given: a user claims the prebuilt workspace + dbWorkspace := dbgen.ClaimPrebuild(t, db, user.ID, "claimedWorkspace-autostart", preset.ID) + workspace := coderdtest.MustWorkspace(t, client, dbWorkspace.ID) + + // Given: the prebuilt workspace goes to a stop status + setupTestDBWorkspaceBuild( + ctx, t, clock, db, pb, + owner.OrganizationID, + prebuild.ID, + version.ID, + preset.ID, + database.WorkspaceTransitionStop) + + // Tick at the next scheduled time after the prebuild’s LatestBuild.CreatedAt, + // since the next allowed autostart is calculated starting from that point. + // When: the autobuild executor ticks after the scheduled time + go func() { + tickCh <- sched.Next(workspace.LatestBuild.CreatedAt).Add(time.Minute) + close(tickCh) + }() + + // Then: the workspace should eventually be started + workspaceStats := <-statsCh + require.Len(t, workspaceStats.Errors, 0) + require.Len(t, workspaceStats.Transitions, 1) + require.Contains(t, workspaceStats.Transitions, workspace.ID) + require.Equal(t, database.WorkspaceTransitionStart, workspaceStats.Transitions[workspace.ID]) + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.Equal(t, codersdk.BuildReasonAutostart, workspace.LatestBuild.Reason) + }) +} + +func setupTestDBPreset( + t *testing.T, + db database.Store, + templateVersionID uuid.UUID, + desiredInstances int32, +) database.TemplateVersionPreset { + t.Helper() + + preset := dbgen.Preset(t, db, database.InsertPresetParams{ + TemplateVersionID: templateVersionID, + Name: "preset-test", + DesiredInstances: sql.NullInt32{ + Valid: true, + Int32: desiredInstances, + }, + }) + dbgen.PresetParameter(t, db, database.InsertPresetParametersParams{ + TemplateVersionPresetID: preset.ID, + Names: []string{"test-name"}, + Values: []string{"test-value"}, + }) + + return preset +} + +type SetupPrebuiltOptions struct { + AutostartSchedule sql.NullString + IsStopped bool +} + +func WithAutostartSchedule(sched sql.NullString) func(*SetupPrebuiltOptions) { + return func(o *SetupPrebuiltOptions) { + o.AutostartSchedule = sched + } +} + +func WithIsStopped(isStopped bool) func(*SetupPrebuiltOptions) { + return func(o *SetupPrebuiltOptions) { + o.IsStopped = isStopped + } +} + +func setupTestDBWorkspaceBuild( + ctx context.Context, + t *testing.T, + clock quartz.Clock, + db database.Store, + ps pubsub.Pubsub, + orgID uuid.UUID, + workspaceID uuid.UUID, + templateVersionID uuid.UUID, + presetID uuid.UUID, + transition database.WorkspaceTransition, +) (database.ProvisionerJob, database.WorkspaceBuild) { + t.Helper() + + var buildNumber int32 = 1 + latestWorkspaceBuild, err := db.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspaceID) + if !errors.Is(err, sql.ErrNoRows) { + buildNumber = latestWorkspaceBuild.BuildNumber + 1 + } + + job := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ + InitiatorID: database.PrebuildsSystemUserID, + CreatedAt: clock.Now().Add(-time.Hour * 2), + StartedAt: sql.NullTime{Time: clock.Now().Add(-time.Hour * 2), Valid: true}, + CompletedAt: sql.NullTime{Time: clock.Now().Add(-time.Hour), Valid: true}, + OrganizationID: orgID, + JobStatus: database.ProvisionerJobStatusSucceeded, + }) + workspaceBuild := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ + WorkspaceID: workspaceID, + InitiatorID: database.PrebuildsSystemUserID, + TemplateVersionID: templateVersionID, + BuildNumber: buildNumber, + JobID: job.ID, + TemplateVersionPresetID: uuid.NullUUID{UUID: presetID, Valid: true}, + Transition: transition, + CreatedAt: clock.Now(), + }) + dbgen.WorkspaceBuildParameters(t, db, []database.WorkspaceBuildParameter{ + { + WorkspaceBuildID: workspaceBuild.ID, + Name: "test", + Value: "test", + }, + }) + + workspaceResource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{ + JobID: job.ID, + Transition: database.WorkspaceTransitionStart, + Type: "compute", + Name: "main", + }) + + // Workspaces are eligible to be claimed once their agent is marked "ready" + dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ + Name: "test", + ResourceID: workspaceResource.ID, + Architecture: "i386", + OperatingSystem: "linux", + LifecycleState: database.WorkspaceAgentLifecycleStateReady, + StartedAt: sql.NullTime{Time: time.Now().Add(time.Hour), Valid: true}, + ReadyAt: sql.NullTime{Time: time.Now().Add(-1 * time.Hour), Valid: true}, + APIKeyScope: database.AgentKeyScopeEnumAll, + }) + + return job, workspaceBuild +} + +func setupTestDBPrebuiltWorkspace( + ctx context.Context, + t *testing.T, + clock quartz.Clock, + db database.Store, + ps pubsub.Pubsub, + orgID uuid.UUID, + templateID uuid.UUID, + templateVersionID uuid.UUID, + presetID uuid.UUID, + opts ...func(*SetupPrebuiltOptions), +) database.WorkspaceTable { + t.Helper() + + // Optional parameters + options := &SetupPrebuiltOptions{} + for _, opt := range opts { + opt(options) + } + + buildTransition := database.WorkspaceTransitionStart + if options.IsStopped { + buildTransition = database.WorkspaceTransitionStop + } + + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ + TemplateID: templateID, + OrganizationID: orgID, + OwnerID: database.PrebuildsSystemUserID, + Deleted: false, + CreatedAt: time.Now().Add(-time.Hour * 2), + AutostartSchedule: options.AutostartSchedule, + }) + setupTestDBWorkspaceBuild(ctx, t, clock, db, ps, orgID, workspace.ID, templateVersionID, presetID, buildTransition) + + return workspace +} + func mustProvisionWorkspace(t *testing.T, client *codersdk.Client, mut ...func(*codersdk.CreateWorkspaceRequest)) codersdk.Workspace { t.Helper() user := coderdtest.CreateFirstUser(t, client) diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 0bb7bde403297..00fc3aa006e70 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -204,6 +204,17 @@ func WorkspaceAgent(t testing.TB, db database.Store, orig database.WorkspaceAgen require.NoError(t, err, "update workspace agent first connected at") } + // If the lifecycle state is "ready", update the agent with the corresponding timestamps + if orig.LifecycleState == database.WorkspaceAgentLifecycleStateReady && orig.StartedAt.Valid && orig.ReadyAt.Valid { + err := db.UpdateWorkspaceAgentLifecycleStateByID(genCtx, database.UpdateWorkspaceAgentLifecycleStateByIDParams{ + ID: agt.ID, + LifecycleState: orig.LifecycleState, + StartedAt: orig.StartedAt, + ReadyAt: orig.ReadyAt, + }) + require.NoError(t, err, "update workspace agent lifecycle state") + } + if orig.ParentID.UUID == uuid.Nil { // Add a test antagonist. For every agent we add a deleted sub agent // to discover cases where deletion should be handled. @@ -1352,6 +1363,17 @@ func PresetParameter(t testing.TB, db database.Store, seed database.InsertPreset return parameters } +func ClaimPrebuild(t testing.TB, db database.Store, newUserID uuid.UUID, newName string, presetID uuid.UUID) database.ClaimPrebuiltWorkspaceRow { + claimedWorkspace, err := db.ClaimPrebuiltWorkspace(genCtx, database.ClaimPrebuiltWorkspaceParams{ + NewUserID: newUserID, + NewName: newName, + PresetID: presetID, + }) + require.NoError(t, err, "claim prebuilt workspace") + + return claimedWorkspace +} + func provisionerJobTiming(t testing.TB, db database.Store, seed database.ProvisionerJobTiming) database.ProvisionerJobTiming { timing, err := db.InsertProvisionerJobTimings(genCtx, database.InsertProvisionerJobTimingsParams{ JobID: takeFirst(seed.JobID, uuid.New()), diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 15f4be06a3fa0..7b55c6a4db7b8 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -19971,7 +19971,12 @@ WHERE provisioner_jobs.completed_at IS NOT NULL AND ($1 :: timestamptz) - provisioner_jobs.completed_at > (INTERVAL '1 millisecond' * (templates.failure_ttl / 1000000)) ) - ) AND workspaces.deleted = 'false' + ) + AND workspaces.deleted = 'false' + -- Prebuilt workspaces (identified by having the prebuilds system user as owner_id) + -- should not be considered by the lifecycle executor, as they are handled by the + -- prebuilds reconciliation loop. + AND workspaces.owner_id != 'c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID ` type GetWorkspacesEligibleForTransitionRow struct { diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index 25e4d4f97a46b..f166d16f742cd 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -758,7 +758,12 @@ WHERE provisioner_jobs.completed_at IS NOT NULL AND (@now :: timestamptz) - provisioner_jobs.completed_at > (INTERVAL '1 millisecond' * (templates.failure_ttl / 1000000)) ) - ) AND workspaces.deleted = 'false'; + ) + AND workspaces.deleted = 'false' + -- Prebuilt workspaces (identified by having the prebuilds system user as owner_id) + -- should not be considered by the lifecycle executor, as they are handled by the + -- prebuilds reconciliation loop. + AND workspaces.owner_id != 'c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID; -- name: UpdateWorkspaceDormantDeletingAt :one UPDATE diff --git a/coderd/schedule/autostart.go b/coderd/schedule/autostart.go index 0a7f583e4f9b2..538d3dd346fcd 100644 --- a/coderd/schedule/autostart.go +++ b/coderd/schedule/autostart.go @@ -33,6 +33,8 @@ func NextAutostart(at time.Time, wsSchedule string, templateSchedule TemplateSch return zonedTransition, allowed } +// NextAllowedAutostart returns the next valid autostart time after 'at', based on the workspace's +// cron schedule and the template's allowed days. It searches up to 7 days ahead to find a match. func NextAllowedAutostart(at time.Time, wsSchedule string, templateSchedule TemplateScheduleOptions) (time.Time, error) { next := at diff --git a/codersdk/workspacebuilds.go b/codersdk/workspacebuilds.go index 4066341773994..0960c6789dea4 100644 --- a/codersdk/workspacebuilds.go +++ b/codersdk/workspacebuilds.go @@ -37,15 +37,18 @@ const ( type BuildReason string const ( - // "initiator" is used when a workspace build is triggered by a user. + // BuildReasonInitiator "initiator" is used when a workspace build is triggered by a user. // Combined with the initiator id/username, it indicates which user initiated the build. BuildReasonInitiator BuildReason = "initiator" - // "autostart" is used when a build to start a workspace is triggered by Autostart. + // BuildReasonAutostart "autostart" is used when a build to start a workspace is triggered by Autostart. // The initiator id/username in this case is the workspace owner and can be ignored. BuildReasonAutostart BuildReason = "autostart" - // "autostop" is used when a build to stop a workspace is triggered by Autostop. + // BuildReasonAutostop "autostop" is used when a build to stop a workspace is triggered by Autostop. // The initiator id/username in this case is the workspace owner and can be ignored. BuildReasonAutostop BuildReason = "autostop" + // BuildReasonDormancy "dormancy" is used when a build to stop a workspace is triggered due to inactivity (dormancy). + // The initiator id/username in this case is the workspace owner and can be ignored. + BuildReasonDormancy BuildReason = "dormancy" ) // WorkspaceBuild is an at-point representation of a workspace state. diff --git a/docs/admin/templates/extending-templates/prebuilt-workspaces.md b/docs/admin/templates/extending-templates/prebuilt-workspaces.md index 2c5e73ad289b4..8e61687ce0f01 100644 --- a/docs/admin/templates/extending-templates/prebuilt-workspaces.md +++ b/docs/admin/templates/extending-templates/prebuilt-workspaces.md @@ -2,13 +2,10 @@ > [!WARNING] > Prebuilds Compatibility Limitations: -> Prebuilt workspaces are currently not compatible with configurations that have Workspace schedule (autostart/autostop), or Dormancy enabled. -> If these features are configured, prebuilt workspaces may fail to run correctly. +> Prebuilt workspaces currently do not work reliably with [DevContainers feature](../managing-templates/devcontainers/index.md). +> If your project relies on DevContainer configuration, we recommend disabling prebuilds or carefully testing behavior before enabling them. > -> In addition, prebuilds currently do not work reliably with [DevContainers feature](../managing-templates/devcontainers/index.md). -> If your project relies on DevContainer configuration, we recommend disabling prebuilds or carefully testing behavior before enabling them in production. -> -> We’re actively working to improve compatibility, but for now, please avoid using prebuilds with these features to ensure stability and expected behavior. +> We’re actively working to improve compatibility, but for now, please avoid using prebuilds with this feature to ensure stability and expected behavior. Prebuilt workspaces allow template administrators to improve the developer experience by reducing workspace creation time with an automatically maintained pool of ready-to-use workspaces for specific parameter presets. @@ -26,7 +23,7 @@ Prebuilt workspaces are: ## Relationship to workspace presets -Prebuilt workspaces are tightly integrated with [workspace presets](./parameters.md#workspace-presets-beta): +Prebuilt workspaces are tightly integrated with [workspace presets](./parameters.md#workspace-presets): 1. Each prebuilt workspace is associated with a specific template preset. 1. The preset must define all required parameters needed to build the workspace. diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 973797d52d554..305c35e1bebdd 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -1049,6 +1049,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `initiator` | | `autostart` | | `autostop` | +| `dormancy` | ## codersdk.ChangePasswordWithOneTimePasscodeRequest diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index 3bed052702637..5d417f0dfb829 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -10,10 +10,17 @@ import ( "os" "os/exec" "path/filepath" + "strings" "sync/atomic" "testing" "time" + "github.com/prometheus/client_golang/prometheus" + + "github.com/coder/coder/v2/coderd/files" + agplprebuilds "github.com/coder/coder/v2/coderd/prebuilds" + "github.com/coder/coder/v2/enterprise/coderd/prebuilds" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1713,6 +1720,793 @@ func TestTemplateDoesNotAllowUserAutostop(t *testing.T) { }) } +func TestExecutorPrebuilds(t *testing.T) { + t.Parallel() + + if !dbtestutil.WillUsePostgres() { + t.Skip("this test requires postgres") + } + + getRunningPrebuilds := func( + t *testing.T, + ctx context.Context, + db database.Store, + prebuildInstances int, + ) []database.GetRunningPrebuiltWorkspacesRow { + t.Helper() + + var runningPrebuilds []database.GetRunningPrebuiltWorkspacesRow + testutil.Eventually(ctx, t, func(context.Context) bool { + rows, err := db.GetRunningPrebuiltWorkspaces(ctx) + if err != nil { + return false + } + + for _, row := range rows { + runningPrebuilds = append(runningPrebuilds, row) + + agents, err := db.GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx, row.ID) + if err != nil { + return false + } + + for _, agent := range agents { + err = db.UpdateWorkspaceAgentLifecycleStateByID(ctx, database.UpdateWorkspaceAgentLifecycleStateByIDParams{ + ID: agent.ID, + LifecycleState: database.WorkspaceAgentLifecycleStateReady, + StartedAt: sql.NullTime{Time: time.Now().Add(time.Hour), Valid: true}, + ReadyAt: sql.NullTime{Time: time.Now().Add(-1 * time.Hour), Valid: true}, + }) + if err != nil { + return false + } + } + } + + t.Logf("found %d running prebuilds so far, want %d", len(runningPrebuilds), prebuildInstances) + return len(runningPrebuilds) == prebuildInstances + }, testutil.IntervalSlow, "prebuilds not running") + + return runningPrebuilds + } + + runReconciliationLoop := func( + t *testing.T, + ctx context.Context, + db database.Store, + reconciler *prebuilds.StoreReconciler, + presets []codersdk.Preset, + ) { + t.Helper() + + state, err := reconciler.SnapshotState(ctx, db) + require.NoError(t, err) + ps, err := state.FilterByPreset(presets[0].ID) + require.NoError(t, err) + require.NotNil(t, ps) + actions, err := reconciler.CalculateActions(ctx, *ps) + require.NoError(t, err) + require.NotNil(t, actions) + require.NoError(t, reconciler.ReconcilePreset(ctx, *ps)) + } + + claimPrebuild := func( + t *testing.T, + ctx context.Context, + client *codersdk.Client, + userClient *codersdk.Client, + username string, + version codersdk.TemplateVersion, + presetID uuid.UUID, + ) codersdk.Workspace { + t.Helper() + + workspaceName := strings.ReplaceAll(testutil.GetRandomName(t), "_", "-") + userWorkspace, err := userClient.CreateUserWorkspace(ctx, username, codersdk.CreateWorkspaceRequest{ + TemplateVersionID: version.ID, + Name: workspaceName, + TemplateVersionPresetID: presetID, + }) + require.NoError(t, err) + build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, userWorkspace.LatestBuild.ID) + require.Equal(t, build.Job.Status, codersdk.ProvisionerJobSucceeded) + workspace := coderdtest.MustWorkspace(t, client, userWorkspace.ID) + assert.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition) + + return workspace + } + + // Prebuilt workspaces should not be autostopped based on the default TTL. + // This test ensures that DefaultTTLMillis is ignored while the workspace is in a prebuild state. + // Once the workspace is claimed, the default autostop timer should take effect. + t.Run("DefaultTTLOnlyTriggersAfterClaim", func(t *testing.T) { + t.Parallel() + + // Set the clock to Monday, January 1st, 2024 at 8:00 AM UTC to keep the test deterministic + clock := quartz.NewMock(t) + clock.Set(time.Date(2024, 1, 1, 8, 0, 0, 0, time.UTC)) + + // Setup + ctx := testutil.Context(t, testutil.WaitSuperLong) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + logger := testutil.Logger(t) + tickCh := make(chan time.Time) + statsCh := make(chan autobuild.Stats) + notificationsNoop := notifications.NewNoopEnqueuer() + client, _, api, owner := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + Clock: clock, + TemplateScheduleStore: schedule.NewEnterpriseTemplateScheduleStore( + agplUserQuietHoursScheduleStore(), + notificationsNoop, + logger, + clock, + ), + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{codersdk.FeatureAdvancedTemplateScheduling: 1}, + }, + }) + + // Setup Prebuild reconciler + cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{}) + reconciler := prebuilds.NewStoreReconciler( + db, pb, cache, + codersdk.PrebuildsConfig{}, + logger, + clock, + prometheus.NewRegistry(), + notificationsNoop, + ) + var claimer agplprebuilds.Claimer = prebuilds.NewEnterpriseClaimer(db) + api.AGPL.PrebuildsClaimer.Store(&claimer) + + // Setup user, template and template version with a preset with 1 prebuild instance + prebuildInstances := int32(1) + ttlTime := 2 * time.Hour + userClient, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleMember()) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithAgentAndPresetsWithPrebuilds(prebuildInstances)) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + // Set a template level TTL to trigger the autostop + // Template level TTL can only be set if autostop is disabled for users + ctr.AllowUserAutostop = ptr.Ref[bool](false) + ctr.DefaultTTLMillis = ptr.Ref[int64](ttlTime.Milliseconds()) + }) + presets, err := client.TemplateVersionPresets(ctx, version.ID) + require.NoError(t, err) + require.Len(t, presets, 1) + + // Given: Reconciliation loop runs and starts prebuilt workspace + runReconciliationLoop(t, ctx, db, reconciler, presets) + runningPrebuilds := getRunningPrebuilds(t, ctx, db, int(prebuildInstances)) + require.Len(t, runningPrebuilds, int(prebuildInstances)) + + // Given: a running prebuilt workspace with a deadline, ready to be claimed + prebuild := coderdtest.MustWorkspace(t, client, runningPrebuilds[0].ID) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + require.NotZero(t, prebuild.LatestBuild.Deadline) + + // When: the autobuild executor ticks *after* the deadline + next := prebuild.LatestBuild.Deadline.Time.Add(time.Minute) + clock.Set(next) + go func() { + tickCh <- next + }() + + // Then: the prebuilt workspace should remain in a start transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + + // Given: a user claims the prebuilt workspace sometime later + clock.Set(clock.Now().Add(ttlTime)) + workspace := claimPrebuild(t, ctx, client, userClient, user.Username, version, presets[0].ID) + require.Equal(t, prebuild.ID, workspace.ID) + // Workspace deadline must be ttlTime from the time it is claimed + require.True(t, workspace.LatestBuild.Deadline.Time.Equal(clock.Now().Add(ttlTime))) + + // When: the autobuild executor ticks *after* the deadline + next = workspace.LatestBuild.Deadline.Time.Add(time.Minute) + clock.Set(next) + go func() { + tickCh <- next + close(tickCh) + }() + + // Then: the workspace should be stopped + workspaceStats := <-statsCh + require.Len(t, workspaceStats.Errors, 0) + require.Len(t, workspaceStats.Transitions, 1) + require.Contains(t, workspaceStats.Transitions, workspace.ID) + require.Equal(t, database.WorkspaceTransitionStop, workspaceStats.Transitions[workspace.ID]) + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.Equal(t, codersdk.BuildReasonAutostop, workspace.LatestBuild.Reason) + }) + + // Prebuild workspaces should not follow the autostop schedule. + // This test verifies that AutostopRequirement (autostop schedule) is ignored while the workspace is a prebuild. + // After being claimed, the workspace should be stopped according to the autostop schedule. + t.Run("AutostopScheduleOnlyTriggersAfterClaim", func(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + isClaimedBeforeDeadline bool + }{ + // If the prebuild is claimed before the scheduled deadline, + // the claimed workspace should inherit and respect that same deadline. + { + name: "ClaimedBeforeDeadline_UsesSameDeadline", + isClaimedBeforeDeadline: true, + }, + // If the prebuild is claimed after the scheduled deadline, + // the workspace should not stop immediately, but instead respect the next + // valid scheduled deadline (the next day). + { + name: "ClaimedAfterDeadline_SchedulesForNextDay", + isClaimedBeforeDeadline: false, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + // Set the clock to Monday, January 1st, 2024 at 8:00 AM UTC to keep the test deterministic + clock := quartz.NewMock(t) + clock.Set(time.Date(2024, 1, 1, 8, 0, 0, 0, time.UTC)) + + // Setup + ctx := testutil.Context(t, testutil.WaitSuperLong) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + logger := testutil.Logger(t) + tickCh := make(chan time.Time) + statsCh := make(chan autobuild.Stats) + notificationsNoop := notifications.NewNoopEnqueuer() + client, _, api, owner := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + Clock: clock, + TemplateScheduleStore: schedule.NewEnterpriseTemplateScheduleStore( + agplUserQuietHoursScheduleStore(), + notificationsNoop, + logger, + clock, + ), + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{codersdk.FeatureAdvancedTemplateScheduling: 1}, + }, + }) + + // Setup Prebuild reconciler + cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{}) + reconciler := prebuilds.NewStoreReconciler( + db, pb, cache, + codersdk.PrebuildsConfig{}, + logger, + clock, + prometheus.NewRegistry(), + notificationsNoop, + ) + var claimer agplprebuilds.Claimer = prebuilds.NewEnterpriseClaimer(db) + api.AGPL.PrebuildsClaimer.Store(&claimer) + + // Setup user, template and template version with a preset with 1 prebuild instance + prebuildInstances := int32(1) + userClient, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleMember()) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithAgentAndPresetsWithPrebuilds(prebuildInstances)) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + // Set a template level Autostop schedule to trigger the autostop daily + ctr.AutostopRequirement = ptr.Ref[codersdk.TemplateAutostopRequirement]( + codersdk.TemplateAutostopRequirement{ + DaysOfWeek: []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}, + Weeks: 1, + }) + }) + presets, err := client.TemplateVersionPresets(ctx, version.ID) + require.NoError(t, err) + require.Len(t, presets, 1) + + // Given: Reconciliation loop runs and starts prebuilt workspace + runReconciliationLoop(t, ctx, db, reconciler, presets) + runningPrebuilds := getRunningPrebuilds(t, ctx, db, int(prebuildInstances)) + require.Len(t, runningPrebuilds, int(prebuildInstances)) + + // Given: a running prebuilt workspace with a deadline, ready to be claimed + prebuild := coderdtest.MustWorkspace(t, client, runningPrebuilds[0].ID) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + require.NotZero(t, prebuild.LatestBuild.Deadline) + + next := clock.Now() + if tc.isClaimedBeforeDeadline { + // When: the autobuild executor ticks *before* the deadline: + next = next.Add(time.Minute) + } else { + // When: the autobuild executor ticks *after* the deadline: + next = next.Add(24 * time.Hour) + } + + clock.Set(next) + go func() { + tickCh <- next + }() + + // Then: the prebuilt workspace should remain in a start transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + + // Given: a user claims the prebuilt workspace + workspace := claimPrebuild(t, ctx, client, userClient, user.Username, version, presets[0].ID) + require.Equal(t, prebuild.ID, workspace.ID) + + if tc.isClaimedBeforeDeadline { + // Then: the claimed workspace should inherit and respect that same deadline. + require.True(t, workspace.LatestBuild.Deadline.Time.Equal(prebuild.LatestBuild.Deadline.Time)) + } else { + // Then: the claimed workspace should respect the next valid scheduled deadline (next day). + require.True(t, workspace.LatestBuild.Deadline.Time.Equal(clock.Now().Truncate(24*time.Hour).Add(24*time.Hour))) + } + + // When: the autobuild executor ticks *after* the deadline: + next = workspace.LatestBuild.Deadline.Time.Add(time.Minute) + clock.Set(next) + go func() { + tickCh <- next + close(tickCh) + }() + + // Then: the workspace should be stopped + workspaceStats := <-statsCh + require.Len(t, workspaceStats.Errors, 0) + require.Len(t, workspaceStats.Transitions, 1) + require.Contains(t, workspaceStats.Transitions, workspace.ID) + require.Equal(t, database.WorkspaceTransitionStop, workspaceStats.Transitions[workspace.ID]) + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.Equal(t, codersdk.BuildReasonAutostop, workspace.LatestBuild.Reason) + }) + } + }) + + // Prebuild workspaces should not follow the autostart schedule. + // This test verifies that AutostartRequirement (autostart schedule) is ignored while the workspace is a prebuild. + t.Run("AutostartScheduleOnlyTriggersAfterClaim", func(t *testing.T) { + t.Parallel() + + // Set the clock to dbtime.Now() to match the workspace build's CreatedAt + clock := quartz.NewMock(t) + clock.Set(dbtime.Now()) + + // Setup + ctx := testutil.Context(t, testutil.WaitSuperLong) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + logger := testutil.Logger(t) + tickCh := make(chan time.Time) + statsCh := make(chan autobuild.Stats) + notificationsNoop := notifications.NewNoopEnqueuer() + client, _, api, owner := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + Clock: clock, + TemplateScheduleStore: schedule.NewEnterpriseTemplateScheduleStore( + agplUserQuietHoursScheduleStore(), + notificationsNoop, + logger, + clock, + ), + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{codersdk.FeatureAdvancedTemplateScheduling: 1}, + }, + }) + + // Setup Prebuild reconciler + cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{}) + reconciler := prebuilds.NewStoreReconciler( + db, pb, cache, + codersdk.PrebuildsConfig{}, + logger, + clock, + prometheus.NewRegistry(), + notificationsNoop, + ) + var claimer agplprebuilds.Claimer = prebuilds.NewEnterpriseClaimer(db) + api.AGPL.PrebuildsClaimer.Store(&claimer) + + // Setup user, template and template version with a preset with 1 prebuild instance + prebuildInstances := int32(1) + userClient, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleMember()) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithAgentAndPresetsWithPrebuilds(prebuildInstances)) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + // Set a template level Autostart schedule to trigger the autostart daily + ctr.AllowUserAutostart = ptr.Ref[bool](true) + ctr.AutostartRequirement = &codersdk.TemplateAutostartRequirement{DaysOfWeek: codersdk.AllDaysOfWeek} + }) + presets, err := client.TemplateVersionPresets(ctx, version.ID) + require.NoError(t, err) + require.Len(t, presets, 1) + + // Given: Reconciliation loop runs and starts prebuilt workspace + runReconciliationLoop(t, ctx, db, reconciler, presets) + runningPrebuilds := getRunningPrebuilds(t, ctx, db, int(prebuildInstances)) + require.Len(t, runningPrebuilds, int(prebuildInstances)) + + // Given: prebuilt workspace has autostart schedule daily at midnight + prebuild := coderdtest.MustWorkspace(t, client, runningPrebuilds[0].ID) + sched, err := cron.Weekly("CRON_TZ=UTC 0 0 * * *") + require.NoError(t, err) + err = client.UpdateWorkspaceAutostart(ctx, prebuild.ID, codersdk.UpdateWorkspaceAutostartRequest{ + Schedule: ptr.Ref(sched.String()), + }) + require.NoError(t, err) + + // Given: prebuilt workspace is stopped + prebuild = coderdtest.MustTransitionWorkspace(t, client, prebuild.ID, codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, prebuild.LatestBuild.ID) + + // Tick at the next scheduled time after the prebuild’s LatestBuild.CreatedAt, + // since the next allowed autostart is calculated starting from that point. + // When: the autobuild executor ticks after the scheduled time + go func() { + tickCh <- sched.Next(prebuild.LatestBuild.CreatedAt).Add(time.Minute) + }() + + // Then: the prebuilt workspace should remain in a stop transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStop, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + + // Given: a prebuilt workspace that is running and ready to be claimed + prebuild = coderdtest.MustTransitionWorkspace(t, client, prebuild.ID, codersdk.WorkspaceTransitionStop, codersdk.WorkspaceTransitionStart) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, prebuild.LatestBuild.ID) + + // Make sure the workspace's agent is again ready + getRunningPrebuilds(t, ctx, db, int(prebuildInstances)) + + // Given: a user claims the prebuilt workspace + workspace := claimPrebuild(t, ctx, client, userClient, user.Username, version, presets[0].ID) + require.Equal(t, prebuild.ID, workspace.ID) + require.NotNil(t, workspace.NextStartAt) + + // Given: workspace is stopped + workspace = coderdtest.MustTransitionWorkspace(t, client, workspace.ID, codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + + // Then: the claimed workspace should inherit and respect that same NextStartAt + require.True(t, workspace.NextStartAt.Equal(*prebuild.NextStartAt)) + + // Tick at the next scheduled time after the prebuild’s LatestBuild.CreatedAt, + // since the next allowed autostart is calculated starting from that point. + // When: the autobuild executor ticks after the scheduled time + go func() { + tickCh <- sched.Next(prebuild.LatestBuild.CreatedAt).Add(time.Minute) + }() + + // Then: the workspace should have a NextStartAt equal to the next autostart schedule + workspaceStats := <-statsCh + require.Len(t, workspaceStats.Errors, 0) + require.Len(t, workspaceStats.Transitions, 1) + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.NotNil(t, workspace.NextStartAt) + require.Equal(t, sched.Next(clock.Now()), workspace.NextStartAt.UTC()) + }) + + // Prebuild workspaces should not transition to dormant when the inactive TTL is reached. + // This test verifies that TimeTilDormantMillis is ignored while the workspace is a prebuild. + // After being claimed, the workspace should become dormant according to the configured inactivity period. + t.Run("DormantOnlyAfterClaimed", func(t *testing.T) { + t.Parallel() + + // Set the clock to Monday, January 1st, 2024 at 8:00 AM UTC to keep the test deterministic + clock := quartz.NewMock(t) + clock.Set(time.Date(2024, 1, 1, 8, 0, 0, 0, time.UTC)) + + // Setup + ctx := testutil.Context(t, testutil.WaitSuperLong) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + logger := testutil.Logger(t) + tickCh := make(chan time.Time) + statsCh := make(chan autobuild.Stats) + notificationsNoop := notifications.NewNoopEnqueuer() + client, _, api, owner := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + Clock: clock, + TemplateScheduleStore: schedule.NewEnterpriseTemplateScheduleStore( + agplUserQuietHoursScheduleStore(), + notificationsNoop, + logger, + clock, + ), + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{codersdk.FeatureAdvancedTemplateScheduling: 1}, + }, + }) + + // Setup Prebuild reconciler + cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{}) + reconciler := prebuilds.NewStoreReconciler( + db, pb, cache, + codersdk.PrebuildsConfig{}, + logger, + clock, + prometheus.NewRegistry(), + notificationsNoop, + ) + var claimer agplprebuilds.Claimer = prebuilds.NewEnterpriseClaimer(db) + api.AGPL.PrebuildsClaimer.Store(&claimer) + + // Setup user, template and template version with a preset with 1 prebuild instance + prebuildInstances := int32(1) + inactiveTTL := 2 * time.Hour + userClient, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleMember()) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithAgentAndPresetsWithPrebuilds(prebuildInstances)) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + // Set a template level inactive TTL to trigger dormancy + ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) + }) + presets, err := client.TemplateVersionPresets(ctx, version.ID) + require.NoError(t, err) + require.Len(t, presets, 1) + + // Given: reconciliation loop runs and starts prebuilt workspace + runReconciliationLoop(t, ctx, db, reconciler, presets) + runningPrebuilds := getRunningPrebuilds(t, ctx, db, int(prebuildInstances)) + require.Len(t, runningPrebuilds, int(prebuildInstances)) + + // Given: a running prebuilt workspace, ready to be claimed + prebuild := coderdtest.MustWorkspace(t, client, runningPrebuilds[0].ID) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + + // When: the autobuild executor ticks *after* the inactive TTL + go func() { + tickCh <- prebuild.LastUsedAt.Add(inactiveTTL).Add(time.Minute) + }() + + // Then: the prebuilt workspace should remain in a start transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + + // Given: a user claims the prebuilt workspace sometime later + clock.Set(clock.Now().Add(inactiveTTL)) + workspace := claimPrebuild(t, ctx, client, userClient, user.Username, version, presets[0].ID) + require.Equal(t, prebuild.ID, workspace.ID) + require.Nil(t, prebuild.DormantAt) + + // When: the autobuild executor ticks *after* the inactive TTL + go func() { + tickCh <- prebuild.LastUsedAt.Add(inactiveTTL).Add(time.Minute) + close(tickCh) + }() + + // Then: the workspace should transition to stopped state for breaching failure TTL + workspaceStats := <-statsCh + require.Len(t, workspaceStats.Errors, 0) + require.Len(t, workspaceStats.Transitions, 1) + require.Contains(t, workspaceStats.Transitions, workspace.ID) + require.Equal(t, database.WorkspaceTransitionStop, workspaceStats.Transitions[workspace.ID]) + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.Equal(t, codersdk.BuildReasonDormancy, workspace.LatestBuild.Reason) + require.NotNil(t, workspace.DormantAt) + }) + + // Prebuild workspaces should not be deleted when the failure TTL is reached. + // This test verifies that FailureTTLMillis is ignored while the workspace is a prebuild. + t.Run("FailureTTLOnlyAfterClaimed", func(t *testing.T) { + t.Parallel() + + // Set the clock to Monday, January 1st, 2024 at 8:00 AM UTC to keep the test deterministic + clock := quartz.NewMock(t) + clock.Set(time.Date(2024, 1, 1, 8, 0, 0, 0, time.UTC)) + + // Setup + ctx := testutil.Context(t, testutil.WaitSuperLong) + db, pb := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure()) + logger := testutil.Logger(t) + tickCh := make(chan time.Time) + statsCh := make(chan autobuild.Stats) + notificationsNoop := notifications.NewNoopEnqueuer() + client, _, api, owner := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + Database: db, + Pubsub: pb, + AutobuildTicker: tickCh, + IncludeProvisionerDaemon: true, + AutobuildStats: statsCh, + Clock: clock, + TemplateScheduleStore: schedule.NewEnterpriseTemplateScheduleStore( + agplUserQuietHoursScheduleStore(), + notificationsNoop, + logger, + clock, + ), + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureAdvancedTemplateScheduling: 1, + }, + }, + }) + + // Setup Prebuild reconciler + cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{}) + reconciler := prebuilds.NewStoreReconciler( + db, pb, cache, + codersdk.PrebuildsConfig{}, + logger, + clock, + prometheus.NewRegistry(), + notificationsNoop, + ) + var claimer agplprebuilds.Claimer = prebuilds.NewEnterpriseClaimer(db) + api.AGPL.PrebuildsClaimer.Store(&claimer) + + // Setup user, template and template version with a preset with 1 prebuild instance + prebuildInstances := int32(1) + failureTTL := 2 * time.Hour + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, templateWithFailedResponseAndPresetsWithPrebuilds(prebuildInstances)) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + // Set a template level Failure TTL to trigger workspace deletion + ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) + }) + presets, err := client.TemplateVersionPresets(ctx, version.ID) + require.NoError(t, err) + require.Len(t, presets, 1) + + // Given: reconciliation loop runs and starts prebuilt workspace in failed state + runReconciliationLoop(t, ctx, db, reconciler, presets) + + var failedWorkspaceBuilds []database.GetFailedWorkspaceBuildsByTemplateIDRow + require.Eventually(t, func() bool { + rows, err := db.GetFailedWorkspaceBuildsByTemplateID(ctx, database.GetFailedWorkspaceBuildsByTemplateIDParams{ + TemplateID: template.ID, + }) + if err != nil { + return false + } + + failedWorkspaceBuilds = append(failedWorkspaceBuilds, rows...) + + t.Logf("found %d failed prebuilds so far, want %d", len(failedWorkspaceBuilds), prebuildInstances) + return len(failedWorkspaceBuilds) == int(prebuildInstances) + }, testutil.WaitSuperLong, testutil.IntervalSlow) + require.Len(t, failedWorkspaceBuilds, int(prebuildInstances)) + + // Given: a failed prebuilt workspace + prebuild := coderdtest.MustWorkspace(t, client, failedWorkspaceBuilds[0].WorkspaceID) + require.Equal(t, codersdk.WorkspaceStatusFailed, prebuild.LatestBuild.Status) + + // When: the autobuild executor ticks *after* the failure TTL + go func() { + tickCh <- prebuild.LatestBuild.Job.CompletedAt.Add(failureTTL * 2) + }() + + // Then: the prebuilt workspace should remain in a start transition + prebuildStats := <-statsCh + require.Len(t, prebuildStats.Errors, 0) + require.Len(t, prebuildStats.Transitions, 0) + require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition) + prebuild = coderdtest.MustWorkspace(t, client, prebuild.ID) + require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason) + }) +} + +func templateWithAgentAndPresetsWithPrebuilds(desiredInstances int32) *echo.Responses { + return &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: []*proto.Response{ + { + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Presets: []*proto.Preset{ + { + Name: "preset-test", + Parameters: []*proto.PresetParameter{ + { + Name: "k1", + Value: "v1", + }, + }, + Prebuild: &proto.Prebuild{ + Instances: desiredInstances, + }, + }, + }, + }, + }, + }, + }, + ProvisionApply: []*proto.Response{ + { + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ + Resources: []*proto.Resource{ + { + Type: "compute", + Name: "main", + Agents: []*proto.Agent{ + { + Name: "smith", + OperatingSystem: "linux", + Architecture: "i386", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func templateWithFailedResponseAndPresetsWithPrebuilds(desiredInstances int32) *echo.Responses { + return &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: []*proto.Response{ + { + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Presets: []*proto.Preset{ + { + Name: "preset-test", + Parameters: []*proto.PresetParameter{ + { + Name: "k1", + Value: "v1", + }, + }, + Prebuild: &proto.Prebuild{ + Instances: desiredInstances, + }, + }, + }, + }, + }, + }, + }, + ProvisionApply: echo.ApplyFailed, + } +} + // TestWorkspaceTemplateParamsChange tests a workspace with a parameter that // validation changes on apply. The params used in create workspace are invalid // according to the static params on import. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 399b79499edd9..8a8a5583e9069 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -275,11 +275,12 @@ export interface BuildInfoResponse { } // From codersdk/workspacebuilds.go -export type BuildReason = "autostart" | "autostop" | "initiator"; +export type BuildReason = "autostart" | "autostop" | "dormancy" | "initiator"; export const BuildReasons: BuildReason[] = [ "autostart", "autostop", + "dormancy", "initiator", ]; diff --git a/site/src/utils/workspace.tsx b/site/src/utils/workspace.tsx index 135b965589054..c88ffc9d8edaa 100644 --- a/site/src/utils/workspace.tsx +++ b/site/src/utils/workspace.tsx @@ -75,14 +75,16 @@ export const getDisplayWorkspaceBuildStatus = ( export const getDisplayWorkspaceBuildInitiatedBy = ( build: TypesGen.WorkspaceBuild, -): string => { +): string | undefined => { switch (build.reason) { case "initiator": return build.initiator_name; case "autostart": case "autostop": + case "dormancy": return "Coder"; } + return undefined; }; const getWorkspaceBuildDurationInSeconds = ( From bf0271fd65ca301101fe620fe022822aa9737159 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Tue, 8 Jul 2025 15:56:22 +0400 Subject: [PATCH 07/61] chore: stop running postgres-only tests if DB is not set (#18784) Fixes https://github.com/coder/internal/issues/695 PostgreSQL tests are getting run in a non-postgres CI job because the tests don't get skipped if the `DB=` env is unset. This PR adds a skip for them. They are flaking in the `test-go-race` CI job. They run fine in the `test-go-race-pg` job, which pre-creates the postgres server, so the flakiness is almost certainly related to spinning up the database server. --- coderd/database/db_test.go | 4 ++++ coderd/database/dbtestutil/postgres.go | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/coderd/database/db_test.go b/coderd/database/db_test.go index 68b60a788fd3d..f9442942e53e1 100644 --- a/coderd/database/db_test.go +++ b/coderd/database/db_test.go @@ -85,6 +85,10 @@ func TestNestedInTx(t *testing.T) { func testSQLDB(t testing.TB) *sql.DB { t.Helper() + if !dbtestutil.WillUsePostgres() { + t.Skip("this test requires postgres") + } + connection, err := dbtestutil.Open(t) require.NoError(t, err) diff --git a/coderd/database/dbtestutil/postgres.go b/coderd/database/dbtestutil/postgres.go index c1cfa383577de..e5aa4b14de83b 100644 --- a/coderd/database/dbtestutil/postgres.go +++ b/coderd/database/dbtestutil/postgres.go @@ -81,7 +81,7 @@ func initDefaultConnection(t TBSubset) error { } var dbErr error - // Retry up to 3 seconds for temporary errors. + // Retry up to 10 seconds for temporary errors. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() for r := retry.New(10*time.Millisecond, 500*time.Millisecond); r.Wait(ctx); { @@ -93,7 +93,7 @@ func initDefaultConnection(t TBSubset) error { if !containsAnySubstring(errString, retryableErrSubstrings) { break } - t.Logf("failed to connect to postgres, retrying: %s", errString) + t.Logf("%s failed to connect to postgres, retrying: %s", time.Now().Format(time.StampMilli), errString) } // After the loop dbErr is the last connection error (if any). From ac4be155d9a0d73146db17dc28beedbceec71edc Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 16:31:05 +0200 Subject: [PATCH 08/61] chore(coderd/runtimeconfig): remove dbmem from tests (#18790) Related to https://github.com/coder/coder/issues/15109. --- coderd/runtimeconfig/entry_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coderd/runtimeconfig/entry_test.go b/coderd/runtimeconfig/entry_test.go index 3092dae88c4cd..f8e2a925e29d8 100644 --- a/coderd/runtimeconfig/entry_test.go +++ b/coderd/runtimeconfig/entry_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/runtimeconfig" "github.com/coder/coder/v2/testutil" "github.com/coder/serpent" @@ -32,7 +32,7 @@ func TestEntry(t *testing.T) { ctx := testutil.Context(t, testutil.WaitShort) mgr := runtimeconfig.NewManager() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) override := serpent.String("dogfood@dev.coder.com") @@ -54,7 +54,7 @@ func TestEntry(t *testing.T) { ctx := testutil.Context(t, testutil.WaitShort) mgr := runtimeconfig.NewManager() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) override := serpent.Struct[map[string]string]{ Value: map[string]string{ From 321396d9d62f5ea4f7ee4ca838cfed7c62f0d58e Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 16:31:20 +0200 Subject: [PATCH 09/61] chore(coderd/rbac/rolestore): remove dbmem from tests (#18789) Related to https://github.com/coder/coder/issues/15109 --- coderd/rbac/rolestore/rolestore_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/rbac/rolestore/rolestore_test.go b/coderd/rbac/rolestore/rolestore_test.go index b7712357d0721..47289704d8e49 100644 --- a/coderd/rbac/rolestore/rolestore_test.go +++ b/coderd/rbac/rolestore/rolestore_test.go @@ -8,7 +8,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/rolestore" "github.com/coder/coder/v2/testutil" @@ -17,7 +17,7 @@ import ( func TestExpandCustomRoleRoles(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) org := dbgen.Organization(t, db, database.Organization{}) From e0fb15eeff2355ae7cd9c215d830ed6588b6e677 Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 16:32:24 +0200 Subject: [PATCH 10/61] chore(coderd/searchquery): remove dbmem from tests (#18791) Related to https://github.com/coder/coder/issues/15109. --- coderd/searchquery/search_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/coderd/searchquery/search_test.go b/coderd/searchquery/search_test.go index 2b7f4f402e008..ad5f2df966ef9 100644 --- a/coderd/searchquery/search_test.go +++ b/coderd/searchquery/search_test.go @@ -14,7 +14,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/searchquery" "github.com/coder/coder/v2/codersdk" ) @@ -300,7 +300,7 @@ func TestSearchWorkspace(t *testing.T) { t.Run(c.Name, func(t *testing.T) { t.Parallel() // TODO: Replace this with the mock database. - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) if c.Setup != nil { c.Setup(t, db) } @@ -331,7 +331,8 @@ func TestSearchWorkspace(t *testing.T) { query := `` timeout := 1337 * time.Second - values, errs := searchquery.Workspaces(context.Background(), dbmem.New(), query, codersdk.Pagination{}, timeout) + db, _ := dbtestutil.NewDB(t) + values, errs := searchquery.Workspaces(context.Background(), db, query, codersdk.Pagination{}, timeout) require.Empty(t, errs) require.Equal(t, int64(timeout.Seconds()), values.AgentInactiveDisconnectTimeoutSeconds) }) @@ -389,7 +390,7 @@ func TestSearchAudit(t *testing.T) { t.Parallel() // Do not use a real database, this is only used for an // organization lookup. - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) values, countValues, errs := searchquery.AuditLogs(context.Background(), db, c.Query) if c.ExpectedErrorContains != "" { require.True(t, len(errs) > 0, "expect some errors") @@ -628,7 +629,7 @@ func TestSearchTemplates(t *testing.T) { t.Parallel() // Do not use a real database, this is only used for an // organization lookup. - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) values, errs := searchquery.Templates(context.Background(), db, c.Query) if c.ExpectedErrorContains != "" { require.True(t, len(errs) > 0, "expect some errors") From 7f681910e934f13017c17345a3e14b37c05d9094 Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 16:32:46 +0200 Subject: [PATCH 11/61] chore(coderd/updatecheck): remove dbmem from tests (#18792) Related to https://github.com/coder/coder/issues/15109. --- coderd/updatecheck/updatecheck_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coderd/updatecheck/updatecheck_test.go b/coderd/updatecheck/updatecheck_test.go index 725ceb44d9d6f..2e616a550f231 100644 --- a/coderd/updatecheck/updatecheck_test.go +++ b/coderd/updatecheck/updatecheck_test.go @@ -14,7 +14,7 @@ import ( "cdr.dev/slog/sloggers/slogtest" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/updatecheck" "github.com/coder/coder/v2/testutil" ) @@ -49,7 +49,7 @@ func TestChecker_Notify(t *testing.T) { })) defer srv.Close() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Named(t.Name()) notify := make(chan updatecheck.Result, len(wantVersion)) c := updatecheck.New(db, logger, updatecheck.Options{ @@ -130,7 +130,7 @@ func TestChecker_Latest(t *testing.T) { })) defer srv.Close() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Named(t.Name()) c := updatecheck.New(db, logger, updatecheck.Options{ URL: srv.URL, From f147ebf37db933a19a0f36638f21a4014a0e2359 Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 16:39:02 +0200 Subject: [PATCH 12/61] chore(enterprise/audit): remove dbmem from tests (#18794) Related to https://github.com/coder/coder/issues/15109. --- enterprise/audit/audit_test.go | 5 +++-- enterprise/audit/backends/postgres_test.go | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/enterprise/audit/audit_test.go b/enterprise/audit/audit_test.go index bf9393612d65c..dd5d6274f65e9 100644 --- a/enterprise/audit/audit_test.go +++ b/enterprise/audit/audit_test.go @@ -8,7 +8,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/enterprise/audit" "github.com/coder/coder/v2/enterprise/audit/audittest" ) @@ -86,11 +86,12 @@ func TestAuditor(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() + db, _ := dbtestutil.NewDB(t) var ( backend = &testBackend{decision: test.backendDecision, err: test.backendError} exporter = audit.NewAuditor( - dbmem.New(), + db, audit.FilterFunc(func(_ context.Context, _ database.AuditLog) (audit.FilterDecision, error) { return test.filterDecision, test.filterError }), diff --git a/enterprise/audit/backends/postgres_test.go b/enterprise/audit/backends/postgres_test.go index d9a517ca62eaf..5d0032e207ed3 100644 --- a/enterprise/audit/backends/postgres_test.go +++ b/enterprise/audit/backends/postgres_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/enterprise/audit" "github.com/coder/coder/v2/enterprise/audit/audittest" "github.com/coder/coder/v2/enterprise/audit/backends" @@ -20,7 +20,7 @@ func TestPostgresBackend(t *testing.T) { var ( ctx, cancel = context.WithCancel(context.Background()) - db = dbmem.New() + db, _ = dbtestutil.NewDB(t) pgb = backends.NewPostgres(db, true) alog = audittest.RandomLog() ) From 733d3f12871cc9f33a16f1b07b0bf0b7c0535f3d Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 16:59:03 +0200 Subject: [PATCH 13/61] chore(enterprise/cli): remove dbmem from tests (#18795) Related to https://github.com/coder/coder/issues/15109. --- enterprise/cli/server_test.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/enterprise/cli/server_test.go b/enterprise/cli/server_test.go index d913bc443c19f..7022f0d33b7a7 100644 --- a/enterprise/cli/server_test.go +++ b/enterprise/cli/server_test.go @@ -12,10 +12,20 @@ import ( "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/cli/config" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/enterprise/cli" "github.com/coder/coder/v2/testutil" ) +func dbArg(t *testing.T) string { + if !dbtestutil.WillUsePostgres() { + return "--in-memory" + } + dbURL, err := dbtestutil.Open(t) + require.NoError(t, err) + return "--postgres-url=" + dbURL +} + // TestServer runs the enterprise server command // and waits for /healthz to return "OK". func TestServer_Single(t *testing.T) { @@ -27,9 +37,10 @@ func TestServer_Single(t *testing.T) { var root cli.RootCmd cmd, err := root.Command(root.EnterpriseSubcommands()) require.NoError(t, err) + inv, cfg := clitest.NewWithCommand(t, cmd, "server", - "--in-memory", + dbArg(t), "--http-address", ":0", "--access-url", "http://example.com", ) From 0dc36127c045fdd8a92cc9441effa0f9776d5bbd Mon Sep 17 00:00:00 2001 From: Susana Ferreira Date: Tue, 8 Jul 2025 16:13:36 +0100 Subject: [PATCH 14/61] chore(dogfood): update filebrowser module to version 1.1.1 (#18799) Workspaces with `Write Coder on Coder` template are failing with an error in the agent related to File Browser: ``` 2025/07/08 14:00:29 Using database: /home/coder/filebrowser.db 2025/07/08 14:00:29 password is too short, minimum length is 12 ``` Updating filebrowser module version to 1.1.1: https://github.com/coder/registry/pull/173 --- dogfood/coder/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dogfood/coder/main.tf b/dogfood/coder/main.tf index a9cb72b9c7984..fff0bc5f5d169 100644 --- a/dogfood/coder/main.tf +++ b/dogfood/coder/main.tf @@ -315,7 +315,7 @@ module "jetbrains" { module "filebrowser" { count = data.coder_workspace.me.start_count source = "dev.registry.coder.com/coder/filebrowser/coder" - version = "1.0.31" + version = "1.1.1" agent_id = coder_agent.dev.id agent_name = "dev" } From b65e133a17c730f4024ea99da6c38c3041ed0d5b Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 17:16:46 +0200 Subject: [PATCH 15/61] chore(enterprise/coderd): remove dbmem from tests (#18797) Related to https://github.com/coder/coder/issues/15109. --- enterprise/coderd/coderd_test.go | 7 ++- .../coderd/dormancy/dormantusersjob_test.go | 20 +++++-- .../coderd/enidpsync/organizations_test.go | 4 -- enterprise/coderd/license/license_test.go | 58 ++++++++++--------- .../coderd/proxyhealth/proxyhealth_test.go | 10 ++-- 5 files changed, 56 insertions(+), 43 deletions(-) diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go index 89a61c657e21a..52301f6dae034 100644 --- a/enterprise/coderd/coderd_test.go +++ b/enterprise/coderd/coderd_test.go @@ -42,7 +42,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbfake" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/rbac" @@ -323,10 +322,11 @@ func TestAuditLogging(t *testing.T) { t.Parallel() t.Run("Enabled", func(t *testing.T) { t.Parallel() + db, _ := dbtestutil.NewDB(t) _, _, api, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ AuditLogging: true, Options: &coderdtest.Options{ - Auditor: audit.NewAuditor(dbmem.New(), audit.DefaultFilter), + Auditor: audit.NewAuditor(db, audit.DefaultFilter), }, LicenseOptions: &coderdenttest.LicenseOptions{ Features: license.Features{ @@ -334,8 +334,9 @@ func TestAuditLogging(t *testing.T) { }, }, }) + db, _ = dbtestutil.NewDB(t) auditor := *api.AGPL.Auditor.Load() - ea := audit.NewAuditor(dbmem.New(), audit.DefaultFilter) + ea := audit.NewAuditor(db, audit.DefaultFilter) t.Logf("%T = %T", auditor, ea) assert.EqualValues(t, reflect.ValueOf(ea).Type(), reflect.ValueOf(auditor).Type()) }) diff --git a/enterprise/coderd/dormancy/dormantusersjob_test.go b/enterprise/coderd/dormancy/dormantusersjob_test.go index bb3e0b4170baf..e5e5276fe67a9 100644 --- a/enterprise/coderd/dormancy/dormantusersjob_test.go +++ b/enterprise/coderd/dormancy/dormantusersjob_test.go @@ -12,7 +12,7 @@ import ( "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/enterprise/coderd/dormancy" "github.com/coder/quartz" ) @@ -26,7 +26,7 @@ func TestCheckInactiveUsers(t *testing.T) { // Add some dormant accounts logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}) - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) @@ -75,7 +75,7 @@ func TestCheckInactiveUsers(t *testing.T) { allUsers := ignoreUpdatedAt(database.ConvertUserRows(rows)) // Verify user status - expectedUsers := []database.User{ + expectedUsers := ignoreUpdatedAt([]database.User{ asDormant(inactiveUser1), asDormant(inactiveUser2), asDormant(inactiveUser3), @@ -85,14 +85,24 @@ func TestCheckInactiveUsers(t *testing.T) { suspendedUser1, suspendedUser2, suspendedUser3, - } + }) + require.ElementsMatch(t, allUsers, expectedUsers) } func setupUser(ctx context.Context, t *testing.T, db database.Store, email string, status database.UserStatus, lastSeenAt time.Time) database.User { t.Helper() - user, err := db.InsertUser(ctx, database.InsertUserParams{ID: uuid.New(), LoginType: database.LoginTypePassword, Username: uuid.NewString()[:8], Email: email}) + now := dbtestutil.NowInDefaultTimezone() + user, err := db.InsertUser(ctx, database.InsertUserParams{ + ID: uuid.New(), + LoginType: database.LoginTypePassword, + Username: uuid.NewString()[:8], + Email: email, + RBACRoles: []string{}, + CreatedAt: now, + UpdatedAt: now, + }) require.NoError(t, err) // At the beginning of the test all users are marked as active user, err = db.UpdateUserStatus(ctx, database.UpdateUserStatusParams{ID: user.ID, Status: status}) diff --git a/enterprise/coderd/enidpsync/organizations_test.go b/enterprise/coderd/enidpsync/organizations_test.go index d2a5aafece558..13a9bd69ed8fd 100644 --- a/enterprise/coderd/enidpsync/organizations_test.go +++ b/enterprise/coderd/enidpsync/organizations_test.go @@ -53,10 +53,6 @@ type OrganizationSyncTestCase struct { func TestOrganizationSync(t *testing.T) { t.Parallel() - if dbtestutil.WillUsePostgres() { - t.Skip("Skipping test because it populates a lot of db entries, which is slow on postgres") - } - requireUserOrgs := func(t *testing.T, db database.Store, user database.User, expected []uuid.UUID) { t.Helper() diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index bf6d6448205e0..d23dc617817f5 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" @@ -30,7 +30,7 @@ func TestEntitlements(t *testing.T) { t.Run("Defaults", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) entitlements, err := license.Entitlements(context.Background(), db, 1, 1, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -42,7 +42,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("Always return the current user count", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) entitlements, err := license.Entitlements(context.Background(), db, 1, 1, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -51,7 +51,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("SingleLicenseNothing", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{}), Exp: dbtime.Now().Add(time.Hour), @@ -67,7 +67,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("SingleLicenseAll", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: func() license.Features { @@ -90,7 +90,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("SingleLicenseGrace", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -116,7 +116,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("Expiration warning", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -145,7 +145,7 @@ func TestEntitlements(t *testing.T) { t.Run("Expiration warning for license expiring in 1 day", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -174,7 +174,7 @@ func TestEntitlements(t *testing.T) { t.Run("Expiration warning for trials", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -204,7 +204,7 @@ func TestEntitlements(t *testing.T) { t.Run("Expiration warning for non trials", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -233,7 +233,7 @@ func TestEntitlements(t *testing.T) { t.Run("SingleLicenseNotEntitled", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{}), Exp: time.Now().Add(time.Hour), @@ -261,11 +261,13 @@ func TestEntitlements(t *testing.T) { }) t.Run("TooManyUsers", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) activeUser1, err := db.InsertUser(context.Background(), database.InsertUserParams{ ID: uuid.New(), Username: "test1", + Email: "test1@coder.com", LoginType: database.LoginTypePassword, + RBACRoles: []string{}, }) require.NoError(t, err) _, err = db.UpdateUserStatus(context.Background(), database.UpdateUserStatusParams{ @@ -277,7 +279,9 @@ func TestEntitlements(t *testing.T) { activeUser2, err := db.InsertUser(context.Background(), database.InsertUserParams{ ID: uuid.New(), Username: "test2", + Email: "test2@coder.com", LoginType: database.LoginTypePassword, + RBACRoles: []string{}, }) require.NoError(t, err) _, err = db.UpdateUserStatus(context.Background(), database.UpdateUserStatusParams{ @@ -289,7 +293,9 @@ func TestEntitlements(t *testing.T) { _, err = db.InsertUser(context.Background(), database.InsertUserParams{ ID: uuid.New(), Username: "dormant-user", + Email: "dormant-user@coder.com", LoginType: database.LoginTypePassword, + RBACRoles: []string{}, }) require.NoError(t, err) db.InsertLicense(context.Background(), database.InsertLicenseParams{ @@ -307,7 +313,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("MaximizeUserLimit", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertUser(context.Background(), database.InsertUserParams{}) db.InsertUser(context.Background(), database.InsertUserParams{}) db.InsertLicense(context.Background(), database.InsertLicenseParams{ @@ -335,7 +341,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("MultipleLicenseEnabled", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) // One trial db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), @@ -359,7 +365,7 @@ func TestEntitlements(t *testing.T) { t.Run("Enterprise", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) _, err := db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -390,7 +396,7 @@ func TestEntitlements(t *testing.T) { t.Run("Premium", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) _, err := db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -421,7 +427,7 @@ func TestEntitlements(t *testing.T) { t.Run("SetNone", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) _, err := db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -443,7 +449,7 @@ func TestEntitlements(t *testing.T) { // AllFeatures uses the deprecated 'AllFeatures' boolean. t.Run("AllFeatures", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -473,7 +479,7 @@ func TestEntitlements(t *testing.T) { t.Run("AllFeaturesAlwaysEnable", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: dbtime.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -504,7 +510,7 @@ func TestEntitlements(t *testing.T) { t.Run("AllFeaturesGrace", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: dbtime.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -535,7 +541,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleReplicasNoLicense", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) entitlements, err := license.Entitlements(context.Background(), db, 2, 1, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -545,7 +551,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleReplicasNotEntitled", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -565,7 +571,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleReplicasGrace", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -587,7 +593,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleGitAuthNoLicense", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) entitlements, err := license.Entitlements(context.Background(), db, 1, 2, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -597,7 +603,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleGitAuthNotEntitled", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -617,7 +623,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleGitAuthGrace", func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ GraceAt: time.Now().Add(-time.Hour), diff --git a/enterprise/coderd/proxyhealth/proxyhealth_test.go b/enterprise/coderd/proxyhealth/proxyhealth_test.go index 6879382192116..a002b6d9e7a09 100644 --- a/enterprise/coderd/proxyhealth/proxyhealth_test.go +++ b/enterprise/coderd/proxyhealth/proxyhealth_test.go @@ -12,7 +12,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/coderd/proxyhealth" @@ -46,7 +46,7 @@ func TestProxyHealth_Nil(t *testing.T) { func TestProxyHealth_Unregistered(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) proxies := []database.WorkspaceProxy{ insertProxy(t, db, ""), @@ -72,7 +72,7 @@ func TestProxyHealth_Unregistered(t *testing.T) { func TestProxyHealth_Unhealthy(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) srvBadReport := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { httpapi.Write(context.Background(), w, http.StatusOK, codersdk.ProxyHealthReport{ @@ -112,7 +112,7 @@ func TestProxyHealth_Unhealthy(t *testing.T) { func TestProxyHealth_Reachable(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { httpapi.Write(context.Background(), w, http.StatusOK, codersdk.ProxyHealthReport{ @@ -147,7 +147,7 @@ func TestProxyHealth_Reachable(t *testing.T) { func TestProxyHealth_Unreachable(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) cli := &http.Client{ Transport: &http.Transport{ From 66e490986f9fdb15e7709ae5c4ce8373702536ae Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 17:17:14 +0200 Subject: [PATCH 16/61] chore(enterprise/trialer): remove dbmem from tests (#18798) Related to https://github.com/coder/coder/issues/15109. --- enterprise/trialer/trialer_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/enterprise/trialer/trialer_test.go b/enterprise/trialer/trialer_test.go index 7149044a3e89f..575c945fe3d8f 100644 --- a/enterprise/trialer/trialer_test.go +++ b/enterprise/trialer/trialer_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" "github.com/coder/coder/v2/enterprise/trialer" @@ -24,10 +24,12 @@ func TestTrialer(t *testing.T) { _, _ = w.Write([]byte(license)) })) defer srv.Close() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) + err := db.InsertDeploymentID(context.Background(), "test-deployment") + require.NoError(t, err) gen := trialer.New(db, srv.URL, coderdenttest.Keys) - err := gen(context.Background(), codersdk.LicensorTrialRequest{Email: "kyle+colin@coder.com"}) + err = gen(context.Background(), codersdk.LicensorTrialRequest{Email: "kyle+colin@coder.com"}) require.NoError(t, err) licenses, err := db.GetLicenses(context.Background()) require.NoError(t, err) From 5e9cbe8a1b91093410847a550648c06d5b38f8e7 Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 17:19:14 +0200 Subject: [PATCH 17/61] chore(coderd): remove dbmem from tests (#18800) Related to https://github.com/coder/coder/issues/15109. --- coderd/workspaceagents_test.go | 5 ++--- coderd/workspaces_test.go | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 4a37a1bf7bc52..899c863cc5fd6 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -46,7 +46,6 @@ import ( "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/pubsub" @@ -1989,8 +1988,8 @@ func (s *testWAMErrorStore) GetWorkspaceAgentMetadata(ctx context.Context, arg d func TestWorkspaceAgent_Metadata_CatchMemoryLeak(t *testing.T) { t.Parallel() - db := &testWAMErrorStore{Store: dbmem.New()} - psub := pubsub.NewInMemory() + store, psub := dbtestutil.NewDB(t) + db := &testWAMErrorStore{Store: store} logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Named("coderd").Leveled(slog.LevelDebug) client := coderdtest.New(t, &coderdtest.Options{ Database: db, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 3a50f850da5e7..f99e3b9e3ec3f 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -8,7 +8,6 @@ import ( "fmt" "math" "net/http" - "os" "slices" "strings" "testing" @@ -1426,9 +1425,6 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { // TestWorkspaceFilterAllStatus tests workspace status is correctly set given a set of conditions. func TestWorkspaceFilterAllStatus(t *testing.T) { t.Parallel() - if os.Getenv("DB") != "" { - t.Skip(`This test takes too long with an actual database. Takes 10s on local machine`) - } // For this test, we do not care about permissions. // nolint:gocritic // unit testing From 8e038db46315045289948de9716f47c7c5a0a1e5 Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 17:25:01 +0200 Subject: [PATCH 18/61] chore(enterprise/replicasync): remove dbmem from tests (#18801) Related to https://github.com/coder/coder/issues/15109. --- enterprise/replicasync/replicasync_test.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/enterprise/replicasync/replicasync_test.go b/enterprise/replicasync/replicasync_test.go index 1a9fd50e81223..0438db8e21673 100644 --- a/enterprise/replicasync/replicasync_test.go +++ b/enterprise/replicasync/replicasync_test.go @@ -16,10 +16,8 @@ import ( "go.uber.org/goleak" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/enterprise/replicasync" "github.com/coder/coder/v2/testutil" ) @@ -215,11 +213,7 @@ func TestReplica(t *testing.T) { t.Parallel() ctx, cancelCtx := context.WithCancel(context.Background()) defer cancelCtx() - // This doesn't use the database fake because creating - // this many PostgreSQL connections takes some - // configuration tweaking. - db := dbmem.New() - pubsub := pubsub.NewInMemory() + db, pubsub := dbtestutil.NewDB(t) logger := testutil.Logger(t) dh := &derpyHandler{} defer dh.requireOnlyDERPPaths(t) From 2f50b3b7bb6f9e0311c25a190b6d765243b6d05b Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Tue, 8 Jul 2025 17:28:48 +0200 Subject: [PATCH 19/61] chore(site): remove dbmem from tests (#18802) Related to https://github.com/coder/coder/issues/15109. --- site/site_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/site/site_test.go b/site/site_test.go index f7301debba2be..fa3c0809f22a7 100644 --- a/site/site_test.go +++ b/site/site_test.go @@ -27,7 +27,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/db2sdk" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpmw" @@ -46,7 +45,7 @@ func TestInjection(t *testing.T) { }, } binFs := http.FS(fstest.MapFS{}) - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) handler := site.New(&site.Options{ Telemetry: telemetry.NewNoop(), BinFS: binFs, @@ -73,13 +72,17 @@ func TestInjection(t *testing.T) { // This will update as part of the request! got.LastSeenAt = user.LastSeenAt + // json.Unmarshal doesn't parse the timezone correctly + got.CreatedAt = got.CreatedAt.In(user.CreatedAt.Location()) + got.UpdatedAt = got.UpdatedAt.In(user.CreatedAt.Location()) + require.Equal(t, db2sdk.User(user, []uuid.UUID{}), got) } func TestInjectionFailureProducesCleanHTML(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) // Create an expired user with a refresh token, but provide no OAuth2 // configuration so that refresh is impossible, this should result in From 5f50dcce5af9d511c84fc196f7959469dde012f4 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 8 Jul 2025 19:16:00 +0300 Subject: [PATCH 20/61] feat(cli): improve devcontainer support for `coder show` (#18793) Fixes coder/internal#747 --- cli/cliui/resources.go | 149 ++++++-- cli/show.go | 20 +- cli/show_test.go | 358 ++++++++++++++++++ .../error_devcontainer.golden | 9 + .../long_error_message.golden | 9 + .../long_error_message_with_detail.golden | 9 + .../mixed_devcontainer_states.golden | 13 + .../running_devcontainer_with_agent.golden | 11 + ...g_devcontainer_with_agent_and_error.golden | 11 + .../running_devcontainer_without_agent.golden | 8 + .../starting_devcontainer.golden | 8 + .../stopped_devcontainer.golden | 8 + cli/testdata/coder_show_--help.golden | 6 +- docs/reference/cli/show.md | 13 +- 14 files changed, 600 insertions(+), 32 deletions(-) create mode 100644 cli/testdata/TestShowDevcontainers_Golden/error_devcontainer.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/long_error_message.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/long_error_message_with_detail.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/mixed_devcontainer_states.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent_and_error.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_without_agent.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/starting_devcontainer.golden create mode 100644 cli/testdata/TestShowDevcontainers_Golden/stopped_devcontainer.golden diff --git a/cli/cliui/resources.go b/cli/cliui/resources.go index be112ea177200..36ce4194d72c8 100644 --- a/cli/cliui/resources.go +++ b/cli/cliui/resources.go @@ -12,6 +12,7 @@ import ( "golang.org/x/mod/semver" "github.com/coder/coder/v2/coderd/database/dbtime" + "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/codersdk" "github.com/coder/pretty" ) @@ -29,6 +30,7 @@ type WorkspaceResourcesOptions struct { ServerVersion string ListeningPorts map[uuid.UUID]codersdk.WorkspaceAgentListeningPortsResponse Devcontainers map[uuid.UUID]codersdk.WorkspaceAgentListContainersResponse + ShowDetails bool } // WorkspaceResources displays the connection status and tree-view of provided resources. @@ -69,7 +71,11 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource totalAgents := 0 for _, resource := range resources { - totalAgents += len(resource.Agents) + for _, agent := range resource.Agents { + if !agent.ParentID.Valid { + totalAgents++ + } + } } for _, resource := range resources { @@ -94,12 +100,15 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource "", }) // Display all agents associated with the resource. - for index, agent := range resource.Agents { + agents := slice.Filter(resource.Agents, func(agent codersdk.WorkspaceAgent) bool { + return !agent.ParentID.Valid + }) + for index, agent := range agents { tableWriter.AppendRow(renderAgentRow(agent, index, totalAgents, options)) for _, row := range renderListeningPorts(options, agent.ID, index, totalAgents) { tableWriter.AppendRow(row) } - for _, row := range renderDevcontainers(options, agent.ID, index, totalAgents) { + for _, row := range renderDevcontainers(resources, options, agent.ID, index, totalAgents) { tableWriter.AppendRow(row) } } @@ -125,7 +134,7 @@ func renderAgentRow(agent codersdk.WorkspaceAgent, index, totalAgents int, optio } if !options.HideAccess { sshCommand := "coder ssh " + options.WorkspaceName - if totalAgents > 1 { + if totalAgents > 1 || len(options.Devcontainers) > 0 { sshCommand += "." + agent.Name } sshCommand = pretty.Sprint(DefaultStyles.Code, sshCommand) @@ -164,45 +173,129 @@ func renderPortRow(port codersdk.WorkspaceAgentListeningPort, idx, total int) ta return table.Row{sb.String()} } -func renderDevcontainers(wro WorkspaceResourcesOptions, agentID uuid.UUID, index, totalAgents int) []table.Row { +func renderDevcontainers(resources []codersdk.WorkspaceResource, wro WorkspaceResourcesOptions, agentID uuid.UUID, index, totalAgents int) []table.Row { var rows []table.Row if wro.Devcontainers == nil { return []table.Row{} } dc, ok := wro.Devcontainers[agentID] - if !ok || len(dc.Containers) == 0 { + if !ok || len(dc.Devcontainers) == 0 { return []table.Row{} } rows = append(rows, table.Row{ fmt.Sprintf(" %s─ %s", renderPipe(index, totalAgents), "Devcontainers"), }) - for idx, container := range dc.Containers { - rows = append(rows, renderDevcontainerRow(container, idx, len(dc.Containers))) + for idx, devcontainer := range dc.Devcontainers { + rows = append(rows, renderDevcontainerRow(resources, devcontainer, idx, len(dc.Devcontainers), wro)...) } return rows } -func renderDevcontainerRow(container codersdk.WorkspaceAgentContainer, index, total int) table.Row { - var row table.Row - var sb strings.Builder - _, _ = sb.WriteString(" ") - _, _ = sb.WriteString(renderPipe(index, total)) - _, _ = sb.WriteString("─ ") - _, _ = sb.WriteString(pretty.Sprintf(DefaultStyles.Code, "%s", container.FriendlyName)) - row = append(row, sb.String()) - sb.Reset() - if container.Running { - _, _ = sb.WriteString(pretty.Sprintf(DefaultStyles.Keyword, "(%s)", container.Status)) - } else { - _, _ = sb.WriteString(pretty.Sprintf(DefaultStyles.Error, "(%s)", container.Status)) +func renderDevcontainerRow(resources []codersdk.WorkspaceResource, devcontainer codersdk.WorkspaceAgentDevcontainer, index, total int, wro WorkspaceResourcesOptions) []table.Row { + var rows []table.Row + + // If the devcontainer is running and has an associated agent, we want to + // display the agent's details. Otherwise, we just display the devcontainer + // name and status. + var subAgent *codersdk.WorkspaceAgent + displayName := devcontainer.Name + if devcontainer.Agent != nil && devcontainer.Status == codersdk.WorkspaceAgentDevcontainerStatusRunning { + for _, resource := range resources { + if agent, found := slice.Find(resource.Agents, func(agent codersdk.WorkspaceAgent) bool { + return agent.ID == devcontainer.Agent.ID + }); found { + subAgent = &agent + break + } + } + if subAgent != nil { + displayName = subAgent.Name + displayName += fmt.Sprintf(" (%s, %s)", subAgent.OperatingSystem, subAgent.Architecture) + } + } + + if devcontainer.Container != nil { + displayName += " " + pretty.Sprint(DefaultStyles.Keyword, "["+devcontainer.Container.FriendlyName+"]") + } + + // Build the main row. + row := table.Row{ + fmt.Sprintf(" %s─ %s", renderPipe(index, total), displayName), + } + + // Add status, health, and version columns. + if !wro.HideAgentState { + if subAgent != nil { + row = append(row, renderAgentStatus(*subAgent)) + row = append(row, renderAgentHealth(*subAgent)) + row = append(row, renderAgentVersion(subAgent.Version, wro.ServerVersion)) + } else { + row = append(row, renderDevcontainerStatus(devcontainer.Status)) + row = append(row, "") // No health for devcontainer without agent. + row = append(row, "") // No version for devcontainer without agent. + } + } + + // Add access column. + if !wro.HideAccess { + if subAgent != nil { + accessString := fmt.Sprintf("coder ssh %s.%s", wro.WorkspaceName, subAgent.Name) + row = append(row, pretty.Sprint(DefaultStyles.Code, accessString)) + } else { + row = append(row, "") // No access for devcontainers without agent. + } + } + + rows = append(rows, row) + + // Add error message if present. + if errorMessage := devcontainer.Error; errorMessage != "" { + // Cap error message length for display. + if !wro.ShowDetails && len(errorMessage) > 80 { + errorMessage = errorMessage[:79] + "…" + } + errorRow := table.Row{ + " × " + pretty.Sprint(DefaultStyles.Error, errorMessage), + "", + "", + "", + } + if !wro.HideAccess { + errorRow = append(errorRow, "") + } + rows = append(rows, errorRow) + } + + // Add listening ports for the devcontainer agent. + if subAgent != nil { + portRows := renderListeningPorts(wro, subAgent.ID, index, total) + for _, portRow := range portRows { + // Adjust indentation for ports under devcontainer agent. + if len(portRow) > 0 { + if str, ok := portRow[0].(string); ok { + portRow[0] = " " + str // Add extra indentation. + } + } + rows = append(rows, portRow) + } + } + + return rows +} + +func renderDevcontainerStatus(status codersdk.WorkspaceAgentDevcontainerStatus) string { + switch status { + case codersdk.WorkspaceAgentDevcontainerStatusRunning: + return pretty.Sprint(DefaultStyles.Keyword, "▶ running") + case codersdk.WorkspaceAgentDevcontainerStatusStopped: + return pretty.Sprint(DefaultStyles.Placeholder, "⏹ stopped") + case codersdk.WorkspaceAgentDevcontainerStatusStarting: + return pretty.Sprint(DefaultStyles.Warn, "⧗ starting") + case codersdk.WorkspaceAgentDevcontainerStatusError: + return pretty.Sprint(DefaultStyles.Error, "✘ error") + default: + return pretty.Sprint(DefaultStyles.Placeholder, "○ "+string(status)) } - row = append(row, sb.String()) - sb.Reset() - // "health" is not applicable here. - row = append(row, sb.String()) - _, _ = sb.WriteString(container.Image) - row = append(row, sb.String()) - return row } func renderAgentStatus(agent codersdk.WorkspaceAgent) string { diff --git a/cli/show.go b/cli/show.go index f2d3df3ecc3c5..284e8581f5dda 100644 --- a/cli/show.go +++ b/cli/show.go @@ -8,6 +8,7 @@ import ( "github.com/google/uuid" + "github.com/coder/coder/v2/agent/agentcontainers" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" "github.com/coder/serpent" @@ -15,9 +16,18 @@ import ( func (r *RootCmd) show() *serpent.Command { client := new(codersdk.Client) + var details bool return &serpent.Command{ Use: "show ", Short: "Display details of a workspace's resources and agents", + Options: serpent.OptionSet{ + { + Flag: "details", + Description: "Show full error messages and additional details.", + Default: "false", + Value: serpent.BoolOf(&details), + }, + }, Middleware: serpent.Chain( serpent.RequireNArgs(1), r.InitClient(client), @@ -35,6 +45,7 @@ func (r *RootCmd) show() *serpent.Command { options := cliui.WorkspaceResourcesOptions{ WorkspaceName: workspace.Name, ServerVersion: buildInfo.Version, + ShowDetails: details, } if workspace.LatestBuild.Status == codersdk.WorkspaceStatusRunning { // Get listening ports for each agent. @@ -42,6 +53,7 @@ func (r *RootCmd) show() *serpent.Command { options.ListeningPorts = ports options.Devcontainers = devcontainers } + return cliui.WorkspaceResources(inv.Stdout, workspace.LatestBuild.Resources, options) }, } @@ -68,13 +80,17 @@ func fetchRuntimeResources(inv *serpent.Invocation, client *codersdk.Client, res ports[agent.ID] = lp mu.Unlock() }() + + if agent.ParentID.Valid { + continue + } wg.Add(1) go func() { defer wg.Done() dc, err := client.WorkspaceAgentListContainers(inv.Context(), agent.ID, map[string]string{ // Labels set by VSCode Remote Containers and @devcontainers/cli. - "devcontainer.config_file": "", - "devcontainer.local_folder": "", + agentcontainers.DevcontainerConfigFileLabel: "", + agentcontainers.DevcontainerLocalFolderLabel: "", }) if err != nil { cliui.Warnf(inv.Stderr, "Failed to get devcontainers for agent %s: %v", agent.Name, err) diff --git a/cli/show_test.go b/cli/show_test.go index 7191898f8c0ec..36a5824174fc4 100644 --- a/cli/show_test.go +++ b/cli/show_test.go @@ -1,12 +1,19 @@ package cli_test import ( + "bytes" "testing" + "time" + "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/coder/coder/v2/agent/agentcontainers" "github.com/coder/coder/v2/cli/clitest" + "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/coderdtest" + "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/pty/ptytest" ) @@ -53,3 +60,354 @@ func TestShow(t *testing.T) { <-doneChan }) } + +func TestShowDevcontainers_Golden(t *testing.T) { + t.Parallel() + + mainAgentID := uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") + agentID := mainAgentID + + testCases := []struct { + name string + showDetails bool + devcontainers []codersdk.WorkspaceAgentDevcontainer + listeningPorts map[uuid.UUID]codersdk.WorkspaceAgentListeningPortsResponse + }{ + { + name: "running_devcontainer_with_agent", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("11111111-1111-1111-1111-111111111111"), + Name: "web-dev", + WorkspaceFolder: "/workspaces/web-dev", + ConfigPath: "/workspaces/web-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusRunning, + Dirty: false, + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-web-dev", + FriendlyName: "quirky_lovelace", + Image: "mcr.microsoft.com/devcontainers/typescript-node:1.0.0", + Running: true, + Status: "running", + CreatedAt: time.Now().Add(-1 * time.Hour), + Labels: map[string]string{ + agentcontainers.DevcontainerConfigFileLabel: "/workspaces/web-dev/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/web-dev", + }, + }, + Agent: &codersdk.WorkspaceAgentDevcontainerAgent{ + ID: uuid.MustParse("22222222-2222-2222-2222-222222222222"), + Name: "web-dev", + Directory: "/workspaces/web-dev", + }, + }, + }, + listeningPorts: map[uuid.UUID]codersdk.WorkspaceAgentListeningPortsResponse{ + uuid.MustParse("22222222-2222-2222-2222-222222222222"): { + Ports: []codersdk.WorkspaceAgentListeningPort{ + { + ProcessName: "node", + Network: "tcp", + Port: 3000, + }, + { + ProcessName: "webpack-dev-server", + Network: "tcp", + Port: 8080, + }, + }, + }, + }, + }, + { + name: "running_devcontainer_without_agent", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("33333333-3333-3333-3333-333333333333"), + Name: "web-server", + WorkspaceFolder: "/workspaces/web-server", + ConfigPath: "/workspaces/web-server/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusRunning, + Dirty: false, + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-web-server", + FriendlyName: "amazing_turing", + Image: "nginx:latest", + Running: true, + Status: "running", + CreatedAt: time.Now().Add(-30 * time.Minute), + Labels: map[string]string{ + agentcontainers.DevcontainerConfigFileLabel: "/workspaces/web-server/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/web-server", + }, + }, + Agent: nil, // No agent for this running container. + }, + }, + }, + { + name: "stopped_devcontainer", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("44444444-4444-4444-4444-444444444444"), + Name: "api-dev", + WorkspaceFolder: "/workspaces/api-dev", + ConfigPath: "/workspaces/api-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusStopped, + Dirty: false, + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-api-dev", + FriendlyName: "clever_darwin", + Image: "mcr.microsoft.com/devcontainers/go:1.0.0", + Running: false, + Status: "exited", + CreatedAt: time.Now().Add(-2 * time.Hour), + Labels: map[string]string{ + agentcontainers.DevcontainerConfigFileLabel: "/workspaces/api-dev/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/api-dev", + }, + }, + Agent: nil, // No agent for stopped container. + }, + }, + }, + { + name: "starting_devcontainer", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("55555555-5555-5555-5555-555555555555"), + Name: "database-dev", + WorkspaceFolder: "/workspaces/database-dev", + ConfigPath: "/workspaces/database-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusStarting, + Dirty: false, + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-database-dev", + FriendlyName: "nostalgic_hawking", + Image: "mcr.microsoft.com/devcontainers/postgres:1.0.0", + Running: false, + Status: "created", + CreatedAt: time.Now().Add(-5 * time.Minute), + Labels: map[string]string{ + agentcontainers.DevcontainerConfigFileLabel: "/workspaces/database-dev/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/database-dev", + }, + }, + Agent: nil, // No agent yet while starting. + }, + }, + }, + { + name: "error_devcontainer", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("66666666-6666-6666-6666-666666666666"), + Name: "failed-dev", + WorkspaceFolder: "/workspaces/failed-dev", + ConfigPath: "/workspaces/failed-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusError, + Dirty: false, + Error: "Failed to pull image mcr.microsoft.com/devcontainers/go:latest: timeout after 5m0s", + Container: nil, // No container due to error. + Agent: nil, // No agent due to error. + }, + }, + }, + + { + name: "mixed_devcontainer_states", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("88888888-8888-8888-8888-888888888888"), + Name: "frontend", + WorkspaceFolder: "/workspaces/frontend", + Status: codersdk.WorkspaceAgentDevcontainerStatusRunning, + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-frontend", + FriendlyName: "vibrant_tesla", + Image: "node:18", + Running: true, + Status: "running", + CreatedAt: time.Now().Add(-30 * time.Minute), + }, + Agent: &codersdk.WorkspaceAgentDevcontainerAgent{ + ID: uuid.MustParse("99999999-9999-9999-9999-999999999999"), + Name: "frontend", + Directory: "/workspaces/frontend", + }, + }, + { + ID: uuid.MustParse("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"), + Name: "backend", + WorkspaceFolder: "/workspaces/backend", + Status: codersdk.WorkspaceAgentDevcontainerStatusStopped, + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-backend", + FriendlyName: "peaceful_curie", + Image: "python:3.11", + Running: false, + Status: "exited", + CreatedAt: time.Now().Add(-1 * time.Hour), + }, + Agent: nil, + }, + { + ID: uuid.MustParse("bbbbbbbb-cccc-dddd-eeee-ffffffffffff"), + Name: "error-container", + WorkspaceFolder: "/workspaces/error-container", + Status: codersdk.WorkspaceAgentDevcontainerStatusError, + Error: "Container build failed: dockerfile syntax error on line 15", + Container: nil, + Agent: nil, + }, + }, + listeningPorts: map[uuid.UUID]codersdk.WorkspaceAgentListeningPortsResponse{ + uuid.MustParse("99999999-9999-9999-9999-999999999999"): { + Ports: []codersdk.WorkspaceAgentListeningPort{ + { + ProcessName: "vite", + Network: "tcp", + Port: 5173, + }, + }, + }, + }, + }, + { + name: "running_devcontainer_with_agent_and_error", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("cccccccc-dddd-eeee-ffff-000000000000"), + Name: "problematic-dev", + WorkspaceFolder: "/workspaces/problematic-dev", + ConfigPath: "/workspaces/problematic-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusRunning, + Dirty: false, + Error: "Warning: Container started but healthcheck failed", + Container: &codersdk.WorkspaceAgentContainer{ + ID: "container-problematic", + FriendlyName: "cranky_mendel", + Image: "mcr.microsoft.com/devcontainers/python:1.0.0", + Running: true, + Status: "running", + CreatedAt: time.Now().Add(-15 * time.Minute), + Labels: map[string]string{ + agentcontainers.DevcontainerConfigFileLabel: "/workspaces/problematic-dev/.devcontainer/devcontainer.json", + agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/problematic-dev", + }, + }, + Agent: &codersdk.WorkspaceAgentDevcontainerAgent{ + ID: uuid.MustParse("dddddddd-eeee-ffff-aaaa-111111111111"), + Name: "problematic-dev", + Directory: "/workspaces/problematic-dev", + }, + }, + }, + listeningPorts: map[uuid.UUID]codersdk.WorkspaceAgentListeningPortsResponse{ + uuid.MustParse("dddddddd-eeee-ffff-aaaa-111111111111"): { + Ports: []codersdk.WorkspaceAgentListeningPort{ + { + ProcessName: "python", + Network: "tcp", + Port: 8000, + }, + }, + }, + }, + }, + { + name: "long_error_message", + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("eeeeeeee-ffff-0000-1111-222222222222"), + Name: "long-error-dev", + WorkspaceFolder: "/workspaces/long-error-dev", + ConfigPath: "/workspaces/long-error-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusError, + Dirty: false, + Error: "Failed to build devcontainer: dockerfile parse error at line 25: unknown instruction 'INSTALL', did you mean 'RUN apt-get install'? This is a very long error message that should be truncated when detail flag is not used", + Container: nil, + Agent: nil, + }, + }, + }, + { + name: "long_error_message_with_detail", + showDetails: true, + devcontainers: []codersdk.WorkspaceAgentDevcontainer{ + { + ID: uuid.MustParse("eeeeeeee-ffff-0000-1111-222222222222"), + Name: "long-error-dev", + WorkspaceFolder: "/workspaces/long-error-dev", + ConfigPath: "/workspaces/long-error-dev/.devcontainer/devcontainer.json", + Status: codersdk.WorkspaceAgentDevcontainerStatusError, + Dirty: false, + Error: "Failed to build devcontainer: dockerfile parse error at line 25: unknown instruction 'INSTALL', did you mean 'RUN apt-get install'? This is a very long error message that should be truncated when detail flag is not used", + Container: nil, + Agent: nil, + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + var allAgents []codersdk.WorkspaceAgent + mainAgent := codersdk.WorkspaceAgent{ + ID: mainAgentID, + Name: "main", + OperatingSystem: "linux", + Architecture: "amd64", + Status: codersdk.WorkspaceAgentConnected, + Health: codersdk.WorkspaceAgentHealth{Healthy: true}, + Version: "v2.15.0", + } + allAgents = append(allAgents, mainAgent) + + for _, dc := range tc.devcontainers { + if dc.Agent != nil { + devcontainerAgent := codersdk.WorkspaceAgent{ + ID: dc.Agent.ID, + ParentID: uuid.NullUUID{UUID: mainAgentID, Valid: true}, + Name: dc.Agent.Name, + OperatingSystem: "linux", + Architecture: "amd64", + Status: codersdk.WorkspaceAgentConnected, + Health: codersdk.WorkspaceAgentHealth{Healthy: true}, + Version: "v2.15.0", + } + allAgents = append(allAgents, devcontainerAgent) + } + } + + resources := []codersdk.WorkspaceResource{ + { + Type: "compute", + Name: "main", + Agents: allAgents, + }, + } + options := cliui.WorkspaceResourcesOptions{ + WorkspaceName: "test-workspace", + ServerVersion: "v2.15.0", + ShowDetails: tc.showDetails, + Devcontainers: map[uuid.UUID]codersdk.WorkspaceAgentListContainersResponse{ + agentID: { + Devcontainers: tc.devcontainers, + }, + }, + ListeningPorts: tc.listeningPorts, + } + + var buf bytes.Buffer + err := cliui.WorkspaceResources(&buf, resources, options) + require.NoError(t, err) + + replacements := map[string]string{} + clitest.TestGoldenFile(t, "TestShowDevcontainers_Golden/"+tc.name, buf.Bytes(), replacements) + }) + } +} diff --git a/cli/testdata/TestShowDevcontainers_Golden/error_devcontainer.golden b/cli/testdata/TestShowDevcontainers_Golden/error_devcontainer.golden new file mode 100644 index 0000000000000..03a19f16df4e1 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/error_devcontainer.golden @@ -0,0 +1,9 @@ +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ failed-dev ✘ error │ +│ × Failed to pull image mcr.microsoft.com/devcontainers/go:latest: timeout after 5… │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/long_error_message.golden b/cli/testdata/TestShowDevcontainers_Golden/long_error_message.golden new file mode 100644 index 0000000000000..1e80d338a74a8 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/long_error_message.golden @@ -0,0 +1,9 @@ +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ long-error-dev ✘ error │ +│ × Failed to build devcontainer: dockerfile parse error at line 25: unknown instru… │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/long_error_message_with_detail.golden b/cli/testdata/TestShowDevcontainers_Golden/long_error_message_with_detail.golden new file mode 100644 index 0000000000000..9310f7f19a350 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/long_error_message_with_detail.golden @@ -0,0 +1,9 @@ +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ long-error-dev ✘ error │ +│ × Failed to build devcontainer: dockerfile parse error at line 25: unknown instruction 'INSTALL', did you mean 'RUN apt-get install'? This is a very long error message that should be truncated when detail flag is not used │ +└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/mixed_devcontainer_states.golden b/cli/testdata/TestShowDevcontainers_Golden/mixed_devcontainer_states.golden new file mode 100644 index 0000000000000..dfbd677cc3dbe --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/mixed_devcontainer_states.golden @@ -0,0 +1,13 @@ +┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ ├─ frontend (linux, amd64) [vibrant_tesla] ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.frontend │ +│ ├─ Open Ports │ +│ └─ 5173/tcp [vite] │ +│ ├─ backend [peaceful_curie] ⏹ stopped │ +│ └─ error-container ✘ error │ +│ × Container build failed: dockerfile syntax error on line 15 │ +└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent.golden b/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent.golden new file mode 100644 index 0000000000000..ab5d2a2085227 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent.golden @@ -0,0 +1,11 @@ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ web-dev (linux, amd64) [quirky_lovelace] ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.web-dev │ +│ └─ Open Ports │ +│ ├─ 3000/tcp [node] │ +│ └─ 8080/tcp [webpack-dev-server] │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent_and_error.golden b/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent_and_error.golden new file mode 100644 index 0000000000000..6b73f7175bac8 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_with_agent_and_error.golden @@ -0,0 +1,11 @@ +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ problematic-dev (linux, amd64) [cranky_mendel] ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.problematic-dev │ +│ × Warning: Container started but healthcheck failed │ +│ └─ Open Ports │ +│ └─ 8000/tcp [python] │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_without_agent.golden b/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_without_agent.golden new file mode 100644 index 0000000000000..70c3874acc774 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/running_devcontainer_without_agent.golden @@ -0,0 +1,8 @@ +┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├──────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ web-server [amazing_turing] ▶ running │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/starting_devcontainer.golden b/cli/testdata/TestShowDevcontainers_Golden/starting_devcontainer.golden new file mode 100644 index 0000000000000..472201ecc7818 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/starting_devcontainer.golden @@ -0,0 +1,8 @@ +┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├───────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ database-dev [nostalgic_hawking] ⧗ starting │ +└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/TestShowDevcontainers_Golden/stopped_devcontainer.golden b/cli/testdata/TestShowDevcontainers_Golden/stopped_devcontainer.golden new file mode 100644 index 0000000000000..41313b235acc7 --- /dev/null +++ b/cli/testdata/TestShowDevcontainers_Golden/stopped_devcontainer.golden @@ -0,0 +1,8 @@ +┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ RESOURCE STATUS HEALTH VERSION ACCESS │ +├──────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ compute.main │ +│ └─ main (linux, amd64) ⦿ connected ✔ healthy v2.15.0 coder ssh test-workspace.main │ +│ └─ Devcontainers │ +│ └─ api-dev [clever_darwin] ⏹ stopped │ +└──────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/cli/testdata/coder_show_--help.golden b/cli/testdata/coder_show_--help.golden index fc048aa067ea6..76555221e4602 100644 --- a/cli/testdata/coder_show_--help.golden +++ b/cli/testdata/coder_show_--help.golden @@ -1,9 +1,13 @@ coder v0.0.0-devel USAGE: - coder show + coder show [flags] Display details of a workspace's resources and agents +OPTIONS: + --details bool (default: false) + Show full error messages and additional details. + ——— Run `coder --help` for a list of global options. diff --git a/docs/reference/cli/show.md b/docs/reference/cli/show.md index 87c527ed939f9..c6fb9a2c81f64 100644 --- a/docs/reference/cli/show.md +++ b/docs/reference/cli/show.md @@ -6,5 +6,16 @@ Display details of a workspace's resources and agents ## Usage ```console -coder show +coder show [flags] ``` + +## Options + +### --details + +| | | +|---------|--------------------| +| Type | bool | +| Default | false | + +Show full error messages and additional details. From 6c4db7a2bce29c12869835604307f6811d4700d8 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 8 Jul 2025 19:21:41 +0300 Subject: [PATCH 21/61] feat(cli): replace open vscode container with devcontainer subagent (#18765) This change allows a devcontainer to be opened via the agent syntax, `coder open vscode .` and removes the `--container` option to simplify the subcommand. Accessing the subagent will behave similarly to how the `--container` option behaved. Fixes coder/internal#748 --- agent/agentcontainers/devcontainercli.go | 64 ++--- cli/exp_rpty.go | 2 +- cli/open.go | 134 +++++---- cli/open_test.go | 330 +++++++++-------------- cli/ping.go | 2 +- cli/portforward.go | 2 +- cli/speedtest.go | 2 +- cli/ssh.go | 53 ++-- cli/ssh_internal_test.go | 15 +- cli/vscodessh.go | 2 +- 10 files changed, 283 insertions(+), 323 deletions(-) diff --git a/agent/agentcontainers/devcontainercli.go b/agent/agentcontainers/devcontainercli.go index 55e4708d46134..d7cd25f85a7b3 100644 --- a/agent/agentcontainers/devcontainercli.go +++ b/agent/agentcontainers/devcontainercli.go @@ -106,63 +106,63 @@ type DevcontainerCLI interface { // DevcontainerCLIUpOptions are options for the devcontainer CLI Up // command. -type DevcontainerCLIUpOptions func(*devcontainerCLIUpConfig) +type DevcontainerCLIUpOptions func(*DevcontainerCLIUpConfig) -type devcontainerCLIUpConfig struct { - args []string // Additional arguments for the Up command. - stdout io.Writer - stderr io.Writer +type DevcontainerCLIUpConfig struct { + Args []string // Additional arguments for the Up command. + Stdout io.Writer + Stderr io.Writer } // WithRemoveExistingContainer is an option to remove the existing // container. func WithRemoveExistingContainer() DevcontainerCLIUpOptions { - return func(o *devcontainerCLIUpConfig) { - o.args = append(o.args, "--remove-existing-container") + return func(o *DevcontainerCLIUpConfig) { + o.Args = append(o.Args, "--remove-existing-container") } } // WithUpOutput sets additional stdout and stderr writers for logs // during Up operations. func WithUpOutput(stdout, stderr io.Writer) DevcontainerCLIUpOptions { - return func(o *devcontainerCLIUpConfig) { - o.stdout = stdout - o.stderr = stderr + return func(o *DevcontainerCLIUpConfig) { + o.Stdout = stdout + o.Stderr = stderr } } // DevcontainerCLIExecOptions are options for the devcontainer CLI Exec // command. -type DevcontainerCLIExecOptions func(*devcontainerCLIExecConfig) +type DevcontainerCLIExecOptions func(*DevcontainerCLIExecConfig) -type devcontainerCLIExecConfig struct { - args []string // Additional arguments for the Exec command. - stdout io.Writer - stderr io.Writer +type DevcontainerCLIExecConfig struct { + Args []string // Additional arguments for the Exec command. + Stdout io.Writer + Stderr io.Writer } // WithExecOutput sets additional stdout and stderr writers for logs // during Exec operations. func WithExecOutput(stdout, stderr io.Writer) DevcontainerCLIExecOptions { - return func(o *devcontainerCLIExecConfig) { - o.stdout = stdout - o.stderr = stderr + return func(o *DevcontainerCLIExecConfig) { + o.Stdout = stdout + o.Stderr = stderr } } // WithExecContainerID sets the container ID to target a specific // container. func WithExecContainerID(id string) DevcontainerCLIExecOptions { - return func(o *devcontainerCLIExecConfig) { - o.args = append(o.args, "--container-id", id) + return func(o *DevcontainerCLIExecConfig) { + o.Args = append(o.Args, "--container-id", id) } } // WithRemoteEnv sets environment variables for the Exec command. func WithRemoteEnv(env ...string) DevcontainerCLIExecOptions { - return func(o *devcontainerCLIExecConfig) { + return func(o *DevcontainerCLIExecConfig) { for _, e := range env { - o.args = append(o.args, "--remote-env", e) + o.Args = append(o.Args, "--remote-env", e) } } } @@ -185,8 +185,8 @@ func WithReadConfigOutput(stdout, stderr io.Writer) DevcontainerCLIReadConfigOpt } } -func applyDevcontainerCLIUpOptions(opts []DevcontainerCLIUpOptions) devcontainerCLIUpConfig { - conf := devcontainerCLIUpConfig{stdout: io.Discard, stderr: io.Discard} +func applyDevcontainerCLIUpOptions(opts []DevcontainerCLIUpOptions) DevcontainerCLIUpConfig { + conf := DevcontainerCLIUpConfig{Stdout: io.Discard, Stderr: io.Discard} for _, opt := range opts { if opt != nil { opt(&conf) @@ -195,8 +195,8 @@ func applyDevcontainerCLIUpOptions(opts []DevcontainerCLIUpOptions) devcontainer return conf } -func applyDevcontainerCLIExecOptions(opts []DevcontainerCLIExecOptions) devcontainerCLIExecConfig { - conf := devcontainerCLIExecConfig{stdout: io.Discard, stderr: io.Discard} +func applyDevcontainerCLIExecOptions(opts []DevcontainerCLIExecOptions) DevcontainerCLIExecConfig { + conf := DevcontainerCLIExecConfig{Stdout: io.Discard, Stderr: io.Discard} for _, opt := range opts { if opt != nil { opt(&conf) @@ -241,7 +241,7 @@ func (d *devcontainerCLI) Up(ctx context.Context, workspaceFolder, configPath st if configPath != "" { args = append(args, "--config", configPath) } - args = append(args, conf.args...) + args = append(args, conf.Args...) cmd := d.execer.CommandContext(ctx, "devcontainer", args...) // Capture stdout for parsing and stream logs for both default and provided writers. @@ -251,14 +251,14 @@ func (d *devcontainerCLI) Up(ctx context.Context, workspaceFolder, configPath st &devcontainerCLILogWriter{ ctx: ctx, logger: logger.With(slog.F("stdout", true)), - writer: conf.stdout, + writer: conf.Stdout, }, ) // Stream stderr logs and provided writer if any. cmd.Stderr = &devcontainerCLILogWriter{ ctx: ctx, logger: logger.With(slog.F("stderr", true)), - writer: conf.stderr, + writer: conf.Stderr, } if err := cmd.Run(); err != nil { @@ -293,17 +293,17 @@ func (d *devcontainerCLI) Exec(ctx context.Context, workspaceFolder, configPath if configPath != "" { args = append(args, "--config", configPath) } - args = append(args, conf.args...) + args = append(args, conf.Args...) args = append(args, cmd) args = append(args, cmdArgs...) c := d.execer.CommandContext(ctx, "devcontainer", args...) - c.Stdout = io.MultiWriter(conf.stdout, &devcontainerCLILogWriter{ + c.Stdout = io.MultiWriter(conf.Stdout, &devcontainerCLILogWriter{ ctx: ctx, logger: logger.With(slog.F("stdout", true)), writer: io.Discard, }) - c.Stderr = io.MultiWriter(conf.stderr, &devcontainerCLILogWriter{ + c.Stderr = io.MultiWriter(conf.Stderr, &devcontainerCLILogWriter{ ctx: ctx, logger: logger.With(slog.F("stderr", true)), writer: io.Discard, diff --git a/cli/exp_rpty.go b/cli/exp_rpty.go index 48074c7ef5fb9..70154c57ea9bc 100644 --- a/cli/exp_rpty.go +++ b/cli/exp_rpty.go @@ -97,7 +97,7 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT reconnectID = uuid.New() } - ws, agt, err := getWorkspaceAndAgent(ctx, inv, client, true, args.NamedWorkspace) + ws, agt, _, err := getWorkspaceAndAgent(ctx, inv, client, true, args.NamedWorkspace) if err != nil { return err } diff --git a/cli/open.go b/cli/open.go index ff950b552a853..cc21ea863430d 100644 --- a/cli/open.go +++ b/cli/open.go @@ -11,7 +11,9 @@ import ( "runtime" "slices" "strings" + "time" + "github.com/google/uuid" "github.com/skratchdot/open-golang/open" "golang.org/x/xerrors" @@ -42,7 +44,6 @@ func (r *RootCmd) openVSCode() *serpent.Command { generateToken bool testOpenError bool appearanceConfig codersdk.AppearanceConfig - containerName string ) client := new(codersdk.Client) @@ -71,7 +72,7 @@ func (r *RootCmd) openVSCode() *serpent.Command { // need to wait for the agent to start. workspaceQuery := inv.Args[0] autostart := true - workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, autostart, workspaceQuery) + workspace, workspaceAgent, otherWorkspaceAgents, err := getWorkspaceAndAgent(ctx, inv, client, autostart, workspaceQuery) if err != nil { return xerrors.Errorf("get workspace and agent: %w", err) } @@ -79,6 +80,70 @@ func (r *RootCmd) openVSCode() *serpent.Command { workspaceName := workspace.Name + "." + workspaceAgent.Name insideThisWorkspace := insideAWorkspace && inWorkspaceName == workspaceName + // To properly work with devcontainers, VS Code has to connect to + // parent workspace agent. It will then proceed to enter the + // container given the correct parameters. There is inherently no + // dependency on the devcontainer agent in this scenario, but + // relying on it simplifies the logic and ensures the devcontainer + // is ready. To eliminate the dependency we would need to know that + // a sub-agent that hasn't been created yet may be a devcontainer, + // and thus will be created at a later time as well as expose the + // container folder on the API response. + var parentWorkspaceAgent codersdk.WorkspaceAgent + var devcontainer codersdk.WorkspaceAgentDevcontainer + if workspaceAgent.ParentID.Valid { + // This is likely a devcontainer agent, so we need to find the + // parent workspace agent as well as the devcontainer. + for _, otherAgent := range otherWorkspaceAgents { + if otherAgent.ID == workspaceAgent.ParentID.UUID { + parentWorkspaceAgent = otherAgent + break + } + } + if parentWorkspaceAgent.ID == uuid.Nil { + return xerrors.Errorf("parent workspace agent %s not found", workspaceAgent.ParentID.UUID) + } + + printedWaiting := false + for { + resp, err := client.WorkspaceAgentListContainers(ctx, parentWorkspaceAgent.ID, nil) + if err != nil { + return xerrors.Errorf("list parent workspace agent containers: %w", err) + } + + for _, dc := range resp.Devcontainers { + if dc.Agent.ID == workspaceAgent.ID { + devcontainer = dc + break + } + } + if devcontainer.ID == uuid.Nil { + cliui.Warnf(inv.Stderr, "Devcontainer %q not found, opening as a regular workspace...", workspaceAgent.Name) + parentWorkspaceAgent = codersdk.WorkspaceAgent{} // Reset to empty, so we don't use it later. + break + } + + // Precondition, the devcontainer must be running to enter + // it. Once running, devcontainer.Container will be set. + if devcontainer.Status == codersdk.WorkspaceAgentDevcontainerStatusRunning { + break + } + if devcontainer.Status != codersdk.WorkspaceAgentDevcontainerStatusStarting { + return xerrors.Errorf("devcontainer %q is in unexpected status %q, expected %q or %q", + devcontainer.Name, devcontainer.Status, + codersdk.WorkspaceAgentDevcontainerStatusRunning, + codersdk.WorkspaceAgentDevcontainerStatusStarting, + ) + } + + if !printedWaiting { + _, _ = fmt.Fprintf(inv.Stderr, "Waiting for devcontainer %q status to change from %q to %q...\n", devcontainer.Name, devcontainer.Status, codersdk.WorkspaceAgentDevcontainerStatusRunning) + printedWaiting = true + } + time.Sleep(5 * time.Second) // Wait a bit before retrying. + } + } + if !insideThisWorkspace { // Wait for the agent to connect, we don't care about readiness // otherwise (e.g. wait). @@ -99,6 +164,9 @@ func (r *RootCmd) openVSCode() *serpent.Command { // the created state, so we need to wait for that to happen. // However, if no directory is set, the expanded directory will // not be set either. + // + // Note that this is irrelevant for devcontainer sub agents, as + // they always have a directory set. if workspaceAgent.Directory != "" { workspace, workspaceAgent, err = waitForAgentCond(ctx, client, workspace, workspaceAgent, func(_ codersdk.WorkspaceAgent) bool { return workspaceAgent.LifecycleState != codersdk.WorkspaceAgentLifecycleCreated @@ -114,41 +182,6 @@ func (r *RootCmd) openVSCode() *serpent.Command { directory = inv.Args[1] } - if containerName != "" { - containers, err := client.WorkspaceAgentListContainers(ctx, workspaceAgent.ID, map[string]string{"devcontainer.local_folder": ""}) - if err != nil { - return xerrors.Errorf("list workspace agent containers: %w", err) - } - - var foundContainer bool - - for _, container := range containers.Containers { - if container.FriendlyName != containerName { - continue - } - - foundContainer = true - - if directory == "" { - localFolder, ok := container.Labels["devcontainer.local_folder"] - if !ok { - return xerrors.New("container missing `devcontainer.local_folder` label") - } - - directory, ok = container.Volumes[localFolder] - if !ok { - return xerrors.New("container missing volume for `devcontainer.local_folder`") - } - } - - break - } - - if !foundContainer { - return xerrors.New("no container found") - } - } - directory, err = resolveAgentAbsPath(workspaceAgent.ExpandedDirectory, directory, workspaceAgent.OperatingSystem, insideThisWorkspace) if err != nil { return xerrors.Errorf("resolve agent path: %w", err) @@ -174,14 +207,16 @@ func (r *RootCmd) openVSCode() *serpent.Command { u *url.URL qp url.Values ) - if containerName != "" { + if devcontainer.ID != uuid.Nil { u, qp = buildVSCodeWorkspaceDevContainerLink( token, client.URL.String(), workspace, - workspaceAgent, - containerName, + parentWorkspaceAgent, + devcontainer.Container.FriendlyName, directory, + devcontainer.WorkspaceFolder, + devcontainer.ConfigPath, ) } else { u, qp = buildVSCodeWorkspaceLink( @@ -247,13 +282,6 @@ func (r *RootCmd) openVSCode() *serpent.Command { ), Value: serpent.BoolOf(&generateToken), }, - { - Flag: "container", - FlagShorthand: "c", - Description: "Container name to connect to in the workspace.", - Value: serpent.StringOf(&containerName), - Hidden: true, // Hidden until this features is at least in beta. - }, { Flag: "test.open-error", Description: "Don't run the open command.", @@ -288,7 +316,7 @@ func (r *RootCmd) openApp() *serpent.Command { } workspaceName := inv.Args[0] - ws, agt, err := getWorkspaceAndAgent(ctx, inv, client, false, workspaceName) + ws, agt, _, err := getWorkspaceAndAgent(ctx, inv, client, false, workspaceName) if err != nil { var sdkErr *codersdk.Error if errors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound { @@ -430,8 +458,14 @@ func buildVSCodeWorkspaceDevContainerLink( workspaceAgent codersdk.WorkspaceAgent, containerName string, containerFolder string, + localWorkspaceFolder string, + localConfigFile string, ) (*url.URL, url.Values) { containerFolder = filepath.ToSlash(containerFolder) + localWorkspaceFolder = filepath.ToSlash(localWorkspaceFolder) + if localConfigFile != "" { + localConfigFile = filepath.ToSlash(localConfigFile) + } qp := url.Values{} qp.Add("url", clientURL) @@ -440,6 +474,8 @@ func buildVSCodeWorkspaceDevContainerLink( qp.Add("agent", workspaceAgent.Name) qp.Add("devContainerName", containerName) qp.Add("devContainerFolder", containerFolder) + qp.Add("localWorkspaceFolder", localWorkspaceFolder) + qp.Add("localConfigFile", localConfigFile) if token != "" { qp.Add("token", token) @@ -469,7 +505,7 @@ func waitForAgentCond(ctx context.Context, client *codersdk.Client, workspace co } for workspace = range wc { - workspaceAgent, err = getWorkspaceAgent(workspace, workspaceAgent.Name) + workspaceAgent, _, err = getWorkspaceAgent(workspace, workspaceAgent.Name) if err != nil { return workspace, workspaceAgent, xerrors.Errorf("get workspace agent: %w", err) } diff --git a/cli/open_test.go b/cli/open_test.go index b76b603d35b1e..e8d4aa3e65b2e 100644 --- a/cli/open_test.go +++ b/cli/open_test.go @@ -1,8 +1,10 @@ package cli_test import ( + "context" "net/url" "os" + "path" "path/filepath" "runtime" "strings" @@ -11,11 +13,11 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" + "golang.org/x/xerrors" "github.com/coder/coder/v2/agent" "github.com/coder/coder/v2/agent/agentcontainers" - "github.com/coder/coder/v2/agent/agentcontainers/acmock" + "github.com/coder/coder/v2/agent/agentcontainers/watcher" "github.com/coder/coder/v2/agent/agenttest" "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/coderd/coderdtest" @@ -289,238 +291,145 @@ func TestOpenVSCode_NoAgentDirectory(t *testing.T) { } } -func TestOpenVSCodeDevContainer(t *testing.T) { - t.Parallel() +type fakeContainerCLI struct { + resp codersdk.WorkspaceAgentListContainersResponse +} - if runtime.GOOS != "linux" { - t.Skip("DevContainers are only supported for agents on Linux") - } +func (f *fakeContainerCLI) List(ctx context.Context) (codersdk.WorkspaceAgentListContainersResponse, error) { + return f.resp, nil +} - agentName := "agent1" - agentDir, err := filepath.Abs(filepath.FromSlash("/tmp")) - require.NoError(t, err) +func (*fakeContainerCLI) DetectArchitecture(ctx context.Context, containerID string) (string, error) { + return runtime.GOARCH, nil +} - containerName := testutil.GetRandomName(t) - containerFolder := "/workspace/coder" +func (*fakeContainerCLI) Copy(ctx context.Context, containerID, src, dst string) error { + return nil +} - ctrl := gomock.NewController(t) - mccli := acmock.NewMockContainerCLI(ctrl) - mccli.EXPECT().List(gomock.Any()).Return( - codersdk.WorkspaceAgentListContainersResponse{ - Containers: []codersdk.WorkspaceAgentContainer{ - { - ID: uuid.NewString(), - CreatedAt: dbtime.Now(), - FriendlyName: containerName, - Image: "busybox:latest", - Labels: map[string]string{ - "devcontainer.local_folder": "/home/coder/coder", - }, - Running: true, - Status: "running", - Volumes: map[string]string{ - "/home/coder/coder": containerFolder, - }, - }, - }, - }, nil, - ).AnyTimes() +func (*fakeContainerCLI) ExecAs(ctx context.Context, containerID, user string, args ...string) ([]byte, error) { + return nil, nil +} - client, workspace, agentToken := setupWorkspaceForAgent(t, func(agents []*proto.Agent) []*proto.Agent { - agents[0].Directory = agentDir - agents[0].Name = agentName - agents[0].OperatingSystem = runtime.GOOS - return agents - }) +type fakeDevcontainerCLI struct { + config agentcontainers.DevcontainerConfig + execAgent func(ctx context.Context, token string) error +} - _ = agenttest.New(t, client.URL, agentToken, func(o *agent.Options) { - o.Devcontainers = true - o.DevcontainerAPIOptions = append(o.DevcontainerAPIOptions, - agentcontainers.WithContainerCLI(mccli), - agentcontainers.WithContainerLabelIncludeFilter("this.label.does.not.exist.ignore.devcontainers", "true"), - ) - }) - _ = coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).Wait() +func (f *fakeDevcontainerCLI) ReadConfig(ctx context.Context, workspaceFolder, configFile string, env []string, opts ...agentcontainers.DevcontainerCLIReadConfigOptions) (agentcontainers.DevcontainerConfig, error) { + return f.config, nil +} - insideWorkspaceEnv := map[string]string{ - "CODER": "true", - "CODER_WORKSPACE_NAME": workspace.Name, - "CODER_WORKSPACE_AGENT_NAME": agentName, +func (f *fakeDevcontainerCLI) Exec(ctx context.Context, workspaceFolder, configFile string, name string, args []string, opts ...agentcontainers.DevcontainerCLIExecOptions) error { + var opt agentcontainers.DevcontainerCLIExecConfig + for _, o := range opts { + o(&opt) } - - wd, err := os.Getwd() - require.NoError(t, err) - - tests := []struct { - name string - env map[string]string - args []string - wantDir string - wantError bool - wantToken bool - }{ - { - name: "nonexistent container", - args: []string{"--test.open-error", workspace.Name, "--container", containerName + "bad"}, - wantError: true, - }, - { - name: "ok", - args: []string{"--test.open-error", workspace.Name, "--container", containerName}, - wantDir: containerFolder, - wantError: false, - }, - { - name: "ok with absolute path", - args: []string{"--test.open-error", workspace.Name, "--container", containerName, containerFolder}, - wantDir: containerFolder, - wantError: false, - }, - { - name: "ok with relative path", - args: []string{"--test.open-error", workspace.Name, "--container", containerName, "my/relative/path"}, - wantDir: filepath.Join(agentDir, filepath.FromSlash("my/relative/path")), - wantError: false, - }, - { - name: "ok with token", - args: []string{"--test.open-error", workspace.Name, "--container", containerName, "--generate-token"}, - wantDir: containerFolder, - wantError: false, - wantToken: true, - }, - // Inside workspace, does not require --test.open-error - { - name: "ok inside workspace", - env: insideWorkspaceEnv, - args: []string{workspace.Name, "--container", containerName}, - wantDir: containerFolder, - }, - { - name: "ok inside workspace relative path", - env: insideWorkspaceEnv, - args: []string{workspace.Name, "--container", containerName, "foo"}, - wantDir: filepath.Join(wd, "foo"), - }, - { - name: "ok inside workspace token", - env: insideWorkspaceEnv, - args: []string{workspace.Name, "--container", containerName, "--generate-token"}, - wantDir: containerFolder, - wantToken: true, - }, + var token string + for _, arg := range opt.Args { + if strings.HasPrefix(arg, "CODER_AGENT_TOKEN=") { + token = strings.TrimPrefix(arg, "CODER_AGENT_TOKEN=") + break + } } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - inv, root := clitest.New(t, append([]string{"open", "vscode"}, tt.args...)...) - clitest.SetupConfig(t, client, root) - - pty := ptytest.New(t) - inv.Stdin = pty.Input() - inv.Stdout = pty.Output() - - ctx := testutil.Context(t, testutil.WaitLong) - inv = inv.WithContext(ctx) - - for k, v := range tt.env { - inv.Environ.Set(k, v) - } - - w := clitest.StartWithWaiter(t, inv) - - if tt.wantError { - w.RequireError() - return - } - - me, err := client.User(ctx, codersdk.Me) - require.NoError(t, err) - - line := pty.ReadLine(ctx) - u, err := url.ParseRequestURI(line) - require.NoError(t, err, "line: %q", line) - - qp := u.Query() - assert.Equal(t, client.URL.String(), qp.Get("url")) - assert.Equal(t, me.Username, qp.Get("owner")) - assert.Equal(t, workspace.Name, qp.Get("workspace")) - assert.Equal(t, agentName, qp.Get("agent")) - assert.Equal(t, containerName, qp.Get("devContainerName")) - - if tt.wantDir != "" { - assert.Equal(t, tt.wantDir, qp.Get("devContainerFolder")) - } else { - assert.Equal(t, containerFolder, qp.Get("devContainerFolder")) - } - - if tt.wantToken { - assert.NotEmpty(t, qp.Get("token")) - } else { - assert.Empty(t, qp.Get("token")) - } - - w.RequireSuccess() - }) + if token == "" { + return xerrors.New("no agent token provided in args") + } + if f.execAgent == nil { + return nil } + return f.execAgent(ctx, token) +} + +func (*fakeDevcontainerCLI) Up(ctx context.Context, workspaceFolder, configFile string, opts ...agentcontainers.DevcontainerCLIUpOptions) (string, error) { + return "", nil } -func TestOpenVSCodeDevContainer_NoAgentDirectory(t *testing.T) { +func TestOpenVSCodeDevContainer(t *testing.T) { t.Parallel() if runtime.GOOS != "linux" { t.Skip("DevContainers are only supported for agents on Linux") } - agentName := "agent1" + parentAgentName := "agent1" + devcontainerID := uuid.New() + devcontainerName := "wilson" + workspaceFolder := "/home/coder/wilson" + configFile := path.Join(workspaceFolder, ".devcontainer", "devcontainer.json") + + containerID := uuid.NewString() containerName := testutil.GetRandomName(t) - containerFolder := "/workspace/coder" + containerFolder := "/workspaces/wilson" + + client, workspace, agentToken := setupWorkspaceForAgent(t, func(agents []*proto.Agent) []*proto.Agent { + agents[0].Name = parentAgentName + agents[0].OperatingSystem = runtime.GOOS + return agents + }) - ctrl := gomock.NewController(t) - mccli := acmock.NewMockContainerCLI(ctrl) - mccli.EXPECT().List(gomock.Any()).Return( - codersdk.WorkspaceAgentListContainersResponse{ + fCCLI := &fakeContainerCLI{ + resp: codersdk.WorkspaceAgentListContainersResponse{ Containers: []codersdk.WorkspaceAgentContainer{ { - ID: uuid.NewString(), + ID: containerID, CreatedAt: dbtime.Now(), FriendlyName: containerName, Image: "busybox:latest", Labels: map[string]string{ - "devcontainer.local_folder": "/home/coder/coder", + agentcontainers.DevcontainerLocalFolderLabel: workspaceFolder, + agentcontainers.DevcontainerConfigFileLabel: configFile, + agentcontainers.DevcontainerIsTestRunLabel: "true", + "coder.test": t.Name(), }, Running: true, Status: "running", - Volumes: map[string]string{ - "/home/coder/coder": containerFolder, - }, }, }, - }, nil, - ).AnyTimes() - - client, workspace, agentToken := setupWorkspaceForAgent(t, func(agents []*proto.Agent) []*proto.Agent { - agents[0].Name = agentName - agents[0].OperatingSystem = runtime.GOOS - return agents - }) + }, + } + fDCCLI := &fakeDevcontainerCLI{ + config: agentcontainers.DevcontainerConfig{ + Workspace: agentcontainers.DevcontainerWorkspace{ + WorkspaceFolder: containerFolder, + }, + }, + execAgent: func(ctx context.Context, token string) error { + t.Logf("Starting devcontainer subagent with token: %s", token) + _ = agenttest.New(t, client.URL, token) + <-ctx.Done() + return ctx.Err() + }, + } _ = agenttest.New(t, client.URL, agentToken, func(o *agent.Options) { o.Devcontainers = true o.DevcontainerAPIOptions = append(o.DevcontainerAPIOptions, - agentcontainers.WithContainerCLI(mccli), - agentcontainers.WithContainerLabelIncludeFilter("this.label.does.not.exist.ignore.devcontainers", "true"), + agentcontainers.WithContainerCLI(fCCLI), + agentcontainers.WithDevcontainerCLI(fDCCLI), + agentcontainers.WithWatcher(watcher.NewNoop()), + agentcontainers.WithDevcontainers( + []codersdk.WorkspaceAgentDevcontainer{{ + ID: devcontainerID, + Name: devcontainerName, + WorkspaceFolder: workspaceFolder, + Status: codersdk.WorkspaceAgentDevcontainerStatusStopped, + }}, + []codersdk.WorkspaceAgentScript{{ + ID: devcontainerID, + LogSourceID: uuid.New(), + }}, + ), + agentcontainers.WithContainerLabelIncludeFilter("coder.test", t.Name()), ) }) - _ = coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).Wait() + coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).AgentNames([]string{parentAgentName, devcontainerName}).Wait() insideWorkspaceEnv := map[string]string{ "CODER": "true", "CODER_WORKSPACE_NAME": workspace.Name, - "CODER_WORKSPACE_AGENT_NAME": agentName, + "CODER_WORKSPACE_AGENT_NAME": devcontainerName, } wd, err := os.Getwd() @@ -535,41 +444,48 @@ func TestOpenVSCodeDevContainer_NoAgentDirectory(t *testing.T) { wantToken bool }{ { - name: "ok", - args: []string{"--test.open-error", workspace.Name, "--container", containerName}, + name: "nonexistent container", + args: []string{"--test.open-error", workspace.Name + "." + devcontainerName + "bad"}, + wantError: true, }, { - name: "no agent dir error relative path", - args: []string{"--test.open-error", workspace.Name, "--container", containerName, "my/relative/path"}, - wantDir: filepath.FromSlash("my/relative/path"), - wantError: true, + name: "ok", + args: []string{"--test.open-error", workspace.Name + "." + devcontainerName}, + wantError: false, }, { - name: "ok with absolute path", - args: []string{"--test.open-error", workspace.Name, "--container", containerName, "/home/coder"}, - wantDir: "/home/coder", + name: "ok with absolute path", + args: []string{"--test.open-error", workspace.Name + "." + devcontainerName, containerFolder}, + wantError: false, + }, + { + name: "ok with relative path", + args: []string{"--test.open-error", workspace.Name + "." + devcontainerName, "my/relative/path"}, + wantDir: path.Join(containerFolder, "my/relative/path"), + wantError: false, }, { name: "ok with token", - args: []string{"--test.open-error", workspace.Name, "--container", containerName, "--generate-token"}, + args: []string{"--test.open-error", workspace.Name + "." + devcontainerName, "--generate-token"}, + wantError: false, wantToken: true, }, // Inside workspace, does not require --test.open-error { name: "ok inside workspace", env: insideWorkspaceEnv, - args: []string{workspace.Name, "--container", containerName}, + args: []string{workspace.Name + "." + devcontainerName}, }, { name: "ok inside workspace relative path", env: insideWorkspaceEnv, - args: []string{workspace.Name, "--container", containerName, "foo"}, + args: []string{workspace.Name + "." + devcontainerName, "foo"}, wantDir: filepath.Join(wd, "foo"), }, { name: "ok inside workspace token", env: insideWorkspaceEnv, - args: []string{workspace.Name, "--container", containerName, "--generate-token"}, + args: []string{workspace.Name + "." + devcontainerName, "--generate-token"}, wantToken: true, }, } @@ -610,8 +526,10 @@ func TestOpenVSCodeDevContainer_NoAgentDirectory(t *testing.T) { assert.Equal(t, client.URL.String(), qp.Get("url")) assert.Equal(t, me.Username, qp.Get("owner")) assert.Equal(t, workspace.Name, qp.Get("workspace")) - assert.Equal(t, agentName, qp.Get("agent")) + assert.Equal(t, parentAgentName, qp.Get("agent")) assert.Equal(t, containerName, qp.Get("devContainerName")) + assert.Equal(t, workspaceFolder, qp.Get("localWorkspaceFolder")) + assert.Equal(t, configFile, qp.Get("localConfigFile")) if tt.wantDir != "" { assert.Equal(t, tt.wantDir, qp.Get("devContainerFolder")) diff --git a/cli/ping.go b/cli/ping.go index ec094ea1a317b..0836aa8a135db 100644 --- a/cli/ping.go +++ b/cli/ping.go @@ -110,7 +110,7 @@ func (r *RootCmd) ping() *serpent.Command { defer notifyCancel() workspaceName := inv.Args[0] - _, workspaceAgent, err := getWorkspaceAndAgent( + _, workspaceAgent, _, err := getWorkspaceAndAgent( ctx, inv, client, false, // Do not autostart for a ping. workspaceName, diff --git a/cli/portforward.go b/cli/portforward.go index e6ef2eb11bca8..7a7723213f760 100644 --- a/cli/portforward.go +++ b/cli/portforward.go @@ -84,7 +84,7 @@ func (r *RootCmd) portForward() *serpent.Command { return xerrors.New("no port-forwards requested") } - workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, inv.Args[0]) + workspace, workspaceAgent, _, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, inv.Args[0]) if err != nil { return err } diff --git a/cli/speedtest.go b/cli/speedtest.go index 0d9f839d6b458..08112f50cce2c 100644 --- a/cli/speedtest.go +++ b/cli/speedtest.go @@ -83,7 +83,7 @@ func (r *RootCmd) speedtest() *serpent.Command { return xerrors.Errorf("--direct (-d) is incompatible with --%s", varDisableDirect) } - _, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, false, inv.Args[0]) + _, workspaceAgent, _, err := getWorkspaceAndAgent(ctx, inv, client, false, inv.Args[0]) if err != nil { return err } diff --git a/cli/ssh.go b/cli/ssh.go index 56ab0b2a0d3af..9327a0101c0cf 100644 --- a/cli/ssh.go +++ b/cli/ssh.go @@ -754,7 +754,8 @@ func findWorkspaceAndAgentByHostname( hostname = strings.TrimSuffix(hostname, qualifiedSuffix) } hostname = normalizeWorkspaceInput(hostname) - return getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, hostname) + ws, agent, _, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, hostname) + return ws, agent, err } // watchAndClose ensures closer is called if the context is canceled or @@ -827,9 +828,10 @@ startWatchLoop: } // getWorkspaceAgent returns the workspace and agent selected using either the -// `[.]` syntax via `in`. +// `[.]` syntax via `in`. It will also return any other agents +// in the workspace as a slice for use in child->parent lookups. // If autoStart is true, the workspace will be started if it is not already running. -func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, autostart bool, input string) (codersdk.Workspace, codersdk.WorkspaceAgent, error) { //nolint:revive +func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, autostart bool, input string) (codersdk.Workspace, codersdk.WorkspaceAgent, []codersdk.WorkspaceAgent, error) { //nolint:revive var ( workspace codersdk.Workspace // The input will be `owner/name.agent` @@ -840,27 +842,27 @@ func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client * workspace, err = namedWorkspace(ctx, client, workspaceParts[0]) if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, err } if workspace.LatestBuild.Transition != codersdk.WorkspaceTransitionStart { if !autostart { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.New("workspace must be started") + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.New("workspace must be started") } // Autostart the workspace for the user. // For some failure modes, return a better message. if workspace.LatestBuild.Transition == codersdk.WorkspaceTransitionDelete { // Any sort of deleting status, we should reject with a nicer error. - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.Errorf("workspace %q is deleted", workspace.Name) + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("workspace %q is deleted", workspace.Name) } if workspace.LatestBuild.Job.Status == codersdk.ProvisionerJobFailed { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("workspace %q is in failed state, unable to autostart the workspace", workspace.Name) } // The workspace needs to be stopped before we can start it. // It cannot be in any pending or failed state. if workspace.LatestBuild.Status != codersdk.WorkspaceStatusStopped { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("workspace must be started; was unable to autostart as the last build job is %q, expected %q", workspace.LatestBuild.Status, codersdk.WorkspaceStatusStopped, @@ -881,48 +883,48 @@ func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client * case http.StatusForbidden: _, err = startWorkspace(inv, client, workspace, workspaceParameterFlags{}, buildFlags{}, WorkspaceUpdate) if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.Errorf("start workspace with active template version: %w", err) + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("start workspace with active template version: %w", err) } _, _ = fmt.Fprintln(inv.Stdout, "Unable to start the workspace with template version from last build. Your workspace has been updated to the current active template version.") } } else if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.Errorf("start workspace with current template version: %w", err) + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("start workspace with current template version: %w", err) } // Refresh workspace state so that `outdated`, `build`,`template_*` fields are up-to-date. workspace, err = namedWorkspace(ctx, client, workspaceParts[0]) if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, err } } if workspace.LatestBuild.Job.CompletedAt == nil { err := cliui.WorkspaceBuild(ctx, inv.Stderr, client, workspace.LatestBuild.ID) if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, err } // Fetch up-to-date build information after completion. workspace.LatestBuild, err = client.WorkspaceBuild(ctx, workspace.LatestBuild.ID) if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, err } } if workspace.LatestBuild.Transition == codersdk.WorkspaceTransitionDelete { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, xerrors.Errorf("workspace %q is being deleted", workspace.Name) + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("workspace %q is being deleted", workspace.Name) } var agentName string if len(workspaceParts) >= 2 { agentName = workspaceParts[1] } - workspaceAgent, err := getWorkspaceAgent(workspace, agentName) + workspaceAgent, otherWorkspaceAgents, err := getWorkspaceAgent(workspace, agentName) if err != nil { - return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err + return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, err } - return workspace, workspaceAgent, nil + return workspace, workspaceAgent, otherWorkspaceAgents, nil } -func getWorkspaceAgent(workspace codersdk.Workspace, agentName string) (workspaceAgent codersdk.WorkspaceAgent, err error) { +func getWorkspaceAgent(workspace codersdk.Workspace, agentName string) (workspaceAgent codersdk.WorkspaceAgent, otherAgents []codersdk.WorkspaceAgent, err error) { resources := workspace.LatestBuild.Resources var ( @@ -936,22 +938,23 @@ func getWorkspaceAgent(workspace codersdk.Workspace, agentName string) (workspac } } if len(agents) == 0 { - return codersdk.WorkspaceAgent{}, xerrors.Errorf("workspace %q has no agents", workspace.Name) + return codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("workspace %q has no agents", workspace.Name) } slices.Sort(availableNames) if agentName != "" { - for _, otherAgent := range agents { - if otherAgent.Name != agentName { + for i, agent := range agents { + if agent.Name != agentName || agent.ID.String() == agentName { continue } - return otherAgent, nil + otherAgents := slices.Delete(agents, i, i+1) + return agent, otherAgents, nil } - return codersdk.WorkspaceAgent{}, xerrors.Errorf("agent not found by name %q, available agents: %v", agentName, availableNames) + return codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("agent not found by name %q, available agents: %v", agentName, availableNames) } if len(agents) == 1 { - return agents[0], nil + return agents[0], nil, nil } - return codersdk.WorkspaceAgent{}, xerrors.Errorf("multiple agents found, please specify the agent name, available agents: %v", availableNames) + return codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("multiple agents found, please specify the agent name, available agents: %v", availableNames) } // Attempt to poll workspace autostop. We write a per-workspace lockfile to diff --git a/cli/ssh_internal_test.go b/cli/ssh_internal_test.go index 0d956def68938..a7fac11c7254c 100644 --- a/cli/ssh_internal_test.go +++ b/cli/ssh_internal_test.go @@ -376,7 +376,7 @@ func Test_getWorkspaceAgent(t *testing.T) { agent := createAgent("main") workspace := createWorkspaceWithAgents([]codersdk.WorkspaceAgent{agent}) - result, err := getWorkspaceAgent(workspace, "") + result, _, err := getWorkspaceAgent(workspace, "") require.NoError(t, err) assert.Equal(t, agent.ID, result.ID) assert.Equal(t, "main", result.Name) @@ -388,7 +388,7 @@ func Test_getWorkspaceAgent(t *testing.T) { agent2 := createAgent("main2") workspace := createWorkspaceWithAgents([]codersdk.WorkspaceAgent{agent1, agent2}) - _, err := getWorkspaceAgent(workspace, "") + _, _, err := getWorkspaceAgent(workspace, "") require.Error(t, err) assert.Contains(t, err.Error(), "multiple agents found") assert.Contains(t, err.Error(), "available agents: [main1 main2]") @@ -400,10 +400,13 @@ func Test_getWorkspaceAgent(t *testing.T) { agent2 := createAgent("main2") workspace := createWorkspaceWithAgents([]codersdk.WorkspaceAgent{agent1, agent2}) - result, err := getWorkspaceAgent(workspace, "main1") + result, other, err := getWorkspaceAgent(workspace, "main1") require.NoError(t, err) assert.Equal(t, agent1.ID, result.ID) assert.Equal(t, "main1", result.Name) + assert.Len(t, other, 1) + assert.Equal(t, agent2.ID, other[0].ID) + assert.Equal(t, "main2", other[0].Name) }) t.Run("AgentNameSpecified_NotFound", func(t *testing.T) { @@ -412,7 +415,7 @@ func Test_getWorkspaceAgent(t *testing.T) { agent2 := createAgent("main2") workspace := createWorkspaceWithAgents([]codersdk.WorkspaceAgent{agent1, agent2}) - _, err := getWorkspaceAgent(workspace, "nonexistent") + _, _, err := getWorkspaceAgent(workspace, "nonexistent") require.Error(t, err) assert.Contains(t, err.Error(), `agent not found by name "nonexistent"`) assert.Contains(t, err.Error(), "available agents: [main1 main2]") @@ -422,7 +425,7 @@ func Test_getWorkspaceAgent(t *testing.T) { t.Parallel() workspace := createWorkspaceWithAgents([]codersdk.WorkspaceAgent{}) - _, err := getWorkspaceAgent(workspace, "") + _, _, err := getWorkspaceAgent(workspace, "") require.Error(t, err) assert.Contains(t, err.Error(), `workspace "test-workspace" has no agents`) }) @@ -435,7 +438,7 @@ func Test_getWorkspaceAgent(t *testing.T) { agent3 := createAgent("krypton") workspace := createWorkspaceWithAgents([]codersdk.WorkspaceAgent{agent2, agent1, agent3}) - _, err := getWorkspaceAgent(workspace, "nonexistent") + _, _, err := getWorkspaceAgent(workspace, "nonexistent") require.Error(t, err) // Available agents should be sorted alphabetically. assert.Contains(t, err.Error(), "available agents: [clark krypton zod]") diff --git a/cli/vscodessh.go b/cli/vscodessh.go index 872f7d837c0cd..e0b963b7ed80d 100644 --- a/cli/vscodessh.go +++ b/cli/vscodessh.go @@ -102,7 +102,7 @@ func (r *RootCmd) vscodeSSH() *serpent.Command { // will call this command after the workspace is started. autostart := false - workspace, workspaceAgent, err := getWorkspaceAndAgent(ctx, inv, client, autostart, fmt.Sprintf("%s/%s", owner, name)) + workspace, workspaceAgent, _, err := getWorkspaceAndAgent(ctx, inv, client, autostart, fmt.Sprintf("%s/%s", owner, name)) if err != nil { return xerrors.Errorf("find workspace and agent: %w", err) } From 10c1e36fffc269057a7bdec73fabb979a3352305 Mon Sep 17 00:00:00 2001 From: Allen Conlon Date: Tue, 8 Jul 2025 13:19:12 -0400 Subject: [PATCH 22/61] feat: add publishing of helm charts to ghcr registry (#18316) --- .github/workflows/release.yaml | 2 ++ docs/install/kubernetes.md | 54 +++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5e793d81397dc..0ccf2cd38036e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -693,6 +693,8 @@ jobs: gsutil -h "Cache-Control:no-cache,max-age=0" cp build/helm/provisioner_helm_${version}.tgz gs://helm.coder.com/v2 gsutil -h "Cache-Control:no-cache,max-age=0" cp build/helm/index.yaml gs://helm.coder.com/v2 gsutil -h "Cache-Control:no-cache,max-age=0" cp helm/artifacthub-repo.yml gs://helm.coder.com/v2 + helm push build/coder_helm_${version}.tgz oci://ghcr.io/coder/chart + helm push build/provisioner_helm_${version}.tgz oci://ghcr.io/coder/chart - name: Upload artifacts to actions (if dry-run) if: ${{ inputs.dry_run }} diff --git a/docs/install/kubernetes.md b/docs/install/kubernetes.md index b57169fd1d9e4..435a48b5a98d0 100644 --- a/docs/install/kubernetes.md +++ b/docs/install/kubernetes.md @@ -127,25 +127,51 @@ We support two release channels: mainline and stable - read the - **Mainline** Coder release: - + - **Chart Registry** - ```shell - helm install coder coder-v2/coder \ - --namespace coder \ - --values values.yaml \ - --version 2.23.1 - ``` + + + ```shell + helm install coder coder-v2/coder \ + --namespace coder \ + --values values.yaml \ + --version 2.23.1 + ``` + + - **OCI Registry** + + + + ```shell + helm install coder oci://ghcr.io/coder/chart/coder \ + --namespace coder \ + --values values.yaml \ + --version 2.23.1 + ``` - **Stable** Coder release: - + - **Chart Registry** + + + + ```shell + helm install coder coder-v2/coder \ + --namespace coder \ + --values values.yaml \ + --version 2.22.1 + ``` + + - **OCI Registry** + + - ```shell - helm install coder coder-v2/coder \ - --namespace coder \ - --values values.yaml \ - --version 2.22.1 - ``` + ```shell + helm install coder oci://ghcr.io/coder/chart/coder \ + --namespace coder \ + --values values.yaml \ + --version 2.22.1 + ``` You can watch Coder start up by running `kubectl get pods -n coder`. Once Coder has started, the `coder-*` pods should enter the `Running` state. From 39ed0c32e6e08003c2f4e5e390817b796d334f95 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:20:15 -0400 Subject: [PATCH 23/61] docs: simplify PostgreSQL setup by using 'postgresql' as release name (#18754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #18751 Use `postgresql` as the Helm release name instead of `coder-db` to make the service name more intuitive and eliminate confusion entirely. ## Changes - Changed `helm install coder-db bitnami/postgresql` to `helm install postgresql bitnami/postgresql` - Updated PostgreSQL URLs from `coder-db-postgresql.coder.svc.cluster.local` to `postgresql.coder.svc.cluster.local` - Removed explanatory notes about service naming (no longer needed) ## Benefits ✅ Makes examples work out-of-the-box for most users ✅ Uses the most straightforward and intuitive release name ✅ Eliminates confusion about service naming entirely ✅ Simpler documentation without complex explanations ## Testing - Verified that `helm install postgresql bitnami/postgresql` creates service named `postgresql` - Confirmed this approach works with the connection URL `postgresql.coder.svc.cluster.local` Suggested by @EdwardAngert as a cleaner solution than explaining the service naming dependency. --------- Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> Co-authored-by: matifali <10648092+matifali@users.noreply.github.com> Co-authored-by: EdwardAngert <17991901+EdwardAngert@users.noreply.github.com> Co-authored-by: Edward Angert --- docs/install/kubernetes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/install/kubernetes.md b/docs/install/kubernetes.md index 435a48b5a98d0..72c51e0da3e8c 100644 --- a/docs/install/kubernetes.md +++ b/docs/install/kubernetes.md @@ -44,7 +44,7 @@ on the internet that explain sensible configurations for this chart. Example: ```console # Install PostgreSQL helm repo add bitnami https://charts.bitnami.com/bitnami -helm install coder-db bitnami/postgresql \ +helm install postgresql bitnami/postgresql \ --namespace coder \ --set auth.username=coder \ --set auth.password=coder \ @@ -55,7 +55,7 @@ helm install coder-db bitnami/postgresql \ The cluster-internal DB URL for the above database is: ```shell -postgres://coder:coder@coder-db-postgresql.coder.svc.cluster.local:5432/coder?sslmode=disable +postgres://coder:coder@postgresql.coder.svc.cluster.local:5432/coder?sslmode=disable ``` You can optionally use the @@ -69,7 +69,7 @@ self-managed PostgreSQL, the address will be: ```sh kubectl create secret generic coder-db-url -n coder \ - --from-literal=url="postgres://coder:coder@coder-db-postgresql.coder.svc.cluster.local:5432/coder?sslmode=disable" + --from-literal=url="postgres://coder:coder@postgresql.coder.svc.cluster.local:5432/coder?sslmode=disable" ``` ## 4. Install Coder with Helm From 79d1465e23cb58ba1c2305eeaa61137a197f4770 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 9 Jul 2025 01:33:34 +0500 Subject: [PATCH 24/61] chore: update module sources for Windsurf, Zed and JetBrains (#18759) --- dogfood/coder/main.tf | 9 ++++++--- dogfood/coder/zed/main.tf | 39 --------------------------------------- 2 files changed, 6 insertions(+), 42 deletions(-) delete mode 100644 dogfood/coder/zed/main.tf diff --git a/dogfood/coder/main.tf b/dogfood/coder/main.tf index fff0bc5f5d169..7b8058d676328 100644 --- a/dogfood/coder/main.tf +++ b/dogfood/coder/main.tf @@ -306,8 +306,10 @@ module "vscode-web" { module "jetbrains" { count = data.coder_workspace.me.start_count - source = "git::https://github.com/coder/registry.git//registry/coder/modules/jetbrains?ref=jetbrains" + source = "dev.registry.coder.com/coder/jetbrains/coder" + version = "1.0.0" agent_id = coder_agent.dev.id + agent_name = "dev" folder = local.repo_dir major_version = "latest" } @@ -337,7 +339,7 @@ module "cursor" { module "windsurf" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/windsurf/coder" + source = "dev.registry.coder.com/coder/windsurf/coder" version = "1.0.0" agent_id = coder_agent.dev.id folder = local.repo_dir @@ -345,7 +347,8 @@ module "windsurf" { module "zed" { count = data.coder_workspace.me.start_count - source = "./zed" + source = "dev.registry.coder.com/coder/zed/coder" + version = "1.0.0" agent_id = coder_agent.dev.id agent_name = "dev" folder = local.repo_dir diff --git a/dogfood/coder/zed/main.tf b/dogfood/coder/zed/main.tf deleted file mode 100644 index 96466ba258a1b..0000000000000 --- a/dogfood/coder/zed/main.tf +++ /dev/null @@ -1,39 +0,0 @@ -terraform { - required_version = ">= 1.0" - required_providers { - coder = { - source = "coder/coder" - version = ">= 0.17" - } - } -} - -variable "agent_id" { - type = string -} - -variable "agent_name" { - type = string - default = "" -} - -variable "folder" { - type = string -} - -data "coder_workspace" "me" {} - -locals { - workspace_name = lower(data.coder_workspace.me.name) - agent_name = lower(var.agent_name) - hostname = var.agent_name != "" ? "${local.agent_name}.${local.workspace_name}.me.coder" : "${local.workspace_name}.coder" -} - -resource "coder_app" "zed" { - agent_id = var.agent_id - display_name = "Zed" - slug = "zed" - icon = "/icon/zed.svg" - external = true - url = "zed://ssh/${local.hostname}/${var.folder}" -} From 1319ae293f8a53a9142af75503d050febc049adc Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 8 Jul 2025 15:46:39 -0600 Subject: [PATCH 25/61] chore: support zip filetypes in the file cache (#18750) --- coderd/coderdtest/coderdtest.go | 27 +++++++++++++++++++++----- coderd/coderdtest/dynamicparameters.go | 9 ++++++++- coderd/files/cache.go | 15 ++++++++++++-- enterprise/coderd/workspaces_test.go | 4 +++- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 55e62561af60a..4aa968468e146 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -1,6 +1,7 @@ package coderdtest import ( + "archive/tar" "bytes" "context" "crypto" @@ -52,6 +53,7 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" "cdr.dev/slog/sloggers/slogtest" + "github.com/coder/coder/v2/archive" "github.com/coder/coder/v2/coderd/files" "github.com/coder/quartz" @@ -886,14 +888,22 @@ func createAnotherUserRetry(t testing.TB, client *codersdk.Client, organizationI return other, user } -// CreateTemplateVersion creates a template import provisioner job -// with the responses provided. It uses the "echo" provisioner for compatibility -// with testing. -func CreateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion { +func CreateTemplateVersionMimeType(t testing.TB, client *codersdk.Client, mimeType string, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion { t.Helper() data, err := echo.TarWithOptions(context.Background(), client.Logger(), res) require.NoError(t, err) - file, err := client.Upload(context.Background(), codersdk.ContentTypeTar, bytes.NewReader(data)) + + switch mimeType { + case codersdk.ContentTypeTar: + // do nothing + case codersdk.ContentTypeZip: + data, err = archive.CreateZipFromTar(tar.NewReader(bytes.NewBuffer(data)), int64(len(data))) + require.NoError(t, err, "creating zip") + default: + t.Fatal("unexpected mime type", mimeType) + } + + file, err := client.Upload(context.Background(), mimeType, bytes.NewReader(data)) require.NoError(t, err) req := codersdk.CreateTemplateVersionRequest{ @@ -910,6 +920,13 @@ func CreateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID return templateVersion } +// CreateTemplateVersion creates a template import provisioner job +// with the responses provided. It uses the "echo" provisioner for compatibility +// with testing. +func CreateTemplateVersion(t testing.TB, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion { + return CreateTemplateVersionMimeType(t, client, codersdk.ContentTypeTar, organizationID, res, mutators...) +} + // CreateWorkspaceBuild creates a workspace build for the given workspace and transition. func CreateWorkspaceBuild( t *testing.T, diff --git a/coderd/coderdtest/dynamicparameters.go b/coderd/coderdtest/dynamicparameters.go index 5d03f9fde9639..28e01885560ca 100644 --- a/coderd/coderdtest/dynamicparameters.go +++ b/coderd/coderdtest/dynamicparameters.go @@ -20,6 +20,9 @@ type DynamicParameterTemplateParams struct { Plan json.RawMessage ModulesArchive []byte + // Uses a zip archive instead of a tar + Zip bool + // StaticParams is used if the provisioner daemon version does not support dynamic parameters. StaticParams []*proto.RichParameter @@ -45,7 +48,11 @@ func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UU }, }} - version := CreateTemplateVersion(t, client, org, files, func(request *codersdk.CreateTemplateVersionRequest) { + mime := codersdk.ContentTypeTar + if args.Zip { + mime = codersdk.ContentTypeZip + } + version := CreateTemplateVersionMimeType(t, client, mime, org, files, func(request *codersdk.CreateTemplateVersionRequest) { if args.TemplateID != uuid.Nil { request.TemplateID = args.TemplateID } diff --git a/coderd/files/cache.go b/coderd/files/cache.go index 159f1b8aee053..d9e54a66e1c91 100644 --- a/coderd/files/cache.go +++ b/coderd/files/cache.go @@ -303,10 +303,21 @@ func fetch(store database.Store, fileID uuid.UUID) (CacheEntryValue, error) { return CacheEntryValue{}, xerrors.Errorf("failed to read file from database: %w", err) } - content := bytes.NewBuffer(file.Data) + var files fs.FS + switch file.Mimetype { + case "application/zip", "application/x-zip-compressed": + files, err = archivefs.FromZipReader(bytes.NewReader(file.Data), int64(len(file.Data))) + if err != nil { + return CacheEntryValue{}, xerrors.Errorf("failed to read zip file: %w", err) + } + default: + // Assume '"application/x-tar"' as the default mimetype. + files = archivefs.FromTarReader(bytes.NewBuffer(file.Data)) + } + return CacheEntryValue{ Object: file.RBACObject(), - FS: archivefs.FromTarReader(content), + FS: files, Size: int64(len(file.Data)), }, nil } diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index 5d417f0dfb829..1030536f2111d 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -294,7 +294,9 @@ func TestCreateUserWorkspace(t *testing.T) { OrganizationID: first.OrganizationID, }) - template, _ := coderdtest.DynamicParameterTemplate(t, admin, first.OrganizationID, coderdtest.DynamicParameterTemplateParams{}) + template, _ := coderdtest.DynamicParameterTemplate(t, admin, first.OrganizationID, coderdtest.DynamicParameterTemplateParams{ + Zip: true, + }) ctx = testutil.Context(t, testutil.WaitLong) From 3c2f3d640bf7917a487f3e947c752732c62b61e6 Mon Sep 17 00:00:00 2001 From: Hugo Dutka Date: Wed, 9 Jul 2025 09:46:31 +0200 Subject: [PATCH 26/61] chore: remove dbmem (#18803) Remove the in-memory database. Addresses #15109. --- .claude/docs/DATABASE.md | 39 - .claude/docs/OAUTH2.md | 15 +- .claude/docs/TESTING.md | 35 +- .claude/docs/TROUBLESHOOTING.md | 33 +- .claude/docs/WORKFLOWS.md | 10 +- .github/workflows/ci.yaml | 145 +- .golangci.yaml | 1 - CLAUDE.md | 6 +- Makefile | 3 +- cli/server.go | 64 +- cli/server_test.go | 3 - cli/testdata/server-config.yaml.golden | 3 - coderd/apidoc/docs.go | 3 - coderd/apidoc/swagger.json | 3 - coderd/database/dbauthz/customroles_test.go | 4 +- coderd/database/dbauthz/dbauthz_test.go | 111 +- coderd/database/dbmem/dbmem.go | 14242 ---------------- coderd/database/dbmem/dbmem_test.go | 209 - coderd/database/dbtestutil/db.go | 85 +- coderd/database/oidcclaims_test.go | 1 - coderd/database/querier_test.go | 1 - coderd/notifications/notifications_test.go | 2 +- coderd/users_test.go | 10 - codersdk/deployment.go | 10 - docs/about/contributing/backend.md | 1 - docs/reference/api/general.md | 1 - docs/reference/api/schemas.md | 3 - enterprise/cli/server_test.go | 3 - enterprise/coderd/coderd.go | 8 +- .../coderd/coderdenttest/coderdenttest.go | 3 - scripts/dbgen/main.go | 83 +- site/e2e/playwright.config.ts | 2 +- site/src/api/typesGenerated.ts | 1 - 33 files changed, 143 insertions(+), 15000 deletions(-) delete mode 100644 coderd/database/dbmem/dbmem.go delete mode 100644 coderd/database/dbmem/dbmem_test.go diff --git a/.claude/docs/DATABASE.md b/.claude/docs/DATABASE.md index f6ba4bd78859b..090054772fc32 100644 --- a/.claude/docs/DATABASE.md +++ b/.claude/docs/DATABASE.md @@ -58,31 +58,6 @@ If adding fields to auditable types: - `ActionSecret`: Field contains sensitive data 3. Run `make gen` to verify no audit errors -## In-Memory Database (dbmem) Updates - -### Critical Requirements - -When adding new fields to database structs: - -- **CRITICAL**: Update `coderd/database/dbmem/dbmem.go` in-memory implementations -- The `Insert*` functions must include ALL new fields, not just basic ones -- Common issue: Tests pass with real database but fail with in-memory database due to missing field mappings -- Always verify in-memory database functions match the real database schema after migrations - -### Example Pattern - -```go -// In dbmem.go - ensure ALL fields are included -code := database.OAuth2ProviderAppCode{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - // ... existing fields ... - ResourceUri: arg.ResourceUri, // New field - CodeChallenge: arg.CodeChallenge, // New field - CodeChallengeMethod: arg.CodeChallengeMethod, // New field -} -``` - ## Database Architecture ### Core Components @@ -116,7 +91,6 @@ roles, err := db.GetAuthorizationUserRoles(dbauthz.AsSystemRestricted(ctx), user 1. **Nullable field errors**: Use `sql.Null*` types consistently 2. **Missing audit entries**: Update `enterprise/audit/table.go` -3. **dbmem inconsistencies**: Ensure in-memory implementations match schema ### Query Issues @@ -139,19 +113,6 @@ func TestDatabaseFunction(t *testing.T) { } ``` -### In-Memory Testing - -```go -func TestInMemoryDatabase(t *testing.T) { - db := dbmem.New() - - // Test with in-memory database - result, err := db.GetSomething(ctx, param) - require.NoError(t, err) - require.Equal(t, expected, result) -} -``` - ## Best Practices ### Schema Design diff --git a/.claude/docs/OAUTH2.md b/.claude/docs/OAUTH2.md index 2c766dd083516..9fb34f093042a 100644 --- a/.claude/docs/OAUTH2.md +++ b/.claude/docs/OAUTH2.md @@ -112,14 +112,13 @@ Always run the full test suite after OAuth2 changes: ## Common OAuth2 Issues 1. **OAuth2 endpoints returning wrong error format** - Ensure OAuth2 endpoints return RFC 6749 compliant errors -2. **OAuth2 tests failing but scripts working** - Check in-memory database implementations in `dbmem.go` -3. **Resource indicator validation failing** - Ensure database stores and retrieves resource parameters correctly -4. **PKCE tests failing** - Verify both authorization code storage and token exchange handle PKCE fields -5. **RFC compliance failures** - Verify against actual RFC specifications, not assumptions -6. **Authorization context errors in public endpoints** - Use `dbauthz.AsSystemRestricted(ctx)` pattern -7. **Default value mismatches** - Ensure database migrations match application code defaults -8. **Bearer token authentication issues** - Check token extraction precedence and format validation -9. **URI validation failures** - Support both standard schemes and custom schemes per protocol requirements +2. **Resource indicator validation failing** - Ensure database stores and retrieves resource parameters correctly +3. **PKCE tests failing** - Verify both authorization code storage and token exchange handle PKCE fields +4. **RFC compliance failures** - Verify against actual RFC specifications, not assumptions +5. **Authorization context errors in public endpoints** - Use `dbauthz.AsSystemRestricted(ctx)` pattern +6. **Default value mismatches** - Ensure database migrations match application code defaults +7. **Bearer token authentication issues** - Check token extraction precedence and format validation +8. **URI validation failures** - Support both standard schemes and custom schemes per protocol requirements ## Authorization Context Patterns diff --git a/.claude/docs/TESTING.md b/.claude/docs/TESTING.md index b8f92f531bb1c..eff655b0acadc 100644 --- a/.claude/docs/TESTING.md +++ b/.claude/docs/TESTING.md @@ -39,31 +39,6 @@ 2. **Verify information disclosure protections** 3. **Test token security and proper invalidation** -## Database Testing - -### In-Memory Database Testing - -When adding new database fields: - -- **CRITICAL**: Update `coderd/database/dbmem/dbmem.go` in-memory implementations -- The `Insert*` functions must include ALL new fields, not just basic ones -- Common issue: Tests pass with real database but fail with in-memory database due to missing field mappings -- Always verify in-memory database functions match the real database schema after migrations - -Example pattern: - -```go -// In dbmem.go - ensure ALL fields are included -code := database.OAuth2ProviderAppCode{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - // ... existing fields ... - ResourceUri: arg.ResourceUri, // New field - CodeChallenge: arg.CodeChallenge, // New field - CodeChallengeMethod: arg.CodeChallengeMethod, // New field -} -``` - ## Test Organization ### Test File Structure @@ -107,15 +82,13 @@ coderd/ ### Database-Related -1. **Tests passing locally but failing in CI** - Check if `dbmem` implementation needs updating -2. **SQL type errors** - Use `sql.Null*` types for nullable fields -3. **Race conditions in tests** - Use unique identifiers instead of hardcoded names +1. **SQL type errors** - Use `sql.Null*` types for nullable fields +2. **Race conditions in tests** - Use unique identifiers instead of hardcoded names ### OAuth2 Testing -1. **OAuth2 tests failing but scripts working** - Check in-memory database implementations in `dbmem.go` -2. **PKCE tests failing** - Verify both authorization code storage and token exchange handle PKCE fields -3. **Resource indicator validation failing** - Ensure database stores and retrieves resource parameters correctly +1. **PKCE tests failing** - Verify both authorization code storage and token exchange handle PKCE fields +2. **Resource indicator validation failing** - Ensure database stores and retrieves resource parameters correctly ### General Issues diff --git a/.claude/docs/TROUBLESHOOTING.md b/.claude/docs/TROUBLESHOOTING.md index 2b4bb3ee064cc..19c05a7a0cd62 100644 --- a/.claude/docs/TROUBLESHOOTING.md +++ b/.claude/docs/TROUBLESHOOTING.md @@ -21,59 +21,50 @@ } ``` -3. **Tests passing locally but failing in CI** - - **Solution**: Check if `dbmem` implementation needs updating - - Update `coderd/database/dbmem/dbmem.go` for Insert/Update methods - - Missing fields in dbmem can cause tests to fail even if main implementation is correct - ### Testing Issues -4. **"package should be X_test"** +3. **"package should be X_test"** - **Solution**: Use `package_test` naming for test files - Example: `identityprovider_test` for black-box testing -5. **Race conditions in tests** +4. **Race conditions in tests** - **Solution**: Use unique identifiers instead of hardcoded names - Example: `fmt.Sprintf("test-client-%s-%d", t.Name(), time.Now().UnixNano())` - Never use hardcoded names in concurrent tests -6. **Missing newlines** +5. **Missing newlines** - **Solution**: Ensure files end with newline character - Most editors can be configured to add this automatically ### OAuth2 Issues -7. **OAuth2 endpoints returning wrong error format** +6. **OAuth2 endpoints returning wrong error format** - **Solution**: Ensure OAuth2 endpoints return RFC 6749 compliant errors - Use standard error codes: `invalid_client`, `invalid_grant`, `invalid_request` - Format: `{"error": "code", "error_description": "details"}` -8. **OAuth2 tests failing but scripts working** - - **Solution**: Check in-memory database implementations in `dbmem.go` - - Ensure all OAuth2 fields are properly copied in Insert/Update methods - -9. **Resource indicator validation failing** +7. **Resource indicator validation failing** - **Solution**: Ensure database stores and retrieves resource parameters correctly - Check both authorization code storage and token exchange handling -10. **PKCE tests failing** +8. **PKCE tests failing** - **Solution**: Verify both authorization code storage and token exchange handle PKCE fields - Check `CodeChallenge` and `CodeChallengeMethod` field handling ### RFC Compliance Issues -11. **RFC compliance failures** +9. **RFC compliance failures** - **Solution**: Verify against actual RFC specifications, not assumptions - Use WebFetch tool to get current RFC content for compliance verification - Read the actual RFC specifications before implementation -12. **Default value mismatches** +10. **Default value mismatches** - **Solution**: Ensure database migrations match application code defaults - Example: RFC 7591 specifies `client_secret_basic` as default, not `client_secret_post` ### Authorization Issues -13. **Authorization context errors in public endpoints** +11. **Authorization context errors in public endpoints** - **Solution**: Use `dbauthz.AsSystemRestricted(ctx)` pattern - Example: @@ -84,17 +75,17 @@ ### Authentication Issues -14. **Bearer token authentication issues** +12. **Bearer token authentication issues** - **Solution**: Check token extraction precedence and format validation - Ensure proper RFC 6750 Bearer Token Support implementation -15. **URI validation failures** +13. **URI validation failures** - **Solution**: Support both standard schemes and custom schemes per protocol requirements - Native OAuth2 apps may use custom schemes ### General Development Issues -16. **Log message formatting errors** +14. **Log message formatting errors** - **Solution**: Use lowercase, descriptive messages without special characters - Follow Go logging conventions diff --git a/.claude/docs/WORKFLOWS.md b/.claude/docs/WORKFLOWS.md index 1bd595c8a4b34..b846110d589d8 100644 --- a/.claude/docs/WORKFLOWS.md +++ b/.claude/docs/WORKFLOWS.md @@ -81,11 +81,6 @@ - Add each new field with appropriate action (ActionTrack, ActionIgnore, ActionSecret) - Run `make gen` to verify no audit errors -6. **In-memory database (dbmem) updates**: - - When adding new fields to database structs, ensure `dbmem` implementation copies all fields - - Check `coderd/database/dbmem/dbmem.go` for Insert/Update methods - - Missing fields in dbmem can cause tests to fail even if main implementation is correct - ### Database Generation Process 1. Modify SQL files in `coderd/database/queries/` @@ -164,9 +159,8 @@ 1. **Development server won't start** - Use `./scripts/develop.sh` instead of manual commands 2. **Database migration errors** - Check migration file format and use helper scripts -3. **Test failures after database changes** - Update `dbmem` implementations -4. **Audit table errors** - Update `enterprise/audit/table.go` with new fields -5. **OAuth2 compliance issues** - Ensure RFC-compliant error responses +3. **Audit table errors** - Update `enterprise/audit/table.go` with new fields +4. **OAuth2 compliance issues** - Ensure RFC-compliant error responses ### Debug Commands diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8c4e21466c03d..93bd1a9ea65aa 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -311,94 +311,6 @@ jobs: - name: Check for unstaged files run: ./scripts/check_unstaged.sh - test-go: - runs-on: ${{ matrix.os == 'ubuntu-latest' && github.repository_owner == 'coder' && 'depot-ubuntu-22.04-4' || matrix.os == 'macos-latest' && github.repository_owner == 'coder' && 'depot-macos-latest' || matrix.os == 'windows-2022' && github.repository_owner == 'coder' && 'depot-windows-2022-16' || matrix.os }} - needs: changes - if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' - timeout-minutes: 20 - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - - macos-latest - - windows-2022 - steps: - - name: Harden Runner - # Harden Runner is only supported on Ubuntu runners. - if: runner.os == 'Linux' - uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 - with: - egress-policy: audit - - # Set up RAM disks to speed up the rest of the job. This action is in - # a separate repository to allow its use before actions/checkout. - - name: Setup RAM Disks - if: runner.os == 'Windows' - uses: coder/setup-ramdisk-action@e1100847ab2d7bcd9d14bcda8f2d1b0f07b36f1b - - - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - - name: Setup Go Paths - uses: ./.github/actions/setup-go-paths - - - name: Setup Go - uses: ./.github/actions/setup-go - with: - # Runners have Go baked-in and Go will automatically - # download the toolchain configured in go.mod, so we don't - # need to reinstall it. It's faster on Windows runners. - use-preinstalled-go: ${{ runner.os == 'Windows' }} - - - name: Setup Terraform - uses: ./.github/actions/setup-tf - - - name: Download Test Cache - id: download-cache - uses: ./.github/actions/test-cache/download - with: - key-prefix: test-go-${{ runner.os }}-${{ runner.arch }} - - - name: Test with Mock Database - id: test - shell: bash - run: | - # if macOS, install google-chrome for scaletests. As another concern, - # should we really have this kind of external dependency requirement - # on standard CI? - if [ "${{ matrix.os }}" == "macos-latest" ]; then - brew install google-chrome - fi - - # By default Go will use the number of logical CPUs, which - # is a fine default. - PARALLEL_FLAG="" - - # macOS will output "The default interactive shell is now zsh" - # intermittently in CI... - if [ "${{ matrix.os }}" == "macos-latest" ]; then - touch ~/.bash_profile && echo "export BASH_SILENCE_DEPRECATION_WARNING=1" >> ~/.bash_profile - fi - export TS_DEBUG_DISCO=true - gotestsum --junitfile="gotests.xml" --jsonfile="gotests.json" --rerun-fails=2 \ - --packages="./..." -- $PARALLEL_FLAG -short - - - name: Upload Test Cache - uses: ./.github/actions/test-cache/upload - with: - cache-key: ${{ steps.download-cache.outputs.cache-key }} - - - name: Upload test stats to Datadog - timeout-minutes: 1 - continue-on-error: true - uses: ./.github/actions/upload-datadog - if: success() || failure() - with: - api-key: ${{ secrets.DATADOG_API_KEY }} - test-go-pg: # make sure to adjust NUM_PARALLEL_PACKAGES and NUM_PARALLEL_TESTS below # when changing runner sizes @@ -567,7 +479,7 @@ jobs: # We rerun failing tests to counteract flakiness coming from Postgres # choking on macOS and Windows sometimes. - DB=ci gotestsum --rerun-fails=2 --rerun-fails-max-failures=50 \ + gotestsum --rerun-fails=2 --rerun-fails-max-failures=50 \ --format standard-quiet --packages "./..." \ -- -timeout=20m -v -p $NUM_PARALLEL_PACKAGES -parallel=$NUM_PARALLEL_TESTS $TESTCOUNT @@ -655,55 +567,6 @@ jobs: with: api-key: ${{ secrets.DATADOG_API_KEY }} - test-go-race: - runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} - needs: changes - if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' - timeout-minutes: 25 - steps: - - name: Harden Runner - uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 - with: - egress-policy: audit - - - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - - name: Setup Go - uses: ./.github/actions/setup-go - - - name: Setup Terraform - uses: ./.github/actions/setup-tf - - - name: Download Test Cache - id: download-cache - uses: ./.github/actions/test-cache/download - with: - key-prefix: test-go-race-${{ runner.os }}-${{ runner.arch }} - - # We run race tests with reduced parallelism because they use more CPU and we were finding - # instances where tests appear to hang for multiple seconds, resulting in flaky tests when - # short timeouts are used. - # c.f. discussion on https://github.com/coder/coder/pull/15106 - - name: Run Tests - run: | - gotestsum --junitfile="gotests.xml" --packages="./..." --rerun-fails=2 --rerun-fails-abort-on-data-race -- -race -parallel 4 -p 4 - - - name: Upload Test Cache - uses: ./.github/actions/test-cache/upload - with: - cache-key: ${{ steps.download-cache.outputs.cache-key }} - - - name: Upload test stats to Datadog - timeout-minutes: 1 - continue-on-error: true - uses: ./.github/actions/upload-datadog - if: always() - with: - api-key: ${{ secrets.DATADOG_API_KEY }} - test-go-race-pg: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} needs: changes @@ -741,7 +604,7 @@ jobs: POSTGRES_VERSION: "17" run: | make test-postgres-docker - DB=ci gotestsum --junitfile="gotests.xml" --packages="./..." --rerun-fails=2 --rerun-fails-abort-on-data-race -- -race -parallel 4 -p 4 + gotestsum --junitfile="gotests.xml" --packages="./..." --rerun-fails=2 --rerun-fails-abort-on-data-race -- -race -parallel 4 -p 4 - name: Upload Test Cache uses: ./.github/actions/test-cache/upload @@ -1037,9 +900,7 @@ jobs: - fmt - lint - gen - - test-go - test-go-pg - - test-go-race - test-go-race-pg - test-js - test-e2e @@ -1060,9 +921,7 @@ jobs: echo "- fmt: ${{ needs.fmt.result }}" echo "- lint: ${{ needs.lint.result }}" echo "- gen: ${{ needs.gen.result }}" - echo "- test-go: ${{ needs.test-go.result }}" echo "- test-go-pg: ${{ needs.test-go-pg.result }}" - echo "- test-go-race: ${{ needs.test-go-race.result }}" echo "- test-go-race-pg: ${{ needs.test-go-race-pg.result }}" echo "- test-js: ${{ needs.test-js.result }}" echo "- test-e2e: ${{ needs.test-e2e.result }}" diff --git a/.golangci.yaml b/.golangci.yaml index 2e1e853a0425a..aeebaf47e29a6 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -181,7 +181,6 @@ linters-settings: issues: exclude-dirs: - - coderd/database/dbmem - node_modules - .git diff --git a/CLAUDE.md b/CLAUDE.md index 4df2514a45863..d5335a6d4d0b3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,7 +44,6 @@ 2. Run `make gen` 3. If audit errors: update `enterprise/audit/table.go` 4. Run `make gen` again -5. Update `coderd/database/dbmem/dbmem.go` in-memory implementations ### LSP Navigation (USE FIRST) @@ -116,9 +115,8 @@ app, err := api.Database.GetOAuth2ProviderAppByClientID(ctx, clientID) 1. **Audit table errors** → Update `enterprise/audit/table.go` 2. **OAuth2 errors** → Return RFC-compliant format -3. **dbmem failures** → Update in-memory implementations -4. **Race conditions** → Use unique test identifiers -5. **Missing newlines** → Ensure files end with newline +3. **Race conditions** → Use unique test identifiers +4. **Missing newlines** → Ensure files end with newline --- diff --git a/Makefile b/Makefile index 0ed464ba23a80..ebfb286a482cc 100644 --- a/Makefile +++ b/Makefile @@ -599,7 +599,6 @@ DB_GEN_FILES := \ coderd/database/dump.sql \ coderd/database/querier.go \ coderd/database/unique_constraint.go \ - coderd/database/dbmem/dbmem.go \ coderd/database/dbmetrics/dbmetrics.go \ coderd/database/dbauthz/dbauthz.go \ coderd/database/dbmock/dbmock.go @@ -973,7 +972,7 @@ sqlc-vet: test-postgres-docker test-postgres: test-postgres-docker # The postgres test is prone to failure, so we limit parallelism for # more consistent execution. - $(GIT_FLAGS) DB=ci gotestsum \ + $(GIT_FLAGS) gotestsum \ --junitfile="gotests.xml" \ --jsonfile="gotests.json" \ $(GOTESTSUM_RETRY_FLAGS) \ diff --git a/cli/server.go b/cli/server.go index 5074bffc3a342..602f05d028b66 100644 --- a/cli/server.go +++ b/cli/server.go @@ -77,7 +77,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/awsiamrds" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbmetrics" "github.com/coder/coder/v2/coderd/database/dbpurge" "github.com/coder/coder/v2/coderd/database/migrations" @@ -423,7 +422,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. builtinPostgres := false // Only use built-in if PostgreSQL URL isn't specified! - if !vals.InMemoryDatabase && vals.PostgresURL == "" { + if vals.PostgresURL == "" { var closeFunc func() error cliui.Infof(inv.Stdout, "Using built-in PostgreSQL (%s)", config.PostgresPath()) customPostgresCacheDir := "" @@ -726,42 +725,37 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. // nil, that case of the select will just never fire, but it's important not to have a // "bare" read on this channel. var pubsubWatchdogTimeout <-chan struct{} - if vals.InMemoryDatabase { - // This is only used for testing. - options.Database = dbmem.New() - options.Pubsub = pubsub.NewInMemory() - } else { - sqlDB, dbURL, err := getAndMigratePostgresDB(ctx, logger, vals.PostgresURL.String(), codersdk.PostgresAuth(vals.PostgresAuth), sqlDriver) - if err != nil { - return xerrors.Errorf("connect to postgres: %w", err) - } - defer func() { - _ = sqlDB.Close() - }() - if options.DeploymentValues.Prometheus.Enable { - // At this stage we don't think the database name serves much purpose in these metrics. - // It requires parsing the DSN to determine it, which requires pulling in another dependency - // (i.e. https://github.com/jackc/pgx), but it's rather heavy. - // The conn string (https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) can - // take different forms, which make parsing non-trivial. - options.PrometheusRegistry.MustRegister(collectors.NewDBStatsCollector(sqlDB, "")) - } + sqlDB, dbURL, err := getAndMigratePostgresDB(ctx, logger, vals.PostgresURL.String(), codersdk.PostgresAuth(vals.PostgresAuth), sqlDriver) + if err != nil { + return xerrors.Errorf("connect to postgres: %w", err) + } + defer func() { + _ = sqlDB.Close() + }() - options.Database = database.New(sqlDB) - ps, err := pubsub.New(ctx, logger.Named("pubsub"), sqlDB, dbURL) - if err != nil { - return xerrors.Errorf("create pubsub: %w", err) - } - options.Pubsub = ps - if options.DeploymentValues.Prometheus.Enable { - options.PrometheusRegistry.MustRegister(ps) - } - defer options.Pubsub.Close() - psWatchdog := pubsub.NewWatchdog(ctx, logger.Named("pswatch"), ps) - pubsubWatchdogTimeout = psWatchdog.Timeout() - defer psWatchdog.Close() + if options.DeploymentValues.Prometheus.Enable { + // At this stage we don't think the database name serves much purpose in these metrics. + // It requires parsing the DSN to determine it, which requires pulling in another dependency + // (i.e. https://github.com/jackc/pgx), but it's rather heavy. + // The conn string (https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) can + // take different forms, which make parsing non-trivial. + options.PrometheusRegistry.MustRegister(collectors.NewDBStatsCollector(sqlDB, "")) + } + + options.Database = database.New(sqlDB) + ps, err := pubsub.New(ctx, logger.Named("pubsub"), sqlDB, dbURL) + if err != nil { + return xerrors.Errorf("create pubsub: %w", err) + } + options.Pubsub = ps + if options.DeploymentValues.Prometheus.Enable { + options.PrometheusRegistry.MustRegister(ps) } + defer options.Pubsub.Close() + psWatchdog := pubsub.NewWatchdog(ctx, logger.Named("pswatch"), ps) + pubsubWatchdogTimeout = psWatchdog.Timeout() + defer psWatchdog.Close() if options.DeploymentValues.Prometheus.Enable && options.DeploymentValues.Prometheus.CollectDBMetrics { options.Database = dbmetrics.NewQueryMetrics(options.Database, options.Logger, options.PrometheusRegistry) diff --git a/cli/server_test.go b/cli/server_test.go index 2d0bbdd24e83b..435ed2879c9a3 100644 --- a/cli/server_test.go +++ b/cli/server_test.go @@ -59,9 +59,6 @@ import ( ) func dbArg(t *testing.T) string { - if !dbtestutil.WillUsePostgres() { - return "--in-memory" - } dbURL, err := dbtestutil.Open(t) require.NoError(t, err) return "--postgres-url=" + dbURL diff --git a/cli/testdata/server-config.yaml.golden b/cli/testdata/server-config.yaml.golden index dabeab8ca48bd..e23274e442078 100644 --- a/cli/testdata/server-config.yaml.golden +++ b/cli/testdata/server-config.yaml.golden @@ -462,9 +462,6 @@ enableSwagger: false # to be configured as a shared directory across coderd/provisionerd replicas. # (default: [cache dir], type: string) cacheDir: [cache dir] -# Controls whether data will be stored in an in-memory database. -# (default: , type: bool) -inMemoryDatabase: false # Controls whether Coder data, including built-in Postgres, will be stored in a # temporary directory and deleted when the server is stopped. # (default: , type: bool) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 8dea791f7b763..79cff80b1fbc5 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -12305,9 +12305,6 @@ const docTemplate = `{ "http_cookies": { "$ref": "#/definitions/codersdk.HTTPCookieConfig" }, - "in_memory_database": { - "type": "boolean" - }, "job_hang_detector_interval": { "type": "integer" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 143342c1c2147..5fa1d98030cb5 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -10989,9 +10989,6 @@ "http_cookies": { "$ref": "#/definitions/codersdk.HTTPCookieConfig" }, - "in_memory_database": { - "type": "boolean" - }, "job_hang_detector_interval": { "type": "integer" }, diff --git a/coderd/database/dbauthz/customroles_test.go b/coderd/database/dbauthz/customroles_test.go index 5e19f43ab5376..54541d4670c2c 100644 --- a/coderd/database/dbauthz/customroles_test.go +++ b/coderd/database/dbauthz/customroles_test.go @@ -12,7 +12,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/db2sdk" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/policy" "github.com/coder/coder/v2/codersdk" @@ -202,7 +202,7 @@ func TestInsertCustomRoles(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) rec := &coderdtest.RecordingAuthorizer{ Wrapped: rbac.NewAuthorizer(prometheus.NewRegistry()), } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index bcbe6bb881dde..84c2067848ec4 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -19,7 +19,6 @@ import ( "cdr.dev/slog" "github.com/coder/coder/v2/coderd/database/db2sdk" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/notifications" "github.com/coder/coder/v2/coderd/rbac/policy" "github.com/coder/coder/v2/codersdk" @@ -3661,148 +3660,119 @@ func (s *MethodTestSuite) TestExtraMethods() { func (s *MethodTestSuite) TestTailnetFunctions() { s.Run("CleanTailnetCoordinators", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("CleanTailnetLostPeers", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("CleanTailnetTunnels", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("DeleteAllTailnetClientSubscriptions", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteAllTailnetClientSubscriptionsParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("DeleteAllTailnetTunnels", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteAllTailnetTunnelsParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("DeleteCoordinator", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("DeleteTailnetAgent", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetAgentParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate).Errors(sql.ErrNoRows). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate).Errors(sql.ErrNoRows) })) s.Run("DeleteTailnetClient", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetClientParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete).Errors(sql.ErrNoRows). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete).Errors(sql.ErrNoRows) })) s.Run("DeleteTailnetClientSubscription", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetClientSubscriptionParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete) })) s.Run("DeleteTailnetPeer", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetPeerParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented). - ErrorsWithPG(sql.ErrNoRows) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete).Errors(sql.ErrNoRows) })) s.Run("DeleteTailnetTunnel", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetTunnelParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - ErrorsWithInMemDB(dbmem.ErrUnimplemented). - ErrorsWithPG(sql.ErrNoRows) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete).Errors(sql.ErrNoRows) })) s.Run("GetAllTailnetAgents", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetTailnetAgents", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetTailnetClientsForAgent", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetTailnetPeers", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetTailnetTunnelPeerBindings", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetTailnetTunnelPeerIDs", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetAllTailnetCoordinators", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetAllTailnetPeers", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("GetAllTailnetTunnels", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead) })) s.Run("UpsertTailnetAgent", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetAgentParams{Node: json.RawMessage("{}")}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate) })) s.Run("UpsertTailnetClient", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetClientParams{Node: json.RawMessage("{}")}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate) })) s.Run("UpsertTailnetClientSubscription", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetClientSubscriptionParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate) })) s.Run("UpsertTailnetCoordinator", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate) })) s.Run("UpsertTailnetPeer", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetPeerParams{ Status: database.TailnetStatusOk, }). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionCreate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionCreate) })) s.Run("UpsertTailnetTunnel", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetTunnelParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionCreate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionCreate) })) s.Run("UpdateTailnetPeerStatusByCoordinator", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpdateTailnetPeerStatusByCoordinatorParams{Status: database.TailnetStatusOk}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate) })) } @@ -4787,21 +4757,18 @@ func (s *MethodTestSuite) TestNotifications() { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) user := dbgen.User(s.T(), db, database.User{}) check.Args(user.ID).Asserts(rbac.ResourceNotificationTemplate, policy.ActionRead). - ErrorsWithPG(sql.ErrNoRows). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + ErrorsWithPG(sql.ErrNoRows) })) s.Run("GetNotificationTemplatesByKind", s.Subtest(func(db database.Store, check *expects) { check.Args(database.NotificationTemplateKindSystem). - Asserts(). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts() // TODO(dannyk): add support for other database.NotificationTemplateKind types once implemented. })) s.Run("UpdateNotificationTemplateMethodByID", s.Subtest(func(db database.Store, check *expects) { check.Args(database.UpdateNotificationTemplateMethodByIDParams{ Method: database.NullNotificationMethod{NotificationMethod: database.NotificationMethodWebhook, Valid: true}, ID: notifications.TemplateWorkspaceDormant, - }).Asserts(rbac.ResourceNotificationTemplate, policy.ActionUpdate). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + }).Asserts(rbac.ResourceNotificationTemplate, policy.ActionUpdate) })) // Notification preferences @@ -5115,8 +5082,7 @@ func (s *MethodTestSuite) TestPrebuilds() { rbac.ResourceWorkspace.WithOwner(user.ID.String()).InOrg(org.ID), policy.ActionCreate, template, policy.ActionRead, template, policy.ActionUse, - ).ErrorsWithInMemDB(dbmem.ErrUnimplemented). - ErrorsWithPG(sql.ErrNoRows) + ).Errors(sql.ErrNoRows) })) s.Run("GetPrebuildMetrics", s.Subtest(func(_ database.Store, check *expects) { check.Args(). @@ -5130,29 +5096,24 @@ func (s *MethodTestSuite) TestPrebuilds() { })) s.Run("CountInProgressPrebuilds", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead) })) s.Run("GetPresetsAtFailureLimit", s.Subtest(func(_ database.Store, check *expects) { check.Args(int64(0)). - Asserts(rbac.ResourceTemplate.All(), policy.ActionViewInsights). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTemplate.All(), policy.ActionViewInsights) })) s.Run("GetPresetsBackoff", s.Subtest(func(_ database.Store, check *expects) { check.Args(time.Time{}). - Asserts(rbac.ResourceTemplate.All(), policy.ActionViewInsights). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTemplate.All(), policy.ActionViewInsights) })) s.Run("GetRunningPrebuiltWorkspaces", s.Subtest(func(_ database.Store, check *expects) { check.Args(). - Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead) })) s.Run("GetTemplatePresetsWithPrebuilds", s.Subtest(func(db database.Store, check *expects) { user := dbgen.User(s.T(), db, database.User{}) check.Args(uuid.NullUUID{UUID: user.ID, Valid: true}). - Asserts(rbac.ResourceTemplate.All(), policy.ActionRead). - ErrorsWithInMemDB(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTemplate.All(), policy.ActionRead) })) s.Run("GetPresetByID", s.Subtest(func(db database.Store, check *expects) { org := dbgen.Organization(s.T(), db, database.Organization{}) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go deleted file mode 100644 index d106e6a5858fb..0000000000000 --- a/coderd/database/dbmem/dbmem.go +++ /dev/null @@ -1,14242 +0,0 @@ -package dbmem - -import ( - "bytes" - "context" - "database/sql" - "encoding/json" - "errors" - "fmt" - "math" - insecurerand "math/rand" //#nosec // this is only used for shuffling an array to pick random jobs to reap - "reflect" - "regexp" - "slices" - "sort" - "strings" - "sync" - "time" - - "github.com/google/uuid" - "github.com/lib/pq" - "golang.org/x/exp/constraints" - "golang.org/x/exp/maps" - "golang.org/x/xerrors" - - "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbtime" - "github.com/coder/coder/v2/coderd/notifications/types" - "github.com/coder/coder/v2/coderd/rbac" - "github.com/coder/coder/v2/coderd/rbac/regosql" - "github.com/coder/coder/v2/coderd/util/slice" - "github.com/coder/coder/v2/coderd/workspaceapps/appurl" - "github.com/coder/coder/v2/codersdk" - "github.com/coder/coder/v2/provisionersdk" -) - -var validProxyByHostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`) - -// A full mapping of error codes from pq v1.10.9 can be found here: -// https://github.com/lib/pq/blob/2a217b94f5ccd3de31aec4152a541b9ff64bed05/error.go#L75 -var ( - errForeignKeyConstraint = &pq.Error{ - Code: "23503", // "foreign_key_violation" - Message: "update or delete on table violates foreign key constraint", - } - errUniqueConstraint = &pq.Error{ - Code: "23505", // "unique_violation" - Message: "duplicate key value violates unique constraint", - } -) - -// New returns an in-memory fake of the database. -func New() database.Store { - q := &FakeQuerier{ - mutex: &sync.RWMutex{}, - data: &data{ - apiKeys: make([]database.APIKey, 0), - auditLogs: make([]database.AuditLog, 0), - customRoles: make([]database.CustomRole, 0), - dbcryptKeys: make([]database.DBCryptKey, 0), - externalAuthLinks: make([]database.ExternalAuthLink, 0), - files: make([]database.File, 0), - gitSSHKey: make([]database.GitSSHKey, 0), - groups: make([]database.Group, 0), - groupMembers: make([]database.GroupMemberTable, 0), - licenses: make([]database.License, 0), - locks: map[int64]struct{}{}, - notificationMessages: make([]database.NotificationMessage, 0), - notificationPreferences: make([]database.NotificationPreference, 0), - organizationMembers: make([]database.OrganizationMember, 0), - organizations: make([]database.Organization, 0), - inboxNotifications: make([]database.InboxNotification, 0), - parameterSchemas: make([]database.ParameterSchema, 0), - presets: make([]database.TemplateVersionPreset, 0), - presetParameters: make([]database.TemplateVersionPresetParameter, 0), - presetPrebuildSchedules: make([]database.TemplateVersionPresetPrebuildSchedule, 0), - provisionerDaemons: make([]database.ProvisionerDaemon, 0), - provisionerJobs: make([]database.ProvisionerJob, 0), - provisionerJobLogs: make([]database.ProvisionerJobLog, 0), - provisionerKeys: make([]database.ProvisionerKey, 0), - runtimeConfig: map[string]string{}, - telemetryItems: make([]database.TelemetryItem, 0), - templateVersions: make([]database.TemplateVersionTable, 0), - templateVersionTerraformValues: make([]database.TemplateVersionTerraformValue, 0), - templates: make([]database.TemplateTable, 0), - users: make([]database.User, 0), - userConfigs: make([]database.UserConfig, 0), - userStatusChanges: make([]database.UserStatusChange, 0), - workspaceAgents: make([]database.WorkspaceAgent, 0), - workspaceResources: make([]database.WorkspaceResource, 0), - workspaceModules: make([]database.WorkspaceModule, 0), - workspaceResourceMetadata: make([]database.WorkspaceResourceMetadatum, 0), - workspaceAgentStats: make([]database.WorkspaceAgentStat, 0), - workspaceAgentLogs: make([]database.WorkspaceAgentLog, 0), - workspaceBuilds: make([]database.WorkspaceBuild, 0), - workspaceApps: make([]database.WorkspaceApp, 0), - workspaceAppAuditSessions: make([]database.WorkspaceAppAuditSession, 0), - workspaces: make([]database.WorkspaceTable, 0), - workspaceProxies: make([]database.WorkspaceProxy, 0), - }, - } - // Always start with a default org. Matching migration 198. - defaultOrg, err := q.InsertOrganization(context.Background(), database.InsertOrganizationParams{ - ID: uuid.New(), - Name: "coder", - DisplayName: "Coder", - Description: "Builtin default organization.", - Icon: "", - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - }) - if err != nil { - panic(xerrors.Errorf("failed to create default organization: %w", err)) - } - - _, err = q.InsertAllUsersGroup(context.Background(), defaultOrg.ID) - if err != nil { - panic(xerrors.Errorf("failed to create default group: %w", err)) - } - - q.defaultProxyDisplayName = "Default" - q.defaultProxyIconURL = "/emojis/1f3e1.png" - - _, err = q.InsertProvisionerKey(context.Background(), database.InsertProvisionerKeyParams{ - ID: codersdk.ProvisionerKeyUUIDBuiltIn, - OrganizationID: defaultOrg.ID, - CreatedAt: dbtime.Now(), - HashedSecret: []byte{}, - Name: codersdk.ProvisionerKeyNameBuiltIn, - Tags: map[string]string{}, - }) - if err != nil { - panic(xerrors.Errorf("failed to create built-in provisioner key: %w", err)) - } - _, err = q.InsertProvisionerKey(context.Background(), database.InsertProvisionerKeyParams{ - ID: codersdk.ProvisionerKeyUUIDUserAuth, - OrganizationID: defaultOrg.ID, - CreatedAt: dbtime.Now(), - HashedSecret: []byte{}, - Name: codersdk.ProvisionerKeyNameUserAuth, - Tags: map[string]string{}, - }) - if err != nil { - panic(xerrors.Errorf("failed to create user-auth provisioner key: %w", err)) - } - _, err = q.InsertProvisionerKey(context.Background(), database.InsertProvisionerKeyParams{ - ID: codersdk.ProvisionerKeyUUIDPSK, - OrganizationID: defaultOrg.ID, - CreatedAt: dbtime.Now(), - HashedSecret: []byte{}, - Name: codersdk.ProvisionerKeyNamePSK, - Tags: map[string]string{}, - }) - if err != nil { - panic(xerrors.Errorf("failed to create psk provisioner key: %w", err)) - } - - q.mutex.Lock() - // We can't insert this user using the interface, because it's a system user. - q.data.users = append(q.data.users, database.User{ - ID: database.PrebuildsSystemUserID, - Email: "prebuilds@coder.com", - Username: "prebuilds", - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - Status: "active", - LoginType: "none", - HashedPassword: []byte{}, - IsSystem: true, - Deleted: false, - }) - q.mutex.Unlock() - - return q -} - -type rwMutex interface { - Lock() - RLock() - Unlock() - RUnlock() -} - -// inTxMutex is a no op, since inside a transaction we are already locked. -type inTxMutex struct{} - -func (inTxMutex) Lock() {} -func (inTxMutex) RLock() {} -func (inTxMutex) Unlock() {} -func (inTxMutex) RUnlock() {} - -// FakeQuerier replicates database functionality to enable quick testing. It's an exported type so that our test code -// can do type checks. -type FakeQuerier struct { - mutex rwMutex - *data -} - -func (*FakeQuerier) Wrappers() []string { - return []string{} -} - -type fakeTx struct { - *FakeQuerier - locks map[int64]struct{} -} - -type data struct { - // Legacy tables - apiKeys []database.APIKey - organizations []database.Organization - organizationMembers []database.OrganizationMember - users []database.User - userLinks []database.UserLink - - // New tables - auditLogs []database.AuditLog - cryptoKeys []database.CryptoKey - dbcryptKeys []database.DBCryptKey - files []database.File - externalAuthLinks []database.ExternalAuthLink - gitSSHKey []database.GitSSHKey - groupMembers []database.GroupMemberTable - groups []database.Group - licenses []database.License - notificationMessages []database.NotificationMessage - notificationPreferences []database.NotificationPreference - notificationReportGeneratorLogs []database.NotificationReportGeneratorLog - inboxNotifications []database.InboxNotification - oauth2ProviderApps []database.OAuth2ProviderApp - oauth2ProviderAppSecrets []database.OAuth2ProviderAppSecret - oauth2ProviderAppCodes []database.OAuth2ProviderAppCode - oauth2ProviderAppTokens []database.OAuth2ProviderAppToken - parameterSchemas []database.ParameterSchema - provisionerDaemons []database.ProvisionerDaemon - provisionerJobLogs []database.ProvisionerJobLog - provisionerJobs []database.ProvisionerJob - provisionerKeys []database.ProvisionerKey - replicas []database.Replica - templateVersions []database.TemplateVersionTable - templateVersionParameters []database.TemplateVersionParameter - templateVersionTerraformValues []database.TemplateVersionTerraformValue - templateVersionVariables []database.TemplateVersionVariable - templateVersionWorkspaceTags []database.TemplateVersionWorkspaceTag - templates []database.TemplateTable - templateUsageStats []database.TemplateUsageStat - userConfigs []database.UserConfig - webpushSubscriptions []database.WebpushSubscription - workspaceAgents []database.WorkspaceAgent - workspaceAgentMetadata []database.WorkspaceAgentMetadatum - workspaceAgentLogs []database.WorkspaceAgentLog - workspaceAgentLogSources []database.WorkspaceAgentLogSource - workspaceAgentPortShares []database.WorkspaceAgentPortShare - workspaceAgentScriptTimings []database.WorkspaceAgentScriptTiming - workspaceAgentScripts []database.WorkspaceAgentScript - workspaceAgentStats []database.WorkspaceAgentStat - workspaceAgentMemoryResourceMonitors []database.WorkspaceAgentMemoryResourceMonitor - workspaceAgentVolumeResourceMonitors []database.WorkspaceAgentVolumeResourceMonitor - workspaceAgentDevcontainers []database.WorkspaceAgentDevcontainer - workspaceApps []database.WorkspaceApp - workspaceAppStatuses []database.WorkspaceAppStatus - workspaceAppAuditSessions []database.WorkspaceAppAuditSession - workspaceAppStatsLastInsertID int64 - workspaceAppStats []database.WorkspaceAppStat - workspaceBuilds []database.WorkspaceBuild - workspaceBuildParameters []database.WorkspaceBuildParameter - workspaceResourceMetadata []database.WorkspaceResourceMetadatum - workspaceResources []database.WorkspaceResource - workspaceModules []database.WorkspaceModule - workspaces []database.WorkspaceTable - workspaceProxies []database.WorkspaceProxy - customRoles []database.CustomRole - provisionerJobTimings []database.ProvisionerJobTiming - runtimeConfig map[string]string - // Locks is a map of lock names. Any keys within the map are currently - // locked. - locks map[int64]struct{} - deploymentID string - derpMeshKey string - lastUpdateCheck []byte - announcementBanners []byte - healthSettings []byte - notificationsSettings []byte - oauth2GithubDefaultEligible *bool - applicationName string - logoURL string - appSecurityKey string - oauthSigningKey string - coordinatorResumeTokenSigningKey string - lastLicenseID int32 - defaultProxyDisplayName string - defaultProxyIconURL string - webpushVAPIDPublicKey string - webpushVAPIDPrivateKey string - userStatusChanges []database.UserStatusChange - telemetryItems []database.TelemetryItem - presets []database.TemplateVersionPreset - presetParameters []database.TemplateVersionPresetParameter - presetPrebuildSchedules []database.TemplateVersionPresetPrebuildSchedule - prebuildsSettings []byte -} - -func tryPercentileCont(fs []float64, p float64) float64 { - if len(fs) == 0 { - return -1 - } - sort.Float64s(fs) - pos := p * (float64(len(fs)) - 1) / 100 - lower, upper := int(pos), int(math.Ceil(pos)) - if lower == upper { - return fs[lower] - } - return fs[lower] + (fs[upper]-fs[lower])*(pos-float64(lower)) -} - -func tryPercentileDisc(fs []float64, p float64) float64 { - if len(fs) == 0 { - return -1 - } - sort.Float64s(fs) - return fs[max(int(math.Ceil(float64(len(fs))*p/100-1)), 0)] -} - -func validateDatabaseTypeWithValid(v reflect.Value) (handled bool, err error) { - if v.Kind() == reflect.Struct { - return false, nil - } - - if v.CanInterface() { - if !strings.Contains(v.Type().PkgPath(), "coderd/database") { - return true, nil - } - if valid, ok := v.Interface().(interface{ Valid() bool }); ok { - if !valid.Valid() { - return true, xerrors.Errorf("invalid %s: %q", v.Type().Name(), v.Interface()) - } - } - return true, nil - } - return false, nil -} - -// validateDatabaseType uses reflect to check if struct properties are types -// with a Valid() bool function set. If so, call it and return an error -// if false. -// -// Note that we only check immediate values and struct fields. We do not -// recurse into nested structs. -func validateDatabaseType(args interface{}) error { - v := reflect.ValueOf(args) - - // Note: database.Null* types don't have a Valid method, we skip them here - // because their embedded types may have a Valid method and we don't want - // to bother with checking both that the Valid field is true and that the - // type it embeds validates to true. We would need to check: - // - // dbNullEnum.Valid && dbNullEnum.Enum.Valid() - if strings.HasPrefix(v.Type().Name(), "Null") { - return nil - } - - if ok, err := validateDatabaseTypeWithValid(v); ok { - return err - } - switch v.Kind() { - case reflect.Struct: - var errs []string - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - if ok, err := validateDatabaseTypeWithValid(field); ok && err != nil { - errs = append(errs, fmt.Sprintf("%s.%s: %s", v.Type().Name(), v.Type().Field(i).Name, err.Error())) - } - } - if len(errs) > 0 { - return xerrors.Errorf("invalid database type fields:\n\t%s", strings.Join(errs, "\n\t")) - } - default: - panic(fmt.Sprintf("unhandled type: %s", v.Type().Name())) - } - return nil -} - -func newUniqueConstraintError(uc database.UniqueConstraint) *pq.Error { - newErr := *errUniqueConstraint - newErr.Constraint = string(uc) - - return &newErr -} - -func (*FakeQuerier) Ping(_ context.Context) (time.Duration, error) { - return 0, nil -} - -func (*FakeQuerier) PGLocks(_ context.Context) (database.PGLocks, error) { - return []database.PGLock{}, nil -} - -func (tx *fakeTx) AcquireLock(_ context.Context, id int64) error { - if _, ok := tx.FakeQuerier.locks[id]; ok { - return xerrors.Errorf("cannot acquire lock %d: already held", id) - } - tx.FakeQuerier.locks[id] = struct{}{} - tx.locks[id] = struct{}{} - return nil -} - -func (tx *fakeTx) TryAcquireLock(_ context.Context, id int64) (bool, error) { - if _, ok := tx.FakeQuerier.locks[id]; ok { - return false, nil - } - tx.FakeQuerier.locks[id] = struct{}{} - tx.locks[id] = struct{}{} - return true, nil -} - -func (tx *fakeTx) releaseLocks() { - for id := range tx.locks { - delete(tx.FakeQuerier.locks, id) - } - tx.locks = map[int64]struct{}{} -} - -// InTx doesn't rollback data properly for in-memory yet. -func (q *FakeQuerier) InTx(fn func(database.Store) error, opts *database.TxOptions) error { - q.mutex.Lock() - defer q.mutex.Unlock() - tx := &fakeTx{ - FakeQuerier: &FakeQuerier{mutex: inTxMutex{}, data: q.data}, - locks: map[int64]struct{}{}, - } - defer tx.releaseLocks() - - if opts != nil { - database.IncrementExecutionCount(opts) - } - return fn(tx) -} - -// getUserByIDNoLock is used by other functions in the database fake. -func (q *FakeQuerier) getUserByIDNoLock(id uuid.UUID) (database.User, error) { - for _, user := range q.users { - if user.ID == id { - return user, nil - } - } - return database.User{}, sql.ErrNoRows -} - -func convertUsers(users []database.User, count int64) []database.GetUsersRow { - rows := make([]database.GetUsersRow, len(users)) - for i, u := range users { - rows[i] = database.GetUsersRow{ - ID: u.ID, - Email: u.Email, - Username: u.Username, - Name: u.Name, - HashedPassword: u.HashedPassword, - CreatedAt: u.CreatedAt, - UpdatedAt: u.UpdatedAt, - Status: u.Status, - RBACRoles: u.RBACRoles, - LoginType: u.LoginType, - AvatarURL: u.AvatarURL, - Deleted: u.Deleted, - LastSeenAt: u.LastSeenAt, - Count: count, - IsSystem: u.IsSystem, - } - } - - return rows -} - -// mapAgentStatus determines the agent status based on different timestamps like created_at, last_connected_at, disconnected_at, etc. -// The function must be in sync with: coderd/workspaceagents.go:convertWorkspaceAgent. -func mapAgentStatus(dbAgent database.WorkspaceAgent, agentInactiveDisconnectTimeoutSeconds int64) string { - var status string - connectionTimeout := time.Duration(dbAgent.ConnectionTimeoutSeconds) * time.Second - switch { - case !dbAgent.FirstConnectedAt.Valid: - switch { - case connectionTimeout > 0 && dbtime.Now().Sub(dbAgent.CreatedAt) > connectionTimeout: - // If the agent took too long to connect the first time, - // mark it as timed out. - status = "timeout" - default: - // If the agent never connected, it's waiting for the compute - // to start up. - status = "connecting" - } - case dbAgent.DisconnectedAt.Time.After(dbAgent.LastConnectedAt.Time): - // If we've disconnected after our last connection, we know the - // agent is no longer connected. - status = "disconnected" - case dbtime.Now().Sub(dbAgent.LastConnectedAt.Time) > time.Duration(agentInactiveDisconnectTimeoutSeconds)*time.Second: - // The connection died without updating the last connected. - status = "disconnected" - case dbAgent.LastConnectedAt.Valid: - // The agent should be assumed connected if it's under inactivity timeouts - // and last connected at has been properly set. - status = "connected" - default: - panic("unknown agent status: " + status) - } - return status -} - -func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspaces []database.WorkspaceTable, count int64, withSummary bool) []database.GetWorkspacesRow { //nolint:revive // withSummary flag ensures the extra technical row - rows := make([]database.GetWorkspacesRow, 0, len(workspaces)) - for _, w := range workspaces { - extended := q.extendWorkspace(w) - - wr := database.GetWorkspacesRow{ - ID: w.ID, - CreatedAt: w.CreatedAt, - UpdatedAt: w.UpdatedAt, - OwnerID: w.OwnerID, - OrganizationID: w.OrganizationID, - TemplateID: w.TemplateID, - Deleted: w.Deleted, - Name: w.Name, - AutostartSchedule: w.AutostartSchedule, - Ttl: w.Ttl, - LastUsedAt: w.LastUsedAt, - DormantAt: w.DormantAt, - DeletingAt: w.DeletingAt, - AutomaticUpdates: w.AutomaticUpdates, - Favorite: w.Favorite, - NextStartAt: w.NextStartAt, - - OwnerAvatarUrl: extended.OwnerAvatarUrl, - OwnerUsername: extended.OwnerUsername, - OwnerName: extended.OwnerName, - - OrganizationName: extended.OrganizationName, - OrganizationDisplayName: extended.OrganizationDisplayName, - OrganizationIcon: extended.OrganizationIcon, - OrganizationDescription: extended.OrganizationDescription, - - TemplateName: extended.TemplateName, - TemplateDisplayName: extended.TemplateDisplayName, - TemplateIcon: extended.TemplateIcon, - TemplateDescription: extended.TemplateDescription, - - Count: count, - - // These fields are missing! - // Try to resolve them below - TemplateVersionID: uuid.UUID{}, - TemplateVersionName: sql.NullString{}, - LatestBuildCompletedAt: sql.NullTime{}, - LatestBuildCanceledAt: sql.NullTime{}, - LatestBuildError: sql.NullString{}, - LatestBuildTransition: "", - LatestBuildStatus: "", - } - - if build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, w.ID); err == nil { - for _, tv := range q.templateVersions { - if tv.ID == build.TemplateVersionID { - wr.TemplateVersionID = tv.ID - wr.TemplateVersionName = sql.NullString{ - Valid: true, - String: tv.Name, - } - break - } - } - - if pj, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID); err == nil { - wr.LatestBuildStatus = pj.JobStatus - wr.LatestBuildCanceledAt = pj.CanceledAt - wr.LatestBuildCompletedAt = pj.CompletedAt - wr.LatestBuildError = pj.Error - } - - wr.LatestBuildTransition = build.Transition - } - - rows = append(rows, wr) - } - if withSummary { - rows = append(rows, database.GetWorkspacesRow{ - Name: "**TECHNICAL_ROW**", - Count: count, - }) - } - return rows -} - -func (q *FakeQuerier) getWorkspaceByIDNoLock(_ context.Context, id uuid.UUID) (database.Workspace, error) { - return q.getWorkspaceNoLock(func(w database.WorkspaceTable) bool { - return w.ID == id - }) -} - -func (q *FakeQuerier) getWorkspaceNoLock(find func(w database.WorkspaceTable) bool) (database.Workspace, error) { - w, found := slice.Find(q.workspaces, find) - if found { - return q.extendWorkspace(w), nil - } - return database.Workspace{}, sql.ErrNoRows -} - -func (q *FakeQuerier) extendWorkspace(w database.WorkspaceTable) database.Workspace { - var extended database.Workspace - // This is a cheeky way to copy the fields over without explicitly listing them all. - d, _ := json.Marshal(w) - _ = json.Unmarshal(d, &extended) - - org, _ := slice.Find(q.organizations, func(o database.Organization) bool { - return o.ID == w.OrganizationID - }) - extended.OrganizationName = org.Name - extended.OrganizationDescription = org.Description - extended.OrganizationDisplayName = org.DisplayName - extended.OrganizationIcon = org.Icon - - tpl, _ := slice.Find(q.templates, func(t database.TemplateTable) bool { - return t.ID == w.TemplateID - }) - extended.TemplateName = tpl.Name - extended.TemplateDisplayName = tpl.DisplayName - extended.TemplateDescription = tpl.Description - extended.TemplateIcon = tpl.Icon - - owner, _ := slice.Find(q.users, func(u database.User) bool { - return u.ID == w.OwnerID - }) - extended.OwnerUsername = owner.Username - extended.OwnerName = owner.Name - extended.OwnerAvatarUrl = owner.AvatarURL - - return extended -} - -func (q *FakeQuerier) getWorkspaceByAgentIDNoLock(_ context.Context, agentID uuid.UUID) (database.Workspace, error) { - var agent database.WorkspaceAgent - for _, _agent := range q.workspaceAgents { - if _agent.ID == agentID { - agent = _agent - break - } - } - if agent.ID == uuid.Nil { - return database.Workspace{}, sql.ErrNoRows - } - - var resource database.WorkspaceResource - for _, _resource := range q.workspaceResources { - if _resource.ID == agent.ResourceID { - resource = _resource - break - } - } - if resource.ID == uuid.Nil { - return database.Workspace{}, sql.ErrNoRows - } - - var build database.WorkspaceBuild - for _, _build := range q.workspaceBuilds { - if _build.JobID == resource.JobID { - build = q.workspaceBuildWithUserNoLock(_build) - break - } - } - if build.ID == uuid.Nil { - return database.Workspace{}, sql.ErrNoRows - } - - return q.getWorkspaceNoLock(func(w database.WorkspaceTable) bool { - return w.ID == build.WorkspaceID - }) -} - -func (q *FakeQuerier) getWorkspaceBuildByIDNoLock(_ context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { - for _, build := range q.workspaceBuilds { - if build.ID == id { - return q.workspaceBuildWithUserNoLock(build), nil - } - } - return database.WorkspaceBuild{}, sql.ErrNoRows -} - -func (q *FakeQuerier) getLatestWorkspaceBuildByWorkspaceIDNoLock(_ context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) { - var row database.WorkspaceBuild - var buildNum int32 = -1 - for _, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.WorkspaceID == workspaceID && workspaceBuild.BuildNumber > buildNum { - row = q.workspaceBuildWithUserNoLock(workspaceBuild) - buildNum = workspaceBuild.BuildNumber - } - } - if buildNum == -1 { - return database.WorkspaceBuild{}, sql.ErrNoRows - } - return row, nil -} - -func (q *FakeQuerier) getTemplateByIDNoLock(_ context.Context, id uuid.UUID) (database.Template, error) { - for _, template := range q.templates { - if template.ID == id { - return q.templateWithNameNoLock(template), nil - } - } - return database.Template{}, sql.ErrNoRows -} - -func (q *FakeQuerier) templatesWithUserNoLock(tpl []database.TemplateTable) []database.Template { - cpy := make([]database.Template, 0, len(tpl)) - for _, t := range tpl { - cpy = append(cpy, q.templateWithNameNoLock(t)) - } - return cpy -} - -func (q *FakeQuerier) templateWithNameNoLock(tpl database.TemplateTable) database.Template { - var user database.User - for _, _user := range q.users { - if _user.ID == tpl.CreatedBy { - user = _user - break - } - } - - var org database.Organization - for _, _org := range q.organizations { - if _org.ID == tpl.OrganizationID { - org = _org - break - } - } - - var withNames database.Template - // This is a cheeky way to copy the fields over without explicitly listing them all. - d, _ := json.Marshal(tpl) - _ = json.Unmarshal(d, &withNames) - withNames.CreatedByUsername = user.Username - withNames.CreatedByAvatarURL = user.AvatarURL - withNames.OrganizationName = org.Name - withNames.OrganizationDisplayName = org.DisplayName - withNames.OrganizationIcon = org.Icon - return withNames -} - -func (q *FakeQuerier) templateVersionWithUserNoLock(tpl database.TemplateVersionTable) database.TemplateVersion { - var user database.User - for _, _user := range q.users { - if _user.ID == tpl.CreatedBy { - user = _user - break - } - } - var withUser database.TemplateVersion - // This is a cheeky way to copy the fields over without explicitly listing them all. - d, _ := json.Marshal(tpl) - _ = json.Unmarshal(d, &withUser) - withUser.CreatedByUsername = user.Username - withUser.CreatedByAvatarURL = user.AvatarURL - return withUser -} - -func (q *FakeQuerier) workspaceBuildWithUserNoLock(tpl database.WorkspaceBuild) database.WorkspaceBuild { - var user database.User - for _, _user := range q.users { - if _user.ID == tpl.InitiatorID { - user = _user - break - } - } - var withUser database.WorkspaceBuild - // This is a cheeky way to copy the fields over without explicitly listing them all. - d, _ := json.Marshal(tpl) - _ = json.Unmarshal(d, &withUser) - withUser.InitiatorByUsername = user.Username - withUser.InitiatorByAvatarUrl = user.AvatarURL - return withUser -} - -func (q *FakeQuerier) getTemplateVersionByIDNoLock(_ context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) { - for _, templateVersion := range q.templateVersions { - if templateVersion.ID != templateVersionID { - continue - } - return q.templateVersionWithUserNoLock(templateVersion), nil - } - return database.TemplateVersion{}, sql.ErrNoRows -} - -func (q *FakeQuerier) getWorkspaceAgentByIDNoLock(_ context.Context, id uuid.UUID) (database.WorkspaceAgent, error) { - // The schema sorts this by created at, so we iterate the array backwards. - for i := len(q.workspaceAgents) - 1; i >= 0; i-- { - agent := q.workspaceAgents[i] - if !agent.Deleted && agent.ID == id { - return agent, nil - } - } - return database.WorkspaceAgent{}, sql.ErrNoRows -} - -func (q *FakeQuerier) getWorkspaceAgentsByResourceIDsNoLock(_ context.Context, resourceIDs []uuid.UUID) ([]database.WorkspaceAgent, error) { - workspaceAgents := make([]database.WorkspaceAgent, 0) - for _, agent := range q.workspaceAgents { - if agent.Deleted { - continue - } - for _, resourceID := range resourceIDs { - if agent.ResourceID != resourceID { - continue - } - workspaceAgents = append(workspaceAgents, agent) - } - } - return workspaceAgents, nil -} - -func (q *FakeQuerier) getWorkspaceAppByAgentIDAndSlugNoLock(_ context.Context, arg database.GetWorkspaceAppByAgentIDAndSlugParams) (database.WorkspaceApp, error) { - for _, app := range q.workspaceApps { - if app.AgentID != arg.AgentID { - continue - } - if app.Slug != arg.Slug { - continue - } - return app, nil - } - return database.WorkspaceApp{}, sql.ErrNoRows -} - -func (q *FakeQuerier) getProvisionerJobByIDNoLock(_ context.Context, id uuid.UUID) (database.ProvisionerJob, error) { - for _, provisionerJob := range q.provisionerJobs { - if provisionerJob.ID != id { - continue - } - // clone the Tags before returning, since maps are reference types and - // we don't want the caller to be able to mutate the map we have inside - // dbmem! - provisionerJob.Tags = maps.Clone(provisionerJob.Tags) - return provisionerJob, nil - } - return database.ProvisionerJob{}, sql.ErrNoRows -} - -func (q *FakeQuerier) getWorkspaceResourcesByJobIDNoLock(_ context.Context, jobID uuid.UUID) ([]database.WorkspaceResource, error) { - resources := make([]database.WorkspaceResource, 0) - for _, resource := range q.workspaceResources { - if resource.JobID != jobID { - continue - } - resources = append(resources, resource) - } - return resources, nil -} - -func (q *FakeQuerier) getGroupByIDNoLock(_ context.Context, id uuid.UUID) (database.Group, error) { - for _, group := range q.groups { - if group.ID == id { - return group, nil - } - } - - return database.Group{}, sql.ErrNoRows -} - -// ErrUnimplemented is returned by methods only used by the enterprise/tailnet.pgCoord. This coordinator explicitly -// depends on postgres triggers that announce changes on the pubsub. Implementing support for this in the fake -// database would strongly couple the FakeQuerier to the pubsub, which is undesirable. Furthermore, it makes little -// sense to directly test the pgCoord against anything other than postgres. The FakeQuerier is designed to allow us to -// test the Coderd API, and for that kind of test, the in-memory, AGPL tailnet coordinator is sufficient. Therefore, -// these methods remain unimplemented in the FakeQuerier. -var ErrUnimplemented = xerrors.New("unimplemented") - -func uniqueSortedUUIDs(uuids []uuid.UUID) []uuid.UUID { - set := make(map[uuid.UUID]struct{}) - for _, id := range uuids { - set[id] = struct{}{} - } - unique := make([]uuid.UUID, 0, len(set)) - for id := range set { - unique = append(unique, id) - } - slices.SortFunc(unique, func(a, b uuid.UUID) int { - return slice.Ascending(a.String(), b.String()) - }) - return unique -} - -func (q *FakeQuerier) getOrganizationMemberNoLock(orgID uuid.UUID) []database.OrganizationMember { - var members []database.OrganizationMember - for _, member := range q.organizationMembers { - if member.OrganizationID == orgID { - members = append(members, member) - } - } - - return members -} - -var errUserDeleted = xerrors.New("user deleted") - -// getGroupMemberNoLock fetches a group member by user ID and group ID. -func (q *FakeQuerier) getGroupMemberNoLock(ctx context.Context, userID, groupID uuid.UUID) (database.GroupMember, error) { - groupName := "Everyone" - orgID := groupID - groupIsEveryone := q.isEveryoneGroup(groupID) - if !groupIsEveryone { - group, err := q.getGroupByIDNoLock(ctx, groupID) - if err != nil { - return database.GroupMember{}, err - } - groupName = group.Name - orgID = group.OrganizationID - } - - user, err := q.getUserByIDNoLock(userID) - if err != nil { - return database.GroupMember{}, err - } - if user.Deleted { - return database.GroupMember{}, errUserDeleted - } - - return database.GroupMember{ - UserID: user.ID, - UserEmail: user.Email, - UserUsername: user.Username, - UserHashedPassword: user.HashedPassword, - UserCreatedAt: user.CreatedAt, - UserUpdatedAt: user.UpdatedAt, - UserStatus: user.Status, - UserRbacRoles: user.RBACRoles, - UserLoginType: user.LoginType, - UserAvatarUrl: user.AvatarURL, - UserDeleted: user.Deleted, - UserLastSeenAt: user.LastSeenAt, - UserQuietHoursSchedule: user.QuietHoursSchedule, - UserName: user.Name, - UserGithubComUserID: user.GithubComUserID, - OrganizationID: orgID, - GroupName: groupName, - GroupID: groupID, - }, nil -} - -// getEveryoneGroupMembersNoLock fetches all the users in an organization. -func (q *FakeQuerier) getEveryoneGroupMembersNoLock(ctx context.Context, orgID uuid.UUID) []database.GroupMember { - var ( - everyone []database.GroupMember - orgMembers = q.getOrganizationMemberNoLock(orgID) - ) - for _, member := range orgMembers { - groupMember, err := q.getGroupMemberNoLock(ctx, member.UserID, orgID) - if errors.Is(err, errUserDeleted) { - continue - } - if err != nil { - return nil - } - everyone = append(everyone, groupMember) - } - return everyone -} - -// isEveryoneGroup returns true if the provided ID matches -// an organization ID. -func (q *FakeQuerier) isEveryoneGroup(id uuid.UUID) bool { - for _, org := range q.organizations { - if org.ID == id { - return true - } - } - return false -} - -func (q *FakeQuerier) GetActiveDBCryptKeys(_ context.Context) ([]database.DBCryptKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - ks := make([]database.DBCryptKey, 0, len(q.dbcryptKeys)) - for _, k := range q.dbcryptKeys { - if !k.ActiveKeyDigest.Valid { - continue - } - ks = append([]database.DBCryptKey{}, k) - } - return ks, nil -} - -func maxTime(t, u time.Time) time.Time { - if t.After(u) { - return t - } - return u -} - -func minTime(t, u time.Time) time.Time { - if t.Before(u) { - return t - } - return u -} - -func provisionerJobStatus(j database.ProvisionerJob) database.ProvisionerJobStatus { - if isNotNull(j.CompletedAt) { - if j.Error.String != "" { - return database.ProvisionerJobStatusFailed - } - if isNotNull(j.CanceledAt) { - return database.ProvisionerJobStatusCanceled - } - return database.ProvisionerJobStatusSucceeded - } - - if isNotNull(j.CanceledAt) { - return database.ProvisionerJobStatusCanceling - } - if isNull(j.StartedAt) { - return database.ProvisionerJobStatusPending - } - return database.ProvisionerJobStatusRunning -} - -// isNull is only used in dbmem, so reflect is ok. Use this to make the logic -// look more similar to the postgres. -func isNull(v interface{}) bool { - return !isNotNull(v) -} - -func isNotNull(v interface{}) bool { - return reflect.ValueOf(v).FieldByName("Valid").Bool() -} - -// Took the error from the real database. -var deletedUserLinkError = &pq.Error{ - Severity: "ERROR", - // "raise_exception" error - Code: "P0001", - Message: "Cannot create user_link for deleted user", - Where: "PL/pgSQL function insert_user_links_fail_if_user_deleted() line 7 at RAISE", - File: "pl_exec.c", - Line: "3864", - Routine: "exec_stmt_raise", -} - -// m1 and m2 are equal iff |m1| = |m2| ^ m2 ⊆ m1 -func tagsEqual(m1, m2 map[string]string) bool { - return len(m1) == len(m2) && tagsSubset(m1, m2) -} - -// m2 is a subset of m1 if each key in m1 exists in m2 -// with the same value -func tagsSubset(m1, m2 map[string]string) bool { - for k, v1 := range m1 { - if v2, found := m2[k]; !found || v1 != v2 { - return false - } - } - return true -} - -// default tags when no tag is specified for a provisioner or job -var tagsUntagged = provisionersdk.MutateTags(uuid.Nil, nil) - -func least[T constraints.Ordered](a, b T) T { - if a < b { - return a - } - return b -} - -func (q *FakeQuerier) getLatestWorkspaceAppByTemplateIDUserIDSlugNoLock(ctx context.Context, templateID, userID uuid.UUID, slug string) (database.WorkspaceApp, error) { - /* - SELECT - app.display_name, - app.icon, - app.slug - FROM - workspace_apps AS app - JOIN - workspace_agents AS agent - ON - agent.id = app.agent_id - JOIN - workspace_resources AS resource - ON - resource.id = agent.resource_id - JOIN - workspace_builds AS build - ON - build.job_id = resource.job_id - JOIN - workspaces AS workspace - ON - workspace.id = build.workspace_id - WHERE - -- Requires lateral join. - app.slug = app_usage.key - AND workspace.owner_id = tus.user_id - AND workspace.template_id = tus.template_id - ORDER BY - app.created_at DESC - LIMIT 1 - */ - - var workspaces []database.WorkspaceTable - for _, w := range q.workspaces { - if w.TemplateID != templateID || w.OwnerID != userID { - continue - } - workspaces = append(workspaces, w) - } - slices.SortFunc(workspaces, func(a, b database.WorkspaceTable) int { - if a.CreatedAt.Before(b.CreatedAt) { - return 1 - } else if a.CreatedAt.Equal(b.CreatedAt) { - return 0 - } - return -1 - }) - - for _, workspace := range workspaces { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - continue - } - - resources, err := q.getWorkspaceResourcesByJobIDNoLock(ctx, build.JobID) - if err != nil { - continue - } - var resourceIDs []uuid.UUID - for _, resource := range resources { - resourceIDs = append(resourceIDs, resource.ID) - } - - agents, err := q.getWorkspaceAgentsByResourceIDsNoLock(ctx, resourceIDs) - if err != nil { - continue - } - - for _, agent := range agents { - app, err := q.getWorkspaceAppByAgentIDAndSlugNoLock(ctx, database.GetWorkspaceAppByAgentIDAndSlugParams{ - AgentID: agent.ID, - Slug: slug, - }) - if err != nil { - continue - } - return app, nil - } - } - - return database.WorkspaceApp{}, sql.ErrNoRows -} - -// getOrganizationByIDNoLock is used by other functions in the database fake. -func (q *FakeQuerier) getOrganizationByIDNoLock(id uuid.UUID) (database.Organization, error) { - for _, organization := range q.organizations { - if organization.ID == id { - return organization, nil - } - } - return database.Organization{}, sql.ErrNoRows -} - -func (q *FakeQuerier) getWorkspaceAgentScriptsByAgentIDsNoLock(ids []uuid.UUID) ([]database.WorkspaceAgentScript, error) { - scripts := make([]database.WorkspaceAgentScript, 0) - for _, script := range q.workspaceAgentScripts { - for _, id := range ids { - if script.WorkspaceAgentID == id { - scripts = append(scripts, script) - break - } - } - } - return scripts, nil -} - -// getOwnerFromTags returns the lowercase owner from tags, matching SQL's COALESCE(tags ->> 'owner', ”) -func getOwnerFromTags(tags map[string]string) string { - if owner, ok := tags["owner"]; ok { - return strings.ToLower(owner) - } - return "" -} - -// provisionerTagsetContains checks if daemonTags contain all key-value pairs from jobTags -func provisionerTagsetContains(daemonTags, jobTags map[string]string) bool { - for jobKey, jobValue := range jobTags { - if daemonValue, exists := daemonTags[jobKey]; !exists || daemonValue != jobValue { - return false - } - } - return true -} - -// GetProvisionerJobsByIDsWithQueuePosition mimics the SQL logic in pure Go -func (q *FakeQuerier) getProvisionerJobsByIDsWithQueuePositionLockedTagBasedQueue(_ context.Context, jobIDs []uuid.UUID) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) { - // Step 1: Filter provisionerJobs based on jobIDs - filteredJobs := make(map[uuid.UUID]database.ProvisionerJob) - for _, job := range q.provisionerJobs { - for _, id := range jobIDs { - if job.ID == id { - filteredJobs[job.ID] = job - } - } - } - - // Step 2: Identify pending jobs - pendingJobs := make(map[uuid.UUID]database.ProvisionerJob) - for _, job := range q.provisionerJobs { - if job.JobStatus == "pending" { - pendingJobs[job.ID] = job - } - } - - // Step 3: Identify pending jobs that have a matching provisioner - matchedJobs := make(map[uuid.UUID]struct{}) - for _, job := range pendingJobs { - for _, daemon := range q.provisionerDaemons { - if provisionerTagsetContains(daemon.Tags, job.Tags) { - matchedJobs[job.ID] = struct{}{} - break - } - } - } - - // Step 4: Rank pending jobs per provisioner - jobRanks := make(map[uuid.UUID][]database.ProvisionerJob) - for _, job := range pendingJobs { - for _, daemon := range q.provisionerDaemons { - if provisionerTagsetContains(daemon.Tags, job.Tags) { - jobRanks[daemon.ID] = append(jobRanks[daemon.ID], job) - } - } - } - - // Sort jobs per provisioner by CreatedAt - for daemonID := range jobRanks { - sort.Slice(jobRanks[daemonID], func(i, j int) bool { - return jobRanks[daemonID][i].CreatedAt.Before(jobRanks[daemonID][j].CreatedAt) - }) - } - - // Step 5: Compute queue position & max queue size across all provisioners - jobQueueStats := make(map[uuid.UUID]database.GetProvisionerJobsByIDsWithQueuePositionRow) - for _, jobs := range jobRanks { - queueSize := int64(len(jobs)) // Queue size per provisioner - for i, job := range jobs { - queuePosition := int64(i + 1) - - // If the job already exists, update only if this queuePosition is better - if existing, exists := jobQueueStats[job.ID]; exists { - jobQueueStats[job.ID] = database.GetProvisionerJobsByIDsWithQueuePositionRow{ - ID: job.ID, - CreatedAt: job.CreatedAt, - ProvisionerJob: job, - QueuePosition: min(existing.QueuePosition, queuePosition), - QueueSize: max(existing.QueueSize, queueSize), // Take the maximum queue size across provisioners - } - } else { - jobQueueStats[job.ID] = database.GetProvisionerJobsByIDsWithQueuePositionRow{ - ID: job.ID, - CreatedAt: job.CreatedAt, - ProvisionerJob: job, - QueuePosition: queuePosition, - QueueSize: queueSize, - } - } - } - } - - // Step 6: Compute the final results with minimal checks - var results []database.GetProvisionerJobsByIDsWithQueuePositionRow - for _, job := range filteredJobs { - // If the job has a computed rank, use it - if rank, found := jobQueueStats[job.ID]; found { - results = append(results, rank) - } else { - // Otherwise, return (0,0) for non-pending jobs and unranked pending jobs - results = append(results, database.GetProvisionerJobsByIDsWithQueuePositionRow{ - ID: job.ID, - CreatedAt: job.CreatedAt, - ProvisionerJob: job, - QueuePosition: 0, - QueueSize: 0, - }) - } - } - - // Step 7: Sort results by CreatedAt - sort.Slice(results, func(i, j int) bool { - return results[i].CreatedAt.Before(results[j].CreatedAt) - }) - - return results, nil -} - -func (q *FakeQuerier) getProvisionerJobsByIDsWithQueuePositionLockedGlobalQueue(_ context.Context, ids []uuid.UUID) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) { - // WITH pending_jobs AS ( - // SELECT - // id, created_at - // FROM - // provisioner_jobs - // WHERE - // started_at IS NULL - // AND - // canceled_at IS NULL - // AND - // completed_at IS NULL - // AND - // error IS NULL - // ), - type pendingJobRow struct { - ID uuid.UUID - CreatedAt time.Time - } - pendingJobs := make([]pendingJobRow, 0) - for _, job := range q.provisionerJobs { - if job.StartedAt.Valid || - job.CanceledAt.Valid || - job.CompletedAt.Valid || - job.Error.Valid { - continue - } - pendingJobs = append(pendingJobs, pendingJobRow{ - ID: job.ID, - CreatedAt: job.CreatedAt, - }) - } - - // queue_position AS ( - // SELECT - // id, - // ROW_NUMBER() OVER (ORDER BY created_at ASC) AS queue_position - // FROM - // pending_jobs - // ), - slices.SortFunc(pendingJobs, func(a, b pendingJobRow) int { - c := a.CreatedAt.Compare(b.CreatedAt) - return c - }) - - queuePosition := make(map[uuid.UUID]int64) - for idx, pj := range pendingJobs { - queuePosition[pj.ID] = int64(idx + 1) - } - - // queue_size AS ( - // SELECT COUNT(*) AS count FROM pending_jobs - // ), - queueSize := len(pendingJobs) - - // SELECT - // sqlc.embed(pj), - // COALESCE(qp.queue_position, 0) AS queue_position, - // COALESCE(qs.count, 0) AS queue_size - // FROM - // provisioner_jobs pj - // LEFT JOIN - // queue_position qp ON pj.id = qp.id - // LEFT JOIN - // queue_size qs ON TRUE - // WHERE - // pj.id IN (...) - jobs := make([]database.GetProvisionerJobsByIDsWithQueuePositionRow, 0) - for _, job := range q.provisionerJobs { - if ids != nil && !slices.Contains(ids, job.ID) { - continue - } - // clone the Tags before appending, since maps are reference types and - // we don't want the caller to be able to mutate the map we have inside - // dbmem! - job.Tags = maps.Clone(job.Tags) - job := database.GetProvisionerJobsByIDsWithQueuePositionRow{ - // sqlc.embed(pj), - ProvisionerJob: job, - // COALESCE(qp.queue_position, 0) AS queue_position, - QueuePosition: queuePosition[job.ID], - // COALESCE(qs.count, 0) AS queue_size - QueueSize: int64(queueSize), - } - jobs = append(jobs, job) - } - - return jobs, nil -} - -// isDeprecated returns true if the template is deprecated. -// A template is considered deprecated when it has a deprecation message. -func isDeprecated(template database.Template) bool { - return template.Deprecated != "" -} - -func (q *FakeQuerier) getWorkspaceBuildParametersNoLock(workspaceBuildID uuid.UUID) ([]database.WorkspaceBuildParameter, error) { - params := make([]database.WorkspaceBuildParameter, 0) - for _, param := range q.workspaceBuildParameters { - if param.WorkspaceBuildID != workspaceBuildID { - continue - } - params = append(params, param) - } - return params, nil -} - -func (*FakeQuerier) AcquireLock(_ context.Context, _ int64) error { - return xerrors.New("AcquireLock must only be called within a transaction") -} - -// AcquireNotificationMessages implements the *basic* business logic, but is *not* exhaustive or meant to be 1:1 with -// the real AcquireNotificationMessages query. -func (q *FakeQuerier) AcquireNotificationMessages(_ context.Context, arg database.AcquireNotificationMessagesParams) ([]database.AcquireNotificationMessagesRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - // Shift the first "Count" notifications off the slice (FIFO). - sz := len(q.notificationMessages) - if sz > int(arg.Count) { - sz = int(arg.Count) - } - - list := q.notificationMessages[:sz] - q.notificationMessages = q.notificationMessages[sz:] - - var out []database.AcquireNotificationMessagesRow - for _, nm := range list { - acquirableStatuses := []database.NotificationMessageStatus{database.NotificationMessageStatusPending, database.NotificationMessageStatusTemporaryFailure} - if !slices.Contains(acquirableStatuses, nm.Status) { - continue - } - - // Mimic mutation in database query. - nm.UpdatedAt = sql.NullTime{Time: dbtime.Now(), Valid: true} - nm.Status = database.NotificationMessageStatusLeased - nm.StatusReason = sql.NullString{String: fmt.Sprintf("Enqueued by notifier %d", arg.NotifierID), Valid: true} - nm.LeasedUntil = sql.NullTime{Time: dbtime.Now().Add(time.Second * time.Duration(arg.LeaseSeconds)), Valid: true} - - out = append(out, database.AcquireNotificationMessagesRow{ - ID: nm.ID, - Payload: nm.Payload, - Method: nm.Method, - TitleTemplate: "This is a title with {{.Labels.variable}}", - BodyTemplate: "This is a body with {{.Labels.variable}}", - TemplateID: nm.NotificationTemplateID, - }) - } - - return out, nil -} - -func (q *FakeQuerier) AcquireProvisionerJob(_ context.Context, arg database.AcquireProvisionerJobParams) (database.ProvisionerJob, error) { - if err := validateDatabaseType(arg); err != nil { - return database.ProvisionerJob{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, provisionerJob := range q.provisionerJobs { - if provisionerJob.OrganizationID != arg.OrganizationID { - continue - } - if provisionerJob.StartedAt.Valid { - continue - } - found := false - for _, provisionerType := range arg.Types { - if provisionerJob.Provisioner != provisionerType { - continue - } - found = true - break - } - if !found { - continue - } - tags := map[string]string{} - if arg.ProvisionerTags != nil { - err := json.Unmarshal(arg.ProvisionerTags, &tags) - if err != nil { - return provisionerJob, xerrors.Errorf("unmarshal: %w", err) - } - } - - // Special case for untagged provisioners: only match untagged jobs. - // Ref: coderd/database/queries/provisionerjobs.sql:24-30 - // CASE WHEN nested.tags :: jsonb = '{"scope": "organization", "owner": ""}' :: jsonb - // THEN nested.tags :: jsonb = @tags :: jsonb - if tagsEqual(provisionerJob.Tags, tagsUntagged) && !tagsEqual(provisionerJob.Tags, tags) { - continue - } - // ELSE nested.tags :: jsonb <@ @tags :: jsonb - if !tagsSubset(provisionerJob.Tags, tags) { - continue - } - provisionerJob.StartedAt = arg.StartedAt - provisionerJob.UpdatedAt = arg.StartedAt.Time - provisionerJob.WorkerID = arg.WorkerID - provisionerJob.JobStatus = provisionerJobStatus(provisionerJob) - q.provisionerJobs[index] = provisionerJob - // clone the Tags before returning, since maps are reference types and - // we don't want the caller to be able to mutate the map we have inside - // dbmem! - provisionerJob.Tags = maps.Clone(provisionerJob.Tags) - return provisionerJob, nil - } - return database.ProvisionerJob{}, sql.ErrNoRows -} - -func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.ActivityBumpWorkspaceParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - workspace, err := q.getWorkspaceByIDNoLock(ctx, arg.WorkspaceID) - if err != nil { - return err - } - latestBuild, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, arg.WorkspaceID) - if err != nil { - return err - } - - now := dbtime.Now() - for i := range q.workspaceBuilds { - if q.workspaceBuilds[i].BuildNumber != latestBuild.BuildNumber { - continue - } - // If the build is not active, do not bump. - if q.workspaceBuilds[i].Transition != database.WorkspaceTransitionStart { - return nil - } - // If the provisioner job is not completed, do not bump. - pj, err := q.getProvisionerJobByIDNoLock(ctx, q.workspaceBuilds[i].JobID) - if err != nil { - return err - } - if !pj.CompletedAt.Valid { - return nil - } - // Do not bump if the deadline is not set. - if q.workspaceBuilds[i].Deadline.IsZero() { - return nil - } - - // Check the template default TTL. - template, err := q.getTemplateByIDNoLock(ctx, workspace.TemplateID) - if err != nil { - return err - } - if template.ActivityBump == 0 { - return nil - } - activityBump := time.Duration(template.ActivityBump) - - var ttlDur time.Duration - if now.Add(activityBump).After(arg.NextAutostart) && arg.NextAutostart.After(now) { - // Extend to TTL (NOT activity bump) - add := arg.NextAutostart.Sub(now) - if workspace.Ttl.Valid && template.AllowUserAutostop { - add += time.Duration(workspace.Ttl.Int64) - } else { - add += time.Duration(template.DefaultTTL) - } - ttlDur = add - } else { - // Otherwise, default to regular activity bump duration. - ttlDur = activityBump - } - - // Only bump if 5% of the deadline has passed. - ttlDur95 := ttlDur - (ttlDur / 20) - minBumpDeadline := q.workspaceBuilds[i].Deadline.Add(-ttlDur95) - if now.Before(minBumpDeadline) { - return nil - } - - // Bump. - newDeadline := now.Add(ttlDur) - // Never decrease deadlines from a bump - newDeadline = maxTime(newDeadline, q.workspaceBuilds[i].Deadline) - q.workspaceBuilds[i].UpdatedAt = now - if !q.workspaceBuilds[i].MaxDeadline.IsZero() { - q.workspaceBuilds[i].Deadline = minTime(newDeadline, q.workspaceBuilds[i].MaxDeadline) - } else { - q.workspaceBuilds[i].Deadline = newDeadline - } - return nil - } - - return sql.ErrNoRows -} - -// nolint:revive // It's not a control flag, it's a filter. -func (q *FakeQuerier) AllUserIDs(_ context.Context, includeSystem bool) ([]uuid.UUID, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - userIDs := make([]uuid.UUID, 0, len(q.users)) - for idx := range q.users { - if !includeSystem && q.users[idx].IsSystem { - continue - } - - userIDs = append(userIDs, q.users[idx].ID) - } - return userIDs, nil -} - -func (q *FakeQuerier) ArchiveUnusedTemplateVersions(_ context.Context, arg database.ArchiveUnusedTemplateVersionsParams) ([]uuid.UUID, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - q.mutex.Lock() - defer q.mutex.Unlock() - type latestBuild struct { - Number int32 - Version uuid.UUID - } - latest := make(map[uuid.UUID]latestBuild) - - for _, b := range q.workspaceBuilds { - v, ok := latest[b.WorkspaceID] - if ok || b.BuildNumber < v.Number { - // Not the latest - continue - } - // Ignore deleted workspaces. - if b.Transition == database.WorkspaceTransitionDelete { - continue - } - latest[b.WorkspaceID] = latestBuild{ - Number: b.BuildNumber, - Version: b.TemplateVersionID, - } - } - - usedVersions := make(map[uuid.UUID]bool) - for _, l := range latest { - usedVersions[l.Version] = true - } - for _, tpl := range q.templates { - usedVersions[tpl.ActiveVersionID] = true - } - - var archived []uuid.UUID - for i, v := range q.templateVersions { - if arg.TemplateVersionID != uuid.Nil { - if v.ID != arg.TemplateVersionID { - continue - } - } - if v.Archived { - continue - } - - if _, ok := usedVersions[v.ID]; !ok { - var job *database.ProvisionerJob - for i, j := range q.provisionerJobs { - if v.JobID == j.ID { - job = &q.provisionerJobs[i] - break - } - } - - if arg.JobStatus.Valid { - if job.JobStatus != arg.JobStatus.ProvisionerJobStatus { - continue - } - } - - if job.JobStatus == database.ProvisionerJobStatusRunning || job.JobStatus == database.ProvisionerJobStatusPending { - continue - } - - v.Archived = true - q.templateVersions[i] = v - archived = append(archived, v.ID) - } - } - - return archived, nil -} - -func (q *FakeQuerier) BatchUpdateWorkspaceLastUsedAt(_ context.Context, arg database.BatchUpdateWorkspaceLastUsedAtParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - // temporary map to avoid O(q.workspaces*arg.workspaceIds) - m := make(map[uuid.UUID]struct{}) - for _, id := range arg.IDs { - m[id] = struct{}{} - } - n := 0 - for i := 0; i < len(q.workspaces); i++ { - if _, found := m[q.workspaces[i].ID]; !found { - continue - } - // WHERE last_used_at < @last_used_at - if !q.workspaces[i].LastUsedAt.Before(arg.LastUsedAt) { - continue - } - q.workspaces[i].LastUsedAt = arg.LastUsedAt - n++ - } - return nil -} - -func (q *FakeQuerier) BatchUpdateWorkspaceNextStartAt(_ context.Context, arg database.BatchUpdateWorkspaceNextStartAtParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, workspace := range q.workspaces { - for j, workspaceID := range arg.IDs { - if workspace.ID != workspaceID { - continue - } - - nextStartAt := arg.NextStartAts[j] - if nextStartAt.IsZero() { - q.workspaces[i].NextStartAt = sql.NullTime{} - } else { - q.workspaces[i].NextStartAt = sql.NullTime{Valid: true, Time: nextStartAt} - } - - break - } - } - - return nil -} - -func (*FakeQuerier) BulkMarkNotificationMessagesFailed(_ context.Context, arg database.BulkMarkNotificationMessagesFailedParams) (int64, error) { - err := validateDatabaseType(arg) - if err != nil { - return 0, err - } - return int64(len(arg.IDs)), nil -} - -func (*FakeQuerier) BulkMarkNotificationMessagesSent(_ context.Context, arg database.BulkMarkNotificationMessagesSentParams) (int64, error) { - err := validateDatabaseType(arg) - if err != nil { - return 0, err - } - return int64(len(arg.IDs)), nil -} - -func (q *FakeQuerier) ClaimPrebuiltWorkspace(ctx context.Context, arg database.ClaimPrebuiltWorkspaceParams) (database.ClaimPrebuiltWorkspaceRow, error) { - return database.ClaimPrebuiltWorkspaceRow{}, ErrUnimplemented -} - -func (*FakeQuerier) CleanTailnetCoordinators(_ context.Context) error { - return ErrUnimplemented -} - -func (*FakeQuerier) CleanTailnetLostPeers(context.Context) error { - return ErrUnimplemented -} - -func (*FakeQuerier) CleanTailnetTunnels(context.Context) error { - return ErrUnimplemented -} - -func (q *FakeQuerier) CountAuditLogs(ctx context.Context, arg database.CountAuditLogsParams) (int64, error) { - return q.CountAuthorizedAuditLogs(ctx, arg, nil) -} - -func (q *FakeQuerier) CountInProgressPrebuilds(ctx context.Context) ([]database.CountInProgressPrebuildsRow, error) { - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) CountUnreadInboxNotificationsByUserID(_ context.Context, userID uuid.UUID) (int64, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var count int64 - for _, notification := range q.inboxNotifications { - if notification.UserID != userID { - continue - } - - if notification.ReadAt.Valid { - continue - } - - count++ - } - - return count, nil -} - -func (q *FakeQuerier) CustomRoles(_ context.Context, arg database.CustomRolesParams) ([]database.CustomRole, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - found := make([]database.CustomRole, 0) - for _, role := range q.data.customRoles { - if len(arg.LookupRoles) > 0 { - if !slices.ContainsFunc(arg.LookupRoles, func(pair database.NameOrganizationPair) bool { - if pair.Name != role.Name { - return false - } - - if role.OrganizationID.Valid { - // Expect org match - return role.OrganizationID.UUID == pair.OrganizationID - } - // Expect no org - return pair.OrganizationID == uuid.Nil - }) { - continue - } - } - - if arg.ExcludeOrgRoles && role.OrganizationID.Valid { - continue - } - - if arg.OrganizationID != uuid.Nil && role.OrganizationID.UUID != arg.OrganizationID { - continue - } - - found = append(found, role) - } - - return found, nil -} - -func (q *FakeQuerier) DeleteAPIKeyByID(_ context.Context, id string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, apiKey := range q.apiKeys { - if apiKey.ID != id { - continue - } - q.apiKeys[index] = q.apiKeys[len(q.apiKeys)-1] - q.apiKeys = q.apiKeys[:len(q.apiKeys)-1] - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteAPIKeysByUserID(_ context.Context, userID uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i := len(q.apiKeys) - 1; i >= 0; i-- { - if q.apiKeys[i].UserID == userID { - q.apiKeys = append(q.apiKeys[:i], q.apiKeys[i+1:]...) - } - } - - return nil -} - -func (*FakeQuerier) DeleteAllTailnetClientSubscriptions(_ context.Context, arg database.DeleteAllTailnetClientSubscriptionsParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - return ErrUnimplemented -} - -func (*FakeQuerier) DeleteAllTailnetTunnels(_ context.Context, arg database.DeleteAllTailnetTunnelsParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - return ErrUnimplemented -} - -func (q *FakeQuerier) DeleteAllWebpushSubscriptions(_ context.Context) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.webpushSubscriptions = make([]database.WebpushSubscription, 0) - return nil -} - -func (q *FakeQuerier) DeleteApplicationConnectAPIKeysByUserID(_ context.Context, userID uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i := len(q.apiKeys) - 1; i >= 0; i-- { - if q.apiKeys[i].UserID == userID && q.apiKeys[i].Scope == database.APIKeyScopeApplicationConnect { - q.apiKeys = append(q.apiKeys[:i], q.apiKeys[i+1:]...) - } - } - - return nil -} - -func (*FakeQuerier) DeleteCoordinator(context.Context, uuid.UUID) error { - return ErrUnimplemented -} - -func (q *FakeQuerier) DeleteCryptoKey(_ context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.CryptoKey{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, key := range q.cryptoKeys { - if key.Feature == arg.Feature && key.Sequence == arg.Sequence { - q.cryptoKeys[i].Secret.String = "" - q.cryptoKeys[i].Secret.Valid = false - q.cryptoKeys[i].SecretKeyID.String = "" - q.cryptoKeys[i].SecretKeyID.Valid = false - return q.cryptoKeys[i], nil - } - } - return database.CryptoKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteCustomRole(_ context.Context, arg database.DeleteCustomRoleParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - initial := len(q.data.customRoles) - q.data.customRoles = slices.DeleteFunc(q.data.customRoles, func(role database.CustomRole) bool { - return role.OrganizationID.UUID == arg.OrganizationID.UUID && role.Name == arg.Name - }) - if initial == len(q.data.customRoles) { - return sql.ErrNoRows - } - - // Emulate the trigger 'remove_organization_member_custom_role' - for i, mem := range q.organizationMembers { - if mem.OrganizationID == arg.OrganizationID.UUID { - mem.Roles = slices.DeleteFunc(mem.Roles, func(role string) bool { - return role == arg.Name - }) - q.organizationMembers[i] = mem - } - } - return nil -} - -func (q *FakeQuerier) DeleteExternalAuthLink(_ context.Context, arg database.DeleteExternalAuthLinkParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, key := range q.externalAuthLinks { - if key.UserID != arg.UserID { - continue - } - if key.ProviderID != arg.ProviderID { - continue - } - q.externalAuthLinks[index] = q.externalAuthLinks[len(q.externalAuthLinks)-1] - q.externalAuthLinks = q.externalAuthLinks[:len(q.externalAuthLinks)-1] - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteGitSSHKey(_ context.Context, userID uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, key := range q.gitSSHKey { - if key.UserID != userID { - continue - } - q.gitSSHKey[index] = q.gitSSHKey[len(q.gitSSHKey)-1] - q.gitSSHKey = q.gitSSHKey[:len(q.gitSSHKey)-1] - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteGroupByID(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, group := range q.groups { - if group.ID == id { - q.groups = append(q.groups[:i], q.groups[i+1:]...) - return nil - } - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteGroupMemberFromGroup(_ context.Context, arg database.DeleteGroupMemberFromGroupParams) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, member := range q.groupMembers { - if member.UserID == arg.UserID && member.GroupID == arg.GroupID { - q.groupMembers = append(q.groupMembers[:i], q.groupMembers[i+1:]...) - } - } - return nil -} - -func (q *FakeQuerier) DeleteLicense(_ context.Context, id int32) (int32, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, l := range q.licenses { - if l.ID == id { - q.licenses[index] = q.licenses[len(q.licenses)-1] - q.licenses = q.licenses[:len(q.licenses)-1] - return id, nil - } - } - return 0, sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteOAuth2ProviderAppByClientID(ctx context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, app := range q.oauth2ProviderApps { - if app.ID == id { - q.oauth2ProviderApps = append(q.oauth2ProviderApps[:i], q.oauth2ProviderApps[i+1:]...) - - // Also delete related secrets and tokens - for j := len(q.oauth2ProviderAppSecrets) - 1; j >= 0; j-- { - if q.oauth2ProviderAppSecrets[j].AppID == id { - q.oauth2ProviderAppSecrets = append(q.oauth2ProviderAppSecrets[:j], q.oauth2ProviderAppSecrets[j+1:]...) - } - } - - // Delete tokens for the app's secrets - for j := len(q.oauth2ProviderAppTokens) - 1; j >= 0; j-- { - token := q.oauth2ProviderAppTokens[j] - for _, secret := range q.oauth2ProviderAppSecrets { - if secret.AppID == id && token.AppSecretID == secret.ID { - q.oauth2ProviderAppTokens = append(q.oauth2ProviderAppTokens[:j], q.oauth2ProviderAppTokens[j+1:]...) - break - } - } - } - - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteOAuth2ProviderAppByID(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - index := slices.IndexFunc(q.oauth2ProviderApps, func(app database.OAuth2ProviderApp) bool { - return app.ID == id - }) - - if index < 0 { - return sql.ErrNoRows - } - - q.oauth2ProviderApps[index] = q.oauth2ProviderApps[len(q.oauth2ProviderApps)-1] - q.oauth2ProviderApps = q.oauth2ProviderApps[:len(q.oauth2ProviderApps)-1] - - // Cascade delete secrets associated with the deleted app. - var deletedSecretIDs []uuid.UUID - q.oauth2ProviderAppSecrets = slices.DeleteFunc(q.oauth2ProviderAppSecrets, func(secret database.OAuth2ProviderAppSecret) bool { - matches := secret.AppID == id - if matches { - deletedSecretIDs = append(deletedSecretIDs, secret.ID) - } - return matches - }) - - // Cascade delete tokens through the deleted secrets. - var keyIDsToDelete []string - q.oauth2ProviderAppTokens = slices.DeleteFunc(q.oauth2ProviderAppTokens, func(token database.OAuth2ProviderAppToken) bool { - matches := slice.Contains(deletedSecretIDs, token.AppSecretID) - if matches { - keyIDsToDelete = append(keyIDsToDelete, token.APIKeyID) - } - return matches - }) - - // Cascade delete API keys linked to the deleted tokens. - q.apiKeys = slices.DeleteFunc(q.apiKeys, func(key database.APIKey) bool { - return slices.Contains(keyIDsToDelete, key.ID) - }) - - return nil -} - -func (q *FakeQuerier) DeleteOAuth2ProviderAppCodeByID(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, code := range q.oauth2ProviderAppCodes { - if code.ID == id { - q.oauth2ProviderAppCodes[index] = q.oauth2ProviderAppCodes[len(q.oauth2ProviderAppCodes)-1] - q.oauth2ProviderAppCodes = q.oauth2ProviderAppCodes[:len(q.oauth2ProviderAppCodes)-1] - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteOAuth2ProviderAppCodesByAppAndUserID(_ context.Context, arg database.DeleteOAuth2ProviderAppCodesByAppAndUserIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, code := range q.oauth2ProviderAppCodes { - if code.AppID == arg.AppID && code.UserID == arg.UserID { - q.oauth2ProviderAppCodes[index] = q.oauth2ProviderAppCodes[len(q.oauth2ProviderAppCodes)-1] - q.oauth2ProviderAppCodes = q.oauth2ProviderAppCodes[:len(q.oauth2ProviderAppCodes)-1] - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteOAuth2ProviderAppSecretByID(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - index := slices.IndexFunc(q.oauth2ProviderAppSecrets, func(secret database.OAuth2ProviderAppSecret) bool { - return secret.ID == id - }) - - if index < 0 { - return sql.ErrNoRows - } - - q.oauth2ProviderAppSecrets[index] = q.oauth2ProviderAppSecrets[len(q.oauth2ProviderAppSecrets)-1] - q.oauth2ProviderAppSecrets = q.oauth2ProviderAppSecrets[:len(q.oauth2ProviderAppSecrets)-1] - - // Cascade delete tokens created through the deleted secret. - var keyIDsToDelete []string - q.oauth2ProviderAppTokens = slices.DeleteFunc(q.oauth2ProviderAppTokens, func(token database.OAuth2ProviderAppToken) bool { - matches := token.AppSecretID == id - if matches { - keyIDsToDelete = append(keyIDsToDelete, token.APIKeyID) - } - return matches - }) - - // Cascade delete API keys linked to the deleted tokens. - q.apiKeys = slices.DeleteFunc(q.apiKeys, func(key database.APIKey) bool { - return slices.Contains(keyIDsToDelete, key.ID) - }) - - return nil -} - -func (q *FakeQuerier) DeleteOAuth2ProviderAppTokensByAppAndUserID(_ context.Context, arg database.DeleteOAuth2ProviderAppTokensByAppAndUserIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - var keyIDsToDelete []string - q.oauth2ProviderAppTokens = slices.DeleteFunc(q.oauth2ProviderAppTokens, func(token database.OAuth2ProviderAppToken) bool { - // Join secrets and keys to see if the token matches. - secretIdx := slices.IndexFunc(q.oauth2ProviderAppSecrets, func(secret database.OAuth2ProviderAppSecret) bool { - return secret.ID == token.AppSecretID - }) - keyIdx := slices.IndexFunc(q.apiKeys, func(key database.APIKey) bool { - return key.ID == token.APIKeyID - }) - matches := secretIdx != -1 && - q.oauth2ProviderAppSecrets[secretIdx].AppID == arg.AppID && - keyIdx != -1 && q.apiKeys[keyIdx].UserID == arg.UserID - if matches { - keyIDsToDelete = append(keyIDsToDelete, token.APIKeyID) - } - return matches - }) - - // Cascade delete API keys linked to the deleted tokens. - q.apiKeys = slices.DeleteFunc(q.apiKeys, func(key database.APIKey) bool { - return slices.Contains(keyIDsToDelete, key.ID) - }) - - return nil -} - -func (*FakeQuerier) DeleteOldNotificationMessages(_ context.Context) error { - return nil -} - -func (q *FakeQuerier) DeleteOldProvisionerDaemons(_ context.Context) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - now := dbtime.Now() - weekInterval := 7 * 24 * time.Hour - weekAgo := now.Add(-weekInterval) - - var validDaemons []database.ProvisionerDaemon - for _, p := range q.provisionerDaemons { - if (p.CreatedAt.Before(weekAgo) && !p.LastSeenAt.Valid) || (p.LastSeenAt.Valid && p.LastSeenAt.Time.Before(weekAgo)) { - continue - } - validDaemons = append(validDaemons, p) - } - q.provisionerDaemons = validDaemons - return nil -} - -func (q *FakeQuerier) DeleteOldWorkspaceAgentLogs(_ context.Context, threshold time.Time) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - /* - WITH - latest_builds AS ( - SELECT - workspace_id, max(build_number) AS max_build_number - FROM - workspace_builds - GROUP BY - workspace_id - ), - */ - latestBuilds := make(map[uuid.UUID]int32) - for _, wb := range q.workspaceBuilds { - if lastBuildNumber, found := latestBuilds[wb.WorkspaceID]; found && lastBuildNumber > wb.BuildNumber { - continue - } - // not found or newer build number - latestBuilds[wb.WorkspaceID] = wb.BuildNumber - } - - /* - old_agents AS ( - SELECT - wa.id - FROM - workspace_agents AS wa - JOIN - workspace_resources AS wr - ON - wa.resource_id = wr.id - JOIN - workspace_builds AS wb - ON - wb.job_id = wr.job_id - LEFT JOIN - latest_builds - ON - latest_builds.workspace_id = wb.workspace_id - AND - latest_builds.max_build_number = wb.build_number - WHERE - -- Filter out the latest builds for each workspace. - latest_builds.workspace_id IS NULL - AND CASE - -- If the last time the agent connected was before @threshold - WHEN wa.last_connected_at IS NOT NULL THEN - wa.last_connected_at < @threshold :: timestamptz - -- The agent never connected, and was created before @threshold - ELSE wa.created_at < @threshold :: timestamptz - END - ) - */ - oldAgents := make(map[uuid.UUID]struct{}) - for _, wa := range q.workspaceAgents { - for _, wr := range q.workspaceResources { - if wr.ID != wa.ResourceID { - continue - } - for _, wb := range q.workspaceBuilds { - if wb.JobID != wr.JobID { - continue - } - latestBuildNumber, found := latestBuilds[wb.WorkspaceID] - if !found { - panic("workspaceBuilds got modified somehow while q was locked! This is a bug in dbmem!") - } - if latestBuildNumber == wb.BuildNumber { - continue - } - if wa.LastConnectedAt.Valid && wa.LastConnectedAt.Time.Before(threshold) || wa.CreatedAt.Before(threshold) { - oldAgents[wa.ID] = struct{}{} - } - } - } - } - /* - DELETE FROM workspace_agent_logs WHERE agent_id IN (SELECT id FROM old_agents); - */ - var validLogs []database.WorkspaceAgentLog - for _, log := range q.workspaceAgentLogs { - if _, found := oldAgents[log.AgentID]; found { - continue - } - validLogs = append(validLogs, log) - } - q.workspaceAgentLogs = validLogs - return nil -} - -func (q *FakeQuerier) DeleteOldWorkspaceAgentStats(_ context.Context) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - /* - DELETE FROM - workspace_agent_stats - WHERE - created_at < ( - SELECT - COALESCE( - -- When generating initial template usage stats, all the - -- raw agent stats are needed, after that only ~30 mins - -- from last rollup is needed. Deployment stats seem to - -- use between 15 mins and 1 hour of data. We keep a - -- little bit more (1 day) just in case. - MAX(start_time) - '1 days'::interval, - -- Fall back to ~6 months ago if there are no template - -- usage stats so that we don't delete the data before - -- it's rolled up. - NOW() - '180 days'::interval - ) - FROM - template_usage_stats - ) - AND created_at < ( - -- Delete at most in batches of 3 days (with a batch size of 3 days, we - -- can clear out the previous 6 months of data in ~60 iterations) whilst - -- keeping the DB load relatively low. - SELECT - COALESCE(MIN(created_at) + '3 days'::interval, NOW()) - FROM - workspace_agent_stats - ); - */ - - now := dbtime.Now() - var limit time.Time - // MAX - for _, stat := range q.templateUsageStats { - if stat.StartTime.After(limit) { - limit = stat.StartTime.AddDate(0, 0, -1) - } - } - // COALESCE - if limit.IsZero() { - limit = now.AddDate(0, 0, -180) - } - - var validStats []database.WorkspaceAgentStat - var batchLimit time.Time - for _, stat := range q.workspaceAgentStats { - if batchLimit.IsZero() || stat.CreatedAt.Before(batchLimit) { - batchLimit = stat.CreatedAt - } - } - if batchLimit.IsZero() { - batchLimit = time.Now() - } else { - batchLimit = batchLimit.AddDate(0, 0, 3) - } - for _, stat := range q.workspaceAgentStats { - if stat.CreatedAt.Before(limit) && stat.CreatedAt.Before(batchLimit) { - continue - } - validStats = append(validStats, stat) - } - q.workspaceAgentStats = validStats - return nil -} - -func (q *FakeQuerier) DeleteOrganizationMember(ctx context.Context, arg database.DeleteOrganizationMemberParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - deleted := false - q.data.organizationMembers = slices.DeleteFunc(q.data.organizationMembers, func(member database.OrganizationMember) bool { - match := member.OrganizationID == arg.OrganizationID && member.UserID == arg.UserID - deleted = deleted || match - return match - }) - if !deleted { - return sql.ErrNoRows - } - - // Delete group member trigger - q.groupMembers = slices.DeleteFunc(q.groupMembers, func(member database.GroupMemberTable) bool { - if member.UserID != arg.UserID { - return false - } - g, _ := q.getGroupByIDNoLock(ctx, member.GroupID) - return g.OrganizationID == arg.OrganizationID - }) - - return nil -} - -func (q *FakeQuerier) DeleteProvisionerKey(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, key := range q.provisionerKeys { - if key.ID == id { - q.provisionerKeys = append(q.provisionerKeys[:i], q.provisionerKeys[i+1:]...) - return nil - } - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteReplicasUpdatedBefore(_ context.Context, before time.Time) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, replica := range q.replicas { - if replica.UpdatedAt.Before(before) { - q.replicas = append(q.replicas[:i], q.replicas[i+1:]...) - } - } - - return nil -} - -func (q *FakeQuerier) DeleteRuntimeConfig(_ context.Context, key string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - delete(q.runtimeConfig, key) - return nil -} - -func (*FakeQuerier) DeleteTailnetAgent(context.Context, database.DeleteTailnetAgentParams) (database.DeleteTailnetAgentRow, error) { - return database.DeleteTailnetAgentRow{}, ErrUnimplemented -} - -func (*FakeQuerier) DeleteTailnetClient(context.Context, database.DeleteTailnetClientParams) (database.DeleteTailnetClientRow, error) { - return database.DeleteTailnetClientRow{}, ErrUnimplemented -} - -func (*FakeQuerier) DeleteTailnetClientSubscription(context.Context, database.DeleteTailnetClientSubscriptionParams) error { - return ErrUnimplemented -} - -func (*FakeQuerier) DeleteTailnetPeer(_ context.Context, arg database.DeleteTailnetPeerParams) (database.DeleteTailnetPeerRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.DeleteTailnetPeerRow{}, err - } - - return database.DeleteTailnetPeerRow{}, ErrUnimplemented -} - -func (*FakeQuerier) DeleteTailnetTunnel(_ context.Context, arg database.DeleteTailnetTunnelParams) (database.DeleteTailnetTunnelRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.DeleteTailnetTunnelRow{}, err - } - - return database.DeleteTailnetTunnelRow{}, ErrUnimplemented -} - -func (q *FakeQuerier) DeleteWebpushSubscriptionByUserIDAndEndpoint(_ context.Context, arg database.DeleteWebpushSubscriptionByUserIDAndEndpointParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, subscription := range q.webpushSubscriptions { - if subscription.UserID == arg.UserID && subscription.Endpoint == arg.Endpoint { - q.webpushSubscriptions[i] = q.webpushSubscriptions[len(q.webpushSubscriptions)-1] - q.webpushSubscriptions = q.webpushSubscriptions[:len(q.webpushSubscriptions)-1] - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteWebpushSubscriptions(_ context.Context, ids []uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - for i, subscription := range q.webpushSubscriptions { - if slices.Contains(ids, subscription.ID) { - q.webpushSubscriptions[i] = q.webpushSubscriptions[len(q.webpushSubscriptions)-1] - q.webpushSubscriptions = q.webpushSubscriptions[:len(q.webpushSubscriptions)-1] - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) DeleteWorkspaceAgentPortShare(_ context.Context, arg database.DeleteWorkspaceAgentPortShareParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, share := range q.workspaceAgentPortShares { - if share.WorkspaceID == arg.WorkspaceID && share.AgentName == arg.AgentName && share.Port == arg.Port { - q.workspaceAgentPortShares = append(q.workspaceAgentPortShares[:i], q.workspaceAgentPortShares[i+1:]...) - return nil - } - } - - return nil -} - -func (q *FakeQuerier) DeleteWorkspaceAgentPortSharesByTemplate(_ context.Context, templateID uuid.UUID) error { - err := validateDatabaseType(templateID) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, workspace := range q.workspaces { - if workspace.TemplateID != templateID { - continue - } - for i, share := range q.workspaceAgentPortShares { - if share.WorkspaceID != workspace.ID { - continue - } - q.workspaceAgentPortShares = append(q.workspaceAgentPortShares[:i], q.workspaceAgentPortShares[i+1:]...) - } - } - - return nil -} - -func (q *FakeQuerier) DeleteWorkspaceSubAgentByID(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, agent := range q.workspaceAgents { - if agent.ID == id && agent.ParentID.Valid { - q.workspaceAgents[i].Deleted = true - return nil - } - } - - return nil -} - -func (*FakeQuerier) DisableForeignKeysAndTriggers(_ context.Context) error { - // This is a no-op in the in-memory database. - return nil -} - -func (q *FakeQuerier) EnqueueNotificationMessage(_ context.Context, arg database.EnqueueNotificationMessageParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - var payload types.MessagePayload - err = json.Unmarshal(arg.Payload, &payload) - if err != nil { - return err - } - - nm := database.NotificationMessage{ - ID: arg.ID, - UserID: arg.UserID, - Method: arg.Method, - Payload: arg.Payload, - NotificationTemplateID: arg.NotificationTemplateID, - Targets: arg.Targets, - CreatedBy: arg.CreatedBy, - // Default fields. - CreatedAt: dbtime.Now(), - Status: database.NotificationMessageStatusPending, - } - - q.notificationMessages = append(q.notificationMessages, nm) - - return err -} - -func (q *FakeQuerier) FavoriteWorkspace(_ context.Context, arg uuid.UUID) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i := 0; i < len(q.workspaces); i++ { - if q.workspaces[i].ID != arg { - continue - } - q.workspaces[i].Favorite = true - return nil - } - return nil -} - -func (q *FakeQuerier) FetchMemoryResourceMonitorsByAgentID(_ context.Context, agentID uuid.UUID) (database.WorkspaceAgentMemoryResourceMonitor, error) { - for _, monitor := range q.workspaceAgentMemoryResourceMonitors { - if monitor.AgentID == agentID { - return monitor, nil - } - } - - return database.WorkspaceAgentMemoryResourceMonitor{}, sql.ErrNoRows -} - -func (q *FakeQuerier) FetchMemoryResourceMonitorsUpdatedAfter(_ context.Context, updatedAt time.Time) ([]database.WorkspaceAgentMemoryResourceMonitor, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - monitors := []database.WorkspaceAgentMemoryResourceMonitor{} - for _, monitor := range q.workspaceAgentMemoryResourceMonitors { - if monitor.UpdatedAt.After(updatedAt) { - monitors = append(monitors, monitor) - } - } - return monitors, nil -} - -func (q *FakeQuerier) FetchNewMessageMetadata(_ context.Context, arg database.FetchNewMessageMetadataParams) (database.FetchNewMessageMetadataRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.FetchNewMessageMetadataRow{}, err - } - - user, err := q.getUserByIDNoLock(arg.UserID) - if err != nil { - return database.FetchNewMessageMetadataRow{}, xerrors.Errorf("fetch user: %w", err) - } - - // Mimic COALESCE in query - userName := user.Name - if userName == "" { - userName = user.Username - } - - actions, err := json.Marshal([]types.TemplateAction{{URL: "http://xyz.com", Label: "XYZ"}}) - if err != nil { - return database.FetchNewMessageMetadataRow{}, err - } - - return database.FetchNewMessageMetadataRow{ - UserEmail: user.Email, - UserName: userName, - UserUsername: user.Username, - NotificationName: "Some notification", - Actions: actions, - UserID: arg.UserID, - }, nil -} - -func (q *FakeQuerier) FetchVolumesResourceMonitorsByAgentID(_ context.Context, agentID uuid.UUID) ([]database.WorkspaceAgentVolumeResourceMonitor, error) { - monitors := []database.WorkspaceAgentVolumeResourceMonitor{} - - for _, monitor := range q.workspaceAgentVolumeResourceMonitors { - if monitor.AgentID == agentID { - monitors = append(monitors, monitor) - } - } - - return monitors, nil -} - -func (q *FakeQuerier) FetchVolumesResourceMonitorsUpdatedAfter(_ context.Context, updatedAt time.Time) ([]database.WorkspaceAgentVolumeResourceMonitor, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - monitors := []database.WorkspaceAgentVolumeResourceMonitor{} - for _, monitor := range q.workspaceAgentVolumeResourceMonitors { - if monitor.UpdatedAt.After(updatedAt) { - monitors = append(monitors, monitor) - } - } - return monitors, nil -} - -func (q *FakeQuerier) GetAPIKeyByID(_ context.Context, id string) (database.APIKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, apiKey := range q.apiKeys { - if apiKey.ID == id { - return apiKey, nil - } - } - return database.APIKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetAPIKeyByName(_ context.Context, params database.GetAPIKeyByNameParams) (database.APIKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if params.TokenName == "" { - return database.APIKey{}, sql.ErrNoRows - } - for _, apiKey := range q.apiKeys { - if params.UserID == apiKey.UserID && params.TokenName == apiKey.TokenName { - return apiKey, nil - } - } - return database.APIKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetAPIKeysByLoginType(_ context.Context, t database.LoginType) ([]database.APIKey, error) { - if err := validateDatabaseType(t); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - apiKeys := make([]database.APIKey, 0) - for _, key := range q.apiKeys { - if key.LoginType == t { - apiKeys = append(apiKeys, key) - } - } - return apiKeys, nil -} - -func (q *FakeQuerier) GetAPIKeysByUserID(_ context.Context, params database.GetAPIKeysByUserIDParams) ([]database.APIKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - apiKeys := make([]database.APIKey, 0) - for _, key := range q.apiKeys { - if key.UserID == params.UserID && key.LoginType == params.LoginType { - apiKeys = append(apiKeys, key) - } - } - return apiKeys, nil -} - -func (q *FakeQuerier) GetAPIKeysLastUsedAfter(_ context.Context, after time.Time) ([]database.APIKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - apiKeys := make([]database.APIKey, 0) - for _, key := range q.apiKeys { - if key.LastUsed.After(after) { - apiKeys = append(apiKeys, key) - } - } - return apiKeys, nil -} - -func (q *FakeQuerier) GetActivePresetPrebuildSchedules(ctx context.Context) ([]database.TemplateVersionPresetPrebuildSchedule, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var activeSchedules []database.TemplateVersionPresetPrebuildSchedule - - // Create a map of active template version IDs for quick lookup - activeTemplateVersions := make(map[uuid.UUID]bool) - for _, template := range q.templates { - if !template.Deleted && template.Deprecated == "" { - activeTemplateVersions[template.ActiveVersionID] = true - } - } - - // Create a map of presets for quick lookup - presetMap := make(map[uuid.UUID]database.TemplateVersionPreset) - for _, preset := range q.presets { - presetMap[preset.ID] = preset - } - - // Filter preset prebuild schedules to only include those for active template versions - for _, schedule := range q.presetPrebuildSchedules { - // Look up the preset using the map - preset, exists := presetMap[schedule.PresetID] - if !exists { - continue - } - - // Check if preset's template version is active - if !activeTemplateVersions[preset.TemplateVersionID] { - continue - } - - activeSchedules = append(activeSchedules, schedule) - } - - return activeSchedules, nil -} - -// nolint:revive // It's not a control flag, it's a filter. -func (q *FakeQuerier) GetActiveUserCount(_ context.Context, includeSystem bool) (int64, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - active := int64(0) - for _, u := range q.users { - if !includeSystem && u.IsSystem { - continue - } - - if u.Status == database.UserStatusActive && !u.Deleted { - active++ - } - } - return active, nil -} - -func (q *FakeQuerier) GetActiveWorkspaceBuildsByTemplateID(ctx context.Context, templateID uuid.UUID) ([]database.WorkspaceBuild, error) { - workspaceIDs := func() []uuid.UUID { - q.mutex.RLock() - defer q.mutex.RUnlock() - - ids := []uuid.UUID{} - for _, workspace := range q.workspaces { - if workspace.TemplateID == templateID { - ids = append(ids, workspace.ID) - } - } - return ids - }() - - builds, err := q.GetLatestWorkspaceBuildsByWorkspaceIDs(ctx, workspaceIDs) - if err != nil { - return nil, err - } - - filteredBuilds := []database.WorkspaceBuild{} - for _, build := range builds { - if build.Transition == database.WorkspaceTransitionStart { - filteredBuilds = append(filteredBuilds, build) - } - } - return filteredBuilds, nil -} - -func (*FakeQuerier) GetAllTailnetAgents(_ context.Context) ([]database.TailnetAgent, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetAllTailnetCoordinators(context.Context) ([]database.TailnetCoordinator, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetAllTailnetPeers(context.Context) ([]database.TailnetPeer, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetAllTailnetTunnels(context.Context) ([]database.TailnetTunnel, error) { - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) GetAnnouncementBanners(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.announcementBanners == nil { - return "", sql.ErrNoRows - } - - return string(q.announcementBanners), nil -} - -func (q *FakeQuerier) GetAppSecurityKey(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.appSecurityKey, nil -} - -func (q *FakeQuerier) GetApplicationName(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.applicationName == "" { - return "", sql.ErrNoRows - } - - return q.applicationName, nil -} - -func (q *FakeQuerier) GetAuditLogsOffset(ctx context.Context, arg database.GetAuditLogsOffsetParams) ([]database.GetAuditLogsOffsetRow, error) { - return q.GetAuthorizedAuditLogsOffset(ctx, arg, nil) -} - -func (q *FakeQuerier) GetAuthorizationUserRoles(_ context.Context, userID uuid.UUID) (database.GetAuthorizationUserRolesRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var user *database.User - roles := make([]string, 0) - for _, u := range q.users { - if u.ID == userID { - roles = append(roles, u.RBACRoles...) - roles = append(roles, "member") - user = &u - break - } - } - - for _, mem := range q.organizationMembers { - if mem.UserID == userID { - for _, orgRole := range mem.Roles { - roles = append(roles, orgRole+":"+mem.OrganizationID.String()) - } - roles = append(roles, "organization-member:"+mem.OrganizationID.String()) - } - } - - var groups []string - for _, member := range q.groupMembers { - if member.UserID == userID { - groups = append(groups, member.GroupID.String()) - } - } - - if user == nil { - return database.GetAuthorizationUserRolesRow{}, sql.ErrNoRows - } - - return database.GetAuthorizationUserRolesRow{ - ID: userID, - Username: user.Username, - Status: user.Status, - Roles: roles, - Groups: groups, - }, nil -} - -func (q *FakeQuerier) GetCoordinatorResumeTokenSigningKey(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - if q.coordinatorResumeTokenSigningKey == "" { - return "", sql.ErrNoRows - } - return q.coordinatorResumeTokenSigningKey, nil -} - -func (q *FakeQuerier) GetCryptoKeyByFeatureAndSequence(_ context.Context, arg database.GetCryptoKeyByFeatureAndSequenceParams) (database.CryptoKey, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.CryptoKey{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, key := range q.cryptoKeys { - if key.Feature == arg.Feature && key.Sequence == arg.Sequence { - // Keys with NULL secrets are considered deleted. - if key.Secret.Valid { - return key, nil - } - return database.CryptoKey{}, sql.ErrNoRows - } - } - - return database.CryptoKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetCryptoKeys(_ context.Context) ([]database.CryptoKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - keys := make([]database.CryptoKey, 0) - for _, key := range q.cryptoKeys { - if key.Secret.Valid { - keys = append(keys, key) - } - } - return keys, nil -} - -func (q *FakeQuerier) GetCryptoKeysByFeature(_ context.Context, feature database.CryptoKeyFeature) ([]database.CryptoKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - keys := make([]database.CryptoKey, 0) - for _, key := range q.cryptoKeys { - if key.Feature == feature && key.Secret.Valid { - keys = append(keys, key) - } - } - // We want to return the highest sequence number first. - slices.SortFunc(keys, func(i, j database.CryptoKey) int { - return int(j.Sequence - i.Sequence) - }) - return keys, nil -} - -func (q *FakeQuerier) GetDBCryptKeys(_ context.Context) ([]database.DBCryptKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - ks := make([]database.DBCryptKey, 0) - ks = append(ks, q.dbcryptKeys...) - return ks, nil -} - -func (q *FakeQuerier) GetDERPMeshKey(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.derpMeshKey == "" { - return "", sql.ErrNoRows - } - return q.derpMeshKey, nil -} - -func (q *FakeQuerier) GetDefaultOrganization(_ context.Context) (database.Organization, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, org := range q.organizations { - if org.IsDefault { - return org, nil - } - } - return database.Organization{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetDefaultProxyConfig(_ context.Context) (database.GetDefaultProxyConfigRow, error) { - return database.GetDefaultProxyConfigRow{ - DisplayName: q.defaultProxyDisplayName, - IconUrl: q.defaultProxyIconURL, - }, nil -} - -func (q *FakeQuerier) GetDeploymentDAUs(_ context.Context, tzOffset int32) ([]database.GetDeploymentDAUsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - seens := make(map[time.Time]map[uuid.UUID]struct{}) - - for _, as := range q.workspaceAgentStats { - if as.ConnectionCount == 0 { - continue - } - date := as.CreatedAt.UTC().Add(time.Duration(tzOffset) * -1 * time.Hour).Truncate(time.Hour * 24) - - dateEntry := seens[date] - if dateEntry == nil { - dateEntry = make(map[uuid.UUID]struct{}) - } - dateEntry[as.UserID] = struct{}{} - seens[date] = dateEntry - } - - seenKeys := maps.Keys(seens) - sort.Slice(seenKeys, func(i, j int) bool { - return seenKeys[i].Before(seenKeys[j]) - }) - - var rs []database.GetDeploymentDAUsRow - for _, key := range seenKeys { - ids := seens[key] - for id := range ids { - rs = append(rs, database.GetDeploymentDAUsRow{ - Date: key, - UserID: id, - }) - } - } - - return rs, nil -} - -func (q *FakeQuerier) GetDeploymentID(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.deploymentID, nil -} - -func (q *FakeQuerier) GetDeploymentWorkspaceAgentStats(_ context.Context, createdAfter time.Time) (database.GetDeploymentWorkspaceAgentStatsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - agentStatsCreatedAfter := make([]database.WorkspaceAgentStat, 0) - for _, agentStat := range q.workspaceAgentStats { - if agentStat.CreatedAt.After(createdAfter) { - agentStatsCreatedAfter = append(agentStatsCreatedAfter, agentStat) - } - } - - latestAgentStats := map[uuid.UUID]database.WorkspaceAgentStat{} - for _, agentStat := range q.workspaceAgentStats { - if agentStat.CreatedAt.After(createdAfter) { - latestAgentStats[agentStat.AgentID] = agentStat - } - } - - stat := database.GetDeploymentWorkspaceAgentStatsRow{} - for _, agentStat := range latestAgentStats { - stat.SessionCountVSCode += agentStat.SessionCountVSCode - stat.SessionCountJetBrains += agentStat.SessionCountJetBrains - stat.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - stat.SessionCountSSH += agentStat.SessionCountSSH - } - - latencies := make([]float64, 0) - for _, agentStat := range agentStatsCreatedAfter { - if agentStat.ConnectionMedianLatencyMS <= 0 { - continue - } - stat.WorkspaceRxBytes += agentStat.RxBytes - stat.WorkspaceTxBytes += agentStat.TxBytes - latencies = append(latencies, agentStat.ConnectionMedianLatencyMS) - } - - stat.WorkspaceConnectionLatency50 = tryPercentileCont(latencies, 50) - stat.WorkspaceConnectionLatency95 = tryPercentileCont(latencies, 95) - - return stat, nil -} - -func (q *FakeQuerier) GetDeploymentWorkspaceAgentUsageStats(_ context.Context, createdAt time.Time) (database.GetDeploymentWorkspaceAgentUsageStatsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - stat := database.GetDeploymentWorkspaceAgentUsageStatsRow{} - sessions := make(map[uuid.UUID]database.WorkspaceAgentStat) - agentStatsCreatedAfter := make([]database.WorkspaceAgentStat, 0) - for _, agentStat := range q.workspaceAgentStats { - // WHERE workspace_agent_stats.created_at > $1 - if agentStat.CreatedAt.After(createdAt) { - agentStatsCreatedAfter = append(agentStatsCreatedAfter, agentStat) - } - // WHERE - // created_at > $1 - // AND created_at < date_trunc('minute', now()) -- Exclude current partial minute - // AND usage = true - if agentStat.Usage && - (agentStat.CreatedAt.After(createdAt) || agentStat.CreatedAt.Equal(createdAt)) && - agentStat.CreatedAt.Before(time.Now().Truncate(time.Minute)) { - val, ok := sessions[agentStat.AgentID] - if !ok { - sessions[agentStat.AgentID] = agentStat - } else if agentStat.CreatedAt.After(val.CreatedAt) { - sessions[agentStat.AgentID] = agentStat - } else if agentStat.CreatedAt.Truncate(time.Minute).Equal(val.CreatedAt.Truncate(time.Minute)) { - val.SessionCountVSCode += agentStat.SessionCountVSCode - val.SessionCountJetBrains += agentStat.SessionCountJetBrains - val.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - val.SessionCountSSH += agentStat.SessionCountSSH - sessions[agentStat.AgentID] = val - } - } - } - - latencies := make([]float64, 0) - for _, agentStat := range agentStatsCreatedAfter { - if agentStat.ConnectionMedianLatencyMS <= 0 { - continue - } - stat.WorkspaceRxBytes += agentStat.RxBytes - stat.WorkspaceTxBytes += agentStat.TxBytes - latencies = append(latencies, agentStat.ConnectionMedianLatencyMS) - } - stat.WorkspaceConnectionLatency50 = tryPercentileCont(latencies, 50) - stat.WorkspaceConnectionLatency95 = tryPercentileCont(latencies, 95) - - for _, agentStat := range sessions { - stat.SessionCountVSCode += agentStat.SessionCountVSCode - stat.SessionCountJetBrains += agentStat.SessionCountJetBrains - stat.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - stat.SessionCountSSH += agentStat.SessionCountSSH - } - - return stat, nil -} - -func (q *FakeQuerier) GetDeploymentWorkspaceStats(ctx context.Context) (database.GetDeploymentWorkspaceStatsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - stat := database.GetDeploymentWorkspaceStatsRow{} - for _, workspace := range q.workspaces { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return stat, err - } - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err != nil { - return stat, err - } - if !job.StartedAt.Valid { - stat.PendingWorkspaces++ - continue - } - if job.StartedAt.Valid && - !job.CanceledAt.Valid && - time.Since(job.UpdatedAt) <= 30*time.Second && - !job.CompletedAt.Valid { - stat.BuildingWorkspaces++ - continue - } - if job.CompletedAt.Valid && - !job.CanceledAt.Valid && - !job.Error.Valid { - if build.Transition == database.WorkspaceTransitionStart { - stat.RunningWorkspaces++ - } - if build.Transition == database.WorkspaceTransitionStop { - stat.StoppedWorkspaces++ - } - continue - } - if job.CanceledAt.Valid || job.Error.Valid { - stat.FailedWorkspaces++ - continue - } - } - return stat, nil -} - -func (q *FakeQuerier) GetEligibleProvisionerDaemonsByProvisionerJobIDs(_ context.Context, provisionerJobIds []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - results := make([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, 0) - seen := make(map[string]struct{}) // Track unique combinations - - for _, jobID := range provisionerJobIds { - var job database.ProvisionerJob - found := false - for _, j := range q.provisionerJobs { - if j.ID == jobID { - job = j - found = true - break - } - } - if !found { - continue - } - - for _, daemon := range q.provisionerDaemons { - if daemon.OrganizationID != job.OrganizationID { - continue - } - - if !tagsSubset(job.Tags, daemon.Tags) { - continue - } - - provisionerMatches := false - for _, p := range daemon.Provisioners { - if p == job.Provisioner { - provisionerMatches = true - break - } - } - if !provisionerMatches { - continue - } - - key := jobID.String() + "-" + daemon.ID.String() - if _, exists := seen[key]; exists { - continue - } - seen[key] = struct{}{} - - results = append(results, database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{ - JobID: jobID, - ProvisionerDaemon: daemon, - }) - } - } - - return results, nil -} - -func (q *FakeQuerier) GetExternalAuthLink(_ context.Context, arg database.GetExternalAuthLinkParams) (database.ExternalAuthLink, error) { - if err := validateDatabaseType(arg); err != nil { - return database.ExternalAuthLink{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - for _, gitAuthLink := range q.externalAuthLinks { - if arg.UserID != gitAuthLink.UserID { - continue - } - if arg.ProviderID != gitAuthLink.ProviderID { - continue - } - return gitAuthLink, nil - } - return database.ExternalAuthLink{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetExternalAuthLinksByUserID(_ context.Context, userID uuid.UUID) ([]database.ExternalAuthLink, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - gals := make([]database.ExternalAuthLink, 0) - for _, gal := range q.externalAuthLinks { - if gal.UserID == userID { - gals = append(gals, gal) - } - } - return gals, nil -} - -func (q *FakeQuerier) GetFailedWorkspaceBuildsByTemplateID(ctx context.Context, arg database.GetFailedWorkspaceBuildsByTemplateIDParams) ([]database.GetFailedWorkspaceBuildsByTemplateIDRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaceBuildStats := []database.GetFailedWorkspaceBuildsByTemplateIDRow{} - for _, wb := range q.workspaceBuilds { - job, err := q.getProvisionerJobByIDNoLock(ctx, wb.JobID) - if err != nil { - return nil, xerrors.Errorf("get provisioner job by ID: %w", err) - } - - if job.JobStatus != database.ProvisionerJobStatusFailed { - continue - } - - if !job.CompletedAt.Valid { - continue - } - - if wb.CreatedAt.Before(arg.Since) { - continue - } - - w, err := q.getWorkspaceByIDNoLock(ctx, wb.WorkspaceID) - if err != nil { - return nil, xerrors.Errorf("get workspace by ID: %w", err) - } - - t, err := q.getTemplateByIDNoLock(ctx, w.TemplateID) - if err != nil { - return nil, xerrors.Errorf("get template by ID: %w", err) - } - - if t.ID != arg.TemplateID { - continue - } - - workspaceOwner, err := q.getUserByIDNoLock(w.OwnerID) - if err != nil { - return nil, xerrors.Errorf("get user by ID: %w", err) - } - - templateVersion, err := q.getTemplateVersionByIDNoLock(ctx, wb.TemplateVersionID) - if err != nil { - return nil, xerrors.Errorf("get template version by ID: %w", err) - } - - workspaceBuildStats = append(workspaceBuildStats, database.GetFailedWorkspaceBuildsByTemplateIDRow{ - WorkspaceID: w.ID, - WorkspaceName: w.Name, - WorkspaceOwnerUsername: workspaceOwner.Username, - TemplateVersionName: templateVersion.Name, - WorkspaceBuildNumber: wb.BuildNumber, - }) - } - - sort.Slice(workspaceBuildStats, func(i, j int) bool { - if workspaceBuildStats[i].TemplateVersionName != workspaceBuildStats[j].TemplateVersionName { - return workspaceBuildStats[i].TemplateVersionName < workspaceBuildStats[j].TemplateVersionName - } - return workspaceBuildStats[i].WorkspaceBuildNumber > workspaceBuildStats[j].WorkspaceBuildNumber - }) - return workspaceBuildStats, nil -} - -func (q *FakeQuerier) GetFileByHashAndCreator(_ context.Context, arg database.GetFileByHashAndCreatorParams) (database.File, error) { - if err := validateDatabaseType(arg); err != nil { - return database.File{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, file := range q.files { - if file.Hash == arg.Hash && file.CreatedBy == arg.CreatedBy { - return file, nil - } - } - return database.File{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetFileByID(_ context.Context, id uuid.UUID) (database.File, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, file := range q.files { - if file.ID == id { - return file, nil - } - } - return database.File{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetFileIDByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) (uuid.UUID, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, v := range q.templateVersions { - if v.ID == templateVersionID { - jobID := v.JobID - for _, j := range q.provisionerJobs { - if j.ID == jobID { - if j.StorageMethod == database.ProvisionerStorageMethodFile { - return j.FileID, nil - } - // We found the right job id but it wasn't a proper match. - break - } - } - // We found the right template version but it wasn't a proper match. - break - } - } - - return uuid.Nil, sql.ErrNoRows -} - -func (q *FakeQuerier) GetFileTemplates(_ context.Context, id uuid.UUID) ([]database.GetFileTemplatesRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - rows := make([]database.GetFileTemplatesRow, 0) - var file database.File - for _, f := range q.files { - if f.ID == id { - file = f - break - } - } - if file.Hash == "" { - return rows, nil - } - - for _, job := range q.provisionerJobs { - if job.FileID == id { - for _, version := range q.templateVersions { - if version.JobID == job.ID { - for _, template := range q.templates { - if template.ID == version.TemplateID.UUID { - rows = append(rows, database.GetFileTemplatesRow{ - FileID: file.ID, - FileCreatedBy: file.CreatedBy, - TemplateID: template.ID, - TemplateOrganizationID: template.OrganizationID, - TemplateCreatedBy: template.CreatedBy, - UserACL: template.UserACL, - GroupACL: template.GroupACL, - }) - } - } - } - } - } - } - - return rows, nil -} - -func (q *FakeQuerier) GetFilteredInboxNotificationsByUserID(_ context.Context, arg database.GetFilteredInboxNotificationsByUserIDParams) ([]database.InboxNotification, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - notifications := make([]database.InboxNotification, 0) - // TODO : after using go version >= 1.23 , we can change this one to https://pkg.go.dev/slices#Backward - for idx := len(q.inboxNotifications) - 1; idx >= 0; idx-- { - notification := q.inboxNotifications[idx] - - if notification.UserID == arg.UserID { - if !arg.CreatedAtOpt.IsZero() && !notification.CreatedAt.Before(arg.CreatedAtOpt) { - continue - } - - templateFound := false - for _, template := range arg.Templates { - if notification.TemplateID == template { - templateFound = true - } - } - - if len(arg.Templates) > 0 && !templateFound { - continue - } - - targetsFound := true - for _, target := range arg.Targets { - targetFound := false - for _, insertedTarget := range notification.Targets { - if insertedTarget == target { - targetFound = true - break - } - } - - if !targetFound { - targetsFound = false - break - } - } - - if !targetsFound { - continue - } - - if (arg.LimitOpt == 0 && len(notifications) == 25) || - (arg.LimitOpt != 0 && len(notifications) == int(arg.LimitOpt)) { - break - } - - notifications = append(notifications, notification) - } - } - - return notifications, nil -} - -func (q *FakeQuerier) GetGitSSHKey(_ context.Context, userID uuid.UUID) (database.GitSSHKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, key := range q.gitSSHKey { - if key.UserID == userID { - return key, nil - } - } - return database.GitSSHKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetGroupByID(ctx context.Context, id uuid.UUID) (database.Group, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getGroupByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetGroupByOrgAndName(_ context.Context, arg database.GetGroupByOrgAndNameParams) (database.Group, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Group{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, group := range q.groups { - if group.OrganizationID == arg.OrganizationID && - group.Name == arg.Name { - return group, nil - } - } - - return database.Group{}, sql.ErrNoRows -} - -//nolint:revive // It's not a control flag, its a filter -func (q *FakeQuerier) GetGroupMembers(ctx context.Context, includeSystem bool) ([]database.GroupMember, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - members := make([]database.GroupMemberTable, 0, len(q.groupMembers)) - members = append(members, q.groupMembers...) - for _, org := range q.organizations { - for _, user := range q.users { - if !includeSystem && user.IsSystem { - continue - } - members = append(members, database.GroupMemberTable{ - UserID: user.ID, - GroupID: org.ID, - }) - } - } - - var groupMembers []database.GroupMember - for _, member := range members { - groupMember, err := q.getGroupMemberNoLock(ctx, member.UserID, member.GroupID) - if errors.Is(err, errUserDeleted) { - continue - } - if err != nil { - return nil, err - } - groupMembers = append(groupMembers, groupMember) - } - - return groupMembers, nil -} - -func (q *FakeQuerier) GetGroupMembersByGroupID(ctx context.Context, arg database.GetGroupMembersByGroupIDParams) ([]database.GroupMember, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.isEveryoneGroup(arg.GroupID) { - return q.getEveryoneGroupMembersNoLock(ctx, arg.GroupID), nil - } - - var groupMembers []database.GroupMember - for _, member := range q.groupMembers { - if member.GroupID == arg.GroupID { - groupMember, err := q.getGroupMemberNoLock(ctx, member.UserID, member.GroupID) - if errors.Is(err, errUserDeleted) { - continue - } - if err != nil { - return nil, err - } - groupMembers = append(groupMembers, groupMember) - } - } - - return groupMembers, nil -} - -func (q *FakeQuerier) GetGroupMembersCountByGroupID(ctx context.Context, arg database.GetGroupMembersCountByGroupIDParams) (int64, error) { - users, err := q.GetGroupMembersByGroupID(ctx, database.GetGroupMembersByGroupIDParams(arg)) - if err != nil { - return 0, err - } - return int64(len(users)), nil -} - -func (q *FakeQuerier) GetGroups(_ context.Context, arg database.GetGroupsParams) ([]database.GetGroupsRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - userGroupIDs := make(map[uuid.UUID]struct{}) - if arg.HasMemberID != uuid.Nil { - for _, member := range q.groupMembers { - if member.UserID == arg.HasMemberID { - userGroupIDs[member.GroupID] = struct{}{} - } - } - - // Handle the everyone group - for _, orgMember := range q.organizationMembers { - if orgMember.UserID == arg.HasMemberID { - userGroupIDs[orgMember.OrganizationID] = struct{}{} - } - } - } - - orgDetailsCache := make(map[uuid.UUID]struct{ name, displayName string }) - filtered := make([]database.GetGroupsRow, 0) - for _, group := range q.groups { - if len(arg.GroupIds) > 0 { - if !slices.Contains(arg.GroupIds, group.ID) { - continue - } - } - - if arg.OrganizationID != uuid.Nil && group.OrganizationID != arg.OrganizationID { - continue - } - - _, ok := userGroupIDs[group.ID] - if arg.HasMemberID != uuid.Nil && !ok { - continue - } - - if len(arg.GroupNames) > 0 && !slices.Contains(arg.GroupNames, group.Name) { - continue - } - - orgDetails, ok := orgDetailsCache[group.ID] - if !ok { - for _, org := range q.organizations { - if group.OrganizationID == org.ID { - orgDetails = struct{ name, displayName string }{ - name: org.Name, displayName: org.DisplayName, - } - break - } - } - orgDetailsCache[group.ID] = orgDetails - } - - filtered = append(filtered, database.GetGroupsRow{ - Group: group, - OrganizationName: orgDetails.name, - OrganizationDisplayName: orgDetails.displayName, - }) - } - - return filtered, nil -} - -func (q *FakeQuerier) GetHealthSettings(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.healthSettings == nil { - return "{}", nil - } - - return string(q.healthSettings), nil -} - -func (q *FakeQuerier) GetInboxNotificationByID(_ context.Context, id uuid.UUID) (database.InboxNotification, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, notification := range q.inboxNotifications { - if notification.ID == id { - return notification, nil - } - } - - return database.InboxNotification{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetInboxNotificationsByUserID(_ context.Context, params database.GetInboxNotificationsByUserIDParams) ([]database.InboxNotification, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - notifications := make([]database.InboxNotification, 0) - for _, notification := range q.inboxNotifications { - if notification.UserID == params.UserID { - notifications = append(notifications, notification) - } - } - - return notifications, nil -} - -func (q *FakeQuerier) GetLastUpdateCheck(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.lastUpdateCheck == nil { - return "", sql.ErrNoRows - } - return string(q.lastUpdateCheck), nil -} - -func (q *FakeQuerier) GetLatestCryptoKeyByFeature(_ context.Context, feature database.CryptoKeyFeature) (database.CryptoKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var latestKey database.CryptoKey - for _, key := range q.cryptoKeys { - if key.Feature == feature && latestKey.Sequence < key.Sequence { - latestKey = key - } - } - if latestKey.StartsAt.IsZero() { - return database.CryptoKey{}, sql.ErrNoRows - } - return latestKey, nil -} - -func (q *FakeQuerier) GetLatestWorkspaceAppStatusesByWorkspaceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceAppStatus, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - // Map to track latest status per workspace ID - latestByWorkspace := make(map[uuid.UUID]database.WorkspaceAppStatus) - - // Find latest status for each workspace ID - for _, appStatus := range q.workspaceAppStatuses { - if !slices.Contains(ids, appStatus.WorkspaceID) { - continue - } - - current, exists := latestByWorkspace[appStatus.WorkspaceID] - if !exists || appStatus.CreatedAt.After(current.CreatedAt) { - latestByWorkspace[appStatus.WorkspaceID] = appStatus - } - } - - // Convert map to slice - appStatuses := make([]database.WorkspaceAppStatus, 0, len(latestByWorkspace)) - for _, status := range latestByWorkspace { - appStatuses = append(appStatuses, status) - } - - return appStatuses, nil -} - -func (q *FakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspaceID) -} - -func (q *FakeQuerier) GetLatestWorkspaceBuilds(_ context.Context) ([]database.WorkspaceBuild, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - builds := make(map[uuid.UUID]database.WorkspaceBuild) - buildNumbers := make(map[uuid.UUID]int32) - for _, workspaceBuild := range q.workspaceBuilds { - id := workspaceBuild.WorkspaceID - if workspaceBuild.BuildNumber > buildNumbers[id] { - builds[id] = q.workspaceBuildWithUserNoLock(workspaceBuild) - buildNumbers[id] = workspaceBuild.BuildNumber - } - } - var returnBuilds []database.WorkspaceBuild - for i, n := range buildNumbers { - if n > 0 { - b := builds[i] - returnBuilds = append(returnBuilds, b) - } - } - if len(returnBuilds) == 0 { - return nil, sql.ErrNoRows - } - return returnBuilds, nil -} - -func (q *FakeQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceBuild, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - builds := make(map[uuid.UUID]database.WorkspaceBuild) - buildNumbers := make(map[uuid.UUID]int32) - for _, workspaceBuild := range q.workspaceBuilds { - for _, id := range ids { - if id == workspaceBuild.WorkspaceID && workspaceBuild.BuildNumber > buildNumbers[id] { - builds[id] = q.workspaceBuildWithUserNoLock(workspaceBuild) - buildNumbers[id] = workspaceBuild.BuildNumber - } - } - } - var returnBuilds []database.WorkspaceBuild - for i, n := range buildNumbers { - if n > 0 { - b := builds[i] - returnBuilds = append(returnBuilds, b) - } - } - if len(returnBuilds) == 0 { - return nil, sql.ErrNoRows - } - return returnBuilds, nil -} - -func (q *FakeQuerier) GetLicenseByID(_ context.Context, id int32) (database.License, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, license := range q.licenses { - if license.ID == id { - return license, nil - } - } - return database.License{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetLicenses(_ context.Context) ([]database.License, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - results := append([]database.License{}, q.licenses...) - sort.Slice(results, func(i, j int) bool { return results[i].ID < results[j].ID }) - return results, nil -} - -func (q *FakeQuerier) GetLogoURL(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.logoURL == "" { - return "", sql.ErrNoRows - } - - return q.logoURL, nil -} - -func (q *FakeQuerier) GetNotificationMessagesByStatus(_ context.Context, arg database.GetNotificationMessagesByStatusParams) ([]database.NotificationMessage, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - var out []database.NotificationMessage - for _, m := range q.notificationMessages { - if len(out) > int(arg.Limit) { - return out, nil - } - - if m.Status == arg.Status { - out = append(out, m) - } - } - - return out, nil -} - -func (q *FakeQuerier) GetNotificationReportGeneratorLogByTemplate(_ context.Context, templateID uuid.UUID) (database.NotificationReportGeneratorLog, error) { - err := validateDatabaseType(templateID) - if err != nil { - return database.NotificationReportGeneratorLog{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, record := range q.notificationReportGeneratorLogs { - if record.NotificationTemplateID == templateID { - return record, nil - } - } - return database.NotificationReportGeneratorLog{}, sql.ErrNoRows -} - -func (*FakeQuerier) GetNotificationTemplateByID(_ context.Context, _ uuid.UUID) (database.NotificationTemplate, error) { - // Not implementing this function because it relies on state in the database which is created with migrations. - // We could consider using code-generation to align the database state and dbmem, but it's not worth it right now. - return database.NotificationTemplate{}, ErrUnimplemented -} - -func (*FakeQuerier) GetNotificationTemplatesByKind(_ context.Context, _ database.NotificationTemplateKind) ([]database.NotificationTemplate, error) { - // Not implementing this function because it relies on state in the database which is created with migrations. - // We could consider using code-generation to align the database state and dbmem, but it's not worth it right now. - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) GetNotificationsSettings(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.notificationsSettings == nil { - return "{}", nil - } - - return string(q.notificationsSettings), nil -} - -func (q *FakeQuerier) GetOAuth2GithubDefaultEligible(_ context.Context) (bool, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.oauth2GithubDefaultEligible == nil { - return false, sql.ErrNoRows - } - return *q.oauth2GithubDefaultEligible, nil -} - -func (q *FakeQuerier) GetOAuth2ProviderAppByClientID(ctx context.Context, id uuid.UUID) (database.OAuth2ProviderApp, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, app := range q.oauth2ProviderApps { - if app.ID == id { - return app, nil - } - } - return database.OAuth2ProviderApp{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppByID(_ context.Context, id uuid.UUID) (database.OAuth2ProviderApp, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, app := range q.oauth2ProviderApps { - if app.ID == id { - return app, nil - } - } - return database.OAuth2ProviderApp{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppByRegistrationToken(ctx context.Context, registrationAccessToken sql.NullString) (database.OAuth2ProviderApp, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, app := range q.data.oauth2ProviderApps { - if app.RegistrationAccessToken.Valid && registrationAccessToken.Valid && - app.RegistrationAccessToken.String == registrationAccessToken.String { - return app, nil - } - } - return database.OAuth2ProviderApp{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppCodeByID(_ context.Context, id uuid.UUID) (database.OAuth2ProviderAppCode, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, code := range q.oauth2ProviderAppCodes { - if code.ID == id { - return code, nil - } - } - return database.OAuth2ProviderAppCode{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppCodeByPrefix(_ context.Context, secretPrefix []byte) (database.OAuth2ProviderAppCode, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, code := range q.oauth2ProviderAppCodes { - if bytes.Equal(code.SecretPrefix, secretPrefix) { - return code, nil - } - } - return database.OAuth2ProviderAppCode{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppSecretByID(_ context.Context, id uuid.UUID) (database.OAuth2ProviderAppSecret, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, secret := range q.oauth2ProviderAppSecrets { - if secret.ID == id { - return secret, nil - } - } - return database.OAuth2ProviderAppSecret{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppSecretByPrefix(_ context.Context, secretPrefix []byte) (database.OAuth2ProviderAppSecret, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, secret := range q.oauth2ProviderAppSecrets { - if bytes.Equal(secret.SecretPrefix, secretPrefix) { - return secret, nil - } - } - return database.OAuth2ProviderAppSecret{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppSecretsByAppID(_ context.Context, appID uuid.UUID) ([]database.OAuth2ProviderAppSecret, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, app := range q.oauth2ProviderApps { - if app.ID == appID { - secrets := []database.OAuth2ProviderAppSecret{} - for _, secret := range q.oauth2ProviderAppSecrets { - if secret.AppID == appID { - secrets = append(secrets, secret) - } - } - - slices.SortFunc(secrets, func(a, b database.OAuth2ProviderAppSecret) int { - if a.CreatedAt.Before(b.CreatedAt) { - return -1 - } else if a.CreatedAt.Equal(b.CreatedAt) { - return 0 - } - return 1 - }) - return secrets, nil - } - } - - return []database.OAuth2ProviderAppSecret{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppTokenByAPIKeyID(_ context.Context, apiKeyID string) (database.OAuth2ProviderAppToken, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, token := range q.oauth2ProviderAppTokens { - if token.APIKeyID == apiKeyID { - return token, nil - } - } - - return database.OAuth2ProviderAppToken{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderAppTokenByPrefix(_ context.Context, hashPrefix []byte) (database.OAuth2ProviderAppToken, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, token := range q.oauth2ProviderAppTokens { - if bytes.Equal(token.HashPrefix, hashPrefix) { - return token, nil - } - } - return database.OAuth2ProviderAppToken{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOAuth2ProviderApps(_ context.Context) ([]database.OAuth2ProviderApp, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - slices.SortFunc(q.oauth2ProviderApps, func(a, b database.OAuth2ProviderApp) int { - return slice.Ascending(a.Name, b.Name) - }) - return q.oauth2ProviderApps, nil -} - -func (q *FakeQuerier) GetOAuth2ProviderAppsByUserID(_ context.Context, userID uuid.UUID) ([]database.GetOAuth2ProviderAppsByUserIDRow, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - rows := []database.GetOAuth2ProviderAppsByUserIDRow{} - for _, app := range q.oauth2ProviderApps { - tokens := []database.OAuth2ProviderAppToken{} - for _, secret := range q.oauth2ProviderAppSecrets { - if secret.AppID == app.ID { - for _, token := range q.oauth2ProviderAppTokens { - if token.AppSecretID == secret.ID { - keyIdx := slices.IndexFunc(q.apiKeys, func(key database.APIKey) bool { - return key.ID == token.APIKeyID - }) - if keyIdx != -1 && q.apiKeys[keyIdx].UserID == userID { - tokens = append(tokens, token) - } - } - } - } - } - if len(tokens) > 0 { - rows = append(rows, database.GetOAuth2ProviderAppsByUserIDRow{ - OAuth2ProviderApp: app, - TokenCount: int64(len(tokens)), - }) - } - } - return rows, nil -} - -func (q *FakeQuerier) GetOAuthSigningKey(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.oauthSigningKey, nil -} - -func (q *FakeQuerier) GetOrganizationByID(_ context.Context, id uuid.UUID) (database.Organization, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getOrganizationByIDNoLock(id) -} - -func (q *FakeQuerier) GetOrganizationByName(_ context.Context, params database.GetOrganizationByNameParams) (database.Organization, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, organization := range q.organizations { - if organization.Name == params.Name && organization.Deleted == params.Deleted { - return organization, nil - } - } - return database.Organization{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetOrganizationIDsByMemberIDs(_ context.Context, ids []uuid.UUID) ([]database.GetOrganizationIDsByMemberIDsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - getOrganizationIDsByMemberIDRows := make([]database.GetOrganizationIDsByMemberIDsRow, 0, len(ids)) - for _, userID := range ids { - userOrganizationIDs := make([]uuid.UUID, 0) - for _, membership := range q.organizationMembers { - if membership.UserID == userID { - userOrganizationIDs = append(userOrganizationIDs, membership.OrganizationID) - } - } - getOrganizationIDsByMemberIDRows = append(getOrganizationIDsByMemberIDRows, database.GetOrganizationIDsByMemberIDsRow{ - UserID: userID, - OrganizationIDs: userOrganizationIDs, - }) - } - return getOrganizationIDsByMemberIDRows, nil -} - -func (q *FakeQuerier) GetOrganizationResourceCountByID(_ context.Context, organizationID uuid.UUID) (database.GetOrganizationResourceCountByIDRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspacesCount := 0 - for _, workspace := range q.workspaces { - if workspace.OrganizationID == organizationID { - workspacesCount++ - } - } - - groupsCount := 0 - for _, group := range q.groups { - if group.OrganizationID == organizationID { - groupsCount++ - } - } - - templatesCount := 0 - for _, template := range q.templates { - if template.OrganizationID == organizationID { - templatesCount++ - } - } - - organizationMembersCount := 0 - for _, organizationMember := range q.organizationMembers { - if organizationMember.OrganizationID == organizationID { - organizationMembersCount++ - } - } - - provKeyCount := 0 - for _, provKey := range q.provisionerKeys { - if provKey.OrganizationID == organizationID { - provKeyCount++ - } - } - - return database.GetOrganizationResourceCountByIDRow{ - WorkspaceCount: int64(workspacesCount), - GroupCount: int64(groupsCount), - TemplateCount: int64(templatesCount), - MemberCount: int64(organizationMembersCount), - ProvisionerKeyCount: int64(provKeyCount), - }, nil -} - -func (q *FakeQuerier) GetOrganizations(_ context.Context, args database.GetOrganizationsParams) ([]database.Organization, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - tmp := make([]database.Organization, 0) - for _, org := range q.organizations { - if len(args.IDs) > 0 { - if !slices.Contains(args.IDs, org.ID) { - continue - } - } - if args.Name != "" && !strings.EqualFold(org.Name, args.Name) { - continue - } - if args.Deleted != org.Deleted { - continue - } - tmp = append(tmp, org) - } - - return tmp, nil -} - -func (q *FakeQuerier) GetOrganizationsByUserID(_ context.Context, arg database.GetOrganizationsByUserIDParams) ([]database.Organization, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - organizations := make([]database.Organization, 0) - for _, organizationMember := range q.organizationMembers { - if organizationMember.UserID != arg.UserID { - continue - } - for _, organization := range q.organizations { - if organization.ID != organizationMember.OrganizationID { - continue - } - - if arg.Deleted.Valid && organization.Deleted != arg.Deleted.Bool { - continue - } - organizations = append(organizations, organization) - } - } - - return organizations, nil -} - -func (q *FakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.UUID) ([]database.ParameterSchema, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - parameters := make([]database.ParameterSchema, 0) - for _, parameterSchema := range q.parameterSchemas { - if parameterSchema.JobID != jobID { - continue - } - parameters = append(parameters, parameterSchema) - } - if len(parameters) == 0 { - return nil, sql.ErrNoRows - } - sort.Slice(parameters, func(i, j int) bool { - return parameters[i].Index < parameters[j].Index - }) - return parameters, nil -} - -func (*FakeQuerier) GetPrebuildMetrics(_ context.Context) ([]database.GetPrebuildMetricsRow, error) { - return make([]database.GetPrebuildMetricsRow, 0), nil -} - -func (q *FakeQuerier) GetPrebuildsSettings(_ context.Context) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return string(slices.Clone(q.prebuildsSettings)), nil -} - -func (q *FakeQuerier) GetPresetByID(_ context.Context, presetID uuid.UUID) (database.GetPresetByIDRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - empty := database.GetPresetByIDRow{} - - // Create an index for faster lookup - versionMap := make(map[uuid.UUID]database.TemplateVersionTable) - for _, tv := range q.templateVersions { - versionMap[tv.ID] = tv - } - - for _, preset := range q.presets { - if preset.ID == presetID { - tv, ok := versionMap[preset.TemplateVersionID] - if !ok { - return empty, xerrors.Errorf("template version %v does not exist", preset.TemplateVersionID) - } - return database.GetPresetByIDRow{ - ID: preset.ID, - TemplateVersionID: preset.TemplateVersionID, - Name: preset.Name, - CreatedAt: preset.CreatedAt, - DesiredInstances: preset.DesiredInstances, - InvalidateAfterSecs: preset.InvalidateAfterSecs, - PrebuildStatus: preset.PrebuildStatus, - TemplateID: tv.TemplateID, - OrganizationID: tv.OrganizationID, - }, nil - } - } - - return empty, xerrors.Errorf("preset %v does not exist", presetID) -} - -func (q *FakeQuerier) GetPresetByWorkspaceBuildID(_ context.Context, workspaceBuildID uuid.UUID) (database.TemplateVersionPreset, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.ID != workspaceBuildID { - continue - } - for _, preset := range q.presets { - if preset.TemplateVersionID == workspaceBuild.TemplateVersionID { - return preset, nil - } - } - } - return database.TemplateVersionPreset{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetPresetParametersByPresetID(_ context.Context, presetID uuid.UUID) ([]database.TemplateVersionPresetParameter, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - parameters := make([]database.TemplateVersionPresetParameter, 0) - for _, parameter := range q.presetParameters { - if parameter.TemplateVersionPresetID != presetID { - continue - } - parameters = append(parameters, parameter) - } - - return parameters, nil -} - -func (q *FakeQuerier) GetPresetParametersByTemplateVersionID(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPresetParameter, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - presets := make([]database.TemplateVersionPreset, 0) - parameters := make([]database.TemplateVersionPresetParameter, 0) - for _, preset := range q.presets { - if preset.TemplateVersionID != templateVersionID { - continue - } - presets = append(presets, preset) - } - for _, parameter := range q.presetParameters { - for _, preset := range presets { - if parameter.TemplateVersionPresetID != preset.ID { - continue - } - parameters = append(parameters, parameter) - } - } - - return parameters, nil -} - -func (q *FakeQuerier) GetPresetsAtFailureLimit(ctx context.Context, hardLimit int64) ([]database.GetPresetsAtFailureLimitRow, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetPresetsBackoff(_ context.Context, _ time.Time) ([]database.GetPresetsBackoffRow, error) { - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) GetPresetsByTemplateVersionID(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPreset, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - presets := make([]database.TemplateVersionPreset, 0) - for _, preset := range q.presets { - if preset.TemplateVersionID == templateVersionID { - presets = append(presets, preset) - } - } - return presets, nil -} - -func (q *FakeQuerier) GetPreviousTemplateVersion(_ context.Context, arg database.GetPreviousTemplateVersionParams) (database.TemplateVersion, error) { - if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersion{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - var currentTemplateVersion database.TemplateVersion - for _, templateVersion := range q.templateVersions { - if templateVersion.TemplateID != arg.TemplateID { - continue - } - if templateVersion.Name != arg.Name { - continue - } - if templateVersion.OrganizationID != arg.OrganizationID { - continue - } - currentTemplateVersion = q.templateVersionWithUserNoLock(templateVersion) - break - } - - previousTemplateVersions := make([]database.TemplateVersion, 0) - for _, templateVersion := range q.templateVersions { - if templateVersion.ID == currentTemplateVersion.ID { - continue - } - if templateVersion.OrganizationID != arg.OrganizationID { - continue - } - if templateVersion.TemplateID != currentTemplateVersion.TemplateID { - continue - } - - if templateVersion.CreatedAt.Before(currentTemplateVersion.CreatedAt) { - previousTemplateVersions = append(previousTemplateVersions, q.templateVersionWithUserNoLock(templateVersion)) - } - } - - if len(previousTemplateVersions) == 0 { - return database.TemplateVersion{}, sql.ErrNoRows - } - - sort.Slice(previousTemplateVersions, func(i, j int) bool { - return previousTemplateVersions[i].CreatedAt.After(previousTemplateVersions[j].CreatedAt) - }) - - return previousTemplateVersions[0], nil -} - -func (q *FakeQuerier) GetProvisionerDaemons(_ context.Context) ([]database.ProvisionerDaemon, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if len(q.provisionerDaemons) == 0 { - // Returning err=nil here for consistency with real querier - return []database.ProvisionerDaemon{}, nil - } - // copy the data so that the caller can't manipulate any data inside dbmem - // after returning - out := make([]database.ProvisionerDaemon, len(q.provisionerDaemons)) - copy(out, q.provisionerDaemons) - for i := range out { - // maps are reference types, so we need to clone them - out[i].Tags = maps.Clone(out[i].Tags) - } - return out, nil -} - -func (q *FakeQuerier) GetProvisionerDaemonsByOrganization(_ context.Context, arg database.GetProvisionerDaemonsByOrganizationParams) ([]database.ProvisionerDaemon, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - daemons := make([]database.ProvisionerDaemon, 0) - for _, daemon := range q.provisionerDaemons { - if daemon.OrganizationID != arg.OrganizationID { - continue - } - // Special case for untagged provisioners: only match untagged jobs. - // Ref: coderd/database/queries/provisionerjobs.sql:24-30 - // CASE WHEN nested.tags :: jsonb = '{"scope": "organization", "owner": ""}' :: jsonb - // THEN nested.tags :: jsonb = @tags :: jsonb - if tagsEqual(arg.WantTags, tagsUntagged) && !tagsEqual(arg.WantTags, daemon.Tags) { - continue - } - // ELSE nested.tags :: jsonb <@ @tags :: jsonb - if !tagsSubset(arg.WantTags, daemon.Tags) { - continue - } - daemon.Tags = maps.Clone(daemon.Tags) - daemons = append(daemons, daemon) - } - - return daemons, nil -} - -func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(ctx context.Context, arg database.GetProvisionerDaemonsWithStatusByOrganizationParams) ([]database.GetProvisionerDaemonsWithStatusByOrganizationRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - var rows []database.GetProvisionerDaemonsWithStatusByOrganizationRow - for _, daemon := range q.provisionerDaemons { - if daemon.OrganizationID != arg.OrganizationID { - continue - } - if len(arg.IDs) > 0 && !slices.Contains(arg.IDs, daemon.ID) { - continue - } - - if len(arg.Tags) > 0 { - // Special case for untagged provisioners: only match untagged jobs. - // Ref: coderd/database/queries/provisionerjobs.sql:24-30 - // CASE WHEN nested.tags :: jsonb = '{"scope": "organization", "owner": ""}' :: jsonb - // THEN nested.tags :: jsonb = @tags :: jsonb - if tagsEqual(arg.Tags, tagsUntagged) && !tagsEqual(arg.Tags, daemon.Tags) { - continue - } - // ELSE nested.tags :: jsonb <@ @tags :: jsonb - if !tagsSubset(arg.Tags, daemon.Tags) { - continue - } - } - - var status database.ProvisionerDaemonStatus - var currentJob database.ProvisionerJob - if !daemon.LastSeenAt.Valid || daemon.LastSeenAt.Time.Before(time.Now().Add(-time.Duration(arg.StaleIntervalMS)*time.Millisecond)) { - status = database.ProvisionerDaemonStatusOffline - } else { - for _, job := range q.provisionerJobs { - if job.WorkerID.Valid && job.WorkerID.UUID == daemon.ID && !job.CompletedAt.Valid && !job.Error.Valid { - currentJob = job - break - } - } - - if currentJob.ID != uuid.Nil { - status = database.ProvisionerDaemonStatusBusy - } else { - status = database.ProvisionerDaemonStatusIdle - } - } - var currentTemplate database.Template - if currentJob.ID != uuid.Nil { - var input codersdk.ProvisionerJobInput - err := json.Unmarshal(currentJob.Input, &input) - if err != nil { - return nil, err - } - if input.WorkspaceBuildID != nil { - b, err := q.getWorkspaceBuildByIDNoLock(ctx, *input.WorkspaceBuildID) - if err != nil { - return nil, err - } - input.TemplateVersionID = &b.TemplateVersionID - } - if input.TemplateVersionID != nil { - v, err := q.getTemplateVersionByIDNoLock(ctx, *input.TemplateVersionID) - if err != nil { - return nil, err - } - currentTemplate, err = q.getTemplateByIDNoLock(ctx, v.TemplateID.UUID) - if err != nil { - return nil, err - } - } - } - - var previousJob database.ProvisionerJob - for _, job := range q.provisionerJobs { - if !job.WorkerID.Valid || job.WorkerID.UUID != daemon.ID { - continue - } - - if job.StartedAt.Valid || - job.CanceledAt.Valid || - job.CompletedAt.Valid || - job.Error.Valid { - if job.CompletedAt.Time.After(previousJob.CompletedAt.Time) { - previousJob = job - } - } - } - var previousTemplate database.Template - if previousJob.ID != uuid.Nil { - var input codersdk.ProvisionerJobInput - err := json.Unmarshal(previousJob.Input, &input) - if err != nil { - return nil, err - } - if input.WorkspaceBuildID != nil { - b, err := q.getWorkspaceBuildByIDNoLock(ctx, *input.WorkspaceBuildID) - if err != nil { - return nil, err - } - input.TemplateVersionID = &b.TemplateVersionID - } - if input.TemplateVersionID != nil { - v, err := q.getTemplateVersionByIDNoLock(ctx, *input.TemplateVersionID) - if err != nil { - return nil, err - } - previousTemplate, err = q.getTemplateByIDNoLock(ctx, v.TemplateID.UUID) - if err != nil { - return nil, err - } - } - } - - // Get the provisioner key name - var keyName string - for _, key := range q.provisionerKeys { - if key.ID == daemon.KeyID { - keyName = key.Name - break - } - } - - rows = append(rows, database.GetProvisionerDaemonsWithStatusByOrganizationRow{ - ProvisionerDaemon: daemon, - Status: status, - KeyName: keyName, - CurrentJobID: uuid.NullUUID{UUID: currentJob.ID, Valid: currentJob.ID != uuid.Nil}, - CurrentJobStatus: database.NullProvisionerJobStatus{ProvisionerJobStatus: currentJob.JobStatus, Valid: currentJob.ID != uuid.Nil}, - CurrentJobTemplateName: currentTemplate.Name, - CurrentJobTemplateDisplayName: currentTemplate.DisplayName, - CurrentJobTemplateIcon: currentTemplate.Icon, - PreviousJobID: uuid.NullUUID{UUID: previousJob.ID, Valid: previousJob.ID != uuid.Nil}, - PreviousJobStatus: database.NullProvisionerJobStatus{ProvisionerJobStatus: previousJob.JobStatus, Valid: previousJob.ID != uuid.Nil}, - PreviousJobTemplateName: previousTemplate.Name, - PreviousJobTemplateDisplayName: previousTemplate.DisplayName, - PreviousJobTemplateIcon: previousTemplate.Icon, - }) - } - - slices.SortFunc(rows, func(a, b database.GetProvisionerDaemonsWithStatusByOrganizationRow) int { - return b.ProvisionerDaemon.CreatedAt.Compare(a.ProvisionerDaemon.CreatedAt) - }) - - if arg.Limit.Valid && arg.Limit.Int32 > 0 && len(rows) > int(arg.Limit.Int32) { - rows = rows[:arg.Limit.Int32] - } - - return rows, nil -} - -func (q *FakeQuerier) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (database.ProvisionerJob, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getProvisionerJobByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetProvisionerJobByIDForUpdate(ctx context.Context, id uuid.UUID) (database.ProvisionerJob, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getProvisionerJobByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetProvisionerJobTimingsByJobID(_ context.Context, jobID uuid.UUID) ([]database.ProvisionerJobTiming, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - timings := make([]database.ProvisionerJobTiming, 0) - for _, timing := range q.provisionerJobTimings { - if timing.JobID == jobID { - timings = append(timings, timing) - } - } - if len(timings) == 0 { - return nil, sql.ErrNoRows - } - sort.Slice(timings, func(i, j int) bool { - return timings[i].StartedAt.Before(timings[j].StartedAt) - }) - - return timings, nil -} - -func (q *FakeQuerier) GetProvisionerJobsByIDs(_ context.Context, ids []uuid.UUID) ([]database.ProvisionerJob, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - jobs := make([]database.ProvisionerJob, 0) - for _, job := range q.provisionerJobs { - for _, id := range ids { - if id == job.ID { - // clone the Tags before appending, since maps are reference types and - // we don't want the caller to be able to mutate the map we have inside - // dbmem! - job.Tags = maps.Clone(job.Tags) - jobs = append(jobs, job) - break - } - } - } - if len(jobs) == 0 { - return nil, sql.ErrNoRows - } - - return jobs, nil -} - -func (q *FakeQuerier) GetProvisionerJobsByIDsWithQueuePosition(ctx context.Context, arg database.GetProvisionerJobsByIDsWithQueuePositionParams) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if arg.IDs == nil { - arg.IDs = []uuid.UUID{} - } - return q.getProvisionerJobsByIDsWithQueuePositionLockedTagBasedQueue(ctx, arg.IDs) -} - -func (q *FakeQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisioner(ctx context.Context, arg database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams) ([]database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - /* - -- name: GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisioner :many - WITH pending_jobs AS ( - SELECT - id, created_at - FROM - provisioner_jobs - WHERE - started_at IS NULL - AND - canceled_at IS NULL - AND - completed_at IS NULL - AND - error IS NULL - ), - queue_position AS ( - SELECT - id, - ROW_NUMBER() OVER (ORDER BY created_at ASC) AS queue_position - FROM - pending_jobs - ), - queue_size AS ( - SELECT COUNT(*) AS count FROM pending_jobs - ) - SELECT - sqlc.embed(pj), - COALESCE(qp.queue_position, 0) AS queue_position, - COALESCE(qs.count, 0) AS queue_size, - array_agg(DISTINCT pd.id) FILTER (WHERE pd.id IS NOT NULL)::uuid[] AS available_workers - FROM - provisioner_jobs pj - LEFT JOIN - queue_position qp ON qp.id = pj.id - LEFT JOIN - queue_size qs ON TRUE - LEFT JOIN - provisioner_daemons pd ON ( - -- See AcquireProvisionerJob. - pj.started_at IS NULL - AND pj.organization_id = pd.organization_id - AND pj.provisioner = ANY(pd.provisioners) - AND provisioner_tagset_contains(pd.tags, pj.tags) - ) - WHERE - (sqlc.narg('organization_id')::uuid IS NULL OR pj.organization_id = @organization_id) - AND (COALESCE(array_length(@status::provisioner_job_status[], 1), 1) > 0 OR pj.job_status = ANY(@status::provisioner_job_status[])) - GROUP BY - pj.id, - qp.queue_position, - qs.count - ORDER BY - pj.created_at DESC - LIMIT - sqlc.narg('limit')::int; - */ - rowsWithQueuePosition, err := q.getProvisionerJobsByIDsWithQueuePositionLockedGlobalQueue(ctx, nil) - if err != nil { - return nil, err - } - - var rows []database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow - for _, rowQP := range rowsWithQueuePosition { - job := rowQP.ProvisionerJob - - if job.OrganizationID != arg.OrganizationID { - continue - } - if len(arg.Status) > 0 && !slices.Contains(arg.Status, job.JobStatus) { - continue - } - if len(arg.IDs) > 0 && !slices.Contains(arg.IDs, job.ID) { - continue - } - if len(arg.Tags) > 0 && !tagsSubset(job.Tags, arg.Tags) { - continue - } - - row := database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow{ - ProvisionerJob: rowQP.ProvisionerJob, - QueuePosition: rowQP.QueuePosition, - QueueSize: rowQP.QueueSize, - } - - // Start add metadata. - var input codersdk.ProvisionerJobInput - err := json.Unmarshal([]byte(job.Input), &input) - if err != nil { - return nil, err - } - templateVersionID := input.TemplateVersionID - if input.WorkspaceBuildID != nil { - workspaceBuild, err := q.getWorkspaceBuildByIDNoLock(ctx, *input.WorkspaceBuildID) - if err != nil { - return nil, err - } - workspace, err := q.getWorkspaceByIDNoLock(ctx, workspaceBuild.WorkspaceID) - if err != nil { - return nil, err - } - row.WorkspaceID = uuid.NullUUID{UUID: workspace.ID, Valid: true} - row.WorkspaceName = workspace.Name - if templateVersionID == nil { - templateVersionID = &workspaceBuild.TemplateVersionID - } - } - if templateVersionID != nil { - templateVersion, err := q.getTemplateVersionByIDNoLock(ctx, *templateVersionID) - if err != nil { - return nil, err - } - row.TemplateVersionName = templateVersion.Name - template, err := q.getTemplateByIDNoLock(ctx, templateVersion.TemplateID.UUID) - if err != nil { - return nil, err - } - row.TemplateID = uuid.NullUUID{UUID: template.ID, Valid: true} - row.TemplateName = template.Name - row.TemplateDisplayName = template.DisplayName - } - // End add metadata. - - if row.QueuePosition > 0 { - var availableWorkers []database.ProvisionerDaemon - for _, daemon := range q.provisionerDaemons { - if daemon.OrganizationID == job.OrganizationID && slices.Contains(daemon.Provisioners, job.Provisioner) { - if tagsEqual(job.Tags, tagsUntagged) { - if tagsEqual(job.Tags, daemon.Tags) { - availableWorkers = append(availableWorkers, daemon) - } - } else if tagsSubset(job.Tags, daemon.Tags) { - availableWorkers = append(availableWorkers, daemon) - } - } - } - slices.SortFunc(availableWorkers, func(a, b database.ProvisionerDaemon) int { - return a.CreatedAt.Compare(b.CreatedAt) - }) - for _, worker := range availableWorkers { - row.AvailableWorkers = append(row.AvailableWorkers, worker.ID) - } - } - - // Add daemon name to provisioner job - for _, daemon := range q.provisionerDaemons { - if job.WorkerID.Valid && job.WorkerID.UUID == daemon.ID { - row.WorkerName = daemon.Name - } - } - rows = append(rows, row) - } - - slices.SortFunc(rows, func(a, b database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow) int { - return b.ProvisionerJob.CreatedAt.Compare(a.ProvisionerJob.CreatedAt) - }) - if arg.Limit.Valid && arg.Limit.Int32 > 0 && len(rows) > int(arg.Limit.Int32) { - rows = rows[:arg.Limit.Int32] - } - return rows, nil -} - -func (q *FakeQuerier) GetProvisionerJobsCreatedAfter(_ context.Context, after time.Time) ([]database.ProvisionerJob, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - jobs := make([]database.ProvisionerJob, 0) - for _, job := range q.provisionerJobs { - if job.CreatedAt.After(after) { - // clone the Tags before appending, since maps are reference types and - // we don't want the caller to be able to mutate the map we have inside - // dbmem! - job.Tags = maps.Clone(job.Tags) - jobs = append(jobs, job) - } - } - return jobs, nil -} - -func (q *FakeQuerier) GetProvisionerJobsToBeReaped(_ context.Context, arg database.GetProvisionerJobsToBeReapedParams) ([]database.ProvisionerJob, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - maxJobs := arg.MaxJobs - - hungJobs := []database.ProvisionerJob{} - for _, provisionerJob := range q.provisionerJobs { - if !provisionerJob.CompletedAt.Valid { - if (provisionerJob.StartedAt.Valid && provisionerJob.UpdatedAt.Before(arg.HungSince)) || - (!provisionerJob.StartedAt.Valid && provisionerJob.UpdatedAt.Before(arg.PendingSince)) { - // clone the Tags before appending, since maps are reference types and - // we don't want the caller to be able to mutate the map we have inside - // dbmem! - provisionerJob.Tags = maps.Clone(provisionerJob.Tags) - hungJobs = append(hungJobs, provisionerJob) - if len(hungJobs) >= int(maxJobs) { - break - } - } - } - } - insecurerand.Shuffle(len(hungJobs), func(i, j int) { - hungJobs[i], hungJobs[j] = hungJobs[j], hungJobs[i] - }) - return hungJobs, nil -} - -func (q *FakeQuerier) GetProvisionerKeyByHashedSecret(_ context.Context, hashedSecret []byte) (database.ProvisionerKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, key := range q.provisionerKeys { - if bytes.Equal(key.HashedSecret, hashedSecret) { - return key, nil - } - } - - return database.ProvisionerKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetProvisionerKeyByID(_ context.Context, id uuid.UUID) (database.ProvisionerKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, key := range q.provisionerKeys { - if key.ID == id { - return key, nil - } - } - - return database.ProvisionerKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetProvisionerKeyByName(_ context.Context, arg database.GetProvisionerKeyByNameParams) (database.ProvisionerKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, key := range q.provisionerKeys { - if strings.EqualFold(key.Name, arg.Name) && key.OrganizationID == arg.OrganizationID { - return key, nil - } - } - - return database.ProvisionerKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetProvisionerLogsAfterID(_ context.Context, arg database.GetProvisionerLogsAfterIDParams) ([]database.ProvisionerJobLog, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - logs := make([]database.ProvisionerJobLog, 0) - for _, jobLog := range q.provisionerJobLogs { - if jobLog.JobID != arg.JobID { - continue - } - if jobLog.ID <= arg.CreatedAfter { - continue - } - logs = append(logs, jobLog) - } - return logs, nil -} - -func (q *FakeQuerier) GetQuotaAllowanceForUser(_ context.Context, params database.GetQuotaAllowanceForUserParams) (int64, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var sum int64 - for _, member := range q.groupMembers { - if member.UserID != params.UserID { - continue - } - if _, err := q.getOrganizationByIDNoLock(member.GroupID); err == nil { - // This should never happen, but it has been reported in customer deployments. - // The SQL handles this case, and omits `group_members` rows in the - // Everyone group. It counts these distinctly via `organization_members` table. - continue - } - for _, group := range q.groups { - if group.ID == member.GroupID { - sum += int64(group.QuotaAllowance) - continue - } - } - } - - // Grab the quota for the Everyone group iff the user is a member of - // said organization. - for _, mem := range q.organizationMembers { - if mem.UserID != params.UserID { - continue - } - - group, err := q.getGroupByIDNoLock(context.Background(), mem.OrganizationID) - if err != nil { - return -1, xerrors.Errorf("failed to get everyone group for org %q", mem.OrganizationID.String()) - } - if group.OrganizationID != params.OrganizationID { - continue - } - sum += int64(group.QuotaAllowance) - } - - return sum, nil -} - -func (q *FakeQuerier) GetQuotaConsumedForUser(_ context.Context, params database.GetQuotaConsumedForUserParams) (int64, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var sum int64 - for _, workspace := range q.workspaces { - if workspace.OwnerID != params.OwnerID { - continue - } - if workspace.OrganizationID != params.OrganizationID { - continue - } - if workspace.Deleted { - continue - } - - var lastBuild database.WorkspaceBuild - for _, build := range q.workspaceBuilds { - if build.WorkspaceID != workspace.ID { - continue - } - if build.CreatedAt.After(lastBuild.CreatedAt) { - lastBuild = build - } - } - sum += int64(lastBuild.DailyCost) - } - return sum, nil -} - -func (q *FakeQuerier) GetReplicaByID(_ context.Context, id uuid.UUID) (database.Replica, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, replica := range q.replicas { - if replica.ID == id { - return replica, nil - } - } - - return database.Replica{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetReplicasUpdatedAfter(_ context.Context, updatedAt time.Time) ([]database.Replica, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - replicas := make([]database.Replica, 0) - for _, replica := range q.replicas { - if replica.UpdatedAt.After(updatedAt) && !replica.StoppedAt.Valid { - replicas = append(replicas, replica) - } - } - return replicas, nil -} - -func (q *FakeQuerier) GetRunningPrebuiltWorkspaces(ctx context.Context) ([]database.GetRunningPrebuiltWorkspacesRow, error) { - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) GetRuntimeConfig(_ context.Context, key string) (string, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - val, ok := q.runtimeConfig[key] - if !ok { - return "", sql.ErrNoRows - } - - return val, nil -} - -func (*FakeQuerier) GetTailnetAgents(context.Context, uuid.UUID) ([]database.TailnetAgent, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetTailnetClientsForAgent(context.Context, uuid.UUID) ([]database.TailnetClient, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetTailnetPeers(context.Context, uuid.UUID) ([]database.TailnetPeer, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetTailnetTunnelPeerBindings(context.Context, uuid.UUID) ([]database.GetTailnetTunnelPeerBindingsRow, error) { - return nil, ErrUnimplemented -} - -func (*FakeQuerier) GetTailnetTunnelPeerIDs(context.Context, uuid.UUID) ([]database.GetTailnetTunnelPeerIDsRow, error) { - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) GetTelemetryItem(_ context.Context, key string) (database.TelemetryItem, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, item := range q.telemetryItems { - if item.Key == key { - return item, nil - } - } - - return database.TelemetryItem{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetTelemetryItems(_ context.Context) ([]database.TelemetryItem, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - return slices.Clone(q.telemetryItems), nil -} - -func (q *FakeQuerier) GetTemplateAppInsights(ctx context.Context, arg database.GetTemplateAppInsightsParams) ([]database.GetTemplateAppInsightsRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - /* - WITH - */ - - /* - -- Create a list of all unique apps by template, this is used to - -- filter out irrelevant template usage stats. - apps AS ( - SELECT DISTINCT ON (ws.template_id, app.slug) - ws.template_id, - app.slug, - app.display_name, - app.icon - FROM - workspaces ws - JOIN - workspace_builds AS build - ON - build.workspace_id = ws.id - JOIN - workspace_resources AS resource - ON - resource.job_id = build.job_id - JOIN - workspace_agents AS agent - ON - agent.resource_id = resource.id - JOIN - workspace_apps AS app - ON - app.agent_id = agent.id - WHERE - -- Partial query parameter filter. - CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN ws.template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - ORDER BY - ws.template_id, app.slug, app.created_at DESC - ), - -- Join apps and template usage stats to filter out irrelevant rows. - -- Note that this way of joining will eliminate all data-points that - -- aren't for "real" apps. That means ports are ignored (even though - -- they're part of the dataset), as well as are "[terminal]" entries - -- which are alternate datapoints for reconnecting pty usage. - template_usage_stats_with_apps AS ( - SELECT - tus.start_time, - tus.template_id, - tus.user_id, - apps.slug, - apps.display_name, - apps.icon, - tus.app_usage_mins - FROM - apps - JOIN - template_usage_stats AS tus - ON - -- Query parameter filter. - tus.start_time >= @start_time::timestamptz - AND tus.end_time <= @end_time::timestamptz - AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN tus.template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - -- Primary join condition. - AND tus.template_id = apps.template_id - AND apps.slug IN (SELECT jsonb_object_keys(tus.app_usage_mins)) - ), - -- Group the app insights by interval, user and unique app. This - -- allows us to deduplicate a user using the same app across - -- multiple templates. - app_insights AS ( - SELECT - user_id, - slug, - display_name, - icon, - -- See motivation in GetTemplateInsights for LEAST(SUM(n), 30). - LEAST(SUM(app_usage.value::smallint), 30) AS usage_mins - FROM - template_usage_stats_with_apps, jsonb_each(app_usage_mins) AS app_usage - WHERE - app_usage.key = slug - GROUP BY - start_time, user_id, slug, display_name, icon - ), - -- Analyze the users unique app usage across all templates. Count - -- usage across consecutive intervals as continuous usage. - times_used AS ( - SELECT DISTINCT ON (user_id, slug, display_name, icon, uniq) - slug, - display_name, - icon, - -- Turn start_time into a unique identifier that identifies a users - -- continuous app usage. The value of uniq is otherwise garbage. - -- - -- Since we're aggregating per user app usage across templates, - -- there can be duplicate start_times. To handle this, we use the - -- dense_rank() function, otherwise row_number() would suffice. - start_time - ( - dense_rank() OVER ( - PARTITION BY - user_id, slug, display_name, icon - ORDER BY - start_time - ) * '30 minutes'::interval - ) AS uniq - FROM - template_usage_stats_with_apps - ), - */ - - // Due to query optimizations, this logic is somewhat inverted from - // the above query. - type appInsightsGroupBy struct { - StartTime time.Time - UserID uuid.UUID - Slug string - DisplayName string - Icon string - } - type appTimesUsedGroupBy struct { - UserID uuid.UUID - Slug string - DisplayName string - Icon string - } - type appInsightsRow struct { - appInsightsGroupBy - TemplateIDs []uuid.UUID - AppUsageMins int64 - } - appInsightRows := make(map[appInsightsGroupBy]appInsightsRow) - appTimesUsedRows := make(map[appTimesUsedGroupBy]map[time.Time]struct{}) - // FROM - for _, stat := range q.templateUsageStats { - // WHERE - if stat.StartTime.Before(arg.StartTime) || stat.EndTime.After(arg.EndTime) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, stat.TemplateID) { - continue - } - - // json_each - for slug, appUsage := range stat.AppUsageMins { - // FROM apps JOIN template_usage_stats - app, _ := q.getLatestWorkspaceAppByTemplateIDUserIDSlugNoLock(ctx, stat.TemplateID, stat.UserID, slug) - if app.Slug == "" { - continue - } - - // SELECT - key := appInsightsGroupBy{ - StartTime: stat.StartTime, - UserID: stat.UserID, - Slug: slug, - DisplayName: app.DisplayName, - Icon: app.Icon, - } - row, ok := appInsightRows[key] - if !ok { - row = appInsightsRow{ - appInsightsGroupBy: key, - } - } - row.TemplateIDs = append(row.TemplateIDs, stat.TemplateID) - row.AppUsageMins = least(row.AppUsageMins+appUsage, 30) - appInsightRows[key] = row - - // Prepare to do times_used calculation, distinct start times. - timesUsedKey := appTimesUsedGroupBy{ - UserID: stat.UserID, - Slug: slug, - DisplayName: app.DisplayName, - Icon: app.Icon, - } - if appTimesUsedRows[timesUsedKey] == nil { - appTimesUsedRows[timesUsedKey] = make(map[time.Time]struct{}) - } - // This assigns a distinct time, so we don't need to - // dense_rank() later on, we can simply do row_number(). - appTimesUsedRows[timesUsedKey][stat.StartTime] = struct{}{} - } - } - - appTimesUsedTempRows := make(map[appTimesUsedGroupBy][]time.Time) - for key, times := range appTimesUsedRows { - for t := range times { - appTimesUsedTempRows[key] = append(appTimesUsedTempRows[key], t) - } - } - for _, times := range appTimesUsedTempRows { - slices.SortFunc(times, func(a, b time.Time) int { - return int(a.Sub(b)) - }) - } - for key, times := range appTimesUsedTempRows { - uniq := make(map[time.Time]struct{}) - for i, t := range times { - uniq[t.Add(-(30 * time.Minute * time.Duration(i)))] = struct{}{} - } - appTimesUsedRows[key] = uniq - } - - /* - -- Even though we allow identical apps to be aggregated across - -- templates, we still want to be able to report which templates - -- the data comes from. - templates AS ( - SELECT - slug, - display_name, - icon, - array_agg(DISTINCT template_id)::uuid[] AS template_ids - FROM - template_usage_stats_with_apps - GROUP BY - slug, display_name, icon - ) - */ - - type appGroupBy struct { - Slug string - DisplayName string - Icon string - } - type templateRow struct { - appGroupBy - TemplateIDs []uuid.UUID - } - - templateRows := make(map[appGroupBy]templateRow) - for _, aiRow := range appInsightRows { - key := appGroupBy{ - Slug: aiRow.Slug, - DisplayName: aiRow.DisplayName, - Icon: aiRow.Icon, - } - row, ok := templateRows[key] - if !ok { - row = templateRow{ - appGroupBy: key, - } - } - row.TemplateIDs = uniqueSortedUUIDs(append(row.TemplateIDs, aiRow.TemplateIDs...)) - templateRows[key] = row - } - - /* - SELECT - t.template_ids, - COUNT(DISTINCT ai.user_id) AS active_users, - ai.slug, - ai.display_name, - ai.icon, - (SUM(ai.usage_mins) * 60)::bigint AS usage_seconds - FROM - app_insights AS ai - JOIN - templates AS t - ON - t.slug = ai.slug - AND t.display_name = ai.display_name - AND t.icon = ai.icon - GROUP BY - t.template_ids, ai.slug, ai.display_name, ai.icon; - */ - - type templateAppInsightsRow struct { - TemplateIDs []uuid.UUID - ActiveUserIDs []uuid.UUID - UsageSeconds int64 - } - groupedRows := make(map[appGroupBy]templateAppInsightsRow) - for _, aiRow := range appInsightRows { - key := appGroupBy{ - Slug: aiRow.Slug, - DisplayName: aiRow.DisplayName, - Icon: aiRow.Icon, - } - row := groupedRows[key] - row.ActiveUserIDs = append(row.ActiveUserIDs, aiRow.UserID) - row.UsageSeconds += aiRow.AppUsageMins * 60 - groupedRows[key] = row - } - - var rows []database.GetTemplateAppInsightsRow - for key, gr := range groupedRows { - row := database.GetTemplateAppInsightsRow{ - TemplateIDs: templateRows[key].TemplateIDs, - ActiveUsers: int64(len(uniqueSortedUUIDs(gr.ActiveUserIDs))), - Slug: key.Slug, - DisplayName: key.DisplayName, - Icon: key.Icon, - UsageSeconds: gr.UsageSeconds, - } - for tuk, uniq := range appTimesUsedRows { - if key.Slug == tuk.Slug && key.DisplayName == tuk.DisplayName && key.Icon == tuk.Icon { - row.TimesUsed += int64(len(uniq)) - } - } - rows = append(rows, row) - } - - // NOTE(mafredri): Add sorting if we decide on how to handle PostgreSQL collations. - // ORDER BY slug_or_port, display_name, icon, is_app - return rows, nil -} - -func (q *FakeQuerier) GetTemplateAppInsightsByTemplate(ctx context.Context, arg database.GetTemplateAppInsightsByTemplateParams) ([]database.GetTemplateAppInsightsByTemplateRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - type uniqueKey struct { - TemplateID uuid.UUID - DisplayName string - Slug string - } - - // map (TemplateID + DisplayName + Slug) x time.Time x UserID x - usageByTemplateAppUser := map[uniqueKey]map[time.Time]map[uuid.UUID]int64{} - - // Review agent stats in terms of usage - for _, s := range q.workspaceAppStats { - // (was.session_started_at >= ts.from_ AND was.session_started_at < ts.to_) - // OR (was.session_ended_at > ts.from_ AND was.session_ended_at < ts.to_) - // OR (was.session_started_at < ts.from_ AND was.session_ended_at >= ts.to_) - if !(((s.SessionStartedAt.After(arg.StartTime) || s.SessionStartedAt.Equal(arg.StartTime)) && s.SessionStartedAt.Before(arg.EndTime)) || - (s.SessionEndedAt.After(arg.StartTime) && s.SessionEndedAt.Before(arg.EndTime)) || - (s.SessionStartedAt.Before(arg.StartTime) && (s.SessionEndedAt.After(arg.EndTime) || s.SessionEndedAt.Equal(arg.EndTime)))) { - continue - } - - w, err := q.getWorkspaceByIDNoLock(ctx, s.WorkspaceID) - if err != nil { - return nil, err - } - - app, _ := q.getWorkspaceAppByAgentIDAndSlugNoLock(ctx, database.GetWorkspaceAppByAgentIDAndSlugParams{ - AgentID: s.AgentID, - Slug: s.SlugOrPort, - }) - - key := uniqueKey{ - TemplateID: w.TemplateID, - DisplayName: app.DisplayName, - Slug: app.Slug, - } - - t := s.SessionStartedAt.Truncate(time.Minute) - if t.Before(arg.StartTime) { - t = arg.StartTime - } - for t.Before(s.SessionEndedAt) && t.Before(arg.EndTime) { - if _, ok := usageByTemplateAppUser[key]; !ok { - usageByTemplateAppUser[key] = map[time.Time]map[uuid.UUID]int64{} - } - if _, ok := usageByTemplateAppUser[key][t]; !ok { - usageByTemplateAppUser[key][t] = map[uuid.UUID]int64{} - } - if _, ok := usageByTemplateAppUser[key][t][s.UserID]; !ok { - usageByTemplateAppUser[key][t][s.UserID] = 60 // 1 minute - } - t = t.Add(1 * time.Minute) - } - } - - // Sort usage data - usageKeys := make([]uniqueKey, len(usageByTemplateAppUser)) - var i int - for key := range usageByTemplateAppUser { - usageKeys[i] = key - i++ - } - - slices.SortFunc(usageKeys, func(a, b uniqueKey) int { - if a.TemplateID != b.TemplateID { - return slice.Ascending(a.TemplateID.String(), b.TemplateID.String()) - } - if a.DisplayName != b.DisplayName { - return slice.Ascending(a.DisplayName, b.DisplayName) - } - return slice.Ascending(a.Slug, b.Slug) - }) - - // Build result - var result []database.GetTemplateAppInsightsByTemplateRow - for _, usageKey := range usageKeys { - r := database.GetTemplateAppInsightsByTemplateRow{ - TemplateID: usageKey.TemplateID, - DisplayName: usageKey.DisplayName, - SlugOrPort: usageKey.Slug, - } - for _, mUserUsage := range usageByTemplateAppUser[usageKey] { - r.ActiveUsers += int64(len(mUserUsage)) - for _, usage := range mUserUsage { - r.UsageSeconds += usage - } - } - result = append(result, r) - } - return result, nil -} - -func (q *FakeQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg database.GetTemplateAverageBuildTimeParams) (database.GetTemplateAverageBuildTimeRow, error) { - if err := validateDatabaseType(arg); err != nil { - return database.GetTemplateAverageBuildTimeRow{}, err - } - - var emptyRow database.GetTemplateAverageBuildTimeRow - var ( - startTimes []float64 - stopTimes []float64 - deleteTimes []float64 - ) - q.mutex.RLock() - defer q.mutex.RUnlock() - for _, wb := range q.workspaceBuilds { - version, err := q.getTemplateVersionByIDNoLock(ctx, wb.TemplateVersionID) - if err != nil { - return emptyRow, err - } - if version.TemplateID != arg.TemplateID { - continue - } - - job, err := q.getProvisionerJobByIDNoLock(ctx, wb.JobID) - if err != nil { - return emptyRow, err - } - if job.CompletedAt.Valid { - took := job.CompletedAt.Time.Sub(job.StartedAt.Time).Seconds() - switch wb.Transition { - case database.WorkspaceTransitionStart: - startTimes = append(startTimes, took) - case database.WorkspaceTransitionStop: - stopTimes = append(stopTimes, took) - case database.WorkspaceTransitionDelete: - deleteTimes = append(deleteTimes, took) - } - } - } - - var row database.GetTemplateAverageBuildTimeRow - row.Delete50, row.Delete95 = tryPercentileDisc(deleteTimes, 50), tryPercentileDisc(deleteTimes, 95) - row.Stop50, row.Stop95 = tryPercentileDisc(stopTimes, 50), tryPercentileDisc(stopTimes, 95) - row.Start50, row.Start95 = tryPercentileDisc(startTimes, 50), tryPercentileDisc(startTimes, 95) - return row, nil -} - -func (q *FakeQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (database.Template, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getTemplateByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetTemplateByOrganizationAndName(_ context.Context, arg database.GetTemplateByOrganizationAndNameParams) (database.Template, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Template{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, template := range q.templates { - if template.OrganizationID != arg.OrganizationID { - continue - } - if !strings.EqualFold(template.Name, arg.Name) { - continue - } - if template.Deleted != arg.Deleted { - continue - } - return q.templateWithNameNoLock(template), nil - } - return database.Template{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetTemplateDAUs(_ context.Context, arg database.GetTemplateDAUsParams) ([]database.GetTemplateDAUsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - seens := make(map[time.Time]map[uuid.UUID]struct{}) - - for _, as := range q.workspaceAgentStats { - if as.TemplateID != arg.TemplateID { - continue - } - if as.ConnectionCount == 0 { - continue - } - - date := as.CreatedAt.UTC().Add(time.Duration(arg.TzOffset) * time.Hour * -1).Truncate(time.Hour * 24) - - dateEntry := seens[date] - if dateEntry == nil { - dateEntry = make(map[uuid.UUID]struct{}) - } - dateEntry[as.UserID] = struct{}{} - seens[date] = dateEntry - } - - seenKeys := maps.Keys(seens) - sort.Slice(seenKeys, func(i, j int) bool { - return seenKeys[i].Before(seenKeys[j]) - }) - - var rs []database.GetTemplateDAUsRow - for _, key := range seenKeys { - ids := seens[key] - for id := range ids { - rs = append(rs, database.GetTemplateDAUsRow{ - Date: key, - UserID: id, - }) - } - } - - return rs, nil -} - -func (q *FakeQuerier) GetTemplateInsights(_ context.Context, arg database.GetTemplateInsightsParams) (database.GetTemplateInsightsRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.GetTemplateInsightsRow{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - /* - WITH - */ - - /* - insights AS ( - SELECT - user_id, - -- See motivation in GetTemplateInsights for LEAST(SUM(n), 30). - LEAST(SUM(usage_mins), 30) AS usage_mins, - LEAST(SUM(ssh_mins), 30) AS ssh_mins, - LEAST(SUM(sftp_mins), 30) AS sftp_mins, - LEAST(SUM(reconnecting_pty_mins), 30) AS reconnecting_pty_mins, - LEAST(SUM(vscode_mins), 30) AS vscode_mins, - LEAST(SUM(jetbrains_mins), 30) AS jetbrains_mins - FROM - template_usage_stats - WHERE - start_time >= @start_time::timestamptz - AND end_time <= @end_time::timestamptz - AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - GROUP BY - start_time, user_id - ), - */ - - type insightsGroupBy struct { - StartTime time.Time - UserID uuid.UUID - } - type insightsRow struct { - insightsGroupBy - UsageMins int16 - SSHMins int16 - SFTPMins int16 - ReconnectingPTYMins int16 - VSCodeMins int16 - JetBrainsMins int16 - } - insights := make(map[insightsGroupBy]insightsRow) - for _, stat := range q.templateUsageStats { - if stat.StartTime.Before(arg.StartTime) || stat.EndTime.After(arg.EndTime) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, stat.TemplateID) { - continue - } - key := insightsGroupBy{ - StartTime: stat.StartTime, - UserID: stat.UserID, - } - row, ok := insights[key] - if !ok { - row = insightsRow{ - insightsGroupBy: key, - } - } - row.UsageMins = least(row.UsageMins+stat.UsageMins, 30) - row.SSHMins = least(row.SSHMins+stat.SshMins, 30) - row.SFTPMins = least(row.SFTPMins+stat.SftpMins, 30) - row.ReconnectingPTYMins = least(row.ReconnectingPTYMins+stat.ReconnectingPtyMins, 30) - row.VSCodeMins = least(row.VSCodeMins+stat.VscodeMins, 30) - row.JetBrainsMins = least(row.JetBrainsMins+stat.JetbrainsMins, 30) - insights[key] = row - } - - /* - templates AS ( - SELECT - array_agg(DISTINCT template_id) AS template_ids, - array_agg(DISTINCT template_id) FILTER (WHERE ssh_mins > 0) AS ssh_template_ids, - array_agg(DISTINCT template_id) FILTER (WHERE sftp_mins > 0) AS sftp_template_ids, - array_agg(DISTINCT template_id) FILTER (WHERE reconnecting_pty_mins > 0) AS reconnecting_pty_template_ids, - array_agg(DISTINCT template_id) FILTER (WHERE vscode_mins > 0) AS vscode_template_ids, - array_agg(DISTINCT template_id) FILTER (WHERE jetbrains_mins > 0) AS jetbrains_template_ids - FROM - template_usage_stats - WHERE - start_time >= @start_time::timestamptz - AND end_time <= @end_time::timestamptz - AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - ) - */ - - type templateRow struct { - TemplateIDs []uuid.UUID - SSHTemplateIDs []uuid.UUID - SFTPTemplateIDs []uuid.UUID - ReconnectingPTYIDs []uuid.UUID - VSCodeTemplateIDs []uuid.UUID - JetBrainsTemplateIDs []uuid.UUID - } - templates := templateRow{} - for _, stat := range q.templateUsageStats { - if stat.StartTime.Before(arg.StartTime) || stat.EndTime.After(arg.EndTime) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, stat.TemplateID) { - continue - } - templates.TemplateIDs = append(templates.TemplateIDs, stat.TemplateID) - if stat.SshMins > 0 { - templates.SSHTemplateIDs = append(templates.SSHTemplateIDs, stat.TemplateID) - } - if stat.SftpMins > 0 { - templates.SFTPTemplateIDs = append(templates.SFTPTemplateIDs, stat.TemplateID) - } - if stat.ReconnectingPtyMins > 0 { - templates.ReconnectingPTYIDs = append(templates.ReconnectingPTYIDs, stat.TemplateID) - } - if stat.VscodeMins > 0 { - templates.VSCodeTemplateIDs = append(templates.VSCodeTemplateIDs, stat.TemplateID) - } - if stat.JetbrainsMins > 0 { - templates.JetBrainsTemplateIDs = append(templates.JetBrainsTemplateIDs, stat.TemplateID) - } - } - - /* - SELECT - COALESCE((SELECT template_ids FROM templates), '{}')::uuid[] AS template_ids, -- Includes app usage. - COALESCE((SELECT ssh_template_ids FROM templates), '{}')::uuid[] AS ssh_template_ids, - COALESCE((SELECT sftp_template_ids FROM templates), '{}')::uuid[] AS sftp_template_ids, - COALESCE((SELECT reconnecting_pty_template_ids FROM templates), '{}')::uuid[] AS reconnecting_pty_template_ids, - COALESCE((SELECT vscode_template_ids FROM templates), '{}')::uuid[] AS vscode_template_ids, - COALESCE((SELECT jetbrains_template_ids FROM templates), '{}')::uuid[] AS jetbrains_template_ids, - COALESCE(COUNT(DISTINCT user_id), 0)::bigint AS active_users, -- Includes app usage. - COALESCE(SUM(usage_mins) * 60, 0)::bigint AS usage_total_seconds, -- Includes app usage. - COALESCE(SUM(ssh_mins) * 60, 0)::bigint AS usage_ssh_seconds, - COALESCE(SUM(sftp_mins) * 60, 0)::bigint AS usage_sftp_seconds, - COALESCE(SUM(reconnecting_pty_mins) * 60, 0)::bigint AS usage_reconnecting_pty_seconds, - COALESCE(SUM(vscode_mins) * 60, 0)::bigint AS usage_vscode_seconds, - COALESCE(SUM(jetbrains_mins) * 60, 0)::bigint AS usage_jetbrains_seconds - FROM - insights; - */ - - var row database.GetTemplateInsightsRow - row.TemplateIDs = uniqueSortedUUIDs(templates.TemplateIDs) - row.SshTemplateIds = uniqueSortedUUIDs(templates.SSHTemplateIDs) - row.SftpTemplateIds = uniqueSortedUUIDs(templates.SFTPTemplateIDs) - row.ReconnectingPtyTemplateIds = uniqueSortedUUIDs(templates.ReconnectingPTYIDs) - row.VscodeTemplateIds = uniqueSortedUUIDs(templates.VSCodeTemplateIDs) - row.JetbrainsTemplateIds = uniqueSortedUUIDs(templates.JetBrainsTemplateIDs) - activeUserIDs := make(map[uuid.UUID]struct{}) - for _, insight := range insights { - activeUserIDs[insight.UserID] = struct{}{} - row.UsageTotalSeconds += int64(insight.UsageMins) * 60 - row.UsageSshSeconds += int64(insight.SSHMins) * 60 - row.UsageSftpSeconds += int64(insight.SFTPMins) * 60 - row.UsageReconnectingPtySeconds += int64(insight.ReconnectingPTYMins) * 60 - row.UsageVscodeSeconds += int64(insight.VSCodeMins) * 60 - row.UsageJetbrainsSeconds += int64(insight.JetBrainsMins) * 60 - } - row.ActiveUsers = int64(len(activeUserIDs)) - - return row, nil -} - -func (q *FakeQuerier) GetTemplateInsightsByInterval(_ context.Context, arg database.GetTemplateInsightsByIntervalParams) ([]database.GetTemplateInsightsByIntervalRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - /* - WITH - ts AS ( - SELECT - d::timestamptz AS from_, - CASE - WHEN (d::timestamptz + (@interval_days::int || ' day')::interval) <= @end_time::timestamptz - THEN (d::timestamptz + (@interval_days::int || ' day')::interval) - ELSE @end_time::timestamptz - END AS to_ - FROM - -- Subtract 1 microsecond from end_time to avoid including the next interval in the results. - generate_series(@start_time::timestamptz, (@end_time::timestamptz) - '1 microsecond'::interval, (@interval_days::int || ' day')::interval) AS d - ) - - SELECT - ts.from_ AS start_time, - ts.to_ AS end_time, - array_remove(array_agg(DISTINCT tus.template_id), NULL)::uuid[] AS template_ids, - COUNT(DISTINCT tus.user_id) AS active_users - FROM - ts - LEFT JOIN - template_usage_stats AS tus - ON - tus.start_time >= ts.from_ - AND tus.end_time <= ts.to_ - AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN tus.template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - GROUP BY - ts.from_, ts.to_; - */ - - type interval struct { - From time.Time - To time.Time - } - var ts []interval - for d := arg.StartTime; d.Before(arg.EndTime); d = d.AddDate(0, 0, int(arg.IntervalDays)) { - to := d.AddDate(0, 0, int(arg.IntervalDays)) - if to.After(arg.EndTime) { - to = arg.EndTime - } - ts = append(ts, interval{From: d, To: to}) - } - - type grouped struct { - TemplateIDs map[uuid.UUID]struct{} - UserIDs map[uuid.UUID]struct{} - } - groupedByInterval := make(map[interval]grouped) - for _, tus := range q.templateUsageStats { - for _, t := range ts { - if tus.StartTime.Before(t.From) || tus.EndTime.After(t.To) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, tus.TemplateID) { - continue - } - g, ok := groupedByInterval[t] - if !ok { - g = grouped{ - TemplateIDs: make(map[uuid.UUID]struct{}), - UserIDs: make(map[uuid.UUID]struct{}), - } - } - g.TemplateIDs[tus.TemplateID] = struct{}{} - g.UserIDs[tus.UserID] = struct{}{} - groupedByInterval[t] = g - } - } - - var rows []database.GetTemplateInsightsByIntervalRow - for _, t := range ts { // Ordered by interval. - row := database.GetTemplateInsightsByIntervalRow{ - StartTime: t.From, - EndTime: t.To, - } - row.TemplateIDs = uniqueSortedUUIDs(maps.Keys(groupedByInterval[t].TemplateIDs)) - row.ActiveUsers = int64(len(groupedByInterval[t].UserIDs)) - rows = append(rows, row) - } - - return rows, nil -} - -func (q *FakeQuerier) GetTemplateInsightsByTemplate(_ context.Context, arg database.GetTemplateInsightsByTemplateParams) ([]database.GetTemplateInsightsByTemplateRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - // map time.Time x TemplateID x UserID x - appUsageByTemplateAndUser := map[time.Time]map[uuid.UUID]map[uuid.UUID]database.GetTemplateInsightsByTemplateRow{} - - // Review agent stats in terms of usage - templateIDSet := make(map[uuid.UUID]struct{}) - - for _, s := range q.workspaceAgentStats { - if s.CreatedAt.Before(arg.StartTime) || s.CreatedAt.Equal(arg.EndTime) || s.CreatedAt.After(arg.EndTime) { - continue - } - if s.ConnectionCount == 0 { - continue - } - - t := s.CreatedAt.Truncate(time.Minute) - templateIDSet[s.TemplateID] = struct{}{} - - if _, ok := appUsageByTemplateAndUser[t]; !ok { - appUsageByTemplateAndUser[t] = make(map[uuid.UUID]map[uuid.UUID]database.GetTemplateInsightsByTemplateRow) - } - - if _, ok := appUsageByTemplateAndUser[t][s.TemplateID]; !ok { - appUsageByTemplateAndUser[t][s.TemplateID] = make(map[uuid.UUID]database.GetTemplateInsightsByTemplateRow) - } - - if _, ok := appUsageByTemplateAndUser[t][s.TemplateID][s.UserID]; !ok { - appUsageByTemplateAndUser[t][s.TemplateID][s.UserID] = database.GetTemplateInsightsByTemplateRow{} - } - - u := appUsageByTemplateAndUser[t][s.TemplateID][s.UserID] - if s.SessionCountJetBrains > 0 { - u.UsageJetbrainsSeconds = 60 - } - if s.SessionCountVSCode > 0 { - u.UsageVscodeSeconds = 60 - } - if s.SessionCountReconnectingPTY > 0 { - u.UsageReconnectingPtySeconds = 60 - } - if s.SessionCountSSH > 0 { - u.UsageSshSeconds = 60 - } - appUsageByTemplateAndUser[t][s.TemplateID][s.UserID] = u - } - - // Sort used templates - templateIDs := make([]uuid.UUID, 0, len(templateIDSet)) - for templateID := range templateIDSet { - templateIDs = append(templateIDs, templateID) - } - slices.SortFunc(templateIDs, func(a, b uuid.UUID) int { - return slice.Ascending(a.String(), b.String()) - }) - - // Build result - var result []database.GetTemplateInsightsByTemplateRow - for _, templateID := range templateIDs { - r := database.GetTemplateInsightsByTemplateRow{ - TemplateID: templateID, - } - - uniqueUsers := map[uuid.UUID]struct{}{} - - for _, mTemplateUserUsage := range appUsageByTemplateAndUser { - mUserUsage, ok := mTemplateUserUsage[templateID] - if !ok { - continue // template was not used in this time window - } - - for userID, usage := range mUserUsage { - uniqueUsers[userID] = struct{}{} - - r.UsageJetbrainsSeconds += usage.UsageJetbrainsSeconds - r.UsageVscodeSeconds += usage.UsageVscodeSeconds - r.UsageReconnectingPtySeconds += usage.UsageReconnectingPtySeconds - r.UsageSshSeconds += usage.UsageSshSeconds - } - } - - r.ActiveUsers = int64(len(uniqueUsers)) - - result = append(result, r) - } - return result, nil -} - -func (q *FakeQuerier) GetTemplateParameterInsights(ctx context.Context, arg database.GetTemplateParameterInsightsParams) ([]database.GetTemplateParameterInsightsRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - // WITH latest_workspace_builds ... - latestWorkspaceBuilds := make(map[uuid.UUID]database.WorkspaceBuild) - for _, wb := range q.workspaceBuilds { - if wb.CreatedAt.Before(arg.StartTime) || wb.CreatedAt.Equal(arg.EndTime) || wb.CreatedAt.After(arg.EndTime) { - continue - } - if latestWorkspaceBuilds[wb.WorkspaceID].BuildNumber < wb.BuildNumber { - latestWorkspaceBuilds[wb.WorkspaceID] = wb - } - } - if len(arg.TemplateIDs) > 0 { - for wsID := range latestWorkspaceBuilds { - ws, err := q.getWorkspaceByIDNoLock(ctx, wsID) - if err != nil { - return nil, err - } - if slices.Contains(arg.TemplateIDs, ws.TemplateID) { - delete(latestWorkspaceBuilds, wsID) - } - } - } - // WITH unique_template_params ... - num := int64(0) - uniqueTemplateParams := make(map[string]*database.GetTemplateParameterInsightsRow) - uniqueTemplateParamWorkspaceBuildIDs := make(map[string][]uuid.UUID) - for _, wb := range latestWorkspaceBuilds { - tv, err := q.getTemplateVersionByIDNoLock(ctx, wb.TemplateVersionID) - if err != nil { - return nil, err - } - for _, tvp := range q.templateVersionParameters { - if tvp.TemplateVersionID != tv.ID { - continue - } - // GROUP BY tvp.name, tvp.type, tvp.display_name, tvp.description, tvp.options - key := fmt.Sprintf("%s:%s:%s:%s:%s", tvp.Name, tvp.Type, tvp.DisplayName, tvp.Description, tvp.Options) - if _, ok := uniqueTemplateParams[key]; !ok { - num++ - uniqueTemplateParams[key] = &database.GetTemplateParameterInsightsRow{ - Num: num, - Name: tvp.Name, - Type: tvp.Type, - DisplayName: tvp.DisplayName, - Description: tvp.Description, - Options: tvp.Options, - } - } - uniqueTemplateParams[key].TemplateIDs = append(uniqueTemplateParams[key].TemplateIDs, tv.TemplateID.UUID) - uniqueTemplateParamWorkspaceBuildIDs[key] = append(uniqueTemplateParamWorkspaceBuildIDs[key], wb.ID) - } - } - // SELECT ... - counts := make(map[string]map[string]int64) - for key, utp := range uniqueTemplateParams { - for _, wbp := range q.workspaceBuildParameters { - if !slices.Contains(uniqueTemplateParamWorkspaceBuildIDs[key], wbp.WorkspaceBuildID) { - continue - } - if wbp.Name != utp.Name { - continue - } - if counts[key] == nil { - counts[key] = make(map[string]int64) - } - counts[key][wbp.Value]++ - } - } - - var rows []database.GetTemplateParameterInsightsRow - for key, utp := range uniqueTemplateParams { - for value, count := range counts[key] { - rows = append(rows, database.GetTemplateParameterInsightsRow{ - Num: utp.Num, - TemplateIDs: uniqueSortedUUIDs(utp.TemplateIDs), - Name: utp.Name, - DisplayName: utp.DisplayName, - Type: utp.Type, - Description: utp.Description, - Options: utp.Options, - Value: value, - Count: count, - }) - } - } - - // NOTE(mafredri): Add sorting if we decide on how to handle PostgreSQL collations. - // ORDER BY utp.name, utp.type, utp.display_name, utp.description, utp.options, wbp.value - return rows, nil -} - -func (*FakeQuerier) GetTemplatePresetsWithPrebuilds(_ context.Context, _ uuid.NullUUID) ([]database.GetTemplatePresetsWithPrebuildsRow, error) { - return nil, ErrUnimplemented -} - -func (q *FakeQuerier) GetTemplateUsageStats(_ context.Context, arg database.GetTemplateUsageStatsParams) ([]database.TemplateUsageStat, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - var stats []database.TemplateUsageStat - for _, stat := range q.templateUsageStats { - // Exclude all chunks that don't fall exactly within the range. - if stat.StartTime.Before(arg.StartTime) || stat.EndTime.After(arg.EndTime) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, stat.TemplateID) { - continue - } - stats = append(stats, stat) - } - - if len(stats) == 0 { - return nil, sql.ErrNoRows - } - - return stats, nil -} - -func (q *FakeQuerier) GetTemplateVersionByID(ctx context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getTemplateVersionByIDNoLock(ctx, templateVersionID) -} - -func (q *FakeQuerier) GetTemplateVersionByJobID(_ context.Context, jobID uuid.UUID) (database.TemplateVersion, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, templateVersion := range q.templateVersions { - if templateVersion.JobID != jobID { - continue - } - return q.templateVersionWithUserNoLock(templateVersion), nil - } - return database.TemplateVersion{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetTemplateVersionByTemplateIDAndName(_ context.Context, arg database.GetTemplateVersionByTemplateIDAndNameParams) (database.TemplateVersion, error) { - if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersion{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, templateVersion := range q.templateVersions { - if templateVersion.TemplateID != arg.TemplateID { - continue - } - if !strings.EqualFold(templateVersion.Name, arg.Name) { - continue - } - return q.templateVersionWithUserNoLock(templateVersion), nil - } - return database.TemplateVersion{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetTemplateVersionParameters(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionParameter, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - parameters := make([]database.TemplateVersionParameter, 0) - for _, param := range q.templateVersionParameters { - if param.TemplateVersionID != templateVersionID { - continue - } - parameters = append(parameters, param) - } - sort.Slice(parameters, func(i, j int) bool { - if parameters[i].DisplayOrder != parameters[j].DisplayOrder { - return parameters[i].DisplayOrder < parameters[j].DisplayOrder - } - return strings.ToLower(parameters[i].Name) < strings.ToLower(parameters[j].Name) - }) - return parameters, nil -} - -func (q *FakeQuerier) GetTemplateVersionTerraformValues(ctx context.Context, templateVersionID uuid.UUID) (database.TemplateVersionTerraformValue, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, tvtv := range q.templateVersionTerraformValues { - if tvtv.TemplateVersionID == templateVersionID { - return tvtv, nil - } - } - - return database.TemplateVersionTerraformValue{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetTemplateVersionVariables(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionVariable, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - variables := make([]database.TemplateVersionVariable, 0) - for _, variable := range q.templateVersionVariables { - if variable.TemplateVersionID != templateVersionID { - continue - } - variables = append(variables, variable) - } - return variables, nil -} - -func (q *FakeQuerier) GetTemplateVersionWorkspaceTags(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionWorkspaceTag, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaceTags := make([]database.TemplateVersionWorkspaceTag, 0) - for _, workspaceTag := range q.templateVersionWorkspaceTags { - if workspaceTag.TemplateVersionID != templateVersionID { - continue - } - workspaceTags = append(workspaceTags, workspaceTag) - } - - sort.Slice(workspaceTags, func(i, j int) bool { - return workspaceTags[i].Key < workspaceTags[j].Key - }) - return workspaceTags, nil -} - -func (q *FakeQuerier) GetTemplateVersionsByIDs(_ context.Context, ids []uuid.UUID) ([]database.TemplateVersion, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - versions := make([]database.TemplateVersion, 0) - for _, version := range q.templateVersions { - for _, id := range ids { - if id == version.ID { - versions = append(versions, q.templateVersionWithUserNoLock(version)) - break - } - } - } - if len(versions) == 0 { - return nil, sql.ErrNoRows - } - - return versions, nil -} - -func (q *FakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg database.GetTemplateVersionsByTemplateIDParams) (version []database.TemplateVersion, err error) { - if err := validateDatabaseType(arg); err != nil { - return version, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, templateVersion := range q.templateVersions { - if templateVersion.TemplateID.UUID != arg.TemplateID { - continue - } - if arg.Archived.Valid && arg.Archived.Bool != templateVersion.Archived { - continue - } - version = append(version, q.templateVersionWithUserNoLock(templateVersion)) - } - - // Database orders by created_at - slices.SortFunc(version, func(a, b database.TemplateVersion) int { - if a.CreatedAt.Equal(b.CreatedAt) { - // Technically the postgres database also orders by uuid. So match - // that behavior - return slice.Ascending(a.ID.String(), b.ID.String()) - } - if a.CreatedAt.Before(b.CreatedAt) { - return -1 - } - return 1 - }) - - if arg.AfterID != uuid.Nil { - found := false - for i, v := range version { - if v.ID == arg.AfterID { - // We want to return all users after index i. - version = version[i+1:] - found = true - break - } - } - - // If no users after the time, then we return an empty list. - if !found { - return nil, sql.ErrNoRows - } - } - - if arg.OffsetOpt > 0 { - if int(arg.OffsetOpt) > len(version)-1 { - return nil, sql.ErrNoRows - } - version = version[arg.OffsetOpt:] - } - - if arg.LimitOpt > 0 { - if int(arg.LimitOpt) > len(version) { - // #nosec G115 - Safe conversion as version slice length is expected to be within int32 range - arg.LimitOpt = int32(len(version)) - } - version = version[:arg.LimitOpt] - } - - if len(version) == 0 { - return nil, sql.ErrNoRows - } - - return version, nil -} - -func (q *FakeQuerier) GetTemplateVersionsCreatedAfter(_ context.Context, after time.Time) ([]database.TemplateVersion, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - versions := make([]database.TemplateVersion, 0) - for _, version := range q.templateVersions { - if version.CreatedAt.After(after) { - versions = append(versions, q.templateVersionWithUserNoLock(version)) - } - } - return versions, nil -} - -func (q *FakeQuerier) GetTemplates(_ context.Context) ([]database.Template, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - templates := slices.Clone(q.templates) - slices.SortFunc(templates, func(a, b database.TemplateTable) int { - if a.Name != b.Name { - return slice.Ascending(a.Name, b.Name) - } - return slice.Ascending(a.ID.String(), b.ID.String()) - }) - - return q.templatesWithUserNoLock(templates), nil -} - -func (q *FakeQuerier) GetTemplatesWithFilter(ctx context.Context, arg database.GetTemplatesWithFilterParams) ([]database.Template, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - return q.GetAuthorizedTemplates(ctx, arg, nil) -} - -func (q *FakeQuerier) GetUnexpiredLicenses(_ context.Context) ([]database.License, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - now := time.Now() - var results []database.License - for _, l := range q.licenses { - if l.Exp.After(now) { - results = append(results, l) - } - } - sort.Slice(results, func(i, j int) bool { return results[i].ID < results[j].ID }) - return results, nil -} - -func (q *FakeQuerier) GetUserActivityInsights(_ context.Context, arg database.GetUserActivityInsightsParams) ([]database.GetUserActivityInsightsRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - /* - WITH - */ - /* - deployment_stats AS ( - SELECT - start_time, - user_id, - array_agg(template_id) AS template_ids, - -- See motivation in GetTemplateInsights for LEAST(SUM(n), 30). - LEAST(SUM(usage_mins), 30) AS usage_mins - FROM - template_usage_stats - WHERE - start_time >= @start_time::timestamptz - AND end_time <= @end_time::timestamptz - AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - GROUP BY - start_time, user_id - ), - */ - - type deploymentStatsGroupBy struct { - StartTime time.Time - UserID uuid.UUID - } - type deploymentStatsRow struct { - deploymentStatsGroupBy - TemplateIDs []uuid.UUID - UsageMins int16 - } - deploymentStatsRows := make(map[deploymentStatsGroupBy]deploymentStatsRow) - for _, stat := range q.templateUsageStats { - if stat.StartTime.Before(arg.StartTime) || stat.EndTime.After(arg.EndTime) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, stat.TemplateID) { - continue - } - key := deploymentStatsGroupBy{ - StartTime: stat.StartTime, - UserID: stat.UserID, - } - row, ok := deploymentStatsRows[key] - if !ok { - row = deploymentStatsRow{ - deploymentStatsGroupBy: key, - } - } - row.TemplateIDs = append(row.TemplateIDs, stat.TemplateID) - row.UsageMins = least(row.UsageMins+stat.UsageMins, 30) - deploymentStatsRows[key] = row - } - - /* - template_ids AS ( - SELECT - user_id, - array_agg(DISTINCT template_id) AS ids - FROM - deployment_stats, unnest(template_ids) template_id - GROUP BY - user_id - ) - */ - - type templateIDsRow struct { - UserID uuid.UUID - TemplateIDs []uuid.UUID - } - templateIDs := make(map[uuid.UUID]templateIDsRow) - for _, dsRow := range deploymentStatsRows { - row, ok := templateIDs[dsRow.UserID] - if !ok { - row = templateIDsRow{ - UserID: row.UserID, - } - } - row.TemplateIDs = uniqueSortedUUIDs(append(row.TemplateIDs, dsRow.TemplateIDs...)) - templateIDs[dsRow.UserID] = row - } - - /* - SELECT - ds.user_id, - u.username, - u.avatar_url, - t.ids::uuid[] AS template_ids, - (SUM(ds.usage_mins) * 60)::bigint AS usage_seconds - FROM - deployment_stats ds - JOIN - users u - ON - u.id = ds.user_id - JOIN - template_ids t - ON - ds.user_id = t.user_id - GROUP BY - ds.user_id, u.username, u.avatar_url, t.ids - ORDER BY - ds.user_id ASC; - */ - - var rows []database.GetUserActivityInsightsRow - groupedRows := make(map[uuid.UUID]database.GetUserActivityInsightsRow) - for _, dsRow := range deploymentStatsRows { - row, ok := groupedRows[dsRow.UserID] - if !ok { - user, err := q.getUserByIDNoLock(dsRow.UserID) - if err != nil { - return nil, err - } - row = database.GetUserActivityInsightsRow{ - UserID: user.ID, - Username: user.Username, - AvatarURL: user.AvatarURL, - TemplateIDs: templateIDs[user.ID].TemplateIDs, - } - } - row.UsageSeconds += int64(dsRow.UsageMins) * 60 - groupedRows[dsRow.UserID] = row - } - for _, row := range groupedRows { - rows = append(rows, row) - } - if len(rows) == 0 { - return nil, sql.ErrNoRows - } - slices.SortFunc(rows, func(a, b database.GetUserActivityInsightsRow) int { - return slice.Ascending(a.UserID.String(), b.UserID.String()) - }) - - return rows, nil -} - -func (q *FakeQuerier) GetUserByEmailOrUsername(_ context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, user := range q.users { - if !user.Deleted && (strings.EqualFold(user.Email, arg.Email) || strings.EqualFold(user.Username, arg.Username)) { - return user, nil - } - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetUserByID(_ context.Context, id uuid.UUID) (database.User, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getUserByIDNoLock(id) -} - -// nolint:revive // It's not a control flag, it's a filter. -func (q *FakeQuerier) GetUserCount(_ context.Context, includeSystem bool) (int64, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - existing := int64(0) - for _, u := range q.users { - if !includeSystem && u.IsSystem { - continue - } - if !u.Deleted { - existing++ - } - - if !includeSystem && u.IsSystem { - continue - } - } - return existing, nil -} - -func (q *FakeQuerier) GetUserLatencyInsights(_ context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - /* - SELECT - tus.user_id, - u.username, - u.avatar_url, - array_agg(DISTINCT tus.template_id)::uuid[] AS template_ids, - COALESCE((PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY tus.median_latency_ms)), -1)::float AS workspace_connection_latency_50, - COALESCE((PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY tus.median_latency_ms)), -1)::float AS workspace_connection_latency_95 - FROM - template_usage_stats tus - JOIN - users u - ON - u.id = tus.user_id - WHERE - tus.start_time >= @start_time::timestamptz - AND tus.end_time <= @end_time::timestamptz - AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN tus.template_id = ANY(@template_ids::uuid[]) ELSE TRUE END - GROUP BY - tus.user_id, u.username, u.avatar_url - ORDER BY - tus.user_id ASC; - */ - - latenciesByUserID := make(map[uuid.UUID][]float64) - seenTemplatesByUserID := make(map[uuid.UUID][]uuid.UUID) - for _, stat := range q.templateUsageStats { - if stat.StartTime.Before(arg.StartTime) || stat.EndTime.After(arg.EndTime) { - continue - } - if len(arg.TemplateIDs) > 0 && !slices.Contains(arg.TemplateIDs, stat.TemplateID) { - continue - } - - if stat.MedianLatencyMs.Valid { - latenciesByUserID[stat.UserID] = append(latenciesByUserID[stat.UserID], stat.MedianLatencyMs.Float64) - } - seenTemplatesByUserID[stat.UserID] = uniqueSortedUUIDs(append(seenTemplatesByUserID[stat.UserID], stat.TemplateID)) - } - - var rows []database.GetUserLatencyInsightsRow - for userID, latencies := range latenciesByUserID { - user, err := q.getUserByIDNoLock(userID) - if err != nil { - return nil, err - } - row := database.GetUserLatencyInsightsRow{ - UserID: userID, - Username: user.Username, - AvatarURL: user.AvatarURL, - TemplateIDs: seenTemplatesByUserID[userID], - WorkspaceConnectionLatency50: tryPercentileCont(latencies, 50), - WorkspaceConnectionLatency95: tryPercentileCont(latencies, 95), - } - rows = append(rows, row) - } - slices.SortFunc(rows, func(a, b database.GetUserLatencyInsightsRow) int { - return slice.Ascending(a.UserID.String(), b.UserID.String()) - }) - - return rows, nil -} - -func (q *FakeQuerier) GetUserLinkByLinkedID(_ context.Context, id string) (database.UserLink, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, link := range q.userLinks { - user, err := q.getUserByIDNoLock(link.UserID) - if err == nil && user.Deleted { - continue - } - if link.LinkedID == id { - return link, nil - } - } - return database.UserLink{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetUserLinkByUserIDLoginType(_ context.Context, params database.GetUserLinkByUserIDLoginTypeParams) (database.UserLink, error) { - if err := validateDatabaseType(params); err != nil { - return database.UserLink{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, link := range q.userLinks { - if link.UserID == params.UserID && link.LoginType == params.LoginType { - return link, nil - } - } - return database.UserLink{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetUserLinksByUserID(_ context.Context, userID uuid.UUID) ([]database.UserLink, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - uls := make([]database.UserLink, 0) - for _, ul := range q.userLinks { - if ul.UserID == userID { - uls = append(uls, ul) - } - } - return uls, nil -} - -func (q *FakeQuerier) GetUserNotificationPreferences(_ context.Context, userID uuid.UUID) ([]database.NotificationPreference, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - out := make([]database.NotificationPreference, 0, len(q.notificationPreferences)) - for _, np := range q.notificationPreferences { - if np.UserID != userID { - continue - } - - out = append(out, np) - } - - return out, nil -} - -func (q *FakeQuerier) GetUserStatusCounts(_ context.Context, arg database.GetUserStatusCountsParams) ([]database.GetUserStatusCountsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - result := make([]database.GetUserStatusCountsRow, 0) - for _, change := range q.userStatusChanges { - if change.ChangedAt.Before(arg.StartTime) || change.ChangedAt.After(arg.EndTime) { - continue - } - date := time.Date(change.ChangedAt.Year(), change.ChangedAt.Month(), change.ChangedAt.Day(), 0, 0, 0, 0, time.UTC) - if !slices.ContainsFunc(result, func(r database.GetUserStatusCountsRow) bool { - return r.Status == change.NewStatus && r.Date.Equal(date) - }) { - result = append(result, database.GetUserStatusCountsRow{ - Status: change.NewStatus, - Date: date, - Count: 1, - }) - } else { - for i, r := range result { - if r.Status == change.NewStatus && r.Date.Equal(date) { - result[i].Count++ - break - } - } - } - } - - return result, nil -} - -func (q *FakeQuerier) GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, uc := range q.userConfigs { - if uc.UserID != userID || uc.Key != "terminal_font" { - continue - } - return uc.Value, nil - } - - return "", sql.ErrNoRows -} - -func (q *FakeQuerier) GetUserThemePreference(_ context.Context, userID uuid.UUID) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, uc := range q.userConfigs { - if uc.UserID != userID || uc.Key != "theme_preference" { - continue - } - return uc.Value, nil - } - - return "", sql.ErrNoRows -} - -func (q *FakeQuerier) GetUserWorkspaceBuildParameters(_ context.Context, params database.GetUserWorkspaceBuildParametersParams) ([]database.GetUserWorkspaceBuildParametersRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - userWorkspaceIDs := make(map[uuid.UUID]struct{}) - for _, ws := range q.workspaces { - if ws.OwnerID != params.OwnerID { - continue - } - if ws.TemplateID != params.TemplateID { - continue - } - userWorkspaceIDs[ws.ID] = struct{}{} - } - - userWorkspaceBuilds := make(map[uuid.UUID]struct{}) - for _, wb := range q.workspaceBuilds { - if _, ok := userWorkspaceIDs[wb.WorkspaceID]; !ok { - continue - } - userWorkspaceBuilds[wb.ID] = struct{}{} - } - - templateVersions := make(map[uuid.UUID]struct{}) - for _, tv := range q.templateVersions { - if tv.TemplateID.UUID != params.TemplateID { - continue - } - templateVersions[tv.ID] = struct{}{} - } - - tvps := make(map[string]struct{}) - for _, tvp := range q.templateVersionParameters { - if _, ok := templateVersions[tvp.TemplateVersionID]; !ok { - continue - } - - if _, ok := tvps[tvp.Name]; !ok && !tvp.Ephemeral { - tvps[tvp.Name] = struct{}{} - } - } - - userWorkspaceBuildParameters := make(map[string]database.GetUserWorkspaceBuildParametersRow) - for _, wbp := range q.workspaceBuildParameters { - if _, ok := userWorkspaceBuilds[wbp.WorkspaceBuildID]; !ok { - continue - } - if _, ok := tvps[wbp.Name]; !ok { - continue - } - userWorkspaceBuildParameters[wbp.Name] = database.GetUserWorkspaceBuildParametersRow{ - Name: wbp.Name, - Value: wbp.Value, - } - } - - return maps.Values(userWorkspaceBuildParameters), nil -} - -func (q *FakeQuerier) GetUsers(_ context.Context, params database.GetUsersParams) ([]database.GetUsersRow, error) { - if err := validateDatabaseType(params); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - // Avoid side-effect of sorting. - users := make([]database.User, len(q.users)) - copy(users, q.users) - - // Database orders by username - slices.SortFunc(users, func(a, b database.User) int { - return slice.Ascending(strings.ToLower(a.Username), strings.ToLower(b.Username)) - }) - - // Filter out deleted since they should never be returned.. - tmp := make([]database.User, 0, len(users)) - for _, user := range users { - if !user.Deleted { - tmp = append(tmp, user) - } - } - users = tmp - - if params.AfterID != uuid.Nil { - found := false - for i, v := range users { - if v.ID == params.AfterID { - // We want to return all users after index i. - users = users[i+1:] - found = true - break - } - } - - // If no users after the time, then we return an empty list. - if !found { - return []database.GetUsersRow{}, nil - } - } - - if params.Search != "" { - tmp := make([]database.User, 0, len(users)) - for i, user := range users { - if strings.Contains(strings.ToLower(user.Email), strings.ToLower(params.Search)) { - tmp = append(tmp, users[i]) - } else if strings.Contains(strings.ToLower(user.Username), strings.ToLower(params.Search)) { - tmp = append(tmp, users[i]) - } - } - users = tmp - } - - if len(params.Status) > 0 { - usersFilteredByStatus := make([]database.User, 0, len(users)) - for i, user := range users { - if slice.ContainsCompare(params.Status, user.Status, func(a, b database.UserStatus) bool { - return strings.EqualFold(string(a), string(b)) - }) { - usersFilteredByStatus = append(usersFilteredByStatus, users[i]) - } - } - users = usersFilteredByStatus - } - - if len(params.RbacRole) > 0 && !slice.Contains(params.RbacRole, rbac.RoleMember().String()) { - usersFilteredByRole := make([]database.User, 0, len(users)) - for i, user := range users { - if slice.OverlapCompare(params.RbacRole, user.RBACRoles, strings.EqualFold) { - usersFilteredByRole = append(usersFilteredByRole, users[i]) - } - } - users = usersFilteredByRole - } - - if len(params.LoginType) > 0 { - usersFilteredByLoginType := make([]database.User, 0, len(users)) - for i, user := range users { - if slice.ContainsCompare(params.LoginType, user.LoginType, func(a, b database.LoginType) bool { - return strings.EqualFold(string(a), string(b)) - }) { - usersFilteredByLoginType = append(usersFilteredByLoginType, users[i]) - } - } - users = usersFilteredByLoginType - } - - if !params.CreatedBefore.IsZero() { - usersFilteredByCreatedAt := make([]database.User, 0, len(users)) - for i, user := range users { - if user.CreatedAt.Before(params.CreatedBefore) { - usersFilteredByCreatedAt = append(usersFilteredByCreatedAt, users[i]) - } - } - users = usersFilteredByCreatedAt - } - - if !params.CreatedAfter.IsZero() { - usersFilteredByCreatedAt := make([]database.User, 0, len(users)) - for i, user := range users { - if user.CreatedAt.After(params.CreatedAfter) { - usersFilteredByCreatedAt = append(usersFilteredByCreatedAt, users[i]) - } - } - users = usersFilteredByCreatedAt - } - - if !params.LastSeenBefore.IsZero() { - usersFilteredByLastSeen := make([]database.User, 0, len(users)) - for i, user := range users { - if user.LastSeenAt.Before(params.LastSeenBefore) { - usersFilteredByLastSeen = append(usersFilteredByLastSeen, users[i]) - } - } - users = usersFilteredByLastSeen - } - - if !params.LastSeenAfter.IsZero() { - usersFilteredByLastSeen := make([]database.User, 0, len(users)) - for i, user := range users { - if user.LastSeenAt.After(params.LastSeenAfter) { - usersFilteredByLastSeen = append(usersFilteredByLastSeen, users[i]) - } - } - users = usersFilteredByLastSeen - } - - if !params.IncludeSystem { - users = slices.DeleteFunc(users, func(u database.User) bool { - return u.IsSystem - }) - } - - if params.GithubComUserID != 0 { - usersFilteredByGithubComUserID := make([]database.User, 0, len(users)) - for i, user := range users { - if user.GithubComUserID.Int64 == params.GithubComUserID { - usersFilteredByGithubComUserID = append(usersFilteredByGithubComUserID, users[i]) - } - } - users = usersFilteredByGithubComUserID - } - - beforePageCount := len(users) - - if params.OffsetOpt > 0 { - if int(params.OffsetOpt) > len(users)-1 { - return []database.GetUsersRow{}, nil - } - users = users[params.OffsetOpt:] - } - - if params.LimitOpt > 0 { - if int(params.LimitOpt) > len(users) { - // #nosec G115 - Safe conversion as users slice length is expected to be within int32 range - params.LimitOpt = int32(len(users)) - } - users = users[:params.LimitOpt] - } - - return convertUsers(users, int64(beforePageCount)), nil -} - -func (q *FakeQuerier) GetUsersByIDs(_ context.Context, ids []uuid.UUID) ([]database.User, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - users := make([]database.User, 0) - for _, user := range q.users { - for _, id := range ids { - if user.ID != id { - continue - } - users = append(users, user) - } - } - return users, nil -} - -func (q *FakeQuerier) GetWebpushSubscriptionsByUserID(_ context.Context, userID uuid.UUID) ([]database.WebpushSubscription, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - out := make([]database.WebpushSubscription, 0) - for _, subscription := range q.webpushSubscriptions { - if subscription.UserID == userID { - out = append(out, subscription) - } - } - - return out, nil -} - -func (q *FakeQuerier) GetWebpushVAPIDKeys(_ context.Context) (database.GetWebpushVAPIDKeysRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if q.webpushVAPIDPublicKey == "" && q.webpushVAPIDPrivateKey == "" { - return database.GetWebpushVAPIDKeysRow{}, sql.ErrNoRows - } - - return database.GetWebpushVAPIDKeysRow{ - VapidPublicKey: q.webpushVAPIDPublicKey, - VapidPrivateKey: q.webpushVAPIDPrivateKey, - }, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(_ context.Context, authToken uuid.UUID) (database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - rows := []database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow{} - // We want to return the latest build number for each workspace - latestBuildNumber := make(map[uuid.UUID]int32) - - for _, agt := range q.workspaceAgents { - if agt.Deleted { - continue - } - - // get the related workspace and user - for _, res := range q.workspaceResources { - if agt.ResourceID != res.ID { - continue - } - for _, build := range q.workspaceBuilds { - if build.JobID != res.JobID { - continue - } - for _, ws := range q.workspaces { - if build.WorkspaceID != ws.ID { - continue - } - if ws.Deleted { - continue - } - row := database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow{ - WorkspaceTable: database.WorkspaceTable{ - ID: ws.ID, - TemplateID: ws.TemplateID, - }, - WorkspaceAgent: agt, - WorkspaceBuild: build, - } - usr, err := q.getUserByIDNoLock(ws.OwnerID) - if err != nil { - return database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow{}, sql.ErrNoRows - } - row.WorkspaceTable.OwnerID = usr.ID - - // Keep track of the latest build number - rows = append(rows, row) - if build.BuildNumber > latestBuildNumber[ws.ID] { - latestBuildNumber[ws.ID] = build.BuildNumber - } - } - } - } - } - - for i := range rows { - if rows[i].WorkspaceAgent.AuthToken != authToken { - continue - } - - if rows[i].WorkspaceBuild.BuildNumber != latestBuildNumber[rows[i].WorkspaceTable.ID] { - continue - } - - return rows[i], nil - } - - return database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (database.WorkspaceAgent, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceAgentByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetWorkspaceAgentByInstanceID(_ context.Context, instanceID string) (database.WorkspaceAgent, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - // The schema sorts this by created at, so we iterate the array backwards. - for i := len(q.workspaceAgents) - 1; i >= 0; i-- { - agent := q.workspaceAgents[i] - if !agent.Deleted && agent.AuthInstanceID.Valid && agent.AuthInstanceID.String == instanceID { - return agent, nil - } - } - return database.WorkspaceAgent{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceAgentDevcontainersByAgentID(_ context.Context, workspaceAgentID uuid.UUID) ([]database.WorkspaceAgentDevcontainer, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - devcontainers := make([]database.WorkspaceAgentDevcontainer, 0) - for _, dc := range q.workspaceAgentDevcontainers { - if dc.WorkspaceAgentID == workspaceAgentID { - devcontainers = append(devcontainers, dc) - } - } - if len(devcontainers) == 0 { - return nil, sql.ErrNoRows - } - return devcontainers, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentLifecycleStateByID(ctx context.Context, id uuid.UUID) (database.GetWorkspaceAgentLifecycleStateByIDRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - agent, err := q.getWorkspaceAgentByIDNoLock(ctx, id) - if err != nil { - return database.GetWorkspaceAgentLifecycleStateByIDRow{}, err - } - return database.GetWorkspaceAgentLifecycleStateByIDRow{ - LifecycleState: agent.LifecycleState, - StartedAt: agent.StartedAt, - ReadyAt: agent.ReadyAt, - }, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentLogSourcesByAgentIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceAgentLogSource, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - logSources := make([]database.WorkspaceAgentLogSource, 0) - for _, logSource := range q.workspaceAgentLogSources { - for _, id := range ids { - if logSource.WorkspaceAgentID == id { - logSources = append(logSources, logSource) - break - } - } - } - return logSources, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentLogsAfter(_ context.Context, arg database.GetWorkspaceAgentLogsAfterParams) ([]database.WorkspaceAgentLog, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - logs := []database.WorkspaceAgentLog{} - for _, log := range q.workspaceAgentLogs { - if log.AgentID != arg.AgentID { - continue - } - if arg.CreatedAfter != 0 && log.ID <= arg.CreatedAfter { - continue - } - logs = append(logs, log) - } - return logs, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentMetadata(_ context.Context, arg database.GetWorkspaceAgentMetadataParams) ([]database.WorkspaceAgentMetadatum, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - metadata := make([]database.WorkspaceAgentMetadatum, 0) - for _, m := range q.workspaceAgentMetadata { - if m.WorkspaceAgentID == arg.WorkspaceAgentID { - if len(arg.Keys) > 0 && !slices.Contains(arg.Keys, m.Key) { - continue - } - metadata = append(metadata, m) - } - } - return metadata, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentPortShare(_ context.Context, arg database.GetWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceAgentPortShare{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, share := range q.workspaceAgentPortShares { - if share.WorkspaceID == arg.WorkspaceID && share.AgentName == arg.AgentName && share.Port == arg.Port { - return share, nil - } - } - - return database.WorkspaceAgentPortShare{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceAgentScriptTimingsByBuildID(ctx context.Context, id uuid.UUID) ([]database.GetWorkspaceAgentScriptTimingsByBuildIDRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - build, err := q.getWorkspaceBuildByIDNoLock(ctx, id) - if err != nil { - return nil, xerrors.Errorf("get build: %w", err) - } - - resources, err := q.getWorkspaceResourcesByJobIDNoLock(ctx, build.JobID) - if err != nil { - return nil, xerrors.Errorf("get resources: %w", err) - } - resourceIDs := make([]uuid.UUID, 0, len(resources)) - for _, res := range resources { - resourceIDs = append(resourceIDs, res.ID) - } - - agents, err := q.getWorkspaceAgentsByResourceIDsNoLock(ctx, resourceIDs) - if err != nil { - return nil, xerrors.Errorf("get agents: %w", err) - } - agentIDs := make([]uuid.UUID, 0, len(agents)) - for _, agent := range agents { - agentIDs = append(agentIDs, agent.ID) - } - - scripts, err := q.getWorkspaceAgentScriptsByAgentIDsNoLock(agentIDs) - if err != nil { - return nil, xerrors.Errorf("get scripts: %w", err) - } - scriptIDs := make([]uuid.UUID, 0, len(scripts)) - for _, script := range scripts { - scriptIDs = append(scriptIDs, script.ID) - } - - rows := []database.GetWorkspaceAgentScriptTimingsByBuildIDRow{} - for _, t := range q.workspaceAgentScriptTimings { - if !slice.Contains(scriptIDs, t.ScriptID) { - continue - } - - var script database.WorkspaceAgentScript - for _, s := range scripts { - if s.ID == t.ScriptID { - script = s - break - } - } - if script.ID == uuid.Nil { - return nil, xerrors.Errorf("script with ID %s not found", t.ScriptID) - } - - var agent database.WorkspaceAgent - for _, a := range agents { - if a.ID == script.WorkspaceAgentID { - agent = a - break - } - } - if agent.ID == uuid.Nil { - return nil, xerrors.Errorf("agent with ID %s not found", t.ScriptID) - } - - rows = append(rows, database.GetWorkspaceAgentScriptTimingsByBuildIDRow{ - ScriptID: t.ScriptID, - StartedAt: t.StartedAt, - EndedAt: t.EndedAt, - ExitCode: t.ExitCode, - Stage: t.Stage, - Status: t.Status, - DisplayName: script.DisplayName, - WorkspaceAgentID: agent.ID, - WorkspaceAgentName: agent.Name, - }) - } - - // We want to only return the first script run for each Script ID. - slices.SortFunc(rows, func(a, b database.GetWorkspaceAgentScriptTimingsByBuildIDRow) int { - return a.StartedAt.Compare(b.StartedAt) - }) - rows = slices.CompactFunc(rows, func(e1, e2 database.GetWorkspaceAgentScriptTimingsByBuildIDRow) bool { - return e1.ScriptID == e2.ScriptID - }) - - return rows, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentScriptsByAgentIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceAgentScript, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceAgentScriptsByAgentIDsNoLock(ids) -} - -func (q *FakeQuerier) GetWorkspaceAgentStats(_ context.Context, createdAfter time.Time) ([]database.GetWorkspaceAgentStatsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - agentStatsCreatedAfter := make([]database.WorkspaceAgentStat, 0) - for _, agentStat := range q.workspaceAgentStats { - if agentStat.CreatedAt.After(createdAfter) || agentStat.CreatedAt.Equal(createdAfter) { - agentStatsCreatedAfter = append(agentStatsCreatedAfter, agentStat) - } - } - - latestAgentStats := map[uuid.UUID]database.WorkspaceAgentStat{} - for _, agentStat := range q.workspaceAgentStats { - if agentStat.CreatedAt.After(createdAfter) || agentStat.CreatedAt.Equal(createdAfter) { - latestAgentStats[agentStat.AgentID] = agentStat - } - } - - statByAgent := map[uuid.UUID]database.GetWorkspaceAgentStatsRow{} - for agentID, agentStat := range latestAgentStats { - stat := statByAgent[agentID] - stat.AgentID = agentStat.AgentID - stat.TemplateID = agentStat.TemplateID - stat.UserID = agentStat.UserID - stat.WorkspaceID = agentStat.WorkspaceID - stat.SessionCountVSCode += agentStat.SessionCountVSCode - stat.SessionCountJetBrains += agentStat.SessionCountJetBrains - stat.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - stat.SessionCountSSH += agentStat.SessionCountSSH - statByAgent[stat.AgentID] = stat - } - - latenciesByAgent := map[uuid.UUID][]float64{} - minimumDateByAgent := map[uuid.UUID]time.Time{} - for _, agentStat := range agentStatsCreatedAfter { - if agentStat.ConnectionMedianLatencyMS <= 0 { - continue - } - stat := statByAgent[agentStat.AgentID] - minimumDate := minimumDateByAgent[agentStat.AgentID] - if agentStat.CreatedAt.Before(minimumDate) || minimumDate.IsZero() { - minimumDateByAgent[agentStat.AgentID] = agentStat.CreatedAt - } - stat.WorkspaceRxBytes += agentStat.RxBytes - stat.WorkspaceTxBytes += agentStat.TxBytes - statByAgent[agentStat.AgentID] = stat - latenciesByAgent[agentStat.AgentID] = append(latenciesByAgent[agentStat.AgentID], agentStat.ConnectionMedianLatencyMS) - } - - for _, stat := range statByAgent { - stat.AggregatedFrom = minimumDateByAgent[stat.AgentID] - statByAgent[stat.AgentID] = stat - - latencies, ok := latenciesByAgent[stat.AgentID] - if !ok { - continue - } - stat.WorkspaceConnectionLatency50 = tryPercentileCont(latencies, 50) - stat.WorkspaceConnectionLatency95 = tryPercentileCont(latencies, 95) - statByAgent[stat.AgentID] = stat - } - - stats := make([]database.GetWorkspaceAgentStatsRow, 0, len(statByAgent)) - for _, agent := range statByAgent { - stats = append(stats, agent) - } - return stats, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentStatsAndLabels(ctx context.Context, createdAfter time.Time) ([]database.GetWorkspaceAgentStatsAndLabelsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - agentStatsCreatedAfter := make([]database.WorkspaceAgentStat, 0) - latestAgentStats := map[uuid.UUID]database.WorkspaceAgentStat{} - - for _, agentStat := range q.workspaceAgentStats { - if agentStat.CreatedAt.After(createdAfter) { - agentStatsCreatedAfter = append(agentStatsCreatedAfter, agentStat) - latestAgentStats[agentStat.AgentID] = agentStat - } - } - - statByAgent := map[uuid.UUID]database.GetWorkspaceAgentStatsAndLabelsRow{} - - // Session and connection metrics - for _, agentStat := range latestAgentStats { - stat := statByAgent[agentStat.AgentID] - stat.SessionCountVSCode += agentStat.SessionCountVSCode - stat.SessionCountJetBrains += agentStat.SessionCountJetBrains - stat.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - stat.SessionCountSSH += agentStat.SessionCountSSH - stat.ConnectionCount += agentStat.ConnectionCount - if agentStat.ConnectionMedianLatencyMS >= 0 && stat.ConnectionMedianLatencyMS < agentStat.ConnectionMedianLatencyMS { - stat.ConnectionMedianLatencyMS = agentStat.ConnectionMedianLatencyMS - } - statByAgent[agentStat.AgentID] = stat - } - - // Tx, Rx metrics - for _, agentStat := range agentStatsCreatedAfter { - stat := statByAgent[agentStat.AgentID] - stat.RxBytes += agentStat.RxBytes - stat.TxBytes += agentStat.TxBytes - statByAgent[agentStat.AgentID] = stat - } - - // Labels - for _, agentStat := range agentStatsCreatedAfter { - stat := statByAgent[agentStat.AgentID] - - user, err := q.getUserByIDNoLock(agentStat.UserID) - if err != nil { - return nil, err - } - - stat.Username = user.Username - - workspace, err := q.getWorkspaceByIDNoLock(ctx, agentStat.WorkspaceID) - if err != nil { - return nil, err - } - stat.WorkspaceName = workspace.Name - - agent, err := q.getWorkspaceAgentByIDNoLock(ctx, agentStat.AgentID) - if err != nil { - return nil, err - } - stat.AgentName = agent.Name - - statByAgent[agentStat.AgentID] = stat - } - - stats := make([]database.GetWorkspaceAgentStatsAndLabelsRow, 0, len(statByAgent)) - for _, agent := range statByAgent { - stats = append(stats, agent) - } - return stats, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentUsageStats(_ context.Context, createdAt time.Time) ([]database.GetWorkspaceAgentUsageStatsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - type agentStatsKey struct { - UserID uuid.UUID - AgentID uuid.UUID - WorkspaceID uuid.UUID - TemplateID uuid.UUID - } - - type minuteStatsKey struct { - agentStatsKey - MinuteBucket time.Time - } - - latestAgentStats := map[agentStatsKey]database.GetWorkspaceAgentUsageStatsRow{} - latestAgentLatencies := map[agentStatsKey][]float64{} - for _, agentStat := range q.workspaceAgentStats { - key := agentStatsKey{ - UserID: agentStat.UserID, - AgentID: agentStat.AgentID, - WorkspaceID: agentStat.WorkspaceID, - TemplateID: agentStat.TemplateID, - } - if agentStat.CreatedAt.After(createdAt) { - val, ok := latestAgentStats[key] - if ok { - val.WorkspaceRxBytes += agentStat.RxBytes - val.WorkspaceTxBytes += agentStat.TxBytes - latestAgentStats[key] = val - } else { - latestAgentStats[key] = database.GetWorkspaceAgentUsageStatsRow{ - UserID: agentStat.UserID, - AgentID: agentStat.AgentID, - WorkspaceID: agentStat.WorkspaceID, - TemplateID: agentStat.TemplateID, - AggregatedFrom: createdAt, - WorkspaceRxBytes: agentStat.RxBytes, - WorkspaceTxBytes: agentStat.TxBytes, - } - } - - latencies, ok := latestAgentLatencies[key] - if !ok { - latestAgentLatencies[key] = []float64{agentStat.ConnectionMedianLatencyMS} - } else { - latestAgentLatencies[key] = append(latencies, agentStat.ConnectionMedianLatencyMS) - } - } - } - - for key, latencies := range latestAgentLatencies { - val, ok := latestAgentStats[key] - if ok { - val.WorkspaceConnectionLatency50 = tryPercentileCont(latencies, 50) - val.WorkspaceConnectionLatency95 = tryPercentileCont(latencies, 95) - } - latestAgentStats[key] = val - } - - type bucketRow struct { - database.GetWorkspaceAgentUsageStatsRow - MinuteBucket time.Time - } - - minuteBuckets := make(map[minuteStatsKey]bucketRow) - for _, agentStat := range q.workspaceAgentStats { - if agentStat.Usage && - (agentStat.CreatedAt.After(createdAt) || agentStat.CreatedAt.Equal(createdAt)) && - agentStat.CreatedAt.Before(time.Now().Truncate(time.Minute)) { - key := minuteStatsKey{ - agentStatsKey: agentStatsKey{ - UserID: agentStat.UserID, - AgentID: agentStat.AgentID, - WorkspaceID: agentStat.WorkspaceID, - TemplateID: agentStat.TemplateID, - }, - MinuteBucket: agentStat.CreatedAt.Truncate(time.Minute), - } - val, ok := minuteBuckets[key] - if ok { - val.SessionCountVSCode += agentStat.SessionCountVSCode - val.SessionCountJetBrains += agentStat.SessionCountJetBrains - val.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - val.SessionCountSSH += agentStat.SessionCountSSH - minuteBuckets[key] = val - } else { - minuteBuckets[key] = bucketRow{ - GetWorkspaceAgentUsageStatsRow: database.GetWorkspaceAgentUsageStatsRow{ - UserID: agentStat.UserID, - AgentID: agentStat.AgentID, - WorkspaceID: agentStat.WorkspaceID, - TemplateID: agentStat.TemplateID, - SessionCountVSCode: agentStat.SessionCountVSCode, - SessionCountSSH: agentStat.SessionCountSSH, - SessionCountJetBrains: agentStat.SessionCountJetBrains, - SessionCountReconnectingPTY: agentStat.SessionCountReconnectingPTY, - }, - MinuteBucket: agentStat.CreatedAt.Truncate(time.Minute), - } - } - } - } - - // Get the latest minute bucket for each agent. - latestBuckets := make(map[uuid.UUID]bucketRow) - for key, bucket := range minuteBuckets { - latest, ok := latestBuckets[key.AgentID] - if !ok || key.MinuteBucket.After(latest.MinuteBucket) { - latestBuckets[key.AgentID] = bucket - } - } - - for key, stat := range latestAgentStats { - bucket, ok := latestBuckets[stat.AgentID] - if ok { - stat.SessionCountVSCode = bucket.SessionCountVSCode - stat.SessionCountJetBrains = bucket.SessionCountJetBrains - stat.SessionCountReconnectingPTY = bucket.SessionCountReconnectingPTY - stat.SessionCountSSH = bucket.SessionCountSSH - } - latestAgentStats[key] = stat - } - return maps.Values(latestAgentStats), nil -} - -func (q *FakeQuerier) GetWorkspaceAgentUsageStatsAndLabels(_ context.Context, createdAt time.Time) ([]database.GetWorkspaceAgentUsageStatsAndLabelsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - type statsKey struct { - AgentID uuid.UUID - UserID uuid.UUID - WorkspaceID uuid.UUID - } - - latestAgentStats := map[statsKey]database.WorkspaceAgentStat{} - maxConnMedianLatency := 0.0 - for _, agentStat := range q.workspaceAgentStats { - key := statsKey{ - AgentID: agentStat.AgentID, - UserID: agentStat.UserID, - WorkspaceID: agentStat.WorkspaceID, - } - // WHERE workspace_agent_stats.created_at > $1 - // GROUP BY user_id, agent_id, workspace_id - if agentStat.CreatedAt.After(createdAt) { - val, ok := latestAgentStats[key] - if !ok { - val = agentStat - val.SessionCountJetBrains = 0 - val.SessionCountReconnectingPTY = 0 - val.SessionCountSSH = 0 - val.SessionCountVSCode = 0 - } else { - val.RxBytes += agentStat.RxBytes - val.TxBytes += agentStat.TxBytes - } - if agentStat.ConnectionMedianLatencyMS > maxConnMedianLatency { - val.ConnectionMedianLatencyMS = agentStat.ConnectionMedianLatencyMS - } - latestAgentStats[key] = val - } - // WHERE usage = true AND created_at > now() - '1 minute'::interval - // GROUP BY user_id, agent_id, workspace_id - if agentStat.Usage && agentStat.CreatedAt.After(dbtime.Now().Add(-time.Minute)) { - val, ok := latestAgentStats[key] - if !ok { - latestAgentStats[key] = agentStat - } else { - val.SessionCountVSCode += agentStat.SessionCountVSCode - val.SessionCountJetBrains += agentStat.SessionCountJetBrains - val.SessionCountReconnectingPTY += agentStat.SessionCountReconnectingPTY - val.SessionCountSSH += agentStat.SessionCountSSH - val.ConnectionCount += agentStat.ConnectionCount - latestAgentStats[key] = val - } - } - } - - stats := make([]database.GetWorkspaceAgentUsageStatsAndLabelsRow, 0, len(latestAgentStats)) - for key, agentStat := range latestAgentStats { - user, err := q.getUserByIDNoLock(key.UserID) - if err != nil { - return nil, err - } - workspace, err := q.getWorkspaceByIDNoLock(context.Background(), key.WorkspaceID) - if err != nil { - return nil, err - } - agent, err := q.getWorkspaceAgentByIDNoLock(context.Background(), key.AgentID) - if err != nil { - return nil, err - } - stats = append(stats, database.GetWorkspaceAgentUsageStatsAndLabelsRow{ - Username: user.Username, - AgentName: agent.Name, - WorkspaceName: workspace.Name, - RxBytes: agentStat.RxBytes, - TxBytes: agentStat.TxBytes, - SessionCountVSCode: agentStat.SessionCountVSCode, - SessionCountSSH: agentStat.SessionCountSSH, - SessionCountJetBrains: agentStat.SessionCountJetBrains, - SessionCountReconnectingPTY: agentStat.SessionCountReconnectingPTY, - ConnectionCount: agentStat.ConnectionCount, - ConnectionMedianLatencyMS: agentStat.ConnectionMedianLatencyMS, - }) - } - return stats, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentsByParentID(_ context.Context, parentID uuid.UUID) ([]database.WorkspaceAgent, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaceAgents := make([]database.WorkspaceAgent, 0) - for _, agent := range q.workspaceAgents { - if !agent.ParentID.Valid || agent.ParentID.UUID != parentID || agent.Deleted { - continue - } - - workspaceAgents = append(workspaceAgents, agent) - } - - return workspaceAgents, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, resourceIDs []uuid.UUID) ([]database.WorkspaceAgent, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceAgentsByResourceIDsNoLock(ctx, resourceIDs) -} - -func (q *FakeQuerier) GetWorkspaceAgentsByWorkspaceAndBuildNumber(ctx context.Context, arg database.GetWorkspaceAgentsByWorkspaceAndBuildNumberParams) ([]database.WorkspaceAgent, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - build, err := q.GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx, database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams(arg)) - if err != nil { - return nil, err - } - - resources, err := q.getWorkspaceResourcesByJobIDNoLock(ctx, build.JobID) - if err != nil { - return nil, err - } - - var resourceIDs []uuid.UUID - for _, resource := range resources { - resourceIDs = append(resourceIDs, resource.ID) - } - - return q.GetWorkspaceAgentsByResourceIDs(ctx, resourceIDs) -} - -func (q *FakeQuerier) GetWorkspaceAgentsCreatedAfter(_ context.Context, after time.Time) ([]database.WorkspaceAgent, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaceAgents := make([]database.WorkspaceAgent, 0) - for _, agent := range q.workspaceAgents { - if agent.Deleted { - continue - } - if agent.CreatedAt.After(after) { - workspaceAgents = append(workspaceAgents, agent) - } - } - return workspaceAgents, nil -} - -func (q *FakeQuerier) GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) ([]database.WorkspaceAgent, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - // Get latest build for workspace. - workspaceBuild, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspaceID) - if err != nil { - return nil, xerrors.Errorf("get latest workspace build: %w", err) - } - - // Get resources for build. - resources, err := q.getWorkspaceResourcesByJobIDNoLock(ctx, workspaceBuild.JobID) - if err != nil { - return nil, xerrors.Errorf("get workspace resources: %w", err) - } - if len(resources) == 0 { - return []database.WorkspaceAgent{}, nil - } - - resourceIDs := make([]uuid.UUID, len(resources)) - for i, resource := range resources { - resourceIDs[i] = resource.ID - } - - agents, err := q.getWorkspaceAgentsByResourceIDsNoLock(ctx, resourceIDs) - if err != nil { - return nil, xerrors.Errorf("get workspace agents: %w", err) - } - - return agents, nil -} - -func (q *FakeQuerier) GetWorkspaceAppByAgentIDAndSlug(ctx context.Context, arg database.GetWorkspaceAppByAgentIDAndSlugParams) (database.WorkspaceApp, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceApp{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceAppByAgentIDAndSlugNoLock(ctx, arg) -} - -func (q *FakeQuerier) GetWorkspaceAppStatusesByAppIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceAppStatus, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - statuses := make([]database.WorkspaceAppStatus, 0) - for _, status := range q.workspaceAppStatuses { - for _, id := range ids { - if status.AppID == id { - statuses = append(statuses, status) - } - } - } - return statuses, nil -} - -func (q *FakeQuerier) GetWorkspaceAppsByAgentID(_ context.Context, id uuid.UUID) ([]database.WorkspaceApp, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - apps := make([]database.WorkspaceApp, 0) - for _, app := range q.workspaceApps { - if app.AgentID == id { - apps = append(apps, app) - } - } - return apps, nil -} - -func (q *FakeQuerier) GetWorkspaceAppsByAgentIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceApp, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - apps := make([]database.WorkspaceApp, 0) - for _, app := range q.workspaceApps { - for _, id := range ids { - if app.AgentID == id { - apps = append(apps, app) - break - } - } - } - return apps, nil -} - -func (q *FakeQuerier) GetWorkspaceAppsCreatedAfter(_ context.Context, after time.Time) ([]database.WorkspaceApp, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - apps := make([]database.WorkspaceApp, 0) - for _, app := range q.workspaceApps { - if app.CreatedAt.After(after) { - apps = append(apps, app) - } - } - return apps, nil -} - -func (q *FakeQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceBuildByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetWorkspaceBuildByJobID(_ context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, build := range q.workspaceBuilds { - if build.JobID == jobID { - return q.workspaceBuildWithUserNoLock(build), nil - } - } - return database.WorkspaceBuild{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (database.WorkspaceBuild, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceBuild{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.WorkspaceID != arg.WorkspaceID { - continue - } - if workspaceBuild.BuildNumber != arg.BuildNumber { - continue - } - return q.workspaceBuildWithUserNoLock(workspaceBuild), nil - } - return database.WorkspaceBuild{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceBuildParameters(_ context.Context, workspaceBuildID uuid.UUID) ([]database.WorkspaceBuildParameter, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceBuildParametersNoLock(workspaceBuildID) -} - -func (q *FakeQuerier) GetWorkspaceBuildParametersByBuildIDs(ctx context.Context, workspaceBuildIDs []uuid.UUID) ([]database.WorkspaceBuildParameter, error) { - // No auth filter. - return q.GetAuthorizedWorkspaceBuildParametersByBuildIDs(ctx, workspaceBuildIDs, nil) -} - -func (q *FakeQuerier) GetWorkspaceBuildStatsByTemplates(ctx context.Context, since time.Time) ([]database.GetWorkspaceBuildStatsByTemplatesRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - templateStats := map[uuid.UUID]database.GetWorkspaceBuildStatsByTemplatesRow{} - for _, wb := range q.workspaceBuilds { - job, err := q.getProvisionerJobByIDNoLock(ctx, wb.JobID) - if err != nil { - return nil, xerrors.Errorf("get provisioner job by ID: %w", err) - } - - if !job.CompletedAt.Valid { - continue - } - - if wb.CreatedAt.Before(since) { - continue - } - - w, err := q.getWorkspaceByIDNoLock(ctx, wb.WorkspaceID) - if err != nil { - return nil, xerrors.Errorf("get workspace by ID: %w", err) - } - - if _, ok := templateStats[w.TemplateID]; !ok { - t, err := q.getTemplateByIDNoLock(ctx, w.TemplateID) - if err != nil { - return nil, xerrors.Errorf("get template by ID: %w", err) - } - - templateStats[w.TemplateID] = database.GetWorkspaceBuildStatsByTemplatesRow{ - TemplateID: w.TemplateID, - TemplateName: t.Name, - TemplateDisplayName: t.DisplayName, - TemplateOrganizationID: w.OrganizationID, - } - } - - s := templateStats[w.TemplateID] - s.TotalBuilds++ - if job.JobStatus == database.ProvisionerJobStatusFailed { - s.FailedBuilds++ - } - templateStats[w.TemplateID] = s - } - - rows := make([]database.GetWorkspaceBuildStatsByTemplatesRow, 0, len(templateStats)) - for _, ts := range templateStats { - rows = append(rows, ts) - } - - sort.Slice(rows, func(i, j int) bool { - return rows[i].TemplateName < rows[j].TemplateName - }) - return rows, nil -} - -func (q *FakeQuerier) GetWorkspaceBuildsByWorkspaceID(_ context.Context, - params database.GetWorkspaceBuildsByWorkspaceIDParams, -) ([]database.WorkspaceBuild, error) { - if err := validateDatabaseType(params); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - history := make([]database.WorkspaceBuild, 0) - for _, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.CreatedAt.Before(params.Since) { - continue - } - if workspaceBuild.WorkspaceID == params.WorkspaceID { - history = append(history, q.workspaceBuildWithUserNoLock(workspaceBuild)) - } - } - - // Order by build_number - slices.SortFunc(history, func(a, b database.WorkspaceBuild) int { - return slice.Descending(a.BuildNumber, b.BuildNumber) - }) - - if params.AfterID != uuid.Nil { - found := false - for i, v := range history { - if v.ID == params.AfterID { - // We want to return all builds after index i. - history = history[i+1:] - found = true - break - } - } - - // If no builds after the time, then we return an empty list. - if !found { - return nil, sql.ErrNoRows - } - } - - if params.OffsetOpt > 0 { - if int(params.OffsetOpt) > len(history)-1 { - return nil, sql.ErrNoRows - } - history = history[params.OffsetOpt:] - } - - if params.LimitOpt > 0 { - if int(params.LimitOpt) > len(history) { - // #nosec G115 - Safe conversion as history slice length is expected to be within int32 range - params.LimitOpt = int32(len(history)) - } - history = history[:params.LimitOpt] - } - - if len(history) == 0 { - return nil, sql.ErrNoRows - } - return history, nil -} - -func (q *FakeQuerier) GetWorkspaceBuildsCreatedAfter(_ context.Context, after time.Time) ([]database.WorkspaceBuild, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaceBuilds := make([]database.WorkspaceBuild, 0) - for _, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.CreatedAt.After(after) { - workspaceBuilds = append(workspaceBuilds, q.workspaceBuildWithUserNoLock(workspaceBuild)) - } - } - return workspaceBuilds, nil -} - -func (q *FakeQuerier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.Workspace, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - w, err := q.getWorkspaceByAgentIDNoLock(ctx, agentID) - if err != nil { - return database.Workspace{}, err - } - - return w, nil -} - -func (q *FakeQuerier) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (database.Workspace, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceByIDNoLock(ctx, id) -} - -func (q *FakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg database.GetWorkspaceByOwnerIDAndNameParams) (database.Workspace, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Workspace{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - var found *database.WorkspaceTable - for _, workspace := range q.workspaces { - if workspace.OwnerID != arg.OwnerID { - continue - } - if !strings.EqualFold(workspace.Name, arg.Name) { - continue - } - if workspace.Deleted != arg.Deleted { - continue - } - - // Return the most recent workspace with the given name - if found == nil || workspace.CreatedAt.After(found.CreatedAt) { - found = &workspace - } - } - if found != nil { - return q.extendWorkspace(*found), nil - } - return database.Workspace{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (database.Workspace, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, resource := range q.workspaceResources { - if resource.ID != resourceID { - continue - } - - for _, build := range q.workspaceBuilds { - if build.JobID != resource.JobID { - continue - } - - for _, workspace := range q.workspaces { - if workspace.ID != build.WorkspaceID { - continue - } - - return q.extendWorkspace(workspace), nil - } - } - } - - return database.Workspace{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceByWorkspaceAppID(_ context.Context, workspaceAppID uuid.UUID) (database.Workspace, error) { - if err := validateDatabaseType(workspaceAppID); err != nil { - return database.Workspace{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, workspaceApp := range q.workspaceApps { - if workspaceApp.ID == workspaceAppID { - return q.getWorkspaceByAgentIDNoLock(context.Background(), workspaceApp.AgentID) - } - } - return database.Workspace{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceModulesByJobID(_ context.Context, jobID uuid.UUID) ([]database.WorkspaceModule, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - modules := make([]database.WorkspaceModule, 0) - for _, module := range q.workspaceModules { - if module.JobID == jobID { - modules = append(modules, module) - } - } - return modules, nil -} - -func (q *FakeQuerier) GetWorkspaceModulesCreatedAfter(_ context.Context, createdAt time.Time) ([]database.WorkspaceModule, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - modules := make([]database.WorkspaceModule, 0) - for _, module := range q.workspaceModules { - if module.CreatedAt.After(createdAt) { - modules = append(modules, module) - } - } - return modules, nil -} - -func (q *FakeQuerier) GetWorkspaceProxies(_ context.Context) ([]database.WorkspaceProxy, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - cpy := make([]database.WorkspaceProxy, 0, len(q.workspaceProxies)) - - for _, p := range q.workspaceProxies { - if !p.Deleted { - cpy = append(cpy, p) - } - } - return cpy, nil -} - -func (q *FakeQuerier) GetWorkspaceProxyByHostname(_ context.Context, params database.GetWorkspaceProxyByHostnameParams) (database.WorkspaceProxy, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - // Return zero rows if this is called with a non-sanitized hostname. The SQL - // version of this query does the same thing. - if !validProxyByHostnameRegex.MatchString(params.Hostname) { - return database.WorkspaceProxy{}, sql.ErrNoRows - } - - // This regex matches the SQL version. - accessURLRegex := regexp.MustCompile(`[^:]*://` + regexp.QuoteMeta(params.Hostname) + `([:/]?.)*`) - - for _, proxy := range q.workspaceProxies { - if proxy.Deleted { - continue - } - if params.AllowAccessUrl && accessURLRegex.MatchString(proxy.Url) { - return proxy, nil - } - - // Compile the app hostname regex. This is slow sadly. - if params.AllowWildcardHostname { - wildcardRegexp, err := appurl.CompileHostnamePattern(proxy.WildcardHostname) - if err != nil { - return database.WorkspaceProxy{}, xerrors.Errorf("compile hostname pattern %q for proxy %q (%s): %w", proxy.WildcardHostname, proxy.Name, proxy.ID.String(), err) - } - if _, ok := appurl.ExecuteHostnamePattern(wildcardRegexp, params.Hostname); ok { - return proxy, nil - } - } - } - - return database.WorkspaceProxy{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceProxyByID(_ context.Context, id uuid.UUID) (database.WorkspaceProxy, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, proxy := range q.workspaceProxies { - if proxy.ID == id { - return proxy, nil - } - } - return database.WorkspaceProxy{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceProxyByName(_ context.Context, name string) (database.WorkspaceProxy, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, proxy := range q.workspaceProxies { - if proxy.Deleted { - continue - } - if proxy.Name == name { - return proxy, nil - } - } - return database.WorkspaceProxy{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceResourceByID(_ context.Context, id uuid.UUID) (database.WorkspaceResource, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, resource := range q.workspaceResources { - if resource.ID == id { - return resource, nil - } - } - return database.WorkspaceResource{}, sql.ErrNoRows -} - -func (q *FakeQuerier) GetWorkspaceResourceMetadataByResourceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceResourceMetadatum, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - metadata := make([]database.WorkspaceResourceMetadatum, 0) - for _, metadatum := range q.workspaceResourceMetadata { - for _, id := range ids { - if metadatum.WorkspaceResourceID == id { - metadata = append(metadata, metadatum) - } - } - } - return metadata, nil -} - -func (q *FakeQuerier) GetWorkspaceResourceMetadataCreatedAfter(ctx context.Context, after time.Time) ([]database.WorkspaceResourceMetadatum, error) { - resources, err := q.GetWorkspaceResourcesCreatedAfter(ctx, after) - if err != nil { - return nil, err - } - resourceIDs := map[uuid.UUID]struct{}{} - for _, resource := range resources { - resourceIDs[resource.ID] = struct{}{} - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - metadata := make([]database.WorkspaceResourceMetadatum, 0) - for _, m := range q.workspaceResourceMetadata { - _, ok := resourceIDs[m.WorkspaceResourceID] - if !ok { - continue - } - metadata = append(metadata, m) - } - return metadata, nil -} - -func (q *FakeQuerier) GetWorkspaceResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]database.WorkspaceResource, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - return q.getWorkspaceResourcesByJobIDNoLock(ctx, jobID) -} - -func (q *FakeQuerier) GetWorkspaceResourcesByJobIDs(_ context.Context, jobIDs []uuid.UUID) ([]database.WorkspaceResource, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - resources := make([]database.WorkspaceResource, 0) - for _, resource := range q.workspaceResources { - for _, jobID := range jobIDs { - if resource.JobID != jobID { - continue - } - resources = append(resources, resource) - } - } - return resources, nil -} - -func (q *FakeQuerier) GetWorkspaceResourcesCreatedAfter(_ context.Context, after time.Time) ([]database.WorkspaceResource, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - resources := make([]database.WorkspaceResource, 0) - for _, resource := range q.workspaceResources { - if resource.CreatedAt.After(after) { - resources = append(resources, resource) - } - } - return resources, nil -} - -func (q *FakeQuerier) GetWorkspaceUniqueOwnerCountByTemplateIDs(_ context.Context, templateIds []uuid.UUID) ([]database.GetWorkspaceUniqueOwnerCountByTemplateIDsRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaceOwners := make(map[uuid.UUID]map[uuid.UUID]struct{}) - for _, workspace := range q.workspaces { - if workspace.Deleted { - continue - } - if !slices.Contains(templateIds, workspace.TemplateID) { - continue - } - _, ok := workspaceOwners[workspace.TemplateID] - if !ok { - workspaceOwners[workspace.TemplateID] = make(map[uuid.UUID]struct{}) - } - workspaceOwners[workspace.TemplateID][workspace.OwnerID] = struct{}{} - } - resp := make([]database.GetWorkspaceUniqueOwnerCountByTemplateIDsRow, 0) - for _, templateID := range templateIds { - count := len(workspaceOwners[templateID]) - resp = append(resp, database.GetWorkspaceUniqueOwnerCountByTemplateIDsRow{ - TemplateID: templateID, - UniqueOwnersSum: int64(count), - }) - } - - return resp, nil -} - -func (q *FakeQuerier) GetWorkspaces(ctx context.Context, arg database.GetWorkspacesParams) ([]database.GetWorkspacesRow, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - // A nil auth filter means no auth filter. - workspaceRows, err := q.GetAuthorizedWorkspaces(ctx, arg, nil) - return workspaceRows, err -} - -func (q *FakeQuerier) GetWorkspacesAndAgentsByOwnerID(ctx context.Context, ownerID uuid.UUID) ([]database.GetWorkspacesAndAgentsByOwnerIDRow, error) { - // No auth filter. - return q.GetAuthorizedWorkspacesAndAgentsByOwnerID(ctx, ownerID, nil) -} - -func (q *FakeQuerier) GetWorkspacesByTemplateID(_ context.Context, templateID uuid.UUID) ([]database.WorkspaceTable, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaces := []database.WorkspaceTable{} - for _, workspace := range q.workspaces { - if workspace.TemplateID == templateID { - workspaces = append(workspaces, workspace) - } - } - - return workspaces, nil -} - -func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.GetWorkspacesEligibleForTransitionRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - workspaces := []database.GetWorkspacesEligibleForTransitionRow{} - for _, workspace := range q.workspaces { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return nil, xerrors.Errorf("get workspace build by ID: %w", err) - } - - user, err := q.getUserByIDNoLock(workspace.OwnerID) - if err != nil { - return nil, xerrors.Errorf("get user by ID: %w", err) - } - - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err != nil { - return nil, xerrors.Errorf("get provisioner job by ID: %w", err) - } - - template, err := q.getTemplateByIDNoLock(ctx, workspace.TemplateID) - if err != nil { - return nil, xerrors.Errorf("get template by ID: %w", err) - } - - if workspace.Deleted { - continue - } - - if job.JobStatus != database.ProvisionerJobStatusFailed && - !workspace.DormantAt.Valid && - build.Transition == database.WorkspaceTransitionStart && - (user.Status == database.UserStatusSuspended || (!build.Deadline.IsZero() && build.Deadline.Before(now))) { - workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ - ID: workspace.ID, - Name: workspace.Name, - }) - continue - } - - if user.Status == database.UserStatusActive && - job.JobStatus != database.ProvisionerJobStatusFailed && - build.Transition == database.WorkspaceTransitionStop && - workspace.AutostartSchedule.Valid && - // We do not know if workspace with a zero next start is eligible - // for autostart, so we accept this false-positive. This can occur - // when a coder version is upgraded and next_start_at has yet to - // be set. - (workspace.NextStartAt.Time.IsZero() || - !now.Before(workspace.NextStartAt.Time)) { - workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ - ID: workspace.ID, - Name: workspace.Name, - }) - continue - } - - if !workspace.DormantAt.Valid && - template.TimeTilDormant > 0 && - now.Sub(workspace.LastUsedAt) >= time.Duration(template.TimeTilDormant) { - workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ - ID: workspace.ID, - Name: workspace.Name, - }) - continue - } - - if workspace.DormantAt.Valid && - workspace.DeletingAt.Valid && - workspace.DeletingAt.Time.Before(now) && - template.TimeTilDormantAutoDelete > 0 { - if build.Transition == database.WorkspaceTransitionDelete && - job.JobStatus == database.ProvisionerJobStatusFailed { - if job.CanceledAt.Valid && now.Sub(job.CanceledAt.Time) <= 24*time.Hour { - continue - } - - if job.CompletedAt.Valid && now.Sub(job.CompletedAt.Time) <= 24*time.Hour { - continue - } - } - - workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ - ID: workspace.ID, - Name: workspace.Name, - }) - continue - } - - if template.FailureTTL > 0 && - build.Transition == database.WorkspaceTransitionStart && - job.JobStatus == database.ProvisionerJobStatusFailed && - job.CompletedAt.Valid && - now.Sub(job.CompletedAt.Time) > time.Duration(template.FailureTTL) { - workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ - ID: workspace.ID, - Name: workspace.Name, - }) - continue - } - } - - return workspaces, nil -} - -func (q *FakeQuerier) HasTemplateVersionsWithAITask(_ context.Context) (bool, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, templateVersion := range q.templateVersions { - if templateVersion.HasAITask.Valid && templateVersion.HasAITask.Bool { - return true, nil - } - } - - return false, nil -} - -func (q *FakeQuerier) InsertAPIKey(_ context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) { - if err := validateDatabaseType(arg); err != nil { - return database.APIKey{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - if arg.LifetimeSeconds == 0 { - arg.LifetimeSeconds = 86400 - } - - for _, u := range q.users { - if u.ID == arg.UserID && u.Deleted { - return database.APIKey{}, xerrors.Errorf("refusing to create APIKey for deleted user") - } - } - - //nolint:gosimple - key := database.APIKey{ - ID: arg.ID, - LifetimeSeconds: arg.LifetimeSeconds, - HashedSecret: arg.HashedSecret, - IPAddress: arg.IPAddress, - UserID: arg.UserID, - ExpiresAt: arg.ExpiresAt, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - LastUsed: arg.LastUsed, - LoginType: arg.LoginType, - Scope: arg.Scope, - TokenName: arg.TokenName, - } - q.apiKeys = append(q.apiKeys, key) - return key, nil -} - -func (q *FakeQuerier) InsertAllUsersGroup(ctx context.Context, orgID uuid.UUID) (database.Group, error) { - return q.InsertGroup(ctx, database.InsertGroupParams{ - ID: orgID, - Name: database.EveryoneGroup, - DisplayName: "", - OrganizationID: orgID, - AvatarURL: "", - QuotaAllowance: 0, - }) -} - -func (q *FakeQuerier) InsertAuditLog(_ context.Context, arg database.InsertAuditLogParams) (database.AuditLog, error) { - if err := validateDatabaseType(arg); err != nil { - return database.AuditLog{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - alog := database.AuditLog(arg) - - q.auditLogs = append(q.auditLogs, alog) - slices.SortFunc(q.auditLogs, func(a, b database.AuditLog) int { - if a.Time.Before(b.Time) { - return -1 - } else if a.Time.Equal(b.Time) { - return 0 - } - return 1 - }) - - return alog, nil -} - -func (q *FakeQuerier) InsertCryptoKey(_ context.Context, arg database.InsertCryptoKeyParams) (database.CryptoKey, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.CryptoKey{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - key := database.CryptoKey{ - Feature: arg.Feature, - Sequence: arg.Sequence, - Secret: arg.Secret, - SecretKeyID: arg.SecretKeyID, - StartsAt: arg.StartsAt, - } - - q.cryptoKeys = append(q.cryptoKeys, key) - - return key, nil -} - -func (q *FakeQuerier) InsertCustomRole(_ context.Context, arg database.InsertCustomRoleParams) (database.CustomRole, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.CustomRole{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - for i := range q.customRoles { - if strings.EqualFold(q.customRoles[i].Name, arg.Name) && - q.customRoles[i].OrganizationID.UUID == arg.OrganizationID.UUID { - return database.CustomRole{}, errUniqueConstraint - } - } - - role := database.CustomRole{ - ID: uuid.New(), - Name: arg.Name, - DisplayName: arg.DisplayName, - OrganizationID: arg.OrganizationID, - SitePermissions: arg.SitePermissions, - OrgPermissions: arg.OrgPermissions, - UserPermissions: arg.UserPermissions, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - } - q.customRoles = append(q.customRoles, role) - - return role, nil -} - -func (q *FakeQuerier) InsertDBCryptKey(_ context.Context, arg database.InsertDBCryptKeyParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - for _, key := range q.dbcryptKeys { - if key.Number == arg.Number { - return errUniqueConstraint - } - } - - q.dbcryptKeys = append(q.dbcryptKeys, database.DBCryptKey{ - Number: arg.Number, - ActiveKeyDigest: sql.NullString{String: arg.ActiveKeyDigest, Valid: true}, - Test: arg.Test, - }) - return nil -} - -func (q *FakeQuerier) InsertDERPMeshKey(_ context.Context, id string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.derpMeshKey = id - return nil -} - -func (q *FakeQuerier) InsertDeploymentID(_ context.Context, id string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.deploymentID = id - return nil -} - -func (q *FakeQuerier) InsertExternalAuthLink(_ context.Context, arg database.InsertExternalAuthLinkParams) (database.ExternalAuthLink, error) { - if err := validateDatabaseType(arg); err != nil { - return database.ExternalAuthLink{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - // nolint:gosimple - gitAuthLink := database.ExternalAuthLink{ - ProviderID: arg.ProviderID, - UserID: arg.UserID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - OAuthAccessToken: arg.OAuthAccessToken, - OAuthAccessTokenKeyID: arg.OAuthAccessTokenKeyID, - OAuthRefreshToken: arg.OAuthRefreshToken, - OAuthRefreshTokenKeyID: arg.OAuthRefreshTokenKeyID, - OAuthExpiry: arg.OAuthExpiry, - OAuthExtra: arg.OAuthExtra, - } - q.externalAuthLinks = append(q.externalAuthLinks, gitAuthLink) - return gitAuthLink, nil -} - -func (q *FakeQuerier) InsertFile(_ context.Context, arg database.InsertFileParams) (database.File, error) { - if err := validateDatabaseType(arg); err != nil { - return database.File{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - if slices.ContainsFunc(q.files, func(file database.File) bool { - return file.CreatedBy == arg.CreatedBy && file.Hash == arg.Hash - }) { - return database.File{}, newUniqueConstraintError(database.UniqueFilesHashCreatedByKey) - } - - //nolint:gosimple - file := database.File{ - ID: arg.ID, - Hash: arg.Hash, - CreatedAt: arg.CreatedAt, - CreatedBy: arg.CreatedBy, - Mimetype: arg.Mimetype, - Data: arg.Data, - } - q.files = append(q.files, file) - return file, nil -} - -func (q *FakeQuerier) InsertGitSSHKey(_ context.Context, arg database.InsertGitSSHKeyParams) (database.GitSSHKey, error) { - if err := validateDatabaseType(arg); err != nil { - return database.GitSSHKey{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - gitSSHKey := database.GitSSHKey{ - UserID: arg.UserID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - PrivateKey: arg.PrivateKey, - PublicKey: arg.PublicKey, - } - q.gitSSHKey = append(q.gitSSHKey, gitSSHKey) - return gitSSHKey, nil -} - -func (q *FakeQuerier) InsertGroup(_ context.Context, arg database.InsertGroupParams) (database.Group, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Group{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, group := range q.groups { - if group.OrganizationID == arg.OrganizationID && - group.Name == arg.Name { - return database.Group{}, errUniqueConstraint - } - } - - //nolint:gosimple - group := database.Group{ - ID: arg.ID, - Name: arg.Name, - DisplayName: arg.DisplayName, - OrganizationID: arg.OrganizationID, - AvatarURL: arg.AvatarURL, - QuotaAllowance: arg.QuotaAllowance, - Source: database.GroupSourceUser, - } - - q.groups = append(q.groups, group) - - return group, nil -} - -func (q *FakeQuerier) InsertGroupMember(_ context.Context, arg database.InsertGroupMemberParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, member := range q.groupMembers { - if member.GroupID == arg.GroupID && - member.UserID == arg.UserID { - return errUniqueConstraint - } - } - - //nolint:gosimple - q.groupMembers = append(q.groupMembers, database.GroupMemberTable{ - GroupID: arg.GroupID, - UserID: arg.UserID, - }) - - return nil -} - -func (q *FakeQuerier) InsertInboxNotification(_ context.Context, arg database.InsertInboxNotificationParams) (database.InboxNotification, error) { - if err := validateDatabaseType(arg); err != nil { - return database.InboxNotification{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - notification := database.InboxNotification{ - ID: arg.ID, - UserID: arg.UserID, - TemplateID: arg.TemplateID, - Targets: arg.Targets, - Title: arg.Title, - Content: arg.Content, - Icon: arg.Icon, - Actions: arg.Actions, - CreatedAt: arg.CreatedAt, - } - - q.inboxNotifications = append(q.inboxNotifications, notification) - return notification, nil -} - -func (q *FakeQuerier) InsertLicense( - _ context.Context, arg database.InsertLicenseParams, -) (database.License, error) { - if err := validateDatabaseType(arg); err != nil { - return database.License{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - l := database.License{ - ID: q.lastLicenseID + 1, - UploadedAt: arg.UploadedAt, - JWT: arg.JWT, - Exp: arg.Exp, - } - q.lastLicenseID = l.ID - q.licenses = append(q.licenses, l) - return l, nil -} - -func (q *FakeQuerier) InsertMemoryResourceMonitor(_ context.Context, arg database.InsertMemoryResourceMonitorParams) (database.WorkspaceAgentMemoryResourceMonitor, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceAgentMemoryResourceMonitor{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:unconvert // The structs field-order differs so this is needed. - monitor := database.WorkspaceAgentMemoryResourceMonitor(database.WorkspaceAgentMemoryResourceMonitor{ - AgentID: arg.AgentID, - Enabled: arg.Enabled, - State: arg.State, - Threshold: arg.Threshold, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - DebouncedUntil: arg.DebouncedUntil, - }) - - q.workspaceAgentMemoryResourceMonitors = append(q.workspaceAgentMemoryResourceMonitors, monitor) - return monitor, nil -} - -func (q *FakeQuerier) InsertMissingGroups(_ context.Context, arg database.InsertMissingGroupsParams) ([]database.Group, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - groupNameMap := make(map[string]struct{}) - for _, g := range arg.GroupNames { - groupNameMap[g] = struct{}{} - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, g := range q.groups { - if g.OrganizationID != arg.OrganizationID { - continue - } - delete(groupNameMap, g.Name) - } - - newGroups := make([]database.Group, 0, len(groupNameMap)) - for k := range groupNameMap { - g := database.Group{ - ID: uuid.New(), - Name: k, - OrganizationID: arg.OrganizationID, - AvatarURL: "", - QuotaAllowance: 0, - DisplayName: "", - Source: arg.Source, - } - q.groups = append(q.groups, g) - newGroups = append(newGroups, g) - } - - return newGroups, nil -} - -func (q *FakeQuerier) InsertOAuth2ProviderApp(_ context.Context, arg database.InsertOAuth2ProviderAppParams) (database.OAuth2ProviderApp, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderApp{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple // Go wants database.OAuth2ProviderApp(arg), but we cannot be sure the structs will remain identical. - app := database.OAuth2ProviderApp{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - Name: arg.Name, - Icon: arg.Icon, - CallbackURL: arg.CallbackURL, - RedirectUris: arg.RedirectUris, - ClientType: arg.ClientType, - DynamicallyRegistered: arg.DynamicallyRegistered, - ClientIDIssuedAt: arg.ClientIDIssuedAt, - ClientSecretExpiresAt: arg.ClientSecretExpiresAt, - GrantTypes: arg.GrantTypes, - ResponseTypes: arg.ResponseTypes, - TokenEndpointAuthMethod: arg.TokenEndpointAuthMethod, - Scope: arg.Scope, - Contacts: arg.Contacts, - ClientUri: arg.ClientUri, - LogoUri: arg.LogoUri, - TosUri: arg.TosUri, - PolicyUri: arg.PolicyUri, - JwksUri: arg.JwksUri, - Jwks: arg.Jwks, - SoftwareID: arg.SoftwareID, - SoftwareVersion: arg.SoftwareVersion, - RegistrationAccessToken: arg.RegistrationAccessToken, - RegistrationClientUri: arg.RegistrationClientUri, - } - - // Apply RFC-compliant defaults to match database migration defaults - if !app.ClientType.Valid { - app.ClientType = sql.NullString{String: "confidential", Valid: true} - } - if !app.DynamicallyRegistered.Valid { - app.DynamicallyRegistered = sql.NullBool{Bool: false, Valid: true} - } - if len(app.GrantTypes) == 0 { - app.GrantTypes = []string{"authorization_code", "refresh_token"} - } - if len(app.ResponseTypes) == 0 { - app.ResponseTypes = []string{"code"} - } - if !app.TokenEndpointAuthMethod.Valid { - app.TokenEndpointAuthMethod = sql.NullString{String: "client_secret_basic", Valid: true} - } - if !app.Scope.Valid { - app.Scope = sql.NullString{String: "", Valid: true} - } - if app.Contacts == nil { - app.Contacts = []string{} - } - q.oauth2ProviderApps = append(q.oauth2ProviderApps, app) - - return app, nil -} - -func (q *FakeQuerier) InsertOAuth2ProviderAppCode(_ context.Context, arg database.InsertOAuth2ProviderAppCodeParams) (database.OAuth2ProviderAppCode, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderAppCode{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, app := range q.oauth2ProviderApps { - if app.ID == arg.AppID { - code := database.OAuth2ProviderAppCode{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - ExpiresAt: arg.ExpiresAt, - SecretPrefix: arg.SecretPrefix, - HashedSecret: arg.HashedSecret, - UserID: arg.UserID, - AppID: arg.AppID, - ResourceUri: arg.ResourceUri, - CodeChallenge: arg.CodeChallenge, - CodeChallengeMethod: arg.CodeChallengeMethod, - } - q.oauth2ProviderAppCodes = append(q.oauth2ProviderAppCodes, code) - return code, nil - } - } - - return database.OAuth2ProviderAppCode{}, sql.ErrNoRows -} - -func (q *FakeQuerier) InsertOAuth2ProviderAppSecret(_ context.Context, arg database.InsertOAuth2ProviderAppSecretParams) (database.OAuth2ProviderAppSecret, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderAppSecret{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, app := range q.oauth2ProviderApps { - if app.ID == arg.AppID { - secret := database.OAuth2ProviderAppSecret{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - SecretPrefix: arg.SecretPrefix, - HashedSecret: arg.HashedSecret, - DisplaySecret: arg.DisplaySecret, - AppID: arg.AppID, - } - q.oauth2ProviderAppSecrets = append(q.oauth2ProviderAppSecrets, secret) - return secret, nil - } - } - - return database.OAuth2ProviderAppSecret{}, sql.ErrNoRows -} - -func (q *FakeQuerier) InsertOAuth2ProviderAppToken(_ context.Context, arg database.InsertOAuth2ProviderAppTokenParams) (database.OAuth2ProviderAppToken, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderAppToken{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, secret := range q.oauth2ProviderAppSecrets { - if secret.ID == arg.AppSecretID { - //nolint:gosimple // Go wants database.OAuth2ProviderAppToken(arg), but we cannot be sure the structs will remain identical. - token := database.OAuth2ProviderAppToken{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - ExpiresAt: arg.ExpiresAt, - HashPrefix: arg.HashPrefix, - RefreshHash: arg.RefreshHash, - APIKeyID: arg.APIKeyID, - AppSecretID: arg.AppSecretID, - UserID: arg.UserID, - Audience: arg.Audience, - } - q.oauth2ProviderAppTokens = append(q.oauth2ProviderAppTokens, token) - return token, nil - } - } - - return database.OAuth2ProviderAppToken{}, sql.ErrNoRows -} - -func (q *FakeQuerier) InsertOrganization(_ context.Context, arg database.InsertOrganizationParams) (database.Organization, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Organization{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - organization := database.Organization{ - ID: arg.ID, - Name: arg.Name, - DisplayName: arg.DisplayName, - Description: arg.Description, - Icon: arg.Icon, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - IsDefault: len(q.organizations) == 0, - } - q.organizations = append(q.organizations, organization) - return organization, nil -} - -func (q *FakeQuerier) InsertOrganizationMember(_ context.Context, arg database.InsertOrganizationMemberParams) (database.OrganizationMember, error) { - if err := validateDatabaseType(arg); err != nil { - return database.OrganizationMember{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - if slices.IndexFunc(q.data.organizationMembers, func(member database.OrganizationMember) bool { - return member.OrganizationID == arg.OrganizationID && member.UserID == arg.UserID - }) >= 0 { - // Error pulled from a live db error - return database.OrganizationMember{}, &pq.Error{ - Severity: "ERROR", - Code: "23505", - Message: "duplicate key value violates unique constraint \"organization_members_pkey\"", - Detail: "Key (organization_id, user_id)=(f7de1f4e-5833-4410-a28d-0a105f96003f, 36052a80-4a7f-4998-a7ca-44cefa608d3e) already exists.", - Table: "organization_members", - Constraint: "organization_members_pkey", - } - } - - //nolint:gosimple - organizationMember := database.OrganizationMember{ - OrganizationID: arg.OrganizationID, - UserID: arg.UserID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - Roles: arg.Roles, - } - q.organizationMembers = append(q.organizationMembers, organizationMember) - return organizationMember, nil -} - -func (q *FakeQuerier) InsertPreset(_ context.Context, arg database.InsertPresetParams) (database.TemplateVersionPreset, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.TemplateVersionPreset{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple // arg needs to keep its type for interface reasons and that type is not appropriate for preset below. - preset := database.TemplateVersionPreset{ - ID: uuid.New(), - TemplateVersionID: arg.TemplateVersionID, - Name: arg.Name, - CreatedAt: arg.CreatedAt, - DesiredInstances: arg.DesiredInstances, - InvalidateAfterSecs: sql.NullInt32{ - Int32: 0, - Valid: true, - }, - PrebuildStatus: database.PrebuildStatusHealthy, - IsDefault: arg.IsDefault, - } - q.presets = append(q.presets, preset) - return preset, nil -} - -func (q *FakeQuerier) InsertPresetParameters(_ context.Context, arg database.InsertPresetParametersParams) ([]database.TemplateVersionPresetParameter, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - presetParameters := make([]database.TemplateVersionPresetParameter, 0, len(arg.Names)) - for i, v := range arg.Names { - presetParameter := database.TemplateVersionPresetParameter{ - ID: uuid.New(), - TemplateVersionPresetID: arg.TemplateVersionPresetID, - Name: v, - Value: arg.Values[i], - } - presetParameters = append(presetParameters, presetParameter) - q.presetParameters = append(q.presetParameters, presetParameter) - } - - return presetParameters, nil -} - -func (q *FakeQuerier) InsertPresetPrebuildSchedule(ctx context.Context, arg database.InsertPresetPrebuildScheduleParams) (database.TemplateVersionPresetPrebuildSchedule, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.TemplateVersionPresetPrebuildSchedule{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - presetPrebuildSchedule := database.TemplateVersionPresetPrebuildSchedule{ - ID: uuid.New(), - PresetID: arg.PresetID, - CronExpression: arg.CronExpression, - DesiredInstances: arg.DesiredInstances, - } - q.presetPrebuildSchedules = append(q.presetPrebuildSchedules, presetPrebuildSchedule) - return presetPrebuildSchedule, nil -} - -func (q *FakeQuerier) InsertProvisionerJob(_ context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { - if err := validateDatabaseType(arg); err != nil { - return database.ProvisionerJob{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - job := database.ProvisionerJob{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - OrganizationID: arg.OrganizationID, - InitiatorID: arg.InitiatorID, - Provisioner: arg.Provisioner, - StorageMethod: arg.StorageMethod, - FileID: arg.FileID, - Type: arg.Type, - Input: arg.Input, - Tags: maps.Clone(arg.Tags), - TraceMetadata: arg.TraceMetadata, - } - job.JobStatus = provisionerJobStatus(job) - q.provisionerJobs = append(q.provisionerJobs, job) - return job, nil -} - -func (q *FakeQuerier) InsertProvisionerJobLogs(_ context.Context, arg database.InsertProvisionerJobLogsParams) ([]database.ProvisionerJobLog, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - logs := make([]database.ProvisionerJobLog, 0) - id := int64(1) - if len(q.provisionerJobLogs) > 0 { - id = q.provisionerJobLogs[len(q.provisionerJobLogs)-1].ID - } - for index, output := range arg.Output { - id++ - logs = append(logs, database.ProvisionerJobLog{ - ID: id, - JobID: arg.JobID, - CreatedAt: arg.CreatedAt[index], - Source: arg.Source[index], - Level: arg.Level[index], - Stage: arg.Stage[index], - Output: output, - }) - } - q.provisionerJobLogs = append(q.provisionerJobLogs, logs...) - return logs, nil -} - -func (q *FakeQuerier) InsertProvisionerJobTimings(_ context.Context, arg database.InsertProvisionerJobTimingsParams) ([]database.ProvisionerJobTiming, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - insertedTimings := make([]database.ProvisionerJobTiming, 0, len(arg.StartedAt)) - for i := range arg.StartedAt { - timing := database.ProvisionerJobTiming{ - JobID: arg.JobID, - StartedAt: arg.StartedAt[i], - EndedAt: arg.EndedAt[i], - Stage: arg.Stage[i], - Source: arg.Source[i], - Action: arg.Action[i], - Resource: arg.Resource[i], - } - q.provisionerJobTimings = append(q.provisionerJobTimings, timing) - insertedTimings = append(insertedTimings, timing) - } - - return insertedTimings, nil -} - -func (q *FakeQuerier) InsertProvisionerKey(_ context.Context, arg database.InsertProvisionerKeyParams) (database.ProvisionerKey, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.ProvisionerKey{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, key := range q.provisionerKeys { - if key.ID == arg.ID || (key.OrganizationID == arg.OrganizationID && strings.EqualFold(key.Name, arg.Name)) { - return database.ProvisionerKey{}, newUniqueConstraintError(database.UniqueProvisionerKeysOrganizationIDNameIndex) - } - } - - //nolint:gosimple - provisionerKey := database.ProvisionerKey{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - OrganizationID: arg.OrganizationID, - Name: strings.ToLower(arg.Name), - HashedSecret: arg.HashedSecret, - Tags: arg.Tags, - } - q.provisionerKeys = append(q.provisionerKeys, provisionerKey) - - return provisionerKey, nil -} - -func (q *FakeQuerier) InsertReplica(_ context.Context, arg database.InsertReplicaParams) (database.Replica, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Replica{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - replica := database.Replica{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - StartedAt: arg.StartedAt, - UpdatedAt: arg.UpdatedAt, - Hostname: arg.Hostname, - RegionID: arg.RegionID, - RelayAddress: arg.RelayAddress, - Version: arg.Version, - DatabaseLatency: arg.DatabaseLatency, - Primary: arg.Primary, - } - q.replicas = append(q.replicas, replica) - return replica, nil -} - -func (q *FakeQuerier) InsertTelemetryItemIfNotExists(_ context.Context, arg database.InsertTelemetryItemIfNotExistsParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, item := range q.telemetryItems { - if item.Key == arg.Key { - return nil - } - } - - q.telemetryItems = append(q.telemetryItems, database.TelemetryItem{ - Key: arg.Key, - Value: arg.Value, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }) - return nil -} - -func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTemplateParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - template := database.TemplateTable{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - OrganizationID: arg.OrganizationID, - Name: arg.Name, - Provisioner: arg.Provisioner, - ActiveVersionID: arg.ActiveVersionID, - Description: arg.Description, - CreatedBy: arg.CreatedBy, - UserACL: arg.UserACL, - GroupACL: arg.GroupACL, - DisplayName: arg.DisplayName, - Icon: arg.Icon, - AllowUserCancelWorkspaceJobs: arg.AllowUserCancelWorkspaceJobs, - AllowUserAutostart: true, - AllowUserAutostop: true, - MaxPortSharingLevel: arg.MaxPortSharingLevel, - UseClassicParameterFlow: arg.UseClassicParameterFlow, - } - q.templates = append(q.templates, template) - return nil -} - -func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.InsertTemplateVersionParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - if len(arg.Message) > 1048576 { - return xerrors.New("message too long") - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - version := database.TemplateVersionTable{ - ID: arg.ID, - TemplateID: arg.TemplateID, - OrganizationID: arg.OrganizationID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - Name: arg.Name, - Message: arg.Message, - Readme: arg.Readme, - JobID: arg.JobID, - CreatedBy: arg.CreatedBy, - SourceExampleID: arg.SourceExampleID, - } - q.templateVersions = append(q.templateVersions, version) - return nil -} - -func (q *FakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg database.InsertTemplateVersionParameterParams) (database.TemplateVersionParameter, error) { - if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersionParameter{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - param := database.TemplateVersionParameter{ - TemplateVersionID: arg.TemplateVersionID, - Name: arg.Name, - DisplayName: arg.DisplayName, - Description: arg.Description, - Type: arg.Type, - FormType: arg.FormType, - Mutable: arg.Mutable, - DefaultValue: arg.DefaultValue, - Icon: arg.Icon, - Options: arg.Options, - ValidationError: arg.ValidationError, - ValidationRegex: arg.ValidationRegex, - ValidationMin: arg.ValidationMin, - ValidationMax: arg.ValidationMax, - ValidationMonotonic: arg.ValidationMonotonic, - Required: arg.Required, - DisplayOrder: arg.DisplayOrder, - Ephemeral: arg.Ephemeral, - } - q.templateVersionParameters = append(q.templateVersionParameters, param) - return param, nil -} - -func (q *FakeQuerier) InsertTemplateVersionTerraformValuesByJobID(_ context.Context, arg database.InsertTemplateVersionTerraformValuesByJobIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - // Find the template version by the job_id - templateVersion, ok := slice.Find(q.templateVersions, func(v database.TemplateVersionTable) bool { - return v.JobID == arg.JobID - }) - if !ok { - return sql.ErrNoRows - } - - if !json.Valid(arg.CachedPlan) { - return xerrors.Errorf("cached plan must be valid json, received %q", string(arg.CachedPlan)) - } - - // Insert the new row - row := database.TemplateVersionTerraformValue{ - TemplateVersionID: templateVersion.ID, - UpdatedAt: arg.UpdatedAt, - CachedPlan: arg.CachedPlan, - CachedModuleFiles: arg.CachedModuleFiles, - ProvisionerdVersion: arg.ProvisionerdVersion, - } - q.templateVersionTerraformValues = append(q.templateVersionTerraformValues, row) - return nil -} - -func (q *FakeQuerier) InsertTemplateVersionVariable(_ context.Context, arg database.InsertTemplateVersionVariableParams) (database.TemplateVersionVariable, error) { - if err := validateDatabaseType(arg); err != nil { - return database.TemplateVersionVariable{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - variable := database.TemplateVersionVariable{ - TemplateVersionID: arg.TemplateVersionID, - Name: arg.Name, - Description: arg.Description, - Type: arg.Type, - Value: arg.Value, - DefaultValue: arg.DefaultValue, - Required: arg.Required, - Sensitive: arg.Sensitive, - } - q.templateVersionVariables = append(q.templateVersionVariables, variable) - return variable, nil -} - -func (q *FakeQuerier) InsertTemplateVersionWorkspaceTag(_ context.Context, arg database.InsertTemplateVersionWorkspaceTagParams) (database.TemplateVersionWorkspaceTag, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.TemplateVersionWorkspaceTag{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - workspaceTag := database.TemplateVersionWorkspaceTag{ - TemplateVersionID: arg.TemplateVersionID, - Key: arg.Key, - Value: arg.Value, - } - q.templateVersionWorkspaceTags = append(q.templateVersionWorkspaceTags, workspaceTag) - return workspaceTag, nil -} - -func (q *FakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, user := range q.users { - if user.Username == arg.Username && !user.Deleted { - return database.User{}, errUniqueConstraint - } - } - - status := database.UserStatusDormant - if arg.Status != "" { - status = database.UserStatus(arg.Status) - } - - user := database.User{ - ID: arg.ID, - Email: arg.Email, - HashedPassword: arg.HashedPassword, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - Username: arg.Username, - Name: arg.Name, - Status: status, - RBACRoles: arg.RBACRoles, - LoginType: arg.LoginType, - IsSystem: false, - } - q.users = append(q.users, user) - sort.Slice(q.users, func(i, j int) bool { - return q.users[i].CreatedAt.Before(q.users[j].CreatedAt) - }) - - q.userStatusChanges = append(q.userStatusChanges, database.UserStatusChange{ - UserID: user.ID, - NewStatus: user.Status, - ChangedAt: user.UpdatedAt, - }) - return user, nil -} - -func (q *FakeQuerier) InsertUserGroupsByID(_ context.Context, arg database.InsertUserGroupsByIDParams) ([]uuid.UUID, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - var groupIDs []uuid.UUID - for _, group := range q.groups { - for _, groupID := range arg.GroupIds { - if group.ID == groupID { - q.groupMembers = append(q.groupMembers, database.GroupMemberTable{ - UserID: arg.UserID, - GroupID: groupID, - }) - groupIDs = append(groupIDs, group.ID) - } - } - } - - return groupIDs, nil -} - -func (q *FakeQuerier) InsertUserGroupsByName(_ context.Context, arg database.InsertUserGroupsByNameParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - var groupIDs []uuid.UUID - for _, group := range q.groups { - for _, groupName := range arg.GroupNames { - if group.Name == groupName { - groupIDs = append(groupIDs, group.ID) - } - } - } - - for _, groupID := range groupIDs { - q.groupMembers = append(q.groupMembers, database.GroupMemberTable{ - UserID: arg.UserID, - GroupID: groupID, - }) - } - - return nil -} - -func (q *FakeQuerier) InsertUserLink(_ context.Context, args database.InsertUserLinkParams) (database.UserLink, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - if u, err := q.getUserByIDNoLock(args.UserID); err == nil && u.Deleted { - return database.UserLink{}, deletedUserLinkError - } - - //nolint:gosimple - link := database.UserLink{ - UserID: args.UserID, - LoginType: args.LoginType, - LinkedID: args.LinkedID, - OAuthAccessToken: args.OAuthAccessToken, - OAuthAccessTokenKeyID: args.OAuthAccessTokenKeyID, - OAuthRefreshToken: args.OAuthRefreshToken, - OAuthRefreshTokenKeyID: args.OAuthRefreshTokenKeyID, - OAuthExpiry: args.OAuthExpiry, - Claims: args.Claims, - } - - q.userLinks = append(q.userLinks, link) - - return link, nil -} - -func (q *FakeQuerier) InsertVolumeResourceMonitor(_ context.Context, arg database.InsertVolumeResourceMonitorParams) (database.WorkspaceAgentVolumeResourceMonitor, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceAgentVolumeResourceMonitor{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - monitor := database.WorkspaceAgentVolumeResourceMonitor{ - AgentID: arg.AgentID, - Path: arg.Path, - Enabled: arg.Enabled, - State: arg.State, - Threshold: arg.Threshold, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - DebouncedUntil: arg.DebouncedUntil, - } - - q.workspaceAgentVolumeResourceMonitors = append(q.workspaceAgentVolumeResourceMonitors, monitor) - return monitor, nil -} - -func (q *FakeQuerier) InsertWebpushSubscription(_ context.Context, arg database.InsertWebpushSubscriptionParams) (database.WebpushSubscription, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WebpushSubscription{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - newSub := database.WebpushSubscription{ - ID: uuid.New(), - UserID: arg.UserID, - CreatedAt: arg.CreatedAt, - Endpoint: arg.Endpoint, - EndpointP256dhKey: arg.EndpointP256dhKey, - EndpointAuthKey: arg.EndpointAuthKey, - } - q.webpushSubscriptions = append(q.webpushSubscriptions, newSub) - return newSub, nil -} - -func (q *FakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWorkspaceParams) (database.WorkspaceTable, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceTable{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - workspace := database.WorkspaceTable{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - OwnerID: arg.OwnerID, - OrganizationID: arg.OrganizationID, - TemplateID: arg.TemplateID, - Name: arg.Name, - AutostartSchedule: arg.AutostartSchedule, - Ttl: arg.Ttl, - LastUsedAt: arg.LastUsedAt, - AutomaticUpdates: arg.AutomaticUpdates, - NextStartAt: arg.NextStartAt, - } - q.workspaces = append(q.workspaces, workspace) - return workspace, nil -} - -func (q *FakeQuerier) InsertWorkspaceAgent(_ context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceAgent{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - agent := database.WorkspaceAgent{ - ID: arg.ID, - ParentID: arg.ParentID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - ResourceID: arg.ResourceID, - AuthToken: arg.AuthToken, - AuthInstanceID: arg.AuthInstanceID, - EnvironmentVariables: arg.EnvironmentVariables, - Name: arg.Name, - Architecture: arg.Architecture, - OperatingSystem: arg.OperatingSystem, - Directory: arg.Directory, - InstanceMetadata: arg.InstanceMetadata, - ResourceMetadata: arg.ResourceMetadata, - ConnectionTimeoutSeconds: arg.ConnectionTimeoutSeconds, - TroubleshootingURL: arg.TroubleshootingURL, - MOTDFile: arg.MOTDFile, - LifecycleState: database.WorkspaceAgentLifecycleStateCreated, - DisplayApps: arg.DisplayApps, - DisplayOrder: arg.DisplayOrder, - APIKeyScope: arg.APIKeyScope, - } - - q.workspaceAgents = append(q.workspaceAgents, agent) - return agent, nil -} - -func (q *FakeQuerier) InsertWorkspaceAgentDevcontainers(_ context.Context, arg database.InsertWorkspaceAgentDevcontainersParams) ([]database.WorkspaceAgentDevcontainer, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, agent := range q.workspaceAgents { - if agent.ID == arg.WorkspaceAgentID { - var devcontainers []database.WorkspaceAgentDevcontainer - for i, id := range arg.ID { - devcontainers = append(devcontainers, database.WorkspaceAgentDevcontainer{ - WorkspaceAgentID: arg.WorkspaceAgentID, - CreatedAt: arg.CreatedAt, - ID: id, - Name: arg.Name[i], - WorkspaceFolder: arg.WorkspaceFolder[i], - ConfigPath: arg.ConfigPath[i], - }) - } - q.workspaceAgentDevcontainers = append(q.workspaceAgentDevcontainers, devcontainers...) - return devcontainers, nil - } - } - - return nil, errForeignKeyConstraint -} - -func (q *FakeQuerier) InsertWorkspaceAgentLogSources(_ context.Context, arg database.InsertWorkspaceAgentLogSourcesParams) ([]database.WorkspaceAgentLogSource, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - logSources := make([]database.WorkspaceAgentLogSource, 0) - for index, source := range arg.ID { - logSource := database.WorkspaceAgentLogSource{ - ID: source, - WorkspaceAgentID: arg.WorkspaceAgentID, - CreatedAt: arg.CreatedAt, - DisplayName: arg.DisplayName[index], - Icon: arg.Icon[index], - } - logSources = append(logSources, logSource) - } - q.workspaceAgentLogSources = append(q.workspaceAgentLogSources, logSources...) - return logSources, nil -} - -func (q *FakeQuerier) InsertWorkspaceAgentLogs(_ context.Context, arg database.InsertWorkspaceAgentLogsParams) ([]database.WorkspaceAgentLog, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - logs := []database.WorkspaceAgentLog{} - id := int64(0) - if len(q.workspaceAgentLogs) > 0 { - id = q.workspaceAgentLogs[len(q.workspaceAgentLogs)-1].ID - } - outputLength := int32(0) - for index, output := range arg.Output { - id++ - logs = append(logs, database.WorkspaceAgentLog{ - ID: id, - AgentID: arg.AgentID, - CreatedAt: arg.CreatedAt, - Level: arg.Level[index], - LogSourceID: arg.LogSourceID, - Output: output, - }) - // #nosec G115 - Safe conversion as log output length is expected to be within int32 range - outputLength += int32(len(output)) - } - for index, agent := range q.workspaceAgents { - if agent.ID != arg.AgentID { - continue - } - // Greater than 1MB, same as the PostgreSQL constraint! - if agent.LogsLength+outputLength > (1 << 20) { - return nil, &pq.Error{ - Constraint: "max_logs_length", - Table: "workspace_agents", - } - } - agent.LogsLength += outputLength - q.workspaceAgents[index] = agent - break - } - q.workspaceAgentLogs = append(q.workspaceAgentLogs, logs...) - return logs, nil -} - -func (q *FakeQuerier) InsertWorkspaceAgentMetadata(_ context.Context, arg database.InsertWorkspaceAgentMetadataParams) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - metadatum := database.WorkspaceAgentMetadatum{ - WorkspaceAgentID: arg.WorkspaceAgentID, - Script: arg.Script, - DisplayName: arg.DisplayName, - Key: arg.Key, - Timeout: arg.Timeout, - Interval: arg.Interval, - DisplayOrder: arg.DisplayOrder, - } - - q.workspaceAgentMetadata = append(q.workspaceAgentMetadata, metadatum) - return nil -} - -func (q *FakeQuerier) InsertWorkspaceAgentScriptTimings(_ context.Context, arg database.InsertWorkspaceAgentScriptTimingsParams) (database.WorkspaceAgentScriptTiming, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceAgentScriptTiming{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - timing := database.WorkspaceAgentScriptTiming(arg) - q.workspaceAgentScriptTimings = append(q.workspaceAgentScriptTimings, timing) - - return timing, nil -} - -func (q *FakeQuerier) InsertWorkspaceAgentScripts(_ context.Context, arg database.InsertWorkspaceAgentScriptsParams) ([]database.WorkspaceAgentScript, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - scripts := make([]database.WorkspaceAgentScript, 0) - for index, source := range arg.LogSourceID { - script := database.WorkspaceAgentScript{ - LogSourceID: source, - WorkspaceAgentID: arg.WorkspaceAgentID, - ID: arg.ID[index], - LogPath: arg.LogPath[index], - Script: arg.Script[index], - Cron: arg.Cron[index], - StartBlocksLogin: arg.StartBlocksLogin[index], - RunOnStart: arg.RunOnStart[index], - RunOnStop: arg.RunOnStop[index], - TimeoutSeconds: arg.TimeoutSeconds[index], - CreatedAt: arg.CreatedAt, - } - scripts = append(scripts, script) - } - q.workspaceAgentScripts = append(q.workspaceAgentScripts, scripts...) - return scripts, nil -} - -func (q *FakeQuerier) InsertWorkspaceAgentStats(_ context.Context, arg database.InsertWorkspaceAgentStatsParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - var connectionsByProto []map[string]int64 - if err := json.Unmarshal(arg.ConnectionsByProto, &connectionsByProto); err != nil { - return err - } - for i := 0; i < len(arg.ID); i++ { - cbp, err := json.Marshal(connectionsByProto[i]) - if err != nil { - return xerrors.Errorf("failed to marshal connections_by_proto: %w", err) - } - stat := database.WorkspaceAgentStat{ - ID: arg.ID[i], - CreatedAt: arg.CreatedAt[i], - WorkspaceID: arg.WorkspaceID[i], - AgentID: arg.AgentID[i], - UserID: arg.UserID[i], - ConnectionsByProto: cbp, - ConnectionCount: arg.ConnectionCount[i], - RxPackets: arg.RxPackets[i], - RxBytes: arg.RxBytes[i], - TxPackets: arg.TxPackets[i], - TxBytes: arg.TxBytes[i], - TemplateID: arg.TemplateID[i], - SessionCountVSCode: arg.SessionCountVSCode[i], - SessionCountJetBrains: arg.SessionCountJetBrains[i], - SessionCountReconnectingPTY: arg.SessionCountReconnectingPTY[i], - SessionCountSSH: arg.SessionCountSSH[i], - ConnectionMedianLatencyMS: arg.ConnectionMedianLatencyMS[i], - Usage: arg.Usage[i], - } - q.workspaceAgentStats = append(q.workspaceAgentStats, stat) - } - - return nil -} - -func (q *FakeQuerier) InsertWorkspaceAppStats(_ context.Context, arg database.InsertWorkspaceAppStatsParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - -InsertWorkspaceAppStatsLoop: - for i := 0; i < len(arg.UserID); i++ { - stat := database.WorkspaceAppStat{ - ID: q.workspaceAppStatsLastInsertID + 1, - UserID: arg.UserID[i], - WorkspaceID: arg.WorkspaceID[i], - AgentID: arg.AgentID[i], - AccessMethod: arg.AccessMethod[i], - SlugOrPort: arg.SlugOrPort[i], - SessionID: arg.SessionID[i], - SessionStartedAt: arg.SessionStartedAt[i], - SessionEndedAt: arg.SessionEndedAt[i], - Requests: arg.Requests[i], - } - for j, s := range q.workspaceAppStats { - // Check unique constraint for upsert. - if s.UserID == stat.UserID && s.AgentID == stat.AgentID && s.SessionID == stat.SessionID { - q.workspaceAppStats[j].SessionEndedAt = stat.SessionEndedAt - q.workspaceAppStats[j].Requests = stat.Requests - continue InsertWorkspaceAppStatsLoop - } - } - q.workspaceAppStats = append(q.workspaceAppStats, stat) - q.workspaceAppStatsLastInsertID++ - } - - return nil -} - -func (q *FakeQuerier) InsertWorkspaceAppStatus(_ context.Context, arg database.InsertWorkspaceAppStatusParams) (database.WorkspaceAppStatus, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceAppStatus{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - status := database.WorkspaceAppStatus{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - WorkspaceID: arg.WorkspaceID, - AgentID: arg.AgentID, - AppID: arg.AppID, - State: arg.State, - Message: arg.Message, - Uri: arg.Uri, - } - q.workspaceAppStatuses = append(q.workspaceAppStatuses, status) - return status, nil -} - -func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.InsertWorkspaceBuildParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - workspaceBuild := database.WorkspaceBuild{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - WorkspaceID: arg.WorkspaceID, - TemplateVersionID: arg.TemplateVersionID, - BuildNumber: arg.BuildNumber, - Transition: arg.Transition, - InitiatorID: arg.InitiatorID, - JobID: arg.JobID, - ProvisionerState: arg.ProvisionerState, - Deadline: arg.Deadline, - MaxDeadline: arg.MaxDeadline, - Reason: arg.Reason, - TemplateVersionPresetID: arg.TemplateVersionPresetID, - } - q.workspaceBuilds = append(q.workspaceBuilds, workspaceBuild) - return nil -} - -func (q *FakeQuerier) InsertWorkspaceBuildParameters(_ context.Context, arg database.InsertWorkspaceBuildParametersParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, name := range arg.Name { - q.workspaceBuildParameters = append(q.workspaceBuildParameters, database.WorkspaceBuildParameter{ - WorkspaceBuildID: arg.WorkspaceBuildID, - Name: name, - Value: arg.Value[index], - }) - } - return nil -} - -func (q *FakeQuerier) InsertWorkspaceModule(_ context.Context, arg database.InsertWorkspaceModuleParams) (database.WorkspaceModule, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceModule{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - workspaceModule := database.WorkspaceModule(arg) - q.workspaceModules = append(q.workspaceModules, workspaceModule) - return workspaceModule, nil -} - -func (q *FakeQuerier) InsertWorkspaceProxy(_ context.Context, arg database.InsertWorkspaceProxyParams) (database.WorkspaceProxy, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - lastRegionID := int32(0) - for _, p := range q.workspaceProxies { - if !p.Deleted && p.Name == arg.Name { - return database.WorkspaceProxy{}, errUniqueConstraint - } - if p.RegionID > lastRegionID { - lastRegionID = p.RegionID - } - } - - p := database.WorkspaceProxy{ - ID: arg.ID, - Name: arg.Name, - DisplayName: arg.DisplayName, - Icon: arg.Icon, - DerpEnabled: arg.DerpEnabled, - DerpOnly: arg.DerpOnly, - TokenHashedSecret: arg.TokenHashedSecret, - RegionID: lastRegionID + 1, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - Deleted: false, - } - q.workspaceProxies = append(q.workspaceProxies, p) - return p, nil -} - -func (q *FakeQuerier) InsertWorkspaceResource(_ context.Context, arg database.InsertWorkspaceResourceParams) (database.WorkspaceResource, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceResource{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - resource := database.WorkspaceResource{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - JobID: arg.JobID, - Transition: arg.Transition, - Type: arg.Type, - Name: arg.Name, - Hide: arg.Hide, - Icon: arg.Icon, - DailyCost: arg.DailyCost, - ModulePath: arg.ModulePath, - } - q.workspaceResources = append(q.workspaceResources, resource) - return resource, nil -} - -func (q *FakeQuerier) InsertWorkspaceResourceMetadata(_ context.Context, arg database.InsertWorkspaceResourceMetadataParams) ([]database.WorkspaceResourceMetadatum, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - metadata := make([]database.WorkspaceResourceMetadatum, 0) - id := int64(1) - if len(q.workspaceResourceMetadata) > 0 { - id = q.workspaceResourceMetadata[len(q.workspaceResourceMetadata)-1].ID - } - for index, key := range arg.Key { - id++ - value := arg.Value[index] - metadata = append(metadata, database.WorkspaceResourceMetadatum{ - ID: id, - WorkspaceResourceID: arg.WorkspaceResourceID, - Key: key, - Value: sql.NullString{ - String: value, - Valid: value != "", - }, - Sensitive: arg.Sensitive[index], - }) - } - q.workspaceResourceMetadata = append(q.workspaceResourceMetadata, metadata...) - return metadata, nil -} - -func (q *FakeQuerier) ListProvisionerKeysByOrganization(_ context.Context, organizationID uuid.UUID) ([]database.ProvisionerKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - keys := make([]database.ProvisionerKey, 0) - for _, key := range q.provisionerKeys { - if key.OrganizationID == organizationID { - keys = append(keys, key) - } - } - - return keys, nil -} - -func (q *FakeQuerier) ListProvisionerKeysByOrganizationExcludeReserved(_ context.Context, organizationID uuid.UUID) ([]database.ProvisionerKey, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - keys := make([]database.ProvisionerKey, 0) - for _, key := range q.provisionerKeys { - if key.ID.String() == codersdk.ProvisionerKeyIDBuiltIn || - key.ID.String() == codersdk.ProvisionerKeyIDUserAuth || - key.ID.String() == codersdk.ProvisionerKeyIDPSK { - continue - } - if key.OrganizationID == organizationID { - keys = append(keys, key) - } - } - - return keys, nil -} - -func (q *FakeQuerier) ListWorkspaceAgentPortShares(_ context.Context, workspaceID uuid.UUID) ([]database.WorkspaceAgentPortShare, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - shares := []database.WorkspaceAgentPortShare{} - for _, share := range q.workspaceAgentPortShares { - if share.WorkspaceID == workspaceID { - shares = append(shares, share) - } - } - - return shares, nil -} - -func (q *FakeQuerier) MarkAllInboxNotificationsAsRead(_ context.Context, arg database.MarkAllInboxNotificationsAsReadParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - for idx, notif := range q.inboxNotifications { - if notif.UserID == arg.UserID && !notif.ReadAt.Valid { - q.inboxNotifications[idx].ReadAt = arg.ReadAt - } - } - - return nil -} - -// nolint:forcetypeassert -func (q *FakeQuerier) OIDCClaimFieldValues(_ context.Context, args database.OIDCClaimFieldValuesParams) ([]string, error) { - orgMembers := q.getOrganizationMemberNoLock(args.OrganizationID) - - var values []string - for _, link := range q.userLinks { - if args.OrganizationID != uuid.Nil { - inOrg := slices.ContainsFunc(orgMembers, func(organizationMember database.OrganizationMember) bool { - return organizationMember.UserID == link.UserID - }) - if !inOrg { - continue - } - } - - if link.LoginType != database.LoginTypeOIDC { - continue - } - - if len(link.Claims.MergedClaims) == 0 { - continue - } - - value, ok := link.Claims.MergedClaims[args.ClaimField] - if !ok { - continue - } - switch value := value.(type) { - case string: - values = append(values, value) - case []string: - values = append(values, value...) - case []any: - for _, v := range value { - if sv, ok := v.(string); ok { - values = append(values, sv) - } - } - default: - continue - } - } - - return slice.Unique(values), nil -} - -func (q *FakeQuerier) OIDCClaimFields(_ context.Context, organizationID uuid.UUID) ([]string, error) { - orgMembers := q.getOrganizationMemberNoLock(organizationID) - - var fields []string - for _, link := range q.userLinks { - if organizationID != uuid.Nil { - inOrg := slices.ContainsFunc(orgMembers, func(organizationMember database.OrganizationMember) bool { - return organizationMember.UserID == link.UserID - }) - if !inOrg { - continue - } - } - - if link.LoginType != database.LoginTypeOIDC { - continue - } - - for k := range link.Claims.MergedClaims { - fields = append(fields, k) - } - } - - return slice.Unique(fields), nil -} - -func (q *FakeQuerier) OrganizationMembers(_ context.Context, arg database.OrganizationMembersParams) ([]database.OrganizationMembersRow, error) { - if err := validateDatabaseType(arg); err != nil { - return []database.OrganizationMembersRow{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - tmp := make([]database.OrganizationMembersRow, 0) - for _, organizationMember := range q.organizationMembers { - if arg.OrganizationID != uuid.Nil && organizationMember.OrganizationID != arg.OrganizationID { - continue - } - - if arg.UserID != uuid.Nil && organizationMember.UserID != arg.UserID { - continue - } - - user, _ := q.getUserByIDNoLock(organizationMember.UserID) - tmp = append(tmp, database.OrganizationMembersRow{ - OrganizationMember: organizationMember, - Username: user.Username, - AvatarURL: user.AvatarURL, - Name: user.Name, - Email: user.Email, - GlobalRoles: user.RBACRoles, - }) - } - return tmp, nil -} - -func (q *FakeQuerier) PaginatedOrganizationMembers(_ context.Context, arg database.PaginatedOrganizationMembersParams) ([]database.PaginatedOrganizationMembersRow, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - // All of the members in the organization - orgMembers := make([]database.OrganizationMember, 0) - for _, mem := range q.organizationMembers { - if mem.OrganizationID != arg.OrganizationID { - continue - } - - orgMembers = append(orgMembers, mem) - } - - selectedMembers := make([]database.PaginatedOrganizationMembersRow, 0) - - skippedMembers := 0 - for _, organizationMember := range orgMembers { - if skippedMembers < int(arg.OffsetOpt) { - skippedMembers++ - continue - } - - // if the limit is set to 0 we treat that as returning all of the org members - if int(arg.LimitOpt) != 0 && len(selectedMembers) >= int(arg.LimitOpt) { - break - } - - user, _ := q.getUserByIDNoLock(organizationMember.UserID) - selectedMembers = append(selectedMembers, database.PaginatedOrganizationMembersRow{ - OrganizationMember: organizationMember, - Username: user.Username, - AvatarURL: user.AvatarURL, - Name: user.Name, - Email: user.Email, - GlobalRoles: user.RBACRoles, - Count: int64(len(orgMembers)), - }) - } - return selectedMembers, nil -} - -func (q *FakeQuerier) ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate(_ context.Context, templateID uuid.UUID) error { - err := validateDatabaseType(templateID) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, workspace := range q.workspaces { - if workspace.TemplateID != templateID { - continue - } - for i, share := range q.workspaceAgentPortShares { - if share.WorkspaceID != workspace.ID { - continue - } - if share.ShareLevel == database.AppSharingLevelPublic { - share.ShareLevel = database.AppSharingLevelAuthenticated - } - q.workspaceAgentPortShares[i] = share - } - } - - return nil -} - -func (q *FakeQuerier) RegisterWorkspaceProxy(_ context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, p := range q.workspaceProxies { - if p.ID == arg.ID { - p.Url = arg.Url - p.WildcardHostname = arg.WildcardHostname - p.DerpEnabled = arg.DerpEnabled - p.DerpOnly = arg.DerpOnly - p.Version = arg.Version - p.UpdatedAt = dbtime.Now() - q.workspaceProxies[i] = p - return p, nil - } - } - return database.WorkspaceProxy{}, sql.ErrNoRows -} - -func (q *FakeQuerier) RemoveUserFromAllGroups(_ context.Context, userID uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - newMembers := q.groupMembers[:0] - for _, member := range q.groupMembers { - if member.UserID == userID { - continue - } - newMembers = append(newMembers, member) - } - q.groupMembers = newMembers - - return nil -} - -func (q *FakeQuerier) RemoveUserFromGroups(_ context.Context, arg database.RemoveUserFromGroupsParams) ([]uuid.UUID, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - removed := make([]uuid.UUID, 0) - q.data.groupMembers = slices.DeleteFunc(q.data.groupMembers, func(groupMember database.GroupMemberTable) bool { - // Delete all group members that match the arguments. - if groupMember.UserID != arg.UserID { - // Not the right user, ignore. - return false - } - - if !slices.Contains(arg.GroupIds, groupMember.GroupID) { - return false - } - - removed = append(removed, groupMember.GroupID) - return true - }) - - return removed, nil -} - -func (q *FakeQuerier) RevokeDBCryptKey(_ context.Context, activeKeyDigest string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i := range q.dbcryptKeys { - key := q.dbcryptKeys[i] - - // Is the key already revoked? - if !key.ActiveKeyDigest.Valid { - continue - } - - if key.ActiveKeyDigest.String != activeKeyDigest { - continue - } - - // Check for foreign key constraints. - for _, ul := range q.userLinks { - if (ul.OAuthAccessTokenKeyID.Valid && ul.OAuthAccessTokenKeyID.String == activeKeyDigest) || - (ul.OAuthRefreshTokenKeyID.Valid && ul.OAuthRefreshTokenKeyID.String == activeKeyDigest) { - return errForeignKeyConstraint - } - } - for _, gal := range q.externalAuthLinks { - if (gal.OAuthAccessTokenKeyID.Valid && gal.OAuthAccessTokenKeyID.String == activeKeyDigest) || - (gal.OAuthRefreshTokenKeyID.Valid && gal.OAuthRefreshTokenKeyID.String == activeKeyDigest) { - return errForeignKeyConstraint - } - } - - // Revoke the key. - q.dbcryptKeys[i].RevokedAt = sql.NullTime{Time: dbtime.Now(), Valid: true} - q.dbcryptKeys[i].RevokedKeyDigest = sql.NullString{String: key.ActiveKeyDigest.String, Valid: true} - q.dbcryptKeys[i].ActiveKeyDigest = sql.NullString{} - return nil - } - - return sql.ErrNoRows -} - -func (*FakeQuerier) TryAcquireLock(_ context.Context, _ int64) (bool, error) { - return false, xerrors.New("TryAcquireLock must only be called within a transaction") -} - -func (q *FakeQuerier) UnarchiveTemplateVersion(_ context.Context, arg database.UnarchiveTemplateVersionParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, v := range q.data.templateVersions { - if v.ID == arg.TemplateVersionID { - v.Archived = false - v.UpdatedAt = arg.UpdatedAt - q.data.templateVersions[i] = v - return nil - } - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UnfavoriteWorkspace(_ context.Context, arg uuid.UUID) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i := 0; i < len(q.workspaces); i++ { - if q.workspaces[i].ID != arg { - continue - } - q.workspaces[i].Favorite = false - return nil - } - - return nil -} - -func (q *FakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPIKeyByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, apiKey := range q.apiKeys { - if apiKey.ID != arg.ID { - continue - } - apiKey.LastUsed = arg.LastUsed - apiKey.ExpiresAt = arg.ExpiresAt - apiKey.IPAddress = arg.IPAddress - q.apiKeys[index] = apiKey - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateCryptoKeyDeletesAt(_ context.Context, arg database.UpdateCryptoKeyDeletesAtParams) (database.CryptoKey, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.CryptoKey{}, err - } - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, key := range q.cryptoKeys { - if key.Feature == arg.Feature && key.Sequence == arg.Sequence { - key.DeletesAt = arg.DeletesAt - q.cryptoKeys[i] = key - return key, nil - } - } - - return database.CryptoKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateCustomRole(_ context.Context, arg database.UpdateCustomRoleParams) (database.CustomRole, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.CustomRole{}, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - for i := range q.customRoles { - if strings.EqualFold(q.customRoles[i].Name, arg.Name) && - q.customRoles[i].OrganizationID.UUID == arg.OrganizationID.UUID { - q.customRoles[i].DisplayName = arg.DisplayName - q.customRoles[i].OrganizationID = arg.OrganizationID - q.customRoles[i].SitePermissions = arg.SitePermissions - q.customRoles[i].OrgPermissions = arg.OrgPermissions - q.customRoles[i].UserPermissions = arg.UserPermissions - q.customRoles[i].UpdatedAt = dbtime.Now() - return q.customRoles[i], nil - } - } - return database.CustomRole{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateExternalAuthLink(_ context.Context, arg database.UpdateExternalAuthLinkParams) (database.ExternalAuthLink, error) { - if err := validateDatabaseType(arg); err != nil { - return database.ExternalAuthLink{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - for index, gitAuthLink := range q.externalAuthLinks { - if gitAuthLink.ProviderID != arg.ProviderID { - continue - } - if gitAuthLink.UserID != arg.UserID { - continue - } - gitAuthLink.UpdatedAt = arg.UpdatedAt - gitAuthLink.OAuthAccessToken = arg.OAuthAccessToken - gitAuthLink.OAuthAccessTokenKeyID = arg.OAuthAccessTokenKeyID - gitAuthLink.OAuthRefreshToken = arg.OAuthRefreshToken - gitAuthLink.OAuthRefreshTokenKeyID = arg.OAuthRefreshTokenKeyID - gitAuthLink.OAuthExpiry = arg.OAuthExpiry - gitAuthLink.OAuthExtra = arg.OAuthExtra - q.externalAuthLinks[index] = gitAuthLink - - return gitAuthLink, nil - } - return database.ExternalAuthLink{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateExternalAuthLinkRefreshToken(_ context.Context, arg database.UpdateExternalAuthLinkRefreshTokenParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - for index, gitAuthLink := range q.externalAuthLinks { - if gitAuthLink.ProviderID != arg.ProviderID { - continue - } - if gitAuthLink.UserID != arg.UserID { - continue - } - gitAuthLink.UpdatedAt = arg.UpdatedAt - gitAuthLink.OAuthRefreshToken = arg.OAuthRefreshToken - q.externalAuthLinks[index] = gitAuthLink - - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateGitSSHKey(_ context.Context, arg database.UpdateGitSSHKeyParams) (database.GitSSHKey, error) { - if err := validateDatabaseType(arg); err != nil { - return database.GitSSHKey{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, key := range q.gitSSHKey { - if key.UserID != arg.UserID { - continue - } - key.UpdatedAt = arg.UpdatedAt - key.PrivateKey = arg.PrivateKey - key.PublicKey = arg.PublicKey - q.gitSSHKey[index] = key - return key, nil - } - return database.GitSSHKey{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateGroupByID(_ context.Context, arg database.UpdateGroupByIDParams) (database.Group, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Group{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, group := range q.groups { - if group.ID == arg.ID { - group.DisplayName = arg.DisplayName - group.Name = arg.Name - group.AvatarURL = arg.AvatarURL - group.QuotaAllowance = arg.QuotaAllowance - q.groups[i] = group - return group, nil - } - } - return database.Group{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateInactiveUsersToDormant(_ context.Context, params database.UpdateInactiveUsersToDormantParams) ([]database.UpdateInactiveUsersToDormantRow, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - var updated []database.UpdateInactiveUsersToDormantRow - for index, user := range q.users { - if user.Status == database.UserStatusActive && user.LastSeenAt.Before(params.LastSeenAfter) && !user.IsSystem { - q.users[index].Status = database.UserStatusDormant - q.users[index].UpdatedAt = params.UpdatedAt - updated = append(updated, database.UpdateInactiveUsersToDormantRow{ - ID: user.ID, - Email: user.Email, - Username: user.Username, - LastSeenAt: user.LastSeenAt, - }) - q.userStatusChanges = append(q.userStatusChanges, database.UserStatusChange{ - UserID: user.ID, - NewStatus: database.UserStatusDormant, - ChangedAt: params.UpdatedAt, - }) - } - } - - if len(updated) == 0 { - return nil, sql.ErrNoRows - } - - return updated, nil -} - -func (q *FakeQuerier) UpdateInboxNotificationReadStatus(_ context.Context, arg database.UpdateInboxNotificationReadStatusParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i := range q.inboxNotifications { - if q.inboxNotifications[i].ID == arg.ID { - q.inboxNotifications[i].ReadAt = arg.ReadAt - } - } - - return nil -} - -func (q *FakeQuerier) UpdateMemberRoles(_ context.Context, arg database.UpdateMemberRolesParams) (database.OrganizationMember, error) { - if err := validateDatabaseType(arg); err != nil { - return database.OrganizationMember{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, mem := range q.organizationMembers { - if mem.UserID == arg.UserID && mem.OrganizationID == arg.OrgID { - uniqueRoles := make([]string, 0, len(arg.GrantedRoles)) - exist := make(map[string]struct{}) - for _, r := range arg.GrantedRoles { - if _, ok := exist[r]; ok { - continue - } - exist[r] = struct{}{} - uniqueRoles = append(uniqueRoles, r) - } - sort.Strings(uniqueRoles) - - mem.Roles = uniqueRoles - q.organizationMembers[i] = mem - return mem, nil - } - } - - return database.OrganizationMember{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateMemoryResourceMonitor(_ context.Context, arg database.UpdateMemoryResourceMonitorParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, monitor := range q.workspaceAgentMemoryResourceMonitors { - if monitor.AgentID != arg.AgentID { - continue - } - - monitor.State = arg.State - monitor.UpdatedAt = arg.UpdatedAt - monitor.DebouncedUntil = arg.DebouncedUntil - q.workspaceAgentMemoryResourceMonitors[i] = monitor - return nil - } - - return nil -} - -func (*FakeQuerier) UpdateNotificationTemplateMethodByID(_ context.Context, _ database.UpdateNotificationTemplateMethodByIDParams) (database.NotificationTemplate, error) { - // Not implementing this function because it relies on state in the database which is created with migrations. - // We could consider using code-generation to align the database state and dbmem, but it's not worth it right now. - return database.NotificationTemplate{}, ErrUnimplemented -} - -func (q *FakeQuerier) UpdateOAuth2ProviderAppByClientID(ctx context.Context, arg database.UpdateOAuth2ProviderAppByClientIDParams) (database.OAuth2ProviderApp, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderApp{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, app := range q.oauth2ProviderApps { - if app.ID == arg.ID { - app.UpdatedAt = arg.UpdatedAt - app.Name = arg.Name - app.Icon = arg.Icon - app.CallbackURL = arg.CallbackURL - app.RedirectUris = arg.RedirectUris - app.GrantTypes = arg.GrantTypes - app.ResponseTypes = arg.ResponseTypes - app.TokenEndpointAuthMethod = arg.TokenEndpointAuthMethod - app.Scope = arg.Scope - app.Contacts = arg.Contacts - app.ClientUri = arg.ClientUri - app.LogoUri = arg.LogoUri - app.TosUri = arg.TosUri - app.PolicyUri = arg.PolicyUri - app.JwksUri = arg.JwksUri - app.Jwks = arg.Jwks - app.SoftwareID = arg.SoftwareID - app.SoftwareVersion = arg.SoftwareVersion - - // Apply RFC-compliant defaults to match database migration defaults - if !app.ClientType.Valid { - app.ClientType = sql.NullString{String: "confidential", Valid: true} - } - if !app.DynamicallyRegistered.Valid { - app.DynamicallyRegistered = sql.NullBool{Bool: false, Valid: true} - } - if len(app.GrantTypes) == 0 { - app.GrantTypes = []string{"authorization_code", "refresh_token"} - } - if len(app.ResponseTypes) == 0 { - app.ResponseTypes = []string{"code"} - } - if !app.TokenEndpointAuthMethod.Valid { - app.TokenEndpointAuthMethod = sql.NullString{String: "client_secret_basic", Valid: true} - } - if !app.Scope.Valid { - app.Scope = sql.NullString{String: "", Valid: true} - } - if app.Contacts == nil { - app.Contacts = []string{} - } - - q.oauth2ProviderApps[i] = app - return app, nil - } - } - return database.OAuth2ProviderApp{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateOAuth2ProviderAppByID(_ context.Context, arg database.UpdateOAuth2ProviderAppByIDParams) (database.OAuth2ProviderApp, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderApp{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, app := range q.oauth2ProviderApps { - if app.Name == arg.Name && app.ID != arg.ID { - return database.OAuth2ProviderApp{}, errUniqueConstraint - } - } - - for index, app := range q.oauth2ProviderApps { - if app.ID == arg.ID { - app.UpdatedAt = arg.UpdatedAt - app.Name = arg.Name - app.Icon = arg.Icon - app.CallbackURL = arg.CallbackURL - app.RedirectUris = arg.RedirectUris - app.ClientType = arg.ClientType - app.DynamicallyRegistered = arg.DynamicallyRegistered - app.ClientSecretExpiresAt = arg.ClientSecretExpiresAt - app.GrantTypes = arg.GrantTypes - app.ResponseTypes = arg.ResponseTypes - app.TokenEndpointAuthMethod = arg.TokenEndpointAuthMethod - app.Scope = arg.Scope - app.Contacts = arg.Contacts - app.ClientUri = arg.ClientUri - app.LogoUri = arg.LogoUri - app.TosUri = arg.TosUri - app.PolicyUri = arg.PolicyUri - app.JwksUri = arg.JwksUri - app.Jwks = arg.Jwks - app.SoftwareID = arg.SoftwareID - app.SoftwareVersion = arg.SoftwareVersion - - // Apply RFC-compliant defaults to match database migration defaults - if !app.ClientType.Valid { - app.ClientType = sql.NullString{String: "confidential", Valid: true} - } - if !app.DynamicallyRegistered.Valid { - app.DynamicallyRegistered = sql.NullBool{Bool: false, Valid: true} - } - if len(app.GrantTypes) == 0 { - app.GrantTypes = []string{"authorization_code", "refresh_token"} - } - if len(app.ResponseTypes) == 0 { - app.ResponseTypes = []string{"code"} - } - if !app.TokenEndpointAuthMethod.Valid { - app.TokenEndpointAuthMethod = sql.NullString{String: "client_secret_basic", Valid: true} - } - if !app.Scope.Valid { - app.Scope = sql.NullString{String: "", Valid: true} - } - if app.Contacts == nil { - app.Contacts = []string{} - } - - q.oauth2ProviderApps[index] = app - return app, nil - } - } - return database.OAuth2ProviderApp{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateOAuth2ProviderAppSecretByID(_ context.Context, arg database.UpdateOAuth2ProviderAppSecretByIDParams) (database.OAuth2ProviderAppSecret, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.OAuth2ProviderAppSecret{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, secret := range q.oauth2ProviderAppSecrets { - if secret.ID == arg.ID { - newSecret := database.OAuth2ProviderAppSecret{ - ID: arg.ID, - CreatedAt: secret.CreatedAt, - SecretPrefix: secret.SecretPrefix, - HashedSecret: secret.HashedSecret, - DisplaySecret: secret.DisplaySecret, - AppID: secret.AppID, - LastUsedAt: arg.LastUsedAt, - } - q.oauth2ProviderAppSecrets[index] = newSecret - return newSecret, nil - } - } - return database.OAuth2ProviderAppSecret{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateOrganization(_ context.Context, arg database.UpdateOrganizationParams) (database.Organization, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.Organization{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - // Enforce the unique constraint, because the API endpoint relies on the database catching - // non-unique names during updates. - for _, org := range q.organizations { - if org.Name == arg.Name && org.ID != arg.ID { - return database.Organization{}, errUniqueConstraint - } - } - - for i, org := range q.organizations { - if org.ID == arg.ID { - org.Name = arg.Name - org.DisplayName = arg.DisplayName - org.Description = arg.Description - org.Icon = arg.Icon - q.organizations[i] = org - return org, nil - } - } - return database.Organization{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateOrganizationDeletedByID(_ context.Context, arg database.UpdateOrganizationDeletedByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, organization := range q.organizations { - if organization.ID != arg.ID || organization.IsDefault { - continue - } - organization.Deleted = true - organization.UpdatedAt = arg.UpdatedAt - q.organizations[index] = organization - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdatePresetPrebuildStatus(ctx context.Context, arg database.UpdatePresetPrebuildStatusParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, preset := range q.presets { - if preset.ID == arg.PresetID { - preset.PrebuildStatus = arg.Status - return nil - } - } - - return xerrors.Errorf("preset %v does not exist", arg.PresetID) -} - -func (q *FakeQuerier) UpdateProvisionerDaemonLastSeenAt(_ context.Context, arg database.UpdateProvisionerDaemonLastSeenAtParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for idx := range q.provisionerDaemons { - if q.provisionerDaemons[idx].ID != arg.ID { - continue - } - if q.provisionerDaemons[idx].LastSeenAt.Time.After(arg.LastSeenAt.Time) { - continue - } - q.provisionerDaemons[idx].LastSeenAt = arg.LastSeenAt - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateProvisionerJobByID(_ context.Context, arg database.UpdateProvisionerJobByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, job := range q.provisionerJobs { - if arg.ID != job.ID { - continue - } - job.UpdatedAt = arg.UpdatedAt - job.JobStatus = provisionerJobStatus(job) - q.provisionerJobs[index] = job - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateProvisionerJobWithCancelByID(_ context.Context, arg database.UpdateProvisionerJobWithCancelByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, job := range q.provisionerJobs { - if arg.ID != job.ID { - continue - } - job.CanceledAt = arg.CanceledAt - job.CompletedAt = arg.CompletedAt - job.JobStatus = provisionerJobStatus(job) - q.provisionerJobs[index] = job - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateProvisionerJobWithCompleteByID(_ context.Context, arg database.UpdateProvisionerJobWithCompleteByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, job := range q.provisionerJobs { - if arg.ID != job.ID { - continue - } - job.UpdatedAt = arg.UpdatedAt - job.CompletedAt = arg.CompletedAt - job.Error = arg.Error - job.ErrorCode = arg.ErrorCode - job.JobStatus = provisionerJobStatus(job) - q.provisionerJobs[index] = job - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateProvisionerJobWithCompleteWithStartedAtByID(_ context.Context, arg database.UpdateProvisionerJobWithCompleteWithStartedAtByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, job := range q.provisionerJobs { - if arg.ID != job.ID { - continue - } - job.UpdatedAt = arg.UpdatedAt - job.CompletedAt = arg.CompletedAt - job.Error = arg.Error - job.ErrorCode = arg.ErrorCode - job.StartedAt = arg.StartedAt - job.JobStatus = provisionerJobStatus(job) - q.provisionerJobs[index] = job - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateReplica(_ context.Context, arg database.UpdateReplicaParams) (database.Replica, error) { - if err := validateDatabaseType(arg); err != nil { - return database.Replica{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, replica := range q.replicas { - if replica.ID != arg.ID { - continue - } - replica.Hostname = arg.Hostname - replica.StartedAt = arg.StartedAt - replica.StoppedAt = arg.StoppedAt - replica.UpdatedAt = arg.UpdatedAt - replica.RelayAddress = arg.RelayAddress - replica.RegionID = arg.RegionID - replica.Version = arg.Version - replica.Error = arg.Error - replica.DatabaseLatency = arg.DatabaseLatency - replica.Primary = arg.Primary - q.replicas[index] = replica - return replica, nil - } - return database.Replica{}, sql.ErrNoRows -} - -func (*FakeQuerier) UpdateTailnetPeerStatusByCoordinator(context.Context, database.UpdateTailnetPeerStatusByCoordinatorParams) error { - return ErrUnimplemented -} - -func (q *FakeQuerier) UpdateTemplateACLByID(_ context.Context, arg database.UpdateTemplateACLByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, template := range q.templates { - if template.ID == arg.ID { - template.GroupACL = arg.GroupACL - template.UserACL = arg.UserACL - - q.templates[i] = template - return nil - } - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateAccessControlByID(_ context.Context, arg database.UpdateTemplateAccessControlByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for idx, tpl := range q.templates { - if tpl.ID != arg.ID { - continue - } - q.templates[idx].RequireActiveVersion = arg.RequireActiveVersion - q.templates[idx].Deprecated = arg.Deprecated - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateActiveVersionByID(_ context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, template := range q.templates { - if template.ID != arg.ID { - continue - } - template.ActiveVersionID = arg.ActiveVersionID - template.UpdatedAt = arg.UpdatedAt - q.templates[index] = template - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateDeletedByID(_ context.Context, arg database.UpdateTemplateDeletedByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, template := range q.templates { - if template.ID != arg.ID { - continue - } - template.Deleted = arg.Deleted - template.UpdatedAt = arg.UpdatedAt - q.templates[index] = template - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.UpdateTemplateMetaByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for idx, tpl := range q.templates { - if tpl.ID != arg.ID { - continue - } - tpl.UpdatedAt = dbtime.Now() - tpl.Name = arg.Name - tpl.DisplayName = arg.DisplayName - tpl.Description = arg.Description - tpl.Icon = arg.Icon - tpl.GroupACL = arg.GroupACL - tpl.AllowUserCancelWorkspaceJobs = arg.AllowUserCancelWorkspaceJobs - tpl.MaxPortSharingLevel = arg.MaxPortSharingLevel - tpl.UseClassicParameterFlow = arg.UseClassicParameterFlow - q.templates[idx] = tpl - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database.UpdateTemplateScheduleByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for idx, tpl := range q.templates { - if tpl.ID != arg.ID { - continue - } - tpl.AllowUserAutostart = arg.AllowUserAutostart - tpl.AllowUserAutostop = arg.AllowUserAutostop - tpl.UpdatedAt = dbtime.Now() - tpl.DefaultTTL = arg.DefaultTTL - tpl.ActivityBump = arg.ActivityBump - tpl.AutostopRequirementDaysOfWeek = arg.AutostopRequirementDaysOfWeek - tpl.AutostopRequirementWeeks = arg.AutostopRequirementWeeks - tpl.AutostartBlockDaysOfWeek = arg.AutostartBlockDaysOfWeek - tpl.FailureTTL = arg.FailureTTL - tpl.TimeTilDormant = arg.TimeTilDormant - tpl.TimeTilDormantAutoDelete = arg.TimeTilDormantAutoDelete - q.templates[idx] = tpl - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateVersionAITaskByJobID(_ context.Context, arg database.UpdateTemplateVersionAITaskByJobIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, templateVersion := range q.templateVersions { - if templateVersion.JobID != arg.JobID { - continue - } - templateVersion.HasAITask = arg.HasAITask - templateVersion.UpdatedAt = arg.UpdatedAt - q.templateVersions[index] = templateVersion - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, templateVersion := range q.templateVersions { - if templateVersion.ID != arg.ID { - continue - } - templateVersion.TemplateID = arg.TemplateID - templateVersion.UpdatedAt = arg.UpdatedAt - templateVersion.Name = arg.Name - templateVersion.Message = arg.Message - q.templateVersions[index] = templateVersion - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateVersionDescriptionByJobID(_ context.Context, arg database.UpdateTemplateVersionDescriptionByJobIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, templateVersion := range q.templateVersions { - if templateVersion.JobID != arg.JobID { - continue - } - templateVersion.Readme = arg.Readme - templateVersion.UpdatedAt = arg.UpdatedAt - q.templateVersions[index] = templateVersion - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateVersionExternalAuthProvidersByJobID(_ context.Context, arg database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, templateVersion := range q.templateVersions { - if templateVersion.JobID != arg.JobID { - continue - } - templateVersion.ExternalAuthProviders = arg.ExternalAuthProviders - templateVersion.UpdatedAt = arg.UpdatedAt - q.templateVersions[index] = templateVersion - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateTemplateWorkspacesLastUsedAt(_ context.Context, arg database.UpdateTemplateWorkspacesLastUsedAtParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, ws := range q.workspaces { - if ws.TemplateID != arg.TemplateID { - continue - } - ws.LastUsedAt = arg.LastUsedAt - q.workspaces[i] = ws - } - - return nil -} - -func (q *FakeQuerier) UpdateUserDeletedByID(_ context.Context, id uuid.UUID) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, u := range q.users { - if u.ID == id { - u.Deleted = true - q.users[i] = u - // NOTE: In the real world, this is done by a trigger. - q.apiKeys = slices.DeleteFunc(q.apiKeys, func(u database.APIKey) bool { - return id == u.UserID - }) - - q.userLinks = slices.DeleteFunc(q.userLinks, func(u database.UserLink) bool { - return id == u.UserID - }) - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserGithubComUserID(_ context.Context, arg database.UpdateUserGithubComUserIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, user := range q.users { - if user.ID != arg.ID { - continue - } - user.GithubComUserID = arg.GithubComUserID - q.users[i] = user - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserHashedOneTimePasscode(_ context.Context, arg database.UpdateUserHashedOneTimePasscodeParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, user := range q.users { - if user.ID != arg.ID { - continue - } - user.HashedOneTimePasscode = arg.HashedOneTimePasscode - user.OneTimePasscodeExpiresAt = arg.OneTimePasscodeExpiresAt - q.users[i] = user - } - return nil -} - -func (q *FakeQuerier) UpdateUserHashedPassword(_ context.Context, arg database.UpdateUserHashedPasswordParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, user := range q.users { - if user.ID != arg.ID { - continue - } - user.HashedPassword = arg.HashedPassword - user.HashedOneTimePasscode = nil - user.OneTimePasscodeExpiresAt = sql.NullTime{} - q.users[i] = user - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserLastSeenAt(_ context.Context, arg database.UpdateUserLastSeenAtParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, user := range q.users { - if user.ID != arg.ID { - continue - } - user.LastSeenAt = arg.LastSeenAt - user.UpdatedAt = arg.UpdatedAt - q.users[index] = user - return user, nil - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserLink(_ context.Context, params database.UpdateUserLinkParams) (database.UserLink, error) { - if err := validateDatabaseType(params); err != nil { - return database.UserLink{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - if u, err := q.getUserByIDNoLock(params.UserID); err == nil && u.Deleted { - return database.UserLink{}, deletedUserLinkError - } - - for i, link := range q.userLinks { - if link.UserID == params.UserID && link.LoginType == params.LoginType { - link.OAuthAccessToken = params.OAuthAccessToken - link.OAuthAccessTokenKeyID = params.OAuthAccessTokenKeyID - link.OAuthRefreshToken = params.OAuthRefreshToken - link.OAuthRefreshTokenKeyID = params.OAuthRefreshTokenKeyID - link.OAuthExpiry = params.OAuthExpiry - link.Claims = params.Claims - - q.userLinks[i] = link - return link, nil - } - } - - return database.UserLink{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserLinkedID(_ context.Context, params database.UpdateUserLinkedIDParams) (database.UserLink, error) { - if err := validateDatabaseType(params); err != nil { - return database.UserLink{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, link := range q.userLinks { - if link.UserID == params.UserID && link.LoginType == params.LoginType { - link.LinkedID = params.LinkedID - - q.userLinks[i] = link - return link, nil - } - } - - return database.UserLink{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserLoginType(_ context.Context, arg database.UpdateUserLoginTypeParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, u := range q.users { - if u.ID == arg.UserID { - u.LoginType = arg.NewLoginType - if arg.NewLoginType != database.LoginTypePassword { - u.HashedPassword = []byte{} - } - q.users[i] = u - return u, nil - } - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserNotificationPreferences(_ context.Context, arg database.UpdateUserNotificationPreferencesParams) (int64, error) { - err := validateDatabaseType(arg) - if err != nil { - return 0, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - var upserted int64 - for i := range arg.NotificationTemplateIds { - var ( - found bool - templateID = arg.NotificationTemplateIds[i] - disabled = arg.Disableds[i] - ) - - for j, np := range q.notificationPreferences { - if np.UserID != arg.UserID { - continue - } - - if np.NotificationTemplateID != templateID { - continue - } - - np.Disabled = disabled - np.UpdatedAt = dbtime.Now() - q.notificationPreferences[j] = np - - upserted++ - found = true - break - } - - if !found { - np := database.NotificationPreference{ - Disabled: disabled, - UserID: arg.UserID, - NotificationTemplateID: templateID, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - } - q.notificationPreferences = append(q.notificationPreferences, np) - upserted++ - } - } - - return upserted, nil -} - -func (q *FakeQuerier) UpdateUserProfile(_ context.Context, arg database.UpdateUserProfileParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, user := range q.users { - if user.ID != arg.ID { - continue - } - user.Email = arg.Email - user.Username = arg.Username - user.AvatarURL = arg.AvatarURL - user.Name = arg.Name - q.users[index] = user - return user, nil - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserQuietHoursSchedule(_ context.Context, arg database.UpdateUserQuietHoursScheduleParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, user := range q.users { - if user.ID != arg.ID { - continue - } - user.QuietHoursSchedule = arg.QuietHoursSchedule - q.users[index] = user - return user, nil - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserRoles(_ context.Context, arg database.UpdateUserRolesParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, user := range q.users { - if user.ID != arg.ID { - continue - } - - // Set new roles - user.RBACRoles = slice.Unique(arg.GrantedRoles) - // Remove duplicates and sort - uniqueRoles := make([]string, 0, len(user.RBACRoles)) - exist := make(map[string]struct{}) - for _, r := range user.RBACRoles { - if _, ok := exist[r]; ok { - continue - } - exist[r] = struct{}{} - uniqueRoles = append(uniqueRoles, r) - } - sort.Strings(uniqueRoles) - user.RBACRoles = uniqueRoles - - q.users[index] = user - return user, nil - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUserStatusParams) (database.User, error) { - if err := validateDatabaseType(arg); err != nil { - return database.User{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, user := range q.users { - if user.ID != arg.ID { - continue - } - user.Status = arg.Status - user.UpdatedAt = arg.UpdatedAt - q.users[index] = user - - q.userStatusChanges = append(q.userStatusChanges, database.UserStatusChange{ - UserID: user.ID, - NewStatus: user.Status, - ChangedAt: user.UpdatedAt, - }) - return user, nil - } - return database.User{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserTerminalFont(ctx context.Context, arg database.UpdateUserTerminalFontParams) (database.UserConfig, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.UserConfig{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, uc := range q.userConfigs { - if uc.UserID != arg.UserID || uc.Key != "terminal_font" { - continue - } - uc.Value = arg.TerminalFont - q.userConfigs[i] = uc - return uc, nil - } - - uc := database.UserConfig{ - UserID: arg.UserID, - Key: "terminal_font", - Value: arg.TerminalFont, - } - q.userConfigs = append(q.userConfigs, uc) - return uc, nil -} - -func (q *FakeQuerier) UpdateUserThemePreference(_ context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.UserConfig{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, uc := range q.userConfigs { - if uc.UserID != arg.UserID || uc.Key != "theme_preference" { - continue - } - uc.Value = arg.ThemePreference - q.userConfigs[i] = uc - return uc, nil - } - - uc := database.UserConfig{ - UserID: arg.UserID, - Key: "theme_preference", - Value: arg.ThemePreference, - } - q.userConfigs = append(q.userConfigs, uc) - return uc, nil -} - -func (q *FakeQuerier) UpdateVolumeResourceMonitor(_ context.Context, arg database.UpdateVolumeResourceMonitorParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, monitor := range q.workspaceAgentVolumeResourceMonitors { - if monitor.AgentID != arg.AgentID || monitor.Path != arg.Path { - continue - } - - monitor.State = arg.State - monitor.UpdatedAt = arg.UpdatedAt - monitor.DebouncedUntil = arg.DebouncedUntil - q.workspaceAgentVolumeResourceMonitors[i] = monitor - return nil - } - - return nil -} - -func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceTable{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, workspace := range q.workspaces { - if workspace.Deleted || workspace.ID != arg.ID { - continue - } - for _, other := range q.workspaces { - if other.Deleted || other.ID == workspace.ID || workspace.OwnerID != other.OwnerID { - continue - } - if other.Name == arg.Name { - return database.WorkspaceTable{}, errUniqueConstraint - } - } - - workspace.Name = arg.Name - q.workspaces[i] = workspace - - return workspace, nil - } - - return database.WorkspaceTable{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAgentConnectionByID(_ context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, agent := range q.workspaceAgents { - if agent.ID != arg.ID { - continue - } - agent.FirstConnectedAt = arg.FirstConnectedAt - agent.LastConnectedAt = arg.LastConnectedAt - agent.DisconnectedAt = arg.DisconnectedAt - agent.UpdatedAt = arg.UpdatedAt - agent.LastConnectedReplicaID = arg.LastConnectedReplicaID - q.workspaceAgents[index] = agent - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAgentLifecycleStateByID(_ context.Context, arg database.UpdateWorkspaceAgentLifecycleStateByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - for i, agent := range q.workspaceAgents { - if agent.ID == arg.ID { - agent.LifecycleState = arg.LifecycleState - agent.StartedAt = arg.StartedAt - agent.ReadyAt = arg.ReadyAt - q.workspaceAgents[i] = agent - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAgentLogOverflowByID(_ context.Context, arg database.UpdateWorkspaceAgentLogOverflowByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - for i, agent := range q.workspaceAgents { - if agent.ID == arg.ID { - agent.LogsOverflowed = arg.LogsOverflowed - q.workspaceAgents[i] = agent - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAgentMetadata(_ context.Context, arg database.UpdateWorkspaceAgentMetadataParams) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, m := range q.workspaceAgentMetadata { - if m.WorkspaceAgentID != arg.WorkspaceAgentID { - continue - } - for j := 0; j < len(arg.Key); j++ { - if m.Key == arg.Key[j] { - q.workspaceAgentMetadata[i].Value = arg.Value[j] - q.workspaceAgentMetadata[i].Error = arg.Error[j] - q.workspaceAgentMetadata[i].CollectedAt = arg.CollectedAt[j] - return nil - } - } - } - - return nil -} - -func (q *FakeQuerier) UpdateWorkspaceAgentStartupByID(_ context.Context, arg database.UpdateWorkspaceAgentStartupByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - if len(arg.Subsystems) > 0 { - seen := map[database.WorkspaceAgentSubsystem]struct{}{ - arg.Subsystems[0]: {}, - } - for i := 1; i < len(arg.Subsystems); i++ { - s := arg.Subsystems[i] - if _, ok := seen[s]; ok { - return xerrors.Errorf("duplicate subsystem %q", s) - } - seen[s] = struct{}{} - - if arg.Subsystems[i-1] > arg.Subsystems[i] { - return xerrors.Errorf("subsystems not sorted: %q > %q", arg.Subsystems[i-1], arg.Subsystems[i]) - } - } - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, agent := range q.workspaceAgents { - if agent.ID != arg.ID { - continue - } - - agent.Version = arg.Version - agent.APIVersion = arg.APIVersion - agent.ExpandedDirectory = arg.ExpandedDirectory - agent.Subsystems = arg.Subsystems - q.workspaceAgents[index] = agent - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAppHealthByID(_ context.Context, arg database.UpdateWorkspaceAppHealthByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, app := range q.workspaceApps { - if app.ID != arg.ID { - continue - } - app.Health = arg.Health - q.workspaceApps[index] = app - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAutomaticUpdates(_ context.Context, arg database.UpdateWorkspaceAutomaticUpdatesParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - workspace.AutomaticUpdates = arg.AutomaticUpdates - q.workspaces[index] = workspace - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.UpdateWorkspaceAutostartParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - workspace.AutostartSchedule = arg.AutostartSchedule - workspace.NextStartAt = arg.NextStartAt - q.workspaces[index] = workspace - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceBuildAITaskByID(_ context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { - if arg.HasAITask.Bool && !arg.SidebarAppID.Valid { - return xerrors.Errorf("ai_task_sidebar_app_id is required when has_ai_task is true") - } - if !arg.HasAITask.Valid && arg.SidebarAppID.Valid { - return xerrors.Errorf("ai_task_sidebar_app_id is can only be set when has_ai_task is true") - } - - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.ID != arg.ID { - continue - } - workspaceBuild.HasAITask = arg.HasAITask - workspaceBuild.AITaskSidebarAppID = arg.SidebarAppID - workspaceBuild.UpdatedAt = dbtime.Now() - q.workspaceBuilds[index] = workspaceBuild - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceBuildCostByID(_ context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspaceBuild := range q.workspaceBuilds { - if workspaceBuild.ID != arg.ID { - continue - } - workspaceBuild.DailyCost = arg.DailyCost - q.workspaceBuilds[index] = workspaceBuild - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceBuildDeadlineByID(_ context.Context, arg database.UpdateWorkspaceBuildDeadlineByIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for idx, build := range q.workspaceBuilds { - if build.ID != arg.ID { - continue - } - build.Deadline = arg.Deadline - build.MaxDeadline = arg.MaxDeadline - build.UpdatedAt = arg.UpdatedAt - q.workspaceBuilds[idx] = build - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceBuildProvisionerStateByID(_ context.Context, arg database.UpdateWorkspaceBuildProvisionerStateByIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for idx, build := range q.workspaceBuilds { - if build.ID != arg.ID { - continue - } - build.ProvisionerState = arg.ProvisionerState - build.UpdatedAt = arg.UpdatedAt - q.workspaceBuilds[idx] = build - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceDeletedByID(_ context.Context, arg database.UpdateWorkspaceDeletedByIDParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - workspace.Deleted = arg.Deleted - q.workspaces[index] = workspace - return nil - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceDormantDeletingAt(_ context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.WorkspaceTable, error) { - if err := validateDatabaseType(arg); err != nil { - return database.WorkspaceTable{}, err - } - q.mutex.Lock() - defer q.mutex.Unlock() - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - workspace.DormantAt = arg.DormantAt - if workspace.DormantAt.Time.IsZero() { - workspace.LastUsedAt = dbtime.Now() - workspace.DeletingAt = sql.NullTime{} - } - if !workspace.DormantAt.Time.IsZero() { - var template database.TemplateTable - for _, t := range q.templates { - if t.ID == workspace.TemplateID { - template = t - break - } - } - if template.ID == uuid.Nil { - return database.WorkspaceTable{}, xerrors.Errorf("unable to find workspace template") - } - if template.TimeTilDormantAutoDelete > 0 { - workspace.DeletingAt = sql.NullTime{ - Valid: true, - Time: workspace.DormantAt.Time.Add(time.Duration(template.TimeTilDormantAutoDelete)), - } - } - } - q.workspaces[index] = workspace - return workspace, nil - } - return database.WorkspaceTable{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceLastUsedAt(_ context.Context, arg database.UpdateWorkspaceLastUsedAtParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - workspace.LastUsedAt = arg.LastUsedAt - q.workspaces[index] = workspace - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceNextStartAt(_ context.Context, arg database.UpdateWorkspaceNextStartAtParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - - workspace.NextStartAt = arg.NextStartAt - q.workspaces[index] = workspace - - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceProxy(_ context.Context, arg database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, p := range q.workspaceProxies { - if p.Name == arg.Name && p.ID != arg.ID { - return database.WorkspaceProxy{}, errUniqueConstraint - } - } - - for i, p := range q.workspaceProxies { - if p.ID == arg.ID { - p.Name = arg.Name - p.DisplayName = arg.DisplayName - p.Icon = arg.Icon - if len(p.TokenHashedSecret) > 0 { - p.TokenHashedSecret = arg.TokenHashedSecret - } - q.workspaceProxies[i] = p - return p, nil - } - } - return database.WorkspaceProxy{}, sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceProxyDeleted(_ context.Context, arg database.UpdateWorkspaceProxyDeletedParams) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, p := range q.workspaceProxies { - if p.ID == arg.ID { - p.Deleted = arg.Deleted - p.UpdatedAt = dbtime.Now() - q.workspaceProxies[i] = p - return nil - } - } - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspaceTTL(_ context.Context, arg database.UpdateWorkspaceTTLParams) error { - if err := validateDatabaseType(arg); err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for index, workspace := range q.workspaces { - if workspace.ID != arg.ID { - continue - } - workspace.Ttl = arg.Ttl - q.workspaces[index] = workspace - return nil - } - - return sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(_ context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.WorkspaceTable, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - affectedRows := []database.WorkspaceTable{} - for i, ws := range q.workspaces { - if ws.TemplateID != arg.TemplateID { - continue - } - - if ws.DormantAt.Time.IsZero() { - continue - } - - if !arg.DormantAt.IsZero() { - ws.DormantAt = sql.NullTime{ - Valid: true, - Time: arg.DormantAt, - } - } - - deletingAt := sql.NullTime{ - Valid: arg.TimeTilDormantAutodeleteMs > 0, - } - if arg.TimeTilDormantAutodeleteMs > 0 { - deletingAt.Time = ws.DormantAt.Time.Add(time.Duration(arg.TimeTilDormantAutodeleteMs) * time.Millisecond) - } - ws.DeletingAt = deletingAt - q.workspaces[i] = ws - affectedRows = append(affectedRows, ws) - } - - return affectedRows, nil -} - -func (q *FakeQuerier) UpdateWorkspacesTTLByTemplateID(_ context.Context, arg database.UpdateWorkspacesTTLByTemplateIDParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, ws := range q.workspaces { - if ws.TemplateID != arg.TemplateID { - continue - } - - q.workspaces[i].Ttl = arg.Ttl - } - - return nil -} - -func (q *FakeQuerier) UpsertAnnouncementBanners(_ context.Context, data string) error { - q.mutex.RLock() - defer q.mutex.RUnlock() - - q.announcementBanners = []byte(data) - return nil -} - -func (q *FakeQuerier) UpsertAppSecurityKey(_ context.Context, data string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.appSecurityKey = data - return nil -} - -func (q *FakeQuerier) UpsertApplicationName(_ context.Context, data string) error { - q.mutex.RLock() - defer q.mutex.RUnlock() - - q.applicationName = data - return nil -} - -func (q *FakeQuerier) UpsertCoordinatorResumeTokenSigningKey(_ context.Context, value string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.coordinatorResumeTokenSigningKey = value - return nil -} - -func (q *FakeQuerier) UpsertDefaultProxy(_ context.Context, arg database.UpsertDefaultProxyParams) error { - q.defaultProxyDisplayName = arg.DisplayName - q.defaultProxyIconURL = arg.IconUrl - return nil -} - -func (q *FakeQuerier) UpsertHealthSettings(_ context.Context, data string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.healthSettings = []byte(data) - return nil -} - -func (q *FakeQuerier) UpsertLastUpdateCheck(_ context.Context, data string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.lastUpdateCheck = []byte(data) - return nil -} - -func (q *FakeQuerier) UpsertLogoURL(_ context.Context, data string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.logoURL = data - return nil -} - -func (q *FakeQuerier) UpsertNotificationReportGeneratorLog(_ context.Context, arg database.UpsertNotificationReportGeneratorLogParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, record := range q.notificationReportGeneratorLogs { - if arg.NotificationTemplateID == record.NotificationTemplateID { - q.notificationReportGeneratorLogs[i].LastGeneratedAt = arg.LastGeneratedAt - return nil - } - } - - q.notificationReportGeneratorLogs = append(q.notificationReportGeneratorLogs, database.NotificationReportGeneratorLog(arg)) - return nil -} - -func (q *FakeQuerier) UpsertNotificationsSettings(_ context.Context, data string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.notificationsSettings = []byte(data) - return nil -} - -func (q *FakeQuerier) UpsertOAuth2GithubDefaultEligible(_ context.Context, eligible bool) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.oauth2GithubDefaultEligible = &eligible - return nil -} - -func (q *FakeQuerier) UpsertOAuthSigningKey(_ context.Context, value string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.oauthSigningKey = value - return nil -} - -func (q *FakeQuerier) UpsertPrebuildsSettings(_ context.Context, value string) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - q.prebuildsSettings = []byte(value) - return nil -} - -func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) { - if err := validateDatabaseType(arg); err != nil { - return database.ProvisionerDaemon{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - // Look for existing daemon using the same composite key as SQL - for i, d := range q.provisionerDaemons { - if d.OrganizationID == arg.OrganizationID && - d.Name == arg.Name && - getOwnerFromTags(d.Tags) == getOwnerFromTags(arg.Tags) { - d.Provisioners = arg.Provisioners - d.Tags = maps.Clone(arg.Tags) - d.LastSeenAt = arg.LastSeenAt - d.Version = arg.Version - d.APIVersion = arg.APIVersion - d.OrganizationID = arg.OrganizationID - d.KeyID = arg.KeyID - q.provisionerDaemons[i] = d - return d, nil - } - } - d := database.ProvisionerDaemon{ - ID: uuid.New(), - CreatedAt: arg.CreatedAt, - Name: arg.Name, - Provisioners: arg.Provisioners, - Tags: maps.Clone(arg.Tags), - LastSeenAt: arg.LastSeenAt, - Version: arg.Version, - APIVersion: arg.APIVersion, - OrganizationID: arg.OrganizationID, - KeyID: arg.KeyID, - } - q.provisionerDaemons = append(q.provisionerDaemons, d) - return d, nil -} - -func (q *FakeQuerier) UpsertRuntimeConfig(_ context.Context, arg database.UpsertRuntimeConfigParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - q.runtimeConfig[arg.Key] = arg.Value - return nil -} - -func (*FakeQuerier) UpsertTailnetAgent(context.Context, database.UpsertTailnetAgentParams) (database.TailnetAgent, error) { - return database.TailnetAgent{}, ErrUnimplemented -} - -func (*FakeQuerier) UpsertTailnetClient(context.Context, database.UpsertTailnetClientParams) (database.TailnetClient, error) { - return database.TailnetClient{}, ErrUnimplemented -} - -func (*FakeQuerier) UpsertTailnetClientSubscription(context.Context, database.UpsertTailnetClientSubscriptionParams) error { - return ErrUnimplemented -} - -func (*FakeQuerier) UpsertTailnetCoordinator(context.Context, uuid.UUID) (database.TailnetCoordinator, error) { - return database.TailnetCoordinator{}, ErrUnimplemented -} - -func (*FakeQuerier) UpsertTailnetPeer(_ context.Context, arg database.UpsertTailnetPeerParams) (database.TailnetPeer, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.TailnetPeer{}, err - } - - return database.TailnetPeer{}, ErrUnimplemented -} - -func (*FakeQuerier) UpsertTailnetTunnel(_ context.Context, arg database.UpsertTailnetTunnelParams) (database.TailnetTunnel, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.TailnetTunnel{}, err - } - - return database.TailnetTunnel{}, ErrUnimplemented -} - -func (q *FakeQuerier) UpsertTelemetryItem(_ context.Context, arg database.UpsertTelemetryItemParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, item := range q.telemetryItems { - if item.Key == arg.Key { - q.telemetryItems[i].Value = arg.Value - q.telemetryItems[i].UpdatedAt = time.Now() - return nil - } - } - - q.telemetryItems = append(q.telemetryItems, database.TelemetryItem{ - Key: arg.Key, - Value: arg.Value, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }) - - return nil -} - -func (q *FakeQuerier) UpsertTemplateUsageStats(ctx context.Context) error { - q.mutex.Lock() - defer q.mutex.Unlock() - - /* - WITH - */ - - /* - latest_start AS ( - SELECT - -- Truncate to hour so that we always look at even ranges of data. - date_trunc('hour', COALESCE( - MAX(start_time) - '1 hour'::interval), - -- Fallback when there are no template usage stats yet. - -- App stats can exist before this, but not agent stats, - -- limit the lookback to avoid inconsistency. - (SELECT MIN(created_at) FROM workspace_agent_stats) - )) AS t - FROM - template_usage_stats - ), - */ - - now := time.Now() - latestStart := time.Time{} - for _, stat := range q.templateUsageStats { - if stat.StartTime.After(latestStart) { - latestStart = stat.StartTime.Add(-time.Hour) - } - } - if latestStart.IsZero() { - for _, stat := range q.workspaceAgentStats { - if latestStart.IsZero() || stat.CreatedAt.Before(latestStart) { - latestStart = stat.CreatedAt - } - } - } - if latestStart.IsZero() { - return nil - } - latestStart = latestStart.Truncate(time.Hour) - - /* - workspace_app_stat_buckets AS ( - SELECT - -- Truncate the minute to the nearest half hour, this is the bucket size - -- for the data. - date_trunc('hour', s.minute_bucket) + trunc(date_part('minute', s.minute_bucket) / 30) * 30 * '1 minute'::interval AS time_bucket, - w.template_id, - was.user_id, - -- Both app stats and agent stats track web terminal usage, but - -- by different means. The app stats value should be more - -- accurate so we don't want to discard it just yet. - CASE - WHEN was.access_method = 'terminal' - THEN '[terminal]' -- Unique name, app names can't contain brackets. - ELSE was.slug_or_port - END AS app_name, - COUNT(DISTINCT s.minute_bucket) AS app_minutes, - -- Store each unique minute bucket for later merge between datasets. - array_agg(DISTINCT s.minute_bucket) AS minute_buckets - FROM - workspace_app_stats AS was - JOIN - workspaces AS w - ON - w.id = was.workspace_id - -- Generate a series of minute buckets for each session for computing the - -- mintes/bucket. - CROSS JOIN - generate_series( - date_trunc('minute', was.session_started_at), - -- Subtract 1 microsecond to avoid creating an extra series. - date_trunc('minute', was.session_ended_at - '1 microsecond'::interval), - '1 minute'::interval - ) AS s(minute_bucket) - WHERE - -- s.minute_bucket >= @start_time::timestamptz - -- AND s.minute_bucket < @end_time::timestamptz - s.minute_bucket >= (SELECT t FROM latest_start) - AND s.minute_bucket < NOW() - GROUP BY - time_bucket, w.template_id, was.user_id, was.access_method, was.slug_or_port - ), - */ - - type workspaceAppStatGroupBy struct { - TimeBucket time.Time - TemplateID uuid.UUID - UserID uuid.UUID - AccessMethod string - SlugOrPort string - } - type workspaceAppStatRow struct { - workspaceAppStatGroupBy - AppName string - AppMinutes int - MinuteBuckets map[time.Time]struct{} - } - workspaceAppStatRows := make(map[workspaceAppStatGroupBy]workspaceAppStatRow) - for _, was := range q.workspaceAppStats { - // Preflight: s.minute_bucket >= (SELECT t FROM latest_start) - if was.SessionEndedAt.Before(latestStart) { - continue - } - // JOIN workspaces - w, err := q.getWorkspaceByIDNoLock(ctx, was.WorkspaceID) - if err != nil { - return err - } - // CROSS JOIN generate_series - for t := was.SessionStartedAt.Truncate(time.Minute); t.Before(was.SessionEndedAt); t = t.Add(time.Minute) { - // WHERE - if t.Before(latestStart) || t.After(now) || t.Equal(now) { - continue - } - - bucket := t.Truncate(30 * time.Minute) - // GROUP BY - key := workspaceAppStatGroupBy{ - TimeBucket: bucket, - TemplateID: w.TemplateID, - UserID: was.UserID, - AccessMethod: was.AccessMethod, - SlugOrPort: was.SlugOrPort, - } - // SELECT - row, ok := workspaceAppStatRows[key] - if !ok { - row = workspaceAppStatRow{ - workspaceAppStatGroupBy: key, - AppName: was.SlugOrPort, - AppMinutes: 0, - MinuteBuckets: make(map[time.Time]struct{}), - } - if was.AccessMethod == "terminal" { - row.AppName = "[terminal]" - } - } - row.MinuteBuckets[t] = struct{}{} - row.AppMinutes = len(row.MinuteBuckets) - workspaceAppStatRows[key] = row - } - } - - /* - agent_stats_buckets AS ( - SELECT - -- Truncate the minute to the nearest half hour, this is the bucket size - -- for the data. - date_trunc('hour', created_at) + trunc(date_part('minute', created_at) / 30) * 30 * '1 minute'::interval AS time_bucket, - template_id, - user_id, - -- Store each unique minute bucket for later merge between datasets. - array_agg( - DISTINCT CASE - WHEN - session_count_ssh > 0 - -- TODO(mafredri): Enable when we have the column. - -- OR session_count_sftp > 0 - OR session_count_reconnecting_pty > 0 - OR session_count_vscode > 0 - OR session_count_jetbrains > 0 - THEN - date_trunc('minute', created_at) - ELSE - NULL - END - ) AS minute_buckets, - COUNT(DISTINCT CASE WHEN session_count_ssh > 0 THEN date_trunc('minute', created_at) ELSE NULL END) AS ssh_mins, - -- TODO(mafredri): Enable when we have the column. - -- COUNT(DISTINCT CASE WHEN session_count_sftp > 0 THEN date_trunc('minute', created_at) ELSE NULL END) AS sftp_mins, - COUNT(DISTINCT CASE WHEN session_count_reconnecting_pty > 0 THEN date_trunc('minute', created_at) ELSE NULL END) AS reconnecting_pty_mins, - COUNT(DISTINCT CASE WHEN session_count_vscode > 0 THEN date_trunc('minute', created_at) ELSE NULL END) AS vscode_mins, - COUNT(DISTINCT CASE WHEN session_count_jetbrains > 0 THEN date_trunc('minute', created_at) ELSE NULL END) AS jetbrains_mins, - -- NOTE(mafredri): The agent stats are currently very unreliable, and - -- sometimes the connections are missing, even during active sessions. - -- Since we can't fully rely on this, we check for "any connection - -- during this half-hour". A better solution here would be preferable. - MAX(connection_count) > 0 AS has_connection - FROM - workspace_agent_stats - WHERE - -- created_at >= @start_time::timestamptz - -- AND created_at < @end_time::timestamptz - created_at >= (SELECT t FROM latest_start) - AND created_at < NOW() - -- Inclusion criteria to filter out empty results. - AND ( - session_count_ssh > 0 - -- TODO(mafredri): Enable when we have the column. - -- OR session_count_sftp > 0 - OR session_count_reconnecting_pty > 0 - OR session_count_vscode > 0 - OR session_count_jetbrains > 0 - ) - GROUP BY - time_bucket, template_id, user_id - ), - */ - - type agentStatGroupBy struct { - TimeBucket time.Time - TemplateID uuid.UUID - UserID uuid.UUID - } - type agentStatRow struct { - agentStatGroupBy - MinuteBuckets map[time.Time]struct{} - SSHMinuteBuckets map[time.Time]struct{} - SSHMins int - SFTPMinuteBuckets map[time.Time]struct{} - SFTPMins int - ReconnectingPTYMinuteBuckets map[time.Time]struct{} - ReconnectingPTYMins int - VSCodeMinuteBuckets map[time.Time]struct{} - VSCodeMins int - JetBrainsMinuteBuckets map[time.Time]struct{} - JetBrainsMins int - HasConnection bool - } - agentStatRows := make(map[agentStatGroupBy]agentStatRow) - for _, was := range q.workspaceAgentStats { - // WHERE - if was.CreatedAt.Before(latestStart) || was.CreatedAt.After(now) || was.CreatedAt.Equal(now) { - continue - } - if was.SessionCountSSH == 0 && was.SessionCountReconnectingPTY == 0 && was.SessionCountVSCode == 0 && was.SessionCountJetBrains == 0 { - continue - } - // GROUP BY - key := agentStatGroupBy{ - TimeBucket: was.CreatedAt.Truncate(30 * time.Minute), - TemplateID: was.TemplateID, - UserID: was.UserID, - } - // SELECT - row, ok := agentStatRows[key] - if !ok { - row = agentStatRow{ - agentStatGroupBy: key, - MinuteBuckets: make(map[time.Time]struct{}), - SSHMinuteBuckets: make(map[time.Time]struct{}), - SFTPMinuteBuckets: make(map[time.Time]struct{}), - ReconnectingPTYMinuteBuckets: make(map[time.Time]struct{}), - VSCodeMinuteBuckets: make(map[time.Time]struct{}), - JetBrainsMinuteBuckets: make(map[time.Time]struct{}), - } - } - minute := was.CreatedAt.Truncate(time.Minute) - row.MinuteBuckets[minute] = struct{}{} - if was.SessionCountSSH > 0 { - row.SSHMinuteBuckets[minute] = struct{}{} - row.SSHMins = len(row.SSHMinuteBuckets) - } - // TODO(mafredri): Enable when we have the column. - // if was.SessionCountSFTP > 0 { - // row.SFTPMinuteBuckets[minute] = struct{}{} - // row.SFTPMins = len(row.SFTPMinuteBuckets) - // } - _ = row.SFTPMinuteBuckets - if was.SessionCountReconnectingPTY > 0 { - row.ReconnectingPTYMinuteBuckets[minute] = struct{}{} - row.ReconnectingPTYMins = len(row.ReconnectingPTYMinuteBuckets) - } - if was.SessionCountVSCode > 0 { - row.VSCodeMinuteBuckets[minute] = struct{}{} - row.VSCodeMins = len(row.VSCodeMinuteBuckets) - } - if was.SessionCountJetBrains > 0 { - row.JetBrainsMinuteBuckets[minute] = struct{}{} - row.JetBrainsMins = len(row.JetBrainsMinuteBuckets) - } - if !row.HasConnection { - row.HasConnection = was.ConnectionCount > 0 - } - agentStatRows[key] = row - } - - /* - stats AS ( - SELECT - stats.time_bucket AS start_time, - stats.time_bucket + '30 minutes'::interval AS end_time, - stats.template_id, - stats.user_id, - -- Sum/distinct to handle zero/duplicate values due union and to unnest. - COUNT(DISTINCT minute_bucket) AS usage_mins, - array_agg(DISTINCT minute_bucket) AS minute_buckets, - SUM(DISTINCT stats.ssh_mins) AS ssh_mins, - SUM(DISTINCT stats.sftp_mins) AS sftp_mins, - SUM(DISTINCT stats.reconnecting_pty_mins) AS reconnecting_pty_mins, - SUM(DISTINCT stats.vscode_mins) AS vscode_mins, - SUM(DISTINCT stats.jetbrains_mins) AS jetbrains_mins, - -- This is what we unnested, re-nest as json. - jsonb_object_agg(stats.app_name, stats.app_minutes) FILTER (WHERE stats.app_name IS NOT NULL) AS app_usage_mins - FROM ( - SELECT - time_bucket, - template_id, - user_id, - 0 AS ssh_mins, - 0 AS sftp_mins, - 0 AS reconnecting_pty_mins, - 0 AS vscode_mins, - 0 AS jetbrains_mins, - app_name, - app_minutes, - minute_buckets - FROM - workspace_app_stat_buckets - - UNION ALL - - SELECT - time_bucket, - template_id, - user_id, - ssh_mins, - -- TODO(mafredri): Enable when we have the column. - 0 AS sftp_mins, - reconnecting_pty_mins, - vscode_mins, - jetbrains_mins, - NULL AS app_name, - NULL AS app_minutes, - minute_buckets - FROM - agent_stats_buckets - WHERE - -- See note in the agent_stats_buckets CTE. - has_connection - ) AS stats, unnest(minute_buckets) AS minute_bucket - GROUP BY - stats.time_bucket, stats.template_id, stats.user_id - ), - */ - - type statsGroupBy struct { - TimeBucket time.Time - TemplateID uuid.UUID - UserID uuid.UUID - } - type statsRow struct { - statsGroupBy - UsageMinuteBuckets map[time.Time]struct{} - UsageMins int - SSHMins int - SFTPMins int - ReconnectingPTYMins int - VSCodeMins int - JetBrainsMins int - AppUsageMinutes map[string]int - } - statsRows := make(map[statsGroupBy]statsRow) - for _, was := range workspaceAppStatRows { - // GROUP BY - key := statsGroupBy{ - TimeBucket: was.TimeBucket, - TemplateID: was.TemplateID, - UserID: was.UserID, - } - // SELECT - row, ok := statsRows[key] - if !ok { - row = statsRow{ - statsGroupBy: key, - UsageMinuteBuckets: make(map[time.Time]struct{}), - AppUsageMinutes: make(map[string]int), - } - } - for t := range was.MinuteBuckets { - row.UsageMinuteBuckets[t] = struct{}{} - } - row.UsageMins = len(row.UsageMinuteBuckets) - row.AppUsageMinutes[was.AppName] = was.AppMinutes - statsRows[key] = row - } - for _, was := range agentStatRows { - // GROUP BY - key := statsGroupBy{ - TimeBucket: was.TimeBucket, - TemplateID: was.TemplateID, - UserID: was.UserID, - } - // SELECT - row, ok := statsRows[key] - if !ok { - row = statsRow{ - statsGroupBy: key, - UsageMinuteBuckets: make(map[time.Time]struct{}), - AppUsageMinutes: make(map[string]int), - } - } - for t := range was.MinuteBuckets { - row.UsageMinuteBuckets[t] = struct{}{} - } - row.UsageMins = len(row.UsageMinuteBuckets) - row.SSHMins += was.SSHMins - row.SFTPMins += was.SFTPMins - row.ReconnectingPTYMins += was.ReconnectingPTYMins - row.VSCodeMins += was.VSCodeMins - row.JetBrainsMins += was.JetBrainsMins - statsRows[key] = row - } - - /* - minute_buckets AS ( - -- Create distinct minute buckets for user-activity, so we can filter out - -- irrelevant latencies. - SELECT DISTINCT ON (stats.start_time, stats.template_id, stats.user_id, minute_bucket) - stats.start_time, - stats.template_id, - stats.user_id, - minute_bucket - FROM - stats, unnest(minute_buckets) AS minute_bucket - ), - latencies AS ( - -- Select all non-zero latencies for all the minutes that a user used the - -- workspace in some way. - SELECT - mb.start_time, - mb.template_id, - mb.user_id, - -- TODO(mafredri): We're doing medians on medians here, we may want to - -- improve upon this at some point. - PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY was.connection_median_latency_ms)::real AS median_latency_ms - FROM - minute_buckets AS mb - JOIN - workspace_agent_stats AS was - ON - date_trunc('minute', was.created_at) = mb.minute_bucket - AND was.template_id = mb.template_id - AND was.user_id = mb.user_id - AND was.connection_median_latency_ms >= 0 - GROUP BY - mb.start_time, mb.template_id, mb.user_id - ) - */ - - type latenciesGroupBy struct { - StartTime time.Time - TemplateID uuid.UUID - UserID uuid.UUID - } - type latenciesRow struct { - latenciesGroupBy - Latencies []float64 - MedianLatencyMS float64 - } - latenciesRows := make(map[latenciesGroupBy]latenciesRow) - for _, stat := range statsRows { - for t := range stat.UsageMinuteBuckets { - // GROUP BY - key := latenciesGroupBy{ - StartTime: stat.TimeBucket, - TemplateID: stat.TemplateID, - UserID: stat.UserID, - } - // JOIN - for _, was := range q.workspaceAgentStats { - if !t.Equal(was.CreatedAt.Truncate(time.Minute)) { - continue - } - if was.TemplateID != stat.TemplateID || was.UserID != stat.UserID { - continue - } - if was.ConnectionMedianLatencyMS < 0 { - continue - } - // SELECT - row, ok := latenciesRows[key] - if !ok { - row = latenciesRow{ - latenciesGroupBy: key, - } - } - row.Latencies = append(row.Latencies, was.ConnectionMedianLatencyMS) - sort.Float64s(row.Latencies) - if len(row.Latencies) == 1 { - row.MedianLatencyMS = was.ConnectionMedianLatencyMS - } else if len(row.Latencies)%2 == 0 { - row.MedianLatencyMS = (row.Latencies[len(row.Latencies)/2-1] + row.Latencies[len(row.Latencies)/2]) / 2 - } else { - row.MedianLatencyMS = row.Latencies[len(row.Latencies)/2] - } - latenciesRows[key] = row - } - } - } - - /* - INSERT INTO template_usage_stats AS tus ( - start_time, - end_time, - template_id, - user_id, - usage_mins, - median_latency_ms, - ssh_mins, - sftp_mins, - reconnecting_pty_mins, - vscode_mins, - jetbrains_mins, - app_usage_mins - ) ( - SELECT - stats.start_time, - stats.end_time, - stats.template_id, - stats.user_id, - stats.usage_mins, - latencies.median_latency_ms, - stats.ssh_mins, - stats.sftp_mins, - stats.reconnecting_pty_mins, - stats.vscode_mins, - stats.jetbrains_mins, - stats.app_usage_mins - FROM - stats - LEFT JOIN - latencies - ON - -- The latencies group-by ensures there at most one row. - latencies.start_time = stats.start_time - AND latencies.template_id = stats.template_id - AND latencies.user_id = stats.user_id - ) - ON CONFLICT - (start_time, template_id, user_id) - DO UPDATE - SET - usage_mins = EXCLUDED.usage_mins, - median_latency_ms = EXCLUDED.median_latency_ms, - ssh_mins = EXCLUDED.ssh_mins, - sftp_mins = EXCLUDED.sftp_mins, - reconnecting_pty_mins = EXCLUDED.reconnecting_pty_mins, - vscode_mins = EXCLUDED.vscode_mins, - jetbrains_mins = EXCLUDED.jetbrains_mins, - app_usage_mins = EXCLUDED.app_usage_mins - WHERE - (tus.*) IS DISTINCT FROM (EXCLUDED.*); - */ - -TemplateUsageStatsInsertLoop: - for _, stat := range statsRows { - // LEFT JOIN latencies - latency, latencyOk := latenciesRows[latenciesGroupBy{ - StartTime: stat.TimeBucket, - TemplateID: stat.TemplateID, - UserID: stat.UserID, - }] - - // SELECT - tus := database.TemplateUsageStat{ - StartTime: stat.TimeBucket, - EndTime: stat.TimeBucket.Add(30 * time.Minute), - TemplateID: stat.TemplateID, - UserID: stat.UserID, - // #nosec G115 - Safe conversion for usage minutes which are expected to be within int16 range - UsageMins: int16(stat.UsageMins), - MedianLatencyMs: sql.NullFloat64{Float64: latency.MedianLatencyMS, Valid: latencyOk}, - // #nosec G115 - Safe conversion for SSH minutes which are expected to be within int16 range - SshMins: int16(stat.SSHMins), - // #nosec G115 - Safe conversion for SFTP minutes which are expected to be within int16 range - SftpMins: int16(stat.SFTPMins), - // #nosec G115 - Safe conversion for ReconnectingPTY minutes which are expected to be within int16 range - ReconnectingPtyMins: int16(stat.ReconnectingPTYMins), - // #nosec G115 - Safe conversion for VSCode minutes which are expected to be within int16 range - VscodeMins: int16(stat.VSCodeMins), - // #nosec G115 - Safe conversion for JetBrains minutes which are expected to be within int16 range - JetbrainsMins: int16(stat.JetBrainsMins), - } - if len(stat.AppUsageMinutes) > 0 { - tus.AppUsageMins = make(map[string]int64, len(stat.AppUsageMinutes)) - for k, v := range stat.AppUsageMinutes { - tus.AppUsageMins[k] = int64(v) - } - } - - // ON CONFLICT - for i, existing := range q.templateUsageStats { - if existing.StartTime.Equal(tus.StartTime) && existing.TemplateID == tus.TemplateID && existing.UserID == tus.UserID { - q.templateUsageStats[i] = tus - continue TemplateUsageStatsInsertLoop - } - } - // INSERT INTO - q.templateUsageStats = append(q.templateUsageStats, tus) - } - - return nil -} - -func (q *FakeQuerier) UpsertWebpushVAPIDKeys(_ context.Context, arg database.UpsertWebpushVAPIDKeysParams) error { - err := validateDatabaseType(arg) - if err != nil { - return err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - q.webpushVAPIDPublicKey = arg.VapidPublicKey - q.webpushVAPIDPrivateKey = arg.VapidPrivateKey - return nil -} - -func (q *FakeQuerier) UpsertWorkspaceAgentPortShare(_ context.Context, arg database.UpsertWorkspaceAgentPortShareParams) (database.WorkspaceAgentPortShare, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceAgentPortShare{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, share := range q.workspaceAgentPortShares { - if share.WorkspaceID == arg.WorkspaceID && share.Port == arg.Port && share.AgentName == arg.AgentName { - share.ShareLevel = arg.ShareLevel - share.Protocol = arg.Protocol - q.workspaceAgentPortShares[i] = share - return share, nil - } - } - - //nolint:gosimple // casts are not a simplification - psl := database.WorkspaceAgentPortShare{ - WorkspaceID: arg.WorkspaceID, - AgentName: arg.AgentName, - Port: arg.Port, - ShareLevel: arg.ShareLevel, - Protocol: arg.Protocol, - } - q.workspaceAgentPortShares = append(q.workspaceAgentPortShares, psl) - - return psl, nil -} - -func (q *FakeQuerier) UpsertWorkspaceApp(ctx context.Context, arg database.UpsertWorkspaceAppParams) (database.WorkspaceApp, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.WorkspaceApp{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - if arg.SharingLevel == "" { - arg.SharingLevel = database.AppSharingLevelOwner - } - if arg.OpenIn == "" { - arg.OpenIn = database.WorkspaceAppOpenInSlimWindow - } - - buildApp := func(id uuid.UUID, createdAt time.Time) database.WorkspaceApp { - return database.WorkspaceApp{ - ID: id, - CreatedAt: createdAt, - AgentID: arg.AgentID, - Slug: arg.Slug, - DisplayName: arg.DisplayName, - Icon: arg.Icon, - Command: arg.Command, - Url: arg.Url, - External: arg.External, - Subdomain: arg.Subdomain, - SharingLevel: arg.SharingLevel, - HealthcheckUrl: arg.HealthcheckUrl, - HealthcheckInterval: arg.HealthcheckInterval, - HealthcheckThreshold: arg.HealthcheckThreshold, - Health: arg.Health, - Hidden: arg.Hidden, - DisplayOrder: arg.DisplayOrder, - OpenIn: arg.OpenIn, - DisplayGroup: arg.DisplayGroup, - } - } - - for i, app := range q.workspaceApps { - if app.ID == arg.ID { - q.workspaceApps[i] = buildApp(app.ID, app.CreatedAt) - return q.workspaceApps[i], nil - } - } - - workspaceApp := buildApp(arg.ID, arg.CreatedAt) - q.workspaceApps = append(q.workspaceApps, workspaceApp) - return workspaceApp, nil -} - -func (q *FakeQuerier) UpsertWorkspaceAppAuditSession(_ context.Context, arg database.UpsertWorkspaceAppAuditSessionParams) (bool, error) { - err := validateDatabaseType(arg) - if err != nil { - return false, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, s := range q.workspaceAppAuditSessions { - if s.AgentID != arg.AgentID { - continue - } - if s.AppID != arg.AppID { - continue - } - if s.UserID != arg.UserID { - continue - } - if s.Ip != arg.Ip { - continue - } - if s.UserAgent != arg.UserAgent { - continue - } - if s.SlugOrPort != arg.SlugOrPort { - continue - } - if s.StatusCode != arg.StatusCode { - continue - } - - staleTime := dbtime.Now().Add(-(time.Duration(arg.StaleIntervalMS) * time.Millisecond)) - fresh := s.UpdatedAt.After(staleTime) - - q.workspaceAppAuditSessions[i].UpdatedAt = arg.UpdatedAt - if !fresh { - q.workspaceAppAuditSessions[i].ID = arg.ID - q.workspaceAppAuditSessions[i].StartedAt = arg.StartedAt - return true, nil - } - return false, nil - } - - q.workspaceAppAuditSessions = append(q.workspaceAppAuditSessions, database.WorkspaceAppAuditSession{ - AgentID: arg.AgentID, - AppID: arg.AppID, - UserID: arg.UserID, - Ip: arg.Ip, - UserAgent: arg.UserAgent, - SlugOrPort: arg.SlugOrPort, - StatusCode: arg.StatusCode, - StartedAt: arg.StartedAt, - UpdatedAt: arg.UpdatedAt, - }) - return true, nil -} - -func (q *FakeQuerier) GetAuthorizedTemplates(ctx context.Context, arg database.GetTemplatesWithFilterParams, prepared rbac.PreparedAuthorized) ([]database.Template, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - // Call this to match the same function calls as the SQL implementation. - if prepared != nil { - _, err := prepared.CompileToSQL(ctx, rbac.ConfigWithACL()) - if err != nil { - return nil, err - } - } - - var templates []database.Template - for _, templateTable := range q.templates { - template := q.templateWithNameNoLock(templateTable) - if prepared != nil && prepared.Authorize(ctx, template.RBACObject()) != nil { - continue - } - - if template.Deleted != arg.Deleted { - continue - } - if arg.OrganizationID != uuid.Nil && template.OrganizationID != arg.OrganizationID { - continue - } - - if arg.ExactName != "" && !strings.EqualFold(template.Name, arg.ExactName) { - continue - } - // Filters templates based on the search query filter 'Deprecated' status - // Matching SQL logic: - // -- Filter by deprecated - // AND CASE - // WHEN :deprecated IS NOT NULL THEN - // CASE - // WHEN :deprecated THEN deprecated != '' - // ELSE deprecated = '' - // END - // ELSE true - if arg.Deprecated.Valid && arg.Deprecated.Bool != isDeprecated(template) { - continue - } - if arg.FuzzyName != "" { - if !strings.Contains(strings.ToLower(template.Name), strings.ToLower(arg.FuzzyName)) { - continue - } - } - - if len(arg.IDs) > 0 { - match := false - for _, id := range arg.IDs { - if template.ID == id { - match = true - break - } - } - if !match { - continue - } - } - - if arg.HasAITask.Valid { - tv, err := q.getTemplateVersionByIDNoLock(ctx, template.ActiveVersionID) - if err != nil { - return nil, xerrors.Errorf("get template version: %w", err) - } - tvHasAITask := tv.HasAITask.Valid && tv.HasAITask.Bool - if tvHasAITask != arg.HasAITask.Bool { - continue - } - } - - templates = append(templates, template) - } - if len(templates) > 0 { - slices.SortFunc(templates, func(a, b database.Template) int { - if a.Name != b.Name { - return slice.Ascending(a.Name, b.Name) - } - return slice.Ascending(a.ID.String(), b.ID.String()) - }) - return templates, nil - } - - return nil, sql.ErrNoRows -} - -func (q *FakeQuerier) GetTemplateGroupRoles(_ context.Context, id uuid.UUID) ([]database.TemplateGroup, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var template database.TemplateTable - for _, t := range q.templates { - if t.ID == id { - template = t - break - } - } - - if template.ID == uuid.Nil { - return nil, sql.ErrNoRows - } - - groups := make([]database.TemplateGroup, 0, len(template.GroupACL)) - for k, v := range template.GroupACL { - group, err := q.getGroupByIDNoLock(context.Background(), uuid.MustParse(k)) - if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - return nil, xerrors.Errorf("get group by ID: %w", err) - } - // We don't delete groups from the map if they - // get deleted so just skip. - if xerrors.Is(err, sql.ErrNoRows) { - continue - } - - groups = append(groups, database.TemplateGroup{ - Group: group, - Actions: v, - }) - } - - return groups, nil -} - -func (q *FakeQuerier) GetTemplateUserRoles(_ context.Context, id uuid.UUID) ([]database.TemplateUser, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - var template database.TemplateTable - for _, t := range q.templates { - if t.ID == id { - template = t - break - } - } - - if template.ID == uuid.Nil { - return nil, sql.ErrNoRows - } - - users := make([]database.TemplateUser, 0, len(template.UserACL)) - for k, v := range template.UserACL { - user, err := q.getUserByIDNoLock(uuid.MustParse(k)) - if err != nil && xerrors.Is(err, sql.ErrNoRows) { - return nil, xerrors.Errorf("get user by ID: %w", err) - } - // We don't delete users from the map if they - // get deleted so just skip. - if xerrors.Is(err, sql.ErrNoRows) { - continue - } - - if user.Deleted || user.Status == database.UserStatusSuspended { - continue - } - - users = append(users, database.TemplateUser{ - User: user, - Actions: v, - }) - } - - return users, nil -} - -func (q *FakeQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg database.GetWorkspacesParams, prepared rbac.PreparedAuthorized) ([]database.GetWorkspacesRow, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - if prepared != nil { - // Call this to match the same function calls as the SQL implementation. - _, err := prepared.CompileToSQL(ctx, rbac.ConfigWithoutACL()) - if err != nil { - return nil, err - } - } - - workspaces := make([]database.WorkspaceTable, 0) - for _, workspace := range q.workspaces { - if arg.OwnerID != uuid.Nil && workspace.OwnerID != arg.OwnerID { - continue - } - - if len(arg.HasParam) > 0 || len(arg.ParamNames) > 0 { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return nil, xerrors.Errorf("get latest build: %w", err) - } - - params := make([]database.WorkspaceBuildParameter, 0) - for _, param := range q.workspaceBuildParameters { - if param.WorkspaceBuildID != build.ID { - continue - } - params = append(params, param) - } - - index := slices.IndexFunc(params, func(buildParam database.WorkspaceBuildParameter) bool { - // If hasParam matches, then we are done. This is a good match. - if slices.ContainsFunc(arg.HasParam, func(name string) bool { - return strings.EqualFold(buildParam.Name, name) - }) { - return true - } - - // Check name + value - match := false - for i := range arg.ParamNames { - matchName := arg.ParamNames[i] - if !strings.EqualFold(matchName, buildParam.Name) { - continue - } - - matchValue := arg.ParamValues[i] - if !strings.EqualFold(matchValue, buildParam.Value) { - continue - } - match = true - break - } - - return match - }) - if index < 0 { - continue - } - } - - if arg.OrganizationID != uuid.Nil { - if workspace.OrganizationID != arg.OrganizationID { - continue - } - } - - if arg.OwnerUsername != "" { - owner, err := q.getUserByIDNoLock(workspace.OwnerID) - if err == nil && !strings.EqualFold(arg.OwnerUsername, owner.Username) { - continue - } - } - - if arg.TemplateName != "" { - template, err := q.getTemplateByIDNoLock(ctx, workspace.TemplateID) - if err == nil && !strings.EqualFold(arg.TemplateName, template.Name) { - continue - } - } - - if arg.UsingActive.Valid { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return nil, xerrors.Errorf("get latest build: %w", err) - } - - template, err := q.getTemplateByIDNoLock(ctx, workspace.TemplateID) - if err != nil { - return nil, xerrors.Errorf("get template: %w", err) - } - - updated := build.TemplateVersionID == template.ActiveVersionID - if arg.UsingActive.Bool != updated { - continue - } - } - - if !arg.Deleted && workspace.Deleted { - continue - } - - if arg.Name != "" && !strings.Contains(strings.ToLower(workspace.Name), strings.ToLower(arg.Name)) { - continue - } - - if !arg.LastUsedBefore.IsZero() { - if workspace.LastUsedAt.After(arg.LastUsedBefore) { - continue - } - } - - if !arg.LastUsedAfter.IsZero() { - if workspace.LastUsedAt.Before(arg.LastUsedAfter) { - continue - } - } - - if arg.Status != "" { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return nil, xerrors.Errorf("get latest build: %w", err) - } - - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err != nil { - return nil, xerrors.Errorf("get provisioner job: %w", err) - } - - // This logic should match the logic in the workspace.sql file. - var statusMatch bool - switch database.WorkspaceStatus(arg.Status) { - case database.WorkspaceStatusStarting: - statusMatch = job.JobStatus == database.ProvisionerJobStatusRunning && - build.Transition == database.WorkspaceTransitionStart - case database.WorkspaceStatusStopping: - statusMatch = job.JobStatus == database.ProvisionerJobStatusRunning && - build.Transition == database.WorkspaceTransitionStop - case database.WorkspaceStatusDeleting: - statusMatch = job.JobStatus == database.ProvisionerJobStatusRunning && - build.Transition == database.WorkspaceTransitionDelete - - case "started": - statusMatch = job.JobStatus == database.ProvisionerJobStatusSucceeded && - build.Transition == database.WorkspaceTransitionStart - case database.WorkspaceStatusDeleted: - statusMatch = job.JobStatus == database.ProvisionerJobStatusSucceeded && - build.Transition == database.WorkspaceTransitionDelete - case database.WorkspaceStatusStopped: - statusMatch = job.JobStatus == database.ProvisionerJobStatusSucceeded && - build.Transition == database.WorkspaceTransitionStop - case database.WorkspaceStatusRunning: - statusMatch = job.JobStatus == database.ProvisionerJobStatusSucceeded && - build.Transition == database.WorkspaceTransitionStart - default: - statusMatch = job.JobStatus == database.ProvisionerJobStatus(arg.Status) - } - if !statusMatch { - continue - } - } - - if arg.HasAgent != "" { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return nil, xerrors.Errorf("get latest build: %w", err) - } - - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err != nil { - return nil, xerrors.Errorf("get provisioner job: %w", err) - } - - workspaceResources, err := q.getWorkspaceResourcesByJobIDNoLock(ctx, job.ID) - if err != nil { - return nil, xerrors.Errorf("get workspace resources: %w", err) - } - - var workspaceResourceIDs []uuid.UUID - for _, wr := range workspaceResources { - workspaceResourceIDs = append(workspaceResourceIDs, wr.ID) - } - - workspaceAgents, err := q.getWorkspaceAgentsByResourceIDsNoLock(ctx, workspaceResourceIDs) - if err != nil { - return nil, xerrors.Errorf("get workspace agents: %w", err) - } - - var hasAgentMatched bool - for _, wa := range workspaceAgents { - if mapAgentStatus(wa, arg.AgentInactiveDisconnectTimeoutSeconds) == arg.HasAgent { - hasAgentMatched = true - } - } - - if !hasAgentMatched { - continue - } - } - - if arg.Dormant && !workspace.DormantAt.Valid { - continue - } - - if len(arg.TemplateIDs) > 0 { - match := false - for _, id := range arg.TemplateIDs { - if workspace.TemplateID == id { - match = true - break - } - } - if !match { - continue - } - } - - if len(arg.WorkspaceIds) > 0 { - match := false - for _, id := range arg.WorkspaceIds { - if workspace.ID == id { - match = true - break - } - } - if !match { - continue - } - } - - if arg.HasAITask.Valid { - hasAITask, err := func() (bool, error) { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) - if err != nil { - return false, xerrors.Errorf("get latest build: %w", err) - } - if build.HasAITask.Valid { - return build.HasAITask.Bool, nil - } - // If the build has a nil AI task, check if the job is in progress - // and if it has a non-empty AI Prompt parameter - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err != nil { - return false, xerrors.Errorf("get provisioner job: %w", err) - } - if job.CompletedAt.Valid { - return false, nil - } - parameters, err := q.getWorkspaceBuildParametersNoLock(build.ID) - if err != nil { - return false, xerrors.Errorf("get workspace build parameters: %w", err) - } - for _, param := range parameters { - if param.Name == "AI Prompt" && param.Value != "" { - return true, nil - } - } - return false, nil - }() - if err != nil { - return nil, xerrors.Errorf("get hasAITask: %w", err) - } - if hasAITask != arg.HasAITask.Bool { - continue - } - } - - // If the filter exists, ensure the object is authorized. - if prepared != nil && prepared.Authorize(ctx, workspace.RBACObject()) != nil { - continue - } - workspaces = append(workspaces, workspace) - } - - // Sort workspaces (ORDER BY) - isRunning := func(build database.WorkspaceBuild, job database.ProvisionerJob) bool { - return job.CompletedAt.Valid && !job.CanceledAt.Valid && !job.Error.Valid && build.Transition == database.WorkspaceTransitionStart - } - - preloadedWorkspaceBuilds := map[uuid.UUID]database.WorkspaceBuild{} - preloadedProvisionerJobs := map[uuid.UUID]database.ProvisionerJob{} - preloadedUsers := map[uuid.UUID]database.User{} - - for _, w := range workspaces { - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, w.ID) - if err == nil { - preloadedWorkspaceBuilds[w.ID] = build - } else if !errors.Is(err, sql.ErrNoRows) { - return nil, xerrors.Errorf("get latest build: %w", err) - } - - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err == nil { - preloadedProvisionerJobs[w.ID] = job - } else if !errors.Is(err, sql.ErrNoRows) { - return nil, xerrors.Errorf("get provisioner job: %w", err) - } - - user, err := q.getUserByIDNoLock(w.OwnerID) - if err == nil { - preloadedUsers[w.ID] = user - } else if !errors.Is(err, sql.ErrNoRows) { - return nil, xerrors.Errorf("get user: %w", err) - } - } - - sort.Slice(workspaces, func(i, j int) bool { - w1 := workspaces[i] - w2 := workspaces[j] - - // Order by: favorite first - if arg.RequesterID == w1.OwnerID && w1.Favorite { - return true - } - if arg.RequesterID == w2.OwnerID && w2.Favorite { - return false - } - - // Order by: running - w1IsRunning := isRunning(preloadedWorkspaceBuilds[w1.ID], preloadedProvisionerJobs[w1.ID]) - w2IsRunning := isRunning(preloadedWorkspaceBuilds[w2.ID], preloadedProvisionerJobs[w2.ID]) - - if w1IsRunning && !w2IsRunning { - return true - } - - if !w1IsRunning && w2IsRunning { - return false - } - - // Order by: usernames - if strings.Compare(preloadedUsers[w1.ID].Username, preloadedUsers[w2.ID].Username) < 0 { - return true - } - - // Order by: workspace names - return strings.Compare(w1.Name, w2.Name) < 0 - }) - - beforePageCount := len(workspaces) - - if arg.Offset > 0 { - if int(arg.Offset) > len(workspaces) { - return q.convertToWorkspaceRowsNoLock(ctx, []database.WorkspaceTable{}, int64(beforePageCount), arg.WithSummary), nil - } - workspaces = workspaces[arg.Offset:] - } - if arg.Limit > 0 { - if int(arg.Limit) > len(workspaces) { - return q.convertToWorkspaceRowsNoLock(ctx, workspaces, int64(beforePageCount), arg.WithSummary), nil - } - workspaces = workspaces[:arg.Limit] - } - - return q.convertToWorkspaceRowsNoLock(ctx, workspaces, int64(beforePageCount), arg.WithSummary), nil -} - -func (q *FakeQuerier) GetAuthorizedWorkspacesAndAgentsByOwnerID(ctx context.Context, ownerID uuid.UUID, prepared rbac.PreparedAuthorized) ([]database.GetWorkspacesAndAgentsByOwnerIDRow, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if prepared != nil { - // Call this to match the same function calls as the SQL implementation. - _, err := prepared.CompileToSQL(ctx, rbac.ConfigWithoutACL()) - if err != nil { - return nil, err - } - } - workspaces := make([]database.WorkspaceTable, 0) - for _, workspace := range q.workspaces { - if workspace.OwnerID == ownerID && !workspace.Deleted { - workspaces = append(workspaces, workspace) - } - } - - out := make([]database.GetWorkspacesAndAgentsByOwnerIDRow, 0, len(workspaces)) - for _, w := range workspaces { - // these always exist - build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, w.ID) - if err != nil { - return nil, xerrors.Errorf("get latest build: %w", err) - } - - job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID) - if err != nil { - return nil, xerrors.Errorf("get provisioner job: %w", err) - } - - outAgents := make([]database.AgentIDNamePair, 0) - resources, err := q.getWorkspaceResourcesByJobIDNoLock(ctx, job.ID) - if err != nil { - return nil, xerrors.Errorf("get workspace resources: %w", err) - } - if len(resources) > 0 { - agents, err := q.getWorkspaceAgentsByResourceIDsNoLock(ctx, []uuid.UUID{resources[0].ID}) - if err != nil { - return nil, xerrors.Errorf("get workspace agents: %w", err) - } - for _, a := range agents { - outAgents = append(outAgents, database.AgentIDNamePair{ - ID: a.ID, - Name: a.Name, - }) - } - } - - out = append(out, database.GetWorkspacesAndAgentsByOwnerIDRow{ - ID: w.ID, - Name: w.Name, - JobStatus: job.JobStatus, - Transition: build.Transition, - Agents: outAgents, - }) - } - - return out, nil -} - -func (q *FakeQuerier) GetAuthorizedWorkspaceBuildParametersByBuildIDs(ctx context.Context, workspaceBuildIDs []uuid.UUID, prepared rbac.PreparedAuthorized) ([]database.WorkspaceBuildParameter, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - if prepared != nil { - // Call this to match the same function calls as the SQL implementation. - _, err := prepared.CompileToSQL(ctx, rbac.ConfigWithoutACL()) - if err != nil { - return nil, err - } - } - - filteredParameters := make([]database.WorkspaceBuildParameter, 0) - for _, buildID := range workspaceBuildIDs { - parameters, err := q.GetWorkspaceBuildParameters(ctx, buildID) - if err != nil { - return nil, err - } - filteredParameters = append(filteredParameters, parameters...) - } - - return filteredParameters, nil -} - -func (q *FakeQuerier) GetAuthorizedUsers(ctx context.Context, arg database.GetUsersParams, prepared rbac.PreparedAuthorized) ([]database.GetUsersRow, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - // Call this to match the same function calls as the SQL implementation. - if prepared != nil { - _, err := prepared.CompileToSQL(ctx, regosql.ConvertConfig{ - VariableConverter: regosql.UserConverter(), - }) - if err != nil { - return nil, err - } - } - - users, err := q.GetUsers(ctx, arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - filteredUsers := make([]database.GetUsersRow, 0, len(users)) - for _, user := range users { - // If the filter exists, ensure the object is authorized. - if prepared != nil && prepared.Authorize(ctx, user.RBACObject()) != nil { - continue - } - - filteredUsers = append(filteredUsers, user) - } - return filteredUsers, nil -} - -func (q *FakeQuerier) GetAuthorizedAuditLogsOffset(ctx context.Context, arg database.GetAuditLogsOffsetParams, prepared rbac.PreparedAuthorized) ([]database.GetAuditLogsOffsetRow, error) { - if err := validateDatabaseType(arg); err != nil { - return nil, err - } - - // Call this to match the same function calls as the SQL implementation. - // It functionally does nothing for filtering. - if prepared != nil { - _, err := prepared.CompileToSQL(ctx, regosql.ConvertConfig{ - VariableConverter: regosql.AuditLogConverter(), - }) - if err != nil { - return nil, err - } - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - if arg.LimitOpt == 0 { - // Default to 100 is set in the SQL query. - arg.LimitOpt = 100 - } - - logs := make([]database.GetAuditLogsOffsetRow, 0, arg.LimitOpt) - - // q.auditLogs are already sorted by time DESC, so no need to sort after the fact. - for _, alog := range q.auditLogs { - if arg.OffsetOpt > 0 { - arg.OffsetOpt-- - continue - } - if arg.RequestID != uuid.Nil && arg.RequestID != alog.RequestID { - continue - } - if arg.OrganizationID != uuid.Nil && arg.OrganizationID != alog.OrganizationID { - continue - } - if arg.Action != "" && string(alog.Action) != arg.Action { - continue - } - if arg.ResourceType != "" && !strings.Contains(string(alog.ResourceType), arg.ResourceType) { - continue - } - if arg.ResourceID != uuid.Nil && alog.ResourceID != arg.ResourceID { - continue - } - if arg.Username != "" { - user, err := q.getUserByIDNoLock(alog.UserID) - if err == nil && !strings.EqualFold(arg.Username, user.Username) { - continue - } - } - if arg.Email != "" { - user, err := q.getUserByIDNoLock(alog.UserID) - if err == nil && !strings.EqualFold(arg.Email, user.Email) { - continue - } - } - if !arg.DateFrom.IsZero() { - if alog.Time.Before(arg.DateFrom) { - continue - } - } - if !arg.DateTo.IsZero() { - if alog.Time.After(arg.DateTo) { - continue - } - } - if arg.BuildReason != "" { - workspaceBuild, err := q.getWorkspaceBuildByIDNoLock(context.Background(), alog.ResourceID) - if err == nil && !strings.EqualFold(arg.BuildReason, string(workspaceBuild.Reason)) { - continue - } - } - // If the filter exists, ensure the object is authorized. - if prepared != nil && prepared.Authorize(ctx, alog.RBACObject()) != nil { - continue - } - - user, err := q.getUserByIDNoLock(alog.UserID) - userValid := err == nil - - org, _ := q.getOrganizationByIDNoLock(alog.OrganizationID) - - cpy := alog - logs = append(logs, database.GetAuditLogsOffsetRow{ - AuditLog: cpy, - OrganizationName: org.Name, - OrganizationDisplayName: org.DisplayName, - OrganizationIcon: org.Icon, - UserUsername: sql.NullString{String: user.Username, Valid: userValid}, - UserName: sql.NullString{String: user.Name, Valid: userValid}, - UserEmail: sql.NullString{String: user.Email, Valid: userValid}, - UserCreatedAt: sql.NullTime{Time: user.CreatedAt, Valid: userValid}, - UserUpdatedAt: sql.NullTime{Time: user.UpdatedAt, Valid: userValid}, - UserLastSeenAt: sql.NullTime{Time: user.LastSeenAt, Valid: userValid}, - UserLoginType: database.NullLoginType{LoginType: user.LoginType, Valid: userValid}, - UserDeleted: sql.NullBool{Bool: user.Deleted, Valid: userValid}, - UserQuietHoursSchedule: sql.NullString{String: user.QuietHoursSchedule, Valid: userValid}, - UserStatus: database.NullUserStatus{UserStatus: user.Status, Valid: userValid}, - UserRoles: user.RBACRoles, - }) - - if len(logs) >= int(arg.LimitOpt) { - break - } - } - - return logs, nil -} - -func (q *FakeQuerier) CountAuthorizedAuditLogs(ctx context.Context, arg database.CountAuditLogsParams, prepared rbac.PreparedAuthorized) (int64, error) { - if err := validateDatabaseType(arg); err != nil { - return 0, err - } - - // Call this to match the same function calls as the SQL implementation. - // It functionally does nothing for filtering. - if prepared != nil { - _, err := prepared.CompileToSQL(ctx, regosql.ConvertConfig{ - VariableConverter: regosql.AuditLogConverter(), - }) - if err != nil { - return 0, err - } - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - - var count int64 - - // q.auditLogs are already sorted by time DESC, so no need to sort after the fact. - for _, alog := range q.auditLogs { - if arg.RequestID != uuid.Nil && arg.RequestID != alog.RequestID { - continue - } - if arg.OrganizationID != uuid.Nil && arg.OrganizationID != alog.OrganizationID { - continue - } - if arg.Action != "" && string(alog.Action) != arg.Action { - continue - } - if arg.ResourceType != "" && !strings.Contains(string(alog.ResourceType), arg.ResourceType) { - continue - } - if arg.ResourceID != uuid.Nil && alog.ResourceID != arg.ResourceID { - continue - } - if arg.Username != "" { - user, err := q.getUserByIDNoLock(alog.UserID) - if err == nil && !strings.EqualFold(arg.Username, user.Username) { - continue - } - } - if arg.Email != "" { - user, err := q.getUserByIDNoLock(alog.UserID) - if err == nil && !strings.EqualFold(arg.Email, user.Email) { - continue - } - } - if !arg.DateFrom.IsZero() { - if alog.Time.Before(arg.DateFrom) { - continue - } - } - if !arg.DateTo.IsZero() { - if alog.Time.After(arg.DateTo) { - continue - } - } - if arg.BuildReason != "" { - workspaceBuild, err := q.getWorkspaceBuildByIDNoLock(context.Background(), alog.ResourceID) - if err == nil && !strings.EqualFold(arg.BuildReason, string(workspaceBuild.Reason)) { - continue - } - } - // If the filter exists, ensure the object is authorized. - if prepared != nil && prepared.Authorize(ctx, alog.RBACObject()) != nil { - continue - } - - count++ - } - - return count, nil -} diff --git a/coderd/database/dbmem/dbmem_test.go b/coderd/database/dbmem/dbmem_test.go deleted file mode 100644 index c3df828b95c98..0000000000000 --- a/coderd/database/dbmem/dbmem_test.go +++ /dev/null @@ -1,209 +0,0 @@ -package dbmem_test - -import ( - "context" - "database/sql" - "sort" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" - "github.com/coder/coder/v2/coderd/database/dbtime" -) - -// test that transactions don't deadlock, and that we don't see intermediate state. -func TestInTx(t *testing.T) { - t.Parallel() - - uut := dbmem.New() - - inTx := make(chan any) - queriesDone := make(chan any) - queriesStarted := make(chan any) - go func() { - err := uut.InTx(func(tx database.Store) error { - close(inTx) - _, err := tx.InsertOrganization(context.Background(), database.InsertOrganizationParams{ - Name: "1", - }) - assert.NoError(t, err) - <-queriesStarted - time.Sleep(5 * time.Millisecond) - _, err = tx.InsertOrganization(context.Background(), database.InsertOrganizationParams{ - Name: "2", - }) - assert.NoError(t, err) - return nil - }, nil) - assert.NoError(t, err) - }() - var nums []int - go func() { - <-inTx - for i := 0; i < 20; i++ { - orgs, err := uut.GetOrganizations(context.Background(), database.GetOrganizationsParams{}) - if err != nil { - assert.ErrorIs(t, err, sql.ErrNoRows) - } - nums = append(nums, len(orgs)) - time.Sleep(time.Millisecond) - } - close(queriesDone) - }() - close(queriesStarted) - <-queriesDone - // ensure we never saw 1 org, only 0 or 2. - for i := 0; i < 20; i++ { - assert.NotEqual(t, 1, nums[i]) - } -} - -// TestUserOrder ensures that the fake database returns users sorted by username. -func TestUserOrder(t *testing.T) { - t.Parallel() - - db := dbmem.New() - now := dbtime.Now() - - usernames := []string{"b-user", "d-user", "a-user", "c-user", "e-user"} - for _, username := range usernames { - dbgen.User(t, db, database.User{Username: username, CreatedAt: now}) - } - - users, err := db.GetUsers(context.Background(), database.GetUsersParams{}) - require.NoError(t, err) - require.Lenf(t, users, len(usernames), "expected %d users", len(usernames)) - - sort.Strings(usernames) - for i, user := range users { - require.Equal(t, usernames[i], user.Username) - } -} - -func TestProxyByHostname(t *testing.T) { - t.Parallel() - - db := dbmem.New() - - // Insert a bunch of different proxies. - proxies := []struct { - name string - accessURL string - wildcardHostname string - }{ - { - name: "one", - accessURL: "https://one.coder.com", - wildcardHostname: "*.wildcard.one.coder.com", - }, - { - name: "two", - accessURL: "https://two.coder.com", - wildcardHostname: "*--suffix.two.coder.com", - }, - } - for _, p := range proxies { - dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{ - Name: p.name, - Url: p.accessURL, - WildcardHostname: p.wildcardHostname, - }) - } - - cases := []struct { - name string - testHostname string - allowAccessURL bool - allowWildcardHost bool - matchProxyName string - }{ - { - name: "NoMatch", - testHostname: "test.com", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "", - }, - { - name: "MatchAccessURL", - testHostname: "one.coder.com", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "one", - }, - { - name: "MatchWildcard", - testHostname: "something.wildcard.one.coder.com", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "one", - }, - { - name: "MatchSuffix", - testHostname: "something--suffix.two.coder.com", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "two", - }, - { - name: "ValidateHostname/1", - testHostname: ".*ne.coder.com", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "", - }, - { - name: "ValidateHostname/2", - testHostname: "https://one.coder.com", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "", - }, - { - name: "ValidateHostname/3", - testHostname: "one.coder.com:8080/hello", - allowAccessURL: true, - allowWildcardHost: true, - matchProxyName: "", - }, - { - name: "IgnoreAccessURLMatch", - testHostname: "one.coder.com", - allowAccessURL: false, - allowWildcardHost: true, - matchProxyName: "", - }, - { - name: "IgnoreWildcardMatch", - testHostname: "hi.wildcard.one.coder.com", - allowAccessURL: true, - allowWildcardHost: false, - matchProxyName: "", - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - t.Parallel() - - proxy, err := db.GetWorkspaceProxyByHostname(context.Background(), database.GetWorkspaceProxyByHostnameParams{ - Hostname: c.testHostname, - AllowAccessUrl: c.allowAccessURL, - AllowWildcardHostname: c.allowWildcardHost, - }) - if c.matchProxyName == "" { - require.ErrorIs(t, err, sql.ErrNoRows) - require.Empty(t, proxy) - } else { - require.NoError(t, err) - require.NotEmpty(t, proxy) - require.Equal(t, c.matchProxyName, proxy.Name) - } - }) - } -} diff --git a/coderd/database/dbtestutil/db.go b/coderd/database/dbtestutil/db.go index fa3567c490826..f67e3206b09d1 100644 --- a/coderd/database/dbtestutil/db.go +++ b/coderd/database/dbtestutil/db.go @@ -20,14 +20,15 @@ import ( "cdr.dev/slog" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/testutil" ) // WillUsePostgres returns true if a call to NewDB() will return a real, postgres-backed Store and Pubsub. +// TODO(hugodutka): since we removed the in-memory database, this is always true, +// and we need to remove this function. https://github.com/coder/internal/issues/758 func WillUsePostgres() bool { - return os.Getenv("DB") != "" + return true } type options struct { @@ -109,52 +110,48 @@ func NewDB(t testing.TB, opts ...Option) (database.Store, pubsub.Pubsub) { var db database.Store var ps pubsub.Pubsub - if WillUsePostgres() { - connectionURL := os.Getenv("CODER_PG_CONNECTION_URL") - if connectionURL == "" && o.url != "" { - connectionURL = o.url - } - if connectionURL == "" { - var err error - connectionURL, err = Open(t) - require.NoError(t, err) - } - - if o.fixedTimezone == "" { - // To make sure we find timezone-related issues, we set the timezone - // of the database to a non-UTC one. - // The below was picked due to the following properties: - // - It has a non-UTC offset - // - It has a fractional hour UTC offset - // - It includes a daylight savings time component - o.fixedTimezone = DefaultTimezone - } - dbName := dbNameFromConnectionURL(t, connectionURL) - setDBTimezone(t, connectionURL, dbName, o.fixedTimezone) - sqlDB, err := sql.Open("postgres", connectionURL) + connectionURL := os.Getenv("CODER_PG_CONNECTION_URL") + if connectionURL == "" && o.url != "" { + connectionURL = o.url + } + if connectionURL == "" { + var err error + connectionURL, err = Open(t) require.NoError(t, err) - t.Cleanup(func() { - _ = sqlDB.Close() - }) - if o.returnSQLDB != nil { - o.returnSQLDB(sqlDB) - } - if o.dumpOnFailure { - t.Cleanup(func() { DumpOnFailure(t, connectionURL) }) - } - // Unit tests should not retry serial transaction failures. - db = database.New(sqlDB, database.WithSerialRetryCount(1)) + } - ps, err = pubsub.New(context.Background(), o.logger, sqlDB, connectionURL) - require.NoError(t, err) - t.Cleanup(func() { - _ = ps.Close() - }) - } else { - db = dbmem.New() - ps = pubsub.NewInMemory() + if o.fixedTimezone == "" { + // To make sure we find timezone-related issues, we set the timezone + // of the database to a non-UTC one. + // The below was picked due to the following properties: + // - It has a non-UTC offset + // - It has a fractional hour UTC offset + // - It includes a daylight savings time component + o.fixedTimezone = DefaultTimezone + } + dbName := dbNameFromConnectionURL(t, connectionURL) + setDBTimezone(t, connectionURL, dbName, o.fixedTimezone) + + sqlDB, err := sql.Open("postgres", connectionURL) + require.NoError(t, err) + t.Cleanup(func() { + _ = sqlDB.Close() + }) + if o.returnSQLDB != nil { + o.returnSQLDB(sqlDB) + } + if o.dumpOnFailure { + t.Cleanup(func() { DumpOnFailure(t, connectionURL) }) } + // Unit tests should not retry serial transaction failures. + db = database.New(sqlDB, database.WithSerialRetryCount(1)) + + ps, err = pubsub.New(context.Background(), o.logger, sqlDB, connectionURL) + require.NoError(t, err) + t.Cleanup(func() { + _ = ps.Close() + }) return db, ps } diff --git a/coderd/database/oidcclaims_test.go b/coderd/database/oidcclaims_test.go index f9fe1711b19b8..fe4a10d83495e 100644 --- a/coderd/database/oidcclaims_test.go +++ b/coderd/database/oidcclaims_test.go @@ -222,7 +222,6 @@ func (g userGenerator) withLink(lt database.LoginType, rawJSON json.RawMessage) err := sql.UpdateUserLinkRawJSON(context.Background(), user.ID, rawJSON) require.NoError(t, err) } else { - // no need to test the json key logic in dbmem. Everything is type safe. var claims database.UserLinkClaims err := json.Unmarshal(rawJSON, &claims) require.NoError(t, err) diff --git a/coderd/database/querier_test.go b/coderd/database/querier_test.go index f80f68115ad2c..4dc7bdd66d30a 100644 --- a/coderd/database/querier_test.go +++ b/coderd/database/querier_test.go @@ -1400,7 +1400,6 @@ func TestGetUsers_IncludeSystem(t *testing.T) { // Given: a system user // postgres: introduced by migration coderd/database/migrations/00030*_system_user.up.sql - // dbmem: created in dbmem/dbmem.go db, _ := dbtestutil.NewDB(t) other := dbgen.User(t, db, database.User{}) users, err := db.GetUsers(ctx, database.GetUsersParams{ diff --git a/coderd/notifications/notifications_test.go b/coderd/notifications/notifications_test.go index ec9edee4c8514..e213a62df9996 100644 --- a/coderd/notifications/notifications_test.go +++ b/coderd/notifications/notifications_test.go @@ -769,7 +769,7 @@ func TestNotificationTemplates_Golden(t *testing.T) { hello = "localhost" from = "system@coder.com" - hint = "run \"DB=ci make gen/golden-files\" and commit the changes" + hint = "run \"make gen/golden-files\" and commit the changes" ) tests := []struct { diff --git a/coderd/users_test.go b/coderd/users_test.go index bd0f138b6a339..9d695f37c9906 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -32,7 +32,6 @@ import ( "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/util/ptr" @@ -1794,15 +1793,6 @@ func TestUsersFilter(t *testing.T) { } } - // TODO: This can be removed with dbmem - if !dbtestutil.WillUsePostgres() { - for i := range matched.Users { - if len(matched.Users[i].OrganizationIDs) == 0 { - matched.Users[i].OrganizationIDs = nil - } - } - } - require.ElementsMatch(t, exp, matched.Users, "expected users returned") }) } diff --git a/codersdk/deployment.go b/codersdk/deployment.go index b24e321b8e434..266baaee8cd9a 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -354,7 +354,6 @@ type DeploymentValues struct { ProxyTrustedHeaders serpent.StringArray `json:"proxy_trusted_headers,omitempty" typescript:",notnull"` ProxyTrustedOrigins serpent.StringArray `json:"proxy_trusted_origins,omitempty" typescript:",notnull"` CacheDir serpent.String `json:"cache_directory,omitempty" typescript:",notnull"` - InMemoryDatabase serpent.Bool `json:"in_memory_database,omitempty" typescript:",notnull"` EphemeralDeployment serpent.Bool `json:"ephemeral_deployment,omitempty" typescript:",notnull"` PostgresURL serpent.String `json:"pg_connection_url,omitempty" typescript:",notnull"` PostgresAuth string `json:"pg_auth,omitempty" typescript:",notnull"` @@ -2404,15 +2403,6 @@ func (c *DeploymentValues) Options() serpent.OptionSet { Value: &c.CacheDir, YAML: "cacheDir", }, - { - Name: "In Memory Database", - Description: "Controls whether data will be stored in an in-memory database.", - Flag: "in-memory", - Env: "CODER_IN_MEMORY", - Hidden: true, - Value: &c.InMemoryDatabase, - YAML: "inMemoryDatabase", - }, { Name: "Ephemeral Deployment", Description: "Controls whether Coder data, including built-in Postgres, will be stored in a temporary directory and deleted when the server is stopped.", diff --git a/docs/about/contributing/backend.md b/docs/about/contributing/backend.md index fd1a80dc6b73c..1ffafa62fb324 100644 --- a/docs/about/contributing/backend.md +++ b/docs/about/contributing/backend.md @@ -68,7 +68,6 @@ The Coder backend is organized into multiple packages and directories, each with * [dbauthz](https://github.com/coder/coder/tree/main/coderd/database/dbauthz): AuthZ wrappers for database queries, ideally, every query should verify first if the accessor is eligible to see the query results. * [dbfake](https://github.com/coder/coder/tree/main/coderd/database/dbfake): helper functions to quickly prepare the initial database state for testing purposes (e.g. create N healthy workspaces and templates), operates on higher level than [dbgen](https://github.com/coder/coder/tree/main/coderd/database/dbgen) * [dbgen](https://github.com/coder/coder/tree/main/coderd/database/dbgen): helper functions to insert raw records to the database store, used for testing purposes - * [dbmem](https://github.com/coder/coder/tree/main/coderd/database/dbmem): in-memory implementation of the database store, ideally, every real query should have a complimentary Go implementation * [dbmock](https://github.com/coder/coder/tree/main/coderd/database/dbmock): a store wrapper for database queries, useful to verify if the function has been called, used for testing purposes * [dbpurge](https://github.com/coder/coder/tree/main/coderd/database/dbpurge): simple wrapper for periodic database cleanup operations * [migrations](https://github.com/coder/coder/tree/main/coderd/database/migrations): an ordered list of up/down database migrations, use `./create_migration.sh my_migration_name` to modify the database schema diff --git a/docs/reference/api/general.md b/docs/reference/api/general.md index 8f440c55b42d6..72543f6774dfd 100644 --- a/docs/reference/api/general.md +++ b/docs/reference/api/general.md @@ -265,7 +265,6 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \ "same_site": "string", "secure_auth_cookie": true }, - "in_memory_database": true, "job_hang_detector_interval": 0, "logging": { "human": "string", diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 305c35e1bebdd..6ca1cfb9dfe51 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -1987,7 +1987,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "same_site": "string", "secure_auth_cookie": true }, - "in_memory_database": true, "job_hang_detector_interval": 0, "logging": { "human": "string", @@ -2475,7 +2474,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "same_site": "string", "secure_auth_cookie": true }, - "in_memory_database": true, "job_hang_detector_interval": 0, "logging": { "human": "string", @@ -2772,7 +2770,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o | `hide_ai_tasks` | boolean | false | | | | `http_address` | string | false | | Http address is a string because it may be set to zero to disable. | | `http_cookies` | [codersdk.HTTPCookieConfig](#codersdkhttpcookieconfig) | false | | | -| `in_memory_database` | boolean | false | | | | `job_hang_detector_interval` | integer | false | | | | `logging` | [codersdk.LoggingConfig](#codersdkloggingconfig) | false | | | | `metrics_cache_refresh_interval` | integer | false | | | diff --git a/enterprise/cli/server_test.go b/enterprise/cli/server_test.go index 7022f0d33b7a7..7489699a6f3dd 100644 --- a/enterprise/cli/server_test.go +++ b/enterprise/cli/server_test.go @@ -18,9 +18,6 @@ import ( ) func dbArg(t *testing.T) string { - if !dbtestutil.WillUsePostgres() { - return "--in-memory" - } dbURL, err := dbtestutil.Open(t) require.NoError(t, err) return "--postgres-url=" + dbURL diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 5f79608275f96..bd128b25e2ef4 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -780,13 +780,7 @@ func (api *API) updateEntitlements(ctx context.Context) error { if initial, changed, enabled := featureChanged(codersdk.FeatureHighAvailability); shouldUpdate(initial, changed, enabled) { var coordinator agpltailnet.Coordinator - // If HA is enabled, but the database is in-memory, we can't actually - // run HA and the PG coordinator. So throw a log line, and continue to use - // the in memory AGPL coordinator. - if enabled && api.DeploymentValues.InMemoryDatabase.Value() { - api.Logger.Warn(ctx, "high availability is enabled, but cannot be configured due to the database being set to in-memory") - } - if enabled && !api.DeploymentValues.InMemoryDatabase.Value() { + if enabled { haCoordinator, err := tailnet.NewPGCoord(api.ctx, api.Logger, api.Pubsub, api.Database) if err != nil { api.Logger.Error(ctx, "unable to set up high availability coordinator", slog.Error(err)) diff --git a/enterprise/coderd/coderdenttest/coderdenttest.go b/enterprise/coderd/coderdenttest/coderdenttest.go index bd81e5a039599..e4088e83d09f5 100644 --- a/enterprise/coderd/coderdenttest/coderdenttest.go +++ b/enterprise/coderd/coderdenttest/coderdenttest.go @@ -22,7 +22,6 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/drpcsdk" @@ -149,8 +148,6 @@ func NewWithAPI(t *testing.T, options *Options) ( // we check for the in-memory test types so that the real types don't have to exported _, ok := coderAPI.Pubsub.(*pubsub.MemoryPubsub) require.False(t, ok, "FeatureHighAvailability is incompatible with MemoryPubsub") - _, ok = coderAPI.Database.(*dbmem.FakeQuerier) - require.False(t, ok, "FeatureHighAvailability is incompatible with dbmem") } } _ = AddLicense(t, client, lo) diff --git a/scripts/dbgen/main.go b/scripts/dbgen/main.go index 7396a5140d605..561a46199a6ef 100644 --- a/scripts/dbgen/main.go +++ b/scripts/dbgen/main.go @@ -7,7 +7,6 @@ import ( "go/format" "go/token" "os" - "path" "path/filepath" "reflect" "runtime" @@ -52,14 +51,6 @@ func run() error { return err } databasePath := filepath.Join(localPath, "..", "..", "..", "coderd", "database") - - err = orderAndStubDatabaseFunctions(filepath.Join(databasePath, "dbmem", "dbmem.go"), "q", "FakeQuerier", func(_ stubParams) string { - return `panic("not implemented")` - }) - if err != nil { - return xerrors.Errorf("stub dbmem: %w", err) - } - err = orderAndStubDatabaseFunctions(filepath.Join(databasePath, "dbmetrics", "querymetrics.go"), "m", "queryMetricsStore", func(params stubParams) string { return fmt.Sprintf(` start := time.Now() @@ -257,13 +248,13 @@ func orderAndStubDatabaseFunctions(filePath, receiver, structName string, stub f contents, err := os.ReadFile(filePath) if err != nil { - return xerrors.Errorf("read dbmem: %w", err) + return xerrors.Errorf("read file: %w", err) } // Required to preserve imports! f, err := decorator.NewDecoratorWithImports(token.NewFileSet(), packageName, goast.New()).Parse(contents) if err != nil { - return xerrors.Errorf("parse dbmem: %w", err) + return xerrors.Errorf("parse file: %w", err) } pointer := false @@ -298,76 +289,6 @@ func orderAndStubDatabaseFunctions(filePath, receiver, structName string, stub f for _, fn := range funcs { var bodyStmts []dst.Stmt - // Add input validation, only relevant for dbmem. - if strings.Contains(filePath, "dbmem") && len(fn.Func.Params.List) == 2 && fn.Func.Params.List[1].Names[0].Name == "arg" { - /* - err := validateDatabaseType(arg) - if err != nil { - return database.User{}, err - } - */ - bodyStmts = append(bodyStmts, &dst.AssignStmt{ - Lhs: []dst.Expr{dst.NewIdent("err")}, - Tok: token.DEFINE, - Rhs: []dst.Expr{ - &dst.CallExpr{ - Fun: &dst.Ident{ - Name: "validateDatabaseType", - }, - Args: []dst.Expr{dst.NewIdent("arg")}, - }, - }, - }) - returnStmt := &dst.ReturnStmt{ - Results: []dst.Expr{}, // Filled below. - } - bodyStmts = append(bodyStmts, &dst.IfStmt{ - Cond: &dst.BinaryExpr{ - X: dst.NewIdent("err"), - Op: token.NEQ, - Y: dst.NewIdent("nil"), - }, - Body: &dst.BlockStmt{ - List: []dst.Stmt{ - returnStmt, - }, - }, - Decs: dst.IfStmtDecorations{ - NodeDecs: dst.NodeDecs{ - After: dst.EmptyLine, - }, - }, - }) - for _, r := range fn.Func.Results.List { - switch typ := r.Type.(type) { - case *dst.StarExpr, *dst.ArrayType, *dst.SelectorExpr: - returnStmt.Results = append(returnStmt.Results, dst.NewIdent("nil")) - case *dst.Ident: - if typ.Path != "" { - returnStmt.Results = append(returnStmt.Results, dst.NewIdent(fmt.Sprintf("%s.%s{}", path.Base(typ.Path), typ.Name))) - } else { - switch typ.Name { - case "uint8", "uint16", "uint32", "uint64", "uint", "uintptr", - "int8", "int16", "int32", "int64", "int", - "byte", "rune", - "float32", "float64", - "complex64", "complex128": - returnStmt.Results = append(returnStmt.Results, dst.NewIdent("0")) - case "string": - returnStmt.Results = append(returnStmt.Results, dst.NewIdent("\"\"")) - case "bool": - returnStmt.Results = append(returnStmt.Results, dst.NewIdent("false")) - case "error": - returnStmt.Results = append(returnStmt.Results, dst.NewIdent("err")) - default: - panic(fmt.Sprintf("unknown ident: %#v", r.Type)) - } - } - default: - panic(fmt.Sprintf("unknown return type: %T", r.Type)) - } - } - } decl, ok := declByName[fn.Name] if !ok { typeName := structName diff --git a/site/e2e/playwright.config.ts b/site/e2e/playwright.config.ts index 436af99240493..4b3e5c5c86fc6 100644 --- a/site/e2e/playwright.config.ts +++ b/site/e2e/playwright.config.ts @@ -72,7 +72,7 @@ export default defineConfig({ "--global-config $(mktemp -d -t e2e-XXXXXXXXXX)", `--access-url=http://localhost:${coderPort}`, `--http-address=0.0.0.0:${coderPort}`, - "--in-memory", + "--ephemeral", "--telemetry=false", "--dangerous-disable-rate-limits", "--provisioner-daemons 10", diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 8a8a5583e9069..53dc919df2df3 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -668,7 +668,6 @@ export interface DeploymentValues { readonly proxy_trusted_headers?: string; readonly proxy_trusted_origins?: string; readonly cache_directory?: string; - readonly in_memory_database?: boolean; readonly ephemeral_deployment?: boolean; readonly pg_connection_url?: string; readonly pg_auth?: string; From dc0919da332f27364969b9d5be63d8045ca0d993 Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Wed, 9 Jul 2025 11:53:27 +0200 Subject: [PATCH 27/61] feat: sign coder binaries with the release key using GPG (#18774) ### Description This PR introduces GPG signing for all Coder *slim-binaries*. Detached signatures will allow users to verify the integrity and authenticity of the binaries they download. ### Changes * `scripts/sign_with_gpg.sh`: New script to sign a given binary using GPG. It imports the release key, signs the binary, and verifies the signature. * `scripts/build_go.sh`: Updated to call `sign_with_gpg.sh` when the `CODER_SIGN_GPG` environment variable is set to 1. * `.github/workflows/release.yaml`: The` CODER_SIGN_GPG` environment variable is now set to 1 during the release build, enabling GPG signing for all release binaries. * `.github/workflows/ci.yaml`: The `CODER_SIGN_GPG` environment variable is now set to 1 during the CI build, enabling GPG signing for all CI binaries. * `Makefile`: Detached signatures are moved to the `/site/out/bin/ `directory --- .github/workflows/ci.yaml | 2 ++ .github/workflows/release.yaml | 2 ++ Makefile | 4 +++ scripts/build_go.sh | 13 ++++++++ scripts/release/publish.sh | 21 ++---------- scripts/sign_with_gpg.sh | 59 ++++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 19 deletions(-) create mode 100755 scripts/sign_with_gpg.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 93bd1a9ea65aa..03394c67b317b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1137,6 +1137,8 @@ jobs: # do (see above). CODER_SIGN_WINDOWS: "1" CODER_WINDOWS_RESOURCES: "1" + CODER_SIGN_GPG: "1" + CODER_GPG_RELEASE_KEY_BASE64: ${{ secrets.GPG_RELEASE_KEY_BASE64 }} EV_KEY: ${{ secrets.EV_KEY }} EV_KEYSTORE: ${{ secrets.EV_KEYSTORE }} EV_TSA_URL: ${{ secrets.EV_TSA_URL }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0ccf2cd38036e..5a1faa9bd1528 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -323,6 +323,8 @@ jobs: env: CODER_SIGN_WINDOWS: "1" CODER_SIGN_DARWIN: "1" + CODER_SIGN_GPG: "1" + CODER_GPG_RELEASE_KEY_BASE64: ${{ secrets.GPG_RELEASE_KEY_BASE64 }} CODER_WINDOWS_RESOURCES: "1" AC_CERTIFICATE_FILE: /tmp/apple_cert.p12 AC_CERTIFICATE_PASSWORD_FILE: /tmp/apple_cert_password.txt diff --git a/Makefile b/Makefile index ebfb286a482cc..bd3f04a4874cd 100644 --- a/Makefile +++ b/Makefile @@ -252,6 +252,10 @@ $(CODER_ALL_BINARIES): go.mod go.sum \ fi cp "$@" "./site/out/bin/coder-$$os-$$arch$$dot_ext" + + if [[ "$${CODER_SIGN_GPG:-0}" == "1" ]]; then + cp "$@.asc" "./site/out/bin/coder-$$os-$$arch$$dot_ext.asc" + fi fi # This task builds Coder Desktop dylibs diff --git a/scripts/build_go.sh b/scripts/build_go.sh index 97d9431beb544..b3b074b183f91 100755 --- a/scripts/build_go.sh +++ b/scripts/build_go.sh @@ -20,6 +20,9 @@ # binary will be signed using ./sign_darwin.sh. Read that file for more details # on the requirements. # +# If the --sign-gpg parameter is specified, the output binary will be signed using ./sign_with_gpg.sh. +# Read that file for more details on the requirements. +# # If the --agpl parameter is specified, builds only the AGPL-licensed code (no # Coder enterprise features). # @@ -41,6 +44,7 @@ slim="${CODER_SLIM_BUILD:-0}" agpl="${CODER_BUILD_AGPL:-0}" sign_darwin="${CODER_SIGN_DARWIN:-0}" sign_windows="${CODER_SIGN_WINDOWS:-0}" +sign_gpg="${CODER_SIGN_GPG:-0}" boringcrypto=${CODER_BUILD_BORINGCRYPTO:-0} dylib=0 windows_resources="${CODER_WINDOWS_RESOURCES:-0}" @@ -85,6 +89,10 @@ while true; do sign_windows=1 shift ;; + --sign-gpg) + sign_gpg=1 + shift + ;; --boringcrypto) boringcrypto=1 shift @@ -319,4 +327,9 @@ if [[ "$sign_windows" == 1 ]] && [[ "$os" == "windows" ]]; then execrelative ./sign_windows.sh "$output_path" 1>&2 fi +# Platform agnostic signing +if [[ "$sign_gpg" == 1 ]]; then + execrelative ./sign_with_gpg.sh "$output_path" 1>&2 +fi + echo "$output_path" diff --git a/scripts/release/publish.sh b/scripts/release/publish.sh index df28d46ad2710..5ffd40aeb65cb 100755 --- a/scripts/release/publish.sh +++ b/scripts/release/publish.sh @@ -129,26 +129,9 @@ if [[ "$dry_run" == 0 ]] && [[ "${CODER_GPG_RELEASE_KEY_BASE64:-}" != "" ]]; the log "--- Signing checksums file" log - # Import the GPG key. - old_gnupg_home="${GNUPGHOME:-}" - gnupg_home_temp="$(mktemp -d)" - export GNUPGHOME="$gnupg_home_temp" - echo "$CODER_GPG_RELEASE_KEY_BASE64" | base64 -d | gpg --import 1>&2 - - # Sign the checksums file. This generates a file in the same directory and - # with the same name as the checksums file but ending in ".asc". - # - # We pipe `true` into `gpg` so that it never tries to be interactive (i.e. - # ask for a passphrase). The key we import above is not password protected. - true | gpg --detach-sign --armor "${temp_dir}/${checksum_file}" 1>&2 - - rm -rf "$gnupg_home_temp" - unset GNUPGHOME - if [[ "$old_gnupg_home" != "" ]]; then - export GNUPGHOME="$old_gnupg_home" - fi - + execrelative ../sign_with_gpg.sh "${temp_dir}/${checksum_file}" signed_checksum_path="${temp_dir}/${checksum_file}.asc" + if [[ ! -e "$signed_checksum_path" ]]; then log "Signed checksum file not found: ${signed_checksum_path}" log diff --git a/scripts/sign_with_gpg.sh b/scripts/sign_with_gpg.sh new file mode 100755 index 0000000000000..fb75df5ca1bb9 --- /dev/null +++ b/scripts/sign_with_gpg.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +# This script signs a given binary using GPG. +# It expects the binary to be signed as the first argument. +# +# Usage: ./sign_with_gpg.sh path/to/binary +# +# On success, the input file will be signed using the GPG key and the signature output file will moved to /site/out/bin/ (happens in the Makefile) +# +# Depends on the GPG utility. Requires the following environment variables to be set: +# - $CODER_GPG_RELEASE_KEY_BASE64: The base64 encoded private key to use. + +set -euo pipefail +# shellcheck source=scripts/lib.sh +source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" + +requiredenvs CODER_GPG_RELEASE_KEY_BASE64 + +FILE_TO_SIGN="$1" + +if [[ -z "$FILE_TO_SIGN" ]]; then + error "Usage: $0 " +fi + +if [[ ! -f "$FILE_TO_SIGN" ]]; then + error "File not found: $FILE_TO_SIGN" +fi + +# Import the GPG key. +old_gnupg_home="${GNUPGHOME:-}" +gnupg_home_temp="$(mktemp -d)" +export GNUPGHOME="$gnupg_home_temp" + +# Ensure GPG uses the temporary directory +echo "$CODER_GPG_RELEASE_KEY_BASE64" | base64 -d | gpg --homedir "$gnupg_home_temp" --import 1>&2 + +# Sign the binary. This generates a file in the same directory and +# with the same name as the binary but ending in ".asc". +# +# We pipe `true` into `gpg` so that it never tries to be interactive (i.e. +# ask for a passphrase). The key we import above is not password protected. +true | gpg --homedir "$gnupg_home_temp" --detach-sign --armor "$FILE_TO_SIGN" 1>&2 + +# Verify the signature and capture the exit status +gpg --homedir "$gnupg_home_temp" --verify "${FILE_TO_SIGN}.asc" "$FILE_TO_SIGN" 1>&2 +verification_result=$? + +# Clean up the temporary GPG home +rm -rf "$gnupg_home_temp" +unset GNUPGHOME +if [[ "$old_gnupg_home" != "" ]]; then + export GNUPGHOME="$old_gnupg_home" +fi + +if [[ $verification_result -eq 0 ]]; then + echo "${FILE_TO_SIGN}.asc" +else + error "Signature verification failed!" +fi From 0367dbac433595322aef5e013fbce2fd886af238 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 9 Jul 2025 11:30:42 +0100 Subject: [PATCH 28/61] chore: optimize GetPrebuiltWorkspaces query (#18717) * Adds GetRunningPrebuiltWorkspacesOptimized query * Runs both original and updated query side-by-side and logs diffs --- coderd/database/dbauthz/dbauthz.go | 8 + coderd/database/dbauthz/dbauthz_test.go | 3 +- coderd/database/dbauthz/setup_test.go | 2 + coderd/database/dbgen/dbgen.go | 8 + coderd/database/dbmetrics/querymetrics.go | 7 + coderd/database/dbmock/dbmock.go | 15 + coderd/database/querier.go | 1 + coderd/database/querier_test.go | 99 +++++++ coderd/database/queries.sql.go | 101 +++++++ coderd/database/queries/prebuilds.sql | 61 +++- enterprise/coderd/prebuilds/reconcile.go | 38 +++ enterprise/coderd/prebuilds/reconcile_test.go | 274 ++++++++++++++++++ 12 files changed, 615 insertions(+), 2 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index b4162f0db59d7..55665b4381862 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2596,6 +2596,14 @@ func (q *querier) GetRunningPrebuiltWorkspaces(ctx context.Context) ([]database. return q.db.GetRunningPrebuiltWorkspaces(ctx) } +func (q *querier) GetRunningPrebuiltWorkspacesOptimized(ctx context.Context) ([]database.GetRunningPrebuiltWorkspacesOptimizedRow, error) { + // This query returns only prebuilt workspaces, but we decided to require permissions for all workspaces. + if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceWorkspace.All()); err != nil { + return nil, err + } + return q.db.GetRunningPrebuiltWorkspacesOptimized(ctx) +} + func (q *querier) GetRuntimeConfig(ctx context.Context, key string) (string, error) { if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil { return "", err diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 84c2067848ec4..fba199b637c06 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -178,7 +178,8 @@ func TestDBAuthzRecursive(t *testing.T) { if method.Name == "InTx" || method.Name == "Ping" || method.Name == "Wrappers" || - method.Name == "PGLocks" { + method.Name == "PGLocks" || + method.Name == "GetRunningPrebuiltWorkspacesOptimized" { continue } // easy to know which method failed. diff --git a/coderd/database/dbauthz/setup_test.go b/coderd/database/dbauthz/setup_test.go index 555a17fb2070f..23effafc632e0 100644 --- a/coderd/database/dbauthz/setup_test.go +++ b/coderd/database/dbauthz/setup_test.go @@ -41,6 +41,8 @@ var skipMethods = map[string]string{ "Wrappers": "Not relevant", "AcquireLock": "Not relevant", "TryAcquireLock": "Not relevant", + // This method will be removed once we know this works correctly. + "GetRunningPrebuiltWorkspacesOptimized": "Not relevant", } // TestMethodTestSuite runs MethodTestSuite. diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 00fc3aa006e70..fda7c6325899f 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -359,6 +359,14 @@ func Workspace(t testing.TB, db database.Store, orig database.WorkspaceTable) da NextStartAt: orig.NextStartAt, }) require.NoError(t, err, "insert workspace") + if orig.Deleted { + err = db.UpdateWorkspaceDeletedByID(genCtx, database.UpdateWorkspaceDeletedByIDParams{ + ID: workspace.ID, + Deleted: true, + }) + require.NoError(t, err, "set workspace as deleted") + workspace.Deleted = true + } return workspace } diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index debb8c2b89f56..b8ae92cd9f270 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -1335,6 +1335,13 @@ func (m queryMetricsStore) GetRunningPrebuiltWorkspaces(ctx context.Context) ([] return r0, r1 } +func (m queryMetricsStore) GetRunningPrebuiltWorkspacesOptimized(ctx context.Context) ([]database.GetRunningPrebuiltWorkspacesOptimizedRow, error) { + start := time.Now() + r0, r1 := m.s.GetRunningPrebuiltWorkspacesOptimized(ctx) + m.queryLatencies.WithLabelValues("GetRunningPrebuiltWorkspacesOptimized").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m queryMetricsStore) GetRuntimeConfig(ctx context.Context, key string) (string, error) { start := time.Now() r0, r1 := m.s.GetRuntimeConfig(ctx, key) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 059f37f8852b9..ec9ca45b195e7 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -2778,6 +2778,21 @@ func (mr *MockStoreMockRecorder) GetRunningPrebuiltWorkspaces(ctx any) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRunningPrebuiltWorkspaces", reflect.TypeOf((*MockStore)(nil).GetRunningPrebuiltWorkspaces), ctx) } +// GetRunningPrebuiltWorkspacesOptimized mocks base method. +func (m *MockStore) GetRunningPrebuiltWorkspacesOptimized(ctx context.Context) ([]database.GetRunningPrebuiltWorkspacesOptimizedRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRunningPrebuiltWorkspacesOptimized", ctx) + ret0, _ := ret[0].([]database.GetRunningPrebuiltWorkspacesOptimizedRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRunningPrebuiltWorkspacesOptimized indicates an expected call of GetRunningPrebuiltWorkspacesOptimized. +func (mr *MockStoreMockRecorder) GetRunningPrebuiltWorkspacesOptimized(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRunningPrebuiltWorkspacesOptimized", reflect.TypeOf((*MockStore)(nil).GetRunningPrebuiltWorkspacesOptimized), ctx) +} + // GetRuntimeConfig mocks base method. func (m *MockStore) GetRuntimeConfig(ctx context.Context, key string) (string, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index dcbac88611dd0..b83c7415a60c8 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -298,6 +298,7 @@ type sqlcQuerier interface { GetReplicaByID(ctx context.Context, id uuid.UUID) (Replica, error) GetReplicasUpdatedAfter(ctx context.Context, updatedAt time.Time) ([]Replica, error) GetRunningPrebuiltWorkspaces(ctx context.Context) ([]GetRunningPrebuiltWorkspacesRow, error) + GetRunningPrebuiltWorkspacesOptimized(ctx context.Context) ([]GetRunningPrebuiltWorkspacesOptimizedRow, error) GetRuntimeConfig(ctx context.Context, key string) (string, error) GetTailnetAgents(ctx context.Context, id uuid.UUID) ([]TailnetAgent, error) GetTailnetClientsForAgent(ctx context.Context, agentID uuid.UUID) ([]TailnetClient, error) diff --git a/coderd/database/querier_test.go b/coderd/database/querier_test.go index 4dc7bdd66d30a..789fc85655afb 100644 --- a/coderd/database/querier_test.go +++ b/coderd/database/querier_test.go @@ -5020,3 +5020,102 @@ func requireUsersMatch(t testing.TB, expected []database.User, found []database. t.Helper() require.ElementsMatch(t, expected, database.ConvertUserRows(found), msg) } + +// TestGetRunningPrebuiltWorkspaces ensures the correct behavior of the +// GetRunningPrebuiltWorkspaces query. +func TestGetRunningPrebuiltWorkspaces(t *testing.T) { + t.Parallel() + + if !dbtestutil.WillUsePostgres() { + t.Skip("Test requires PostgreSQL for complex queries") + } + + ctx := testutil.Context(t, testutil.WaitLong) + db, _ := dbtestutil.NewDB(t) + now := dbtime.Now() + + // Given: a prebuilt workspace with a successful start build and a stop build. + org := dbgen.Organization(t, db, database.Organization{}) + user := dbgen.User(t, db, database.User{}) + template := dbgen.Template(t, db, database.Template{ + CreatedBy: user.ID, + OrganizationID: org.ID, + }) + templateVersion := dbgen.TemplateVersion(t, db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, + OrganizationID: org.ID, + CreatedBy: user.ID, + }) + preset := dbgen.Preset(t, db, database.InsertPresetParams{ + TemplateVersionID: templateVersion.ID, + DesiredInstances: sql.NullInt32{Int32: 1, Valid: true}, + }) + + setupFixture := func(t *testing.T, db database.Store, name string, deleted bool, transition database.WorkspaceTransition, jobStatus database.ProvisionerJobStatus) database.WorkspaceTable { + t.Helper() + ws := dbgen.Workspace(t, db, database.WorkspaceTable{ + OwnerID: database.PrebuildsSystemUserID, + TemplateID: template.ID, + Name: name, + Deleted: deleted, + }) + var canceledAt sql.NullTime + var jobError sql.NullString + switch jobStatus { + case database.ProvisionerJobStatusFailed: + jobError = sql.NullString{String: assert.AnError.Error(), Valid: true} + case database.ProvisionerJobStatusCanceled: + canceledAt = sql.NullTime{Time: now, Valid: true} + } + pj := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{ + OrganizationID: org.ID, + InitiatorID: database.PrebuildsSystemUserID, + Provisioner: database.ProvisionerTypeEcho, + Type: database.ProvisionerJobTypeWorkspaceBuild, + StartedAt: sql.NullTime{Time: now.Add(-time.Minute), Valid: true}, + CanceledAt: canceledAt, + CompletedAt: sql.NullTime{Time: now, Valid: true}, + Error: jobError, + }) + wb := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ + WorkspaceID: ws.ID, + TemplateVersionID: templateVersion.ID, + TemplateVersionPresetID: uuid.NullUUID{UUID: preset.ID, Valid: true}, + JobID: pj.ID, + BuildNumber: 1, + Transition: transition, + InitiatorID: database.PrebuildsSystemUserID, + Reason: database.BuildReasonInitiator, + }) + // Ensure things are set up as expectd + require.Equal(t, transition, wb.Transition) + require.Equal(t, int32(1), wb.BuildNumber) + require.Equal(t, jobStatus, pj.JobStatus) + require.Equal(t, deleted, ws.Deleted) + + return ws + } + + // Given: a number of prebuild workspaces with different states exist. + runningPrebuild := setupFixture(t, db, "running-prebuild", false, database.WorkspaceTransitionStart, database.ProvisionerJobStatusSucceeded) + _ = setupFixture(t, db, "stopped-prebuild", false, database.WorkspaceTransitionStop, database.ProvisionerJobStatusSucceeded) + _ = setupFixture(t, db, "failed-prebuild", false, database.WorkspaceTransitionStart, database.ProvisionerJobStatusFailed) + _ = setupFixture(t, db, "canceled-prebuild", false, database.WorkspaceTransitionStart, database.ProvisionerJobStatusCanceled) + _ = setupFixture(t, db, "deleted-prebuild", true, database.WorkspaceTransitionStart, database.ProvisionerJobStatusSucceeded) + + // Given: a regular workspace also exists. + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ + OwnerID: user.ID, + TemplateID: template.ID, + Name: "test-running-regular-workspace", + Deleted: false, + }) + + // When: we query for running prebuild workspaces + runningPrebuilds, err := db.GetRunningPrebuiltWorkspaces(ctx) + require.NoError(t, err) + + // Then: only the running prebuild workspace should be returned. + require.Len(t, runningPrebuilds, 1, "expected only one running prebuilt workspace") + require.Equal(t, runningPrebuild.ID, runningPrebuilds[0].ID, "expected the running prebuilt workspace to be returned") +} diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 7b55c6a4db7b8..04ded71f1242a 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -6843,6 +6843,7 @@ FROM workspace_prebuilds p INNER JOIN workspace_latest_builds b ON b.workspace_id = p.id WHERE (b.transition = 'start'::workspace_transition AND b.job_status = 'succeeded'::provisioner_job_status) +ORDER BY p.id ` type GetRunningPrebuiltWorkspacesRow struct { @@ -6886,6 +6887,106 @@ func (q *sqlQuerier) GetRunningPrebuiltWorkspaces(ctx context.Context) ([]GetRun return items, nil } +const getRunningPrebuiltWorkspacesOptimized = `-- name: GetRunningPrebuiltWorkspacesOptimized :many +WITH latest_prebuilds AS ( + -- All workspaces that match the following criteria: + -- 1. Owned by prebuilds user + -- 2. Not deleted + -- 3. Latest build is a 'start' transition + -- 4. Latest build was successful + SELECT + workspaces.id, + workspaces.name, + workspaces.template_id, + workspace_latest_builds.template_version_id, + workspace_latest_builds.job_id, + workspaces.created_at + FROM workspace_latest_builds + JOIN workspaces ON workspaces.id = workspace_latest_builds.workspace_id + WHERE workspace_latest_builds.transition = 'start'::workspace_transition + AND workspace_latest_builds.job_status = 'succeeded'::provisioner_job_status + AND workspaces.owner_id = 'c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID + AND NOT workspaces.deleted +), +workspace_latest_presets AS ( + -- For each of the above workspaces, the preset_id of the most recent + -- successful start transition. + SELECT DISTINCT ON (latest_prebuilds.id) + latest_prebuilds.id AS workspace_id, + workspace_builds.template_version_preset_id AS current_preset_id + FROM latest_prebuilds + JOIN workspace_builds ON workspace_builds.workspace_id = latest_prebuilds.id + WHERE workspace_builds.transition = 'start'::workspace_transition + AND workspace_builds.template_version_preset_id IS NOT NULL + ORDER BY latest_prebuilds.id, workspace_builds.build_number DESC +), +ready_agents AS ( + -- For each of the above workspaces, check if all agents are ready. + SELECT + latest_prebuilds.job_id, + BOOL_AND(workspace_agents.lifecycle_state = 'ready'::workspace_agent_lifecycle_state)::boolean AS ready + FROM latest_prebuilds + JOIN workspace_resources ON workspace_resources.job_id = latest_prebuilds.job_id + JOIN workspace_agents ON workspace_agents.resource_id = workspace_resources.id + WHERE workspace_agents.deleted = false + AND workspace_agents.parent_id IS NULL + GROUP BY latest_prebuilds.job_id +) +SELECT + latest_prebuilds.id, + latest_prebuilds.name, + latest_prebuilds.template_id, + latest_prebuilds.template_version_id, + workspace_latest_presets.current_preset_id, + COALESCE(ready_agents.ready, false)::boolean AS ready, + latest_prebuilds.created_at +FROM latest_prebuilds +LEFT JOIN ready_agents ON ready_agents.job_id = latest_prebuilds.job_id +LEFT JOIN workspace_latest_presets ON workspace_latest_presets.workspace_id = latest_prebuilds.id +ORDER BY latest_prebuilds.id +` + +type GetRunningPrebuiltWorkspacesOptimizedRow struct { + ID uuid.UUID `db:"id" json:"id"` + Name string `db:"name" json:"name"` + TemplateID uuid.UUID `db:"template_id" json:"template_id"` + TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` + CurrentPresetID uuid.NullUUID `db:"current_preset_id" json:"current_preset_id"` + Ready bool `db:"ready" json:"ready"` + CreatedAt time.Time `db:"created_at" json:"created_at"` +} + +func (q *sqlQuerier) GetRunningPrebuiltWorkspacesOptimized(ctx context.Context) ([]GetRunningPrebuiltWorkspacesOptimizedRow, error) { + rows, err := q.db.QueryContext(ctx, getRunningPrebuiltWorkspacesOptimized) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetRunningPrebuiltWorkspacesOptimizedRow + for rows.Next() { + var i GetRunningPrebuiltWorkspacesOptimizedRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.TemplateID, + &i.TemplateVersionID, + &i.CurrentPresetID, + &i.Ready, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getTemplatePresetsWithPrebuilds = `-- name: GetTemplatePresetsWithPrebuilds :many SELECT t.id AS template_id, diff --git a/coderd/database/queries/prebuilds.sql b/coderd/database/queries/prebuilds.sql index 2fc9f3f4a67f6..7e1dbc71f4a26 100644 --- a/coderd/database/queries/prebuilds.sql +++ b/coderd/database/queries/prebuilds.sql @@ -48,6 +48,64 @@ WHERE tvp.desired_instances IS NOT NULL -- Consider only presets that have a pre -- AND NOT t.deleted -- We don't exclude deleted templates because there's no constraint in the DB preventing a soft deletion on a template while workspaces are running. AND (t.id = sqlc.narg('template_id')::uuid OR sqlc.narg('template_id') IS NULL); +-- name: GetRunningPrebuiltWorkspacesOptimized :many +WITH latest_prebuilds AS ( + -- All workspaces that match the following criteria: + -- 1. Owned by prebuilds user + -- 2. Not deleted + -- 3. Latest build is a 'start' transition + -- 4. Latest build was successful + SELECT + workspaces.id, + workspaces.name, + workspaces.template_id, + workspace_latest_builds.template_version_id, + workspace_latest_builds.job_id, + workspaces.created_at + FROM workspace_latest_builds + JOIN workspaces ON workspaces.id = workspace_latest_builds.workspace_id + WHERE workspace_latest_builds.transition = 'start'::workspace_transition + AND workspace_latest_builds.job_status = 'succeeded'::provisioner_job_status + AND workspaces.owner_id = 'c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID + AND NOT workspaces.deleted +), +workspace_latest_presets AS ( + -- For each of the above workspaces, the preset_id of the most recent + -- successful start transition. + SELECT DISTINCT ON (latest_prebuilds.id) + latest_prebuilds.id AS workspace_id, + workspace_builds.template_version_preset_id AS current_preset_id + FROM latest_prebuilds + JOIN workspace_builds ON workspace_builds.workspace_id = latest_prebuilds.id + WHERE workspace_builds.transition = 'start'::workspace_transition + AND workspace_builds.template_version_preset_id IS NOT NULL + ORDER BY latest_prebuilds.id, workspace_builds.build_number DESC +), +ready_agents AS ( + -- For each of the above workspaces, check if all agents are ready. + SELECT + latest_prebuilds.job_id, + BOOL_AND(workspace_agents.lifecycle_state = 'ready'::workspace_agent_lifecycle_state)::boolean AS ready + FROM latest_prebuilds + JOIN workspace_resources ON workspace_resources.job_id = latest_prebuilds.job_id + JOIN workspace_agents ON workspace_agents.resource_id = workspace_resources.id + WHERE workspace_agents.deleted = false + AND workspace_agents.parent_id IS NULL + GROUP BY latest_prebuilds.job_id +) +SELECT + latest_prebuilds.id, + latest_prebuilds.name, + latest_prebuilds.template_id, + latest_prebuilds.template_version_id, + workspace_latest_presets.current_preset_id, + COALESCE(ready_agents.ready, false)::boolean AS ready, + latest_prebuilds.created_at +FROM latest_prebuilds +LEFT JOIN ready_agents ON ready_agents.job_id = latest_prebuilds.job_id +LEFT JOIN workspace_latest_presets ON workspace_latest_presets.workspace_id = latest_prebuilds.id +ORDER BY latest_prebuilds.id; + -- name: GetRunningPrebuiltWorkspaces :many SELECT p.id, @@ -60,7 +118,8 @@ SELECT FROM workspace_prebuilds p INNER JOIN workspace_latest_builds b ON b.workspace_id = p.id WHERE (b.transition = 'start'::workspace_transition - AND b.job_status = 'succeeded'::provisioner_job_status); + AND b.job_status = 'succeeded'::provisioner_job_status) +ORDER BY p.id; -- name: CountInProgressPrebuilds :many -- CountInProgressPrebuilds returns the number of in-progress prebuilds, grouped by preset ID and transition. diff --git a/enterprise/coderd/prebuilds/reconcile.go b/enterprise/coderd/prebuilds/reconcile.go index 44e0e82c8881a..cce39ea251323 100644 --- a/enterprise/coderd/prebuilds/reconcile.go +++ b/enterprise/coderd/prebuilds/reconcile.go @@ -12,6 +12,7 @@ import ( "sync/atomic" "time" + "github.com/google/go-cmp/cmp" "github.com/hashicorp/go-multierror" "github.com/prometheus/client_golang/prometheus" @@ -398,11 +399,21 @@ func (c *StoreReconciler) SnapshotState(ctx context.Context, store database.Stor return xerrors.Errorf("failed to get preset prebuild schedules: %w", err) } + // Get results from both original and optimized queries for comparison allRunningPrebuilds, err := db.GetRunningPrebuiltWorkspaces(ctx) if err != nil { return xerrors.Errorf("failed to get running prebuilds: %w", err) } + // Compare with optimized query to ensure behavioral correctness + optimized, err := db.GetRunningPrebuiltWorkspacesOptimized(ctx) + if err != nil { + // Log the error but continue with original results + c.logger.Error(ctx, "optimized GetRunningPrebuiltWorkspacesOptimized failed", slog.Error(err)) + } else { + CompareGetRunningPrebuiltWorkspacesResults(ctx, c.logger, allRunningPrebuilds, optimized) + } + allPrebuildsInProgress, err := db.CountInProgressPrebuilds(ctx) if err != nil { return xerrors.Errorf("failed to get prebuilds in progress: %w", err) @@ -922,3 +933,30 @@ func SetPrebuildsReconciliationPaused(ctx context.Context, db database.Store, pa } return db.UpsertPrebuildsSettings(ctx, string(settingsJSON)) } + +// CompareGetRunningPrebuiltWorkspacesResults compares the original and optimized +// query results and logs any differences found. This function can be easily +// removed once we're confident the optimized query works correctly. +// TODO(Cian): Remove this function once the optimized query is stable and correct. +func CompareGetRunningPrebuiltWorkspacesResults( + ctx context.Context, + logger slog.Logger, + original []database.GetRunningPrebuiltWorkspacesRow, + optimized []database.GetRunningPrebuiltWorkspacesOptimizedRow, +) { + if len(original) == 0 && len(optimized) == 0 { + return + } + // Convert optimized results to the same type as original for comparison + optimizedConverted := make([]database.GetRunningPrebuiltWorkspacesRow, len(optimized)) + for i, row := range optimized { + optimizedConverted[i] = database.GetRunningPrebuiltWorkspacesRow(row) + } + + // Compare the results and log an error if they differ. + // NOTE: explicitly not sorting here as both query results are ordered by ID. + if diff := cmp.Diff(original, optimizedConverted); diff != "" { + logger.Error(ctx, "results differ for GetRunningPrebuiltWorkspacesOptimized", + slog.F("diff", diff)) + } +} diff --git a/enterprise/coderd/prebuilds/reconcile_test.go b/enterprise/coderd/prebuilds/reconcile_test.go index fce5269214ed1..858b01abc00b9 100644 --- a/enterprise/coderd/prebuilds/reconcile_test.go +++ b/enterprise/coderd/prebuilds/reconcile_test.go @@ -5,6 +5,7 @@ import ( "database/sql" "fmt" "sort" + "strings" "sync" "testing" "time" @@ -26,6 +27,7 @@ import ( "tailscale.com/types/ptr" "cdr.dev/slog" + "cdr.dev/slog/sloggers/slogjson" "cdr.dev/slog/sloggers/slogtest" "github.com/coder/quartz" @@ -370,6 +372,8 @@ func TestPrebuildReconciliation(t *testing.T) { templateVersionID, ) + setupTestDBPrebuildAntagonists(t, db, pubSub, org) + if !templateVersionActive { // Create a new template version and mark it as active // This marks the template version that we care about as inactive @@ -2116,6 +2120,115 @@ func setupTestDBWorkspaceAgent(t *testing.T, db database.Store, workspaceID uuid return agent } +// setupTestDBAntagonists creates test antagonists that should not influence running prebuild workspace tests. +// 1. A stopped prebuilt workspace (STOP then START transitions, owned by +// prebuilds system user). +// 2. A running regular workspace (not owned by the prebuilds system user). +func setupTestDBPrebuildAntagonists(t *testing.T, db database.Store, ps pubsub.Pubsub, org database.Organization) { + t.Helper() + + templateAdmin := dbgen.User(t, db, database.User{RBACRoles: []string{codersdk.RoleTemplateAdmin}}) + _ = dbgen.OrganizationMember(t, db, database.OrganizationMember{ + OrganizationID: org.ID, + UserID: templateAdmin.ID, + }) + member := dbgen.User(t, db, database.User{}) + _ = dbgen.OrganizationMember(t, db, database.OrganizationMember{ + OrganizationID: org.ID, + UserID: member.ID, + }) + tpl := dbgen.Template(t, db, database.Template{ + OrganizationID: org.ID, + CreatedBy: templateAdmin.ID, + }) + tv := dbgen.TemplateVersion(t, db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: org.ID, + CreatedBy: templateAdmin.ID, + }) + + // 1) Stopped prebuilt workspace (owned by prebuilds system user) + stoppedPrebuild := dbgen.Workspace(t, db, database.WorkspaceTable{ + OwnerID: database.PrebuildsSystemUserID, + TemplateID: tpl.ID, + Name: "prebuild-antagonist-stopped", + Deleted: false, + }) + + // STOP build (build number 2, most recent) + stoppedJob2 := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ + OrganizationID: org.ID, + InitiatorID: database.PrebuildsSystemUserID, + Provisioner: database.ProvisionerTypeEcho, + Type: database.ProvisionerJobTypeWorkspaceBuild, + StartedAt: sql.NullTime{Time: dbtime.Now().Add(-30 * time.Second), Valid: true}, + CompletedAt: sql.NullTime{Time: dbtime.Now().Add(-20 * time.Second), Valid: true}, + Error: sql.NullString{}, + ErrorCode: sql.NullString{}, + }) + dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ + WorkspaceID: stoppedPrebuild.ID, + TemplateVersionID: tv.ID, + JobID: stoppedJob2.ID, + BuildNumber: 2, + Transition: database.WorkspaceTransitionStop, + InitiatorID: database.PrebuildsSystemUserID, + Reason: database.BuildReasonInitiator, + // Explicitly not using a preset here. This shouldn't normally be possible, + // but without this the reconciler will try to create a new prebuild for + // this preset, which will affect the tests. + TemplateVersionPresetID: uuid.NullUUID{}, + }) + + // START build (build number 1, older) + stoppedJob1 := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ + OrganizationID: org.ID, + InitiatorID: database.PrebuildsSystemUserID, + Provisioner: database.ProvisionerTypeEcho, + Type: database.ProvisionerJobTypeWorkspaceBuild, + StartedAt: sql.NullTime{Time: dbtime.Now().Add(-60 * time.Second), Valid: true}, + CompletedAt: sql.NullTime{Time: dbtime.Now().Add(-50 * time.Second), Valid: true}, + Error: sql.NullString{}, + ErrorCode: sql.NullString{}, + }) + dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ + WorkspaceID: stoppedPrebuild.ID, + TemplateVersionID: tv.ID, + JobID: stoppedJob1.ID, + BuildNumber: 1, + Transition: database.WorkspaceTransitionStart, + InitiatorID: database.PrebuildsSystemUserID, + Reason: database.BuildReasonInitiator, + }) + + // 2) Running regular workspace (not owned by prebuilds system user) + regularWorkspace := dbgen.Workspace(t, db, database.WorkspaceTable{ + OwnerID: member.ID, + TemplateID: tpl.ID, + Name: "antagonist-regular-workspace", + Deleted: false, + }) + regularJob := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{ + OrganizationID: org.ID, + InitiatorID: member.ID, + Provisioner: database.ProvisionerTypeEcho, + Type: database.ProvisionerJobTypeWorkspaceBuild, + StartedAt: sql.NullTime{Time: dbtime.Now().Add(-40 * time.Second), Valid: true}, + CompletedAt: sql.NullTime{Time: dbtime.Now().Add(-30 * time.Second), Valid: true}, + Error: sql.NullString{}, + ErrorCode: sql.NullString{}, + }) + dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ + WorkspaceID: regularWorkspace.ID, + TemplateVersionID: tv.ID, + JobID: regularJob.ID, + BuildNumber: 1, + Transition: database.WorkspaceTransitionStart, + InitiatorID: member.ID, + Reason: database.BuildReasonInitiator, + }) +} + var allTransitions = []database.WorkspaceTransition{ database.WorkspaceTransitionStart, database.WorkspaceTransitionStop, @@ -2220,3 +2333,164 @@ func TestReconciliationRespectsPauseSetting(t *testing.T) { require.NoError(t, err) require.Len(t, workspaces, 2, "should have recreated 2 prebuilds after resuming") } + +func TestCompareGetRunningPrebuiltWorkspacesResults(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + // Helper to create test data + createWorkspaceRow := func(id string, name string, ready bool) database.GetRunningPrebuiltWorkspacesRow { + uid := uuid.MustParse(id) + return database.GetRunningPrebuiltWorkspacesRow{ + ID: uid, + Name: name, + TemplateID: uuid.New(), + TemplateVersionID: uuid.New(), + CurrentPresetID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + Ready: ready, + CreatedAt: time.Now(), + } + } + + createOptimizedRow := func(row database.GetRunningPrebuiltWorkspacesRow) database.GetRunningPrebuiltWorkspacesOptimizedRow { + return database.GetRunningPrebuiltWorkspacesOptimizedRow(row) + } + + t.Run("identical results - no logging", func(t *testing.T) { + t.Parallel() + + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + + original := []database.GetRunningPrebuiltWorkspacesRow{ + createWorkspaceRow("550e8400-e29b-41d4-a716-446655440000", "workspace1", true), + createWorkspaceRow("550e8400-e29b-41d4-a716-446655440001", "workspace2", false), + } + + optimized := []database.GetRunningPrebuiltWorkspacesOptimizedRow{ + createOptimizedRow(original[0]), + createOptimizedRow(original[1]), + } + + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, original, optimized) + + // Should not log any errors when results are identical + require.Empty(t, strings.TrimSpace(sb.String())) + }) + + t.Run("count mismatch - logs error", func(t *testing.T) { + t.Parallel() + + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + + original := []database.GetRunningPrebuiltWorkspacesRow{ + createWorkspaceRow("550e8400-e29b-41d4-a716-446655440000", "workspace1", true), + } + + optimized := []database.GetRunningPrebuiltWorkspacesOptimizedRow{ + createOptimizedRow(original[0]), + createOptimizedRow(createWorkspaceRow("550e8400-e29b-41d4-a716-446655440001", "workspace2", false)), + } + + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, original, optimized) + + // Should log exactly one error. + if lines := strings.Split(strings.TrimSpace(sb.String()), "\n"); assert.NotEmpty(t, lines) { + require.Len(t, lines, 1) + assert.Contains(t, lines[0], "ERROR") + assert.Contains(t, lines[0], "workspace2") + assert.Contains(t, lines[0], "CurrentPresetID") + } + }) + + t.Run("count mismatch - other direction", func(t *testing.T) { + t.Parallel() + + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + + original := []database.GetRunningPrebuiltWorkspacesRow{} + + optimized := []database.GetRunningPrebuiltWorkspacesOptimizedRow{ + createOptimizedRow(createWorkspaceRow("550e8400-e29b-41d4-a716-446655440001", "workspace2", false)), + } + + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, original, optimized) + + if lines := strings.Split(strings.TrimSpace(sb.String()), "\n"); assert.NotEmpty(t, lines) { + require.Len(t, lines, 1) + assert.Contains(t, lines[0], "ERROR") + assert.Contains(t, lines[0], "workspace2") + assert.Contains(t, lines[0], "CurrentPresetID") + } + }) + + t.Run("field differences - logs errors", func(t *testing.T) { + t.Parallel() + + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + + workspace1 := createWorkspaceRow("550e8400-e29b-41d4-a716-446655440000", "workspace1", true) + workspace2 := createWorkspaceRow("550e8400-e29b-41d4-a716-446655440001", "workspace2", false) + + original := []database.GetRunningPrebuiltWorkspacesRow{workspace1, workspace2} + + // Create optimized with different values + optimized1 := createOptimizedRow(workspace1) + optimized1.Name = "different-name" // Different name + optimized1.Ready = false // Different ready status + + optimized2 := createOptimizedRow(workspace2) + optimized2.CurrentPresetID = uuid.NullUUID{Valid: false} // Different preset ID (NULL) + + optimized := []database.GetRunningPrebuiltWorkspacesOptimizedRow{optimized1, optimized2} + + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, original, optimized) + + // Should log exactly one error with a cmp.Diff output + if lines := strings.Split(strings.TrimSpace(sb.String()), "\n"); assert.NotEmpty(t, lines) { + require.Len(t, lines, 1) + assert.Contains(t, lines[0], "ERROR") + assert.Contains(t, lines[0], "different-name") + assert.Contains(t, lines[0], "workspace1") + assert.Contains(t, lines[0], "Ready") + assert.Contains(t, lines[0], "CurrentPresetID") + } + }) + + t.Run("empty results - no logging", func(t *testing.T) { + t.Parallel() + + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + + original := []database.GetRunningPrebuiltWorkspacesRow{} + optimized := []database.GetRunningPrebuiltWorkspacesOptimizedRow{} + + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, original, optimized) + + // Should not log any errors when both results are empty + require.Empty(t, strings.TrimSpace(sb.String())) + }) + + t.Run("nil original", func(t *testing.T) { + t.Parallel() + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, nil, []database.GetRunningPrebuiltWorkspacesOptimizedRow{}) + // Should not log any errors when original is nil + require.Empty(t, strings.TrimSpace(sb.String())) + }) + + t.Run("nil optimized ", func(t *testing.T) { + t.Parallel() + var sb strings.Builder + logger := slog.Make(slogjson.Sink(&sb)) + prebuilds.CompareGetRunningPrebuiltWorkspacesResults(ctx, logger, []database.GetRunningPrebuiltWorkspacesRow{}, nil) + // Should not log any errors when optimized is nil + require.Empty(t, strings.TrimSpace(sb.String())) + }) +} From 9c61ef82b069cc8a6b755a91aacccf9371bc98df Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 9 Jul 2025 11:09:10 -0300 Subject: [PATCH 29/61] test: fix DeploymentSidebarView stories (#18812) --- .../modules/management/DeploymentSidebarView.stories.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/site/src/modules/management/DeploymentSidebarView.stories.tsx b/site/src/modules/management/DeploymentSidebarView.stories.tsx index d7fee99bc2ade..2465556110e98 100644 --- a/site/src/modules/management/DeploymentSidebarView.stories.tsx +++ b/site/src/modules/management/DeploymentSidebarView.stories.tsx @@ -1,5 +1,9 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { MockNoPermissions, MockPermissions } from "testHelpers/entities"; +import { + MockBuildInfo, + MockNoPermissions, + MockPermissions, +} from "testHelpers/entities"; import { withDashboardProvider } from "testHelpers/storybook"; import { DeploymentSidebarView } from "./DeploymentSidebarView"; @@ -10,6 +14,8 @@ const meta: Meta = { parameters: { showOrganizations: true }, args: { permissions: MockPermissions, + experiments: [], + buildInfo: MockBuildInfo, }, }; From 00ba0278d2586f66dc0005ee88954874ea3a56a3 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 9 Jul 2025 08:45:24 -0600 Subject: [PATCH 30/61] chore: modify parameter dynamic immutability behavior (#18583) Immutability behavior is determined by the current build, not affected by the previous --- coderd/dynamicparameters/resolver.go | 41 +++++------ coderd/dynamicparameters/resolver_test.go | 66 +++++++++++++++++ enterprise/coderd/dynamicparameters_test.go | 70 ++++++++++++++++++- .../parameters/dynamicimmutable/main.tf | 23 ++++++ 4 files changed, 174 insertions(+), 26 deletions(-) create mode 100644 enterprise/coderd/testdata/parameters/dynamicimmutable/main.tf diff --git a/coderd/dynamicparameters/resolver.go b/coderd/dynamicparameters/resolver.go index bd8e2294cf136..7fc67d29a0d55 100644 --- a/coderd/dynamicparameters/resolver.go +++ b/coderd/dynamicparameters/resolver.go @@ -55,19 +55,21 @@ func ResolveParameters( values[preset.Name] = parameterValue{Source: sourcePreset, Value: preset.Value} } - // originalValues is going to be used to detect if a user tried to change + // originalInputValues is going to be used to detect if a user tried to change // an immutable parameter after the first build. - originalValues := make(map[string]parameterValue, len(values)) + // The actual input values are mutated based on attributes like mutability + // and ephemerality. + originalInputValues := make(map[string]parameterValue, len(values)) for name, value := range values { // Store the original values for later use. - originalValues[name] = value + originalInputValues[name] = value } // Render the parameters using the values that were supplied to the previous build. // // This is how the form should look to the user on their workspace settings page. // This is the original form truth that our validations should initially be based on. - output, diags := renderer.Render(ctx, ownerID, values.ValuesMap()) + output, diags := renderer.Render(ctx, ownerID, previousValuesMap) if diags.HasErrors() { // Top level diagnostics should break the build. Previous values (and new) should // always be valid. If there is a case where this is not true, then this has to @@ -91,22 +93,6 @@ func ResolveParameters( delete(values, parameter.Name) } } - - // Immutable parameters should also not be allowed to be changed from - // the previous build. Remove any values taken from the preset or - // new build params. This forces the value to be the same as it was before. - // - // We do this so the next form render uses the original immutable value. - if !firstBuild && !parameter.Mutable { - delete(values, parameter.Name) - prev, ok := previousValuesMap[parameter.Name] - if ok { - values[parameter.Name] = parameterValue{ - Value: prev, - Source: sourcePrevious, - } - } - } } // This is the final set of values that will be used. Any errors at this stage @@ -116,7 +102,7 @@ func ResolveParameters( return nil, parameterValidationError(diags) } - // parameterNames is going to be used to remove any excess values that were left + // parameterNames is going to be used to remove any excess values left // around without a parameter. parameterNames := make(map[string]struct{}, len(output.Parameters)) parameterError := parameterValidationError(nil) @@ -124,15 +110,20 @@ func ResolveParameters( parameterNames[parameter.Name] = struct{}{} if !firstBuild && !parameter.Mutable { - originalValue, ok := originalValues[parameter.Name] + // previousValuesMap should be used over the first render output + // for the previous state of parameters. The previous build + // should emit all values, so the previousValuesMap should be + // complete with all parameter values (user specified and defaults) + originalValue, ok := previousValuesMap[parameter.Name] + // Immutable parameters should not be changed after the first build. - // If the value matches the original value, that is fine. + // If the value matches the previous input value, that is fine. // - // If the original value is not set, that means this is a new parameter. New + // If the previous value is not set, that means this is a new parameter. New // immutable parameters are allowed. This is an opinionated choice to prevent // workspaces failing to update or delete. Ideally we would block this, as // immutable parameters should only be able to be set at creation time. - if ok && parameter.Value.AsString() != originalValue.Value { + if ok && parameter.Value.AsString() != originalValue { var src *hcl.Range if parameter.Source != nil { src = ¶meter.Source.HCLBlock().TypeRange diff --git a/coderd/dynamicparameters/resolver_test.go b/coderd/dynamicparameters/resolver_test.go index ec5218613ff03..e6675e6f4c7dc 100644 --- a/coderd/dynamicparameters/resolver_test.go +++ b/coderd/dynamicparameters/resolver_test.go @@ -10,6 +10,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/dynamicparameters" "github.com/coder/coder/v2/coderd/dynamicparameters/rendermock" + "github.com/coder/coder/v2/coderd/httpapi/httperror" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/testutil" "github.com/coder/preview" @@ -56,4 +57,69 @@ func TestResolveParameters(t *testing.T) { require.NoError(t, err) require.Equal(t, map[string]string{"immutable": "foo"}, values) }) + + // Tests a parameter going from mutable -> immutable + t.Run("BecameImmutable", func(t *testing.T) { + t.Parallel() + + ctrl := gomock.NewController(t) + render := rendermock.NewMockRenderer(ctrl) + + mutable := previewtypes.ParameterData{ + Name: "immutable", + Type: previewtypes.ParameterTypeString, + FormType: provider.ParameterFormTypeInput, + Mutable: true, + DefaultValue: previewtypes.StringLiteral("foo"), + Required: true, + } + immutable := mutable + immutable.Mutable = false + + // A single immutable parameter with no previous value. + render.EXPECT(). + Render(gomock.Any(), gomock.Any(), gomock.Any()). + // Return the mutable param first + Return(&preview.Output{ + Parameters: []previewtypes.Parameter{ + { + ParameterData: mutable, + Value: previewtypes.StringLiteral("foo"), + Diagnostics: nil, + }, + }, + }, nil) + + render.EXPECT(). + Render(gomock.Any(), gomock.Any(), gomock.Any()). + // Then the immutable param + Return(&preview.Output{ + Parameters: []previewtypes.Parameter{ + { + ParameterData: immutable, + // The user set the value to bar + Value: previewtypes.StringLiteral("bar"), + Diagnostics: nil, + }, + }, + }, nil) + + ctx := testutil.Context(t, testutil.WaitShort) + _, err := dynamicparameters.ResolveParameters(ctx, uuid.New(), render, false, + []database.WorkspaceBuildParameter{ + {Name: "immutable", Value: "foo"}, // Previous value foo + }, + []codersdk.WorkspaceBuildParameter{ + {Name: "immutable", Value: "bar"}, // New value + }, + []database.TemplateVersionPresetParameter{}, // No preset values + ) + require.Error(t, err) + resp, ok := httperror.IsResponder(err) + require.True(t, ok) + + _, respErr := resp.Response() + require.Len(t, respErr.Validations, 1) + require.Contains(t, respErr.Validations[0].Error(), "is not mutable") + }) } diff --git a/enterprise/coderd/dynamicparameters_test.go b/enterprise/coderd/dynamicparameters_test.go index e13d370a059ad..94a4158dc8354 100644 --- a/enterprise/coderd/dynamicparameters_test.go +++ b/enterprise/coderd/dynamicparameters_test.go @@ -338,7 +338,6 @@ func TestDynamicParameterBuild(t *testing.T) { bld, err := templateAdmin.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{ TemplateVersionID: immutable.ID, // Use the new template version with the immutable parameter Transition: codersdk.WorkspaceTransitionDelete, - DryRun: false, }) require.NoError(t, err) coderdtest.AwaitWorkspaceBuildJobCompleted(t, templateAdmin, bld.ID) @@ -354,6 +353,75 @@ func TestDynamicParameterBuild(t *testing.T) { require.NoError(t, err) require.Equal(t, wrk.ID, deleted.ID, "workspace should be deleted") }) + + t.Run("PreviouslyImmutable", func(t *testing.T) { + // Ok this is a weird test to document how things are working. + // What if a parameter flips it's immutability based on a value? + // The current behavior is to source immutability from the new state. + // So the value is allowed to be changed. + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitShort) + // Start with a new template that has 1 parameter that is immutable + immutable, _ := coderdtest.DynamicParameterTemplate(t, templateAdmin, orgID, coderdtest.DynamicParameterTemplateParams{ + MainTF: "# PreviouslyImmutable\n" + string(must(os.ReadFile("testdata/parameters/dynamicimmutable/main.tf"))), + }) + + // Create the workspace with the immutable parameter + wrk, err := templateAdmin.CreateUserWorkspace(ctx, codersdk.Me, codersdk.CreateWorkspaceRequest{ + TemplateID: immutable.ID, + Name: coderdtest.RandomUsername(t), + RichParameterValues: []codersdk.WorkspaceBuildParameter{ + {Name: "isimmutable", Value: "true"}, + {Name: "immutable", Value: "coder"}, + }, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, templateAdmin, wrk.LatestBuild.ID) + + // Try new values + _, err = templateAdmin.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionStart, + RichParameterValues: []codersdk.WorkspaceBuildParameter{ + {Name: "isimmutable", Value: "false"}, + {Name: "immutable", Value: "not-coder"}, + }, + }) + require.NoError(t, err) + }) + + t.Run("PreviouslyMutable", func(t *testing.T) { + // The value cannot be changed because it becomes immutable. + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitShort) + immutable, _ := coderdtest.DynamicParameterTemplate(t, templateAdmin, orgID, coderdtest.DynamicParameterTemplateParams{ + MainTF: "# PreviouslyMutable\n" + string(must(os.ReadFile("testdata/parameters/dynamicimmutable/main.tf"))), + }) + + // Create the workspace with the mutable parameter + wrk, err := templateAdmin.CreateUserWorkspace(ctx, codersdk.Me, codersdk.CreateWorkspaceRequest{ + TemplateID: immutable.ID, + Name: coderdtest.RandomUsername(t), + RichParameterValues: []codersdk.WorkspaceBuildParameter{ + {Name: "isimmutable", Value: "false"}, + {Name: "immutable", Value: "coder"}, + }, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, templateAdmin, wrk.LatestBuild.ID) + + // Switch it to immutable, which breaks the validation + _, err = templateAdmin.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionStart, + RichParameterValues: []codersdk.WorkspaceBuildParameter{ + {Name: "isimmutable", Value: "true"}, + {Name: "immutable", Value: "not-coder"}, + }, + }) + require.Error(t, err) + require.ErrorContains(t, err, "is not mutable") + }) }) } diff --git a/enterprise/coderd/testdata/parameters/dynamicimmutable/main.tf b/enterprise/coderd/testdata/parameters/dynamicimmutable/main.tf new file mode 100644 index 0000000000000..08bdd3336faa9 --- /dev/null +++ b/enterprise/coderd/testdata/parameters/dynamicimmutable/main.tf @@ -0,0 +1,23 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + } +} + +data "coder_workspace_owner" "me" {} + +data "coder_parameter" "isimmutable" { + name = "isimmutable" + type = "bool" + mutable = true + default = "true" +} + +data "coder_parameter" "immutable" { + name = "immutable" + type = "string" + mutable = data.coder_parameter.isimmutable.value == "false" + default = "Hello World" +} From 5a8a19be70b9e133dc9f511f64ae8bb928a489b5 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 9 Jul 2025 15:04:24 -0300 Subject: [PATCH 31/61] feat: auto reconnect the terminal (#18796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Changes:** - Use [websocket-ts](https://www.npmjs.com/package/websocket-ts) to have auto reconnection out of the box 🙏 - Update the disconnected alert message to "Trying to connect..." since the connection is always trying to reconnect - Remove `useWithRetry` because it is not necessary anymore **Other topics:** - The disconnected alert is displaying a simple message, but we can include more info such as the number of attemtps - The reconnection feature is in a good state and adding value. IMO, any improvement can be done after getting this merged Closes https://github.com/coder/internal/issues/659 --- site/package.json | 1 + site/pnpm-lock.yaml | 8 + site/src/hooks/index.ts | 1 - site/src/hooks/useWithRetry.test.ts | 329 ------------------ site/src/hooks/useWithRetry.ts | 106 ------ .../src/pages/TerminalPage/TerminalAlerts.tsx | 6 +- .../pages/TerminalPage/TerminalPage.test.tsx | 6 +- site/src/pages/TerminalPage/TerminalPage.tsx | 40 ++- 8 files changed, 47 insertions(+), 450 deletions(-) delete mode 100644 site/src/hooks/useWithRetry.test.ts delete mode 100644 site/src/hooks/useWithRetry.ts diff --git a/site/package.json b/site/package.json index 1512a803b0a96..e3a99b9d8eebf 100644 --- a/site/package.json +++ b/site/package.json @@ -120,6 +120,7 @@ "undici": "6.21.2", "unique-names-generator": "4.7.1", "uuid": "9.0.1", + "websocket-ts": "2.2.1", "yup": "1.6.1" }, "devDependencies": { diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml index 62cdc6176092a..3c7f5176b5b6b 100644 --- a/site/pnpm-lock.yaml +++ b/site/pnpm-lock.yaml @@ -274,6 +274,9 @@ importers: uuid: specifier: 9.0.1 version: 9.0.1 + websocket-ts: + specifier: 2.2.1 + version: 2.2.1 yup: specifier: 1.6.1 version: 1.6.1 @@ -6344,6 +6347,9 @@ packages: webpack-virtual-modules@0.5.0: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==, tarball: https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz} + websocket-ts@2.2.1: + resolution: {integrity: sha512-YKPDfxlK5qOheLZ2bTIiktZO1bpfGdNCPJmTEaPW7G9UXI1GKjDdeacOrsULUS000OPNxDVOyAuKLuIWPqWM0Q==, tarball: https://registry.npmjs.org/websocket-ts/-/websocket-ts-2.2.1.tgz} + whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==, tarball: https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz} engines: {node: '>=12'} @@ -13266,6 +13272,8 @@ snapshots: webpack-virtual-modules@0.5.0: {} + websocket-ts@2.2.1: {} + whatwg-encoding@2.0.0: dependencies: iconv-lite: 0.6.3 diff --git a/site/src/hooks/index.ts b/site/src/hooks/index.ts index 4453e36fa4bb4..901fee8a50ded 100644 --- a/site/src/hooks/index.ts +++ b/site/src/hooks/index.ts @@ -3,4 +3,3 @@ export * from "./useClickable"; export * from "./useClickableTableRow"; export * from "./useClipboard"; export * from "./usePagination"; -export * from "./useWithRetry"; diff --git a/site/src/hooks/useWithRetry.test.ts b/site/src/hooks/useWithRetry.test.ts deleted file mode 100644 index 7ed7b4331f21e..0000000000000 --- a/site/src/hooks/useWithRetry.test.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { act, renderHook } from "@testing-library/react"; -import { useWithRetry } from "./useWithRetry"; - -// Mock timers -jest.useFakeTimers(); - -describe("useWithRetry", () => { - let mockFn: jest.Mock; - - beforeEach(() => { - mockFn = jest.fn(); - jest.clearAllTimers(); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it("should initialize with correct default state", () => { - const { result } = renderHook(() => useWithRetry(mockFn)); - - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).toBe(undefined); - }); - - it("should execute function successfully on first attempt", async () => { - mockFn.mockResolvedValue(undefined); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - await act(async () => { - await result.current.call(); - }); - - expect(mockFn).toHaveBeenCalledTimes(1); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).toBe(undefined); - }); - - it("should set isLoading to true during execution", async () => { - let resolvePromise: () => void; - const promise = new Promise((resolve) => { - resolvePromise = resolve; - }); - mockFn.mockReturnValue(promise); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - act(() => { - result.current.call(); - }); - - expect(result.current.isLoading).toBe(true); - - await act(async () => { - resolvePromise!(); - await promise; - }); - - expect(result.current.isLoading).toBe(false); - }); - - it("should retry on failure with exponential backoff", async () => { - mockFn - .mockRejectedValueOnce(new Error("First failure")) - .mockRejectedValueOnce(new Error("Second failure")) - .mockResolvedValueOnce(undefined); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - // Start the call - await act(async () => { - await result.current.call(); - }); - - expect(mockFn).toHaveBeenCalledTimes(1); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - - // Fast-forward to first retry (1 second) - await act(async () => { - jest.advanceTimersByTime(1000); - }); - - expect(mockFn).toHaveBeenCalledTimes(2); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - - // Fast-forward to second retry (2 seconds) - await act(async () => { - jest.advanceTimersByTime(2000); - }); - - expect(mockFn).toHaveBeenCalledTimes(3); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).toBe(undefined); - }); - - it("should continue retrying without limit", async () => { - mockFn.mockRejectedValue(new Error("Always fails")); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - // Start the call - await act(async () => { - await result.current.call(); - }); - - expect(mockFn).toHaveBeenCalledTimes(1); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - - // Fast-forward through multiple retries to verify it continues - for (let i = 1; i < 15; i++) { - const delay = Math.min(1000 * 2 ** (i - 1), 600000); // exponential backoff with max delay - await act(async () => { - jest.advanceTimersByTime(delay); - }); - expect(mockFn).toHaveBeenCalledTimes(i + 1); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - } - - // Should still be retrying after 15 attempts - expect(result.current.nextRetryAt).not.toBe(null); - }); - - it("should respect max delay of 10 minutes", async () => { - mockFn.mockRejectedValue(new Error("Always fails")); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - // Start the call - await act(async () => { - await result.current.call(); - }); - - expect(result.current.isLoading).toBe(false); - - // Fast-forward through several retries to reach max delay - // After attempt 9, delay would be 1000 * 2^9 = 512000ms, which is less than 600000ms (10 min) - // After attempt 10, delay would be 1000 * 2^10 = 1024000ms, which should be capped at 600000ms - - // Skip to attempt 9 (delay calculation: 1000 * 2^8 = 256000ms) - for (let i = 1; i < 9; i++) { - const delay = 1000 * 2 ** (i - 1); - await act(async () => { - jest.advanceTimersByTime(delay); - }); - } - - expect(mockFn).toHaveBeenCalledTimes(9); - expect(result.current.nextRetryAt).not.toBe(null); - - // The 9th retry should use max delay (600000ms = 10 minutes) - await act(async () => { - jest.advanceTimersByTime(600000); - }); - - expect(mockFn).toHaveBeenCalledTimes(10); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - - // Continue with more retries at max delay to verify it continues indefinitely - await act(async () => { - jest.advanceTimersByTime(600000); - }); - - expect(mockFn).toHaveBeenCalledTimes(11); - expect(result.current.nextRetryAt).not.toBe(null); - }); - - it("should cancel previous retry when call is invoked again", async () => { - mockFn - .mockRejectedValueOnce(new Error("First failure")) - .mockResolvedValueOnce(undefined); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - // Start the first call - await act(async () => { - await result.current.call(); - }); - - expect(mockFn).toHaveBeenCalledTimes(1); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - - // Call again before retry happens - await act(async () => { - await result.current.call(); - }); - - expect(mockFn).toHaveBeenCalledTimes(2); - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).toBe(undefined); - - // Advance time to ensure previous retry was cancelled - await act(async () => { - jest.advanceTimersByTime(5000); - }); - - expect(mockFn).toHaveBeenCalledTimes(2); // Should not have been called again - }); - - it("should set nextRetryAt when scheduling retry", async () => { - mockFn - .mockRejectedValueOnce(new Error("Failure")) - .mockResolvedValueOnce(undefined); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - // Start the call - await act(async () => { - await result.current.call(); - }); - - const nextRetryAt = result.current.nextRetryAt; - expect(nextRetryAt).not.toBe(null); - expect(nextRetryAt).toBeInstanceOf(Date); - - // nextRetryAt should be approximately 1 second in the future - const expectedTime = Date.now() + 1000; - const actualTime = nextRetryAt!.getTime(); - expect(Math.abs(actualTime - expectedTime)).toBeLessThan(100); // Allow 100ms tolerance - - // Advance past retry time - await act(async () => { - jest.advanceTimersByTime(1000); - }); - - expect(result.current.nextRetryAt).toBe(undefined); - }); - - it("should cleanup timer on unmount", async () => { - mockFn.mockRejectedValue(new Error("Failure")); - - const { result, unmount } = renderHook(() => useWithRetry(mockFn)); - - // Start the call to create timer - await act(async () => { - await result.current.call(); - }); - - expect(result.current.isLoading).toBe(false); - expect(result.current.nextRetryAt).not.toBe(null); - - // Unmount should cleanup timer - unmount(); - - // Advance time to ensure timer was cleared - await act(async () => { - jest.advanceTimersByTime(5000); - }); - - // Function should not have been called again - expect(mockFn).toHaveBeenCalledTimes(1); - }); - - it("should prevent scheduling retries when function completes after unmount", async () => { - let rejectPromise: (error: Error) => void; - const promise = new Promise((_, reject) => { - rejectPromise = reject; - }); - mockFn.mockReturnValue(promise); - - const { result, unmount } = renderHook(() => useWithRetry(mockFn)); - - // Start the call - this will make the function in-flight - act(() => { - result.current.call(); - }); - - expect(result.current.isLoading).toBe(true); - - // Unmount while function is still in-flight - unmount(); - - // Function completes with error after unmount - await act(async () => { - rejectPromise!(new Error("Failed after unmount")); - await promise.catch(() => {}); // Suppress unhandled rejection - }); - - // Advance time to ensure no retry timers were scheduled - await act(async () => { - jest.advanceTimersByTime(5000); - }); - - // Function should only have been called once (no retries after unmount) - expect(mockFn).toHaveBeenCalledTimes(1); - }); - - it("should do nothing when call() is invoked while function is already loading", async () => { - let resolvePromise: () => void; - const promise = new Promise((resolve) => { - resolvePromise = resolve; - }); - mockFn.mockReturnValue(promise); - - const { result } = renderHook(() => useWithRetry(mockFn)); - - // Start the first call - this will set isLoading to true - act(() => { - result.current.call(); - }); - - expect(result.current.isLoading).toBe(true); - expect(mockFn).toHaveBeenCalledTimes(1); - - // Try to call again while loading - should do nothing - act(() => { - result.current.call(); - }); - - // Function should not have been called again - expect(mockFn).toHaveBeenCalledTimes(1); - expect(result.current.isLoading).toBe(true); - - // Complete the original promise - await act(async () => { - resolvePromise!(); - await promise; - }); - - expect(result.current.isLoading).toBe(false); - expect(mockFn).toHaveBeenCalledTimes(1); - }); -}); diff --git a/site/src/hooks/useWithRetry.ts b/site/src/hooks/useWithRetry.ts deleted file mode 100644 index 1310da221efc5..0000000000000 --- a/site/src/hooks/useWithRetry.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from "react"; -import { useEffectEvent } from "./hookPolyfills"; - -const DELAY_MS = 1_000; -const MAX_DELAY_MS = 600_000; // 10 minutes -// Determines how much the delay between retry attempts increases after each -// failure. -const MULTIPLIER = 2; - -interface UseWithRetryResult { - call: () => void; - nextRetryAt: Date | undefined; - isLoading: boolean; -} - -interface RetryState { - isLoading: boolean; - nextRetryAt: Date | undefined; -} - -/** - * Hook that wraps a function with automatic retry functionality - * Provides a simple interface for executing functions with exponential backoff retry - */ -export function useWithRetry(fn: () => Promise): UseWithRetryResult { - const [state, setState] = useState({ - isLoading: false, - nextRetryAt: undefined, - }); - - const timeoutRef = useRef(null); - const mountedRef = useRef(true); - - const clearTimeout = useCallback(() => { - if (timeoutRef.current) { - window.clearTimeout(timeoutRef.current); - timeoutRef.current = null; - } - }, []); - - const stableFn = useEffectEvent(fn); - - const call = useCallback(() => { - if (state.isLoading) { - return; - } - - clearTimeout(); - - const executeAttempt = async (attempt = 0): Promise => { - if (!mountedRef.current) { - return; - } - setState({ - isLoading: true, - nextRetryAt: undefined, - }); - - try { - await stableFn(); - if (mountedRef.current) { - setState({ isLoading: false, nextRetryAt: undefined }); - } - } catch (error) { - if (!mountedRef.current) { - return; - } - const delayMs = Math.min( - DELAY_MS * MULTIPLIER ** attempt, - MAX_DELAY_MS, - ); - - setState({ - isLoading: false, - nextRetryAt: new Date(Date.now() + delayMs), - }); - - timeoutRef.current = window.setTimeout(() => { - if (!mountedRef.current) { - return; - } - setState({ - isLoading: false, - nextRetryAt: undefined, - }); - executeAttempt(attempt + 1); - }, delayMs); - } - }; - - executeAttempt(); - }, [state.isLoading, stableFn, clearTimeout]); - - useEffect(() => { - return () => { - mountedRef.current = false; - clearTimeout(); - }; - }, [clearTimeout]); - - return { - call, - nextRetryAt: state.nextRetryAt, - isLoading: state.isLoading, - }; -} diff --git a/site/src/pages/TerminalPage/TerminalAlerts.tsx b/site/src/pages/TerminalPage/TerminalAlerts.tsx index 07740135769f3..6a06a76964128 100644 --- a/site/src/pages/TerminalPage/TerminalAlerts.tsx +++ b/site/src/pages/TerminalPage/TerminalAlerts.tsx @@ -170,14 +170,16 @@ const TerminalAlert: FC = (props) => { ); }; +// Since the terminal connection is always trying to reconnect, we show this +// alert to indicate that the terminal is trying to connect. const DisconnectedAlert: FC = (props) => { return ( } > - Disconnected + Trying to connect... ); }; diff --git a/site/src/pages/TerminalPage/TerminalPage.test.tsx b/site/src/pages/TerminalPage/TerminalPage.test.tsx index 7600fa5257d43..4591190ad9904 100644 --- a/site/src/pages/TerminalPage/TerminalPage.test.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.test.tsx @@ -85,7 +85,7 @@ describe("TerminalPage", () => { await expectTerminalText(container, Language.workspaceErrorMessagePrefix); }); - it("shows an error if the websocket fails", async () => { + it("shows reconnect message when websocket fails", async () => { server.use( http.get("/api/v2/workspaceagents/:agentId/pty", () => { return HttpResponse.json({}, { status: 500 }); @@ -94,7 +94,9 @@ describe("TerminalPage", () => { const { container } = await renderTerminal(); - await expectTerminalText(container, Language.websocketErrorMessagePrefix); + await waitFor(() => { + expect(container.textContent).toContain("Trying to connect..."); + }); }); it("renders data from the backend", async () => { diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index 2023bdb0eeb29..5c13e89c30005 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -26,6 +26,13 @@ import { openMaybePortForwardedURL } from "utils/portForward"; import { terminalWebsocketUrl } from "utils/terminal"; import { getMatchingAgentOrFirst } from "utils/workspace"; import { v4 as uuidv4 } from "uuid"; +// Use websocket-ts for better WebSocket handling and auto-reconnection. +import { + ExponentialBackoff, + type Websocket, + WebsocketBuilder, + WebsocketEvent, +} from "websocket-ts"; import { TerminalAlerts } from "./TerminalAlerts"; import type { ConnectionStatus } from "./types"; @@ -221,7 +228,7 @@ const TerminalPage: FC = () => { } // Hook up terminal events to the websocket. - let websocket: WebSocket | null; + let websocket: Websocket | null; const disposers = [ terminal.onData((data) => { websocket?.send( @@ -259,9 +266,11 @@ const TerminalPage: FC = () => { if (disposed) { return; // Unmounted while we waited for the async call. } - websocket = new WebSocket(url); + websocket = new WebsocketBuilder(url) + .withBackoff(new ExponentialBackoff(1000, 6)) + .build(); websocket.binaryType = "arraybuffer"; - websocket.addEventListener("open", () => { + websocket.addEventListener(WebsocketEvent.open, () => { // Now that we are connected, allow user input. terminal.options = { disableStdin: false, @@ -278,18 +287,16 @@ const TerminalPage: FC = () => { ); setConnectionStatus("connected"); }); - websocket.addEventListener("error", () => { + websocket.addEventListener(WebsocketEvent.error, (_, event) => { + console.error("WebSocket error:", event); terminal.options.disableStdin = true; - terminal.writeln( - `${Language.websocketErrorMessagePrefix}socket errored`, - ); setConnectionStatus("disconnected"); }); - websocket.addEventListener("close", () => { + websocket.addEventListener(WebsocketEvent.close, () => { terminal.options.disableStdin = true; setConnectionStatus("disconnected"); }); - websocket.addEventListener("message", (event) => { + websocket.addEventListener(WebsocketEvent.message, (_, event) => { if (typeof event.data === "string") { // This exclusively occurs when testing. // "jest-websocket-mock" doesn't support ArrayBuffer. @@ -298,12 +305,25 @@ const TerminalPage: FC = () => { terminal.write(new Uint8Array(event.data)); } }); + websocket.addEventListener(WebsocketEvent.reconnect, () => { + if (websocket) { + websocket.binaryType = "arraybuffer"; + websocket.send( + new TextEncoder().encode( + JSON.stringify({ + height: terminal.rows, + width: terminal.cols, + }), + ), + ); + } + }); }) .catch((error) => { if (disposed) { return; // Unmounted while we waited for the async call. } - terminal.writeln(Language.websocketErrorMessagePrefix + error.message); + console.error("WebSocket connection failed:", error); setConnectionStatus("disconnected"); }); From b882d46d912d0be6c7a78d22fcf29b11991c84e5 Mon Sep 17 00:00:00 2001 From: Edward Angert Date: Wed, 9 Jul 2025 16:04:48 -0400 Subject: [PATCH 32/61] docs: fix relative links in about/contributing (#18818) hotfix --------- Co-authored-by: EdwardAngert <17991901+EdwardAngert@users.noreply.github.com> --- docs/about/contributing/backend.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/about/contributing/backend.md b/docs/about/contributing/backend.md index 1ffafa62fb324..ad5d91bcda879 100644 --- a/docs/about/contributing/backend.md +++ b/docs/about/contributing/backend.md @@ -16,9 +16,9 @@ Need help or have questions? Join the conversation on our [Discord server](https To understand how the backend fits into the broader system, we recommend reviewing the following resources: -* [General Concepts](../admin/infrastructure/validated-architectures/index.md#general-concepts): Essential concepts and language used to describe how Coder is structured and operated. +* [General Concepts](../../admin/infrastructure/validated-architectures/index.md#general-concepts): Essential concepts and language used to describe how Coder is structured and operated. -* [Architecture](../admin/infrastructure/architecture.md): A high-level overview of the infrastructure layout, key services, and how components interact. +* [Architecture](../../admin/infrastructure/architecture.md): A high-level overview of the infrastructure layout, key services, and how components interact. These sections provide the necessary context for navigating and contributing to the backend effectively. @@ -168,9 +168,9 @@ There are two types of fixtures that are used to test that migrations don't break existing Coder deployments: * Partial fixtures - [`migrations/testdata/fixtures`](../../coderd/database/migrations/testdata/fixtures) + [`migrations/testdata/fixtures`](../../../coderd/database/migrations/testdata/fixtures) * Full database dumps - [`migrations/testdata/full_dumps`](../../coderd/database/migrations/testdata/full_dumps) + [`migrations/testdata/full_dumps`](../../../coderd/database/migrations/testdata/full_dumps) Both types behave like database migrations (they also [`migrate`](https://github.com/golang-migrate/migrate)). Their behavior mirrors @@ -193,7 +193,7 @@ To add a new partial fixture, run the following command: ``` Then add some queries to insert data and commit the file to the repo. See -[`000024_example.up.sql`](../../coderd/database/migrations/testdata/fixtures/000024_example.up.sql) +[`000024_example.up.sql`](../../../coderd/database/migrations/testdata/fixtures/000024_example.up.sql) for an example. To create a full dump, run a fully fledged Coder deployment and use it to From c1b2304d183aa73213f057d9531f7a0d357e9d30 Mon Sep 17 00:00:00 2001 From: Ethan <39577870+ethanndickson@users.noreply.github.com> Date: Thu, 10 Jul 2025 19:50:30 +1000 Subject: [PATCH 33/61] test(agent/agentssh): use fish shell compatible exit status checking (#18824) This (week-old) test was failing in my workspace because I use fish shell. I really do not like that Fish shell does not support `$?`, but I also do like Fish shell! We have a few people at Coder who use it who would appreciate this change. --- agent/agentssh/agentssh_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/agentssh/agentssh_test.go b/agent/agentssh/agentssh_test.go index 08fa02ddb4565..159fe345483d2 100644 --- a/agent/agentssh/agentssh_test.go +++ b/agent/agentssh/agentssh_test.go @@ -453,7 +453,7 @@ func TestSSHServer_ClosesStdin(t *testing.T) { // exit code 1 if it hits EOF, which is what we want to test. cmdErrCh := make(chan error, 1) go func() { - cmdErrCh <- sess.Start(fmt.Sprintf("echo started; read; echo \"read exit code: $?\" > %s", filePath)) + cmdErrCh <- sess.Start(fmt.Sprintf(`echo started; echo "read exit code: $(read && echo 0 || echo 1)" > %s`, filePath)) }() cmdErr := testutil.RequireReceive(ctx, t, cmdErrCh) From 040fa30aba749f5e8810833a93ee558d27e216ab Mon Sep 17 00:00:00 2001 From: Edward Angert Date: Thu, 10 Jul 2025 16:01:20 -0400 Subject: [PATCH 34/61] docs: update screenshots with new logo (#18830) stage 1 of many - new login screenshot - remove unused platforms screenshots - update [screenshots doc](https://coder.com/docs/@2025-screenshots/about/screenshots) - update [quickstart doc](https://coder.com/docs/@2025-screenshots/tutorials/quickstart) closes #18813
list of screenshots with old logo or that are outdated |docs/images/|notes?| |--|--| |logo-black.png| | |jupyter-notebook.png| | |platforms/docker/login.png| | |platforms/docker/create-workspace.png| | |platforms/docker/ides.png| | |platforms/gcp/marketplace.png| | |platforms/gcp/start.png| | |platforms/aws/aws-linux.png| | |platforms/aws/marketplace.png| | |platforms/kubernetes/template-variables.png| | |platforms/kubernetes/region-picker.png| | |platforms/kubernetes/starter-template.png| | |install/windows-installer.png| | |install/homebrew.png| | |screenshots/create-template.png| | |screenshots/login.png| | |screenshots/starter_templates.png| | |screenshots/settings.png| | |screenshots/audit.png| | |screenshots/workspace-running-with-topbar.png| | |screenshots/workspaces_listing.png| | |screenshots/templates_listing.png| | |screenshots/welcome-create-admin-user.png| | |screenshots/workspace_launch.png| | |screenshots/templates_insights.png| | |screenshots/healthcheck.png| | |screenshots/terraform.png| | |deploy-pr-manually.png| | |workspace-update.png| | |custom-app.png| | |code-server.png| | |networking/annotatedports.png| | |networking/portsharingmax.png| | |networking/portforwarddashboard.png| | |networking/listeningports.png| | |agent-metadata.png| | |jupyter.png| | |admin/service-banner-maintenance.png| | |admin/provisioner-tags.png| | |admin/github-app-register.png| | |admin/licenses/licenses-screen.png| | |admin/licenses/licenses-nolicense.png| | |admin/licenses/add-license-ui.png| | |admin/service-banner-config.png| | |admin/group-allowlist.png| | |admin/networking/workspace-proxies/ws-proxy-picker.png| | |admin/setup/appearance/application-name-logo-url.png| | |admin/setup/appearance/announcement_banner_settings.png| | |admin/setup/appearance/support-links.png| | |admin/setup/appearance/service-banner-secret.png| | |admin/quota-buildlog.png| | |admin/integrations/kube-region-picker.png| | |admin/integrations/coder-logstream-kube-logs-wrong-image.png| | |admin/integrations/coder-logstream-kube-logs-pod-crashed.png| | |admin/integrations/coder-logstream-kube-logs-normal.png| | |admin/integrations/coder-logstream-kube-logs-quota-exceeded.png| | |admin/git-auth-template.png| | |admin/github-app-install.png| | |admin/users/organizations/role-sync.png| | |admin/users/organizations/group-sync-empty.png| | |admin/users/organizations/workspace-list.png| | |admin/users/organizations/new-organization.png| | |admin/users/organizations/role-sync-empty.png| | |admin/users/organizations/template-org-picker.png| | |admin/users/organizations/organization-members.png| | |admin/users/organizations/org-dropdown-create.png| | |admin/users/organizations/default-organization-settings.png| | |admin/users/organizations/group-sync.png| | |admin/users/organizations/idp-org-sync.png| | |admin/users/organizations/admin-settings-orgs.png| | |admin/users/organizations/custom-roles.png| | |admin/users/quotas/quota-groups.png| | |admin/users/create-token.png| | |admin/users/headless-user.png| | |admin/provisioners/provisioner-jobs.png| | |admin/github-app-permissions.png| | |admin/templates/coder-apps-ui.png| | |admin/templates/starter-templates.png| | |admin/templates/create-template.png| | |admin/templates/schedule/template-schedule-settings.png| | |admin/templates/schedule/user-quiet-hours.png| | |admin/templates/coder-metadata-ui.png| | |admin/templates/duplicate-menu.png| | |admin/templates/agent-metadata-ui.png| | |admin/templates/troubleshooting/workspace-build-timings-ui.png| | |admin/templates/duplicate-page.png| | |admin/templates/new-duplicate-template.png| | |admin/templates/import-template.png| | |admin/templates/extend-templates/prebuilt/replacement-notification.png| | |admin/templates/extend-templates/prebuilt/prebuilt-workspaces.png| | |admin/templates/extend-templates/dyn-params/dynamic-params-compare.png| | |admin/templates/extend-templates/dyn-params/enable-dynamic-parameters.png| | |admin/templates/extend-templates/template-preset-dropdown.png| | |admin/monitoring/health-check.png| | |admin/monitoring/logstream-kube.png| | |admin/monitoring/notifications/user-notification-preferences.png| | |admin/monitoring/notifications/notification-admin-prefs.png| | |admin/workspace-proxy-picker.png| | |admin/admin-settings-general.png| | |admin/deployment-id-copy-clipboard.png| | |icons-gallery.png| | |start/setup-page.png| | |start/workspace-schedule-settings.png| | |start/build-template.png| | |start/starter-templates.png| | |start/create-template.png| | |start/create-workspace.png| | |start/template-preview.png| | |start/blank-workspaces.png| | |start/template-source-code.png| | |start/first-template.png| | |start/workspace-ready.png| | |start/template-edit-source-code.png| | |start/template-publish.png| | |start/starter-templates-annotated.png| | |display-apps.png| | |workspace-automatic-updates.png| | |workspaces/autostop.png| | |workspaces/autostart.png| | |create-workspace-from-templates-ui.png| | |ide-row.png| | |editors.png| | |delete-template.png| | |logo-white.png| | |template-rbac.png| | |coderapp-port-forward.png| | |user-guides/terminal-access.png| | |user-guides/workspace-bulk-actions.png| | |user-guides/devcontainers/devcontainer-agent-ports.png| | |user-guides/devcontainers/devcontainer-web-terminal.png| | |user-guides/create-workspace-ui.png| | |user-guides/workspace-view-connection-annotated.png| | |user-guides/remote-desktops/web-rdp-demo.png| | |user-guides/remote-desktops/amazon-dcv-windows-demo.png| | |user-guides/desktop/coder-desktop-file-sync-add.png| | |user-guides/desktop/coder-desktop-session-token.png| | |user-guides/desktop/coder-desktop-win-pre-sign-in.png| | |user-guides/desktop/coder-desktop-file-sync-conflicts-mouseover.png| | |user-guides/desktop/coder-desktop-mac-pre-sign-in.png| | |user-guides/desktop/coder-desktop-file-sync-watching.png| | |user-guides/desktop/coder-desktop-win-enable-coder-connect.png| | |user-guides/desktop/coder-desktop-sign-in.png| | |user-guides/desktop/coder-desktop-file-sync.png| | |user-guides/desktop/coder-desktop-file-sync-staging.png| | |user-guides/desktop/chrome-insecure-origin.png| | |user-guides/desktop/coder-desktop-workspaces.png| | |user-guides/jetbrains/toolbox/workspaces.png| | |user-guides/jetbrains/toolbox/install.png| | |user-guides/jetbrains/toolbox/login-token.png| | |user-guides/jetbrains/toolbox/login-url.png| | |user-guides/schedule-settings-workspace.png| | |user-guides/dotfiles-module.png| | |user-guides/workspace-list-ui.png| | |user-guides/workspace-settings-location.png| | |template-variables.png| | |ides/code-web-extensions.png| | |ides/copilot.png| | |architecture-multi-region.png| | |external-apps.png| | |guides/ai-agents/tasks-ui.png| | |guides/ai-agents/duplicate.png| | |guides/ai-agents/landing.png| | |guides/ai-agents/workspace-page.png| | |guides/ai-agents/realworld-ui.png| | |guides/xray-integration/example.png| | |guides/using-organizations/workspace-list.png| | |guides/using-organizations/new-organization.png| | |guides/using-organizations/template-org-picker.png| | |guides/using-organizations/deployment-organizations.png| | |guides/using-organizations/organization-members.png| | |readme-logos.png| | |metadata-ui.png| | |secret-metadata-ui.png| | |projector-intellij.png| | |schedule.png| | |ssh-keys.png| | |template-scheduling.png| | |templates/general-settings.png| | |templates/build-template.png| | |templates/update.png| | |templates/starter-templates.png| | |templates/create-template.png| | |templates/select-template.png| | |templates/pre-filled-parameters.png| | |templates/source-code.png| | |templates/upload-create-your-first-template.png| | |templates/create-workspace.png| | |templates/edit-source-code.png| | |templates/permissions.png| | |templates/coder-session-token.png| | |templates/starter-templates-button.png| | |templates/template-tour.png| | |templates/edit-files.png| | |templates/workspace-ready.png| | |templates/template-menu-settings.png| | |templates/workspace-apps.png| | |templates/coder-login-web.png| | |templates/new-workspace.png| | |templates/template-variables.png| | |templates/use-template.png| | |templates/healthy-workspace-agent.png| | |templates/update-policies.png| | |templates/upload-create-template-form.png| | |templates/develop-in-docker-template.png| | |templates/publish.png| | |templates/devcontainers.png| | |templates/create-template-permissions.png| | |port-forward-dashboard.png| | |creating-workspace-ui.png| | |parameters.png| | |best-practice/build-timeline.png| | |file-browser.png| | |architecture-single-region.png| | |gateway/plugin-settings-marketplace.png| | |gateway/plugin-session-token.png| | |gateway/plugin-connect-to-coder.png| | |gateway/plugin-select-ide.png| | |gateway/plugin-ide-list.png| | |hero-image.png| |
--------- Co-authored-by: EdwardAngert <17991901+EdwardAngert@users.noreply.github.com> --- docs/about/screenshots.md | 14 +++++++------- .../platforms/docker/create-workspace.png | Bin 342066 -> 0 bytes docs/images/platforms/docker/ides.png | Bin 121835 -> 0 bytes docs/images/platforms/docker/login.png | Bin 169912 -> 0 bytes .../platforms/kubernetes/region-picker.png | Bin 30520 -> 0 bytes .../platforms/kubernetes/starter-template.png | Bin 45113 -> 0 bytes .../kubernetes/template-variables.png | Bin 29692 -> 0 bytes docs/images/screenshots/admin-settings.png | Bin 0 -> 185082 bytes docs/images/screenshots/audit.png | Bin 131530 -> 129315 bytes docs/images/screenshots/coder-login.png | Bin 0 -> 35683 bytes docs/images/screenshots/create-template.png | Bin 81986 -> 111231 bytes docs/images/screenshots/healthcheck.png | Bin 127743 -> 312389 bytes docs/images/screenshots/login.png | Bin 40459 -> 0 bytes docs/images/screenshots/settings.png | Bin 131744 -> 0 bytes docs/images/screenshots/starter-templates.png | Bin 0 -> 198604 bytes docs/images/screenshots/starter_templates.png | Bin 112764 -> 0 bytes docs/images/screenshots/template-insights.png | Bin 0 -> 157186 bytes docs/images/screenshots/templates-listing.png | Bin 0 -> 174462 bytes .../images/screenshots/templates_insights.png | Bin 165651 -> 0 bytes docs/images/screenshots/templates_listing.png | Bin 140304 -> 0 bytes docs/images/screenshots/terraform.png | Bin 166705 -> 263690 bytes .../screenshots/welcome-create-admin-user.png | Bin 85251 -> 65405 bytes .../workspace-running-with-topbar.png | Bin 58980 -> 122019 bytes docs/images/screenshots/workspace_launch.png | Bin 101241 -> 0 bytes .../images/screenshots/workspaces-listing.png | Bin 0 -> 91669 bytes .../images/screenshots/workspaces_listing.png | Bin 86975 -> 0 bytes docs/images/start/blank-workspaces.png | Bin 458834 -> 0 bytes docs/images/templates/coder-login-web.png | Bin 54783 -> 0 bytes docs/tutorials/quickstart.md | 2 +- docs/tutorials/template-from-scratch.md | 4 ++-- 30 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 docs/images/platforms/docker/create-workspace.png delete mode 100755 docs/images/platforms/docker/ides.png delete mode 100755 docs/images/platforms/docker/login.png delete mode 100644 docs/images/platforms/kubernetes/region-picker.png delete mode 100644 docs/images/platforms/kubernetes/starter-template.png delete mode 100644 docs/images/platforms/kubernetes/template-variables.png create mode 100644 docs/images/screenshots/admin-settings.png create mode 100644 docs/images/screenshots/coder-login.png delete mode 100644 docs/images/screenshots/login.png delete mode 100644 docs/images/screenshots/settings.png create mode 100644 docs/images/screenshots/starter-templates.png delete mode 100644 docs/images/screenshots/starter_templates.png create mode 100644 docs/images/screenshots/template-insights.png create mode 100644 docs/images/screenshots/templates-listing.png delete mode 100644 docs/images/screenshots/templates_insights.png delete mode 100644 docs/images/screenshots/templates_listing.png delete mode 100644 docs/images/screenshots/workspace_launch.png create mode 100644 docs/images/screenshots/workspaces-listing.png delete mode 100644 docs/images/screenshots/workspaces_listing.png delete mode 100644 docs/images/start/blank-workspaces.png delete mode 100644 docs/images/templates/coder-login-web.png diff --git a/docs/about/screenshots.md b/docs/about/screenshots.md index ddf71b823f7fc..dff7ea75946d8 100644 --- a/docs/about/screenshots.md +++ b/docs/about/screenshots.md @@ -2,19 +2,19 @@ ## Log in -![Install Coder in your cloud or air-gapped on-premises. Developers simply log in via their browser to access their Workspaces.](../images/screenshots/login.png) +![Install Coder in your cloud or air-gapped on-premises. Developers simply log in via their browser to access their Workspaces.](../images/screenshots/coder-login.png) Install Coder in your cloud or air-gapped on-premises. Developers simply log in via their browser to access their Workspaces. ## Templates -![Developers provision their own ephemeral Workspaces in minutes using pre-defined Templates that include approved tooling and infrastructure.](../images/screenshots/templates_listing.png) +![Developers provision their own ephemeral Workspaces in minutes using pre-defined Templates that include approved tooling and infrastructure.](../images/screenshots/templates-listing.png) Developers provision their own ephemeral Workspaces in minutes using pre-defined Templates that include approved tooling and infrastructure. -![Template administrators can either create a new Template from scratch or choose a Starter Template](../images/screenshots/starter_templates.png) +![Template administrators can either create a new Template from scratch or choose a Starter Template](../images/screenshots/starter-templates.png) Template administrators can either create a new Template from scratch or choose a Starter Template. @@ -26,25 +26,25 @@ underlying infrastructure that Coder Workspaces run on. ## Workspaces -![Developers create and delete their own workspaces. Coder administrators can easily enforce Workspace scheduling and autostop policies to ensure idle Workspaces don’t burn unnecessary cloud budget.](../images/screenshots/workspaces_listing.png) +![Developers create and delete their own workspaces. Coder administrators can easily enforce Workspace scheduling and autostop policies to ensure idle Workspaces don’t burn unnecessary cloud budget.](../images/screenshots/workspaces-listing.png) Developers create and delete their own workspaces. Coder administrators can easily enforce Workspace scheduling and autostop policies to ensure idle Workspaces don’t burn unnecessary cloud budget. -![Developers launch their favorite web-based or desktop IDE, browse files, or access their Workspace’s Terminal.](../images/screenshots/workspace_launch.png) +![Developers launch their favorite web-based or desktop IDE, browse files, or access their Workspace’s Terminal.](../images/screenshots/workspace-running-with-topbar.png) Developers launch their favorite web-based or desktop IDE, browse files, or access their Workspace’s Terminal. ## Administration -![Coder administrators can access Template usage insights to understand which Templates are most popular and how well they perform for developers.](../images/screenshots/templates_insights.png) +![Coder administrators can access Template usage insights to understand which Templates are most popular and how well they perform for developers.](../images/screenshots/template-insights.png) Coder administrators can access Template usage insights to understand which Templates are most popular and how well they perform for developers. -![Coder administrators can control *every* aspect of their Coder deployment.](../images/screenshots/settings.png) +![Coder administrators can control *every* aspect of their Coder deployment.](../images/screenshots/admin-settings.png) Coder administrators can control *every* aspect of their Coder deployment. diff --git a/docs/images/platforms/docker/create-workspace.png b/docs/images/platforms/docker/create-workspace.png deleted file mode 100644 index 9959244a96f1c0655a8bfb3ae41152e775ca28fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 342066 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

mAo_qXoE~349Yox45M_iq~`DjanCSD}0qv-qS%T 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

-4LhG}rVx8dQ6NaSzUuGgPXq}OUfGrC&% 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

W+%M!V;hJ~(RSa6ufB^{ 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 z%0Dy+&h2V?4h90QAnVqrRfS4T;(!9+opv+YzRK#Y0{Q~ad_g4GQyz#okyz}@vry7v zK;1xbUB|jAr>9+glpep=ZG{*T3RZ5!VbFcKv6WNn3x&M5qKuDwZSiX4q=*xS^^z$D z6Ap}oU|tT0&-WVc8_q!~TSr+{nUim*(4`IpnRKH}IZDXa6Ej!k@@n3yc*p-$m6X&F zIYVLJnTpcVSLr448~#j@QCkD}-j;PBu9G;A51X0K{b2U_1C%N_3_~*Pd`{~4NW*Ri z1WRAvaF90n4iq>b807jUsPZSsI;oW2HmCx&zinRe6hfX9cFWoXF6-PIUILy}B*ZquZ zbkv!Q%SUc#&^#{Vv7f&&UlTP71*AuzGWzQ##`$O#T-cuS1=A7Yn^X%9W6}-u>W|0P zuGo3`C=wb0h0Lswcl-e_Bd$Zt!^sp)8zDtAhaoV`+ZwL*i=qWylI;K?o$(PimRsj- z+^452GjC*`M?#9mJ|StccyWF%DF1CM5<-G8UthLUrvAB3)b|hB?z3S3L?ELBU;NA^ z`KQ)J>^VSpD&&S?NffQ$U`FFFA^^f@FQ78Zz~rQ@d~HI)$J z01YZn$pl#?FV*zX2o^ZpKUwAzb9h(H_&8l~jNJpEaDQ}yl7J!oHszZg%BIAwGnqi_v|Y4=Xz8f4yd5kvJ(QlygL=Rb1-{x^&ZldZK zI}EUyUJ#iU!0(n)`q}aJWt0fph@MQ}XjuI&5w!q76!H&VF0y+EA-5oz_-8E<#wQgH`8(YvnK~6@yYAdClCN;zLuJ_$2mImkS`Lxp-nzMDmCiDI1xZ%QSkCFDg5PBJzFyhQY0 zW2ner@NBi@{{ebC1IO??vDo5V)EC1WEkvPBHu2Gdxf<1JN&Hje5LvkE(hoHdcy-jP z{r$JlA@mrEwKgM6O=$Zz_cm>a?tK!D$+`!OV%pzcZh=CY8JUa3nlE3%mMImPnc&@H z?iKg4qJrYmn&7BE#=CU{u<%G;XXF{&mIVhkL!Gdgy)>vRskvm)!sTlYM2p;u7QN~v z(d=opfC)Z5T{yi!%De_1eV|*C=gjyxbTf}`ffBM_Ox}~>t(4(hon$4HOil8U`=2tj z-uZ0xm(%iRi39v0*{o3P@i}7aNxRBI**(QO;=90*EQ3z-jMZ&Nj;WR`M<#a+`Zb&* zQkNv&-T^IBSgt7>m!*x-OnOL`K6ErPS?n=?UIMlg*mto!LP-EWM;TG}EzWChI4o0V5K-unFSg59C14!D5)U_V(EJ(PsbJT4b zxq~O~yHY)&I|d_VH{8CDEpiFf#(X}!?QqitrB~5xALiSt1YLXYcCk@agWc}TKBv+X zwpB(t;0I<}Z}y8gpD>3TZ3~EH8r=>CZwTJD#%V?xjGLX#yEUe4L_V?5gw-EGA?Xr2 zH0wDwzjgw98jLo=uyr{o3{n$#OpNeyLTm*c>g^DZKF9$D-6$Be*wV7uw8^^hW{{C< z9T!GZ^3ZycnO^o{n^LgLh;PnpQ0Dl;ECeL|D(VAxwPOTL>ZAf9KcQugkhhqeRMy=2 z@XZmb0c8rit)Yz0{2r>Y^1c&n`t0_BybGp$vH5+c8;wTy?R?};^eZP`Y`XnXxPRx~ z$GiAD%4^p0rweS#xURulsD>n+;4*B6I(0M{K4px_NAtr25`%W-&+uIge?kOrAk%fx z-u+eiBRuXV9tSRi$SZ(OF4NR7n1tbiN;736X*xR`d+Gc?<7_AdZ<>ASiyGBODZ(C> zuo80)Ol|}@i($E$QZb4rXblNoTcURsNU>8m;lbFu=4b<5{1ZKi`$KpPxtGl}06yei zHr>YNoZKftw8>V&2e^6#l)KU~a(kBVY48%Gf%Yb*g)3}n9vB#KebMYI+u$Gc@of~2 zR!AEx5zz3kn1`A%7j=hmRduWHCq8yuSsEoM(Y%0+OIWSrd<&*yF!EV?bjhGlC;9A$ zs~u~nO{^DkN188;8!Sg`p(xgCeLife#2Yn{XPn(@V8ed5$->3wYkp{gFhI8jWp*p< zsoRXJHRs(WKO*WlP?zgcD%f{>=adNLv@;@)X*9ZlJ$K{_cLZ=(=7h zgMGR!x=I^>74H{joQ)({p#LiQ_&$jg{0kfDiT|W0dE*8XQ>pXdT$b7c7ffrO z@iP%kBw|Lx)qF}s>(r8`m;~i_W*^dEd;v;1w6VGZEt!=k%f)dq%Nv zK+9@P#(ZO%?^(^YSN(Sd6YC60CO}42wWfy3&~Lj5`XDR;o^vKY`-4H=#DknJlm>hI z{&3yW>8QUgufcs?FRxl=6J|qQN{9ULa-)8>A^`0qEu&0a?GA`YU`sm^=k}9Fil0$50@w6cD2eeBCf>w}my9pL1{t zJ79i=By3=8Q}0ubTp64k7{H7?k>@XaxUT`G(%3m_*`5&Se;YA4R78Ca4bf;IOj=nGRmjXhE~jS4z#Snn9nG}!X)Iq43^7(Ld2>T?~cytK01xrj&GRR21)#k1xH3EK4y(?4uIXjYtZMxr>F_XY$QPs+l>tCS4Z9u zQUaIl_>!UC9!VDNs9hFmz3GB5^i_7`W)&7uMOQKbmE8E zG49aLZ_7tm|8!bUi=$#aosVN<>yytH`Lf<`vr+dqluC?j;12mpYnD29Qp`He#+I_lk^4 z+t$BoJUqR`$Mbcs;#T{?f{QDAKc>*xot%+d=mYB~#>1@&l5YW-@tVdDa`!#Q6IIoS z9S*_ur@n)0xwC9qaM@?&`WdYsM+1%{7S1d^-=EP+^EdmwAXrYab1eB)wFL|FwN0|b zl7Dmu?z8wYik*HVcJX%MAbS#3{wl-Tt$LEvqz!71GD>L?A#P@k+C*Iui#?ow>H%sx zPiMuq@vwx^T>-QHbalBIzl^S>asSX#nZNd%3vU){;Lz_gIbxUFSbrb(HdF9-vYa9$ zp{cJtN5q{+<_8+3wXD`KxF0f^Z>z58jq|SQJ>oTcbjRQ?G(D zO$}H7qr`#%$)bhPtv)}Ql4zXx)6d=ev_3tbsvns+X7#t*eY*+d&!b3c3Vlu5ryqY| zj^{p6C?@M>h{x|Gt+Q0){m_U{K2w;*Em74EcZMQZLvhCbnKoJ)wDBzgV$R?77( zN7NJkyX9|_d`Xt+v{JD}WnUX&THI;aGoKru|4YiGD?Vhobx1aPDa1RI!>@-V9pVd*+e#9GJG639%?;)=m$QgSgYGSVRzP43B7P1x zsJk9)7RXh`5tB;QIEeH~rHxNa z(@0!=;I6R4#u}@^Omkn~!LF4Iu0_y7ffH<}PEy>=0u}OdWDSuNzPo$*#WisWMZNP4 zpcVHOUOM(6Fa$)AFZAFzTt17%921}IPCZ($5@JklFCd@BSP2#mwyL$hyG<)Z22G-T z{a}E0#~mJyWNo?nR8`W@9@`= z(#g~lV+R?n_21^5k+sq{yM17kn~Df)--{;a1D|Uvmr)LsHXP95?xhli8`~+f8y%re z)H;j|)K({QcwetOLT1g3(-KhzR&6x>BE$S@L(Z+J233@-Eq7_tk)Mx5$pV-n+zR zB=eTy?1u50iKKHQ^?BqVOlQYrunZTqJ(ho!hHY!Bd%8|CU}KV*u(%dwj6P5jVQW(E zym00ziGxVI2;yMt?hy|C8c9K-cVJ-RtSn{(a;yJ*)Sovm3s(Kc{K_6D~h$yTk_JzH$bFE~DZw9|_4 z*N^6{)RFVdb<15d+C~PwB{?G6s8f(<2Jct;^f3eL9sL=ZYM5!-O3EayYzLEMYA^j!UlY#kjrq z@S8t&*c2)_|E!vIXociYykyW)q8l*5On6?)dm69-rBiL7QM%#H@VF(vYeAjUeO3%d zXRZPpkGc<&4cqQ$8>ue&G3vkFHjh1gn0PKF%Q`Uwci8V#@SbV9_AqTC$b0_6308N- zX*5Glp|0(7 zFpItqrkv5DrnAs;-N-6=Nn69_vPFNXx*w#Hgl>_n9?*4PA-ukDZlsswl}v7VNxce> z2@{YCxg^zU{S5L(SiqBkxtUbK`x3vXzN14%8>Gdq2@%!iY2=24GGllzt55xBqvx*a z^h?widZnVTg(agyJ$NMFv&feE>7GItIY|u*zzyj(t-R{kw3e~C9%`*&)HGaZQg&D~ z`rH0oTzxvC6v^Kh-8bq%y;FG+t1fG*$9vu#UDR{|<&zH|r{x8?eSdRaYFZuJ3yr8X zLe70k~v&z>LFVW%l34?^a;{SMwD>^EX$OD#7OZC+K}-jgrJ3l^>eGa ziDJHlos&V{sZ;O#_3ZDUab~Mi!KedO?tRq0%P9r*+TKAwVug-lEY)dsoNB=sa&>gE z0jz%gcri%D@OByc!wbzbc(WQb6zg`p&*bjbfxut>lOEi*k;*&Y>`4l0%3o2nj%U%JjNODKk8RtM7*8x8fLgzUJ$NMtW3=sB4gR=S5hqqh18Yk?PamRqhs~ zRKP>w)sJ}VIZ8$$j53RG-VGUPR9EHg&m9eRO41u0nSl^L!_~W7aVYlLW6thY2oY`F z<8P^>o*QQ{omuuR!}6Kjv<)gs8Rbp><1S3v$5bxKvIuTmrf%(K+a1!60DY|!FmQLx zOZcZAvM2=%hDHH_J-Zj=CceVq@?JEtom?)p^s`?NW3OcTvr=LlN>z$O%J*BTFDJ2I zPi&zUeoUEqg1l%~=}tp>3n0Av_h$r(DWA^lb_m{$UeZ|*SG8`3UO-kdNIT|!6hAyQ zW2?FgTEysYlp4Kl`jXXGl@sL& zI4k*6&xBcRCGcwJ*1|vXfBOfV(oI>U;V76se@N4WP9D2Lo<&Wc`B?3}V;)LDp6ES+ z>(b~}hm5@(&Kw z`&ojmz{CO;-1$3?*F#pdu~^G7)OnZ~cma8&ARQ@_$sHuOMF7(c@|F}4ujGJXMGITu z&(A)vl_~|?diWHBBe*c@A7BiPiYwMewdzW)C!UpVuuLuli&S6#=Jm&z=B^2$G;2kH zqMWd)=IKnu2^<)egy1|Qr+Lmlq_}+#wx|4Xi@X1kd5qnPS{Ulex_b6-z!|HRjNVLv z6*7)?W~XUeQqyoy|Bt}~I9e1LoHxVoxK{>{-J?)!1(|e}iwg1lUK>B~8ZZ|hj~NDj zHK#__-)Uo9$7|e*#PU8~UlpA9D>~y1wu2pm+wF47`iN_sth*V>R_8*W*uQ8d58+MrseXul=fZ-$VoVB^pN|HnT;#ERAhE!^T)p9))8K zzuZd824i^CY{tCX=`ikmU)8%msf?V?=-An)I{2Y~c290Hy)WD6CIKU}V~ZY)Kexg5 zgOt;zw*PGX)N^b4dhvN`eeou$)g+h}jrxc3c%0O8@{A`*Yj?U?%udP;e*)IYJm=lb zj3gXfQRR3>j&Rk2qJK634GFEGS8^+!dFf!%Mw6@%~Rw zna}JJfm6JNCT`n-3%kNV)WxTS64%t#i;f(HN8FmrOZ&U|0eN@?_fNh)!y-`rHUROa?wm_)1R)tnNd zR>^XDQ;x>vn2Cr~!}Nk`?I@NU~yt1ADU#C=FT zNj}F{FCsvxDB{p>H;9WkPBTeIDeKjNMKvV?LgmB(+M23iw*cP+Fu5It8!vAY`M9ui z+DcYPW@?i;+k+1`eEJx7;7}Onk#n(@b}l@`(mb}~@u=0xfRd(R@_1giP`n=wrNw6C zxkz;CR{O0hO8sKd!CsDcj3D^H5J|0V;h2ovs)NcB)>0UPb@Nxr<#YFpcT{1HP;AOu z3*y1EXSMjAtEzBD_Z@*e5;(k9x@g1I6{sRaLdj`Ne_hk|%Z?MM6!&si`FTOSV$T!> zBcR2ux5|BlFJZ7pwZA@TTxhMa3?8^ALDNm{Mk27s0*|1|C-(aPLQ*3)dh>U=4BeB# zh-0&U(@3fXTE%JD!d#takJpXZj-B`Ej;zFgTG(*Uu+>O)B}5Uhh1yD|6Xsh_8*BqA zk~E#0TV*9XjE*q4?RXys@cw?!1-nxdt_j%3rZuk0{%g?RnPflZ=^Uo{i{ zNOe?{%?pM5PUB~m?BXwbv@FlEeSxchI*kho9nyWeveaeCMR|_6S#VQ8inIsx|0(u+l4AiBl|qjZiQz2 zTWytQXqtQe{RM&vA6Toka>de2UDq|WK>2HU<_zx;EMTKv#4gI>szx_w+~Yq{^NVyP zbq7yotp4)BXq)X)tJIGeRs0%1J&9r6seHRi!`53DTzk!`%g>|iVfY|i2u!(#OqvwG zQK|4Bn4*k5Q=UtfiBsP!TG%ydP}-$QQA_?>wtQ3{Mj_i~$zVS*v!JT4xL}l6nA{gmV*En)-R&WF-1t&&v{WWAHJBCl z7^8XMzONhLGA|WoGCF7bnLCdZiO)WJnA7!9C|?Mxf7llER=1qdJ-FYa&}|bn1?z=Y zmS4nbyWNfc7VdU-<@ih2oN5D!M&KBLsoL+0rOBGI?gh(^{4AHZYARbO?jN^OTjrS# zZqOYwt5x~fe4(di>Q8B0e*DwNYc@2S!xp6ro=VH-pCmUhHEG(@8!o|r{jtku=Tfn* zWI?U+$;`HhM4qdKC>ST3NGh0EGR^9q9vhigd$b-J9rs6Qjm+rZ9u3!&+?cp^q+R?z zs4Oe#9+W)%_*0q{_a8v{RU38?ZsNSu6Jl$LP!H^?-PEdb8ov^S zi^Pka-#k_DvVjsWN;e&tx6Js+VRg7Izj)a!qpq}(`?GWg|I~R~EoRAbb6f94OJV(2 zC-3}-8@!fJ`R==@yBzp%ff#+cGJ_3o!h z<@NH#%WmGs)~CjPb#AM>VlLUyiZxuZqroq68!#383HOyYIz(L^d2?*hV>|FhEM<{{ z2A$wNBZT1TcnutCFt|V8kGR3+(ScS{`ARS#s@0DDTIc>VAMP~NVYp8?KyExz@H@^r zD@eEHgw*tM%;ytl9T{LR@#&bw)&#?rPrEDzW;e7pkEt*(Yh&T;6aX}Nr1FLZBt~2j zP4E6WL^@E{L7V5s+o8p60Pu!FHyCJ}+^CMb^feNGn zf;fI~sr>-F`XMPay<_n6SIMpbhU(8|-=DLJ3%=7aL|30g$6QNVOaJ;*a>wcZCmS%~ zyD6V7qSw46&F)O#FT{^(_AeS=PThh!1xU>Y+PX+^p9v5a+u<)=G*`NjZgG9X~PIX|BUL>qQq`VnvOxz%Lh zp(Aq6l?^jR)m0`tI*U@jKISjZMHX|Mjxoz=hZJR84waL9etz{DSB@{`X%!X;3)rk5 zap2nlTYhrc?1wTATWSiQ8gjVm?Y~*SbmrlZd0syx?NdTc4U@-ItzH3!mO8@=-6Ky6 zD-(AQ$qt)>FxY2mg%9c_bt0(ZM>$D%B=^(^q`sq8LukXwDd>BVuVg%j@IzUMzDpnfyZojd@-XNw5$8L2UJ4tFrqKMuO6Du-ok0> z{58^}Vfq-0){7`OE7Wo;6~1E~*|4-)I&%24<2;QwL%JzVu`7~nY+kXAb$KX_{m2EE z$(LH(E#5vtkEz54y|gtbCVJo)_c*Y|bj7B6nCGkGK;RMUqJ~BfYuY|DDTJqq_>l7S z`Al@I_N!qc^P&Afx?6+;S?A_RD}J`7Sj}F-b0p8uDjsIkk302rDL#Ndl(@kloaX?bB zDAOM<7M%2K=&jEv;R`Hu z%w0w2I%S8wO>LQ~%SWSkEwt_~YM>jVcm4h0 z&XIwHM$Dhvsx9|r>=re@v%LC4`eoO2>$%GvBg>MSrsz>`&xCaEP?nqME;pZWJ?J#} zAycq##I>d`s2n_(%%_xf>MJ=W?nPwV4P7Tc8*6T;t{1FJ*tT%xW!gR4SZ!`3PPZlX z^`lFf&P?A5pS_Pu*600j8|&G2FvdcqR5diEw6KlSTN+N*StBJ_1l*y<-fDh}fSHUj z>`15o%B>v$DTnP=27gT_jjmarb5LH)}lKd`X>j#nYaK-IwBc-3ARDhq_RsswV`RPH3)2oEla$aT5)No1CyHg zbY?W>i@n&{h(M0qKelfjPy?REnS{k+C(j5-UO<@n1ycH%@%2Hj+-e~GDpPxeWUH3G zAO}&+&)HCK=on z{p(hxntl=+e&bBkI4=6oiUdo`fgS$7eYV3&ujpUTs<0gQ#?M6w&(wjc+kA}tYiSa4*HgVjLU0$KAj=KT1CYtIH%YP z628(CeiTjfmfub!oeSV6*DDp^lRy#I@@C9^(a%UzG>2upqul+iz7Y(6X=D3@K;V2d ziQ!^O>e6N`kESOCh^)4-g0`datboo0&L6!s^tY`;zgt3?%y-z>Xi>XJ+-w3obwjVr z_|E`y9HtkM+z&S7z~8}pWH{}vbUvg8f-8x3D?Bres9ys;M&RSr85E*E4N3yKr*N4M zQN&4&R%ay1Ib95RKME!1fJmVAG!ZAkuVo_yguyjL{Y2f@CyAVYsFdl^X0rOHH_Pke zLU-9Jp1k~xs&l&ls+K3bdCEtPyr*d1O#RUyQN~qav$Ax9qiHI-gs@VBTmLQorUPy5 zr0K=9MEiZp$@bsrq_H5b6)+)_KJHG;3c59+2(-f{`6huke)-E%b6v{M-wap$VQ$^tty(E1{i0K&a^*51Y!u9@-H33z+``j93njCY?1l>{} zemJa*7f$f>Pi&i>-DJAF$koE_yOp?UwBcC^WJ!MCMun0ij}TZjj40lDd&>59lhH;x zZpX^;iBoF-m!8 zh&ienjQ;1%xu=;RqAAa@uVQ34=BaPDcH=@{u1&a{BTQO*$wEX3L6I)C<3Ejw=~$o@ zoU>N|KNxAmMp5B0wRdbzdTRf!gEFZ)u!)M9GLo%0KyP2wt8+raJpBW&1uWYLnPML! z-DVIg`+N}__JD^}eJn1oz}z~SQARryL6LYpbvf?x=ZK6a^V;wzMqMZMSs8KFYGZR| zAKS;5YFnXL@*Vt}y`StVcA;ob8oD$>Q3h5~hoTzCXoPJ2cv|D~zIpe5tq5b>%5ihr z8RspW74%b|A#&^AxGC zd*^d6$I6P3A4E z&6}w$4e?)nODxB`QWU%&Eu5{?>2Gjub5o*SR*ju@tD05&(yr`t7|!HFDDFcKiL|J; z>NQa5ZV#;32uvX;pa+k@75nr5GDm-*Wu%Z>81zg&o1Voz7&wLkB6u!W2cFs9^n3t} znM#FCPwdNn#$Xrld363l_jftS{vu&oj>(U>7|{0 z#$0dU6VdRBz|k-ok5Z6nz&VmdCM|);g>VTsC~f0@xs~` zc8OA=S4ZZU2!0W;XAZcWN}+aNQ=-JfTi&u2}$P${H|sp8#w ztU^7xa;nP5K{0RZXlm&L3pB7i0wWEmTEfQHn4w1c7jh+fQuM?PSw zjk}0_I%hlyI%aiL>4852$QbbQQU)DbIj5gL3FPe!O~%~KxN8G0Gz#qKKbd(5GY`z?XM$&O$PY@wG&VJ+l&k+ebAZUeA+(_uN12;tRjbfeJve9ssCn zffWzcz9$n%Nlz8%Uz~F?h9ETuV5h-Qr2;AtqFkh$=z={l(9c|6h?598;qLi{;WV3* zmq$dJ_@9#d->lh7{rf`_QUb2a9(3q}cKlJiR-$ehI1!Jm&p(L)*K{*FG%TBUBW~{c z*P)(-IP8AMn0?*HaCx&Cn(}eT3^DF&5QJ-8>Y%hRpO@@i7>aosgZ;C2!KZQNx>m*n zxXbCNy&@xg#$*L#Dx$d&ve%X@0`i2nQyd{_1O(K@0;RA>@aO?JwhC0WH%Bmi**p$z zPF;Mg3bKfk8WFMyd|uYWc6_(B^U8nyS?2u0VzT}w>Xwr|q(?|PRC(Xn_aZEyA_mK2 znD~yVne& z|Eh|56NEfGFh@rLU&t(iO!i7oLe@iDTpS~gY@yzM6k($O4dH;OVf-8X+*k_ z_oWCQU2#LVxuhN*qD*GxkXciCN=9-Z(@dY+lUxFX=8X$#S+G27ui9?4bZh3+@!8I^( zSn!#DLSoh-0i-;s#etgWcp>sdGy4;;E6E4{EH*^K+Cqy7=IEM~7724NBfAZV3|!|| zOd)={gBS{qRi!Ei4O7C4)g=u_^lj$0&}QgZHNm8dZLUJ4lZAxseBn}abd{9ywIfix z1N5CL@i_Q?6waa9s*giSBjt_(cxYK(t5}L}Gyakl@X#xoN z=75h&m}u+e3ouY30(jib85NmhQrg=&-w3bkCSZgo-t1>GC$~U1r|_=;81aA{c_4!f zm4^_32>DKQ?}-r1BLrf#Y_u9m`dr6j(cV-+cRDDtclm%)6C|DU2@t8o$pHWD*+6@r z^V1Qi)F15&XZ1Kh=djy7dq~1+0uagb{LEFnO%70DTnA-g1ZE6DVfQlxLi}Y?P|W0< z`Z=8h40G?Zj_)YhI0n?*_q&HSqHOq_SNa`SA?z{k!*22T2K5cy79>-z^q^(-JDR>Fc|p|$!HGPz;^^k;{T`7mUiC*evb15O3j!{K z4ho5%EUG;zZihPu^GWrJgD=`cQ{u?%h0nm;-ICyrD=o6Hi?DB0Ui45`c8MG3P6DgHOah?d#$$VoqQmgqzYDG=Xh3rXN)H~n z`k`B;DVJ=zP&Lj^yvr4QqFUGqeM5)@hy8VlkO`gRF7VIFL+FtcCusWSdD4Adzn-C0 zyB*2SJ7>2Y{82b7**f*A)3#6KSXz(o-dSF@g=HY5_weIkM>xO1e!x7sa^uN#F!?;p zqR!lOMwu@Ws3sI{0Jk8-XVd|XkC%>^JyNX{m_i>_hT9v!VN=uAwOH(W^YW+Vj z<1sqLog;Oq=bm$hLRR_$$vuui{r-)g*tVC$T2JUPyhumx5Exjxb^>_FEbOtQA z)faDrWvPyix2#Nc^G$YAo!X^6v7403{>QbzxoNS+8&*P^Q(fXrw9PrGEnw_ESs2jU;sw(5b546py+6o_A zc1t7rLMOcBTpFT_;6Kr-KQ)0FNxspy+^vK32r>N_6N$sV{YDLKn@$MUlL48{iYOZ{ z3ivYCTO_Jj{gS!i+vST&EtIPeJ36w$yL9r1Cx1&+-=+RRS+%Eb>KVs?q&C$b9kx(B zy0iKr3A7f4!~NI3n;QpYu#I!Gma+CK??y~i-_jZ8&ehwPG&fV@q$m6}d-#rNiHQ10 z5B3BxkhUcCT?&S`cOw%y`{PIQ9LjC!(mu};-PCg-ryr|nzK_v3u(0t@h%ubNZYO0q z&q}G_#hPlX%ibls7~`q?Xx^POt97c4h&QB0Kj{eGjals6{m|!H@YAw`n$X_^Xh`fm z=sV36)JPmnGlj}S6gQ<%S$QpP0y76YMoTLcKtxbJV&zIZ^vk?WC5x;BY^E?U2&mCP zU*EbW>v|nsFoJ&RkFWgb5UNePS`)vYQvdssl`t2UuMIdR!vuen`_c|gV%L(pY zt+*`uUzCiwU^%|8u=!S1dUVelrsS7RCZu8Vk043oIe_U965~NE)!{P;2SKIE-Zu|!x8*@C5V2T%*jU6;I8!atk;~b2EXe+1ec$;wtLv3FWZ7d&QDL`#OpkfjIA5qnAqX z1>mNAl}l!VmCGp{ta_)`PIcx`t_`cyimdMziR-p${#rtJp2Xwy1M*a=xX6RFJy1L^ zaOX$$$fiZ&Z!yBoiBqSLk_Io$AA4UEd1}O^S8q1k4`eFNC$P*JyR1TBP=7oq%dJDe zb#z(~A3>T|gs1Lfvy!rJ&wqpO-ctS<4afGCe50kEExk$r*S((->jS*NhUhDq87uOo z;lfOR39ft5Zw992)d=E$Boz@gNmf-dYmIA@AyIz!?x%1^_)2z8kBnmA({DXc*yx&a zK|Gr!Uma?M1kXsKG;X|_IltUK1hDfgSBHf}`(HlBJS`1~^UIFtR8N`D15i!bX!y|gW;uvZeI;K;jdO)( zczFy@Rvgp$$t!t2tQ%bAab*GBIh64x+mi$)zd$vmNX<(zm0Sxzd!9F+p9F>e$~Tv< zM0Q7&W@_Jl@o|<#Si_6ww?;mUR{;$dd~s|Tf3MZ4n(PCckOy0telR>6-+BARo~|}x z&U`v8@_}^V&{L)=a5o&2Get5!x0Lo>$sa$V(+uj^FgrK!SFPGZpr!4@fK{UIVDqNk zP3Y#aiLkB7jMVD5-XIcm$rr#mPq}7+x5B$vz0PX;sS=K00mi^^g?-=m=zCB~4rM|| z|0_NI&4km}b;3Ur7Q_q5Rqsn_Ybj%vn-0WyclK$tw8p@+Bk4#|_N4;?9@(cyId605K!ywqsa(~D@IGffBjnLDAhsd<%(#w5FR z=MY}*F+_WBj~w^JDAX%sDls*O-KHeXwGu%r{j-TJbdODNU{4*<5r-{zgLkJv1kgRI z_#~TMiKhlo#8Rl-!4PwU{(oUIzQa=kDdPRVktjH?MsfZrfw@kc)`b2xy%9FN(h)f% zI2ne`9}OAV4?Cucyy`D`($~7OQ{5}&IiCgM+8?&$R#m~PI^&?7$EB5g5cTrS@;Fy` zjK?sV3sr_C)u;MF8u%Yh#^yNhX_|#poc$vds0WGxHhZ;}R)?#H{;E}Rwhk#?SVd=( zvca!ZMY09-;=AMHlsRVa8i9EU>k#}&k6b?IG!#e-oC7)%z@Z-7$O@=~mR|9D#y3zL zfb!48ng=k(sXQ2$?Y6PX2@!AFV%EnbhP^VVA-PKq!FRa!#>jPxPF})O{|btBV-mwq^#ORnqt$&F)c zL?>@%de4{#%Bi|-U<=dP+52S;3TK~y-Eiu~_N7<_F52Q$8JW-h(NlW?poxIudeBJG z-{*7RA{2YuW2sM-|ECZ6j+uEzy>0VIiC@^$R1h$j7$leb9oHXRt18HtmHZ#^oFYj8m;^ht- z06rpz=28x6v&uBU(3tdJ42@8&v>IQGJz?gjm>O%IrlNwO!fFfY6qKKQ^Po)jT?QJN ze>jfAG{20HVs8C}c_p+LIq5#RxL04F`hs)DEJ5LzeXW#TI2)o+NN1DlHgT9ar*S?& zg#MKW%Q^9cu^r-^f){@YfUD4zLwF=Bfdo0-RP!iUwTa)td~l!N&tlRxEkZxfR^GcO zon2Y`tp(c~A9vANF>{4y3GHQg>6`7S+%EvV=P2w^pLD3*vg~H=2g;aDXW(b_UyN?E zmsDWd#y~~@?I*A_i+HNupW~Qeuu>vxD_8_x&;rInYiNx3{#^ky&9#!#jy9Eaw?@5j zx={#xlSfkj#$pl$umVt0H?7(x&zf^-qRWPHXPaqNMlSaRH*eO!jd3$9T->c@5K{5e z#jQ^;J59vr|Ev|bN7Gli4}Or^{*0j?gEtM1E36I8b`C)BJ4`i)}vpX0j`rgs{jHan(LRkaeCphF0J>ujjfIP!i;vQ#Hdd`+l1yzguwZbjpd*c3Zxm5 zq1^8`!VX5*E2P|ltal&u4RwNC8gMM0CD~UkAVd1lwjF-rI|doy5*SB^8&4%eq;P=v z{XMGdZ%>gQlUU}~{)dWGidYX1N)-Y^!JZzzcK`0f2VvXW>!O3WR}lO0HaRFb-(;i# z8>2`4#)1?Awc-~HoKbMe35HzQhZIuMy>2POV-w$J{JY+V4}8Y60U3k9*x+otyi7l{v8a=6|x|NenKa#&2&tLV^v+5-81vD^Z&=osH*XY z52CGifLX|&2~Ug(*tJu5E^EmrK;)!#Z`^KGB_QuhXk+X|7|rNccy?nKZVC==JOdUM z6_H}9kOOOjavz>HLgB9U0PYZAM-FC5F-o?Jomk24^qxW z3VlR&ILdc#a+rR!NGdp%8Fm#r3AXH~x&b6>v{rpuC|qfs+Ah1P;geHAPAU83W39Tb zM9n#?6gk#OCt2H|l3qDTf>fZ=8DgJt1Us>Z?_lXih9G;#YkZr~wMP$s>xW5l+ly5O zJ*mK;7UvMuvYYq$d8Sb?eJI%m+g2+~ZOslMz-f+VQrIpS2!k=mzD^u{YX0cgqmM%$ zKekj2qXr+1G&LO^)|uI29zPEFA5W8+hJ8N}DPwFAV}^!F640VBwG(>0=J_u2H&oQ- zuZMDX!?=x$(c&vg{jwjyuy|j`y}1Yl%y4eRm`IVYGN*n+_{?j&fDN+5BD^22uR~=K zV?G!`Fw%1s7oPA>EHW{C0#WF~{?;Sl#8XyS@m(k5s_UKW>@rML$(0 zG`A4X*c+!0brGfY1;2r$kY+>S61L`&?L7wo0#_~w7K^Xp33pn2)QTQ5ClPu>R&!x@ zL_L9;6sAW`j!)m)Ax{NB1%bfZ8sC|n*Qdz!{hOS}jd82IpB>wxmje-_Y)63D_6*Z% zZU=IbT-iWExg)7e6^oqez}pmH==M&a=X9 z?s<#8!nA(8Qoq67w@SYys#n~9KU=#ZNe+~b^*v}GL|A|j7a%ScTl6GoW3LL#(aA?> zkAV5Jm?HihpAP-3ENtr(T=b+5WbBj;#TsbO_Re`7gzd1!CA0hrdv*khZ-$3mwqru+ zf8sLKiG>ryAfh{9DYyMqZuJ~5jkt_(U*UiC3_F?C>NeN~*W(&jQ3ld*ZlwNS_JKsk zHEpud_6fAbM0!gZ3}NumnwrJpd1D9RgZ;-a`vZiANVRGq=y+!b--VcYCUr%J|v ztsi{gj3^-D`BsoXej22xz4PCd+XEQ4V{X`-nuDIRn|=gzCNQ&yV6 z&j6hQQ6;MlM6(~+K%fQ?pQ<-|?kkxO^trvx^=`hpqrhx9_5Eug>8W;5(c3eL&)8};V9q|qw8*S^7gB)#7?I(W)Fq@L>O@Fzu^f(RdZ!Hu#&ED5${sktmTdXZh@z7q zw(5V07-`_qs#%1_1@8R3l=h(cLW0m-4?`4D9HRczjy?hR6>+rj+oPcIS@u+WC z*dfj89)I#eW?s?}B}mmCKp+b~7qaK4fI?>wSgzo@UsaC|L^q(&f;2m9ekYA2C2k(D za;S+=rWKFOiI`?wqMJ@7!s$1~Ues~N^>3}L{Qv`jW}hsfWWi-Xw=4e#j@M7~E=q^% z2WA?i3=_kRiXI$fKeCQv#J6A5Vyr^yb>@>K(Ohp7sF?;J8=zlLd8^7|B)-N5wGJMc);rUiU6rX;2jX?YK z0pA=b{)Rx%D#Gi)PG$K`shAx_XN*m3?;&ooQf6LL3`~HnkT1hXPkX>cvwy?2b52_e zBvlr4ANSM%L7>~7OAc~v8gQKNRM-|)CHadd7DUQ%i;D%&%>n+4UN!15Yz41=pjZ&c zMaHG*LPN0$IwXeLg4mFEaPf{j#2-8f^}jsHavzXgxS<#r`tl6}n<_ z9kkndaoA8*$p9_hhEBr+kLzYvcI@{?3@Lit2JjosiyUe{pob2-4+awOmdWJ;D4;?X ziD!fv;1N)G^Z|^s?JAI4R2U%d{2hf+<2E=Rva5t;pg!g`+e4eN5O4C>45Z(heHl7} zZS8}zx8R!C(TN!npoMBrj0g()U==n!foVV=sER)TS*8@T#c!gZ_nuMEY?o5?ayJvP zlz-zrd-!h`JS_eb?2QRf5t=bCEIvw1)192D|Z$p7jm4===_6HNFj=&y;_U=Cn z*VR8Tt-?kgzZksr4eiZ7)%Jm1!^eJw5!WHLG~s8Z=qc0i7M#|AusoK6Y}sm1uW_Hw zIR*#2h}P{&T4QRY_Ua-|U#(p5fQq&QjxHZ?msix=(^p)Rg($hNNg{M);HMLEx;t!ZZVAtv1z~skS*DVsL_tj_bd6vRB_AQzC5a|-l2ZWB4^@6>2dS#` z>R~0RA``k+h_!ssye+tV;&;+w(koW1A}Zm81;z|3EV@|lS+U8@Pel5J>Sehj*gP0~ zFcbZhqT$mS2<_-*CioR?SMoVn1)4Y%QJ6V0AK39TI2J!nf?5*ZaCOT1WS7x1iEy-@ z(dlDw?dII7aq!gcmETq70EEgFwEa(v!+IBpXmS;WAUgp}cTr3Gd2iXp97!Eg@)N zlS9$s>lYhjfbPm#waO~|t0#10TooI3DTDR$e4!xrccKQiiPr+p17?9&?2T^(4kcse zx(^~$;Gj~l{{1IH&yo-9&Ty}~PJBJmm$bYD-wpTL+xcO)6v_7hMnw^S1wpJ#JV7h( z`mioS5hPlkZzOHBQ$lb}|K$9)X~`uW)_V=PN<~)ZjASisei#`<{`aFRYbavZYg)Cs z=WDT(*qy~!rWXfqljnj2>RT7*P#^cA-wF~{);ylPnRSQI^BM5!L&9LC*gPoT7Wa+@ zv7TG>vVjQ&+3o@2)i(6~4u7Z*fWp<2Em;l@QCjBLWDZEg)j5`P!?Q+y1Y4tRok3Q8 z`7L^WY+|c?c=+=yz-hP z<Pyt1k^S=P))Kn5&oB%*c-_XwU$%7msd5ou6>Ap=o(i1f7%LL&a zo)b59=H&%5ozMFO!O&dSURA#weyjLbd*982vPx`koYHK!`9hS2kB&>72*3X=0DROc z{p6aC(t$1VXe^YQM)v(zGQw5ZSy=bcbt5|qY_uFE?P$2?u8ADx%K5lTtg`R8E9;sK z)%*cSUWYM1p&RTG3vgbqm?t8}w81Fft8u%5Jzc9_GU497bI_LC5AY7p zshTuvVJ+aZc2Cp1Tx>`0RT1bd z#E5qp!9%jMz`Tyf*3V)1z;JR^f49D0ugFY8nhp9FMYKL#+Rd6e|JSkvC@suZX&fuy zJ6BO=QvXx1xcV}j<_UF{e{G(>^`Z~$J&Ovs(R9dDf#uZ;>zzQ5&A6fL>a=q|3MJ0!@F4{R{A01MZPeh#ZOmbnjF;I`|}kpOsTE}Rt~0^zEi zSYPk&C;rOcx%68+^@qm_MvA87Fvy5Gu>Z3=T62A2mHwX%oHsCpg=W9sJsQUL+gM}= zZGkH`aE#Vy+&Df@6bWv)_8M?9nwDT3yYz(VZiA~+8_{KMl|$iPHxvaf*{-EBqX=RS zlq_npZ*P@%LH6Y^MWZlYXR{h6 zC9)jjHP^8fjJ10N=5JWv56XrEci^c!EiD^Y3Nc6Jz}xHLzMLF)2I>O%n)qjQ*ad7T|aB%Lt!@UEf zyu?*#2mZiORnnBc``{6qpyu)ErL?a9-TRL;leV!@dXGtH?%c<}dmo>GghoKd>dCX$ z2a$R|S|`GxMK5XI5R=ohaJ|DGojrI+NJhn;QP!tv{V9Z$~p?)9y`-Tgx$2~D6n&ri_LF}Wn9&*hY~^Q-z^yrffBGjR2bE3O-?s%>uT zKn8t@F)_0vqj<%^Cq>UHY+~*AR#wlr7;Zcdo+O{_Kjt(x~4D4d)wJpydn$|8s8CeCW zp|R@g8pR&GgtQF)H3%-5WT;@;z!_^&duO4P5JK1L!0Sy(L* zd(vE-?=2xI`R((6(6&;7HTDWm8AQjY<|hNx;l@%P3PK;m_!d8Fey^&ZS-N9^s}cMyM5;v4=xB&L-AG+=1@ z@-$Jqns}<$em?h8ji~lKeHR)S;m2Va^cm@&v>b(ia=U(atc-qlCjkky$td9vD@zL% zp`uGEk{m)XMSS!h%JH7;^o+vH`L25w5{h4A2E@;|5Y+HSf6MjK++Lu8o2Dj%r_(XN=Nm)<8qXJh542vP zImOAY9T6Z;?CS6m`q?>_$;!{h=3+S(2j~5RHx*uxg_d*y)Z7)Oy!G?~TOPRgyS(+{ z0?T>aT(P^F%2S)-sA6vf8ez^|2cr!GadB`s#UoS57I1}IcW1LhTQ3eCh@br;4BYFV zXuUvl9&a~#V~r&Lyr0fuC1mzIvFGVZsq1r2^YFayNCcN< zL)_)$*6iNy0VR^$L;ZMET7_`azxA>NA8GaBcsG!Slk*_FRwpkft^#IxNGjZ4@4P6n z_{#}m=~vq-j$@2-2Hj70nisk5Z0U8nJoweM+j_kZyaF#5Cl+Qe{+0@e&(-eEw%0=j zjwp_t8f)eyF{@1d2d;fneuj0qd5?ZAk@JhRJXq{sKpXH1zIl^5M)2s-UlI2qNnYgg zlyjj<4Z==!+QspB%Uqf)s7KeQ-T z{Q<@GRprFPj#E?35BpQZT=Z*Rvmpr>b=04~!=qGuX4}v_Q5)Z&AICY5lev;L^#(N> zoTnEGVS4_uBg2P%y7D#_WM*d@^}`(B{5$`SB4rwnXXZ0uD6&4?osc>f60;3Ey+s!; zB}&)r>40TzW4&(qL>if7B<}w0atex((5Hy#q%N3N$x6=R3g6*)Qet7bkwySf#}XNl zU;kGUooDOn;N`1ItK%1``)OaZ#L{~eVjh?<%?}V5*J)=>eNPi(1Zz6EKKf$U<^*m zlxPtpP0q2^`YPwG|B<=ZNsnM4>8QS;iyuoU*K$u?SX^NOMiqQsWtNi^gBwy(0?RGD zls#L2X_ieuNfp6od(aEHg?)-B(mI^(e4Wj(B&lqsR7K6&AG?2nwHBNLx-6eFEQ+5#hy zJqmdjsb}_fA3oT@(xji4!LE2^`yC^XDjyJ1iTPb$4u~~gU11RLMwgxF7Xprf z&O5WIkCA$YOaY{%;?khyj*!C>FRmRo_>UB1$}|GH#A3-Sb)VvgZo7QoVUpmJ-}$_3 zhGL$NoGj@j1oaG`nQdIYW1CfN`+By=*XbIaUD;?WWlR@NuNUP2DD)2>ZJSxbB+KkUP z2%!iv;uM^8j^k3Ey_d&t=zJ+_7BSg&2xF6c!x+HO zwfPgXyh379=G~$T1AEd|1QS=i>XZ+3GVNPbMdcUc&V-JO!?7ctJTh_T8iE?a53xtl zt?t;>R&}AvKcDJE=s1Y|FaBIYdog#dl7a1&348E3B5w)}NJvF@uyx2tw{Te>35>MNs}c{MJASa~N&L~z)OGRADH#O^M? zR@TJkp+-Ghx3h?Cu~T9R?75It?F|0fD`C0~LZhlL6*A8U7|>+8vMP-mFtvNos-K0h zT+7BeM?{(V^DZ};LF_m%A6|jQUTPuzN)B;~B>f$F2EHG%GVPNdEIFb@4CpNlu_3O> z6h9`X@J)5fDXroUOqAnjba!;7ko$HA<9r%KD9Fi^Z!ts~eUNGlMnSp8G>3I41u6e>}Zg^gA9$1gN zS=hiz@BYZXT@?E1IfCs2y~aURA`u6gmwcsohphnl20FXhuo7nxW@3qe5%29ToC_>e}sg`kWc5d1-kEvLB8+Gx|%;hkvr~8YY9x>0)DG= zL#VKZcl|VJiQ!oe{E_1= zZWgbhcb`O<={zA=t}cn^M8BAp@$745mK1}cUDUhfz=OSaqP^i}C6nG<@64F+h{LEZ zK1+g)CmUST)(n#~xA4&RN%-~K2Y(e5&7xa|N?~wIZ%P*nIZAQCSDje~g5Q$I3Xse9 z1bR7Hx^rPsP$)0r@0Go1=b+!wmfmObaY```@d;MKNj(#$eDWcxvV>#J0b2CL2VN=U zB`K!c0%56Fie~-v0y<*G2Q0Y93Br4{S$(dO+lt?=|N7$3qNLhp)74cg$6TYx5M;SC zng`hXRIN1u&KfE64X(*T1IUSLb*23y9;u!QsSZUR_tGi7&cw~6vP$QPWUEQ~QY?ik7-UTn1tN-0&o^ZYM{80mKFn?pwhZ1}4b38Pg z7SFiUGJ2hKap`3|bfk@ZbHtJ-Pt54|R(>V9B5}2vQ&)&9H09n4*9nvFB64QG)WB%o z2*}C%&&O6xUpL8B|~{8p3rP5XMJ&1m3tosxyybA zH9E4bcl32_tvfmX>grRns*PfP`Tc#PGj=E&Dw~qB+9zvi6-sRwXtH`Xyv=j`WoJ$d zvf3G)n>#ZwI@I9WK<5eox!Oz^{eACXm+?%)m&nIRQEyl&Ds zEGDFfAuTUHKgHH}sgX?rl)jchr@gx-V&oZe^qr~8R#ujIu5JA+KvK(m@2b#r`3!&j zX&2>a7ffVF6O~!`Qe!uSx!ghij2R7)*Xmz-TpsbriGNM+Xf$O0PbCL>REcsS$c-N% zN?w1xm2^@PcOrdvTcG{B-0vP@jh!Br+=YTfvLN5$y!Ma$Rti+?PMYA@F+-&HpsM

4Z!zbUH3@uXd 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 diff --git a/docs/images/platforms/kubernetes/starter-template.png b/docs/images/platforms/kubernetes/starter-template.png deleted file mode 100644 index ff81645d73f73a4a4b04603815cda7da3e71520c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45113 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 diff --git a/docs/images/platforms/kubernetes/template-variables.png b/docs/images/platforms/kubernetes/template-variables.png deleted file mode 100644 index 2d0a9993e4385a57539d5c3895f38ed077328dfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29692 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ⅈ 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%0A>(GCb&&e*AHDdf9M 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 z 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