18
18
class OpenStackAmuletUtils(AmuletUtils):
19
"""This class inherits from AmuletUtils and has additional support
20
that is specifically for use by OpenStack charms."""
19
"""OpenStack amulet utilities.
21
This class inherits from AmuletUtils and has additional support
22
that is specifically for use by OpenStack charms.
22
25
def __init__(self, log_level=ERROR):
23
26
"""Initialize the deployment environment."""
26
29
def validate_endpoint_data(self, endpoints, admin_port, internal_port,
27
30
public_port, expected):
28
"""Validate actual endpoint data vs expected endpoint data. The ports
29
are used to find the matching endpoint."""
31
"""Validate endpoint data.
33
Validate actual endpoint data vs expected endpoint data. The ports
34
are used to find the matching endpoint.
31
37
for ep in endpoints:
32
38
self.log.debug('endpoint: {}'.format(repr(ep)))
33
if admin_port in ep.adminurl and internal_port in ep.internalurl \
34
and public_port in ep.publicurl:
39
if (admin_port in ep.adminurl and
40
internal_port in ep.internalurl and
41
public_port in ep.publicurl):
36
43
actual = {'id': ep.id,
37
44
'region': ep.region,
47
54
return 'endpoint not found'
49
56
def validate_svc_catalog_endpoint_data(self, expected, actual):
50
"""Validate a list of actual service catalog endpoints vs a list of
51
expected service catalog endpoints."""
57
"""Validate service catalog endpoint data.
59
Validate a list of actual service catalog endpoints vs a list of
60
expected service catalog endpoints.
52
62
self.log.debug('actual: {}'.format(repr(actual)))
53
63
for k, v in expected.iteritems():
62
72
def validate_tenant_data(self, expected, actual):
63
"""Validate a list of actual tenant data vs list of expected tenant
73
"""Validate tenant data.
75
Validate a list of actual tenant data vs list of expected tenant
65
78
self.log.debug('actual: {}'.format(repr(actual)))
80
93
def validate_role_data(self, expected, actual):
81
"""Validate a list of actual role data vs a list of expected role
94
"""Validate role data.
96
Validate a list of actual role data vs a list of expected role
83
99
self.log.debug('actual: {}'.format(repr(actual)))
84
100
for e in expected:
97
113
def validate_user_data(self, expected, actual):
98
"""Validate a list of actual user data vs a list of expected user
114
"""Validate user data.
116
Validate a list of actual user data vs a list of expected user
100
119
self.log.debug('actual: {}'.format(repr(actual)))
101
120
for e in expected:
116
135
def validate_flavor_data(self, expected, actual):
117
"""Validate a list of actual flavors vs a list of expected flavors."""
136
"""Validate flavor data.
138
Validate a list of actual flavors vs a list of expected flavors.
118
140
self.log.debug('actual: {}'.format(repr(actual)))
119
141
act = [a.name for a in actual]
120
142
return self._validate_list_data(expected, act)
122
144
def tenant_exists(self, keystone, tenant):
123
"""Return True if tenant exists"""
145
"""Return True if tenant exists."""
124
146
return tenant in [t.name for t in keystone.tenants.list()]
126
148
def authenticate_keystone_admin(self, keystone_sentry, user, password,
128
150
"""Authenticates admin user with the keystone admin endpoint."""
130
keystone_sentry.relation('shared-db',
131
'mysql:shared-db')['private-address']
151
unit = keystone_sentry
152
service_ip = unit.relation('shared-db',
153
'mysql:shared-db')['private-address']
132
154
ep = "http://{}:35357/v2.0".format(service_ip.strip().decode('utf-8'))
133
155
return keystone_client.Client(username=user, password=password,
134
156
tenant_name=tenant, auth_url=ep)
166
188
f = opener.open("http://download.cirros-cloud.net/version/released")
167
189
version = f.read().strip()
168
cirros_img = "tests/cirros-{}-x86_64-disk.img".format(version)
190
cirros_img = "cirros-{}-x86_64-disk.img".format(version)
191
local_path = os.path.join('tests', cirros_img)
170
if not os.path.exists(cirros_img):
193
if not os.path.exists(local_path):
171
194
cirros_url = "http://{}/{}/{}".format("download.cirros-cloud.net",
172
195
version, cirros_img)
173
opener.retrieve(cirros_url, cirros_img)
196
opener.retrieve(cirros_url, local_path)
176
with open(cirros_img) as f:
199
with open(local_path) as f:
177
200
image = glance.images.create(name=image_name, is_public=True,
178
201
disk_format='qcow2',
179
202
container_format='bare', data=f)
204
status = image.status
205
while status != 'active' and count < 10:
207
image = glance.images.get(image.id)
208
status = image.status
209
self.log.debug('image status: {}'.format(status))
212
if status != 'active':
213
self.log.error('image creation timed out')
182
218
def delete_image(self, glance, image):
183
219
"""Delete the specified image."""
220
num_before = len(list(glance.images.list()))
184
221
glance.images.delete(image)
224
num_after = len(list(glance.images.list()))
225
while num_after != (num_before - 1) and count < 10:
227
num_after = len(list(glance.images.list()))
228
self.log.debug('number of images: {}'.format(num_after))
231
if num_after != (num_before - 1):
232
self.log.error('image deletion timed out')
186
237
def create_instance(self, nova, image_name, instance_name, flavor):
187
238
"""Create the specified instance."""
188
239
image = nova.images.find(name=image_name)
199
250
self.log.debug('instance status: {}'.format(status))
202
if status == 'BUILD':
253
if status != 'ACTIVE':
254
self.log.error('instance creation timed out')
207
259
def delete_instance(self, nova, instance):
208
260
"""Delete the specified instance."""
261
num_before = len(list(nova.servers.list()))
209
262
nova.servers.delete(instance)
265
num_after = len(list(nova.servers.list()))
266
while num_after != (num_before - 1) and count < 10:
268
num_after = len(list(nova.servers.list()))
269
self.log.debug('number of instances: {}'.format(num_after))
272
if num_after != (num_before - 1):
273
self.log.error('instance deletion timed out')