~openstack-charmers-archive/charms/trusty/nova-compute/next

« back to all changes in this revision

Viewing changes to tests/charmhelpers/contrib/openstack/amulet/utils.py

  • Committer: Billy Olsen
  • Date: 2015-06-22 17:03:01 UTC
  • mfrom: (133.1.1 nova-compute)
  • Revision ID: billy.olsen@canonical.com-20150622170301-swtb01c6wd0e4yup
[corey.bryant,r=billy-olsen] Fix global requirements for git-deploy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import logging
18
18
import os
 
19
import six
19
20
import time
20
21
import urllib
21
22
 
22
23
import glanceclient.v1.client as glance_client
 
24
import heatclient.v1.client as heat_client
23
25
import keystoneclient.v2_0 as keystone_client
24
26
import novaclient.v1_1.client as nova_client
25
27
 
26
 
import six
27
 
 
28
28
from charmhelpers.contrib.amulet.utils import (
29
29
    AmuletUtils
30
30
)
37
37
    """OpenStack amulet utilities.
38
38
 
39
39
       This class inherits from AmuletUtils and has additional support
40
 
       that is specifically for use by OpenStack charms.
 
40
       that is specifically for use by OpenStack charm tests.
41
41
       """
42
42
 
43
43
    def __init__(self, log_level=ERROR):
51
51
           Validate actual endpoint data vs expected endpoint data. The ports
52
52
           are used to find the matching endpoint.
53
53
           """
 
54
        self.log.debug('Validating endpoint data...')
 
55
        self.log.debug('actual: {}'.format(repr(endpoints)))
54
56
        found = False
55
57
        for ep in endpoints:
56
58
            self.log.debug('endpoint: {}'.format(repr(ep)))
77
79
           Validate a list of actual service catalog endpoints vs a list of
78
80
           expected service catalog endpoints.
79
81
           """
 
82
        self.log.debug('Validating service catalog endpoint data...')
80
83
        self.log.debug('actual: {}'.format(repr(actual)))
81
84
        for k, v in six.iteritems(expected):
82
85
            if k in actual:
93
96
           Validate a list of actual tenant data vs list of expected tenant
94
97
           data.
95
98
           """
 
99
        self.log.debug('Validating tenant data...')
96
100
        self.log.debug('actual: {}'.format(repr(actual)))
97
101
        for e in expected:
98
102
            found = False
114
118
           Validate a list of actual role data vs a list of expected role
115
119
           data.
116
120
           """
 
121
        self.log.debug('Validating role data...')
117
122
        self.log.debug('actual: {}'.format(repr(actual)))
118
123
        for e in expected:
119
124
            found = False
134
139
           Validate a list of actual user data vs a list of expected user
135
140
           data.
136
141
           """
 
142
        self.log.debug('Validating user data...')
137
143
        self.log.debug('actual: {}'.format(repr(actual)))
138
144
        for e in expected:
139
145
            found = False
155
161
 
156
162
           Validate a list of actual flavors vs a list of expected flavors.
157
163
           """
 
164
        self.log.debug('Validating flavor data...')
158
165
        self.log.debug('actual: {}'.format(repr(actual)))
159
166
        act = [a.name for a in actual]
160
167
        return self._validate_list_data(expected, act)
161
168
 
162
169
    def tenant_exists(self, keystone, tenant):
163
170
        """Return True if tenant exists."""
 
171
        self.log.debug('Checking if tenant exists ({})...'.format(tenant))
164
172
        return tenant in [t.name for t in keystone.tenants.list()]
165
173
 
166
174
    def authenticate_keystone_admin(self, keystone_sentry, user, password,
167
175
                                    tenant):
168
176
        """Authenticates admin user with the keystone admin endpoint."""
 
177
        self.log.debug('Authenticating keystone admin...')
169
178
        unit = keystone_sentry
170
179
        service_ip = unit.relation('shared-db',
171
180
                                   'mysql:shared-db')['private-address']
175
184
 
176
185
    def authenticate_keystone_user(self, keystone, user, password, tenant):
177
186
        """Authenticates a regular user with the keystone public endpoint."""
 
187
        self.log.debug('Authenticating keystone user ({})...'.format(user))
178
188
        ep = keystone.service_catalog.url_for(service_type='identity',
179
189
                                              endpoint_type='publicURL')
