Files
libra/libra/mgm/nova.py
Andrew Hutchings 25d6ad32b9 [MGM] Refactor pool manager ready for new functions such as delete
Change-Id: I2941b12de47b8b693e284c65f96cd671fd1d6290
2013-07-08 14:43:33 +01:00

183 lines
5.9 KiB
Python

# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
import sys
import urllib
from novaclient import client
from novaclient import exceptions
class NotFound(Exception):
pass
class BuildError(Exception):
def __init__(self, msg, node_name, node_id=0):
self.msg = msg
self.node_name = node_name
self.node_id = node_id
def __str__(self):
return self.msg
class Node(object):
def __init__(self, username, password, tenant, auth_url, region, keyname,
secgroup, image, node_type, node_basename=None):
self.nova = client.HTTPClient(
username,
password,
tenant,
auth_url,
region_name=region,
no_cache=True,
service_type='compute'
)
self.keyname = keyname
self.secgroup = secgroup
self.node_basename = node_basename
# Replace '_' with '-' in basename
if self.node_basename:
self.node_basename = self.node_basename.replace('_', '-')
if image.isdigit():
self.image = image
else:
self.image = self._get_image(image)
if node_type.isdigit():
self.node_type = node_type
else:
self.node_type = self._get_flavor(node_type)
def build(self):
""" create a node, test it is running """
node_id = uuid.uuid1()
try:
body = self._create(node_id)
except exceptions.ClientException:
raise BuildError(
'Error creating node, exception {exc}'
.format(exc=sys.exc_info()[0]), node_id
)
return body['server']['id']
def delete(self, node_id):
""" delete a node """
try:
resp = self._delete(node_id)
except exceptions.ClientException:
return False, 'Error deleting node {nid} exception {exc}'.format(
nid=node_id, exc=sys.exc_info()[0]
)
if resp.status_code != 204:
return False, 'Error deleting node {nid} status {stat}'.format(
nid=node_id, stat=resp.status_code
)
return True, ''
def _create(self, node_id):
""" create a nova node """
url = "/servers"
if self.node_basename:
node_name = '{0}-{1}'.format(self.node_basename, node_id)
else:
node_name = '{0}'.format(node_id)
body = {"server": {
"name": node_name,
"imageRef": self.image,
"key_name": self.keyname,
"flavorRef": self.node_type,
"max_count": 1,
"min_count": 1,
"networks": [],
"security_groups": [{"name": self.secgroup}]
}}
resp, body = self.nova.post(url, body=body)
return body
def status(self, node_id):
""" used to keep scanning to see if node is up """
url = "/servers/{0}".format(node_id)
try:
resp, body = self.nova.get(url)
except exceptions.NotFound:
msg = "Could not find node with id {0}".format(node_id)
raise NotFound(msg)
return resp, body
def _delete(self, node_id):
""" delete a nova node, return 204 succeed """
url = "/servers/{0}".format(node_id)
resp, body = self.nova.delete(url)
return resp
# TODO: merge get_node and _get_image to remove duplication of code
def get_node(self, node_name):
""" tries to find a node from the name """
args = {'name': node_name}
url = "/servers?{0}".format(urllib.urlencode(args))
try:
resp, body = self.nova.get(url)
except exceptions.NotFound:
msg = "Could not find node with name {0}".format(node_name)
raise NotFound(msg)
if resp.status_code not in [200, 203]:
msg = "Error {0} searching for node with name {1}".format(
resp.status_code, node_name
)
raise NotFound(msg)
if len(body['servers']) != 1:
msg = "Could not find node with name {0}".format(node_name)
raise NotFound(msg)
return body['servers'][0]['id']
def _get_image(self, image_name):
""" tries to find an image from the name """
args = {'name': image_name}
url = "/images?{0}".format(urllib.urlencode(args))
resp, body = self.nova.get(url)
if resp.status_code not in [200, 203]:
msg = "Error {0} searching for image with name {1}".format(
resp.status_code, image_name
)
raise NotFound(msg)
if len(body['images']) != 1:
msg = "Could not find image with name {0}".format(image_name)
raise NotFound(msg)
return body['images'][0]['id']
def _get_flavor(self, flavor_name):
""" tries to find a flavor from the name """
url = "/flavors"
resp, body = self.nova.get(url)
if resp.status_code not in [200, 203]:
msg = "Error {0} searching for flavor with name {1}".format(
resp.status_code, flavor_name
)
raise NotFound(msg)
for flavor in body['flavors']:
if flavor['name'] == flavor_name:
return flavor['id']
msg = "Could not find flavor with name {0}".format(flavor_name)
raise NotFound(msg)