# Copyright (c) 2018 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Library to control Kubernetes kubectl.""" from time import sleep from resources.libraries.python.Constants import Constants from resources.libraries.python.topology import NodeType from resources.libraries.python.ssh import SSH, exec_cmd_no_error from resources.libraries.python.CpuUtils import CpuUtils from resources.libraries.python.VppConfigGenerator import VppConfigGenerator __all__ = ["KubernetesUtils"] # Maximum number of retries to check if PODs are running or deleted. MAX_RETRY = 48 class KubernetesUtils(object): """Kubernetes utilities class.""" def __init__(self): """Initialize KubernetesUtils class.""" pass @staticmethod def load_docker_image_on_node(node, image_path): """Load Docker container image from file on node. :param node: DUT node. :param image_path: Container image path. :type node: dict :type image_path: str :raises RuntimeError: If loading image failed on node. """ command = 'docker load -i {image_path}'.\ format(image_path=image_path) message = 'Failed to load Docker image on {node}.'.\ format(node=node['host']) exec_cmd_no_error(node, command, timeout=240, sudo=True, message=message) command = "docker rmi $(sudo docker images -f 'dangling=true' -q)".\ format(image_path=image_path) message = 'Failed to clean Docker images on {node}.'.\ format(node=node['host']) try: exec_cmd_no_error(node, command, timeout=240, sudo=True, message=message) except RuntimeError: pass @staticmethod def load_docker_image_on_all_duts(nodes, image_path): """Load Docker container image from file on all DUTs. :param nodes: Topology nodes. :param image_path: Container image path. :type nodes: dict :type image_path: str """ for node in nodes.values(): if node['type'] == NodeType.DUT: KubernetesUtils.load_docker_image_on_node(node, image_path) @staticmethod def setup_kubernetes_on_node(node): """Set up Kubernetes on node. :param node: DUT node. :type node: dict :raises RuntimeError: If Kubernetes setup failed on node. """ ssh = SSH() ssh.connect(node) cmd = '{dir}/{lib}/k8s_setup.sh deploy_calico'\ .format(dir=Constants.REMOTE_FW_DIR, lib=Constants.RESOURCES_LIB_SH) (ret_code, _, _) = ssh.exec_command(cmd, timeout=240) if int(ret_code) != 0: raise RuntimeError('Failed to setup Kubernetes on {node}.' .format(node=node['host'])) KubernetesUtils.wait_for_kubernetes_pods_on_node(node, nspace='kube-system') @staticmethod def setup_kubernetes_on_all_duts(nodes): """Set up Kubernetes on all DUTs. :param nodes: Topology nodes. :type nodes: dict """ for node in nodes.values(): if node['type'] == NodeType.DUT: KubernetesUtils.setup_kubernetes_on_node(node) @staticmethod def destroy_kubernetes_on_node(node): """Destroy Kubernetes on node. :param node: DUT node. :type node: dict :raises RuntimeError: If destroying Kubernetes failed. """ ssh = SSH() ssh.connect(node) cmd = '{dir}/{lib}/k8s_setup.sh destroy'\ .format(dir=Constants.REMOTE_FW_DIR, lib=Constants.RESOURCES_LIB_SH) (ret_code, _, _) = ssh.exec_command(cmd, timeout=120) if int(ret_code) != 0: raise RuntimeError('Failed to destroy Kubernetes on {node}.' .format(node=node['host'])) @staticmethod def destroy_kubernetes_on_all_duts(nodes): """Destroy Kubernetes on all DUTs. :param nodes: Topology nodes. :type nodes: dict """ for node in nodes.values(): if node['type'] == NodeType.DUT: KubernetesUtils.destroy_kubernetes_on_node(node) @staticmethod def apply_kubernetes_resource_on_node(node, yaml_file, **kwargs): """Apply Kubernetes resource on node. :param node: DUT node. :param yaml_file: YAML configuration file. :param kwargs: Key-value pairs to replace in YAML template. :type node: dict :type yaml_file: str :type kwargs: dict :raises RuntimeError: If applying Kubernetes template failed. """ ssh = SSH() ssh.connect(node) fqn_file = '{tpl}/{yaml}'.format(tpl=Constants.RESOURCES_TPL_K8S, yaml=yaml_file) with open(fqn_file, 'r') as src_file: stream = src_file.read() data = reduce(lambda a, kv: a.replace(*kv), kwargs.iteritems(), stream) cmd = 'cat <