blob: fb8426518d53510711937b609a1974d2f200182d [file] [log] [blame]
Hanna Arhipova55cc1292019-01-08 14:22:18 +02001from cinderclient import client as cinder_client
2from glanceclient import client as glance_client
3from keystoneauth1 import identity as keystone_identity
4from keystoneauth1 import session as keystone_session
5from keystoneclient.v3 import client as keystone_client
6from neutronclient.v2_0 import client as neutron_client
7from novaclient import client as novaclient
8
9import os
10import random
11import time
Oleksii Zhurba864f2322019-04-29 15:48:12 -050012import utils
Hanna Arhipova55cc1292019-01-08 14:22:18 +020013
14class OfficialClientManager(object):
15 """Manager that provides access to the official python clients for
16 calling various OpenStack APIs.
17 """
18
19 CINDERCLIENT_VERSION = 3
20 GLANCECLIENT_VERSION = 2
21 KEYSTONECLIENT_VERSION = 3
22 NEUTRONCLIENT_VERSION = 2
23 NOVACLIENT_VERSION = 2
24 INTERFACE = 'admin'
25 if "OS_ENDPOINT_TYPE" in os.environ.keys():
26 INTERFACE = os.environ["OS_ENDPOINT_TYPE"]
27
28 def __init__(self, username=None, password=None,
29 tenant_name=None, auth_url=None, endpoint_type="internalURL",
30 cert=False, domain="Default", **kwargs):
31 self.traceback = ""
32
33 self.client_attr_names = [
34 "auth",
35 "compute",
36 "network",
37 "volume",
38 "image",
39 ]
40 self.username = username
41 self.password = password
42 self.tenant_name = tenant_name
43 self.project_name = tenant_name
44 self.auth_url = auth_url
45 self.endpoint_type = endpoint_type
46 self.cert = cert
47 self.domain = domain
48 self.kwargs = kwargs
49
50 # Lazy clients
51 self._auth = None
52 self._compute = None
53 self._network = None
54 self._volume = None
55 self._image = None
56
57 @classmethod
58 def _get_auth_session(cls, username=None, password=None,
59 tenant_name=None, auth_url=None, cert=None,
60 domain='Default'):
61 if None in (username, password, tenant_name):
62 print(username, password, tenant_name)
63 msg = ("Missing required credentials for identity client. "
64 "username: {username}, password: {password}, "
65 "tenant_name: {tenant_name}").format(
66 username=username,
67 password=password,
68 tenant_name=tenant_name, )
69 raise msg
70
71 if cert and "https" not in auth_url:
72 auth_url = auth_url.replace("http", "https")
73
74 if cls.KEYSTONECLIENT_VERSION == (2, 0):
75 # auth_url = "{}{}".format(auth_url, "v2.0/")
76 auth = keystone_identity.v2.Password(
77 username=username,
78 password=password,
79 auth_url=auth_url,
80 tenant_name=tenant_name)
81 else:
82 auth_url = "{}{}".format(auth_url, "/v3")
83 auth = keystone_identity.v3.Password(
84 auth_url=auth_url,
85 user_domain_name=domain,
86 username=username,
87 password=password,
88 project_domain_name=domain,
89 project_name=tenant_name)
90
91 auth_session = keystone_session.Session(auth=auth, verify=cert)
92 # auth_session.get_auth_headers()
93 return auth_session
94
95 @classmethod
96 def get_auth_client(cls, username=None, password=None,
97 tenant_name=None, auth_url=None, cert=None,
98 domain='Default', **kwargs):
99 session = cls._get_auth_session(
100 username=username,
101 password=password,
102 tenant_name=tenant_name,
103 auth_url=auth_url,
104 cert=cert,
105 domain=domain)
106 keystone = keystone_client.Client(version=cls.KEYSTONECLIENT_VERSION,
107 session=session, **kwargs)
108 keystone.management_url = auth_url
109 return keystone
110
111 @classmethod
112 def get_compute_client(cls, username=None, password=None,
113 tenant_name=None, auth_url=None, cert=None,
114 domain='Default', **kwargs):
115 session = cls._get_auth_session(
116 username=username, password=password, tenant_name=tenant_name,
117 auth_url=auth_url, cert=cert, domain=domain)
118 service_type = 'compute'
119 compute_client = novaclient.Client(
120 version=cls.NOVACLIENT_VERSION, session=session,
121 service_type=service_type, os_cache=False, **kwargs)
122 return compute_client
123
124 @classmethod
125 def get_network_client(cls, username=None, password=None,
126 tenant_name=None, auth_url=None, cert=None,
127 domain='Default', **kwargs):
128 session = cls._get_auth_session(
129 username=username, password=password, tenant_name=tenant_name,
130 auth_url=auth_url, cert=cert, domain=domain)
131 service_type = 'network'
132 return neutron_client.Client(
133 service_type=service_type, session=session, interface=cls.INTERFACE, **kwargs)
134
135 @classmethod
136 def get_volume_client(cls, username=None, password=None,
137 tenant_name=None, auth_url=None, cert=None,
138 domain='Default', **kwargs):
139 session = cls._get_auth_session(
140 username=username, password=password, tenant_name=tenant_name,
141 auth_url=auth_url, cert=cert, domain=domain)
142 service_type = 'volume'
143 return cinder_client.Client(
144 version=cls.CINDERCLIENT_VERSION,
145 service_type=service_type,
146 interface=cls.INTERFACE,
147 session=session, **kwargs)
148
149 @classmethod
150 def get_image_client(cls, username=None, password=None,
151 tenant_name=None, auth_url=None, cert=None,
152 domain='Default', **kwargs):
153 session = cls._get_auth_session(
154 username=username, password=password, tenant_name=tenant_name,
155 auth_url=auth_url, cert=cert, domain=domain)
156 service_type = 'image'
157 return glance_client.Client(
158 version=cls.GLANCECLIENT_VERSION,
159 service_type=service_type,
160 session=session, interface=cls.INTERFACE,
161 **kwargs)
162
163 @property
164 def auth(self):
165 if self._auth is None:
166 self._auth = self.get_auth_client(
167 self.username, self.password, self.tenant_name, self.auth_url,
168 self.cert, self.domain, endpoint_type=self.endpoint_type
169 )
170 return self._auth
171
172 @property
173 def compute(self):
174 if self._compute is None:
175 self._compute = self.get_compute_client(
176 self.username, self.password, self.tenant_name, self.auth_url,
177 self.cert, self.domain, endpoint_type=self.endpoint_type
178 )
179 return self._compute
180
181 @property
182 def network(self):
183 if self._network is None:
184 self._network = self.get_network_client(
185 self.username, self.password, self.tenant_name, self.auth_url,
186 self.cert, self.domain, endpoint_type=self.endpoint_type
187 )
188 return self._network
189
190 @property
191 def volume(self):
192 if self._volume is None:
193 self._volume = self.get_volume_client(
194 self.username, self.password, self.tenant_name, self.auth_url,
195 self.cert, self.domain, endpoint_type=self.endpoint_type
196 )
197 return self._volume
198
199 @property
200 def image(self):
201 if self._image is None:
202 self._image = self.get_image_client(
203 self.username, self.password, self.tenant_name, self.auth_url,
204 self.cert, self.domain
205 )
206 return self._image
207
208
209class OSCliActions(object):
210 def __init__(self, os_clients):
211 self.os_clients = os_clients
212
213 def get_admin_tenant(self):
214 # TODO Keystone v3 doesnt have tenants attribute
215 return self.os_clients.auth.projects.find(name="admin")
216
217 # TODO: refactor
218 def get_cirros_image(self):
219 images_list = list(self.os_clients.image.images.list(name='TestVM'))
220 if images_list:
221 image = images_list[0]
222 else:
223 image = self.os_clients.image.images.create(
224 name="TestVM",
225 disk_format='qcow2',
226 container_format='bare')
227 with file_cache.get_file(settings.CIRROS_QCOW2_URL) as f:
228 self.os_clients.image.images.upload(image.id, f)
229 return image
230
231 def get_internal_network(self):
232 networks = [
233 net for net in self.os_clients.network.list_networks()["networks"]
234 if net["admin_state_up"] and not net["router:external"] and
235 len(net["subnets"])
236 ]
237 if networks:
238 net = networks[0]
239 else:
240 net = self.create_network_resources()
241 return net
242
243 def get_external_network(self):
Oleksii Zhurba864f2322019-04-29 15:48:12 -0500244 config = utils.get_configuration()
245 ext_net = config.get('external_network') or ''
246 if not ext_net:
247 networks = [
248 net for net in self.os_clients.network.list_networks()["networks"]
249 if net["admin_state_up"] and net["router:external"] and
250 len(net["subnets"])
251 ]
252 if networks:
253 ext_net = networks[0]
254 else:
255 ext_net = self.create_fake_external_network()
Hanna Arhipova55cc1292019-01-08 14:22:18 +0200256 return ext_net
257
258 def create_flavor(self, name, ram=256, vcpus=1, disk=2):
259 return self.os_clients.compute.flavors.create(name, ram, vcpus, disk)
260
261 def create_sec_group(self, rulesets=None):
262 if rulesets is None:
263 rulesets = [
264 {
265 # ssh
266 'ip_protocol': 'tcp',
267 'from_port': 22,
268 'to_port': 22,
269 'cidr': '0.0.0.0/0',
270 },
271 {
272 # iperf
273 'ip_protocol': 'tcp',
274 'from_port':5001,
275 'to_port': 5001,
276 'cidr': '0.0.0.0/0',
277 },
278 {
279 # ping
280 'ip_protocol': 'icmp',
281 'from_port': -1,
282 'to_port': -1,
283 'cidr': '0.0.0.0/0',
284 }
285 ]
286 sg_name = "spt-test-secgroup-{}".format(random.randrange(100, 999))
287 sg_desc = sg_name + " SPT"
288 secgroup = self.os_clients.compute.security_groups.create(
289 sg_name, sg_desc)
290 for ruleset in rulesets:
291 self.os_clients.compute.security_group_rules.create(
292 secgroup.id, **ruleset)
293 return secgroup
294
295
296 def wait(predicate, interval=5, timeout=60, timeout_msg="Waiting timed out"):
297 start_time = time.time()
298 if not timeout:
299 return predicate()
300 while not predicate():
301 if start_time + timeout < time.time():
302 raise exceptions.TimeoutError(timeout_msg)
303
304 seconds_to_sleep = max(
305 0,
306 min(interval, start_time + timeout - time.time()))
307 time.sleep(seconds_to_sleep)
308
309 return timeout + start_time - time.time()
310
311 def create_basic_server(self, image=None, flavor=None, net=None,
312 availability_zone=None, sec_groups=(),
313 keypair=None,
314 wait_timeout=3 * 60):
315 os_conn = self.os_clients
316 image = image or self.get_cirros_image()
317 flavor = flavor or self.get_micro_flavor()
318 net = net or self.get_internal_network()
319 kwargs = {}
320 if sec_groups:
321 kwargs['security_groups'] = sec_groups
322 server = os_conn.compute.servers.create(
323 "spt-test-server-{}".format(random.randrange(100, 999)),
324 image, flavor, nics=[{"net-id": net["id"]}],
325 availability_zone=availability_zone, key_name=keypair, **kwargs)
326 # TODO
327 #if wait_timeout:
328 # self.wait(
329 # lambda: os_conn.compute.servers.get(server).status == "ACTIVE",
330 # timeout=wait_timeout,
331 # timeout_msg=(
332 # "Create server {!r} failed by timeout. "
333 # "Please, take a look at OpenStack logs".format(server.id)))
334 return server
335
336 def create_network(self, tenant_id):
337 net_name = "spt-test-net-{}".format(random.randrange(100, 999))
338 net_body = {
339 'network': {
340 'name': net_name,
341 'tenant_id': tenant_id
342 }
343 }
344 net = self.os_clients.network.create_network(net_body)['network']
345 return net
346 #yield net
347 #self.os_clients.network.delete_network(net['id'])
348
349 def create_subnet(self, net, tenant_id, cidr=None):
350 subnet_name = "spt-test-subnet-{}".format(random.randrange(100, 999))
351 subnet_body = {
352 'subnet': {
353 "name": subnet_name,
354 'network_id': net['id'],
355 'ip_version': 4,
356 'cidr': cidr if cidr else '10.1.7.0/24',
357 'tenant_id': tenant_id
358 }
359 }
360 subnet = self.os_clients.network.create_subnet(subnet_body)['subnet']
361 return subnet
362 #yield subnet
363 #self.os_clients.network.delete_subnet(subnet['id'])
364
365 def create_router(self, ext_net, tenant_id):
366 name = 'spt-test-router-{}'.format(random.randrange(100, 999))
367 router_body = {
368 'router': {
369 'name': name,
370 'external_gateway_info': {
371 'network_id': ext_net['id']
372 },
373 'tenant_id': tenant_id
374 }
375 }
376 router = self.os_clients.network.create_router(router_body)['router']
377 return router
378 #yield router
379 #self.os_clients.network.delete_router(router['id'])
380
381 def create_network_resources(self):
382 tenant_id = self.get_admin_tenant().id
383 ext_net = self.get_external_network()
384 net = self.create_network(tenant_id)
385 subnet = self.create_subnet(net, tenant_id)
386 #router = self.create_router(ext_net, tenant_id)
387 #self.os_clients.network.add_interface_router(
388 # router['id'], {'subnet_id': subnet['id']})
389
390 private_net_id = net['id']
391 # floating_ip_pool = ext_net['id']
392
393 return net
394 #yield private_net_id, floating_ip_pool
395 #yield private_net_id
396 #
397 #self.os_clients.network.remove_interface_router(
398 # router['id'], {'subnet_id': subnet['id']})
399 #self.os_clients.network.remove_gateway_router(router['id'])