~nttdata/nova/lp746821

« back to all changes in this revision

Viewing changes to nova/adminclient.py

  • Committer: Tarmac
  • Author(s): Devin Carlen
  • Date: 2011-04-04 18:05:15 UTC
  • mfrom: (925.2.1 remove-adminclient)
  • Revision ID: tarmac-20110404180515-dgi2iye1zpxfao9n
Removed adminclient.py and added reference to the new nova-adminclient project in tools/pip-requires.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
 
 
3
 
# Copyright 2010 United States Government as represented by the
4
 
# Administrator of the National Aeronautics and Space Administration.
5
 
# All Rights Reserved.
6
 
#
7
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
8
 
#    not use this file except in compliance with the License. You may obtain
9
 
#    a copy of the License at
10
 
#
11
 
#         http://www.apache.org/licenses/LICENSE-2.0
12
 
#
13
 
#    Unless required by applicable law or agreed to in writing, software
14
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
 
#    License for the specific language governing permissions and limitations
17
 
#    under the License.
18
 
"""
19
 
Nova User API client library.
20
 
"""
21
 
 
22
 
import base64
23
 
import boto
24
 
import boto.exception
25
 
import httplib
26
 
import re
27
 
import string
28
 
 
29
 
from boto.ec2.regioninfo import RegionInfo
30
 
 
31
 
 
32
 
DEFAULT_CLC_URL = 'http://127.0.0.1:8773'
33
 
DEFAULT_REGION = 'nova'
34
 
 
35
 
 
36
 
class UserInfo(object):
37
 
    """
38
 
    Information about a Nova user, as parsed through SAX.
39
 
 
40
 
    **Fields Include**
41
 
 
42
 
    * username
43
 
    * accesskey
44
 
    * secretkey
45
 
    * file (optional) containing zip of X509 cert & rc file
46
 
 
47
 
    """
48
 
 
49
 
    def __init__(self, connection=None, username=None, endpoint=None):
50
 
        self.connection = connection
51
 
        self.username = username
52
 
        self.endpoint = endpoint
53
 
 
54
 
    def __repr__(self):
55
 
        return 'UserInfo:%s' % self.username
56
 
 
57
 
    def startElement(self, name, attrs, connection):
58
 
        return None
59
 
 
60
 
    def endElement(self, name, value, connection):
61
 
        if name == 'username':
62
 
            self.username = str(value)
63
 
        elif name == 'file':
64
 
            self.file = base64.b64decode(str(value))
65
 
        elif name == 'accesskey':
66
 
            self.accesskey = str(value)
67
 
        elif name == 'secretkey':
68
 
            self.secretkey = str(value)
69
 
 
70
 
 
71
 
class UserRole(object):
72
 
    """
73
 
    Information about a Nova user's role, as parsed through SAX.
74
 
 
75
 
    **Fields include**
76
 
 
77
 
    * role
78
 
 
79
 
    """
80
 
 
81
 
    def __init__(self, connection=None):
82
 
        self.connection = connection
83
 
        self.role = None
84
 
 
85
 
    def __repr__(self):
86
 
        return 'UserRole:%s' % self.role
87
 
 
88
 
    def startElement(self, name, attrs, connection):
89
 
        return None
90
 
 
91
 
    def endElement(self, name, value, connection):
92
 
        if name == 'role':
93
 
            self.role = value
94
 
        else:
95
 
            setattr(self, name, str(value))
96
 
 
97
 
 
98
 
class ProjectInfo(object):
99
 
    """
100
 
    Information about a Nova project, as parsed through SAX.
101
 
 
102
 
    **Fields include**
103
 
 
104
 
    * projectname
105
 
    * description
106
 
    * projectManagerId
107
 
    * memberIds
108
 
 
109
 
    """
110
 
 
111
 
    def __init__(self, connection=None):
112
 
        self.connection = connection
113
 
        self.projectname = None
114
 
        self.description = None
115
 
        self.projectManagerId = None
116
 
        self.memberIds = []
117
 
 
118
 
    def __repr__(self):
119
 
        return 'ProjectInfo:%s' % self.projectname
120
 
 
121
 
    def startElement(self, name, attrs, connection):
122
 
        return None
123
 
 
124
 
    def endElement(self, name, value, connection):
125
 
        if name == 'projectname':
126
 
            self.projectname = value
127
 
        elif name == 'description':
128
 
            self.description = value
