From a61513464fac7b0cce9280c83622262a49f60720 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Wed, 3 Jul 2024 14:48:17 -0700 Subject: [PATCH 01/14] bulk application upgrade testcase --- requirements.txt | 2 + tests/__pycache__/tests.cpython-312.pyc | Bin 0 -> 21807 bytes tests/application-upgrade/provider.conf | 1 + .../resource-composition-0.0.1.tgz | Bin 0 -> 1424 bytes .../resource-composition-0.0.2.tgz | Bin 0 -> 1809 bytes .../resource-composition-localchart.yaml | 43 ++++ tests/application-upgrade/tenant1.yaml | 6 + tests/tests.py | 222 +++++++++++++++--- 8 files changed, 247 insertions(+), 27 deletions(-) create mode 100644 tests/__pycache__/tests.cpython-312.pyc create mode 100644 tests/application-upgrade/provider.conf create mode 100644 tests/application-upgrade/resource-composition-0.0.1.tgz create mode 100644 tests/application-upgrade/resource-composition-0.0.2.tgz create mode 100644 tests/application-upgrade/resource-composition-localchart.yaml create mode 100644 tests/application-upgrade/tenant1.yaml diff --git a/requirements.txt b/requirements.txt index c3726e8b..4554d9c0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ pyyaml +kubernetes +bs4 \ No newline at end of file diff --git a/tests/__pycache__/tests.cpython-312.pyc b/tests/__pycache__/tests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d28d109f8c17eb9bb4476182e629d5aba1e2647c GIT binary patch literal 21807 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%0A1qok#X?!Yv+gvO4Oo}Zd#TUh)EyyNSX7S zK;DBwy6u`LI>?ToS*AvjVGH~@%!+8KM5FA$^B3>|jt@DmLbxcO$8-bcN0*;!UPo9Q zkJgXu&KhpE#%bU)84YbjTqYZeBgRPnH}Ard3xIm#*%l>Bg^BF(*EPc6T`)k zH%lkpgq^r>dhQ~qoZgm#?}@jo+#Yy%Y3@=%_+SVgw(ctE=Jr1f&4uP$4@?gLLNa^f zrxS&%kBvVMBWJM9*$M+s{ri_)P|LC#4#v#dp13;8J9kgp%I?PJZIpK>w)YnYmv_Qu zJbi8Ua?!P~$n2A04FtoK3l|buOh1PRSxkCZL~!5{U6%wvh&W|_FCpjwgUag@N-*T%7G(i(a9`O!Hnf|x9@><#yZ>g2ad9T z2M~f~nttw}fRf<#U)YwNl)D9(L4AaZOl3cWzpcKkaLPenMM`y0V^KW{2R0w@ci1Gi zN_ddl1Vmf+FpzdC6OptUPg1i;c4@8(Yu$QovP6)> zP;r-1zV-{~I#Ydc33ll%w_}r%9ji)qZoOm}-EXajBE!0n18JlE?e(!v*@m2DlXz z2C6YXwYS835$#Rm=}`8tGFgep4K5M*fpY5bs(k2BA->AMoXEf#KO%hrW{)B>4=YYS z6}Z~R5_y}9bXa8$`3gLcEHX{N=|0H_=fnGW!tD4=hxCV2G{epECZ|nXB*4* zSaB>}w5PuUm6z9{8aS{93t6|;N+Gj`S$@v4z!2ZaO)6CLE_p+FMjIXfQ|7=1a>t+j zi;_Fmkt9@k1MPM-k_2c?C_}L1WQxYy$Vr;*$UGL%W34$oYXe=ju7m*gf0JTqBxh1U zmH@ei5luu?uRhVETG+ueE+v{lX9chlbXJFGA#HVHxOIt)$QR&`m{G0yakO2px-<{L zoL#iDF5D?tHwlSu%X%=LbBGS10eV>P{7jX1-PHAU@>Fr{sf3Zr;I2fjxL=8BzpPiA z5%8wm&U`d(E4L-*WSe02^f{O46fTM`wwcVz0L1)cv|XD>BdYwXj5bS)RqmAqJ{Vj4#0L`D~lQb*imR6~@k^ z>tc4tY0a%YFq~q^Nf5%h;2cOOTcfRkd=tp}0zo`d4@YP+eSu&qfCt?Jd=ko%tbk<8 zSb`u~6hn$I!rz8O{!cMLJ(d3%1_B1ialqMs3k(in0Lh4TNi@Rz@<9Q90!zVp>2_<( zZ#9}vaESAm6Tt`>g_y+{60-c|3IJd^&MDlgxbDpM{Zp~^~-D7eEpGHYG}@ztF``?S*~#7XYq}JBiFG{ zgp%tFI4aDTtMq?V`&;q-KZ;N9n}vVEe6t?a$zb5hMRK;P#^(;#0>J^w5CI$jNI|~p zed$T_tAlR@&`M75YtiAF(Dsr|O3}EYzN!>}aB53IeIB)R@Qb5~rwY^oT+YZ6ZdBo) za-7CDSu2L33<#M)GbX$>$G{$DALNfiTGn|PteyC^s{kJA>F4|LAw3L7d-{p=E9vio zcS^;Wm~G$a93BBIv&KO1HtbQ#wpXzyf`6G1=r(BQk%;G3w?*DFPD7>q83-gsk=-RD zIDxT}9>iy2uqWq^@a$h$u|9)@J;n;-qoc8VWWNy*yj6Dzd3*4X?E%|D-UsXLDkO7F zdJ&iZeJBaOrc`tA2MkX|=gz{8k~6fx^ggRO282ebo3qBr4xDX%Yg zz-k*Rbqp1mov>cu9M2_iu<><28YuaCAMY;tjy}Fq@|`HY@G zs~sw>UY0*%1L{zQ0}CU1>}^21{};OP>%*`%=Ew@}4*I>eLR5+ek8<$5lCLi)ghrwP5R)3MIQQlB0ADmKUklkx#kjgi%KvaP>}2CsoHsjQvP z(odP4WcM2E_DM{bxRHdzk~JJ2OR?h#4&wGOeDWfaKvxd9vypGljB%M;DOMh7g0+x= zKY}9-2cRha7zP(Hcpn3lM~PX1|8tD}6$BCkU+&A`41gmQ99-xBJ*NBz2tK4pgJgpi z5q2>^;a5O^)OV>R+WlN_rTt$TD3fOyW6OSsJ=dG)#>z8@fvsrGvlng)J*0clA9uPN(~fa(zZwKcj4)Q63VpkhtwDW5TT4HT~U1?;bGPeMRBj^6$7PqdlK}VrVHF XJ@+rX_uB8h_HTxk4V1B!)b{@XDc zVQyr3R8em|NM&qo0PI*xbK<%Z&f34CD|a!Ig^8SyP~}+>!kwgU9$X-qI;$yRcZe#o zrIBQEn8$xVB^w(X49w&;XR7E$AT4#PC3S!Lni173c*GHva=&v=m1#_A#CKj)2qEOS z*-SqPA&Z~HYaQ))&7)?Ev`Fii>=5s;d3?MB&hOs*R(8tuKcPH9{qg{?ss0a|WU>BR-qE)H-$MQar+7ybZXmt=w2*Dx zYDoiZIN`{501}NVD`xxGJ2-RzB-Q#+sL(IIW%_%ejStaOf8h>5IQpC!S{FJTIRHus zGdDIuDChF8!T&El54!!^^G^5kRr|7=d)Pw6D@(cl4MvhvgL*&Jx{o+=sg!Prl8b4C z@e|3xhWbA|Y__WPf8ZT>t!@3kg_PfaDy80^c+LZhLmy6yTX!NfG^B=FEXc~ani>uO zrz7OrP5|p?X@-^<*inU&vw&(JJO@A{$G`}c*+tX@_ZKBcRaXu`o}sh(rLe5F!$!{qfxfX5RKw*fnVU+8o zeP!~1Q@?=u6;butgTbfk{^@UsEPpRnM0VO9wolrF?&in>5#O=#C6yb3v-8#kwC0%3 zt_Q=n3&cLRgmY_(6JWHO0Q}vhta8itz0lG;T8{ z8IBsc9=^lqxQTH9-{DIl48o5e6&6u7%k{NpD|gVz54C<1m9w0UW^|>xxYecM)op0T zXzJpii4i)WoWT4X}rbiEw~{h(o(MvW95R$Yi>nf7Cd3s_%X^jx|KF ze|^SKK6qAbweO;OIe?HDzC#*H?mWOS|ln!U3SA+#Ef28RVF^{dW1x~CB4Eg z3F@DjyNP`s9+G2caTnE8p9r2rcqx*&>Zvr>l@_kF!PvOk2t~(OavE9F9yRwq>`$oL z=WMiJU83rY#mvkOl8smR2}SUL%Ej2IsT3?WGpj~^(OJ|>edNY)=R>!thYqK#k_mxT zT$PxB1dn{eCich1`V z_XlKe??XEE{A$qc58?c3cwL^k2e<8uo9+PKzk5jd16475xA);`-C7x^{#6ayue6wX z*Q=)l!+En*Lf&$_G*j0!UMm-|n3QOP>b&Q} em56cMS#4!2TiME=DgOij0RR7cxh&QIBme;1?ZgcL literal 0 HcmV?d00001 diff --git a/tests/application-upgrade/resource-composition-0.0.2.tgz b/tests/application-upgrade/resource-composition-0.0.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..7cc2fbcb3f59522a89a9413b85b3235c2ed53d30 GIT binary patch literal 1809 zcmV+s2k!VEiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI>{Z`(K$&$B+o!28e!s2s^oVn9V7+|;-2UE=s`H^t#_C@5)S zb3>5|Njc};?sq>>|18vZU?$rgA(A4nX-dt?y=CTZYSNYJP>UI z5~d-2`e`AXx>Yd=ux*9DX8|M%Wme4QU$@h>0AixlgOH(De#*w@LTL}8rMhPpKjij@l3C+a!+d5Mw5m z5%NcpgFW@%?Vk4P_1|$ju6wBe=aB0CPvTgeEL`i3no@gLK6NWXO+uoHDaEXu>#1P@ zFybRqMgfeU4Gk4zU}h!8j0Qw`;939*83tO&%q}82m|s>L)m>QtMTX}3m9UJkn(2ly zKoNwIKyXbcM_C%!P$4XK)y@cw$P7I&=t5Xbq+*2E>%_|lQ_WzMFg6m521^h6?13y* zIgfm?3bj}}L&A@f!ML1)44MBXMdVcm&EW+S^*?Yq#@qT#@svW}HfU=H5<}#g5~eox zmB}40y%OfPL^bM9CZDdy@BV_wiu+&f)_0x{QZIUWnCRW+%~Bp(T>Jveh5$FgnPT4ViL!B5hs)==!b9#)~bq6mNd0qvWN zNrryA7>6(5pPwQR;0xR*LL>b7XN^VF&5H3xv#mS0C=RuG6ScFf`R}*{&NDMW`D&nJkkojc z5;;R%rc)EPr-`$U@2ia4z;&Ivycm7_s41hr6VnHdPzK0#iie$@2_+Xaz#Usvi=fN9gO=+!QL8d8 z@jgNIHM;xQXSeH|TkE^1r}{#$B*H6^@Vcjpt{oe=QX09ol@^lBu;Mf_rX!-~9-J(Q zJYm#7sV`A?Mmg2_LDJb4KcNWjP}<0~T*iWOom;hw2c1Q|(MRqLcQtjBdbnVO)-oY5 z1H-Dbg`JKyuGGAjGMBvOvtKjYO6EpQ!EU=4s)2s{4MBncmAVpPai%tmk%XTl)p*SV zv^J7@JxTME_Q3s>KCWG8I-5cxfBXi!;ftLvc`+XJrvsSw-(C)??mmk|5~Wdo7Fh;TB)(Ds)Z>J<)hY^>ioO%5nmn(zSY=ELmb+GAV(>cE(0KXU1pzjG+e=E$P9 znxCYE@fXS0gJ^vvb0^&}ko-Z~qsV&Zz>b;9*WQgm_CiD$r)IATB@@5SR;b z*M?72&qbm$1x7i(0zJpv)o;Q#o&v!Y4N+nUF_9X?t num_users_first) + def _check_pod_status(self, cmd, num_of_pods): all_running = False @@ -159,7 +329,6 @@ def _check_pod_status(self, cmd, num_of_pods): return pods, count, all_running - def _check_crd_installed(self, crd): installed = False cmd = "kubectl get crds" @@ -198,13 +367,14 @@ def test_force_delete_application(self): cmd = "kubectl delete -f tenant1.yaml --kubeconfig=../kubeplus-saas-provider.json" out, err = TestKubePlus.run_command(cmd) - #print("Out:" + out) - #print("Err:" + err) + # print("Out:" + out) + # print("Err:" + err) self.assertTrue("Custom Resource instance cannot be deleted. It is not ready yet." in err) cmd = "kubectl delete -f wordpress-service-composition-chart-nopodpolicies.yaml --kubeconfig=../kubeplus-saas-provider.json" out, err = TestKubePlus.run_command(cmd) - self.assertTrue("ResourceComposition instance cannot be deleted. It has an application instance starting up." in err) + self.assertTrue( + "ResourceComposition instance cannot be deleted. It has an application instance starting up." in err) cmd = "kubectl label WordpressService tenant1 delete=true" TestKubePlus.run_command(cmd) @@ -220,7 +390,6 @@ def test_force_delete_application(self): clean_up = "kubectl delete ns tenant1" TestKubePlus.run_command(clean_up) - def test_res_comp_with_no_podpolicies(self): if not TestKubePlus._is_kubeplus_running(): print("KubePlus is not running. Deploy KubePlus and then run tests") @@ -249,22 +418,22 @@ def test_res_comp_with_no_podpolicies(self): if count < target_pod_count: print("Application Pod not started..") else: - #print(pods) + # print(pods) # Check container configs for pod in pods: cmd = "kubectl get pod " + pod + " -n tenant1 -o json " out, err = TestKubePlus.run_command(cmd) json_obj = json.loads(out) - #print(json_obj) - #print(json_obj['spec']['containers'][0]) + # print(json_obj) + # print(json_obj['spec']['containers'][0]) resources = json_obj['spec']['containers'][0]['resources'] if not resources: self.assertTrue(True) else: self.assertTrue(False) - #clean up - #wait and then clean up + # clean up + # wait and then clean up time.sleep(30) cmd = "kubectl delete -f tenant1.yaml --kubeconfig=../kubeplus-saas-provider.json" TestKubePlus.run_command(cmd) @@ -300,7 +469,7 @@ def test_kubeplus_cli(self): kind = "wp" ns = "default" kubeplus_saas_provider = kubeplus_home + "/kubeplus-saas-provider.json" - cmdsuffix = kind + " " + instance + " " + ns + " -k " + kubeplus_saas_provider + cmdsuffix = kind + " " + instance + " " + ns + " -k " + kubeplus_saas_provider cmd = "kubectl connections " + cmdsuffix @unittest.skip("Skipping Kyverno integration test") @@ -318,8 +487,8 @@ def test_kyverno_policies(self): cmd = "kubectl create -f resource-quota/wordpress-service-composition.yaml --kubeconfig=../kubeplus-saas-provider.json" out, err = TestKubePlus.run_command(cmd) - #print("Out:" + out) - #print("Err:" + err) + # print("Out:" + out) + # print("Err:" + err) for line in err.split("\n"): if 'block-stale-images' in line.strip(): @@ -332,4 +501,3 @@ def test_kyverno_policies(self): if __name__ == '__main__': unittest.main() - From 257303181a5496f1b5b37dae1ffcaaa89c46f957 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Wed, 3 Jul 2024 15:02:29 -0700 Subject: [PATCH 02/14] added automatic provider copy for testcase --- tests/application-upgrade/provider.conf | 1 - tests/tests.py | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 tests/application-upgrade/provider.conf diff --git a/tests/application-upgrade/provider.conf b/tests/application-upgrade/provider.conf deleted file mode 100644 index be155b5a..00000000 --- a/tests/application-upgrade/provider.conf +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion": "v1", "kind": "Config", "users": [{"name": "kubeplus-saas-provider", "user": {"token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkhJMEplMXc4RzFvaVVDa0I4RTZ5ZlE2QkdWcHpDeUFzejR4XzdscWxJZU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Imt1YmVwbHVzLXNhYXMtcHJvdmlkZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3ViZXBsdXMtc2Fhcy1wcm92aWRlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQ3MDllYWQ4LWQ4NTgtNGZkZC05NzE3LWRlNjhkMWZmYjQ4OSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Omt1YmVwbHVzLXNhYXMtcHJvdmlkZXIifQ.A-h-Ae9D8j9IZthFHsWLrBeXf0poo0fAt1Bt94aWN_DwUtU-R4pD16DEGVFcmyvFOaAjqgeDJ-TDoF1jqjvLeQ3SMiDqBIIZH8XmuyL33fq0pMBwarTsH7JBhQGZCSXvdF-WxyuY5tOl063wo3P3S9eQ6HkUGq0g-sXFNcL6jDfFd6j91hu3kOA13eEtBxHipnSBXHy6uDTR-_UyqQbE1R7bbQYt__lLq07GRfkQnaNuuswN0JOPndfHBm-jbnRjJFH25ow8BCxKwtNBBU2nlk3uT6uEO5Y9Gs6eRsmMKriQyTEWxaTUvOgwAVNxGhssxmoMZW71cgaJvokWRofDgA"}}], "clusters": [{"cluster": {"server": "https://127.0.0.1:62382", "insecure-skip-tls-verify": true}, "name": "kubeplus-saas-provider"}], "contexts": [{"context": {"cluster": "kubeplus-saas-provider", "user": "kubeplus-saas-provider", "namespace": "default"}, "name": "kubeplus-saas-provider"}], "current-context": "kubeplus-saas-provider"} \ No newline at end of file diff --git a/tests/tests.py b/tests/tests.py index c7d0f549..aa05fe57 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -196,7 +196,11 @@ def count_users(response): if os.getenv("KUBEPLUS_HOME") == '': print("Skipping test as KUBEPLUS_HOME is not set.") return - + + # add Kubeplus provider + cmd = "cp ../kubeplus-saas-provider.json ./application-upgrade/provider.conf" + TestKubePlus.run_command(cmd) + # chart uploads cmd = "kubectl upload chart ./application-upgrade/resource-composition-0.0.1.tgz ./application-upgrade/provider.conf" TestKubePlus.run_command(cmd) From 568a5935b8d6ce1f4d686079e4a6a69bd42290f1 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Wed, 3 Jul 2024 16:49:23 -0700 Subject: [PATCH 03/14] removed pycache and adjusted req.txt --- requirements.txt | 4 +++- tests/__pycache__/tests.cpython-312.pyc | Bin 21807 -> 0 bytes tests/tests.py | 15 +++++++-------- 3 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 tests/__pycache__/tests.cpython-312.pyc diff --git a/requirements.txt b/requirements.txt index 4554d9c0..ec1dbbb7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ pyyaml kubernetes -bs4 \ No newline at end of file +bs4 +lxml +select \ No newline at end of file diff --git a/tests/__pycache__/tests.cpython-312.pyc b/tests/__pycache__/tests.cpython-312.pyc deleted file mode 100644 index d28d109f8c17eb9bb4476182e629d5aba1e2647c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21807 zcmdsfYit`=mS*u$WbsXkltevjQ^ z6=hpQaodBdcHe-Gdot63qI?0-Jqcu?x)3&R~FD(vl&j;vNW?3>Nt( zI~nvs*dKe&EmjpNQLiN1-Ix+|d8_WN`#krabG~zK{k_9srQrIT|NZW${WXgEN4!xk zx)S;Fk0A1ZVkuUapsvfmy6ZY}ufMJ*zlQ4u@~b>IUN@3^`Z`U1P1j9&>Q#!>ze}+O zj*2^#O0?gP408NB!&zA4?fn$RH|QzI>(lZmv5zVd9W|kw&~?*a;Qe4!NygtwY1Efb z;N}68gDt+U=M1dwT}pZXx)JW7P3k=j_lBx_6Ki~zx^8A^2pQG{p@lU=Xk{4)ZL9@C zJ8Ol|!P+2nvUUhv&~A5pcXe~*IP3UGSBW{RYQcWi&+k(6yQ}hhCp_H^l6`~|GMC41 zaKnjlA*!#c%>;4m|CdRq?E#gk)JakC>Rgo~qsm)xv-*-6 zQAReW7xk>61)j$(YN8rpjY>ar2FOQmA)hg0Q(lkTm6-O+nppEkmEPuPk!Be}Q9T)# zl1J1jb?T_9r-ph@SxddAqS|U5B^pHIsQxO|Z5b>#ruwP*n=flrRm!ed=>h+oGqV?wq<*_0u(VrE*txHB1lW@8w-zLYt_l zx=`Q-7Z6!QS%|>)r^{6@6lHsXH09C=>TQ_koE}Lzu56-8CirFb3Nf9f-f=)qBMZcH zhZ1yC3~Q{!9I&;~Mry*;Z5~|l;=o5Ui2%%NAe~}`K=Aa6&MGm=gh=Ms$CJre^5)3- z4-GsnM}7wcKz8XwEb}4FH{qjZ3~*`jt(a&`#FCtV4J7l;x8p-!I3|RZV#6?VSZcPT zW!D5Ar5ZtGhoSk{YGw-fN@4=Gy;G=(WL%M62&MlG zM1WmDC|~h9RIY63LLj5kHe0=ws!SlxDCKCs8tv;q5U5#E>UOT>uCt=3IINh}7pxk? z9ZFeMuyUwwdT`}?mn*z65EBB)R3=cN=1|})>|&{jfSL|lRv>eWOJa@y+1JQUogKr4 zfa@;GbFjw-f}?@EDV|O9uoVYkZ@d$WazWVh(kUU9iKUXk=&cB!3EqumZY71#L}V-x z2nIry+^3$o+7?}hO0Gi-uEVek z7aN8a?8DFOuJzH8D|^q>FR&Z7Udr_A8mO+qE+-LRSe zb`mp?zVTZleY%$PS<}`_CJV(p$OmCwWPmP>$K zgsXU+PVpfeiNi>%wM*mhR;XNn#m}+fO4->{+g>KM1-yjKn1Em_OXfH%8OFEB1WHVx z;9X$4mW`BaK)>li8Z5qkt?0kDz`U{KtS#dy)3w3k`WMA1susYH)>1X>gsE{JHu@ip zr!tX^NjliKeWJc~aWp`R#@${>bJ5snjAMH$(Fr8uz$mmJa3_)&=Y)Qs_#eS*4Y z)Fz_++N(r1vyzTnfMs&VDzUGgD5mPVM7g1JCf4#b-m&J)A{F<*tgpI6wLLjTWQ2yQ zmfA!!s$i@g!~5bVp|QR>!&&#ex`H>o_UlG%3a)u_C#hWic3tlPFq zW955cg!n@kAX>%amdyJg02C^Ei;La{Wt0u8bS8N!PXPe~DLaxG7x+HN-R&UCE#R0L z(7wab1Q$t44jgw}gW+4LF-|h3Bbi&P0Wbp;FF9)KumMRc=#1os0)eE$SYb3Zp3Fcw zfWApIxe<_6qx!5~vL4+`#3`gTL}oz^3Xi8*fDf{J){0DPb6tf(h5rP)>lVcRreNNt ziT!O0Oz?Am>qE<&rO-R?Kb&`b?()1pF*z~YH17)JjY~HF?3pLFokZzAvtS=6+Z#}_ zI=7x=rKeocb<&oc#{h-(w=eqpO8&mbo%8;e@{Uhk?Fg&xojo$sQ|vfbYB;xGKM$2G zIkT(PlX6oV0JI3@F15868GpHR-(u(SQs?ncI*X@<<~xT$kI5VJ-1J*zo4e@S^Tf8N zY4^?pKrN>SJza4)z%-K$*XH+PlUn<#C8v2@3p+w z`d%AC%B(&?jRCL>(us~WB=lp3oSwvu3F8=@Gmto)FpZgWMiQqI%um`NuPI>}v;L$- zN99}dZKHayNijJ(-!iHLyA+c%Wf1QrR~&)aRaX^+*QO-ZSU7Msk}HlF?5e8<>_Z5Y zTy?EoRz>PzZ58=btIw{a5&6@RGgq~_ODR?R)#O7M2j{kOySA0v4e}=y->22A#6(7E zG021#kWjV0ctnOss10i*RPWa7CUTH9XJdUiJKLCZRF&VP)C`uYZlyi(14>N$Wt+8} ztY5Te!JM=G7HBntJPbP#UNGuZ&M8{s2o|ln*cK%h7&N{EHM-bV(Ip!+L|5H6+LSkP zZqW^IfoUS=fww%Bw>)v=4XZANZgbA579+GMsWVcdE{;54)urSFyPQ6LWK|;ED(Sff zwq0xpw<N>ykAMtenqEf&zw;1Mb#4g@eaj) z`jb|8o7Ph5jRC8ToDXuFM4!^OTqDd-Q|6RX1G|&mrD!wXp>oZc(@IMGj1tp+MU`@L zO<=KyKjmGR`GDBOcHlLnxf8>CG?+r9NUC40^PA4)#(>!oDiBnWe@x(03KQg-(yvI4}4@CgChbWX|J9e3G|KwkP^29Hrj(7|^P zrocSJX8=YgWE=pmmlV{QO3IJB*iaT6Yam0mHE;_sBQ&y(rV?OuMO1_22G||vtJ?xD zJ*ntzE(7W&m$?Dz@NLK=nFTJ%g6asVU}TDdq6l^=aKIt0lxR`}vC{GlSc(}HNgi_D z%4E_K1JHUpl@vft1wAps{{XT``t&G20ucf2=|sc4e_z%wJ!6sETo~U3OrDqm>VfgK zn&nMC!g8UPiS{m>46P~QXIRsh5d5F}RN343;P}k(*^!@~0uK$ld(qxrvbWEUfUbo) z*p>cIi*8GKXLsQw^^uRIWn9a(z%;XLqrA<_cFN&-|I*~8sVhsq zrUw^hEmqD;2!`;j9sDX7e z{B`(|EXnb)aHSwH0i`8#h7D&THwFH8F`1T=bYULt`vPjZgj@rG3cUhD0q8_7A=|$h z2C|A$tKR*0SUe8_(x|^Be-XTg3jUI-`_twec+%MDc-ZDe^b`WRpRZo&ythu*pl?KPtr0>0op{>TV zglvN{zFhYu)sqAnyXLs^O{zP*bph!uw90nlZX{SKB9;gCmF>Bj;5gYpkqUrKmGGG=3XomtOBz2NiG2MPEH=lt%T$|l{BrA?4p9K57 zz+VO`kUZLhP&5(ak{SLAJ}1^RIb-E{2;_VIwbkzcbKoLl{2)9h;)i6oAsi(;`}*KL zie?12mtp*qSf()(1K6Dwkm3n9;UoCijg~gzUkZRa`ou|YT!xp7vg0&5Ul5$|~f z6Jc$FaRU7F@JG@`B|8kiY}-giIhoPAR7M*fjq%Xvx9~;XsN~iX1n}}svhswyjg=D_ zu^nO+rn~m%l~-Po1xJ4!!vtYD*{&^dF~U*>rulK+d*QJIJsayg*FKj<@#5; zHGn>G3#`HTG2`G`U>=?x-MVoC3%P@})p1x}@^$1bWtTT^{0e*zoki!%3(SdUjQxG< zq;>l6loQ|G_o$`hJY4_%XN)5sowAY=YMh@lT=nGSj%obd;EmLdOELr`)`IvAL(z+%w-C%G;qNXUlB+V#}3M z%awA=j&jTHXS;S6j(#xlmD%7tkk>!AQogRj$h`N!qW4hAd+4!u-us zZ{7t1;P&N>&m7>!IanONI`0@+rgWCB;+sEw=52m(a^_^AW8S+bfA&}4lhXyckG!P= zv(6in_UU&@OlRRziRt}()ypUGWf0W|CkJPb7Ceu~pW090>nCxvUt7l>^*Q4xIu9){ zec#6H(3YOBGds_5c9zZX_H*~w9N4zKg?saDhrl3)ovlmTzsB)qRDaw3k4}~R{ZESAKN?ACswAw$th5Bto;W_q~8T--ws2hGJp^zdFjYO^n#h-UcLz=wXJNcwj=Gqv78K z7|EZ&*&f4f(E0f}h#9l+LXOTrC|~uotyOO2X0Z5}>uOvo{sS5p?C0P=WD+f4po`F;n9c(#%0A1qok#X?!Yv+gvO4Oo}Zd#TUh)EyyNSX7S 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 XJ@+rX_uB8h_HTxk4V1B!)b{@X Date: Mon, 8 Jul 2024 08:59:12 -0700 Subject: [PATCH 04/14] added tests dir requirements.txt and installed lxml in pr.yaml --- .github/workflows/pr.yaml | 6 +++++- requirements.txt | 6 +----- tests/requirements.txt | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 tests/requirements.txt diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index d86e6c37..f13d25e5 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -20,6 +20,7 @@ jobs: eval $(minikube -p minikube docker-env) echo "Glibc version" ldd --version + sudo apt-get install python3-lxml echo "Installing helm..." wget https://get.helm.sh/helm-v3.12.1-linux-amd64.tar.gz gunzip helm-v3.12.1-linux-amd64.tar.gz @@ -113,8 +114,11 @@ jobs: kubectl delete resourcecomposition wordpress-service-composition --kubeconfig=kubeplus-saas-provider.json echo "Running tests..starting in 5 seconds" sleep 5 - source venv/bin/activate cd tests + python3 -m venv venv + source venv/bin/activate + pip3 install -r requirements.txt python3 -m unittest -v tests + deactivate cd ../.. mv kubeplus $runner_dir diff --git a/requirements.txt b/requirements.txt index ec1dbbb7..4818cc54 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1 @@ -pyyaml -kubernetes -bs4 -lxml -select \ No newline at end of file +pyyaml \ No newline at end of file diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 00000000..487f1efc --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,4 @@ +pyyaml +kubernetes +bs4 +select \ No newline at end of file From 7d0e88e241102be5126b4ae96d71f4973e065224 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Mon, 8 Jul 2024 09:17:41 -0700 Subject: [PATCH 05/14] removed select from tests/requirements.txt --- tests/requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index 487f1efc..4554d9c0 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,4 +1,3 @@ pyyaml kubernetes -bs4 -select \ No newline at end of file +bs4 \ No newline at end of file From 70196109ab777d806410df7b34524e3391cb0a6f Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Mon, 8 Jul 2024 10:37:15 -0700 Subject: [PATCH 06/14] added lxml back into req.txt --- tests/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index 4554d9c0..c6ffc00e 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,3 +1,4 @@ pyyaml kubernetes -bs4 \ No newline at end of file +bs4 +lxml \ No newline at end of file From fbb8041c837b8e1009bbbaf2e2dd7caf221cbc5a Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Tue, 23 Jul 2024 15:55:19 -0700 Subject: [PATCH 07/14] added kubectl appstatus plugin --- plugins/appresources.py | 68 ++++--------------------- plugins/appstatus.py | 102 ++++++++++++++++++++++++++++++++++++++ plugins/crmetrics.py | 59 +++++++++++++++++++++- plugins/kubectl-appstatus | 53 ++++++++++++++++++++ 4 files changed, 223 insertions(+), 59 deletions(-) create mode 100644 plugins/appstatus.py create mode 100755 plugins/kubectl-appstatus diff --git a/plugins/appresources.py b/plugins/appresources.py index 33d1360f..b22d369b 100644 --- a/plugins/appresources.py +++ b/plugins/appresources.py @@ -6,30 +6,8 @@ import os from crmetrics import CRBase -class AppResourcesFinder(CRBase): - def _run_command(self, cmd): - cmdOut = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate() - out = cmdOut[0].decode('utf-8') - err = cmdOut[1].decode('utf-8') - return out, err - - def _get_resources(self, kind, plural, targetNS, kubeconfig): - cmd = "kubectl get " + plural + " -n " + targetNS + " " + kubeconfig - out, err = self._run_command(cmd) - resources = [] - for line in out.split("\n"): - res_details = {} - line = line.strip() - if 'NAME' not in line and line != '' and line != '\n': - line1 = ' '.join(line.split()) - parts = line1.split(" ") - res_name = parts[0].strip() - res_details['name'] = res_name - res_details['namespace'] = targetNS - res_details['kind'] = kind - resources.append(res_details) - return resources +class AppResourcesFinder(CRBase): def get_kubeplus_ns(self, kubeconfig): cmd = 'kubectl get deployments -A ' + kubeconfig @@ -43,7 +21,7 @@ def get_kubeplus_ns(self, kubeconfig): return kubeplus_ns def get_target_ns(self, kubeplus_ns, kind, instance, kubeconfig): - cmd = 'kubectl get ' + kind + ' ' + instance + " -n " + kubeplus_ns + ' -o json ' + kubeconfig + cmd = 'kubectl get ' + kind + ' ' + instance + " -n " + kubeplus_ns + ' -o json ' + kubeconfig out, err = self._run_command(cmd) targetNS = '' releaseName = '' @@ -56,10 +34,10 @@ def get_target_ns(self, kubeplus_ns, kind, instance, kubeconfig): targetNS = parts[0].strip() releaseName = parts[1].strip().split("\n")[0] return targetNS, releaseName - return targetNS, releaseName + return targetNS, releaseName def get_helm_resources(self, targetNS, helmrelease, kubeconfig): - #print("Inside helm_resources") + # print("Inside helm_resources") cmd = "helm get all " + helmrelease + " -n " + targetNS + ' ' + kubeconfig out, err = self._run_command(cmd) @@ -74,7 +52,7 @@ def get_helm_resources(self, targetNS, helmrelease, kubeconfig): res_details = {} res_details['name'] = res_name res_details['namespace'] = targetNS - res_details['kind'] = kind + res_details['kind'] = kind resources.append(res_details) new_resource = False @@ -96,32 +74,6 @@ def get_pods(self, targetNS, kind, instance, kubeconfig): resources = self._get_resources('Pod', 'pods', targetNS, kubeconfig) return resources - def check_res_exists(self, kind, instance, kubeconfig): - cmd = 'kubectl get ' + kind + ' -A ' + kubeconfig - out, err = self._run_command(cmd) - for line in out.split("\n"): - if instance in line: - parts = line.split(" ") - ns = parts[0].strip() - return True, ns, '' - return False, '', kind + ' ' + instance + ' not found.' - - def verify_kind_is_consumerapi(self, kind, kubeconfig): - - if kind.lower() in 'resourcecompositions': - return False - - cmd = 'kubectl get crds ' + kubeconfig - out, err = self._run_command(cmd) - for line in out.split("\n"): - parts = line.split(" ") - fqn = parts[0].strip() - parts1 = fqn.split(".") - plural = parts1[0] - singular = plural[0:len(plural)-1] - if kind.lower() == singular: - return True - return False if __name__ == '__main__': appResourcesFinder = AppResourcesFinder() @@ -129,7 +81,7 @@ def verify_kind_is_consumerapi(self, kind, kubeconfig): instance = sys.argv[2] kubeconfig = sys.argv[3] - #print("kind:" + kind + " instance:" + instance + " kubeconfig:" + kubeconfig) + # print("kind:" + kind + " instance:" + instance + " kubeconfig:" + kubeconfig) valid_consumer_api = appResourcesFinder.verify_kind_is_consumerapi(kind, kubeconfig) if not valid_consumer_api: @@ -148,7 +100,7 @@ def verify_kind_is_consumerapi(self, kind, kubeconfig): targetNS, helmrelease = appResourcesFinder.get_target_ns(res_ns, kind, instance, kubeconfig) if targetNS == '' and helmrelease == '': print("No Helm release found for {} resource {}".format(kind, instance)) - #print(targetNS + " " + helmrelease) + # print(targetNS + " " + helmrelease) pods = appResourcesFinder.get_pods(targetNS, kind, instance, kubeconfig) networkpolicies = appResourcesFinder.get_networkpolicies(targetNS, kind, instance, kubeconfig) resourcequotas = appResourcesFinder.get_resourcequotas(targetNS, kind, instance, kubeconfig) @@ -162,10 +114,10 @@ def verify_kind_is_consumerapi(self, kind, kubeconfig): # Ref: https://www.educba.com/python-print-table/ # https://stackoverflow.com/questions/20309255/how-to-pad-a-string-to-a-fixed-length-with-spaces-in-python - print ("{:<25} {:<25} {:<25} ".format("NAMESPACE", "KIND", "NAME")) - print ("{:<25} {:<25} {:<25} ".format(kubeplus_ns, kind, instance)) + print("{:<25} {:<25} {:<25} ".format("NAMESPACE", "KIND", "NAME")) + print("{:<25} {:<25} {:<25} ".format(kubeplus_ns, kind, instance)) for res in allresources: ns = res['namespace'] kind = res['kind'] name = res['name'] - print ("{:<25} {:<25} {:<25} ".format(ns, kind, name)) + print("{:<25} {:<25} {:<25} ".format(ns, kind, name)) diff --git a/plugins/appstatus.py b/plugins/appstatus.py new file mode 100644 index 00000000..8ac0ec00 --- /dev/null +++ b/plugins/appstatus.py @@ -0,0 +1,102 @@ +import subprocess +import sys +import json +from crmetrics import CRBase + +''' + new plugin app-status -- takes in kind and instance and displays + kind, namespace, name and status and lists pods in that application + with their status + + application name is the namespace and pods will be under this namespace + for application status itself, name would just be the helm release + + Input: name of kind and name of application instance + + TODO: reexamine all error checks for plugins +''' + + +class AppStatusFinder(CRBase): + + def get_app_instance_status(self, kind, instance, kubeconfig): + cmd = 'kubectl get %s %s -o json %s' % (kind, instance, kubeconfig) + out, err = self._run_command(cmd) + if err != "": + print("Something went wrong while getting app instance status.") + print(err) + exit(1) + ''' + with response, check if status exists + check if helmrelease exists and extract name of instance + or check if status contains an error + otherwise (i.e. status missing), display "App not deployed properly" + ''' + # response = json.dumps(json.loads(out), indent=4) + response = json.loads(out) + if 'status' in response: + if 'helmrelease' in response['status']: + helm_release = response['status']['helmrelease'].strip('\n') + ns, name = helm_release.split(':') + return name, ns, True, None + else: + # an error has occurred + status = response['status'] + return status, None, False, None + + else: + return '', 'Application not deployed properly', False, None + + + + + def get_app_pods(self, namespace, kubeconfig): + cmd = 'kubectl get pods -n %s %s -o json' % (namespace, kubeconfig) + # pods = self._get_resources(None, 'pods', namespace, kubeconfig) + out, err = self._run_command(cmd) + # format? + response = json.loads(out) + pods = [] + for pod in response['items']: + name = pod['metadata']['name'] + typ = pod['kind'] + ns = pod['metadata']['namespace'] + phase = pod['status']['phase'] + pods.append((name, typ, ns, phase)) + return pods + + +if __name__ == '__main__': + appStatusFinder = AppStatusFinder() + kind = sys.argv[1] + instance = sys.argv[2] + kubeconfig = sys.argv[3] + + valid_consumer_api = appStatusFinder.verify_kind_is_consumerapi(kind, kubeconfig) + if not valid_consumer_api: + print(("{} is not a valid Consumer API.").format(kind)) + exit(0) + + res_exists, ns, err = appStatusFinder.check_res_exists(kind, instance, kubeconfig) + if not res_exists: + print(err) + exit(0) + + release_name_or_status, release_ns, deployed, err = appStatusFinder.get_app_instance_status(kind, instance, kubeconfig) + if err is not None: + print(err) + exit(1) + + if deployed: + deploy_str = 'Deployed' + else: + print(release_name_or_status) + exit(1) + + # if not deployed, there's probably an error -- maybe display a different response in this case + pods = appStatusFinder.get_app_pods(instance, kubeconfig) + + print("{:<35} {:<35} {:<35} {:<35}".format("NAME", "TYPE", "NAMESPACE", "STATUS")) + print("{:<35} {:<35} {:<35} {:<35}".format(release_name_or_status, 'helmrelease', release_ns, deploy_str)) + for pod_name, typ, pod_ns, phase in pods: + print("{:<35} {:<35} {:<35} {:<35}".format(pod_name, typ, pod_ns, phase)) \ No newline at end of file diff --git a/plugins/crmetrics.py b/plugins/crmetrics.py index e01b10d6..876736cd 100644 --- a/plugins/crmetrics.py +++ b/plugins/crmetrics.py @@ -6,10 +6,15 @@ import platform import pprint import time - +import yaml import utils class CRBase(object): + def _run_command(self, cmd): + cmdOut = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate() + out = cmdOut[0].decode('utf-8') + err = cmdOut[1].decode('utf-8') + return out, err def parse_pod_details(self, out, instance): pod_list = [] @@ -114,6 +119,58 @@ def get_resources_connections(self, kind, instance, namespace, kubeconfig): print(e) return json_output + def _get_resources(self, kind, plural, targetNS, kubeconfig): + cmd = "kubectl get " + plural + " -n " + targetNS + " " + kubeconfig + out, err = self._run_command(cmd) + resources = [] + for line in out.split("\n"): + res_details = {} + line = line.strip() + if 'NAME' not in line and line != '' and line != '\n': + line1 = ' '.join(line.split()) + parts = line1.split(" ") + res_name = parts[0].strip() + res_details['name'] = res_name + res_details['namespace'] = targetNS + res_details['kind'] = kind + resources.append(res_details) + return resources + + def check_res_exists(self, kind, instance, kubeconfig): + cmd = 'kubectl get ' + kind + ' -A ' + kubeconfig + out, err = self._run_command(cmd) + for line in out.split("\n"): + if instance in line: + parts = line.split(" ") + ns = parts[0].strip() + return True, ns, '' + return False, '', kind + ' ' + instance + ' not found.' + + def verify_kind_is_consumerapi(self, kind, kubeconfig): + + if kind.lower() in 'resourcecompositions': + return False + + cmd = 'kubectl get crds ' + kubeconfig + out, err = self._run_command(cmd) + for line in out.split("\n"): + parts = line.split(" ") + fqn = parts[0].strip() + parts1 = fqn.split(".") + plural = parts1[0] + singular = plural[0:len(plural) - 1] + if kind.lower() == singular: + return True + return False + + ''' + TODO: add method that accepts kind name (HelloWorldService), instance name (hs1), and namespace + (KUBEPLUS_NS) + it will run `kubectl get kind_name instance_name -n namespace` and if this errors out, no further check + is needed and the user must be informed + otherwise, proceed as normal + ''' + class CRMetrics(CRBase): diff --git a/plugins/kubectl-appstatus b/plugins/kubectl-appstatus new file mode 100755 index 00000000..c1f0650b --- /dev/null +++ b/plugins/kubectl-appstatus @@ -0,0 +1,53 @@ +#!/bin/bash + +source utils.sh + +print_help () { + echo "NAME" + echo " kubectl appstatus" + echo "" + echo "SYNOPSIS" + echo " kubectl appstatus -k " + echo "" + echo "DESCRIPTION" + echo " kubectl appstatus shows the status of the application instance and its pods" + exit 0 +} + +if (( $# < 2 )); then + print_help +fi + +kind=$1 +instance=$2 +kubeconfig="" + +shift; +shift; + +while getopts ":k:" opt; do + case ${opt} in + k ) + kubeconfig1=$OPTARG + if [ ! -f $kubeconfig1 ]; then + echo "Kubeconfig $kubeconfig1 does not exist." + exit 0 + fi;; + ? ) + echo "Invalid option: ${1} " 1>&2 + print_help + exit 0 + ;; + esac +done + +kubeconfig="--kubeconfig="$kubeconfig1 + +canonicalKind=$(get_canonical_kind $kind) + +if [[ $canonicalKind == *"Unknown"* ]]; then + echo "$canonicalKind" + exit 0 +fi + +python3 /$KUBEPLUS_HOME/plugins/appstatus.py $canonicalKind $instance $kubeconfig From 89a5efde0a0e3a533f37f87310af7a00b2096abf Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Fri, 26 Jul 2024 12:56:49 -0700 Subject: [PATCH 08/14] added appstatus plugin testcase & instance validation check in crmetrics --- plugins/appstatus.py | 5 ++ plugins/crmetrics.py | 6 +++ .../hello-world-service-composition.yaml | 54 +++++++++++++++++++ tests/hello-world/hs1.yaml | 7 +++ tests/hello-world/provider.conf | 1 + tests/tests.py | 48 +++++++++++++++++ 6 files changed, 121 insertions(+) create mode 100644 tests/hello-world/hello-world-service-composition.yaml create mode 100644 tests/hello-world/hs1.yaml create mode 100644 tests/hello-world/provider.conf diff --git a/plugins/appstatus.py b/plugins/appstatus.py index 8ac0ec00..b469019f 100644 --- a/plugins/appstatus.py +++ b/plugins/appstatus.py @@ -82,6 +82,11 @@ def get_app_pods(self, namespace, kubeconfig): print(err) exit(0) + working, error = appStatusFinder.validate_kind_and_instance(kind, instance, ns) + if working == False: + print(err) + exit(1) + release_name_or_status, release_ns, deployed, err = appStatusFinder.get_app_instance_status(kind, instance, kubeconfig) if err is not None: print(err) diff --git a/plugins/crmetrics.py b/plugins/crmetrics.py index fcbc0c08..ea77cd4f 100644 --- a/plugins/crmetrics.py +++ b/plugins/crmetrics.py @@ -170,6 +170,12 @@ def verify_kind_is_consumerapi(self, kind, kubeconfig): is needed and the user must be informed otherwise, proceed as normal ''' + def validate_kind_and_instance(self, kind, instance, namespace): + cmd = 'kubectl get %s %s -n %s' % (kind, instance, namespace) + _, err = self._run_command(cmd) + if err == '': # or None? + return True, None + return False, err class CRMetrics(CRBase): diff --git a/tests/hello-world/hello-world-service-composition.yaml b/tests/hello-world/hello-world-service-composition.yaml new file mode 100644 index 00000000..e82aa52b --- /dev/null +++ b/tests/hello-world/hello-world-service-composition.yaml @@ -0,0 +1,54 @@ +apiVersion: workflows.kubeplus/v1alpha1 +kind: ResourceComposition +metadata: + name: hello-world-service-composition +spec: + # newResource defines the new CRD to be installed define a workflow. + newResource: + resource: + kind: HelloWorldService + group: platformapi.kubeplus + version: v1alpha1 + plural: helloworldservices + # URL of the Helm chart that contains Kubernetes resources that represent a workflow. + chartURL: https://github.com/cloud-ark/operatorcharts/blob/master/hello-world-chart-0.0.2.tgz?raw=true + chartName: hello-world-chart + # respolicy defines the resource policy to be applied to instances of the specified custom resource. + respolicy: + apiVersion: workflows.kubeplus/v1alpha1 + kind: ResourcePolicy + metadata: + name: hello-world-service-policy + spec: + resource: + kind: HelloWorldService + group: platformapi.kubeplus + version: v1alpha1 + policy: + # Add following requests and limits for the first container of all the Pods that are related via + # owner reference relationship to instances of resources specified above. + podconfig: + limits: + cpu: 200m + memory: 2Gi + requests: + cpu: 100m + memory: 1Gi + nodeSelector: values.nodeName + # resmonitor identifies the resource instances that should be monitored for CPU/Memory/Storage. + # All the Pods that are related to the resource instance through either ownerReference relationship, or all the relationships + # (ownerReference, label, annotation, spec properties) are considered in calculating the statistics. + # The generated output is in Prometheus format. + resmonitor: + apiVersion: workflows.kubeplus/v1alpha1 + kind: ResourceMonitor + metadata: + name: hello-world-service-monitor + spec: + resource: + kind: HelloWorldService + group: platformapi.kubeplus + version: v1alpha1 + # This attribute indicates that Pods that are reachable through all the relationships should be used + # as part of calculating the monitoring statistics. + monitorRelationships: all diff --git a/tests/hello-world/hs1.yaml b/tests/hello-world/hs1.yaml new file mode 100644 index 00000000..d2b1bdc9 --- /dev/null +++ b/tests/hello-world/hs1.yaml @@ -0,0 +1,7 @@ +apiVersion: platformapi.kubeplus/v1alpha1 +kind: HelloWorldService +metadata: + name: hs1 +spec: + greeting: Hello hello hello + diff --git a/tests/hello-world/provider.conf b/tests/hello-world/provider.conf new file mode 100644 index 00000000..0485db91 --- /dev/null +++ b/tests/hello-world/provider.conf @@ -0,0 +1 @@ +{"apiVersion": "v1", "kind": "Config", "users": [{"name": "kubeplus-saas-provider", "user": {"token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkhJMEplMXc4RzFvaVVDa0I4RTZ5ZlE2QkdWcHpDeUFzejR4XzdscWxJZU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Imt1YmVwbHVzLXNhYXMtcHJvdmlkZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3ViZXBsdXMtc2Fhcy1wcm92aWRlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRiNjE2YzU3LTMyMmYtNGRlMS1hOGNiLTY2ODYzYTg2NTZhMSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Omt1YmVwbHVzLXNhYXMtcHJvdmlkZXIifQ.EYZCk4l4UcyH_1SQmaAHrUzF0QPLlvxF-udD-xe6WGCNDSCQl0vRFcO7E57I8-ApxJsLketX7Rt6F1UZKoOABN5PpNppr5iDuuYJw6A1A2CrcfDtxS4Xv-gwHQhmFV9BNomccBfKA0UIXVrV1q5i8Xp6iyLJ0sl5Pm-D2rysvUCqM_kuhWz2zdeglivRwYo0-Q3H7nXi5ozq_na5Knu6BzAi3LF_ocfIwwxwbsOZbMIUBK937gEuHHYwVph2DLrFUG6CdpW2CJdsWwKj82upkE8QwXayWgr4TsDAC6bouAG6-5ICpJU9GCNFYPGwcYAl6qfMHT8V0uWzZGPN_4V5YQ"}}], "clusters": [{"cluster": {"server": "https://127.0.0.1:65101", "insecure-skip-tls-verify": true}, "name": "kubeplus-saas-provider"}], "contexts": [{"context": {"cluster": "kubeplus-saas-provider", "user": "kubeplus-saas-provider", "namespace": "default"}, "name": "kubeplus-saas-provider"}], "current-context": "kubeplus-saas-provider"} \ No newline at end of file diff --git a/tests/tests.py b/tests/tests.py index 2824decd..37dabda8 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -454,13 +454,61 @@ def test_res_comp_with_no_podpolicies(self): removed = True else: time.sleep(1) + + def test_appstatus_plugin(self): + def cleanup(): + cmd = "cd ./hello-world" + TestKubePlus.run_command(cmd) + cmd = "kubectl delete -f hs1.yaml --kubeconfig=provider.conf" + TestKubePlus.run_command(cmd) + cmd = "kubectl delete -f hello-world-service-composition.yaml --kubeconfig=provider.conf" + + if not TestKubePlus._is_kubeplus_running(): + print("KubePlus is not running. Deploy KubePlus and then run tests") + sys.exit(0) + + if os.getenv("KUBEPLUS_HOME") == '': + print("Skipping test as KUBEPLUS_HOME is not set.") + return + + # add Kubeplus provider + cmd = "cp ../kubeplus-saas-provider.json ./hello-world/provider.conf" + TestKubePlus.run_command(cmd) + + # register HelloWorldService API + cmd = "kubectl create -f ./hello-world/hello-world-service-composition.yaml --kubeconfig=./hello-world/provider.conf" + TestKubePlus.run_command(cmd) + + # check CRD installation + crd = "helloworldservices.platformapi.kubeplus" + crd_installed = self._check_crd_installed(crd) + if not crd_installed: + print("CRD " + crd + " not installed. Exiting this test.") + return + + # create app instance + cmd = "kubectl create -f ./hello-world/hs1.yaml --kubeconfig=./hello-world/provider.conf" + out, err = TestKubePlus.run_command(cmd) + + # test plugin + cmd = "kubectl appstatus HelloWorldService hs1" + out, err = TestKubePlus.run_command(cmd) + + if err != '': + print("Something went wrong with the plugin.") + cleanup() + sys.exit(1) + + cleanup() # TODO: Add tests for # kubectl connections # kubectl appresources # kubectl appurl # kubectl applogs # kubectl metrics + # TODO: pos test case for kubectl appstatus with HelloWorld + # maybe write/find a method for setting up HelloWorld instance and reuse here @unittest.skip("Skipping CLI test") def test_kubeplus_cli(self): kubeplus_home = os.getenv("KUBEPLUS_HOME") From df8a6d9de35bfc11f1dda126436b35c8e73563a2 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Fri, 26 Jul 2024 14:57:37 -0700 Subject: [PATCH 09/14] removed provider file & web token from tests/hello-world --- tests/hello-world/provider.conf | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/hello-world/provider.conf diff --git a/tests/hello-world/provider.conf b/tests/hello-world/provider.conf deleted file mode 100644 index 0485db91..00000000 --- a/tests/hello-world/provider.conf +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion": "v1", "kind": "Config", "users": [{"name": "kubeplus-saas-provider", "user": {"token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkhJMEplMXc4RzFvaVVDa0I4RTZ5ZlE2QkdWcHpDeUFzejR4XzdscWxJZU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Imt1YmVwbHVzLXNhYXMtcHJvdmlkZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3ViZXBsdXMtc2Fhcy1wcm92aWRlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRiNjE2YzU3LTMyMmYtNGRlMS1hOGNiLTY2ODYzYTg2NTZhMSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Omt1YmVwbHVzLXNhYXMtcHJvdmlkZXIifQ.EYZCk4l4UcyH_1SQmaAHrUzF0QPLlvxF-udD-xe6WGCNDSCQl0vRFcO7E57I8-ApxJsLketX7Rt6F1UZKoOABN5PpNppr5iDuuYJw6A1A2CrcfDtxS4Xv-gwHQhmFV9BNomccBfKA0UIXVrV1q5i8Xp6iyLJ0sl5Pm-D2rysvUCqM_kuhWz2zdeglivRwYo0-Q3H7nXi5ozq_na5Knu6BzAi3LF_ocfIwwxwbsOZbMIUBK937gEuHHYwVph2DLrFUG6CdpW2CJdsWwKj82upkE8QwXayWgr4TsDAC6bouAG6-5ICpJU9GCNFYPGwcYAl6qfMHT8V0uWzZGPN_4V5YQ"}}], "clusters": [{"cluster": {"server": "https://127.0.0.1:65101", "insecure-skip-tls-verify": true}, "name": "kubeplus-saas-provider"}], "contexts": [{"context": {"cluster": "kubeplus-saas-provider", "user": "kubeplus-saas-provider", "namespace": "default"}, "name": "kubeplus-saas-provider"}], "current-context": "kubeplus-saas-provider"} \ No newline at end of file From ffd65005fa559ded75a78130d13051affbc0d04a Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Thu, 1 Aug 2024 11:02:09 -0700 Subject: [PATCH 10/14] appresources working fine, cleaned up appstatus file --- plugins/appstatus.py | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/plugins/appstatus.py b/plugins/appstatus.py index b469019f..059dd101 100644 --- a/plugins/appstatus.py +++ b/plugins/appstatus.py @@ -3,19 +3,6 @@ import json from crmetrics import CRBase -''' - new plugin app-status -- takes in kind and instance and displays - kind, namespace, name and status and lists pods in that application - with their status - - application name is the namespace and pods will be under this namespace - for application status itself, name would just be the helm release - - Input: name of kind and name of application instance - - TODO: reexamine all error checks for plugins -''' - class AppStatusFinder(CRBase): @@ -26,13 +13,7 @@ def get_app_instance_status(self, kind, instance, kubeconfig): print("Something went wrong while getting app instance status.") print(err) exit(1) - ''' - with response, check if status exists - check if helmrelease exists and extract name of instance - or check if status contains an error - otherwise (i.e. status missing), display "App not deployed properly" - ''' - # response = json.dumps(json.loads(out), indent=4) + response = json.loads(out) if 'status' in response: if 'helmrelease' in response['status']: @@ -48,11 +29,8 @@ def get_app_instance_status(self, kind, instance, kubeconfig): return '', 'Application not deployed properly', False, None - - def get_app_pods(self, namespace, kubeconfig): cmd = 'kubectl get pods -n %s %s -o json' % (namespace, kubeconfig) - # pods = self._get_resources(None, 'pods', namespace, kubeconfig) out, err = self._run_command(cmd) # format? response = json.loads(out) From 76dfbca5440aaa18ac69f358dde6964bbba77564 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Mon, 5 Aug 2024 13:58:18 -0700 Subject: [PATCH 11/14] removed comments & tests/hello-world, and restored hs1.yaml --- examples/multitenancy/hello-world/hs1.yaml | 2 +- plugins/appstatus.py | 11 ++-- .../hello-world-service-composition.yaml | 54 ------------------- tests/hello-world/hs1.yaml | 7 --- tests/tests.py | 2 - 5 files changed, 8 insertions(+), 68 deletions(-) delete mode 100644 tests/hello-world/hello-world-service-composition.yaml delete mode 100644 tests/hello-world/hs1.yaml diff --git a/examples/multitenancy/hello-world/hs1.yaml b/examples/multitenancy/hello-world/hs1.yaml index d2b1bdc9..77ebb91a 100644 --- a/examples/multitenancy/hello-world/hs1.yaml +++ b/examples/multitenancy/hello-world/hs1.yaml @@ -4,4 +4,4 @@ metadata: name: hs1 spec: greeting: Hello hello hello - + replicas: 1 \ No newline at end of file diff --git a/plugins/appstatus.py b/plugins/appstatus.py index e75a092a..a853a2ca 100644 --- a/plugins/appstatus.py +++ b/plugins/appstatus.py @@ -13,20 +13,23 @@ def get_app_instance_status(self, kind, instance, kubeconfig): print("Something went wrong while getting app instance status.") print(err) exit(1) - + + deployed = False + ns = None response = json.loads(out) if 'status' in response: if 'helmrelease' in response['status']: helm_release = response['status']['helmrelease'].strip('\n') ns, name = helm_release.split(':') - return name, ns, True + deployed = True + return name, ns, deployed else: # an error has occurred status = response['status'] - return status, None, False + return status, ns, deployed else: - return 'Application not deployed properly', None, False + return 'Application not deployed properly', ns, deployed def get_app_pods(self, namespace, kubeconfig): diff --git a/tests/hello-world/hello-world-service-composition.yaml b/tests/hello-world/hello-world-service-composition.yaml deleted file mode 100644 index e82aa52b..00000000 --- a/tests/hello-world/hello-world-service-composition.yaml +++ /dev/null @@ -1,54 +0,0 @@ -apiVersion: workflows.kubeplus/v1alpha1 -kind: ResourceComposition -metadata: - name: hello-world-service-composition -spec: - # newResource defines the new CRD to be installed define a workflow. - newResource: - resource: - kind: HelloWorldService - group: platformapi.kubeplus - version: v1alpha1 - plural: helloworldservices - # URL of the Helm chart that contains Kubernetes resources that represent a workflow. - chartURL: https://github.com/cloud-ark/operatorcharts/blob/master/hello-world-chart-0.0.2.tgz?raw=true - chartName: hello-world-chart - # respolicy defines the resource policy to be applied to instances of the specified custom resource. - respolicy: - apiVersion: workflows.kubeplus/v1alpha1 - kind: ResourcePolicy - metadata: - name: hello-world-service-policy - spec: - resource: - kind: HelloWorldService - group: platformapi.kubeplus - version: v1alpha1 - policy: - # Add following requests and limits for the first container of all the Pods that are related via - # owner reference relationship to instances of resources specified above. - podconfig: - limits: - cpu: 200m - memory: 2Gi - requests: - cpu: 100m - memory: 1Gi - nodeSelector: values.nodeName - # resmonitor identifies the resource instances that should be monitored for CPU/Memory/Storage. - # All the Pods that are related to the resource instance through either ownerReference relationship, or all the relationships - # (ownerReference, label, annotation, spec properties) are considered in calculating the statistics. - # The generated output is in Prometheus format. - resmonitor: - apiVersion: workflows.kubeplus/v1alpha1 - kind: ResourceMonitor - metadata: - name: hello-world-service-monitor - spec: - resource: - kind: HelloWorldService - group: platformapi.kubeplus - version: v1alpha1 - # This attribute indicates that Pods that are reachable through all the relationships should be used - # as part of calculating the monitoring statistics. - monitorRelationships: all diff --git a/tests/hello-world/hs1.yaml b/tests/hello-world/hs1.yaml deleted file mode 100644 index d2b1bdc9..00000000 --- a/tests/hello-world/hs1.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: platformapi.kubeplus/v1alpha1 -kind: HelloWorldService -metadata: - name: hs1 -spec: - greeting: Hello hello hello - diff --git a/tests/tests.py b/tests/tests.py index 2e1a4c38..76e0f3d9 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -594,8 +594,6 @@ def cleanup(): # kubectl appurl # kubectl applogs # kubectl metrics - # TODO: pos test case for kubectl appstatus with HelloWorld - # maybe write/find a method for setting up HelloWorld instance and reuse here @unittest.skip("Skipping CLI test") def test_kubeplus_cli(self): kubeplus_home = os.getenv("KUBEPLUS_HOME") From 414220a01b234a2e755b70b0190a54a42db8a576 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Tue, 6 Aug 2024 09:50:32 -0700 Subject: [PATCH 12/14] switched chart reference in tests.py for appstatus test --- tests/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 76e0f3d9..6c94749e 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -545,7 +545,7 @@ def test_appstatus_plugin(self): def cleanup(): cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hs1.yaml --kubeconfig=%s" % provider TestKubePlus.run_command(cmd) - cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hello-world-service-composition.yaml --kubeconfig=%s" % provider + cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider TestKubePlus.run_command(cmd) if not TestKubePlus._is_kubeplus_running(): @@ -557,7 +557,7 @@ def cleanup(): return # register HelloWorldService API - cmd = "kubectl create -f ../examples/multitenancy/hello-world/hello-world-service-composition.yaml --kubeconfig=%s" % provider + cmd = "kubectl create -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider TestKubePlus.run_command(cmd) # check CRD installation From 8b6baeab9ec17c6111dc5e8d2a27477d97dff1fa Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Fri, 9 Aug 2024 23:35:41 -0700 Subject: [PATCH 13/14] refactored setup/cleanup methods for hello-world example --- tests/tests.py | 68 +++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index fc7e3eaa..96ac9abe 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -45,6 +45,40 @@ def _is_kyverno_running(self): if 'kyverno' in line and 'Running' in line: return True return False + + + def setup_example_hello_world(self, provider): + + if not TestKubePlus._is_kubeplus_running(): + print("KubePlus is not running. Deploy KubePlus and then run tests") + sys.exit(0) + + if os.getenv("KUBEPLUS_HOME") == '': + print("Skipping test as KUBEPLUS_HOME is not set.") + return + + # register HelloWorldService API + cmd = "kubectl create -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider + TestKubePlus.run_command(cmd) + + # check CRD installation + crd = "helloworldservices.platformapi.kubeplus" + crd_installed = self._check_crd_installed(crd) + if not crd_installed: + print("CRD " + crd + " not installed. Exiting this test.") + return + + # create app instance + cmd = "kubectl create -f ../examples/multitenancy/hello-world/hs1.yaml --kubeconfig=%s" % provider + out, err = TestKubePlus.run_command(cmd) + time.sleep(10) + + + def cleanup_example_hello_world(self, provider): + cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hs1.yaml --kubeconfig=%s" % provider + TestKubePlus.run_command(cmd) + cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider + TestKubePlus.run_command(cmd) def test_create_res_comp_for_chart_with_ns(self): if not TestKubePlus._is_kubeplus_running(): @@ -526,37 +560,9 @@ def test_res_comp_with_no_podpolicies(self): def test_appstatus_plugin(self): kubeplus_home = os.getenv("KUBEPLUS_HOME") provider = kubeplus_home + '/kubeplus-saas-provider.json' - - def cleanup(): - cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hs1.yaml --kubeconfig=%s" % provider - TestKubePlus.run_command(cmd) - cmd = "kubectl delete -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider - TestKubePlus.run_command(cmd) - - if not TestKubePlus._is_kubeplus_running(): - print("KubePlus is not running. Deploy KubePlus and then run tests") - sys.exit(0) - if os.getenv("KUBEPLUS_HOME") == '': - print("Skipping test as KUBEPLUS_HOME is not set.") - return - - # register HelloWorldService API - cmd = "kubectl create -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider - TestKubePlus.run_command(cmd) + self.setup_example_hello_world(provider=provider) - # check CRD installation - crd = "helloworldservices.platformapi.kubeplus" - crd_installed = self._check_crd_installed(crd) - if not crd_installed: - print("CRD " + crd + " not installed. Exiting this test.") - return - - # create app instance - cmd = "kubectl create -f ../examples/multitenancy/hello-world/hs1.yaml --kubeconfig=%s" % provider - out, err = TestKubePlus.run_command(cmd) - - time.sleep(10) # test plugin cmd = "kubectl appstatus HelloWorldService hs1 -k %s" % provider out, err = TestKubePlus.run_command(cmd) @@ -564,7 +570,7 @@ def cleanup(): if err != '': print("Something went wrong with the plugin.") print(err) - cleanup() + self.cleanup_example_hello_world(provider=provider) sys.exit(1) # asserts @@ -572,7 +578,7 @@ def cleanup(): self.assertTrue('Deployed' in lines[1]) self.assertTrue('Running' in lines[2] or 'Pending' in lines[2] or 'ContainerCreating' in lines[2]) - cleanup() + self.cleanup_example_hello_world(provider=provider) # TODO: Add tests for # kubectl connections # kubectl appresources From fddcca02c22dfac56c70cd3f35e5c5b121469866 Mon Sep 17 00:00:00 2001 From: Om Goswami Date: Mon, 12 Aug 2024 11:28:51 -0700 Subject: [PATCH 14/14] added appresources test --- tests/tests.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 96ac9abe..f36210f4 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -56,7 +56,9 @@ def setup_example_hello_world(self, provider): if os.getenv("KUBEPLUS_HOME") == '': print("Skipping test as KUBEPLUS_HOME is not set.") return - + + # upload chart -- sanity check + cmd = "kubectl upload chart ../examples/multitenancy/hello-world/hello-world-chart-0.0.3.tgz %s" % provider # register HelloWorldService API cmd = "kubectl create -f ../examples/multitenancy/hello-world/hello-world-service-composition-localchart.yaml --kubeconfig=%s" % provider TestKubePlus.run_command(cmd) @@ -561,8 +563,7 @@ def test_appstatus_plugin(self): kubeplus_home = os.getenv("KUBEPLUS_HOME") provider = kubeplus_home + '/kubeplus-saas-provider.json' - self.setup_example_hello_world(provider=provider) - + self.setup_example_hello_world(provider) # test plugin cmd = "kubectl appstatus HelloWorldService hs1 -k %s" % provider out, err = TestKubePlus.run_command(cmd) @@ -570,7 +571,7 @@ def test_appstatus_plugin(self): if err != '': print("Something went wrong with the plugin.") print(err) - self.cleanup_example_hello_world(provider=provider) + self.cleanup_example_hello_world(provider) sys.exit(1) # asserts @@ -579,6 +580,32 @@ def test_appstatus_plugin(self): self.assertTrue('Running' in lines[2] or 'Pending' in lines[2] or 'ContainerCreating' in lines[2]) self.cleanup_example_hello_world(provider=provider) + + def test_appresources_plugin(self): + kubeplus_home = os.getenv("KUBEPLUS_HOME") + provider = kubeplus_home + '/kubeplus-saas-provider.json' + + self.setup_example_hello_world(provider) + + cmd = "kubectl appresources HelloWorldService hs1 -k %s" % provider + out, err = TestKubePlus.run_command(cmd) + + if err != '': + print("An error occurred when running the plugin.") + print(err) + sys.exit(1) + + # there should be HelloWorldService hs1, Service, Deployment, and Pod in 2, 3, and 4 + lines = out.split('\n') + service = lines[2].split() + deployment = lines[3].split() + pod = lines[4].split() + + self.assertTrue(service[1] == 'Service' and 'helloworldservice' in service[2]) + self.assertTrue(deployment[1] == 'Deployment' and 'helloworldservice' in deployment[2]) + self.assertTrue(pod[1] == 'Pod' and 'helloworldservice' in pod[2]) + + self.cleanup_example_hello_world(provider) # TODO: Add tests for # kubectl connections # kubectl appresources