~nobuto/charms/trusty/ceph/workaround-multinics

« back to all changes in this revision

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

  • Committer: Liam Young
  • Date: 2014-09-17 06:36:31 UTC
  • mfrom: (78.1.5 ceph)
  • Revision ID: liam.young@canonical.com-20140917063631-sh28aabz283xfxyo
[corey.bryant,r=gnuoy] Add Amulet basic tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import logging
 
2
import os
 
3
import time
 
4
import urllib
 
5
 
 
6
import glanceclient.v1.client as glance_client
 
7
import keystoneclient.v2_0 as keystone_client
 
8
import novaclient.v1_1.client as nova_client
 
9
 
 
10
from charmhelpers.contrib.amulet.utils import (
 
11
    AmuletUtils
 
12
)
 
13
 
 
14
DEBUG = logging.DEBUG
 
15
ERROR = logging.ERROR
 
16
 
 
17
 
 
18
class OpenStackAmuletUtils(AmuletUtils):
 
19
    """OpenStack amulet utilities.
 
20
 
 
21
       This class inherits from AmuletUtils and has additional support
 
22
       that is specifically for use by OpenStack charms.
 
23
       """
 
24
 
 
25
    def __init__(self, log_level=ERROR):
 
26
        """Initialize the deployment environment."""
 
27
        super(OpenStackAmuletUtils, self).__init__(log_level)
 
28
 
 
29
    def validate_endpoint_data(self, endpoints, admin_port, internal_port,
 
30
                               public_port, expected):
 
31
        """Validate endpoint data.
 
32
 
 
33
           Validate actual endpoint data vs expected endpoint data. The ports
 
34
           are used to find the matching endpoint.
 
35
           """
 
36
        found = False
 
37
        for ep in endpoints:
 
38
            self.log.debug('endpoint: {}'.format(repr(ep)))
 
39
            if (admin_port in ep.adminurl and
 
40
                    internal_port in ep.internalurl and
 
41
                    public_port in ep.publicurl):
 
42
                found = True
 
43
                actual = {'id': ep.id,
 
44
                          'region': ep.region,
 
45
                          'adminurl': ep.adminurl,
 
46
                          'internalurl': ep.internalurl,
 
47
                          'publicurl': ep.publicurl,
 
48
                          'service_id': ep.service_id}
 
49
                ret = self._validate_dict_data(expected, actual)
 
50
                if ret:
 
51
                    return 'unexpected endpoint data - {}'.format(ret)
 
52
 
 
53
        if not found:
 
54
            return 'endpoint not found'
 
55
 
 
56
    def validate_svc_catalog_endpoint_data(self, expected, actual):
 
57
        """Validate service catalog endpoint data.
 
58
 
 
59
           Validate a list of actual service catalog endpoints vs a list of
 
60
           expected service catalog endpoints.
 
61
           """
 
62
        self.log.debug('actual: {}'.format(repr(actual)))
 
63
        for k, v in expected.iteritems():
 
64
            if k in actual:
 
65
                ret = self._validate_dict_data(expected[k][0], actual[k][0])
 
66
                if ret:
 
67
                    return self.endpoint_error(k, ret)
 
68
            else:
 
69
                return "endpoint {} does not exist".format(k)
 
70
        return ret
 
71
 
 
72
    def validate_tenant_data(self, expected, actual):
 
73
        """Validate tenant data.
 
74
 
 
75
           Validate a list of actual tenant data vs list of expected tenant
 
76
           data.
 
77
           """
 
78
        self.log.debug('actual: {}'.format(repr(actual)))
 
79
        for e in expected:
 
80
            found = False
 
81
            for act in actual:
 
82
                a = {'enabled': act.enabled, 'description': act.description,
 
83
                     'name': act.name, 'id': act.id}
 
84
                if e['name'] == a['name']:
 
85
                    found = True
 
86
                    ret = self._validate_dict_data(e, a)
 
87
                    if ret:
 
88
                        return "unexpected tenant data - {}".format(ret)
 
89
            if not found:
 