129
 
        elif name == 'projectManagerId':
130
 
            self.projectManagerId = value
131
 
        elif name == 'memberId':
132
 
            self.memberIds.append(value)
133
 
        else:
134
 
            setattr(self, name, str(value))
135
 
 
136
 
 
137
 
class ProjectMember(object):
138
 
    """
139
 
    Information about a Nova project member, as parsed through SAX.
140
 
 
141
 
    **Fields include**
142
 
 
143
 
    * memberId
144
 
 
145
 
    """
146
 
 
147
 
    def __init__(self, connection=None):
148
 
        self.connection = connection
149
 
        self.memberId = None
150
 
 
151
 
    def __repr__(self):
152
 
        return 'ProjectMember:%s' % self.memberId
153
 
 
154
 
    def startElement(self, name, attrs, connection):
155
 
        return None
156
 
 
157
 
    def endElement(self, name, value, connection):
158
 
        if name == 'member':
159
 
            self.memberId = value
160
 
        else:
161
 
            setattr(self, name, str(value))
162
 
 
163
 
 
164
 
class HostInfo(object):
165
 
    """
166
 
    Information about a Nova Host, as parsed through SAX.
167
 
 
168
 
    **Fields Include**
169
 
 
170
 
    * Hostname
171
 
    * Compute service status
172
 
    * Volume service status
173
 
    * Instance count
174
 
    * Volume count
175
 
    """
176
 
 
177
 
    def __init__(self, connection=None):
178
 
        self.connection = connection
179
 
        self.hostname = None
180
 
        self.compute = None
181
 
        self.volume = None
182
 
        self.instance_count = 0
183
 
        self.volume_count = 0
184
 
 
185
 
    def __repr__(self):
186
 
        return 'Host:%s' % self.hostname
187
 
 
188
 
    # this is needed by the sax parser, so ignore the ugly name
189
 
    def startElement(self, name, attrs, connection):
190
 
        return None
191
 
 
192
 
    # this is needed by the sax parser, so ignore the ugly name
193
 
    def endElement(self, name, value, connection):
194
 
        fixed_name = string.lower(re.sub(r'([A-Z])', r'_\1', name))
195
 
        setattr(self, fixed_name, value)
196
 
 
197
 
 
198
 
class Vpn(object):
199
 
    """
200
 
    Information about a Vpn, as parsed through SAX
201
 
 
202
 
    **Fields Include**
203
 
 
204
 
    * instance_id
205
 
    * project_id
206
 
    * public_ip
207
 
    * public_port
208
 
    * created_at
209
 
    * internal_ip
210
 
    * state
211
 
    """
212
 
 
213
 
    def __init__(self, connection=None):
214
 
        self.connection = connection
215
 
        self.instance_id = None
216
 
        self.project_id = None
217
 
 
218
 
    def __repr__(self):
219
 
        return 'Vpn:%s:%s' % (self.project_id, self.instance_id)
220
 
 
221
 
    def startElement(self, name, attrs, connection):
222
 
        return None
223
 
 
224
 
    def endElement(self, name, value, connection):
225
 
        fixed_name = string.lower(re.sub(r'([A-Z])', r'_\1', name))
226
 
        setattr(self, fixed_name, value)
227
 
 
228
 
 
229
 
class InstanceType(object):
230
 
    """
231
 
    Information about a Nova instance type, as parsed through SAX.
232
 
 
233
 
    **Fields include**
234
 
 
235
 
    * name
236
 
    * vcpus
237
 
    * disk_gb
238
 
    * memory_mb
239
 
    * flavor_id
240
 
 
241
 
    """
242
 
 
243
 
    def __init__(self, connection=None):
244
 
        self.connection = connection
245
 
        self.name = None
246
 
        self.vcpus = None
247
 
        self.disk_gb = None
248
 
        self.memory_mb = None
249
 
        self.flavor_id = None
250
 
 
251
 
    def __repr__(self):
252
 
        return 'InstanceType:%s' % self.name
253
 
 
254
 
    def startElement(self, name, attrs, connection):
255
 
        return None
256
 
 
257
 
    def endElement(self, name, value, connection):
258
 
        if name == "memoryMb":
259
 
            self.memory_mb = str(value)
260
 
        elif name == "flavorId":
261
 
            self.flavor_id = str(value)
262
 
        elif name == "diskGb":
263
 
            self.disk_gb = str(value)
