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