90
                return "tenant {} does not exist".format(e['name'])
 
91
        return ret
 
92
 
 
93
    def validate_role_data(self, expected, actual):
 
94
        """Validate role data.
 
95
 
 
96
           Validate a list of actual role data vs a list of expected role
 
97
           data.
 
98
           """
 
99
        self.log.debug('actual: {}'.format(repr(actual)))
 
100
        for e in expected:
 
101
            found = False
 
102
            for act in actual:
 
103
                a = {'name': act.name, 'id': act.id}
 
104
                if e['name'] == a['name']:
 
105
                    found = True
 
106
                    ret = self._validate_dict_data(e, a)
 
107
                    if ret:
 
108
                        return "unexpected role data - {}".format(ret)
 
109
            if not found:
 
110
                return "role {} does not exist".format(e['name'])
 
111
        return ret
 
112
 
 
113
    def validate_user_data(self, expected, actual):
 
114
        """Validate user data.
 
115
 
 
116
           Validate a list of actual user data vs a list of expected user
 
117
           data.
 
118
           """
 
119
        self.log.debug('actual: {}'.format(repr(actual)))
 
120
        for e in expected:
 
121
            found = False
 
122
            for act in actual:
 
123
                a = {'enabled': act.enabled, 'name': act.name,
 
124
                     'email': act.email, 'tenantId': act.tenantId,
 
125
                     'id': act.id}
 
126
                if e['name'] == a['name']:
 
127
                    found = True
 
128
                    ret = self._validate_dict_data(e, a)
 
129
                    if ret:
 
130
                        return "unexpected user data - {}".format(ret)
 
131
            if not found:
 
132
                return "user {} does not exist".format(e['name'])
 
133
        return ret
 
134
 
 
135
    def validate_flavor_data(self, expected, actual):
 
136
        """Validate flavor data.
 
137
 
 
138
           Validate a list of actual flavors vs a list of expected flavors.
 
139
           """
 
140
        self.log.debug('actual: {}'.format(repr(actual)))
 
141
        act = [a.name for a in actual]
 
142
        return self._validate_list_data(expected, act)
 
143
 
 
144
    def tenant_exists(self, keystone, tenant):
 
145
        """Return True if tenant exists."""
 
146
        return tenant in [t.name for t in keystone.tenants.list()]
 
147
 
 
148
    def authenticate_keystone_admin(self, keystone_sentry, user, password,
 
149
                                    tenant):
 
150
        """Authenticates admin user with the keystone admin endpoint."""
 
151
        unit = keystone_sentry
 
152
        service_ip = unit.relation('shared-db',
 
153
                                   'mysql:shared-db')['private-address']
 
154
        ep = "http://{}:35357/v2.0".format(service_ip.strip().decode('utf-8'))
 
155
        return keystone_client.Client(username=user, password=password,
 
156
                                      tenant_name=tenant, auth_url=ep)
 
157
 
 
158
    def authenticate_keystone_user(self, keystone, user, password, tenant):
 
159
        """Authenticates a regular user with the keystone public endpoint."""
 
160
        ep = keystone.service_catalog.url_for(service_type='identity',
 
161
                                              endpoint_type='publicURL')
 
162
        return keystone_client.Client(username=user, password=password,
 
163
                                      tenant_name=tenant, auth_url=ep)
 
164
 
 
165
    def authenticate_glance_admin(self, keystone):
 
166
        """Authenticates admin user with glance."""
 
167
        ep = keystone.service_catalog.url_for(service_type='image',
 
168
                                              endpoint_type='adminURL')
 
169
        return glance_client.Client(ep, token=keystone.auth_token)
 
170
 
 
171
    def authenticate_nova_user(self, keystone, user, password, tenant):
 
172
        """Authenticates a regular user with nova-api."""
 
173
        ep = keystone.service_catalog.url_for(service_type='identity',
 
174
                                              endpoint_type='publicURL')
 
175
        return nova_client.Client(username=user, api_key=password,
 
176
                                  project_id=tenant, auth_url=ep)
 
