blob: f63afbf1024f5da2657d1883e08e7065b7810697 [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
Ievgeniia Zadorozhnab1c22c32019-10-02 13:21:16 +0300243 def create_fake_external_network(self):
244 net_name = "spt-ext-net-{}".format(random.randrange(100, 999))
245 net_body = {"network": {"name": net_name,
246 "router:external": True,
247 "provider:network_type": "local"}}
248
249 ext_net = self.os_clients.network.create_network(net_body)['network']
250 subnet_name = "spt-ext-subnet-{}".format(random.randrange(100, 999))
251 subnet_body = {
252 "subnet": {
253 "name": subnet_name,
254 "network_id": ext_net["id"],
255 "ip_version": 4,
256 "cidr": "10.255.255.0/24",
257 "allocation_pools": [{"start": "10.255.255.100",
258 "end": "10.255.255.200"}]
259 }
260 }
261 self.os_clients.network.create_subnet(subnet_body)
262 return ext_net
263
Hanna Arhipova55cc1292019-01-08 14:22:18 +0200264 def get_external_network(self):
Oleksii Zhurba864f2322019-04-29 15:48:12 -0500265 config = utils.get_configuration()
266 ext_net = config.get('external_network') or ''
267 if not ext_net:
268 networks = [
269 net for net in self.os_clients.network.list_networks()["networks"]
270 if net["admin_state_up"] and net["router:external"] and
271 len(net["subnets"])
272 ]
273 if networks:
274 ext_net = networks[0]
275 else:
276 ext_net = self.create_fake_external_network()
Hanna Arhipova55cc1292019-01-08 14:22:18 +0200277 return ext_net
278
279 def create_flavor(self, name, ram=256, vcpus=1, disk=2):
280 return self.os_clients.compute.flavors.create(name, ram, vcpus, disk)
281
282 def create_sec_group(self, rulesets=None):
283 if rulesets is None:
284 rulesets = [
285 {
286 # ssh
287 'ip_protocol': 'tcp',
288 'from_port': 22,
289 'to_port': 22,
290 'cidr': '0.0.0.0/0',
291 },
292 {
293 # iperf
294 'ip_protocol': 'tcp',
295 'from_port':5001,
296 'to_port': 5001,
297 'cidr': '0.0.0.0/0',
298 },
299 {
300 # ping
301 'ip_protocol': 'icmp',
302 'from_port': -1,
303 'to_port': -1,
304 'cidr': '0.0.0.0/0',
305 }
306 ]
307 sg_name = "spt-test-secgroup-{}".format(random.randrange(100, 999))
308 sg_desc = sg_name + " SPT"
309 secgroup = self.os_clients.compute.security_groups.create(
310 sg_name, sg_desc)
311 for ruleset in rulesets:
312 self.os_clients.compute.security_group_rules.create(
313 secgroup.id, **ruleset)
314 return secgroup
315
316
317 def wait(predicate, interval=5, timeout=60, timeout_msg="Waiting timed out"):
318 start_time = time.time()
319 if not timeout:
320 return predicate()
321 while not predicate():
322 if start_time + timeout < time.time():
323 raise exceptions.TimeoutError(timeout_msg)
324
325 seconds_to_sleep = max(
326 0,
327 min(interval, start_time + timeout - time.time()))
328 time.sleep(seconds_to_sleep)
329
330 return timeout + start_time - time.time()
331
332 def create_basic_server(self, image=None, flavor=None, net=None,
333 availability_zone=None, sec_groups=(),
334 keypair=None,
335 wait_timeout=3 * 60):
336 os_conn = self.os_clients
337 image = image or self.get_cirros_image()
338 flavor = flavor or self.get_micro_flavor()
339 net = net or self.get_internal_network()
340 kwargs = {}
341 if sec_groups:
342 kwargs['security_groups'] = sec_groups
343 server = os_conn.compute.servers.create(
344 "spt-test-server-{}".format(random.randrange(100, 999)),
345 image, flavor, nics=[{"net-id": net["id"]}],
346 availability_zone=availability_zone, key_name=keypair, **kwargs)
347 # TODO
348 #if wait_timeout:
349 # self.wait(
350 # lambda: os_conn.compute.servers.get(server).status == "ACTIVE",
351 # timeout=wait_timeout,
352 # timeout_msg=(
353 # "Create server {!r} failed by timeout. "
354 # "Please, take a look at OpenStack logs".format(server.id)))
355 return server
356
357 def create_network(self, tenant_id):
358 net_name = "spt-test-net-{}".format(random.randrange(100, 999))
359 net_body = {
360 'network': {
361 'name': net_name,
362 'tenant_id': tenant_id
363 }
364 }
365 net = self.os_clients.network.create_network(net_body)['network']
366 return net
367 #yield net
368 #self.os_clients.network.delete_network(net['id'])
369
370 def create_subnet(self, net, tenant_id, cidr=None):
371 subnet_name = "spt-test-subnet-{}".format(random.randrange(100, 999))
372 subnet_body = {
373 'subnet': {
374 "name": subnet_name,
375 'network_id': net['id'],
376 'ip_version': 4,
377 'cidr': cidr if cidr else '10.1.7.0/24',
378 'tenant_id': tenant_id
379 }
380 }
381 subnet = self.os_clients.network.create_subnet(subnet_body)['subnet']
382 return subnet
383 #yield subnet
384 #self.os_clients.network.delete_subnet(subnet['id'])
385
386 def create_router(self, ext_net, tenant_id):
387 name = 'spt-test-router-{}'.format(random.randrange(100, 999))
388 router_body = {
389 'router': {
390 'name': name,
391 'external_gateway_info': {
392 'network_id': ext_net['id']
393 },
394 'tenant_id': tenant_id
395 }
396 }
397 router = self.os_clients.network.create_router(router_body)['router']
398 return router
399 #yield router
400 #self.os_clients.network.delete_router(router['id'])
401
402 def create_network_resources(self):
403 tenant_id = self.get_admin_tenant().id
404 ext_net = self.get_external_network()
405 net = self.create_network(tenant_id)
406 subnet = self.create_subnet(net, tenant_id)
407 #router = self.create_router(ext_net, tenant_id)
408 #self.os_clients.network.add_interface_router(
409 # router['id'], {'subnet_id': subnet['id']})
410
411 private_net_id = net['id']
412 # floating_ip_pool = ext_net['id']
413
414 return net
415 #yield private_net_id, floating_ip_pool
416 #yield private_net_id
417 #
418 #self.os_clients.network.remove_interface_router(
419 # router['id'], {'subnet_id': subnet['id']})
420 #self.os_clients.network.remove_gateway_router(router['id'])