180
190
        return keystone_client.Client(username=user, password=password,
182
192
 
183
193
    def authenticate_glance_admin(self, keystone):
184
194
        """Authenticates admin user with glance."""
 
195
        self.log.debug('Authenticating glance admin...')
185
196
        ep = keystone.service_catalog.url_for(service_type='image',
186
197
                                              endpoint_type='adminURL')
187
198
        return glance_client.Client(ep, token=keystone.auth_token)
188
199
 
 
200
    def authenticate_heat_admin(self, keystone):
 
201
        """Authenticates the admin user with heat."""
 
202
        self.log.debug('Authenticating heat admin...')
 
203
        ep = keystone.service_catalog.url_for(service_type='orchestration',
 
204
                                              endpoint_type='publicURL')
 
205
        return heat_client.Client(endpoint=ep, token=keystone.auth_token)
 
206
 
189
207
    def authenticate_nova_user(self, keystone, user, password, tenant):
190
208
        """Authenticates a regular user with nova-api."""
 
209
        self.log.debug('Authenticating nova user ({})...'.format(user))
191
210
        ep = keystone.service_catalog.url_for(service_type='identity',
192
211
                                              endpoint_type='publicURL')
193
212
        return nova_client.Client(username=user, api_key=password,
195
214
 
196
215
    def create_cirros_image(self, glance, image_name):
197
216
        """Download the latest cirros image and upload it to glance."""
 
217
        self.log.debug('Creating glance image ({})...'.format(image_name))
198
218
        http_proxy = os.getenv('AMULET_HTTP_PROXY')
199
219
        self.log.debug('AMULET_HTTP_PROXY: {}'.format(http_proxy))
200
220
        if http_proxy:
235
255
 
236
256
    def delete_image(self, glance, image):
237
257
        """Delete the specified image."""
 
258
 
 
259
        # /!\ DEPRECATION WARNING
 
260
        self.log.warn('/!\\ DEPRECATION WARNING:  use '
 
261
                      'delete_resource instead of delete_image.')
 
262
        self.log.debug('Deleting glance image ({})...'.format(image))
238
263
        num_before = len(list(glance.images.list()))
239
264
        glance.images.delete(image)
240
265
 
254
279
 
255
280
    def create_instance(self, nova, image_name, instance_name, flavor):
256
281
        """Create the specified instance."""
 
282
        self.log.debug('Creating instance '
 
283
                       '({}|{}|{})'.format(instance_name, image_name, flavor))
257
284
        image = nova.images.find(name=image_name)
258
285
        flavor = nova.flavors.find(name=flavor)
259
286
        instance = nova.servers.create(name=instance_name, image=image,
276
303
 
277
304
    def delete_instance(self, nova, instance):
278
305
        """Delete the specified instance."""
 
306
 
 
307
        # /!\ DEPRECATION WARNING
 
308
        self.log.warn('/!\\ DEPRECATION WARNING:  use '
 
309
                      'delete_resource instead of delete_instance.')
 
310
        self.log.debug('Deleting instance ({})...'.format(instance))
279
311
        num_before = len(list(nova.servers.list()))
280
312
        nova.servers.delete(instance)
281
313
 
292
324
            return False
293
325
 
294
326
        return True
 
327
 
 
328
    def create_or_get_keypair(self, nova, keypair_name="testkey"):
 
329
        """Create a new keypair, or return pointer if it already exists."""
 
330
        try:
 
331
            _keypair = nova.keypairs.get(keypair_name)
 
332
            self.log.debug('Keypair ({}) already exists, '
 
333
                           'using it.'.format(keypair_name))
 
334
            return _keypair
 
335
        except:
 
336
            self.log.debug('Keypair ({}) does not exist, '
 
337
                           'creating it.'.format(keypair_name))
 
338
 
 
339
        _keypair = nova.keypairs.create(name=keypair_name)
 
340
        return _keypair
 
341
 
 
342
    def delete_resource(self, resource, resource_id,
 
343
                        msg="resource", max_wait=120):
 
344
        """Delete one openstack resource, such as one instance, keypair,
 
345
        image, volume, stack, etc., and confirm deletion within max wait time.
 
346
 
 
347
        :param resource: pointer to os resource type, ex:glance_client.images
 
348
        :param resource_id: unique name or id for the openstack resource
 
349
        :param msg: text to identify purpose in logging
 
350
        :param max_wait: maximum wait time in seconds
 
351
        :returns: True if successful, otherwise False
 
352
        """
 
353
        num_before = len(list(resource.list()))
 
354
        resource.delete(resource_id)
 
355
 
 
356
        tries = 0
 
357
        num_after = len(list(resource.list()))
 
358
        while num_after != (num_before - 1) and tries < (max_wait / 4):
 
359
            self.log.debug('{} delete check: '
 
360
                           '{} [{}:{}] {}'.format(msg, tries,
 
361
                                                  num_before,
 
362
                                                  num_after,
 
363
                                                  resource_id))
 
364
            time.sleep(4)
 
365
            num_after = len(list(resource.list()))
 
366
            tries += 1
 
367
 
 
368
        self.log.debug('{}:  expected, actual count = {}, '
 
369
                       '{}'.format(msg, num_before - 1, num_after))
 
370
 
 
371
        if num_after == (num_before - 1):
 
372
            return True
 
373
        else:
 
374
            self.log.error('{} delete timed out'.format(msg))
 
375
            return False
 
376
 
 
377
    def resource_reaches_status(self, resource, resource_id,
 
378
                                expected_stat='available',
 
379
                                msg='resource', max_wait=120):
 
380
        """Wait for an openstack resources status to reach an
 
381
           expected status within a specified time.  Useful to confirm that
 
382
           nova instances, cinder vols, snapshots, glance images, heat stacks
 
383
           and other resources eventually reach the expected status.
 
384
 
 
385
        :param resource: pointer to os resource type, ex: heat_client.stacks
 
386
        :param resource_id: unique id for the openstack resource
 
387
        :param expected_stat: status to expect resource to reach
 
388
        :param msg: text to identify purpose in logging
 
389
        :param max_wait: maximum wait time in seconds
 
390
        :returns: True if successful, False if status is not reached
 
391
        """
 
392
 
 
393
        tries = 0
 
394
        resource_stat = resource.get(resource_id).status
 
395
        while resource_stat != expected_stat and tries < (max_wait / 4):
 
396
            self.log.debug('{} status check: '
 
397
                           '{} [{}:{}] {}'.format(msg, tries,
 
398
                                                  resource_stat,
 
399
                                                  expected_stat,
 
400
                                                  resource_id))
 
401
            time.sleep(4)
 
402
            resource_stat = resource.get(resource_id).status
 
403
            tries += 1
 
404
 
 
405
        self.log.debug('{}:  expected, actual status = {}, '
 
406
                       '{}'.format(msg, resource_stat, expected_stat))
 
407
 
 
408
        if resource_stat == expected_stat:
 
409
            return True
 
410
        else:
 
411
            self.log.debug('{} never reached expected status: '
 
412
                           '{}'.format(resource_id, expected_stat))
 
413
            return False