hook nova module to salt/utils/openstack/nova.py

This commit is contained in:
Daniel Wallace 2014-03-03 13:41:50 -06:00
parent ccb6e6d52e
commit 97d2a82c29
2 changed files with 88 additions and 365 deletions

View File

@ -51,6 +51,8 @@ import logging
# Import salt libs # Import salt libs
import salt.utils import salt.utils
import salt.utils.openstack.nova as suon
# Get logging started # Get logging started
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -100,7 +102,8 @@ def _auth(profile=None, service_type='compute'):
} }
if region_name: if region_name:
kwargs['region_name'] = region_name kwargs['region_name'] = region_name
return client.Client(**kwargs)
return suon.SaltNova(**kwargs)
def boot(name, flavor_id=0, image_id=0, profile=None, timeout=300): def boot(name, flavor_id=0, image_id=0, profile=None, timeout=300):
@ -136,66 +139,8 @@ def boot(name, flavor_id=0, image_id=0, profile=None, timeout=300):
salt '*' nova.flavor_list salt '*' nova.flavor_list
salt '*' nova.image_list salt '*' nova.image_list
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
response = nt_ks.servers.create( return conn.boot(name, flavor_id, image_id, timeout)
name=name, flavor=flavor_id, image=image_id
)
start = time.time()
trycount = 0
while True:
trycount += 1
try:
return server_show(response.id, profile=profile)
except Exception as exc:
log.debug('Server information not yet available: {0}'.format(exc))
time.sleep(1)
if time.time() - start > timeout:
log.error('Timed out after {0} seconds '
'while waiting for data'.format(timeout))
return False
log.debug(
'Retrying server_show() (try {0})'.format(trycount)
)
def server_by_name(name, profile=None):
'''
.. versionadded:: Helium
Returns information about one server based on the name
name
name of the server
profile
profile to use
CLI Example:
.. code-block:: bash
salt '*' nova.server_by_name test.example.com profile=openstack
'''
return server_list(profile=profile).get(name, {})
def _volume_get(volume_id, profile=None):
'''
Get information about a volume by its id
'''
nt_ks = _auth(profile, service_type='volume')
volume = nt_ks.volumes.get(volume_id)
response = {'name': volume.display_name,
'size': volume.size,
'id': volume.id,
'description': volume.display_description,
'attachments': volume.attachments,
'status': volume.status
}
return response
def volume_list(search_opts=None, profile=None): def volume_list(search_opts=None, profile=None):
@ -217,9 +162,8 @@ def volume_list(search_opts=None, profile=None):
profile=openstack profile=openstack
''' '''
nt_ks = _auth(profile, service_type='volume') conn = _auth(profile)
volume = nt_ks.volumes.list(search_opts=search_opts) return conn.volume_list(search_opts=search_opts)
return volume
def volume_show(name, profile=None): def volume_show(name, profile=None):
@ -239,25 +183,8 @@ def volume_show(name, profile=None):
salt '*' nova.volume_show myblock profile=openstack salt '*' nova.volume_show myblock profile=openstack
''' '''
nt_ks = _auth(profile, service_type='volume') conn = _auth(profile)
volumes = volume_list( return conn.volume_show(name)
search_opts={'display_name': name},
profile=profile
)
try:
volume = volumes[0]
except IndexError:
# volume doesn't exist
return False
response = {'name': volume.display_name,
'size': volume.size,
'id': volume.id,
'description': volume.display_description,
'attachments': volume.attachments,
'status': volume.status
}
return response
def volume_create(name, size=100, snapshot=None, voltype=None, def volume_create(name, size=100, snapshot=None, voltype=None,
@ -287,16 +214,14 @@ def volume_create(name, size=100, snapshot=None, voltype=None,
salt '*' nova.volume_create myblock size=300 profile=openstack salt '*' nova.volume_create myblock size=300 profile=openstack
''' '''
nt_ks = _auth(profile, service_type='volume') conn = _auth(profile)
response = nt_ks.volumes.create( return conn.volume_create(
size=size, name,
display_name=name, size,
volume_type=voltype, snapshot,
snapshot_id=snapshot voltype
) )
return _volume_get(response.id, profile=profile)
def volume_delete(name, profile=None): def volume_delete(name, profile=None):
''' '''
@ -315,10 +240,8 @@ def volume_delete(name, profile=None):
salt '*' nova.volume_delete myblock profile=openstack salt '*' nova.volume_delete myblock profile=openstack
''' '''
nt_ks = _auth(profile, service_type='volume') conn = _auth(profile)
volume = volume_show(name, profile) return conn.volume_delete(name)
response = nt_ks.volumes.delete(volume['id'])
return response
def volume_detach(name, def volume_detach(name,
@ -344,32 +267,12 @@ def volume_detach(name,
salt '*' nova.volume_detach myblock profile=openstack salt '*' nova.volume_detach myblock profile=openstack
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
volume = volume_show(name, profile) return conn.volume_detach(
server = server_by_name(server_name, profile) name,
response = nt_ks.volumes.delete_server_volume( server_name,
server['id'], timeout
volume['attachments'][0]['id']
) )
trycount = 0
start = time.time()
while True:
trycount += 1
try:
response = _volume_get(volume['id'], profile)
if response['status'] == 'available':
return response
except Exception as exc:
log.debug('Volume is detaching: {0}'.format(name))
time.sleep(1)
if time.time() - start > timeout:
log.error('Timed out after {0} seconds '
'while waiting for data'.format(timeout))
return False
log.debug(
'Retrying volume_show() (try {0})'.format(trycount)
)
def volume_attach(name, def volume_attach(name,
@ -401,33 +304,13 @@ def volume_attach(name,
device='/dev/xvdb' profile=openstack device='/dev/xvdb' profile=openstack
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
volume = volume_show(name, profile) return conn.volume_attach(
server = server_by_name(server_name, profile) name,
response = nt_ks.volumes.create_server_volume( server_name,
server['id'], device,
volume['id'], timeout
device=device
) )
trycount = 0
start = time.time()
while True:
trycount += 1
try:
response = _volume_get(volume['id'], profile)
if response['status'] == 'in-use':
return response
except Exception as exc:
log.debug('Volume is attaching: {0}'.format(name))
time.sleep(1)
if time.time() - start > timeout:
log.error('Timed out after {0} seconds '
'while waiting for data'.format(timeout))
return False
log.debug(
'Retrying volume_show() (try {0})'.format(trycount)
)
def suspend(instance_id, profile=None): def suspend(instance_id, profile=None):
@ -444,9 +327,8 @@ def suspend(instance_id, profile=None):
salt '*' nova.suspend 1138 salt '*' nova.suspend 1138
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
response = nt_ks.servers.suspend(instance_id) return conn.suspend(instance_id)
return True
def resume(instance_id, profile=None): def resume(instance_id, profile=None):
@ -463,9 +345,8 @@ def resume(instance_id, profile=None):
salt '*' nova.resume 1138 salt '*' nova.resume 1138
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
response = nt_ks.servers.resume(instance_id) return conn.resume(instance_id)
return True
def lock(instance_id, profile=None): def lock(instance_id, profile=None):
@ -482,9 +363,8 @@ def lock(instance_id, profile=None):
salt '*' nova.lock 1138 salt '*' nova.lock 1138
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
response = nt_ks.servers.lock(instance_id) return conn.lock(instance_id)
return True
def delete(instance_id, profile=None): def delete(instance_id, profile=None):
@ -501,9 +381,8 @@ def delete(instance_id, profile=None):
salt '*' nova.delete 1138 salt '*' nova.delete 1138
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
response = nt_ks.servers.delete(instance_id) return conn.delete(instance_id)
return True
def flavor_list(profile=None): def flavor_list(profile=None):
@ -516,24 +395,8 @@ def flavor_list(profile=None):
salt '*' nova.flavor_list salt '*' nova.flavor_list
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
ret = {} return conn.flavor_list()
for flavor in nt_ks.flavors.list():
links = {}
for link in flavor.links:
links[link['rel']] = link['href']
ret[flavor.name] = {
'disk': flavor.disk,
'id': flavor.id,
'name': flavor.name,
'ram': flavor.ram,
'swap': flavor.swap,
'vcpus': flavor.vcpus,
'links': links,
}
if hasattr(flavor, 'rxtx_factor'):
ret[flavor.name]['rxtx_factor'] = flavor.rxtx_factor
return ret
def flavor_create(name, # pylint: disable=C0103 def flavor_create(name, # pylint: disable=C0103
@ -563,15 +426,14 @@ def flavor_create(name, # pylint: disable=C0103
salt '*' nova.flavor_create myflavor id=6 ram=4096 disk=10 vcpus=1 salt '*' nova.flavor_create myflavor id=6 ram=4096 disk=10 vcpus=1
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
nt_ks.flavors.create( return conn.flavor_create(
name=name, flavorid=id, ram=ram, disk=disk, vcpus=vcpus name,
id,
ram,
disk,
vcpus
) )
return {'name': name,
'id': id,
'ram': ram,
'disk': disk,
'vcpus': vcpus}
def flavor_delete(id, profile=None): # pylint: disable=C0103 def flavor_delete(id, profile=None): # pylint: disable=C0103
@ -584,9 +446,8 @@ def flavor_delete(id, profile=None): # pylint: disable=C0103
salt '*' nova.flavor_delete 7 salt '*' nova.flavor_delete 7
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
nt_ks.flavors.delete(id) return conn.flavor_delete(id)
return 'Flavor deleted: {0}'.format(id)
def keypair_list(profile=None): def keypair_list(profile=None):
@ -599,15 +460,8 @@ def keypair_list(profile=None):
salt '*' nova.keypair_list salt '*' nova.keypair_list
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
ret = {} return conn.keypair_list()
for keypair in nt_ks.keypairs.list():
ret[keypair.name] = {
'name': keypair.name,
'fingerprint': keypair.fingerprint,
'public_key': keypair.public_key,
}
return ret
def keypair_add(name, pubfile=None, pubkey=None, profile=None): def keypair_add(name, pubfile=None, pubkey=None, profile=None):
@ -621,15 +475,12 @@ def keypair_add(name, pubfile=None, pubkey=None, profile=None):
salt '*' nova.keypair_add mykey pubfile='/home/myuser/.ssh/id_rsa.pub' salt '*' nova.keypair_add mykey pubfile='/home/myuser/.ssh/id_rsa.pub'
salt '*' nova.keypair_add mykey pubkey='ssh-rsa <key> myuser@mybox' salt '*' nova.keypair_add mykey pubkey='ssh-rsa <key> myuser@mybox'
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
if pubfile: return conn.keypair_add(
ifile = salt.utils.fopen(pubfile, 'r') name,
pubkey = ifile.read() pubfile,
if not pubkey: pubkey
return False )
nt_ks.keypairs.create(name, public_key=pubkey)
ret = {'name': name, 'pubkey': pubkey}
return ret
def keypair_delete(name, profile=None): def keypair_delete(name, profile=None):
@ -642,9 +493,8 @@ def keypair_delete(name, profile=None):
salt '*' nova.keypair_delete mykey' salt '*' nova.keypair_delete mykey'
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
nt_ks.keypairs.delete(name) return conn.keypair_delete(name)
return 'Keypair deleted: {0}'.format(name)
def image_list(name=None, profile=None): def image_list(name=None, profile=None):
@ -659,29 +509,8 @@ def image_list(name=None, profile=None):
salt '*' nova.image_list salt '*' nova.image_list
salt '*' nova.image_list myimage salt '*' nova.image_list myimage
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
ret = {} return conn.image_list(name)
for image in nt_ks.images.list():
links = {}
for link in image.links:
links[link['rel']] = link['href']
ret[image.name] = {
'name': image.name,
'id': image.id,
'status': image.status,
'progress': image.progress,
'created': image.created,
'updated': image.updated,
'metadata': image.metadata,
'links': links,
}
if hasattr(image, 'minDisk'):
ret[image.name]['minDisk'] = image.minDisk
if hasattr(image, 'minRam'):
ret[image.name]['minRam'] = image.minRam
if name:
return {name: ret[name]}
return ret
def image_meta_set(id=None, def image_meta_set(id=None,
@ -699,15 +528,12 @@ def image_meta_set(id=None,
cheese=gruyere cheese=gruyere
salt '*' nova.image_meta_set name=myimage salad=pasta beans=baked salt '*' nova.image_meta_set name=myimage salad=pasta beans=baked
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
if name: return conn.image_meta_set(
for image in nt_ks.images.list(): id,
if image.name == name: name,
id = image.id # pylint: disable=C0103 **kwargs
if not id: )
return {'Error': 'A valid image name or id was not specified'}
nt_ks.images.set_meta(id, kwargs)
return {id: kwargs}
def image_meta_delete(id=None, # pylint: disable=C0103 def image_meta_delete(id=None, # pylint: disable=C0103
@ -726,16 +552,12 @@ def image_meta_delete(id=None, # pylint: disable=C0103
id=6f52b2ff-0b31-4d84-8fd1-af45b84824f6 keys=cheese id=6f52b2ff-0b31-4d84-8fd1-af45b84824f6 keys=cheese
salt '*' nova.image_meta_delete name=myimage keys=salad,beans salt '*' nova.image_meta_delete name=myimage keys=salad,beans
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
if name: return conn.image_meta_data(
for image in nt_ks.images.list(): id,
if image.name == name: name,
id = image.id # pylint: disable=C0103 keys
pairs = keys.split(',') )
if not id:
return {'Error': 'A valid image name or id was not specified'}
nt_ks.images.delete_meta(id, pairs)
return {id: 'Deleted: {0}'.format(pairs)}
def list_(profile=None): def list_(profile=None):
@ -756,21 +578,8 @@ def server_list(profile=None):
salt '*' nova.show salt '*' nova.show
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
ret = {} return conn.server_list()
for item in nt_ks.servers.list():
ret[item.name] = {
'id': item.id,
'name': item.name,
'status': item.status,
'accessIPv4': item.accessIPv4,
'accessIPv6': item.accessIPv6,
'flavor': {'id': item.flavor['id'],
'links': item.flavor['links']},
'image': {'id': item.image['id'],
'links': item.image['links']},
}
return ret
def show(server_id, profile=None): def show(server_id, profile=None):
@ -797,59 +606,8 @@ def server_list_detailed(profile=None):
salt '*' nova.server_list_detailed salt '*' nova.server_list_detailed
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
ret = {} return conn.server_list_detailed()
for item in nt_ks.servers.list():
ret[item.name] = {
'OS-EXT-SRV-ATTR': {},
'OS-EXT-STS': {},
'accessIPv4': item.accessIPv4,
'accessIPv6': item.accessIPv6,
'addresses': item.addresses,
'config_drive': item.config_drive,
'created': item.created,
'flavor': {'id': item.flavor['id'],
'links': item.flavor['links']},
'hostId': item.hostId,
'id': item.id,
'image': {'id': item.image['id'],
'links': item.image['links']},
'key_name': item.key_name,
'links': item.links,
'metadata': item.metadata,
'name': item.name,
'progress': item.progress,
'status': item.status,
'tenant_id': item.tenant_id,
'updated': item.updated,
'user_id': item.user_id,
}
if hasattr(item.__dict__, 'OS-DCF:diskConfig'):
ret[item.name]['OS-DCF'] = {
'diskConfig': item.__dict__['OS-DCF:diskConfig']
}
if hasattr(item.__dict__, 'OS-EXT-SRV-ATTR:host'):
ret[item.name]['OS-EXT-SRV-ATTR']['host'] = \
item.__dict__['OS-EXT-SRV-ATTR:host']
if hasattr(item.__dict__, 'OS-EXT-SRV-ATTR:hypervisor_hostname'):
ret[item.name]['OS-EXT-SRV-ATTR']['hypervisor_hostname'] = \
item.__dict__['OS-EXT-SRV-ATTR:hypervisor_hostname']
if hasattr(item.__dict__, 'OS-EXT-SRV-ATTR:instance_name'):
ret[item.name]['OS-EXT-SRV-ATTR']['instance_name'] = \
item.__dict__['OS-EXT-SRV-ATTR:instance_name']
if hasattr(item.__dict__, 'OS-EXT-STS:power_state'):
ret[item.name]['OS-EXT-STS']['power_state'] = \
item.__dict__['OS-EXT-STS:power_state']
if hasattr(item.__dict__, 'OS-EXT-STS:task_state'):
ret[item.name]['OS-EXT-STS']['task_state'] = \
item.__dict__['OS-EXT-STS:task_state']
if hasattr(item.__dict__, 'OS-EXT-STS:vm_state'):
ret[item.name]['OS-EXT-STS']['vm_state'] = \
item.__dict__['OS-EXT-STS:vm_state']
if hasattr(item.__dict__, 'security_groups'):
ret[item.name]['security_groups'] = \
item.__dict__['security_groups']
return ret
def server_show(server_id, profile=None): def server_show(server_id, profile=None):
@ -862,12 +620,8 @@ def server_show(server_id, profile=None):
salt '*' nova.server_show <server_id> salt '*' nova.server_show <server_id>
''' '''
ret = {} conn = _auth(profile)
servers = server_list_detailed(profile) return conn.server_show(server_id)
for server_name, server in servers.iteritems():
if str(server['id']) == server_id:
ret[server_name] = server
return ret
def secgroup_create(name, description, profile=None): def secgroup_create(name, description, profile=None):
@ -880,10 +634,8 @@ def secgroup_create(name, description, profile=None):
salt '*' nova.secgroup_create mygroup 'This is my security group' salt '*' nova.secgroup_create mygroup 'This is my security group'
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
nt_ks.security_groups.create(name, description) return conn.secgroup_create(name, description)
ret = {'name': name, 'description': description}
return ret
def secgroup_delete(name, profile=None): def secgroup_delete(name, profile=None):
@ -896,12 +648,8 @@ def secgroup_delete(name, profile=None):
salt '*' nova.secgroup_delete mygroup salt '*' nova.secgroup_delete mygroup
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
for item in nt_ks.security_groups.list(): return conn.secgroup_delete(name)
if item.name == name:
nt_ks.security_groups.delete(item.id)
return {name: 'Deleted security group: {0}'.format(name)}
return 'Security group not found: {0}'.format(name)
def secgroup_list(profile=None): def secgroup_list(profile=None):
@ -914,39 +662,10 @@ def secgroup_list(profile=None):
salt '*' nova.secgroup_list salt '*' nova.secgroup_list
''' '''
nt_ks = _auth(profile) conn = _auth(profile)
ret = {} return conn.secgroup_list()
for item in nt_ks.security_groups.list():
ret[item.name] = {
'name': item.name,
'description': item.description,
'id': item.id,
'tenant_id': item.tenant_id,
'rules': item.rules,
}
return ret
def _item_list(profile=None):
'''
Template for writing list functions
Return a list of available items (nova items-list)
CLI Example:
.. code-block:: bash
salt '*' nova.item_list
'''
nt_ks = _auth(profile)
ret = []
for item in nt_ks.items.list():
ret.append(item.__dict__)
#ret[item.name] = {
# 'name': item.name,
# }
return ret
#The following is a list of functions that need to be incorporated in the #The following is a list of functions that need to be incorporated in the
#nova module. This list should be updated as functions are added. #nova module. This list should be updated as functions are added.
# #

View File

@ -27,11 +27,15 @@ class SaltNova(object):
''' '''
Set up nova credentials Set up nova credentials
''' '''
if not HAS_NOVA:
return False
self.kwargs = { self.kwargs = {
'username': user, 'username': user,
'api_key': password, 'api_key': password,
'project_id': tenant, 'project_id': tenant,
'auth_url': auth_url, 'auth_url': auth_url,
'region': region_name,
'service_type': 'volume' 'service_type': 'volume'
} }