Fix the search algorithm
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / rapid / rapid_k8s_pod.py
1 ##
2 ## Copyright (c) 2019 Intel Corporation
3 ##
4 ## Licensed under the Apache License, Version 2.0 (the "License");
5 ## you may not use this file except in compliance with the License.
6 ## You may obtain a copy of the License at
7 ##
8 ##     http://www.apache.org/licenses/LICENSE-2.0
9 ##
10 ## Unless required by applicable law or agreed to in writing, software
11 ## distributed under the License is distributed on an "AS IS" BASIS,
12 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ## See the License for the specific language governing permissions and
14 ## limitations under the License.
15 ##
16
17 from os import path
18 import time, yaml
19 import logging
20 from kubernetes import client, config
21
22 from rapid_sshclient import SSHClient
23
24 class Pod:
25     """Class which represents test pods.
26     For example with traffic gen, forward/swap applications, etc
27     """
28     k8s_CoreV1Api = None
29
30     _log = None
31
32     _name = "pod"
33     _namespace = "default"
34     _nodeSelector_hostname = None
35     _last_status = None
36     _id = None
37     _admin_ip = None
38     _dp_ip = None
39     _dp_subnet = None
40
41     _ssh_client = None
42
43     _sriov_vf = None
44     _sriov_vf_mac = None
45
46     def __init__(self, name, namespace = "default", logger_name = "k8srapid"):
47         self._log = logging.getLogger(logger_name)
48
49         self._name = name
50         self._namespace = namespace
51         self._ssh_client = SSHClient(logger_name = logger_name)
52
53     def __del__(self):
54         """Destroy POD. Do a cleanup.
55         """
56         if self._ssh_client is not None:
57             self._ssh_client.disconnect()
58
59     def create_from_yaml(self, file_name):
60         """Load POD description from yaml file.
61         """
62         with open(path.join(path.dirname(__file__), file_name)) as yaml_file:
63             self.body = yaml.safe_load(yaml_file)
64
65             self.body["metadata"]["name"] = self._name
66
67             if (self._nodeSelector_hostname is not None):
68                 if ("nodeSelector" not in self.body["spec"]):
69                     self.body["spec"]["nodeSelector"] = {}
70                 self.body["spec"]["nodeSelector"]["kubernetes.io/hostname"] = self._nodeSelector_hostname
71             self._log.debug("Creating POD, body:\n%s" % self.body)
72
73             try:
74                 self.k8s_CoreV1Api.create_namespaced_pod(body = self.body,
75                                                 namespace = self._namespace)
76             except client.rest.ApiException as e:
77                 self._log.error("Couldn't create POD %s!\n%s\n" % (self._name, e))
78
79     def terminate(self):
80         """Terminate POD. Close SSH connection.
81         """
82         if self._ssh_client is not None:
83             self._ssh_client.disconnect()
84
85         try:
86             self.k8s_CoreV1Api.delete_namespaced_pod(name = self._name,
87                                                      namespace = self._namespace)
88         except client.rest.ApiException as e:
89             if e.reason != "Not Found":
90                 self._log.error("Couldn't delete POD %s!\n%s\n" % (self._name, e.reason))
91
92     def update_admin_ip(self):
93         """Check for admin IP address assigned by k8s.
94         """
95         try:
96             pod = self.k8s_CoreV1Api.read_namespaced_pod_status(name = self._name, namespace = self._namespace)
97             self._admin_ip = pod.status.pod_ip
98         except client.rest.ApiException as e:
99             self._log.error("Couldn't update POD %s admin IP!\n%s\n" % (self._name, e))
100
101     def wait_for_start(self):
102         """Wait for POD to start.
103         """
104         self._log.info("Waiting for POD %s to start..." % self._name)
105         while True:
106             self.get_status()
107             if (self._last_status == "Running" or self._last_status == "Failed"
108                 or self._last_status == "Unknown"):
109                 break
110             else:
111                 time.sleep(3)
112
113         self.update_admin_ip()
114
115         return self._last_status
116
117     def ssh_run_cmd(self, cmd):
118         """Execute command for POD via SSH connection.
119         SSH credentials should be configured before use of this function.
120         """
121         self._ssh_client.run_cmd(cmd)
122
123     def get_name(self):
124         return self._name
125
126     def get_admin_ip(self):
127         return self._admin_ip
128
129     def get_dp_ip(self):
130         return self._dp_ip
131
132     def get_dp_subnet(self):
133         return self._dp_subnet
134
135     def get_dp_mac(self):
136         return self._sriov_vf_mac
137
138     def get_dp_pci_dev(self):
139         return self._sriov_vf
140
141     def get_id(self):
142         return self._id
143
144     def get_status(self):
145         """Get current status fro the pod.
146         """
147         try:
148             pod = self.k8s_CoreV1Api.read_namespaced_pod_status(name = self._name,
149                                                                 namespace = self._namespace)
150         except client.rest.ApiException as e:
151             self._log.error("Couldn't read POD %s status!\n%s\n" % (self._name, e))
152
153         self._last_status = pod.status.phase
154         return self._last_status
155
156     def get_sriov_dev_mac(self):
157         """Get assigned by k8s SRIOV network device plugin SRIOV VF devices.
158         Return 0 in case of sucessfull configuration.
159         Otherwise return -1.
160         """
161         self._log.info("Checking assigned SRIOV VF for POD %s" % self._name)
162         ret = self._ssh_client.run_cmd("cat /opt/rapid/k8s_sriov_device_plugin_envs")
163         if ret != 0:
164             self._log.error("Failed to check assigned SRIOV VF!"
165                             "Error %s" % self._ssh_client.get_error())
166             return -1
167
168         cmd_output = self._ssh_client.get_output().decode("utf-8").rstrip()
169         self._log.debug("Environment variable %s" % cmd_output)
170
171         # Parse environment variable
172         cmd_output = cmd_output.split("=")[1]
173         self._sriov_vf = cmd_output.split(",")[0]
174         self._log.debug("Using first SRIOV VF %s" % self._sriov_vf)
175
176         self._log.info("Getting MAC address for assigned SRIOV VF %s" % self._sriov_vf)
177         self._ssh_client.run_cmd("sudo /opt/rapid/port_info_app -n 4 -w %s" % self._sriov_vf)
178         if ret != 0:
179             self._log.error("Failed to get MAC address!"
180                             "Error %s" % self._ssh_client.get_error())
181             return -1
182
183         # Parse MAC address
184         cmd_output = self._ssh_client.get_output().decode("utf-8").rstrip()
185         self._log.debug(cmd_output)
186         cmd_output = cmd_output.splitlines()
187         for line in cmd_output:
188             if line.startswith("Port 0 MAC: "):
189                 self._sriov_vf_mac = line[12:]
190
191         self._log.debug("MAC %s" % self._sriov_vf_mac)
192
193     def set_dp_ip(self, dp_ip):
194         self._dp_ip = dp_ip
195
196     def set_dp_subnet(self, dp_subnet):
197         self._dp_subnet = dp_subnet
198
199     def set_id(self, pod_id):
200         self._id = pod_id
201
202     def set_nodeselector(self, hostname):
203         """Set hostname on which POD will be executed.
204         """
205         self._nodeSelector_hostname = hostname
206
207     def set_ssh_credentials(self, user, rsa_private_key):
208         """Set SSH credentials for the SSH connection to the POD.
209         """
210         self.update_admin_ip()
211         self._ssh_client.set_credentials(ip = self._admin_ip,
212                                          user = user,
213                                          rsa_private_key = rsa_private_key)