264
 
        else:
265
 
            setattr(self, name, str(value))
266
 
 
267
 
 
268
 
class NovaAdminClient(object):
269
 
 
270
 
    def __init__(
271
 
            self,
272
 
            clc_url=DEFAULT_CLC_URL,
273
 
            region=DEFAULT_REGION,
274
 
            access_key=None,
275
 
            secret_key=None,
276
 
            **kwargs):
277
 
        parts = self.split_clc_url(clc_url)
278
 
 
279
 
        self.clc_url = clc_url
280
 
        self.region = region
281
 
        self.access = access_key
282
 
        self.secret = secret_key
283
 
        self.apiconn = boto.connect_ec2(aws_access_key_id=access_key,
284
 
                                        aws_secret_access_key=secret_key,
285
 
                                        is_secure=parts['is_secure'],
286
 
                                        region=RegionInfo(None,
287
 
                                                          region,
288
 
                                                          parts['ip']),
289
 
                                        port=parts['port'],
290
 
                                        path='/services/Admin',
291
 
                                        **kwargs)
292
 
        self.apiconn.APIVersion = 'nova'
293
 
 
294
 
    def connection_for(self, username, project, clc_url=None, region=None,
295
 
                       **kwargs):
296
 
        """Returns a boto ec2 connection for the given username."""
297
 
        if not clc_url:
298
 
            clc_url = self.clc_url
299
 
        if not region:
300
 
            region = self.region
301
 
        parts = self.split_clc_url(clc_url)
302
 
        user = self.get_user(username)
303
 
        access_key = '%s:%s' % (user.accesskey, project)
304
 
        return boto.connect_ec2(aws_access_key_id=access_key,
305
 
                                aws_secret_access_key=user.secretkey,
306
 
                                is_secure=parts['is_secure'],
307
 
                                region=RegionInfo(None,
308
 
                                                  self.region,
309
 
                                                  parts['ip']),
310
 
                                port=parts['port'],
311
 
                                path='/services/Cloud',
312
 
                                **kwargs)
313
 
 
314
 
    def split_clc_url(self, clc_url):
315
 
        """Splits a cloud controller endpoint url."""
316
 
        parts = httplib.urlsplit(clc_url)
317
 
        is_secure = parts.scheme == 'https'
318
 
        ip, port = parts.netloc.split(':')
319
 
        return {'ip': ip, 'port': int(port), 'is_secure': is_secure}
320
 
 
321
 
    def get_users(self):
322
 
        """Grabs the list of all users."""
323
 
        return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)])
324
 
 
325
 
    def get_user(self, name):
326
 
        """Grab a single user by name."""
327
 
        user = self.apiconn.get_object('DescribeUser',
328
 
                                       {'Name': name},
329
 
                                       UserInfo)
330
 
        if user.username != None:
331
 
            return user
332
 
 
333
 
    def has_user(self, username):
334
 
        """Determine if user exists."""
335
 
        return self.get_user(username) != None
336
 
 
337
 
    def create_user(self, username):
338
 
        """Creates a new user, returning the userinfo object with
339
 
        access/secret."""
340
 
        return self.apiconn.get_object('RegisterUser', {'Name': username},
341
 
                                       UserInfo)
342
 
 
343
 
    def delete_user(self, username):
344
 
        """Deletes a user."""
345
 
        return self.apiconn.get_object('DeregisterUser', {'Name': username},
346
 
                                       UserInfo)
347
 
 
348
 
    def get_roles(self, project_roles=True):
349
 
        """Returns a list of available roles."""
350
 
        return self.apiconn.get_list('DescribeRoles',
351
 
                                     {'ProjectRoles': project_roles},
352
 
                                     [('item', UserRole)])
353
 
 
354
 
    def get_user_roles(self, user, project=None):
355
 
        """Returns a list of roles for the given user.
356
 
 
357
 
        Omitting project will return any global roles that the user has.
358
 
        Specifying project will return only project specific roles.
359
 
 
360
 
        """
361
 
        params = {'User': user}
362
 
        if project:
363
 
            params['Project'] = project
364
 
        return self.apiconn.get_list('DescribeUserRoles',
365
 
                                     params,
366
 
                                     [('item', UserRole)])
367
 
 
368
 
    def add_user_role(self, user, role, project=None):
369
 
        """Add a role to a user either globally or for a specific project."""
