blob: e29cdd656f4d5f29eef167b24c1f67ecf7cb804e [file] [log] [blame]
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +02001# 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
Dennis Dmitriev2d643bc2017-12-04 12:23:47 +020015from tcp_tests.helpers import exceptions
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030016from tcp_tests.managers.execute_commands import ExecuteCommandsMixin
Dennis Dmitriev2d643bc2017-12-04 12:23:47 +020017from tcp_tests import logger
18
19LOG = logger.logger
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030020
21
22class CommonServicesManager(ExecuteCommandsMixin):
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020023 """docstring for CommonServicesManager"""
24
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030025 __config = None
26 __underlay = None
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020027
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030028 def __init__(self, config, underlay, salt=None):
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030029 self.__config = config
30 self.__underlay = underlay
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030031 self._salt = salt
Dmitry Tyzhnenko54b415b2017-04-28 16:14:47 +030032 super(CommonServicesManager, self).__init__(
33 config=config, underlay=underlay)
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020034
35 def install(self, commands):
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030036 self.execute_commands(commands,
37 label='Install common services')
vrovachev700a7b02017-05-23 18:36:48 +040038 self.__config.common_services.common_services_installed = True
Dennis Dmitriev2d643bc2017-12-04 12:23:47 +020039
40 def get_keepalived_vip_minion_id(self, vip):
41 """Get minion ID where keepalived VIP is at the moment"""
42 tgt = 'I@keepalived:cluster:enabled:True'
43 grains = 'ip_interfaces'
44 result = self._salt.get_grains(tgt=tgt, grains=grains)[0]
45 minion_ids = [
46 minion_id for minion_id, interfaces in result.items()
47 for interface, ips in interfaces.items()
48 for ip in ips
49 if ip == vip
50 ]
51 LOG.debug("VIP '{0}' found on minions {1}".format(vip, minion_ids))
52 if len(minion_ids) != 1:
53 raise Exception("VIP {0} is expected on a single node. Actual "
54 "nodes with VIP: {1}".format(vip, minion_ids))
55 return minion_ids[0]
56
57 def get_keepalived_vips(self):
58 tgt = 'I@keepalived:cluster:enabled:True'
59 pillar = 'keepalived:cluster:instance'
60 return self._salt.get_pillar(tgt=tgt, pillar=pillar)[0]
61
62 def check_keepalived_pillar(self):
63 """Check the keepalived pillars for VIPs
64
65 Check for:
66 - the same VIP is used for the same 'virtual_router_id'
67 - the same password is used for the same 'virtual_router_id'
68 - no 'virtual_router_id' or VIP doubles in different
69 keepalived instances on the same node
70 - no 'priority' doubles inside the same 'virtual_router_id'
71 on different nodes
72
73 :param pillar_vips: dict {
74 <minion_id>: {
75 <keepalived instance>: {
76 <address>: str,
77 <password>: str,
78 <virtual_router_id>: int,
79 <priority>: int
80 },
81 ...
82 },
83 }
84 :return dict: {
85 <str:vip1> : {
86 'instance_name': <str>
87 'virtual_router_id': <int>,
88 'password': <str>,
89 'nodes' : {<str:node1>: <int:priority>,
90 <str:node2>: <int:priority>,
91 ...},
92 },
93 <str:vip2> : { ...
94 },
95 }
96 """
97
98 def check_single_address(vips, minion_id, instance, data):
99 for vip in vips:
100 if vips[vip]['virtual_router_id'] == data['virtual_router_id']\
101 and (vip != data['address'] or
102 vips[vip]['instance_name'] != instance):
103 message = (
104 "'virtual_router_id': {0} for keepalived instance "
105 "{1}: {2} is already used for {3}: {4} on nodes {5}"
106 .format(data['virtual_router_id'],
107 instance, data['address'],
108 vips[vip]['instance_name'],
109 vip,
110 vips[vip]['nodes'].keys())
111 )
112 raise exceptions.SaltPillarError(
113 minion_id,
114 'keepalived:cluster:instance',
115 message)
116
117 def check_single_router_id(vips, minion_id, instance, data):
118 for vip in vips:
119 if vips[vip]['virtual_router_id'] != data['virtual_router_id']\
120 and vip == data['address']:
121 message = (
122 "'virtual_router_id': {0} for keepalived instance "
123 "{1}: {2} is not the same as for {3}: {4} on nodes {5}"
124 .format(data['virtual_router_id'],
125 instance, data['address'],
126 vips[vip]['instance_name'],
127 vip,
128 vips[vip]['nodes'].keys())
129 )
130 raise exceptions.SaltPillarError(
131 minion_id,
132 'keepalived:cluster:instance',
133 message)
134
135 pillar_vips = self.get_keepalived_vips()
136 vips = {}
137 for minion_id in pillar_vips:
138 for instance, data in pillar_vips[minion_id].items():
139 address = data['address']
140 password = data['password']
141 virtual_router_id = data['virtual_router_id']
142 priority = data['priority']
143
144 if address not in vips:
145 # Check that there is the same VIP
146 # for the same virtual_router_id
147 check_single_address(vips, minion_id, instance, data)
148
149 # Add new VIP
150 vips[address] = {
151 'instance_name': instance,
152 'virtual_router_id': virtual_router_id,
153 'password': password,
154 'nodes': {
155 minion_id: priority,
156 }
157 }
158 else:
159 # Check that there is the same virtual_router_id
160 # for the same VIP
161 check_single_router_id(vips, minion_id, instance, data)
162 if vips[address]['password'] != password:
163 message = (
164 "'password': {0} for keepalived instance "
165 "{1}: {2} is not the same as for {3}: {4} on "
166 "nodes {5}".format(data['password'],
167 instance, data['address'],
168 vips[address]['instance_name'],
169 address,
170 vips[address]['nodes'].keys())
171 )
172 raise exceptions.SaltPillarError(
173 minion_id,
174 'keepalived:cluster:instance',
175 message)
176
177 if any([priority == prio
178 for node, prio in vips[address]['nodes'].items()]):
179 message = (
180 "'priority': {0} for keepalived instance "
181 "{1}: {2} is the same as for {3}: {4} on "
182 "nodes {5}".format(data['priority'],
183 instance, data['address'],
184 vips[address]['instance_name'],
185 address,
186 vips[address]['nodes'].keys())
187 )
188 raise exceptions.SaltPillarError(
189 minion_id,
190 'keepalived:cluster:instance',
191 message)
192
193 # Add data to the vips
194 vips[address]['nodes'][minion_id] = priority
195
196 LOG.debug("keepalived pillars check passed: {0}".format(vips))
197 return vips