Tatyana Leontovich | c8b8ca2 | 2017-05-19 13:37:05 +0300 | [diff] [blame] | 1 | # Copyright 2016 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 | |
Tatyana Leontovich | 063d0ff | 2017-09-05 18:11:55 +0300 | [diff] [blame] | 15 | import os |
| 16 | |
Dennis Dmitriev | 9d9ba9f | 2017-09-13 17:34:03 +0300 | [diff] [blame] | 17 | from devops.helpers import decorators |
| 18 | |
Tatyana Leontovich | c8b8ca2 | 2017-05-19 13:37:05 +0300 | [diff] [blame] | 19 | from tcp_tests.managers.execute_commands import ExecuteCommandsMixin |
Tatyana Leontovich | 09b7b01 | 2017-07-10 12:53:45 +0300 | [diff] [blame] | 20 | from tcp_tests.managers.clients.prometheus import prometheus_client |
Tatyana Leontovich | 126b003 | 2017-08-30 20:51:20 +0300 | [diff] [blame] | 21 | from tcp_tests import logger |
| 22 | |
| 23 | LOG = logger.logger |
Tatyana Leontovich | c8b8ca2 | 2017-05-19 13:37:05 +0300 | [diff] [blame] | 24 | |
| 25 | |
| 26 | class SLManager(ExecuteCommandsMixin): |
| 27 | """docstring for OpenstackManager""" |
| 28 | |
| 29 | __config = None |
| 30 | __underlay = None |
| 31 | |
| 32 | def __init__(self, config, underlay, salt): |
| 33 | self.__config = config |
| 34 | self.__underlay = underlay |
| 35 | self._salt = salt |
Tatyana Leontovich | 09b7b01 | 2017-07-10 12:53:45 +0300 | [diff] [blame] | 36 | self._p_client = None |
Tatyana Leontovich | c8b8ca2 | 2017-05-19 13:37:05 +0300 | [diff] [blame] | 37 | super(SLManager, self).__init__( |
| 38 | config=config, underlay=underlay) |
| 39 | |
| 40 | def install(self, commands): |
| 41 | self.execute_commands(commands, |
| 42 | label='Install SL services') |
vrovachev | 700a7b0 | 2017-05-23 18:36:48 +0400 | [diff] [blame] | 43 | self.__config.stack_light.sl_installed = True |
Tatyana Leontovich | 09b7b01 | 2017-07-10 12:53:45 +0300 | [diff] [blame] | 44 | self.__config.stack_light.sl_vip_host = self.get_sl_vip() |
| 45 | |
| 46 | def get_sl_vip(self): |
| 47 | sl_vip_address_pillars = self._salt.get_pillar( |
| 48 | tgt='I@keepalived:cluster:enabled:true and not ctl*', |
| 49 | pillar='keepalived:cluster:instance:prometheus_server_vip:address') |
| 50 | sl_vip_ip = set([ip |
| 51 | for item in sl_vip_address_pillars |
| 52 | for node,ip in item.items() if ip]) |
| 53 | assert len(sl_vip_ip) == 1, ( |
| 54 | "Found more than one SL VIP in pillars:{0}, " |
| 55 | "expected one!").format(sl_vip_ip) |
| 56 | sl_vip_ip_host = sl_vip_ip.pop() |
| 57 | return sl_vip_ip_host |
| 58 | |
| 59 | @property |
| 60 | def api(self): |
| 61 | if self._p_client is None: |
| 62 | self._p_client = prometheus_client.PrometheusClient( |
| 63 | host=self.__config.stack_light.sl_vip_host, |
| 64 | port=self.__config.stack_light.sl_prometheus_port, |
| 65 | proto=self.__config.stack_light.sl_prometheus_proto) |
| 66 | return self._p_client |
Tatyana Leontovich | 126b003 | 2017-08-30 20:51:20 +0300 | [diff] [blame] | 67 | |
| 68 | def get_monitoring_nodes(self): |
| 69 | return [node_name for node_name |
| 70 | in self.__underlay.node_names() if 'mon' in node_name] |
| 71 | |
| 72 | def get_service_info_from_node(self, node_name): |
| 73 | service_stat_dict = {} |
| 74 | with self.__underlay.remote(node_name=node_name) as node_remote: |
| 75 | result = node_remote.execute( |
| 76 | "docker service ls --format '{{.Name}}:{{.Replicas}}'") |
| 77 | LOG.debug("Service ls result {0} from node {1}".format( |
| 78 | result['stdout'], node_name)) |
| 79 | for line in result['stdout']: |
| 80 | tmp = line.split(':') |
| 81 | service_stat_dict.update({tmp[0]: tmp[1]}) |
| 82 | return service_stat_dict |
Tatyana Leontovich | 063d0ff | 2017-09-05 18:11:55 +0300 | [diff] [blame] | 83 | |
| 84 | def run_sl_functional_tests(self, node_to_run, path_tests_to_run): |
| 85 | target_node_name = [node_name for node_name |
| 86 | in self.__underlay.node_names() |
| 87 | if node_to_run in node_name] |
| 88 | with self.__underlay.remote(node_name=target_node_name[0]) as node_remote: |
Tatyana Leontovich | 8cce8b6 | 2017-09-13 12:55:44 +0300 | [diff] [blame] | 89 | cmd = "pytest -k {}".format(path_tests_to_run) |
Tatyana Leontovich | 063d0ff | 2017-09-05 18:11:55 +0300 | [diff] [blame] | 90 | result = node_remote.execute(cmd) |
| 91 | LOG.debug("Test execution result is {}".format(result)) |
| 92 | return result |
| 93 | |
| 94 | def download_sl_test_report(self, stored_node, file_path): |
| 95 | target_node_name = [node_name for node_name |
| 96 | in self.__underlay.node_names() |
| 97 | if stored_node in node_name] |
| 98 | with self.__underlay.remote(node_name=target_node_name[0]) as r: |
| 99 | r.download( |
| 100 | destination=file_path, |
| 101 | target=os.getcwd()) |
Dennis Dmitriev | 9d9ba9f | 2017-09-13 17:34:03 +0300 | [diff] [blame] | 102 | |
| 103 | def check_docker_services(self, nodes, expected_services): |
| 104 | """Check presense of the specified docker services on all the nodes |
| 105 | :param nodes: list of strings, names of nodes to check |
| 106 | :param expected_services: list of strings, names of services to find |
| 107 | """ |
| 108 | for node in nodes: |
| 109 | services_status = self.get_service_info_from_node(node) |
| 110 | assert len(services_status) == len(expected_services), \ |
| 111 | 'Some services are missed on node {0}. ' \ |
| 112 | 'Current service list: {1}\nExpected service list: {2}' \ |
| 113 | .format(node, services_status, expected_services) |
| 114 | for service in expected_services: |
| 115 | assert service in services_status,\ |
| 116 | 'Missing service {0} in {1}'.format(service, services_status) |
| 117 | assert '0' not in services_status.get(service),\ |
| 118 | 'Service {0} failed to start'.format(service) |
| 119 | |
| 120 | @decorators.retry(AssertionError, count=10, delay=5) |
| 121 | def check_prometheus_targets(self, nodes): |
| 122 | """Check the status for Prometheus targets |
| 123 | :param nodes: list of strings, names of nodes with keepalived VIP |
| 124 | """ |
| 125 | prometheus_client = self.api |
| 126 | try: |
| 127 | current_targets = prometheus_client.get_targets() |
| 128 | except: |
| 129 | LOG.info('Restarting keepalived service on mon nodes...') |
| 130 | for node in nodes: |
| 131 | self._salt.local(tgt=node, fun='cmd.run', |
| 132 | args='systemctl restart keepalived') |
| 133 | LOG.warning( |
| 134 | 'Ip states after force restart {0}'.format( |
| 135 | self._salt.local(tgt='mon*', |
| 136 | fun='cmd.run', args='ip a'))) |
| 137 | current_targets = prometheus_client.get_targets() |
| 138 | |
| 139 | LOG.debug('Current targets after install {0}' |
| 140 | .format(current_targets)) |
| 141 | # Assert that targets are up |
| 142 | for entry in current_targets: |
| 143 | assert 'up' in entry['health'], \ |
| 144 | 'Next target is down {}'.format(entry) |
| 145 | |
| 146 | |