Use Path.home() instead of ~
[functest-kubernetes.git] / functest_kubernetes / k8stest.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2018 All rights reserved
4 # This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10
11 """
12 Define the parent for Kubernetes testing.
13 """
14
15 from __future__ import division
16
17 import logging
18 import os
19 from pathlib import Path
20 import re
21 import subprocess
22 import time
23 import yaml
24
25 from xtesting.core import testcase
26
27
28 class E2ETesting(testcase.TestCase):
29     """Kubernetes test runner"""
30     # pylint: disable=too-many-instance-attributes
31
32     __logger = logging.getLogger(__name__)
33
34     config = f'{Path.home()}/.kube/config'
35     gcr_repo = os.getenv("MIRROR_REPO", "gcr.io")
36     k8s_gcr_repo = os.getenv("MIRROR_REPO", "k8s.gcr.io")
37
38     def __init__(self, **kwargs):
39         super().__init__(**kwargs)
40         self.cmd = []
41         self.dir_results = "/home/opnfv/functest/results"
42         self.res_dir = os.path.join(self.dir_results, self.case_name)
43         self.result = 0
44         self.start_time = 0
45         self.stop_time = 0
46         self.output_log_name = 'functest-kubernetes.log'
47         self.output_debug_log_name = 'functest-kubernetes.debug.log'
48
49     @staticmethod
50     def convert_ini_to_dict(value):
51         "Convert oslo.conf input to dict"
52         assert isinstance(value, str)
53         try:
54             return dict((x.rsplit(':', 1) for x in value.split(',')))
55         except ValueError:
56             return {}
57
58     def run_kubetest(self, **kwargs):  # pylint: disable=too-many-branches
59         """Run the test suites"""
60         cmd_line = [
61             'ginkgo', f'--nodes={kwargs.get("nodes", 1)}',
62             '--no-color', '/usr/local/bin/e2e.test', '--',
63             '-kubeconfig', self.config,
64             '-provider', kwargs.get('provider', 'local'),
65             '-report-dir', self.res_dir]
66         for arg in kwargs.get("ginkgo", {}):
67             cmd_line.extend([f'-ginkgo.{arg}', kwargs["ginkgo"][arg]])
68         for key, value in self.convert_ini_to_dict(
69                 os.environ.get("E2E_TEST_OPTS", "")).items():
70             cmd_line.extend([f'-{key}', value])
71         if "NON_BLOCKING_TAINTS" in os.environ:
72             cmd_line.extend(
73                 ['-non-blocking-taints', os.environ["NON_BLOCKING_TAINTS"]])
74         cmd_line.extend(['-disable-log-dump', 'true'])
75         self._generate_repo_list_file()
76         self.__logger.info("Starting k8s test: '%s'.", cmd_line)
77         env = os.environ.copy()
78         env["KUBE_TEST_REPO_LIST"] = f"{self.res_dir}/repositories.yml"
79         with subprocess.Popen(
80                 cmd_line, stdout=subprocess.PIPE,
81                 stderr=subprocess.STDOUT, env=env) as process:
82             boutput = process.stdout.read()
83         with open(os.path.join(
84                 self.res_dir, 'e2e.log'), 'w', encoding='utf-8') as foutput:
85             foutput.write(boutput.decode("utf-8"))
86         grp = re.search(
87             r'^(FAIL|SUCCESS)!.* ([0-9]+) Passed \| ([0-9]+) Failed \|'
88             r' ([0-9]+) Pending \| ([0-9]+) Skipped',
89             boutput.decode("utf-8", errors="ignore"),
90             re.MULTILINE | re.DOTALL)
91         assert grp
92         self.details['passed'] = int(grp.group(2))
93         self.details['failed'] = int(grp.group(3))
94         self.details['pending'] = int(grp.group(4))
95         self.details['skipped'] = int(grp.group(5))
96         self.__logger.debug("details: %s", self.details)
97         self.result = self.details['passed'] * 100 / (
98             self.details['passed'] + self.details['failed'] +
99             self.details['pending'])
100         self.__logger.debug("result: %s", self.result)
101         if grp.group(1) == 'FAIL':
102             grp2 = re.search(
103                 r'^(Summarizing [0-9]+ Failure.*)Ran',
104                 boutput.decode("utf-8", errors="ignore"),
105                 re.MULTILINE | re.DOTALL)
106             if grp2:
107                 self.__logger.error(grp2.group(1))
108
109     def run(self, **kwargs):
110         if not os.path.exists(self.res_dir):
111             os.makedirs(self.res_dir)
112         if not os.path.isfile(self.config):
113             self.__logger.error(
114                 "Cannot run k8s testcases. Config file not found")
115             return self.EX_RUN_ERROR
116         self.start_time = time.time()
117         try:
118             self.run_kubetest(**kwargs)
119             res = self.EX_OK
120         except Exception:  # pylint: disable=broad-except
121             self.__logger.exception("Error with running kubetest:")
122             res = self.EX_RUN_ERROR
123         self.stop_time = time.time()
124         return res
125
126     def _generate_repo_list_file(self):
127         """Generate the repositories list for the test."""
128         # The list is taken from
129         # https://github.com/kubernetes/kubernetes/blob/master/test/utils/image/manifest.go
130         # It may needs update regularly
131         gcr_repo = os.getenv("GCR_REPO", self.gcr_repo)
132         k8s_gcr_repo = os.getenv("K8S_GCR_REPO", self.k8s_gcr_repo)
133         repo_list = {
134             "GcAuthenticatedRegistry":
135                 f"{gcr_repo}/authenticated-image-pulling",
136             "E2eRegistry": f"{gcr_repo}/kubernetes-e2e-test-images",
137             "PromoterE2eRegistry": f"{k8s_gcr_repo}/e2e-test-images",
138             "BuildImageRegistry": f"{k8s_gcr_repo}/build-image",
139             "InvalidRegistry": "invalid.com/invalid",
140             "GcEtcdRegistry": k8s_gcr_repo,
141             "GcRegistry": k8s_gcr_repo,
142             "SigStorageRegistry": f"{k8s_gcr_repo}/sig-storage",
143             "PrivateRegistry": f"{gcr_repo}/k8s-authenticated-test",
144             "SampleRegistry": f"{gcr_repo}/google-samples",
145             "GcrReleaseRegistry": f"{gcr_repo}/gke-release",
146             "MicrosoftRegistry": "mcr.microsoft.com"
147         }
148         with open(
149                 f"{self.res_dir}/repositories.yml", 'w',
150                 encoding='utf-8') as file:
151             yaml.dump(repo_list, file)