177
 
 
178
    def create_cirros_image(self, glance, image_name):
 
179
        """Download the latest cirros image and upload it to glance."""
 
180
        http_proxy = os.getenv('AMULET_HTTP_PROXY')
 
181
        self.log.debug('AMULET_HTTP_PROXY: {}'.format(http_proxy))
 
182
        if http_proxy:
 
183
            proxies = {'http': http_proxy}
 
184
            opener = urllib.FancyURLopener(proxies)
 
185
        else:
 
186
            opener = urllib.FancyURLopener()
 
187
 
 
188
        f = opener.open("http://download.cirros-cloud.net/version/released")
 
189
        version = f.read().strip()
 
190
        cirros_img = "tests/cirros-{}-x86_64-disk.img".format(version)
 
191
 
 
192
        if not os.path.exists(cirros_img):
 
193
            cirros_url = "http://{}/{}/{}".format("download.cirros-cloud.net",
 
194
                                                  version, cirros_img)
 
195
            opener.retrieve(cirros_url, cirros_img)
 
196
        f.close()
 
197
 
 
198
        with open(cirros_img) as f:
 
199
            image = glance.images.create(name=image_name, is_public=True,
 
200
                                         disk_format='qcow2',
 
201
                                         container_format='bare', data=f)
 
202
        count = 1
 
203
        status = image.status
 
204
        while status != 'active' and count < 10:
 
205
            time.sleep(3)
 
206
            image = glance.images.get(image.id)
 
207
            status = image.status
 
208
            self.log.debug('image status: {}'.format(status))
 
209
            count += 1
 
210
 
 
211
        if status != 'active':
 
212
            self.log.error('image creation timed out')
 
213
            return None
 
214
 
 
215
        return image
 
216
 
 
217
    def delete_image(self, glance, image):
 
218
        """Delete the specified image."""
 
219
        num_before = len(list(glance.images.list()))
 
220
        glance.images.delete(image)
 
221
 
 
222
        count = 1
 
223
        num_after = len(list(glance.images.list()))
 
224
        while num_after != (num_before - 1) and count < 10:
 
225
            time.sleep(3)
 
226
            num_after = len(list(glance.images.list()))
 
227
            self.log.debug('number of images: {}'.format(num_after))
 
228
            count += 1
 
229
 
 
230
        if num_after != (num_before - 1):
 
231
            self.log.error('image deletion timed out')
 
232
            return False
 
233
 
 
234
        return True
 
235
 
 
236
    def create_instance(self, nova, image_name, instance_name, flavor):
 
237
        """Create the specified instance."""
 
238
        image = nova.images.find(name=image_name)
 
239
        flavor = nova.flavors.find(name=flavor)
 
240
        instance = nova.servers.create(name=instance_name, image=image,
 
241
                                       flavor=flavor)
 
242
 
 
243
        count = 1
 
244
        status = instance.status
 
245
        while status != 'ACTIVE' and count < 60:
 
246
            time.sleep(3)
 
247
            instance = nova.servers.get(instance.id)
 
248
            status = instance.status
 
249
            self.log.debug('instance status: {}'.format(status))
 
250
            count += 1
 
251
 
 
252
        if status != 'ACTIVE':
 
253
            self.log.error('instance creation timed out')
 
254
            return None
 
255
 
 
256
        return instance
 
257
 
 
258
    def delete_instance(self, nova, instance):
 
259
        """Delete the specified instance."""
 
260
        num_before = len(list(nova.servers.list()))
 
261
        nova.servers.delete(instance)
 
262
 
 
263
        count = 1
 
264
        num_after = len(list(nova.servers.list()))
 
265
        while num_after != (num_before - 1) and count < 10:
 
266
            time.sleep(3)
 
267
            num_after = len(list(nova.servers.list()))
 
268
            self.log.debug('number of instances: {}'.format(num_after))
 
269
            count += 1
 
270
 
 
271
        if num_after != (num_before - 1):
 
272
            self.log.error('instance deletion timed out')
 
273
            return False
 
274
 
 
275
        return True