1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 United States Government as represented by the
4
# Administrator of the National Aeronautics and Space Administration.
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
11
# http://www.apache.org/licenses/LICENSE-2.0
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
19
Nova User API client library.
29
from boto.ec2.regioninfo import RegionInfo
32
DEFAULT_CLC_URL = 'http://127.0.0.1:8773'
33
DEFAULT_REGION = 'nova'
36
class UserInfo(object):
38
Information about a Nova user, as parsed through SAX.
45
* file (optional) containing zip of X509 cert & rc file
49
def __init__(self, connection=None, username=None, endpoint=None):
50
self.connection = connection
51
self.username = username
52
self.endpoint = endpoint
55
return 'UserInfo:%s' % self.username
57
def startElement(self, name, attrs, connection):
60
def endElement(self, name, value, connection):
61
if name == 'username':
62
self.username = str(value)
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)
71
class UserRole(object):
73
Information about a Nova user's role, as parsed through SAX.
81
def __init__(self, connection=None):
82
self.connection = connection
86
return 'UserRole:%s' % self.role
88
def startElement(self, name, attrs, connection):
91
def endElement(self, name, value, connection):
95
setattr(self, name, str(value))
98
class ProjectInfo(object):
100
Information about a Nova project, as parsed through SAX.
111
def __init__(self, connection=None):
112
self.connection = connection
113
self.projectname = None
114
self.description = None
115
self.projectManagerId = None
119
return 'ProjectInfo:%s' % self.projectname
121
def startElement(self, name, attrs, connection):
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)
134
setattr(self, name, str(value))
137
class ProjectMember(object):
139
Information about a Nova project member, as parsed through SAX.
147
def __init__(self, connection=None):
148
self.connection = connection
152
return 'ProjectMember:%s' % self.memberId
154
def startElement(self, name, attrs, connection):
157
def endElement(self, name, value, connection):
159
self.memberId = value
161
setattr(self, name, str(value))
164
class HostInfo(object):
166
Information about a Nova Host, as parsed through SAX.
171
* Compute service status
172
* Volume service status
177
def __init__(self, connection=None):
178
self.connection = connection
182
self.instance_count = 0
183
self.volume_count = 0
186
return 'Host:%s' % self.hostname
188
# this is needed by the sax parser, so ignore the ugly name
189
def startElement(self, name, attrs, connection):
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)
200
Information about a Vpn, as parsed through SAX
213
def __init__(self, connection=None):
214
self.connection = connection
215
self.instance_id = None
216
self.project_id = None
219
return 'Vpn:%s:%s' % (self.project_id, self.instance_id)
221
def startElement(self, name, attrs, connection):
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)
229
class InstanceType(object):
231
Information about a Nova instance type, as parsed through SAX.
243
def __init__(self, connection=None):
244
self.connection = connection
248
self.memory_mb = None
249
self.flavor_id = None
252
return 'InstanceType:%s' % self.name
254
def startElement(self, name, attrs, connection):
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)
265
setattr(self, name, str(value))
268
class NovaAdminClient(object):
272
clc_url=DEFAULT_CLC_URL,
273
region=DEFAULT_REGION,
277
parts = self.split_clc_url(clc_url)
279
self.clc_url = clc_url
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,
290
path='/services/Admin',
292
self.apiconn.APIVersion = 'nova'
294
def connection_for(self, username, project, clc_url=None, region=None,
296
"""Returns a boto ec2 connection for the given username."""
298
clc_url = self.clc_url
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,
311
path='/services/Cloud',
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}
322
"""Grabs the list of all users."""
323
return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)])
325
def get_user(self, name):
326
"""Grab a single user by name."""
327
user = self.apiconn.get_object('DescribeUser',
330
if user.username != None:
333
def has_user(self, username):
334
"""Determine if user exists."""
335
return self.get_user(username) != None
337
def create_user(self, username):
338
"""Creates a new user, returning the userinfo object with
340
return self.apiconn.get_object('RegisterUser', {'Name': username},
343
def delete_user(self, username):
344
"""Deletes a user."""
345
return self.apiconn.get_object('DeregisterUser', {'Name': username},
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)])
354
def get_user_roles(self, user, project=None):
355
"""Returns a list of roles for the given user.
357
Omitting project will return any global roles that the user has.
358
Specifying project will return only project specific roles.
361
params = {'User': user}
363
params['Project'] = project
364
return self.apiconn.get_list('DescribeUserRoles',
366
[('item', UserRole)])
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,
373
def remove_user_role(self, user, role, project=None):
374
"""Remove a role from a user either globally or for a specific
376
return self.modify_user_role(user, role, project=project,
379
def modify_user_role(self, user, role, project=None, operation='add',
381
"""Add or remove a role for a user and project."""
382
params = {'User': user,
385
'Operation': operation}
386
return self.apiconn.get_status('ModifyUserRole', params)
388
def get_projects(self, user=None):
389
"""Returns a list of all projects."""
391
params = {'User': user}
394
return self.apiconn.get_list('DescribeProjects',
396
[('item', ProjectInfo)])
398
def get_project(self, name):
399
"""Returns a single project with the specified name."""
400
project = self.apiconn.get_object('DescribeProject',
404
if project.projectname != None:
407
def create_project(self, projectname, manager_user, description=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)
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)
423
def delete_project(self, projectname):
424
"""Permanently deletes the specified project."""
425
return self.apiconn.get_object('DeregisterProject',
426
{'Name': projectname},
429
def get_project_members(self, name):
430
"""Returns a list of members of a project."""
431
return self.apiconn.get_list('DescribeProjectMembers',
433
[('item', ProjectMember)])
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')
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')
443
def modify_project_member(self, user, project, operation='add'):
444
"""Adds or removes a user from a project."""
445
params = {'User': user,
447
'Operation': operation}
448
return self.apiconn.get_status('ModifyProjectMember', params)
450
def get_zip(self, user, project):
451
"""Returns the content of a zip file containing novarc and access
453
params = {'Name': user, 'Project': project}
454
zip = self.apiconn.get_object('GenerateX509ForUser', params, UserInfo)
457
def start_vpn(self, project):
459
Starts the vpn for a user
461
return self.apiconn.get_object('StartVpn', {'Project': project}, Vpn)
464
"""Return a list of vpn with project name"""
465
return self.apiconn.get_list('DescribeVpns', {}, [('item', Vpn)])
468
return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)])
470
def get_instance_types(self):
471
"""Grabs the list of all users."""
472
return self.apiconn.get_list('DescribeInstanceTypes', {},
473
[('item', InstanceType)])