370
 
        return self.modify_user_role(user, role, project=project,
371
 
                                     operation='add')
372
 
 
373
 
    def remove_user_role(self, user, role, project=None):
374
 
        """Remove a role from a user either globally or for a specific
375
 
        project."""
376
 
        return self.modify_user_role(user, role, project=project,
377
 
                                     operation='remove')
378
 
 
379
 
    def modify_user_role(self, user, role, project=None, operation='add',
380
 
                         **kwargs):
381
 
        """Add or remove a role for a user and project."""
382
 
        params = {'User': user,
383
 
                  'Role': role,
384
 
                  'Project': project,
385
 
                  'Operation': operation}
386
 
        return self.apiconn.get_status('ModifyUserRole', params)
387
 
 
388
 
    def get_projects(self, user=None):
389
 
        """Returns a list of all projects."""
390
 
        if user:
391
 
            params = {'User': user}
392
 
        else:
393
 
            params = {}
394
 
        return self.apiconn.get_list('DescribeProjects',
395
 
                                     params,
396
 
                                     [('item', ProjectInfo)])
397
 
 
398
 
    def get_project(self, name):
399
 
        """Returns a single project with the specified name."""
400
 
        project = self.apiconn.get_object('DescribeProject',
401
 
                                          {'Name': name},
402
 
                                          ProjectInfo)
403
 
 
404
 
        if project.projectname != None:
405
 
            return project
406
 
 
407
 
    def create_project(self, projectname, manager_user, description=None,
408
 
                       member_users=None):
409
 
        """Creates a new project."""
410
 
        params = {'Name': projectname,
411
 
                  'ManagerUser': manager_user,
412
 
                  'Description': description,
413
 
                  'MemberUsers': member_users}
414
 
        return self.apiconn.get_object('RegisterProject', params, ProjectInfo)
415
 
 
416
 
    def modify_project(self, projectname, manager_user=None, description=None):
417
 
        """Modifies an existing project."""
418
 
        params = {'Name': projectname,
419
 
                  'ManagerUser': manager_user,
420
 
                  'Description': description}
421
 
        return self.apiconn.get_status('ModifyProject', params)
422
 
 
423
 
    def delete_project(self, projectname):
424
 
        """Permanently deletes the specified project."""
425
 
        return self.apiconn.get_object('DeregisterProject',
426
 
                                       {'Name': projectname},
427
 
                                       ProjectInfo)
428
 
 
429
 
    def get_project_members(self, name):
430
 
        """Returns a list of members of a project."""
431
 
        return self.apiconn.get_list('DescribeProjectMembers',
432
 
                                     {'Name': name},
433
 
                                     [('item', ProjectMember)])
434
 
 
435
 
    def add_project_member(self, user, project):
436
 
        """Adds a user to a project."""
437
 
        return self.modify_project_member(user, project, operation='add')
438
 
 
439
 
    def remove_project_member(self, user, project):
440
 
        """Removes a user from a project."""
441
 
        return self.modify_project_member(user, project, operation='remove')
442
 
 
443
 
    def modify_project_member(self, user, project, operation='add'):
444
 
        """Adds or removes a user from a project."""
445
 
        params = {'User': user,
446
 
                  'Project': project,
447
 
                  'Operation': operation}
448
 
        return self.apiconn.get_status('ModifyProjectMember', params)
449
 
 
450
 
    def get_zip(self, user, project):
451
 
        """Returns the content of a zip file containing novarc and access
452
 
        credentials."""
453
 
        params = {'Name': user, 'Project': project}
454
 
        zip = self.apiconn.get_object('GenerateX509ForUser', params, UserInfo)
455
 
        return zip.file
456
 
 
457
 
    def start_vpn(self, project):
458
 
        """
459
 
        Starts the vpn for a user
460
 
        """
461
 
        return self.apiconn.get_object('StartVpn', {'Project': project}, Vpn)
462
 
 
463
 
    def get_vpns(self):
464
 
        """Return a list of vpn with project name"""
465
 
        return self.apiconn.get_list('DescribeVpns', {}, [('item', Vpn)])
466
 
 
467
 
    def get_hosts(self):
468
 
        return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)])
469
 
 
470
 
    def get_instance_types(self):
471
 
        """Grabs the list of all users."""
472
 
        return self.apiconn.get_list('DescribeInstanceTypes', {},
473
 
                                     [('item', InstanceType)])