blob: 34f685e4e5c23e79fc661e0e7ce7a7faac7e40f2 [file] [log] [blame]
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +04001# Copyright 2017 Mirantis, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import pytest
Vladimir Jigulin34dfa942018-07-23 21:05:48 +040016import netaddr
17import os
Vladimir Jigulin57ecae92018-09-10 22:51:15 +040018import json
Vladimir Jigulin5775bbb2018-10-03 10:34:54 +040019import requests
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040020
21from tcp_tests import logger
22from tcp_tests import settings
23
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040024from tcp_tests.managers.k8s import read_yaml_file
25
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040026LOG = logger.logger
27
28
29class TestMCPK8sActions(object):
30 """Test class for different k8s actions"""
31
Vladimir Jigulin57ecae92018-09-10 22:51:15 +040032 def __read_testdata_yaml(self, name):
33 dir = os.path.join(os.path.dirname(__file__), 'testdata/k8s')
34 return read_yaml_file(dir, name)
35
Tatyana Leontovichc411ec32017-10-09 14:48:00 +030036 @pytest.mark.grab_versions
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040037 @pytest.mark.fail_snapshot
Tatyana Leontovich071ce6a2017-10-24 18:08:10 +030038 @pytest.mark.cz8116
Dennis Dmitriev0f624a82018-06-11 12:57:13 +030039 @pytest.mark.k8s_calico
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040040 def test_k8s_externaldns_coredns(self, show_step, config, k8s_deployed):
41 """Test externaldns integration with coredns
42
43 Scenario:
44 1. Install k8s with externaldns addon enabled(including etcd, coredns)
45 2. Start simple service
46 3. Expose deployment
47 4. Annotate service with domain name
48 5. Try to get service using nslookup
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040049 6. Delete service and deployment
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040050 """
51
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040052 show_step(1)
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040053 if not (config.k8s_deploy.kubernetes_externaldns_enabled and
54 config.k8s_deploy.kubernetes_coredns_enabled):
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040055 pytest.skip("Test requires externaldns and coredns addons enabled")
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040056
57 show_step(2)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040058 deployment = k8s_deployed.run_sample_deployment('test-dep')
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040059
60 show_step(3)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040061 svc = deployment.expose()
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040062
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040063 show_step(4)
Vladimir Jigulin7eb41b02018-10-24 17:03:51 +040064 hostname = "test.{0}.".format(settings.DOMAIN_NAME)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040065 svc.patch({
66 "metadata": {
67 "annotations": {
68 "external-dns.alpha.kubernetes.io/hostname": hostname
69 }
70 }
71 })
Victor Ryzhenkin14354ac2017-09-27 17:42:30 +040072
73 show_step(5)
Vladimir Jigulin90689152018-09-26 15:38:19 +040074 dns_svc = k8s_deployed.api.services.get(
75 name='coredns', namespace='kube-system')
76 k8s_deployed.nslookup(hostname, dns_svc.get_ip())
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +040077
78 show_step(6)
79 deployment.delete()
Victor Ryzhenkin87a31422018-03-16 22:25:27 +040080
81 @pytest.mark.grab_versions
82 @pytest.mark.cncf_publisher(name=['e2e.log', 'junit_01.xml', 'version.txt',
83 'cncf_results.tar.gz'])
84 @pytest.mark.fail_snapshot
85 def test_k8s_cncf_certification(self, show_step, config, k8s_deployed,
Vladimir Jigulin0c8dd5a2018-08-28 05:08:35 +040086 k8s_cncf_log_helper):
Victor Ryzhenkin87a31422018-03-16 22:25:27 +040087 """Run cncf e2e suite and provide files needed for pull request
88 to the CNCF repo
89
90 Scenario:
91 1. Run cncf from https://github.com/cncf/k8s-conformance
92 """
93
94 show_step(1)
95 k8s_deployed.start_k8s_cncf_verification()
Vladimir Jigulin62bcf462018-05-28 18:17:01 +040096
97 @pytest.mark.grap_versions
98 @pytest.mark.fail_snapshot
99 def test_k8s_chain_update(self, show_step, underlay, config, k8s_deployed,
100 k8s_chain_update_log_helper):
101 """Test for chain-upgrading k8s hypercube pool and checking it
102
103 Scenario:
104 1. Prepare salt on hosts
105 2. Setup controller nodes
106 3. Setup compute nodes
107 4. Setup Kubernetes cluster
108 5. Run and expose sample test service
109 6. Run conformance to check consistency
110 7. For every version in update chain:
111 Update cluster to new version, check test sample service
112 availability, run conformance
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400113 8. Delete service and deployment
Vladimir Jigulin62bcf462018-05-28 18:17:01 +0400114 """
115
Vladimir Jigulin62bcf462018-05-28 18:17:01 +0400116 show_step(5)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400117 sample = k8s_deployed.run_sample_deployment('test-dep-chain-upgrade')
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400118 sample.expose()
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400119 sample.wait_ready()
Vladimir Jigulin62bcf462018-05-28 18:17:01 +0400120
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400121 assert sample.is_service_available()
Vladimir Jigulin62bcf462018-05-28 18:17:01 +0400122
123 show_step(6)
124 k8s_deployed.run_conformance(log_out="k8s_conformance.log")
125
126 show_step(7)
127 chain_versions = config.k8s.k8s_update_chain.split(" ")
128 for version in chain_versions:
129 LOG.info("Chain update to '{}' version".format(version))
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400130 k8s_deployed.update_k8s_version(version)
Vladimir Jigulin62bcf462018-05-28 18:17:01 +0400131
132 LOG.info("Checking test service availability")
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400133 assert sample.is_service_available()
Vladimir Jigulin62bcf462018-05-28 18:17:01 +0400134
135 LOG.info("Running conformance on {} version".format(version))
136 log_name = "k8s_conformance_{}.log".format(version)
137 k8s_deployed.run_conformance(log_out=log_name, raise_on_err=False)
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400138
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400139 assert sample.is_service_available()
140
141 show_step(8)
142 sample.delete()
143
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400144 @pytest.mark.grap_versions
145 @pytest.mark.fail_snapshot
Dennis Dmitriev66650fc2018-11-02 11:04:37 +0200146 @pytest.mark.k8s_metallb
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400147 def test_k8s_metallb(self, show_step, config, k8s_deployed):
148 """Enable metallb in cluster and do basic tests
149
150 Scenario:
151 1. Setup Kubernetes cluster with enabled metallb
152 2. Check that metallb pods created in metallb-system namespace
153 3. Run 5 sample deployments
154 4. Expose deployments with type=LoadBalancer
155 5. Check services availability from outside of cluster
156 6. Run conformance
157 7. Check services availability from outside of cluster
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400158 8. Delete deployments
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400159 """
160 show_step(1)
Dennis Dmitriev66650fc2018-11-02 11:04:37 +0200161 if not k8s_deployed.is_metallb_enabled:
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400162 pytest.skip("Test requires metallb addon enabled")
163
164 show_step(2)
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400165 ns = "metallb-system"
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400166 assert \
167 len(k8s_deployed.api.pods.list(ns, name_prefix="controller")) > 0
168 assert \
169 len(k8s_deployed.api.pods.list(ns, name_prefix="speaker")) > 0
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400170
171 show_step(3)
172 samples = []
173 for i in range(5):
174 name = 'test-dep-metallb-{}'.format(i)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400175 samples.append(k8s_deployed.run_sample_deployment(name))
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400176
177 show_step(4)
178 for sample in samples:
179 sample.expose('LoadBalancer')
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400180 sample.wait_ready()
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400181
182 show_step(5)
183 for sample in samples:
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400184 assert sample.is_service_available(external=False)
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400185 assert sample.is_service_available(external=True)
186
187 show_step(6)
188 k8s_deployed.run_conformance()
189
190 show_step(7)
191 for sample in samples:
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400192 assert sample.is_service_available(external=False)
Vladimir Jigulina6b018b2018-07-18 15:19:01 +0400193 assert sample.is_service_available(external=True)
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400194
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400195 show_step(8)
196 for sample in samples:
197 sample.delete()
198
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400199 @pytest.mark.grap_versions
200 @pytest.mark.fail_snapshot
Dennis Dmitrievee5ef232018-08-31 13:53:18 +0300201 @pytest.mark.k8s_genie
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400202 def test_k8s_genie_flannel(self, show_step, config,
203 salt_deployed, k8s_deployed):
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400204 """Test genie-cni+flannel cni setup
205
206 Scenario:
207 1. Setup Kubernetes cluster with genie cni and flannel
208 2. Check that flannel pods created in kube-system namespace
209 3. Create sample deployment with flannel cni annotation
210 4. Check that the deployment have 1 ip addresses from cni provider
211 5. Create sample deployment with calico cni annotation
212 6. Check that the deployment have 1 ip addresses from cni provider
213 7. Create sample deployment with multi-cni annotation
214 8. Check that the deployment have 2 ip addresses from different
215 cni providers
216 9. Create sample deployment without cni annotation
217 10. Check that the deployment have 1 ip address
218 11. Check pods availability
219 12. Run conformance
220 13. Check pods availability
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400221 14. Delete pods
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400222 """
223 show_step(1)
224
225 # Find out calico and flannel networks
Victor Ryzhenkin0c373822018-10-30 17:55:50 +0400226 tgt_k8s_control = "I@kubernetes:master"
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400227
228 flannel_pillar = salt_deployed.get_pillar(
229 tgt=tgt_k8s_control,
230 pillar="kubernetes:master:network:flannel:private_ip_range")[0]
231 flannel_network = netaddr.IPNetwork(flannel_pillar.values()[0])
232 LOG.info("Flannel network: {}".format(flannel_network))
233
234 calico_network_pillar = salt_deployed.get_pillar(
235 tgt=tgt_k8s_control, pillar="_param:calico_private_network")[0]
236 calico_netmask_pillar = salt_deployed.get_pillar(
237 tgt=tgt_k8s_control, pillar="_param:calico_private_netmask")[0]
238 calico_network = netaddr.IPNetwork(
239 "{0}/{1}".format(calico_network_pillar.values()[0],
240 calico_netmask_pillar.values()[0]))
241 LOG.info("Calico network: {}".format(calico_network))
242
243 show_step(2)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400244 assert k8s_deployed.api.pods.list(
245 namespace="kube-system", name_prefix="kube-flannel-") > 0
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400246
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400247 show_step(3)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400248 flannel_pod = k8s_deployed.api.pods.create(
Vladimir Jigulin57ecae92018-09-10 22:51:15 +0400249 body=self.__read_testdata_yaml('pod-sample-flannel.yaml'))
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400250 flannel_pod.wait_running()
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400251
252 show_step(4)
253 flannel_ips = k8s_deployed.get_pod_ips_from_container(flannel_pod.name)
254 assert len(flannel_ips) == 1
255 assert netaddr.IPAddress(flannel_ips[0]) in flannel_network
256
257 show_step(5)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400258 calico_pod = k8s_deployed.api.pods.create(
Vladimir Jigulin57ecae92018-09-10 22:51:15 +0400259 body=self.__read_testdata_yaml('pod-sample-calico.yaml'))
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400260 calico_pod.wait_running()
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400261
262 show_step(6)
263 calico_ips = k8s_deployed.get_pod_ips_from_container(calico_pod.name)
264 assert len(calico_ips) == 1
265 assert netaddr.IPAddress(calico_ips[0]) in calico_network
266
267 show_step(7)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400268 multicni_pod = k8s_deployed.api.pods.create(
Vladimir Jigulin57ecae92018-09-10 22:51:15 +0400269 body=self.__read_testdata_yaml('pod-sample-multicni.yaml'))
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400270 multicni_pod.wait_running()
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400271
272 show_step(8)
273 multicni_ips = \
274 k8s_deployed.get_pod_ips_from_container(multicni_pod.name)
275 assert len(multicni_ips) == 2
276 for net in [calico_network, flannel_network]:
277 assert netaddr.IPAddress(multicni_ips[0]) in net or \
278 netaddr.IPAddress(multicni_ips[1]) in net
279
280 show_step(9)
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400281 nocni_pod = k8s_deployed.api.pods.create(
Vladimir Jigulin57ecae92018-09-10 22:51:15 +0400282 body=self.__read_testdata_yaml('pod-sample.yaml'))
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400283 nocni_pod.wait_running()
Vladimir Jigulin34dfa942018-07-23 21:05:48 +0400284
285 show_step(10)
286 nocni_ips = k8s_deployed.get_pod_ips_from_container(nocni_pod.name)
287 assert len(nocni_ips) == 1
288 assert (netaddr.IPAddress(nocni_ips[0]) in calico_network or
289 netaddr.IPAddress(nocni_ips[0]) in flannel_network)
290
291 show_step(11)
292
293 def check_pod_availability(ip):
294 assert "Hello Kubernetes!" in k8s_deployed.curl(
295 "http://{}:8080".format(ip))
296
297 def check_pods_availability():
298 check_pod_availability(flannel_ips[0])
299 check_pod_availability(calico_ips[0])
300 check_pod_availability(multicni_ips[0])
301 check_pod_availability(multicni_ips[1])
302 check_pod_availability(nocni_ips[0])
303
304 check_pods_availability()
305
306 show_step(12)
307 k8s_deployed.run_conformance()
308
309 show_step(13)
310 check_pods_availability()
Vladimir Jigulin4ad52a82018-08-12 05:51:30 +0400311
312 show_step(14)
313 flannel_pod.delete()
314 calico_pod.delete()
315 multicni_pod.delete()
316 nocni_pod.delete()
Vladimir Jigulin57ecae92018-09-10 22:51:15 +0400317
318 @pytest.mark.grap_versions
319 @pytest.mark.fail_snapshot
Dennis Dmitriev66650fc2018-11-02 11:04:37 +0200320 @pytest.mark.k8s_dashboard
Vladimir Jigulin57ecae92018-09-10 22:51:15 +0400321 def test_k8s_dashboard(self, show_step, config,
322 salt_deployed, k8s_deployed):
323 """Test dashboard setup
324
325 Scenario:
326 1. Setup Kubernetes cluster
327 2. Try to curl login status api
328 3. Create a test-admin-user account
329 4. Try to login in dashboard using test-admin-user account
330 5. Get and check list of namespaces using dashboard api
331 """
332 show_step(1)
333
334 show_step(2)
335 system_ns = 'kube-system'
336 dashboard_service = \
337 k8s_deployed.api.services.get('kubernetes-dashboard', system_ns)
338 dashboard_url = 'https://{}'.format(dashboard_service.get_ip())
339
340 def dashboard_curl(url, data=None, headers=None):
341 """ Using curl command on controller node. Alternatives:
342 - connect_{get,post}_namespaced_service_proxy_with_path -
343 k8s lib does not provide way to pass headers or POST data
344 - raw rest k8s api - need to auth somehow
345 - new load-balancer svc for dashboard + requests python lib -
346 requires working metallb or other load-balancer
347 """
348 args = ['--insecure']
349 for name in headers or {}:
350 args.append('--header')
351 args.append("{0}: {1}".format(name, headers[name]))
352 if data is not None:
353 args.append('--data')
354 args.append(data)
355 return ''.join(k8s_deployed.curl(dashboard_url + url, *args))
356
357 assert 'tokenPresent' in \
358 json.loads(dashboard_curl('/api/v1/login/status'))
359
360 show_step(3)
361 account = k8s_deployed.api.serviceaccounts.create(
362 namespace=system_ns,
363 body=self.__read_testdata_yaml('test-admin-user-account.yaml'))
364 account.wait_secret_generation()
365
366 k8s_deployed.api.clusterrolebindings.create(
367 body=self.__read_testdata_yaml(
368 'test-admin-user-cluster-role-bind.yaml'))
369
370 account_secret = account.read().secrets[0]
371 account_token = k8s_deployed.api.secrets.get(
372 namespace=system_ns, name=account_secret.name).read().data['token']
373
374 show_step(4)
375 csrf_token = \
376 json.loads(dashboard_curl('/api/v1/csrftoken/login'))['token']
377 login_headers = {'X-CSRF-TOKEN': csrf_token,
378 'Content-Type': 'application/json'}
379 jwe_token = json.loads(dashboard_curl(
380 '/api/v1/login', headers=login_headers,
381 data=json.dumps({'token': account_token.decode('base64')})
382 ))['jweToken']
383 headers = {'jweToken': jwe_token}
384
385 show_step(5)
386 dashboard_namespaces = json.loads(
387 dashboard_curl('/api/v1/namespace', headers=headers))['namespaces']
388
389 namespaces_names_list = \
390 [ns.name for ns in k8s_deployed.api.namespaces.list()]
391 for namespace in dashboard_namespaces:
392 assert namespace['objectMeta']['name'] in namespaces_names_list
Vladimir Jigulin5775bbb2018-10-03 10:34:54 +0400393
394 @pytest.mark.grap_versions
395 @pytest.mark.fail_snapshot
Dennis Dmitriev66650fc2018-11-02 11:04:37 +0200396 @pytest.mark.k8s_ingress_nginx
Vladimir Jigulin5775bbb2018-10-03 10:34:54 +0400397 def test_k8s_ingress_nginx(self, show_step, config,
398 salt_deployed, k8s_deployed):
399 """Test ingress-nginx configured and working with metallb
400
401 Scenario:
402 1. Setup Kubernetes cluster with metallb
403 2. Create 2 example deployments and expose them
404 3. Create ingress controller with 2 backends to each deployment
405 service respectively
406 4. Wait ingress for deploy
407 5. Try to reach default endpoint
408 6. Try to reach test1 and test2 deployment services endpoints
409 """
410 show_step(1)
Dennis Dmitriev66650fc2018-11-02 11:04:37 +0200411 if not k8s_deployed.is_metallb_enabled:
Vladimir Jigulin5775bbb2018-10-03 10:34:54 +0400412 pytest.skip("Test requires metallb addon enabled")
Dennis Dmitriev66650fc2018-11-02 11:04:37 +0200413 if not k8s_deployed.is_ingress_nginx_enabled:
Vladimir Jigulin5775bbb2018-10-03 10:34:54 +0400414 pytest.skip("Test requires ingress-nginx addon enabled")
415
416 show_step(2)
417 image = 'nginxdemos/hello:plain-text'
418 port = 80
419 dep1 = k8s_deployed.run_sample_deployment(
420 'dep-ingress-1', image=image, port=port)
421 dep2 = k8s_deployed.run_sample_deployment(
422 'dep-ingress-2', image=image, port=port)
423 svc1 = dep1.wait_ready().expose()
424 svc2 = dep2.wait_ready().expose()
425
426 show_step(3)
427 body = {
428 'apiVersion': 'extensions/v1beta1',
429 'kind': 'Ingress',
430 'metadata': {'name': 'ingress-test'},
431 'spec': {
432 'rules': [{'http': {
433 'paths': [{
434 'backend': {
435 'serviceName': svc1.name,
436 'servicePort': port},
437 'path': '/test1'}, {
438 'backend': {
439 'serviceName': svc2.name,
440 'servicePort': port},
441 'path': '/test2'
442 }]
443 }}]
444 }
445 }
446 ingress = k8s_deployed.api.ingresses.create(body=body)
447
448 show_step(4)
449 ingress.wait_ready()
450
451 show_step(5)
452 ingress_address = "https://{}".format(
453 ingress.read().status.load_balancer.ingress[0].ip)
454
455 assert requests.get(ingress_address, verify=False).status_code == 404
456
457 show_step(6)
458 req1 = requests.get(ingress_address + "/test1", verify=False)
459 assert req1.status_code == 200
460 assert 'dep-ingress-1' in req1.text
461
462 req2 = requests.get(ingress_address + "/test2", verify=False)
463 assert req2.status_code == 200
464 assert 'dep-ingress-2' in req2.text