merge trunk and upgrade to cheetah templating
This commit is contained in:
parent
2504643977
commit
81191660cf
1
.mailmap
1
.mailmap
@ -19,6 +19,7 @@
|
|||||||
<mordred@inaugust.com> <mordred@hudson>
|
<mordred@inaugust.com> <mordred@hudson>
|
||||||
<paul@openstack.org> <pvoccio@castor.local>
|
<paul@openstack.org> <pvoccio@castor.local>
|
||||||
<paul@openstack.org> <paul.voccio@rackspace.com>
|
<paul@openstack.org> <paul.voccio@rackspace.com>
|
||||||
|
<soren.hansen@rackspace.com> <soren@linux2go.dk>
|
||||||
<todd@ansolabs.com> <todd@lapex>
|
<todd@ansolabs.com> <todd@lapex>
|
||||||
<todd@ansolabs.com> <todd@rubidine.com>
|
<todd@ansolabs.com> <todd@rubidine.com>
|
||||||
<vishvananda@gmail.com> <vishvananda@yahoo.com>
|
<vishvananda@gmail.com> <vishvananda@yahoo.com>
|
||||||
|
2
Authors
2
Authors
@ -6,6 +6,7 @@ Chris Behrens <cbehrens@codestud.com>
|
|||||||
Chmouel Boudjnah <chmouel@chmouel.com>
|
Chmouel Boudjnah <chmouel@chmouel.com>
|
||||||
Dean Troyer <dtroyer@gmail.com>
|
Dean Troyer <dtroyer@gmail.com>
|
||||||
Devin Carlen <devin.carlen@gmail.com>
|
Devin Carlen <devin.carlen@gmail.com>
|
||||||
|
Ed Leafe <ed@leafe.com>
|
||||||
Eldar Nugaev <enugaev@griddynamics.com>
|
Eldar Nugaev <enugaev@griddynamics.com>
|
||||||
Eric Day <eday@oddments.org>
|
Eric Day <eday@oddments.org>
|
||||||
Ewan Mellor <ewan.mellor@citrix.com>
|
Ewan Mellor <ewan.mellor@citrix.com>
|
||||||
@ -14,6 +15,7 @@ Jay Pipes <jaypipes@gmail.com>
|
|||||||
Jesse Andrews <anotherjesse@gmail.com>
|
Jesse Andrews <anotherjesse@gmail.com>
|
||||||
Joe Heck <heckj@mac.com>
|
Joe Heck <heckj@mac.com>
|
||||||
Joel Moore <joelbm24@gmail.com>
|
Joel Moore <joelbm24@gmail.com>
|
||||||
|
Jonathan Bryce <jbryce@jbryce.com>
|
||||||
Josh Kearney <josh.kearney@rackspace.com>
|
Josh Kearney <josh.kearney@rackspace.com>
|
||||||
Joshua McKenty <jmckenty@gmail.com>
|
Joshua McKenty <jmckenty@gmail.com>
|
||||||
Justin Santa Barbara <justin@fathomdb.com>
|
Justin Santa Barbara <justin@fathomdb.com>
|
||||||
|
@ -13,7 +13,7 @@ include nova/cloudpipe/client.ovpn.template
|
|||||||
include nova/compute/fakevirtinstance.xml
|
include nova/compute/fakevirtinstance.xml
|
||||||
include nova/compute/interfaces.template
|
include nova/compute/interfaces.template
|
||||||
include nova/virt/interfaces.template
|
include nova/virt/interfaces.template
|
||||||
include nova/virt/libvirt.*.xml.template
|
include nova/virt/libvirt*.xml.template
|
||||||
include nova/tests/CA/
|
include nova/tests/CA/
|
||||||
include nova/tests/CA/cacert.pem
|
include nova/tests/CA/cacert.pem
|
||||||
include nova/tests/CA/private/
|
include nova/tests/CA/private/
|
||||||
|
@ -194,6 +194,7 @@ class HostInfo(object):
|
|||||||
|
|
||||||
|
|
||||||
class NovaAdminClient(object):
|
class NovaAdminClient(object):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
clc_url=DEFAULT_CLC_URL,
|
clc_url=DEFAULT_CLC_URL,
|
||||||
|
@ -45,7 +45,7 @@ class API(wsgi.Application):
|
|||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
if req.method == 'POST':
|
if req.method == 'POST':
|
||||||
return self.sign_csr(req)
|
return self.sign_csr(req)
|
||||||
_log.debug("Cloudpipe path is %s" % req.path_info)
|
_log.debug(_("Cloudpipe path is %s") % req.path_info)
|
||||||
if req.path_info.endswith("/getca/"):
|
if req.path_info.endswith("/getca/"):
|
||||||
return self.send_root_ca(req)
|
return self.send_root_ca(req)
|
||||||
return webob.exc.HTTPNotFound()
|
return webob.exc.HTTPNotFound()
|
||||||
@ -56,7 +56,7 @@ class API(wsgi.Application):
|
|||||||
return instance['project_id']
|
return instance['project_id']
|
||||||
|
|
||||||
def send_root_ca(self, req):
|
def send_root_ca(self, req):
|
||||||
_log.debug("Getting root ca")
|
_log.debug(_("Getting root ca"))
|
||||||
project_id = self.get_project_id_from_ip(req.remote_addr)
|
project_id = self.get_project_id_from_ip(req.remote_addr)
|
||||||
res = webob.Response()
|
res = webob.Response()
|
||||||
res.headers["Content-Type"] = "text/plain"
|
res.headers["Content-Type"] = "text/plain"
|
||||||
|
@ -77,7 +77,7 @@ class Authenticate(wsgi.Middleware):
|
|||||||
req.host,
|
req.host,
|
||||||
req.path)
|
req.path)
|
||||||
except exception.Error, ex:
|
except exception.Error, ex:
|
||||||
logging.debug("Authentication Failure: %s" % ex)
|
logging.debug(_("Authentication Failure: %s") % ex)
|
||||||
raise webob.exc.HTTPForbidden()
|
raise webob.exc.HTTPForbidden()
|
||||||
|
|
||||||
# Authenticated!
|
# Authenticated!
|
||||||
@ -120,9 +120,9 @@ class Router(wsgi.Middleware):
|
|||||||
except:
|
except:
|
||||||
raise webob.exc.HTTPBadRequest()
|
raise webob.exc.HTTPBadRequest()
|
||||||
|
|
||||||
_log.debug('action: %s' % action)
|
_log.debug(_('action: %s') % action)
|
||||||
for key, value in args.items():
|
for key, value in args.items():
|
||||||
_log.debug('arg: %s\t\tval: %s' % (key, value))
|
_log.debug(_('arg: %s\t\tval: %s') % (key, value))
|
||||||
|
|
||||||
# Success!
|
# Success!
|
||||||
req.environ['ec2.controller'] = controller
|
req.environ['ec2.controller'] = controller
|
||||||
|
@ -168,6 +168,7 @@ class AdminController(object):
|
|||||||
|
|
||||||
# FIXME(vish): these host commands don't work yet, perhaps some of the
|
# FIXME(vish): these host commands don't work yet, perhaps some of the
|
||||||
# required data can be retrieved from service objects?
|
# required data can be retrieved from service objects?
|
||||||
|
|
||||||
def describe_hosts(self, _context, **_kwargs):
|
def describe_hosts(self, _context, **_kwargs):
|
||||||
"""Returns status info for all nodes. Includes:
|
"""Returns status info for all nodes. Includes:
|
||||||
* Disk Space
|
* Disk Space
|
||||||
|
@ -92,7 +92,7 @@ class APIRequest(object):
|
|||||||
method = getattr(self.controller,
|
method = getattr(self.controller,
|
||||||
_camelcase_to_underscore(self.action))
|
_camelcase_to_underscore(self.action))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
_error = ('Unsupported API request: controller = %s,'
|
_error = _('Unsupported API request: controller = %s,'
|
||||||
'action = %s') % (self.controller, self.action)
|
'action = %s') % (self.controller, self.action)
|
||||||
_log.warning(_error)
|
_log.warning(_error)
|
||||||
# TODO: Raise custom exception, trap in apiserver,
|
# TODO: Raise custom exception, trap in apiserver,
|
||||||
|
@ -114,7 +114,7 @@ class CloudController(object):
|
|||||||
start = os.getcwd()
|
start = os.getcwd()
|
||||||
os.chdir(FLAGS.ca_path)
|
os.chdir(FLAGS.ca_path)
|
||||||
# TODO(vish): Do this with M2Crypto instead
|
# TODO(vish): Do this with M2Crypto instead
|
||||||
utils.runthis("Generating root CA: %s", "sh genrootca.sh")
|
utils.runthis(_("Generating root CA: %s"), "sh genrootca.sh")
|
||||||
os.chdir(start)
|
os.chdir(start)
|
||||||
|
|
||||||
def _get_mpi_data(self, context, project_id):
|
def _get_mpi_data(self, context, project_id):
|
||||||
@ -318,11 +318,11 @@ class CloudController(object):
|
|||||||
ip_protocol = str(ip_protocol)
|
ip_protocol = str(ip_protocol)
|
||||||
|
|
||||||
if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
|
if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
|
||||||
raise InvalidInputException('%s is not a valid ipProtocol' %
|
raise InvalidInputException(_('%s is not a valid ipProtocol') %
|
||||||
(ip_protocol,))
|
(ip_protocol,))
|
||||||
if ((min(from_port, to_port) < -1) or
|
if ((min(from_port, to_port) < -1) or
|
||||||
(max(from_port, to_port) > 65535)):
|
(max(from_port, to_port) > 65535)):
|
||||||
raise InvalidInputException('Invalid port range')
|
raise InvalidInputException(_('Invalid port range'))
|
||||||
|
|
||||||
values['protocol'] = ip_protocol
|
values['protocol'] = ip_protocol
|
||||||
values['from_port'] = from_port
|
values['from_port'] = from_port
|
||||||
@ -360,7 +360,8 @@ class CloudController(object):
|
|||||||
|
|
||||||
criteria = self._revoke_rule_args_to_dict(context, **kwargs)
|
criteria = self._revoke_rule_args_to_dict(context, **kwargs)
|
||||||
if criteria == None:
|
if criteria == None:
|
||||||
raise exception.ApiError("No rule for the specified parameters.")
|
raise exception.ApiError(_("No rule for the specified "
|
||||||
|
"parameters."))
|
||||||
|
|
||||||
for rule in security_group.rules:
|
for rule in security_group.rules:
|
||||||
match = True
|
match = True
|
||||||
@ -371,7 +372,7 @@ class CloudController(object):
|
|||||||
db.security_group_rule_destroy(context, rule['id'])
|
db.security_group_rule_destroy(context, rule['id'])
|
||||||
self._trigger_refresh_security_group(context, security_group)
|
self._trigger_refresh_security_group(context, security_group)
|
||||||
return True
|
return True
|
||||||
raise exception.ApiError("No rule for the specified parameters.")
|
raise exception.ApiError(_("No rule for the specified parameters."))
|
||||||
|
|
||||||
# TODO(soren): This has only been tested with Boto as the client.
|
# TODO(soren): This has only been tested with Boto as the client.
|
||||||
# Unfortunately, it seems Boto is using an old API
|
# Unfortunately, it seems Boto is using an old API
|
||||||
@ -387,8 +388,8 @@ class CloudController(object):
|
|||||||
values['parent_group_id'] = security_group.id
|
values['parent_group_id'] = security_group.id
|
||||||
|
|
||||||
if self._security_group_rule_exists(security_group, values):
|
if self._security_group_rule_exists(security_group, values):
|
||||||
raise exception.ApiError('This rule already exists in group %s' %
|
raise exception.ApiError(_('This rule already exists in group %s')
|
||||||
group_name)
|
% group_name)
|
||||||
|
|
||||||
security_group_rule = db.security_group_rule_create(context, values)
|
security_group_rule = db.security_group_rule_create(context, values)
|
||||||
|
|
||||||
@ -416,7 +417,7 @@ class CloudController(object):
|
|||||||
def create_security_group(self, context, group_name, group_description):
|
def create_security_group(self, context, group_name, group_description):
|
||||||
self.compute_api.ensure_default_security_group(context)
|
self.compute_api.ensure_default_security_group(context)
|
||||||
if db.security_group_exists(context, context.project_id, group_name):
|
if db.security_group_exists(context, context.project_id, group_name):
|
||||||
raise exception.ApiError('group %s already exists' % group_name)
|
raise exception.ApiError(_('group %s already exists') % group_name)
|
||||||
|
|
||||||
group = {'user_id': context.user.id,
|
group = {'user_id': context.user.id,
|
||||||
'project_id': context.project_id,
|
'project_id': context.project_id,
|
||||||
@ -529,13 +530,13 @@ class CloudController(object):
|
|||||||
def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
|
def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
|
||||||
volume_ref = db.volume_get_by_ec2_id(context, volume_id)
|
volume_ref = db.volume_get_by_ec2_id(context, volume_id)
|
||||||
if not re.match("^/dev/[a-z]d[a-z]+$", device):
|
if not re.match("^/dev/[a-z]d[a-z]+$", device):
|
||||||
raise exception.ApiError("Invalid device specified: %s. "
|
raise exception.ApiError(_("Invalid device specified: %s. "
|
||||||
"Example device: /dev/vdb" % device)
|
"Example device: /dev/vdb") % device)
|
||||||
# TODO(vish): abstract status checking?
|
# TODO(vish): abstract status checking?
|
||||||
if volume_ref['status'] != "available":
|
if volume_ref['status'] != "available":
|
||||||
raise exception.ApiError("Volume status must be available")
|
raise exception.ApiError(_("Volume status must be available"))
|
||||||
if volume_ref['attach_status'] == "attached":
|
if volume_ref['attach_status'] == "attached":
|
||||||
raise exception.ApiError("Volume is already attached")
|
raise exception.ApiError(_("Volume is already attached"))
|
||||||
internal_id = ec2_id_to_internal_id(instance_id)
|
internal_id = ec2_id_to_internal_id(instance_id)
|
||||||
instance_ref = self.compute_api.get_instance(context, internal_id)
|
instance_ref = self.compute_api.get_instance(context, internal_id)
|
||||||
host = instance_ref['host']
|
host = instance_ref['host']
|
||||||
@ -557,10 +558,10 @@ class CloudController(object):
|
|||||||
instance_ref = db.volume_get_instance(context.elevated(),
|
instance_ref = db.volume_get_instance(context.elevated(),
|
||||||
volume_ref['id'])
|
volume_ref['id'])
|
||||||
if not instance_ref:
|
if not instance_ref:
|
||||||
raise exception.ApiError("Volume isn't attached to anything!")
|
raise exception.ApiError(_("Volume isn't attached to anything!"))
|
||||||
# TODO(vish): abstract status checking?
|
# TODO(vish): abstract status checking?
|
||||||
if volume_ref['status'] == "available":
|
if volume_ref['status'] == "available":
|
||||||
raise exception.ApiError("Volume is already detached")
|
raise exception.ApiError(_("Volume is already detached"))
|
||||||
try:
|
try:
|
||||||
host = instance_ref['host']
|
host = instance_ref['host']
|
||||||
rpc.cast(context,
|
rpc.cast(context,
|
||||||
@ -689,10 +690,11 @@ class CloudController(object):
|
|||||||
def allocate_address(self, context, **kwargs):
|
def allocate_address(self, context, **kwargs):
|
||||||
# check quota
|
# check quota
|
||||||
if quota.allowed_floating_ips(context, 1) < 1:
|
if quota.allowed_floating_ips(context, 1) < 1:
|
||||||
logging.warn("Quota exceeeded for %s, tried to allocate address",
|
logging.warn(_("Quota exceeeded for %s, tried to allocate "
|
||||||
|
"address"),
|
||||||
context.project_id)
|
context.project_id)
|
||||||
raise quota.QuotaError("Address quota exceeded. You cannot "
|
raise quota.QuotaError(_("Address quota exceeded. You cannot "
|
||||||
"allocate any more addresses")
|
"allocate any more addresses"))
|
||||||
network_topic = self._get_network_topic(context)
|
network_topic = self._get_network_topic(context)
|
||||||
public_ip = rpc.call(context,
|
public_ip = rpc.call(context,
|
||||||
network_topic,
|
network_topic,
|
||||||
@ -751,7 +753,7 @@ class CloudController(object):
|
|||||||
kwargs['image_id'],
|
kwargs['image_id'],
|
||||||
min_count=int(kwargs.get('min_count', max_count)),
|
min_count=int(kwargs.get('min_count', max_count)),
|
||||||
max_count=max_count,
|
max_count=max_count,
|
||||||
kernel_id=kwargs.get('kernel_id'),
|
kernel_id=kwargs.get('kernel_id', None),
|
||||||
ramdisk_id=kwargs.get('ramdisk_id'),
|
ramdisk_id=kwargs.get('ramdisk_id'),
|
||||||
display_name=kwargs.get('display_name'),
|
display_name=kwargs.get('display_name'),
|
||||||
description=kwargs.get('display_description'),
|
description=kwargs.get('display_description'),
|
||||||
@ -805,7 +807,7 @@ class CloudController(object):
|
|||||||
# TODO: return error if not authorized
|
# TODO: return error if not authorized
|
||||||
volume_ref = db.volume_get_by_ec2_id(context, volume_id)
|
volume_ref = db.volume_get_by_ec2_id(context, volume_id)
|
||||||
if volume_ref['status'] != "available":
|
if volume_ref['status'] != "available":
|
||||||
raise exception.ApiError("Volume status must be available")
|
raise exception.ApiError(_("Volume status must be available"))
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
db.volume_update(context, volume_ref['id'], {'status': 'deleting',
|
db.volume_update(context, volume_ref['id'], {'status': 'deleting',
|
||||||
'terminated_at': now})
|
'terminated_at': now})
|
||||||
@ -836,11 +838,12 @@ class CloudController(object):
|
|||||||
|
|
||||||
def describe_image_attribute(self, context, image_id, attribute, **kwargs):
|
def describe_image_attribute(self, context, image_id, attribute, **kwargs):
|
||||||
if attribute != 'launchPermission':
|
if attribute != 'launchPermission':
|
||||||
raise exception.ApiError('attribute not supported: %s' % attribute)
|
raise exception.ApiError(_('attribute not supported: %s')
|
||||||
|
% attribute)
|
||||||
try:
|
try:
|
||||||
image = self.image_service.show(context, image_id)
|
image = self.image_service.show(context, image_id)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise exception.ApiError('invalid id: %s' % image_id)
|
raise exception.ApiError(_('invalid id: %s') % image_id)
|
||||||
result = {'image_id': image_id, 'launchPermission': []}
|
result = {'image_id': image_id, 'launchPermission': []}
|
||||||
if image['isPublic']:
|
if image['isPublic']:
|
||||||
result['launchPermission'].append({'group': 'all'})
|
result['launchPermission'].append({'group': 'all'})
|
||||||
@ -850,13 +853,14 @@ class CloudController(object):
|
|||||||
operation_type, **kwargs):
|
operation_type, **kwargs):
|
||||||
# TODO(devcamcar): Support users and groups other than 'all'.
|
# TODO(devcamcar): Support users and groups other than 'all'.
|
||||||
if attribute != 'launchPermission':
|
if attribute != 'launchPermission':
|
||||||
raise exception.ApiError('attribute not supported: %s' % attribute)
|
raise exception.ApiError(_('attribute not supported: %s')
|
||||||
|
% attribute)
|
||||||
if not 'user_group' in kwargs:
|
if not 'user_group' in kwargs:
|
||||||
raise exception.ApiError('user or group not specified')
|
raise exception.ApiError(_('user or group not specified'))
|
||||||
if len(kwargs['user_group']) != 1 and kwargs['user_group'][0] != 'all':
|
if len(kwargs['user_group']) != 1 and kwargs['user_group'][0] != 'all':
|
||||||
raise exception.ApiError('only group "all" is supported')
|
raise exception.ApiError(_('only group "all" is supported'))
|
||||||
if not operation_type in ['add', 'remove']:
|
if not operation_type in ['add', 'remove']:
|
||||||
raise exception.ApiError('operation_type must be add or remove')
|
raise exception.ApiError(_('operation_type must be add or remove'))
|
||||||
return self.image_service.modify(context, image_id, operation_type)
|
return self.image_service.modify(context, image_id, operation_type)
|
||||||
|
|
||||||
def update_image(self, context, image_id, **kwargs):
|
def update_image(self, context, image_id, **kwargs):
|
||||||
|
@ -65,7 +65,7 @@ class MetadataRequestHandler(object):
|
|||||||
cc = cloud.CloudController()
|
cc = cloud.CloudController()
|
||||||
meta_data = cc.get_metadata(req.remote_addr)
|
meta_data = cc.get_metadata(req.remote_addr)
|
||||||
if meta_data is None:
|
if meta_data is None:
|
||||||
logging.error('Failed to get metadata for ip: %s' %
|
logging.error(_('Failed to get metadata for ip: %s') %
|
||||||
req.remote_addr)
|
req.remote_addr)
|
||||||
raise webob.exc.HTTPNotFound()
|
raise webob.exc.HTTPNotFound()
|
||||||
data = self.lookup(req.path_info, meta_data)
|
data = self.lookup(req.path_info, meta_data)
|
||||||
|
@ -66,7 +66,7 @@ class API(wsgi.Middleware):
|
|||||||
try:
|
try:
|
||||||
return req.get_response(self.application)
|
return req.get_response(self.application)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.warn("Caught error: %s" % str(ex))
|
logging.warn(_("Caught error: %s") % str(ex))
|
||||||
logging.debug(traceback.format_exc())
|
logging.debug(traceback.format_exc())
|
||||||
exc = webob.exc.HTTPInternalServerError(explanation=str(ex))
|
exc = webob.exc.HTTPInternalServerError(explanation=str(ex))
|
||||||
return faults.Fault(exc)
|
return faults.Fault(exc)
|
||||||
@ -133,7 +133,7 @@ class RateLimitingMiddleware(wsgi.Middleware):
|
|||||||
if delay:
|
if delay:
|
||||||
# TODO(gundlach): Get the retry-after format correct.
|
# TODO(gundlach): Get the retry-after format correct.
|
||||||
exc = webob.exc.HTTPRequestEntityTooLarge(
|
exc = webob.exc.HTTPRequestEntityTooLarge(
|
||||||
explanation='Too many requests.',
|
explanation=_('Too many requests.'),
|
||||||
headers={'Retry-After': time.time() + delay})
|
headers={'Retry-After': time.time() + delay})
|
||||||
raise faults.Fault(exc)
|
raise faults.Fault(exc)
|
||||||
return self.application
|
return self.application
|
||||||
@ -170,9 +170,16 @@ class APIRouter(wsgi.Router):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
|
|
||||||
|
server_members = {'action': 'POST'}
|
||||||
|
if FLAGS.allow_admin_api:
|
||||||
|
logging.debug("Including admin operations in API.")
|
||||||
|
server_members['pause'] = 'POST'
|
||||||
|
server_members['unpause'] = 'POST'
|
||||||
|
|
||||||
mapper.resource("server", "servers", controller=servers.Controller(),
|
mapper.resource("server", "servers", controller=servers.Controller(),
|
||||||
collection={'detail': 'GET'},
|
collection={'detail': 'GET'},
|
||||||
member={'action': 'POST'})
|
member=server_members)
|
||||||
|
|
||||||
mapper.resource("backup_schedule", "backup_schedules",
|
mapper.resource("backup_schedule", "backup_schedules",
|
||||||
controller=backup_schedules.Controller(),
|
controller=backup_schedules.Controller(),
|
||||||
@ -186,10 +193,6 @@ class APIRouter(wsgi.Router):
|
|||||||
mapper.resource("sharedipgroup", "sharedipgroups",
|
mapper.resource("sharedipgroup", "sharedipgroups",
|
||||||
controller=sharedipgroups.Controller())
|
controller=sharedipgroups.Controller())
|
||||||
|
|
||||||
if FLAGS.allow_admin_api:
|
|
||||||
logging.debug("Including admin operations in API.")
|
|
||||||
# TODO: Place routes for admin operations here.
|
|
||||||
|
|
||||||
super(APIRouter, self).__init__(mapper)
|
super(APIRouter, self).__init__(mapper)
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import nova.image.service
|
|||||||
|
|
||||||
|
|
||||||
class Controller(wsgi.Controller):
|
class Controller(wsgi.Controller):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
@ -27,6 +30,10 @@ from nova.compute import power_state
|
|||||||
import nova.api.openstack
|
import nova.api.openstack
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger('server')
|
||||||
|
LOG.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def _entity_list(entities):
|
def _entity_list(entities):
|
||||||
""" Coerces a list of servers into proper dictionary format """
|
""" Coerces a list of servers into proper dictionary format """
|
||||||
return dict(servers=entities)
|
return dict(servers=entities)
|
||||||
@ -166,3 +173,25 @@ class Controller(wsgi.Controller):
|
|||||||
except:
|
except:
|
||||||
return faults.Fault(exc.HTTPUnprocessableEntity())
|
return faults.Fault(exc.HTTPUnprocessableEntity())
|
||||||
return exc.HTTPAccepted()
|
return exc.HTTPAccepted()
|
||||||
|
|
||||||
|
def pause(self, req, id):
|
||||||
|
""" Permit Admins to Pause the server. """
|
||||||
|
ctxt = req.environ['nova.context']
|
||||||
|
try:
|
||||||
|
self.compute_api.pause(ctxt, id)
|
||||||
|
except:
|
||||||
|
readable = traceback.format_exc()
|
||||||
|
logging.error("Compute.api::pause %s", readable)
|
||||||
|
return faults.Fault(exc.HTTPUnprocessableEntity())
|
||||||
|
return exc.HTTPAccepted()
|
||||||
|
|
||||||
|
def unpause(self, req, id):
|
||||||
|
""" Permit Admins to Unpause the server. """
|
||||||
|
ctxt = req.environ['nova.context']
|
||||||
|
try:
|
||||||
|
self.compute_api.unpause(ctxt, id)
|
||||||
|
except:
|
||||||
|
readable = traceback.format_exc()
|
||||||
|
logging.error("Compute.api::unpause %s", readable)
|
||||||
|
return faults.Fault(exc.HTTPUnprocessableEntity())
|
||||||
|
return exc.HTTPAccepted()
|
||||||
|
@ -37,7 +37,6 @@ class DbDriver(object):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Imports the LDAP module"""
|
"""Imports the LDAP module"""
|
||||||
pass
|
pass
|
||||||
db
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
@ -83,7 +82,7 @@ class DbDriver(object):
|
|||||||
user_ref = db.user_create(context.get_admin_context(), values)
|
user_ref = db.user_create(context.get_admin_context(), values)
|
||||||
return self._db_user_to_auth_user(user_ref)
|
return self._db_user_to_auth_user(user_ref)
|
||||||
except exception.Duplicate, e:
|
except exception.Duplicate, e:
|
||||||
raise exception.Duplicate('User %s already exists' % name)
|
raise exception.Duplicate(_('User %s already exists') % name)
|
||||||
|
|
||||||
def _db_user_to_auth_user(self, user_ref):
|
def _db_user_to_auth_user(self, user_ref):
|
||||||
return {'id': user_ref['id'],
|
return {'id': user_ref['id'],
|
||||||
@ -105,8 +104,9 @@ class DbDriver(object):
|
|||||||
"""Create a project"""
|
"""Create a project"""
|
||||||
manager = db.user_get(context.get_admin_context(), manager_uid)
|
manager = db.user_get(context.get_admin_context(), manager_uid)
|
||||||
if not manager:
|
if not manager:
|
||||||
raise exception.NotFound("Project can't be created because "
|
raise exception.NotFound(_("Project can't be created because "
|
||||||
"manager %s doesn't exist" % manager_uid)
|
"manager %s doesn't exist")
|
||||||
|
% manager_uid)
|
||||||
|
|
||||||
# description is a required attribute
|
# description is a required attribute
|
||||||
if description is None:
|
if description is None:
|
||||||
@ -133,8 +133,8 @@ class DbDriver(object):
|
|||||||
try:
|
try:
|
||||||
project = db.project_create(context.get_admin_context(), values)
|
project = db.project_create(context.get_admin_context(), values)
|
||||||
except exception.Duplicate:
|
except exception.Duplicate:
|
||||||
raise exception.Duplicate("Project can't be created because "
|
raise exception.Duplicate(_("Project can't be created because "
|
||||||
"project %s already exists" % name)
|
"project %s already exists") % name)
|
||||||
|
|
||||||
for member in members:
|
for member in members:
|
||||||
db.project_add_member(context.get_admin_context(),
|
db.project_add_member(context.get_admin_context(),
|
||||||
@ -155,8 +155,8 @@ class DbDriver(object):
|
|||||||
if manager_uid:
|
if manager_uid:
|
||||||
manager = db.user_get(context.get_admin_context(), manager_uid)
|
manager = db.user_get(context.get_admin_context(), manager_uid)
|
||||||
if not manager:
|
if not manager:
|
||||||
raise exception.NotFound("Project can't be modified because "
|
raise exception.NotFound(_("Project can't be modified because "
|
||||||
"manager %s doesn't exist" %
|
"manager %s doesn't exist") %
|
||||||
manager_uid)
|
manager_uid)
|
||||||
values['project_manager'] = manager['id']
|
values['project_manager'] = manager['id']
|
||||||
if description:
|
if description:
|
||||||
@ -243,8 +243,8 @@ class DbDriver(object):
|
|||||||
def _validate_user_and_project(self, user_id, project_id):
|
def _validate_user_and_project(self, user_id, project_id):
|
||||||
user = db.user_get(context.get_admin_context(), user_id)
|
user = db.user_get(context.get_admin_context(), user_id)
|
||||||
if not user:
|
if not user:
|
||||||
raise exception.NotFound('User "%s" not found' % user_id)
|
raise exception.NotFound(_('User "%s" not found') % user_id)
|
||||||
project = db.project_get(context.get_admin_context(), project_id)
|
project = db.project_get(context.get_admin_context(), project_id)
|
||||||
if not project:
|
if not project:
|
||||||
raise exception.NotFound('Project "%s" not found' % project_id)
|
raise exception.NotFound(_('Project "%s" not found') % project_id)
|
||||||
return user, project
|
return user, project
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
"""Fake LDAP server for test harness, backs to ReDIS.
|
"""Fake LDAP server for test harness.
|
||||||
|
|
||||||
This class does very little error checking, and knows nothing about ldap
|
This class does very little error checking, and knows nothing about ldap
|
||||||
class definitions. It implements the minimum emulation of the python ldap
|
class definitions. It implements the minimum emulation of the python ldap
|
||||||
@ -23,34 +23,65 @@ library to work with nova.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
import json
|
import json
|
||||||
import redis
|
|
||||||
|
|
||||||
from nova import flags
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
flags.DEFINE_string('redis_host', '127.0.0.1',
|
|
||||||
'Host that redis is running on.')
|
|
||||||
flags.DEFINE_integer('redis_port', 6379,
|
|
||||||
'Port that redis is running on.')
|
|
||||||
flags.DEFINE_integer('redis_db', 0, 'Multiple DB keeps tests away')
|
|
||||||
|
|
||||||
|
|
||||||
class Redis(object):
|
class Store(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
if hasattr(self.__class__, '_instance'):
|
if hasattr(self.__class__, '_instance'):
|
||||||
raise Exception('Attempted to instantiate singleton')
|
raise Exception(_('Attempted to instantiate singleton'))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def instance(cls):
|
def instance(cls):
|
||||||
if not hasattr(cls, '_instance'):
|
if not hasattr(cls, '_instance'):
|
||||||
inst = redis.Redis(host=FLAGS.redis_host,
|
cls._instance = _StorageDict()
|
||||||
port=FLAGS.redis_port,
|
|
||||||
db=FLAGS.redis_db)
|
|
||||||
cls._instance = inst
|
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
|
|
||||||
|
class _StorageDict(dict):
|
||||||
|
def keys(self, pat=None):
|
||||||
|
ret = super(_StorageDict, self).keys()
|
||||||
|
if pat is not None:
|
||||||
|
ret = fnmatch.filter(ret, pat)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def delete(self, key):
|
||||||
|
try:
|
||||||
|
del self[key]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def flushdb(self):
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def hgetall(self, key):
|
||||||
|
"""Returns the hash for the given key; creates
|
||||||
|
the hash if the key doesn't exist."""
|
||||||
|
try:
|
||||||
|
return self[key]
|
||||||
|
except KeyError:
|
||||||
|
self[key] = {}
|
||||||
|
return self[key]
|
||||||
|
|
||||||
|
def hget(self, key, field):
|
||||||
|
hashdict = self.hgetall(key)
|
||||||
|
try:
|
||||||
|
return hashdict[field]
|
||||||
|
except KeyError:
|
||||||
|
hashdict[field] = {}
|
||||||
|
return hashdict[field]
|
||||||
|
|
||||||
|
def hset(self, key, field, val):
|
||||||
|
hashdict = self.hgetall(key)
|
||||||
|
hashdict[field] = val
|
||||||
|
|
||||||
|
def hmset(self, key, value_dict):
|
||||||
|
hashdict = self.hgetall(key)
|
||||||
|
for field, val in value_dict.items():
|
||||||
|
hashdict[field] = val
|
||||||
|
|
||||||
|
|
||||||
SCOPE_BASE = 0
|
SCOPE_BASE = 0
|
||||||
SCOPE_ONELEVEL = 1 # Not implemented
|
SCOPE_ONELEVEL = 1 # Not implemented
|
||||||
SCOPE_SUBTREE = 2
|
SCOPE_SUBTREE = 2
|
||||||
@ -169,8 +200,6 @@ def _to_json(unencoded):
|
|||||||
|
|
||||||
|
|
||||||
class FakeLDAP(object):
|
class FakeLDAP(object):
|
||||||
#TODO(vish): refactor this class to use a wrapper instead of accessing
|
|
||||||
# redis directly
|
|
||||||
"""Fake LDAP connection."""
|
"""Fake LDAP connection."""
|
||||||
|
|
||||||
def simple_bind_s(self, dn, password):
|
def simple_bind_s(self, dn, password):
|
||||||
@ -183,14 +212,13 @@ class FakeLDAP(object):
|
|||||||
|
|
||||||
def add_s(self, dn, attr):
|
def add_s(self, dn, attr):
|
||||||
"""Add an object with the specified attributes at dn."""
|
"""Add an object with the specified attributes at dn."""
|
||||||
key = "%s%s" % (self.__redis_prefix, dn)
|
key = "%s%s" % (self.__prefix, dn)
|
||||||
|
|
||||||
value_dict = dict([(k, _to_json(v)) for k, v in attr])
|
value_dict = dict([(k, _to_json(v)) for k, v in attr])
|
||||||
Redis.instance().hmset(key, value_dict)
|
Store.instance().hmset(key, value_dict)
|
||||||
|
|
||||||
def delete_s(self, dn):
|
def delete_s(self, dn):
|
||||||
"""Remove the ldap object at specified dn."""
|
"""Remove the ldap object at specified dn."""
|
||||||
Redis.instance().delete("%s%s" % (self.__redis_prefix, dn))
|
Store.instance().delete("%s%s" % (self.__prefix, dn))
|
||||||
|
|
||||||
def modify_s(self, dn, attrs):
|
def modify_s(self, dn, attrs):
|
||||||
"""Modify the object at dn using the attribute list.
|
"""Modify the object at dn using the attribute list.
|
||||||
@ -201,18 +229,18 @@ class FakeLDAP(object):
|
|||||||
([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
|
([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
redis = Redis.instance()
|
store = Store.instance()
|
||||||
key = "%s%s" % (self.__redis_prefix, dn)
|
key = "%s%s" % (self.__prefix, dn)
|
||||||
|
|
||||||
for cmd, k, v in attrs:
|
for cmd, k, v in attrs:
|
||||||
values = _from_json(redis.hget(key, k))
|
values = _from_json(store.hget(key, k))
|
||||||
if cmd == MOD_ADD:
|
if cmd == MOD_ADD:
|
||||||
values.append(v)
|
values.append(v)
|
||||||
elif cmd == MOD_REPLACE:
|
elif cmd == MOD_REPLACE:
|
||||||
values = [v]
|
values = [v]
|
||||||
else:
|
else:
|
||||||
values.remove(v)
|
values.remove(v)
|
||||||
values = redis.hset(key, k, _to_json(values))
|
values = store.hset(key, k, _to_json(values))
|
||||||
|
|
||||||
def search_s(self, dn, scope, query=None, fields=None):
|
def search_s(self, dn, scope, query=None, fields=None):
|
||||||
"""Search for all matching objects under dn using the query.
|
"""Search for all matching objects under dn using the query.
|
||||||
@ -226,16 +254,17 @@ class FakeLDAP(object):
|
|||||||
"""
|
"""
|
||||||
if scope != SCOPE_BASE and scope != SCOPE_SUBTREE:
|
if scope != SCOPE_BASE and scope != SCOPE_SUBTREE:
|
||||||
raise NotImplementedError(str(scope))
|
raise NotImplementedError(str(scope))
|
||||||
redis = Redis.instance()
|
store = Store.instance()
|
||||||
if scope == SCOPE_BASE:
|
if scope == SCOPE_BASE:
|
||||||
keys = ["%s%s" % (self.__redis_prefix, dn)]
|
keys = ["%s%s" % (self.__prefix, dn)]
|
||||||
else:
|
else:
|
||||||
keys = redis.keys("%s*%s" % (self.__redis_prefix, dn))
|
keys = store.keys("%s*%s" % (self.__prefix, dn))
|
||||||
|
|
||||||
objects = []
|
objects = []
|
||||||
for key in keys:
|
for key in keys:
|
||||||
# get the attributes from redis
|
# get the attributes from the store
|
||||||
attrs = redis.hgetall(key)
|
attrs = store.hgetall(key)
|
||||||
# turn the values from redis into lists
|
# turn the values from the store into lists
|
||||||
# pylint: disable-msg=E1103
|
# pylint: disable-msg=E1103
|
||||||
attrs = dict([(k, _from_json(v))
|
attrs = dict([(k, _from_json(v))
|
||||||
for k, v in attrs.iteritems()])
|
for k, v in attrs.iteritems()])
|
||||||
@ -244,13 +273,13 @@ class FakeLDAP(object):
|
|||||||
# filter the attributes by fields
|
# filter the attributes by fields
|
||||||
attrs = dict([(k, v) for k, v in attrs.iteritems()
|
attrs = dict([(k, v) for k, v in attrs.iteritems()
|
||||||
if not fields or k in fields])
|
if not fields or k in fields])
|
||||||
objects.append((key[len(self.__redis_prefix):], attrs))
|
objects.append((key[len(self.__prefix):], attrs))
|
||||||
# pylint: enable-msg=E1103
|
# pylint: enable-msg=E1103
|
||||||
if objects == []:
|
if objects == []:
|
||||||
raise NO_SUCH_OBJECT()
|
raise NO_SUCH_OBJECT()
|
||||||
return objects
|
return objects
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def __redis_prefix(self): # pylint: disable-msg=R0201
|
def __prefix(self): # pylint: disable-msg=R0201
|
||||||
"""Get the prefix to use for all redis keys."""
|
"""Get the prefix to use for all keys."""
|
||||||
return 'ldap:'
|
return 'ldap:'
|
||||||
|
@ -159,7 +159,7 @@ class LdapDriver(object):
|
|||||||
self.conn.modify_s(self.__uid_to_dn(name), attr)
|
self.conn.modify_s(self.__uid_to_dn(name), attr)
|
||||||
return self.get_user(name)
|
return self.get_user(name)
|
||||||
else:
|
else:
|
||||||
raise exception.NotFound("LDAP object for %s doesn't exist"
|
raise exception.NotFound(_("LDAP object for %s doesn't exist")
|
||||||
% name)
|
% name)
|
||||||
else:
|
else:
|
||||||
attr = [
|
attr = [
|
||||||
@ -182,11 +182,12 @@ class LdapDriver(object):
|
|||||||
description=None, member_uids=None):
|
description=None, member_uids=None):
|
||||||
"""Create a project"""
|
"""Create a project"""
|
||||||
if self.__project_exists(name):
|
if self.__project_exists(name):
|
||||||
raise exception.Duplicate("Project can't be created because "
|
raise exception.Duplicate(_("Project can't be created because "
|
||||||
"project %s already exists" % name)
|
"project %s already exists") % name)
|
||||||
if not self.__user_exists(manager_uid):
|
if not self.__user_exists(manager_uid):
|
||||||
raise exception.NotFound("Project can't be created because "
|
raise exception.NotFound(_("Project can't be created because "
|
||||||
"manager %s doesn't exist" % manager_uid)
|
"manager %s doesn't exist")
|
||||||
|
% manager_uid)
|
||||||
manager_dn = self.__uid_to_dn(manager_uid)
|
manager_dn = self.__uid_to_dn(manager_uid)
|
||||||
# description is a required attribute
|
# description is a required attribute
|
||||||
if description is None:
|
if description is None:
|
||||||
@ -195,8 +196,8 @@ class LdapDriver(object):
|
|||||||
if member_uids is not None:
|
if member_uids is not None:
|
||||||
for member_uid in member_uids:
|
for member_uid in member_uids:
|
||||||
if not self.__user_exists(member_uid):
|
if not self.__user_exists(member_uid):
|
||||||
raise exception.NotFound("Project can't be created "
|
raise exception.NotFound(_("Project can't be created "
|
||||||
"because user %s doesn't exist"
|
"because user %s doesn't exist")
|
||||||
% member_uid)
|
% member_uid)
|
||||||
members.append(self.__uid_to_dn(member_uid))
|
members.append(self.__uid_to_dn(member_uid))
|
||||||
# always add the manager as a member because members is required
|
# always add the manager as a member because members is required
|
||||||
@ -218,9 +219,9 @@ class LdapDriver(object):
|
|||||||
attr = []
|
attr = []
|
||||||
if manager_uid:
|
if manager_uid:
|
||||||
if not self.__user_exists(manager_uid):
|
if not self.__user_exists(manager_uid):
|
||||||
raise exception.NotFound("Project can't be modified because "
|
raise exception.NotFound(_("Project can't be modified because "
|
||||||
"manager %s doesn't exist" %
|
"manager %s doesn't exist")
|
||||||
manager_uid)
|
% manager_uid)
|
||||||
manager_dn = self.__uid_to_dn(manager_uid)
|
manager_dn = self.__uid_to_dn(manager_uid)
|
||||||
attr.append((self.ldap.MOD_REPLACE, 'projectManager', manager_dn))
|
attr.append((self.ldap.MOD_REPLACE, 'projectManager', manager_dn))
|
||||||
if description:
|
if description:
|
||||||
@ -416,8 +417,9 @@ class LdapDriver(object):
|
|||||||
if member_uids is not None:
|
if member_uids is not None:
|
||||||
for member_uid in member_uids:
|
for member_uid in member_uids:
|
||||||
if not self.__user_exists(member_uid):
|
if not self.__user_exists(member_uid):
|
||||||
raise exception.NotFound("Group can't be created "
|
raise exception.NotFound(_("Group can't be created "
|
||||||
"because user %s doesn't exist" % member_uid)
|
"because user %s doesn't exist")
|
||||||
|
% member_uid)
|
||||||
members.append(self.__uid_to_dn(member_uid))
|
members.append(self.__uid_to_dn(member_uid))
|
||||||
dn = self.__uid_to_dn(uid)
|
dn = self.__uid_to_dn(uid)
|
||||||
if not dn in members:
|
if not dn in members:
|
||||||
@ -432,8 +434,9 @@ class LdapDriver(object):
|
|||||||
def __is_in_group(self, uid, group_dn):
|
def __is_in_group(self, uid, group_dn):
|
||||||
"""Check if user is in group"""
|
"""Check if user is in group"""
|
||||||
if not self.__user_exists(uid):
|
if not self.__user_exists(uid):
|
||||||
raise exception.NotFound("User %s can't be searched in group "
|
raise exception.NotFound(_("User %s can't be searched in group "
|
||||||
"becuase the user doesn't exist" % (uid,))
|
"because the user doesn't exist")
|
||||||
|
% uid)
|
||||||
if not self.__group_exists(group_dn):
|
if not self.__group_exists(group_dn):
|
||||||
return False
|
return False
|
||||||
res = self.__find_object(group_dn,
|
res = self.__find_object(group_dn,
|
||||||
@ -444,28 +447,30 @@ class LdapDriver(object):
|
|||||||
def __add_to_group(self, uid, group_dn):
|
def __add_to_group(self, uid, group_dn):
|
||||||
"""Add user to group"""
|
"""Add user to group"""
|
||||||
if not self.__user_exists(uid):
|
if not self.__user_exists(uid):
|
||||||
raise exception.NotFound("User %s can't be added to the group "
|
raise exception.NotFound(_("User %s can't be added to the group "
|
||||||
"becuase the user doesn't exist" % (uid,))
|
"because the user doesn't exist")
|
||||||
|
% uid)
|
||||||
if not self.__group_exists(group_dn):
|
if not self.__group_exists(group_dn):
|
||||||
raise exception.NotFound("The group at dn %s doesn't exist" %
|
raise exception.NotFound(_("The group at dn %s doesn't exist")
|
||||||
(group_dn,))
|
% group_dn)
|
||||||
if self.__is_in_group(uid, group_dn):
|
if self.__is_in_group(uid, group_dn):
|
||||||
raise exception.Duplicate("User %s is already a member of "
|
raise exception.Duplicate(_("User %s is already a member of "
|
||||||
"the group %s" % (uid, group_dn))
|
"the group %s") % (uid, group_dn))
|
||||||
attr = [(self.ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))]
|
attr = [(self.ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))]
|
||||||
self.conn.modify_s(group_dn, attr)
|
self.conn.modify_s(group_dn, attr)
|
||||||
|
|
||||||
def __remove_from_group(self, uid, group_dn):
|
def __remove_from_group(self, uid, group_dn):
|
||||||
"""Remove user from group"""
|
"""Remove user from group"""
|
||||||
if not self.__group_exists(group_dn):
|
if not self.__group_exists(group_dn):
|
||||||
raise exception.NotFound("The group at dn %s doesn't exist" %
|
raise exception.NotFound(_("The group at dn %s doesn't exist")
|
||||||
(group_dn,))
|
% group_dn)
|
||||||
if not self.__user_exists(uid):
|
if not self.__user_exists(uid):
|
||||||
raise exception.NotFound("User %s can't be removed from the "
|
raise exception.NotFound(_("User %s can't be removed from the "
|
||||||
"group because the user doesn't exist" % (uid,))
|
"group because the user doesn't exist")
|
||||||
|
% uid)
|
||||||
if not self.__is_in_group(uid, group_dn):
|
if not self.__is_in_group(uid, group_dn):
|
||||||
raise exception.NotFound("User %s is not a member of the group" %
|
raise exception.NotFound(_("User %s is not a member of the group")
|
||||||
(uid,))
|
% uid)
|
||||||
# NOTE(vish): remove user from group and any sub_groups
|
# NOTE(vish): remove user from group and any sub_groups
|
||||||
sub_dns = self.__find_group_dns_with_member(
|
sub_dns = self.__find_group_dns_with_member(
|
||||||
group_dn, uid)
|
group_dn, uid)
|
||||||
@ -479,15 +484,16 @@ class LdapDriver(object):
|
|||||||
try:
|
try:
|
||||||
self.conn.modify_s(group_dn, attr)
|
self.conn.modify_s(group_dn, attr)
|
||||||
except self.ldap.OBJECT_CLASS_VIOLATION:
|
except self.ldap.OBJECT_CLASS_VIOLATION:
|
||||||
logging.debug("Attempted to remove the last member of a group. "
|
logging.debug(_("Attempted to remove the last member of a group. "
|
||||||
"Deleting the group at %s instead.", group_dn)
|
"Deleting the group at %s instead."), group_dn)
|
||||||
self.__delete_group(group_dn)
|
self.__delete_group(group_dn)
|
||||||
|
|
||||||
def __remove_from_all(self, uid):
|
def __remove_from_all(self, uid):
|
||||||
"""Remove user from all roles and projects"""
|
"""Remove user from all roles and projects"""
|
||||||
if not self.__user_exists(uid):
|
if not self.__user_exists(uid):
|
||||||
raise exception.NotFound("User %s can't be removed from all "
|
raise exception.NotFound(_("User %s can't be removed from all "
|
||||||
"because the user doesn't exist" % (uid,))
|
"because the user doesn't exist")
|
||||||
|
% uid)
|
||||||
role_dns = self.__find_group_dns_with_member(
|
role_dns = self.__find_group_dns_with_member(
|
||||||
FLAGS.role_project_subtree, uid)
|
FLAGS.role_project_subtree, uid)
|
||||||
for role_dn in role_dns:
|
for role_dn in role_dns:
|
||||||
@ -500,7 +506,8 @@ class LdapDriver(object):
|
|||||||
def __delete_group(self, group_dn):
|
def __delete_group(self, group_dn):
|
||||||
"""Delete Group"""
|
"""Delete Group"""
|
||||||
if not self.__group_exists(group_dn):
|
if not self.__group_exists(group_dn):
|
||||||
raise exception.NotFound("Group at dn %s doesn't exist" % group_dn)
|
raise exception.NotFound(_("Group at dn %s doesn't exist")
|
||||||
|
% group_dn)
|
||||||
self.conn.delete_s(group_dn)
|
self.conn.delete_s(group_dn)
|
||||||
|
|
||||||
def __delete_roles(self, project_dn):
|
def __delete_roles(self, project_dn):
|
||||||
|
@ -257,12 +257,12 @@ class AuthManager(object):
|
|||||||
# TODO(vish): check for valid timestamp
|
# TODO(vish): check for valid timestamp
|
||||||
(access_key, _sep, project_id) = access.partition(':')
|
(access_key, _sep, project_id) = access.partition(':')
|
||||||
|
|
||||||
logging.info('Looking up user: %r', access_key)
|
logging.info(_('Looking up user: %r'), access_key)
|
||||||
user = self.get_user_from_access_key(access_key)
|
user = self.get_user_from_access_key(access_key)
|
||||||
logging.info('user: %r', user)
|
logging.info('user: %r', user)
|
||||||
if user == None:
|
if user == None:
|
||||||
raise exception.NotFound('No user found for access key %s' %
|
raise exception.NotFound(_('No user found for access key %s')
|
||||||
access_key)
|
% access_key)
|
||||||
|
|
||||||
# NOTE(vish): if we stop using project name as id we need better
|
# NOTE(vish): if we stop using project name as id we need better
|
||||||
# logic to find a default project for user
|
# logic to find a default project for user
|
||||||
@ -271,12 +271,12 @@ class AuthManager(object):
|
|||||||
|
|
||||||
project = self.get_project(project_id)
|
project = self.get_project(project_id)
|
||||||
if project == None:
|
if project == None:
|
||||||
raise exception.NotFound('No project called %s could be found' %
|
raise exception.NotFound(_('No project called %s could be found')
|
||||||
project_id)
|
% project_id)
|
||||||
if not self.is_admin(user) and not self.is_project_member(user,
|
if not self.is_admin(user) and not self.is_project_member(user,
|
||||||
project):
|
project):
|
||||||
raise exception.NotFound('User %s is not a member of project %s' %
|
raise exception.NotFound(_('User %s is not a member of project %s')
|
||||||
(user.id, project.id))
|
% (user.id, project.id))
|
||||||
if check_type == 's3':
|
if check_type == 's3':
|
||||||
sign = signer.Signer(user.secret.encode())
|
sign = signer.Signer(user.secret.encode())
|
||||||
expected_signature = sign.s3_authorization(headers, verb, path)
|
expected_signature = sign.s3_authorization(headers, verb, path)
|
||||||
@ -284,7 +284,7 @@ class AuthManager(object):
|
|||||||
logging.debug('expected_signature: %s', expected_signature)
|
logging.debug('expected_signature: %s', expected_signature)
|
||||||
logging.debug('signature: %s', signature)
|
logging.debug('signature: %s', signature)
|
||||||
if signature != expected_signature:
|
if signature != expected_signature:
|
||||||
raise exception.NotAuthorized('Signature does not match')
|
raise exception.NotAuthorized(_('Signature does not match'))
|
||||||
elif check_type == 'ec2':
|
elif check_type == 'ec2':
|
||||||
# NOTE(vish): hmac can't handle unicode, so encode ensures that
|
# NOTE(vish): hmac can't handle unicode, so encode ensures that
|
||||||
# secret isn't unicode
|
# secret isn't unicode
|
||||||
@ -294,7 +294,7 @@ class AuthManager(object):
|
|||||||
logging.debug('expected_signature: %s', expected_signature)
|
logging.debug('expected_signature: %s', expected_signature)
|
||||||
logging.debug('signature: %s', signature)
|
logging.debug('signature: %s', signature)
|
||||||
if signature != expected_signature:
|
if signature != expected_signature:
|
||||||
raise exception.NotAuthorized('Signature does not match')
|
raise exception.NotAuthorized(_('Signature does not match'))
|
||||||
return (user, project)
|
return (user, project)
|
||||||
|
|
||||||
def get_access_key(self, user, project):
|
def get_access_key(self, user, project):
|
||||||
@ -364,7 +364,7 @@ class AuthManager(object):
|
|||||||
with self.driver() as drv:
|
with self.driver() as drv:
|
||||||
if role == 'projectmanager':
|
if role == 'projectmanager':
|
||||||
if not project:
|
if not project:
|
||||||
raise exception.Error("Must specify project")
|
raise exception.Error(_("Must specify project"))
|
||||||
return self.is_project_manager(user, project)
|
return self.is_project_manager(user, project)
|
||||||
|
|
||||||
global_role = drv.has_role(User.safe_id(user),
|
global_role = drv.has_role(User.safe_id(user),
|
||||||
@ -398,9 +398,9 @@ class AuthManager(object):
|
|||||||
@param project: Project in which to add local role.
|
@param project: Project in which to add local role.
|
||||||
"""
|
"""
|
||||||
if role not in FLAGS.allowed_roles:
|
if role not in FLAGS.allowed_roles:
|
||||||
raise exception.NotFound("The %s role can not be found" % role)
|
raise exception.NotFound(_("The %s role can not be found") % role)
|
||||||
if project is not None and role in FLAGS.global_roles:
|
if project is not None and role in FLAGS.global_roles:
|
||||||
raise exception.NotFound("The %s role is global only" % role)
|
raise exception.NotFound(_("The %s role is global only") % role)
|
||||||
with self.driver() as drv:
|
with self.driver() as drv:
|
||||||
drv.add_role(User.safe_id(user), role, Project.safe_id(project))
|
drv.add_role(User.safe_id(user), role, Project.safe_id(project))
|
||||||
|
|
||||||
@ -546,7 +546,8 @@ class AuthManager(object):
|
|||||||
Project.safe_id(project))
|
Project.safe_id(project))
|
||||||
|
|
||||||
if not network_ref['vpn_public_port']:
|
if not network_ref['vpn_public_port']:
|
||||||
raise exception.NotFound('project network data has not been set')
|
raise exception.NotFound(_('project network data has not '
|
||||||
|
'been set'))
|
||||||
return (network_ref['vpn_public_address'],
|
return (network_ref['vpn_public_address'],
|
||||||
network_ref['vpn_public_port'])
|
network_ref['vpn_public_port'])
|
||||||
|
|
||||||
@ -659,8 +660,7 @@ class AuthManager(object):
|
|||||||
port=vpn_port)
|
port=vpn_port)
|
||||||
zippy.writestr(FLAGS.credential_vpn_file, config)
|
zippy.writestr(FLAGS.credential_vpn_file, config)
|
||||||
else:
|
else:
|
||||||
logging.warn("No vpn data for project %s" %
|
logging.warn(_("No vpn data for project %s"), pid)
|
||||||
pid)
|
|
||||||
|
|
||||||
zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(user.id))
|
zippy.writestr(FLAGS.ca_file, crypto.fetch_ca(user.id))
|
||||||
zippy.close()
|
zippy.close()
|
||||||
|
@ -49,7 +49,7 @@ class CloudPipe(object):
|
|||||||
self.manager = manager.AuthManager()
|
self.manager = manager.AuthManager()
|
||||||
|
|
||||||
def launch_vpn_instance(self, project_id):
|
def launch_vpn_instance(self, project_id):
|
||||||
logging.debug("Launching VPN for %s" % (project_id))
|
logging.debug(_("Launching VPN for %s") % (project_id))
|
||||||
project = self.manager.get_project(project_id)
|
project = self.manager.get_project(project_id)
|
||||||
# Make a payload.zip
|
# Make a payload.zip
|
||||||
tmpfolder = tempfile.mkdtemp()
|
tmpfolder = tempfile.mkdtemp()
|
||||||
|
@ -73,13 +73,18 @@ class ComputeAPI(base.Base):
|
|||||||
is_vpn = image_id == FLAGS.vpn_image_id
|
is_vpn = image_id == FLAGS.vpn_image_id
|
||||||
if not is_vpn:
|
if not is_vpn:
|
||||||
image = self.image_service.show(context, image_id)
|
image = self.image_service.show(context, image_id)
|
||||||
|
|
||||||
|
# If kernel_id/ramdisk_id isn't explicitly set in API call
|
||||||
|
# we take the defaults from the image's metadata
|
||||||
if kernel_id is None:
|
if kernel_id is None:
|
||||||
kernel_id = image.get('kernelId', FLAGS.default_kernel)
|
kernel_id = image.get('kernelId', None)
|
||||||
if ramdisk_id is None:
|
if ramdisk_id is None:
|
||||||
ramdisk_id = image.get('ramdiskId', FLAGS.default_ramdisk)
|
ramdisk_id = image.get('ramdiskId', None)
|
||||||
|
|
||||||
# Make sure we have access to kernel and ramdisk
|
# Make sure we have access to kernel and ramdisk
|
||||||
|
if kernel_id:
|
||||||
self.image_service.show(context, kernel_id)
|
self.image_service.show(context, kernel_id)
|
||||||
|
if ramdisk_id:
|
||||||
self.image_service.show(context, ramdisk_id)
|
self.image_service.show(context, ramdisk_id)
|
||||||
|
|
||||||
if security_group is None:
|
if security_group is None:
|
||||||
@ -103,8 +108,8 @@ class ComputeAPI(base.Base):
|
|||||||
base_options = {
|
base_options = {
|
||||||
'reservation_id': utils.generate_uid('r'),
|
'reservation_id': utils.generate_uid('r'),
|
||||||
'image_id': image_id,
|
'image_id': image_id,
|
||||||
'kernel_id': kernel_id,
|
'kernel_id': kernel_id or '',
|
||||||
'ramdisk_id': ramdisk_id,
|
'ramdisk_id': ramdisk_id or '',
|
||||||
'state_description': 'scheduling',
|
'state_description': 'scheduling',
|
||||||
'user_id': context.user_id,
|
'user_id': context.user_id,
|
||||||
'project_id': context.project_id,
|
'project_id': context.project_id,
|
||||||
@ -120,7 +125,7 @@ class ComputeAPI(base.Base):
|
|||||||
|
|
||||||
elevated = context.elevated()
|
elevated = context.elevated()
|
||||||
instances = []
|
instances = []
|
||||||
logging.debug("Going to run %s instances...", num_instances)
|
logging.debug(_("Going to run %s instances..."), num_instances)
|
||||||
for num in range(num_instances):
|
for num in range(num_instances):
|
||||||
instance = dict(mac_address=utils.generate_mac(),
|
instance = dict(mac_address=utils.generate_mac(),
|
||||||
launch_index=num,
|
launch_index=num,
|
||||||
@ -157,7 +162,7 @@ class ComputeAPI(base.Base):
|
|||||||
{"method": "setup_fixed_ip",
|
{"method": "setup_fixed_ip",
|
||||||
"args": {"address": address}})
|
"args": {"address": address}})
|
||||||
|
|
||||||
logging.debug("Casting to scheduler for %s/%s's instance %s",
|
logging.debug(_("Casting to scheduler for %s/%s's instance %s"),
|
||||||
context.project_id, context.user_id, instance_id)
|
context.project_id, context.user_id, instance_id)
|
||||||
rpc.cast(context,
|
rpc.cast(context,
|
||||||
FLAGS.scheduler_topic,
|
FLAGS.scheduler_topic,
|
||||||
@ -204,12 +209,12 @@ class ComputeAPI(base.Base):
|
|||||||
instance = self.db.instance_get_by_internal_id(context,
|
instance = self.db.instance_get_by_internal_id(context,
|
||||||
instance_id)
|
instance_id)
|
||||||
except exception.NotFound as e:
|
except exception.NotFound as e:
|
||||||
logging.warning("Instance %d was not found during terminate",
|
logging.warning(_("Instance %d was not found during terminate"),
|
||||||
instance_id)
|
instance_id)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
if (instance['state_description'] == 'terminating'):
|
if (instance['state_description'] == 'terminating'):
|
||||||
logging.warning("Instance %d is already being terminated",
|
logging.warning(_("Instance %d is already being terminated"),
|
||||||
instance_id)
|
instance_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -223,7 +228,7 @@ class ComputeAPI(base.Base):
|
|||||||
address = self.db.instance_get_floating_address(context,
|
address = self.db.instance_get_floating_address(context,
|
||||||
instance['id'])
|
instance['id'])
|
||||||
if address:
|
if address:
|
||||||
logging.debug("Disassociating address %s" % address)
|
logging.debug(_("Disassociating address %s") % address)
|
||||||
# NOTE(vish): Right now we don't really care if the ip is
|
# NOTE(vish): Right now we don't really care if the ip is
|
||||||
# disassociated. We may need to worry about
|
# disassociated. We may need to worry about
|
||||||
# checking this later. Perhaps in the scheduler?
|
# checking this later. Perhaps in the scheduler?
|
||||||
@ -234,7 +239,7 @@ class ComputeAPI(base.Base):
|
|||||||
|
|
||||||
address = self.db.instance_get_fixed_address(context, instance['id'])
|
address = self.db.instance_get_fixed_address(context, instance['id'])
|
||||||
if address:
|
if address:
|
||||||
logging.debug("Deallocating address %s" % address)
|
logging.debug(_("Deallocating address %s") % address)
|
||||||
# NOTE(vish): Currently, nothing needs to be done on the
|
# NOTE(vish): Currently, nothing needs to be done on the
|
||||||
# network node until release. If this changes,
|
# network node until release. If this changes,
|
||||||
# we will need to cast here.
|
# we will need to cast here.
|
||||||
@ -275,6 +280,24 @@ class ComputeAPI(base.Base):
|
|||||||
{"method": "reboot_instance",
|
{"method": "reboot_instance",
|
||||||
"args": {"instance_id": instance['id']}})
|
"args": {"instance_id": instance['id']}})
|
||||||
|
|
||||||
|
def pause(self, context, instance_id):
|
||||||
|
"""Pause the given instance."""
|
||||||
|
instance = self.db.instance_get_by_internal_id(context, instance_id)
|
||||||
|
host = instance['host']
|
||||||
|
rpc.cast(context,
|
||||||
|
self.db.queue_get_for(context, FLAGS.compute_topic, host),
|
||||||
|
{"method": "pause_instance",
|
||||||
|
"args": {"instance_id": instance['id']}})
|
||||||
|
|
||||||
|
def unpause(self, context, instance_id):
|
||||||
|
"""Unpause the given instance."""
|
||||||
|
instance = self.db.instance_get_by_internal_id(context, instance_id)
|
||||||
|
host = instance['host']
|
||||||
|
rpc.cast(context,
|
||||||
|
self.db.queue_get_for(context, FLAGS.compute_topic, host),
|
||||||
|
{"method": "unpause_instance",
|
||||||
|
"args": {"instance_id": instance['id']}})
|
||||||
|
|
||||||
def rescue(self, context, instance_id):
|
def rescue(self, context, instance_id):
|
||||||
"""Rescue the given instance."""
|
"""Rescue the given instance."""
|
||||||
instance = self.db.instance_get_by_internal_id(context, instance_id)
|
instance = self.db.instance_get_by_internal_id(context, instance_id)
|
||||||
|
@ -67,12 +67,12 @@ def partition(infile, outfile, local_bytes=0, resize=True,
|
|||||||
execute('resize2fs %s' % infile)
|
execute('resize2fs %s' % infile)
|
||||||
file_size = FLAGS.minimum_root_size
|
file_size = FLAGS.minimum_root_size
|
||||||
elif file_size % sector_size != 0:
|
elif file_size % sector_size != 0:
|
||||||
logging.warn("Input partition size not evenly divisible by"
|
logging.warn(_("Input partition size not evenly divisible by"
|
||||||
" sector size: %d / %d", file_size, sector_size)
|
" sector size: %d / %d"), file_size, sector_size)
|
||||||
primary_sectors = file_size / sector_size
|
primary_sectors = file_size / sector_size
|
||||||
if local_bytes % sector_size != 0:
|
if local_bytes % sector_size != 0:
|
||||||
logging.warn("Bytes for local storage not evenly divisible"
|
logging.warn(_("Bytes for local storage not evenly divisible"
|
||||||
" by sector size: %d / %d", local_bytes, sector_size)
|
" by sector size: %d / %d"), local_bytes, sector_size)
|
||||||
local_sectors = local_bytes / sector_size
|
local_sectors = local_bytes / sector_size
|
||||||
|
|
||||||
mbr_last = 62 # a
|
mbr_last = 62 # a
|
||||||
@ -106,6 +106,13 @@ def partition(infile, outfile, local_bytes=0, resize=True,
|
|||||||
% (outfile, local_type, local_first, local_last))
|
% (outfile, local_type, local_first, local_last))
|
||||||
|
|
||||||
|
|
||||||
|
def extend(image, size, execute):
|
||||||
|
file_size = os.path.getsize(image)
|
||||||
|
if file_size >= size:
|
||||||
|
return
|
||||||
|
return execute('truncate -s size %s' % (image,))
|
||||||
|
|
||||||
|
|
||||||
def inject_data(image, key=None, net=None, partition=None, execute=None):
|
def inject_data(image, key=None, net=None, partition=None, execute=None):
|
||||||
"""Injects a ssh key and optionally net data into a disk image.
|
"""Injects a ssh key and optionally net data into a disk image.
|
||||||
|
|
||||||
@ -115,20 +122,30 @@ def inject_data(image, key=None, net=None, partition=None, execute=None):
|
|||||||
If partition is not specified it mounts the image as a single partition.
|
If partition is not specified it mounts the image as a single partition.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
out, err = execute('sudo losetup -f --show %s' % image)
|
out, err = execute('sudo losetup --find --show %s' % image)
|
||||||
if err:
|
if err:
|
||||||
raise exception.Error('Could not attach image to loopback: %s' % err)
|
raise exception.Error(_('Could not attach image to loopback: %s')
|
||||||
|
% err)
|
||||||
device = out.strip()
|
device = out.strip()
|
||||||
try:
|
try:
|
||||||
if not partition is None:
|
if not partition is None:
|
||||||
# create partition
|
# create partition
|
||||||
out, err = execute('sudo kpartx -a %s' % device)
|
out, err = execute('sudo kpartx -a %s' % device)
|
||||||
if err:
|
if err:
|
||||||
raise exception.Error('Failed to load partition: %s' % err)
|
raise exception.Error(_('Failed to load partition: %s') % err)
|
||||||
mapped_device = '/dev/mapper/%sp%s' % (device.split('/')[-1],
|
mapped_device = '/dev/mapper/%sp%s' % (device.split('/')[-1],
|
||||||
partition)
|
partition)
|
||||||
else:
|
else:
|
||||||
mapped_device = device
|
mapped_device = device
|
||||||
|
|
||||||
|
# We can only loopback mount raw images. If the device isn't there,
|
||||||
|
# it's normally because it's a .vmdk or a .vdi etc
|
||||||
|
if not os.path.exists(mapped_device):
|
||||||
|
raise exception.Error('Mapped device was not found (we can'
|
||||||
|
' only inject raw disk images): %s' %
|
||||||
|
mapped_device)
|
||||||
|
|
||||||
|
# Configure ext2fs so that it doesn't auto-check every N boots
|
||||||
out, err = execute('sudo tune2fs -c 0 -i 0 %s' % mapped_device)
|
out, err = execute('sudo tune2fs -c 0 -i 0 %s' % mapped_device)
|
||||||
|
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp()
|
||||||
@ -137,7 +154,8 @@ def inject_data(image, key=None, net=None, partition=None, execute=None):
|
|||||||
out, err = execute(
|
out, err = execute(
|
||||||
'sudo mount %s %s' % (mapped_device, tmpdir))
|
'sudo mount %s %s' % (mapped_device, tmpdir))
|
||||||
if err:
|
if err:
|
||||||
raise exception.Error('Failed to mount filesystem: %s' % err)
|
raise exception.Error(_('Failed to mount filesystem: %s')
|
||||||
|
% err)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if key:
|
if key:
|
||||||
@ -156,7 +174,7 @@ def inject_data(image, key=None, net=None, partition=None, execute=None):
|
|||||||
execute('sudo kpartx -d %s' % device)
|
execute('sudo kpartx -d %s' % device)
|
||||||
finally:
|
finally:
|
||||||
# remove loopback
|
# remove loopback
|
||||||
execute('sudo losetup -d %s' % device)
|
execute('sudo losetup --detach %s' % device)
|
||||||
|
|
||||||
|
|
||||||
def _inject_key_into_fs(key, fs, execute=None):
|
def _inject_key_into_fs(key, fs, execute=None):
|
||||||
@ -165,7 +183,7 @@ def _inject_key_into_fs(key, fs, execute=None):
|
|||||||
key is an ssh key string.
|
key is an ssh key string.
|
||||||
fs is the path to the base of the filesystem into which to inject the key.
|
fs is the path to the base of the filesystem into which to inject the key.
|
||||||
"""
|
"""
|
||||||
sshdir = os.path.join(os.path.join(fs, 'root'), '.ssh')
|
sshdir = os.path.join(fs, 'root', '.ssh')
|
||||||
execute('sudo mkdir -p %s' % sshdir) # existing dir doesn't matter
|
execute('sudo mkdir -p %s' % sshdir) # existing dir doesn't matter
|
||||||
execute('sudo chown root %s' % sshdir)
|
execute('sudo chown root %s' % sshdir)
|
||||||
execute('sudo chmod 700 %s' % sshdir)
|
execute('sudo chmod 700 %s' % sshdir)
|
||||||
|
@ -38,7 +38,8 @@ def get_by_type(instance_type):
|
|||||||
if instance_type is None:
|
if instance_type is None:
|
||||||
return FLAGS.default_instance_type
|
return FLAGS.default_instance_type
|
||||||
if instance_type not in INSTANCE_TYPES:
|
if instance_type not in INSTANCE_TYPES:
|
||||||
raise exception.ApiError("Unknown instance type: %s" % instance_type)
|
raise exception.ApiError(_("Unknown instance type: %s"),
|
||||||
|
instance_type)
|
||||||
return instance_type
|
return instance_type
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,8 +93,8 @@ class ComputeManager(manager.Manager):
|
|||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
if instance_ref['name'] in self.driver.list_instances():
|
if instance_ref['name'] in self.driver.list_instances():
|
||||||
raise exception.Error("Instance has already been created")
|
raise exception.Error(_("Instance has already been created"))
|
||||||
logging.debug("instance %s: starting...", instance_id)
|
logging.debug(_("instance %s: starting..."), instance_id)
|
||||||
self.network_manager.setup_compute_network(context, instance_id)
|
self.network_manager.setup_compute_network(context, instance_id)
|
||||||
self.db.instance_update(context,
|
self.db.instance_update(context,
|
||||||
instance_id,
|
instance_id,
|
||||||
@ -113,7 +113,7 @@ class ComputeManager(manager.Manager):
|
|||||||
instance_id,
|
instance_id,
|
||||||
{'launched_at': now})
|
{'launched_at': now})
|
||||||
except Exception: # pylint: disable-msg=W0702
|
except Exception: # pylint: disable-msg=W0702
|
||||||
logging.exception("instance %s: Failed to spawn",
|
logging.exception(_("instance %s: Failed to spawn"),
|
||||||
instance_ref['name'])
|
instance_ref['name'])
|
||||||
self.db.instance_set_state(context,
|
self.db.instance_set_state(context,
|
||||||
instance_id,
|
instance_id,
|
||||||
@ -125,7 +125,7 @@ class ComputeManager(manager.Manager):
|
|||||||
def terminate_instance(self, context, instance_id):
|
def terminate_instance(self, context, instance_id):
|
||||||
"""Terminate an instance on this machine."""
|
"""Terminate an instance on this machine."""
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
logging.debug("instance %s: terminating", instance_id)
|
logging.debug(_("instance %s: terminating"), instance_id)
|
||||||
|
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
volumes = instance_ref.get('volumes', []) or []
|
volumes = instance_ref.get('volumes', []) or []
|
||||||
@ -133,8 +133,8 @@ class ComputeManager(manager.Manager):
|
|||||||
self.detach_volume(context, instance_id, volume['id'])
|
self.detach_volume(context, instance_id, volume['id'])
|
||||||
if instance_ref['state'] == power_state.SHUTOFF:
|
if instance_ref['state'] == power_state.SHUTOFF:
|
||||||
self.db.instance_destroy(context, instance_id)
|
self.db.instance_destroy(context, instance_id)
|
||||||
raise exception.Error('trying to destroy already destroyed'
|
raise exception.Error(_('trying to destroy already destroyed'
|
||||||
' instance: %s' % instance_id)
|
' instance: %s') % instance_id)
|
||||||
self.driver.destroy(instance_ref)
|
self.driver.destroy(instance_ref)
|
||||||
|
|
||||||
# TODO(ja): should we keep it in a terminated state for a bit?
|
# TODO(ja): should we keep it in a terminated state for a bit?
|
||||||
@ -148,13 +148,13 @@ class ComputeManager(manager.Manager):
|
|||||||
self._update_state(context, instance_id)
|
self._update_state(context, instance_id)
|
||||||
|
|
||||||
if instance_ref['state'] != power_state.RUNNING:
|
if instance_ref['state'] != power_state.RUNNING:
|
||||||
logging.warn('trying to reboot a non-running '
|
logging.warn(_('trying to reboot a non-running '
|
||||||
'instance: %s (state: %s excepted: %s)',
|
'instance: %s (state: %s excepted: %s)'),
|
||||||
instance_ref['internal_id'],
|
instance_ref['internal_id'],
|
||||||
instance_ref['state'],
|
instance_ref['state'],
|
||||||
power_state.RUNNING)
|
power_state.RUNNING)
|
||||||
|
|
||||||
logging.debug('instance %s: rebooting', instance_ref['name'])
|
logging.debug(_('instance %s: rebooting'), instance_ref['name'])
|
||||||
self.db.instance_set_state(context,
|
self.db.instance_set_state(context,
|
||||||
instance_id,
|
instance_id,
|
||||||
power_state.NOSTATE,
|
power_state.NOSTATE,
|
||||||
@ -168,7 +168,7 @@ class ComputeManager(manager.Manager):
|
|||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
|
|
||||||
logging.debug('instance %s: rescuing',
|
logging.debug(_('instance %s: rescuing'),
|
||||||
instance_ref['internal_id'])
|
instance_ref['internal_id'])
|
||||||
self.db.instance_set_state(context,
|
self.db.instance_set_state(context,
|
||||||
instance_id,
|
instance_id,
|
||||||
@ -183,7 +183,7 @@ class ComputeManager(manager.Manager):
|
|||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
|
|
||||||
logging.debug('instance %s: unrescuing',
|
logging.debug(_('instance %s: unrescuing'),
|
||||||
instance_ref['internal_id'])
|
instance_ref['internal_id'])
|
||||||
self.db.instance_set_state(context,
|
self.db.instance_set_state(context,
|
||||||
instance_id,
|
instance_id,
|
||||||
@ -192,11 +192,52 @@ class ComputeManager(manager.Manager):
|
|||||||
self.driver.unrescue(instance_ref)
|
self.driver.unrescue(instance_ref)
|
||||||
self._update_state(context, instance_id)
|
self._update_state(context, instance_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _update_state_callback(self, context, instance_id, result):
|
||||||
|
"""Update instance state when async task completes."""
|
||||||
|
self._update_state(context, instance_id)
|
||||||
|
|
||||||
|
@exception.wrap_exception
|
||||||
|
def pause_instance(self, context, instance_id):
|
||||||
|
"""Pause an instance on this server."""
|
||||||
|
context = context.elevated()
|
||||||
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
|
|
||||||
|
logging.debug('instance %s: pausing',
|
||||||
|
instance_ref['internal_id'])
|
||||||
|
self.db.instance_set_state(context,
|
||||||
|
instance_id,
|
||||||
|
power_state.NOSTATE,
|
||||||
|
'pausing')
|
||||||
|
self.driver.pause(instance_ref,
|
||||||
|
lambda result: self._update_state_callback(self,
|
||||||
|
context,
|
||||||
|
instance_id,
|
||||||
|
result))
|
||||||
|
|
||||||
|
@exception.wrap_exception
|
||||||
|
def unpause_instance(self, context, instance_id):
|
||||||
|
"""Unpause a paused instance on this server."""
|
||||||
|
context = context.elevated()
|
||||||
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
|
|
||||||
|
logging.debug('instance %s: unpausing',
|
||||||
|
instance_ref['internal_id'])
|
||||||
|
self.db.instance_set_state(context,
|
||||||
|
instance_id,
|
||||||
|
power_state.NOSTATE,
|
||||||
|
'unpausing')
|
||||||
|
self.driver.unpause(instance_ref,
|
||||||
|
lambda result: self._update_state_callback(self,
|
||||||
|
context,
|
||||||
|
instance_id,
|
||||||
|
result))
|
||||||
|
|
||||||
@exception.wrap_exception
|
@exception.wrap_exception
|
||||||
def get_console_output(self, context, instance_id):
|
def get_console_output(self, context, instance_id):
|
||||||
"""Send the console output for an instance."""
|
"""Send the console output for an instance."""
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
logging.debug("instance %s: getting console output", instance_id)
|
logging.debug(_("instance %s: getting console output"), instance_id)
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
|
|
||||||
return self.driver.get_console_output(instance_ref)
|
return self.driver.get_console_output(instance_ref)
|
||||||
@ -205,7 +246,7 @@ class ComputeManager(manager.Manager):
|
|||||||
def attach_volume(self, context, instance_id, volume_id, mountpoint):
|
def attach_volume(self, context, instance_id, volume_id, mountpoint):
|
||||||
"""Attach a volume to an instance."""
|
"""Attach a volume to an instance."""
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
logging.debug("instance %s: attaching volume %s to %s", instance_id,
|
logging.debug(_("instance %s: attaching volume %s to %s"), instance_id,
|
||||||
volume_id, mountpoint)
|
volume_id, mountpoint)
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
dev_path = self.volume_manager.setup_compute_volume(context,
|
dev_path = self.volume_manager.setup_compute_volume(context,
|
||||||
@ -222,7 +263,7 @@ class ComputeManager(manager.Manager):
|
|||||||
# NOTE(vish): The inline callback eats the exception info so we
|
# NOTE(vish): The inline callback eats the exception info so we
|
||||||
# log the traceback here and reraise the same
|
# log the traceback here and reraise the same
|
||||||
# ecxception below.
|
# ecxception below.
|
||||||
logging.exception("instance %s: attach failed %s, removing",
|
logging.exception(_("instance %s: attach failed %s, removing"),
|
||||||
instance_id, mountpoint)
|
instance_id, mountpoint)
|
||||||
self.volume_manager.remove_compute_volume(context,
|
self.volume_manager.remove_compute_volume(context,
|
||||||
volume_id)
|
volume_id)
|
||||||
@ -234,13 +275,13 @@ class ComputeManager(manager.Manager):
|
|||||||
def detach_volume(self, context, instance_id, volume_id):
|
def detach_volume(self, context, instance_id, volume_id):
|
||||||
"""Detach a volume from an instance."""
|
"""Detach a volume from an instance."""
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
logging.debug("instance %s: detaching volume %s",
|
logging.debug(_("instance %s: detaching volume %s"),
|
||||||
instance_id,
|
instance_id,
|
||||||
volume_id)
|
volume_id)
|
||||||
instance_ref = self.db.instance_get(context, instance_id)
|
instance_ref = self.db.instance_get(context, instance_id)
|
||||||
volume_ref = self.db.volume_get(context, volume_id)
|
volume_ref = self.db.volume_get(context, volume_id)
|
||||||
if instance_ref['name'] not in self.driver.list_instances():
|
if instance_ref['name'] not in self.driver.list_instances():
|
||||||
logging.warn("Detaching volume from unknown instance %s",
|
logging.warn(_("Detaching volume from unknown instance %s"),
|
||||||
instance_ref['name'])
|
instance_ref['name'])
|
||||||
else:
|
else:
|
||||||
self.driver.detach_volume(instance_ref['name'],
|
self.driver.detach_volume(instance_ref['name'],
|
||||||
|
@ -255,7 +255,7 @@ class Instance(object):
|
|||||||
Updates the instances statistics and stores the resulting graphs
|
Updates the instances statistics and stores the resulting graphs
|
||||||
in the internal object store on the cloud controller.
|
in the internal object store on the cloud controller.
|
||||||
"""
|
"""
|
||||||
logging.debug('updating %s...', self.instance_id)
|
logging.debug(_('updating %s...'), self.instance_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = self.fetch_cpu_stats()
|
data = self.fetch_cpu_stats()
|
||||||
@ -285,7 +285,7 @@ class Instance(object):
|
|||||||
graph_disk(self, '1w')
|
graph_disk(self, '1w')
|
||||||
graph_disk(self, '1m')
|
graph_disk(self, '1m')
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception('unexpected error during update')
|
logging.exception(_('unexpected error during update'))
|
||||||
|
|
||||||
self.last_updated = utcnow()
|
self.last_updated = utcnow()
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ class Instance(object):
|
|||||||
rd += rd_bytes
|
rd += rd_bytes
|
||||||
wr += wr_bytes
|
wr += wr_bytes
|
||||||
except TypeError:
|
except TypeError:
|
||||||
logging.error('Cannot get blockstats for "%s" on "%s"',
|
logging.error(_('Cannot get blockstats for "%s" on "%s"'),
|
||||||
disk, self.instance_id)
|
disk, self.instance_id)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ class Instance(object):
|
|||||||
rx += stats[0]
|
rx += stats[0]
|
||||||
tx += stats[4]
|
tx += stats[4]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
logging.error('Cannot get ifstats for "%s" on "%s"',
|
logging.error(_('Cannot get ifstats for "%s" on "%s"'),
|
||||||
interface, self.instance_id)
|
interface, self.instance_id)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ class InstanceMonitor(object, service.Service):
|
|||||||
try:
|
try:
|
||||||
conn = virt_connection.get_connection(read_only=True)
|
conn = virt_connection.get_connection(read_only=True)
|
||||||
except Exception, exn:
|
except Exception, exn:
|
||||||
logging.exception('unexpected exception getting connection')
|
logging.exception(_('unexpected exception getting connection'))
|
||||||
time.sleep(FLAGS.monitoring_instances_delay)
|
time.sleep(FLAGS.monitoring_instances_delay)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ class InstanceMonitor(object, service.Service):
|
|||||||
if not domain_id in self._instances:
|
if not domain_id in self._instances:
|
||||||
instance = Instance(conn, domain_id)
|
instance = Instance(conn, domain_id)
|
||||||
self._instances[domain_id] = instance
|
self._instances[domain_id] = instance
|
||||||
logging.debug('Found instance: %s', domain_id)
|
logging.debug(_('Found instance: %s'), domain_id)
|
||||||
|
|
||||||
for key in self._instances.keys():
|
for key in self._instances.keys():
|
||||||
instance = self._instances[key]
|
instance = self._instances[key]
|
||||||
|
@ -39,13 +39,13 @@ from nova import flags
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
flags.DEFINE_string('ca_file', 'cacert.pem', 'Filename of root CA')
|
flags.DEFINE_string('ca_file', 'cacert.pem', _('Filename of root CA'))
|
||||||
flags.DEFINE_string('keys_path', '$state_path/keys',
|
flags.DEFINE_string('keys_path', '$state_path/keys',
|
||||||
'Where we keep our keys')
|
_('Where we keep our keys'))
|
||||||
flags.DEFINE_string('ca_path', '$state_path/CA',
|
flags.DEFINE_string('ca_path', '$state_path/CA',
|
||||||
'Where we keep our root CA')
|
_('Where we keep our root CA'))
|
||||||
flags.DEFINE_boolean('use_intermediate_ca', False,
|
flags.DEFINE_boolean('use_intermediate_ca', False,
|
||||||
'Should we use intermediate CAs for each project?')
|
_('Should we use intermediate CAs for each project?'))
|
||||||
|
|
||||||
|
|
||||||
def ca_path(project_id):
|
def ca_path(project_id):
|
||||||
@ -111,9 +111,9 @@ def generate_x509_cert(subject, bits=1024):
|
|||||||
keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))
|
keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))
|
||||||
csrfile = os.path.join(tmpdir, 'temp.csr')
|
csrfile = os.path.join(tmpdir, 'temp.csr')
|
||||||
logging.debug("openssl genrsa -out %s %s" % (keyfile, bits))
|
logging.debug("openssl genrsa -out %s %s" % (keyfile, bits))
|
||||||
utils.runthis("Generating private key: %s",
|
utils.runthis(_("Generating private key: %s"),
|
||||||
"openssl genrsa -out %s %s" % (keyfile, bits))
|
"openssl genrsa -out %s %s" % (keyfile, bits))
|
||||||
utils.runthis("Generating CSR: %s",
|
utils.runthis(_("Generating CSR: %s"),
|
||||||
"openssl req -new -key %s -out %s -batch -subj %s" %
|
"openssl req -new -key %s -out %s -batch -subj %s" %
|
||||||
(keyfile, csrfile, subject))
|
(keyfile, csrfile, subject))
|
||||||
private_key = open(keyfile).read()
|
private_key = open(keyfile).read()
|
||||||
@ -131,7 +131,7 @@ def sign_csr(csr_text, intermediate=None):
|
|||||||
if not os.path.exists(user_ca):
|
if not os.path.exists(user_ca):
|
||||||
start = os.getcwd()
|
start = os.getcwd()
|
||||||
os.chdir(FLAGS.ca_path)
|
os.chdir(FLAGS.ca_path)
|
||||||
utils.runthis("Generating intermediate CA: %s",
|
utils.runthis(_("Generating intermediate CA: %s"),
|
||||||
"sh geninter.sh %s" % (intermediate))
|
"sh geninter.sh %s" % (intermediate))
|
||||||
os.chdir(start)
|
os.chdir(start)
|
||||||
return _sign_csr(csr_text, user_ca)
|
return _sign_csr(csr_text, user_ca)
|
||||||
@ -142,11 +142,11 @@ def _sign_csr(csr_text, ca_folder):
|
|||||||
csrfile = open("%s/inbound.csr" % (tmpfolder), "w")
|
csrfile = open("%s/inbound.csr" % (tmpfolder), "w")
|
||||||
csrfile.write(csr_text)
|
csrfile.write(csr_text)
|
||||||
csrfile.close()
|
csrfile.close()
|
||||||
logging.debug("Flags path: %s" % ca_folder)
|
logging.debug(_("Flags path: %s") % ca_folder)
|
||||||
start = os.getcwd()
|
start = os.getcwd()
|
||||||
# Change working dir to CA
|
# Change working dir to CA
|
||||||
os.chdir(ca_folder)
|
os.chdir(ca_folder)
|
||||||
utils.runthis("Signing cert: %s",
|
utils.runthis(_("Signing cert: %s"),
|
||||||
"openssl ca -batch -out %s/outbound.crt "
|
"openssl ca -batch -out %s/outbound.crt "
|
||||||
"-config ./openssl.cnf -infiles %s/inbound.csr" %
|
"-config ./openssl.cnf -infiles %s/inbound.csr" %
|
||||||
(tmpfolder, tmpfolder))
|
(tmpfolder, tmpfolder))
|
||||||
|
@ -334,6 +334,11 @@ def instance_add_security_group(context, instance_id, security_group_id):
|
|||||||
security_group_id)
|
security_group_id)
|
||||||
|
|
||||||
|
|
||||||
|
def instance_action_create(context, values):
|
||||||
|
"""Create an instance action from the values dictionary."""
|
||||||
|
return IMPL.instance_action_create(context, values)
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ FLAGS = flags.FLAGS
|
|||||||
def is_admin_context(context):
|
def is_admin_context(context):
|
||||||
"""Indicates if the request context is an administrator."""
|
"""Indicates if the request context is an administrator."""
|
||||||
if not context:
|
if not context:
|
||||||
warnings.warn('Use of empty request context is deprecated',
|
warnings.warn(_('Use of empty request context is deprecated'),
|
||||||
DeprecationWarning)
|
DeprecationWarning)
|
||||||
raise Exception('die')
|
raise Exception('die')
|
||||||
return context.is_admin
|
return context.is_admin
|
||||||
@ -130,7 +130,7 @@ def service_get(context, service_id, session=None):
|
|||||||
first()
|
first()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No service for id %s' % service_id)
|
raise exception.NotFound(_('No service for id %s') % service_id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ def service_get_by_args(context, host, binary):
|
|||||||
filter_by(deleted=can_read_deleted(context)).\
|
filter_by(deleted=can_read_deleted(context)).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No service for %s, %s' % (host, binary))
|
raise exception.NotFound(_('No service for %s, %s') % (host, binary))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -491,7 +491,7 @@ def fixed_ip_get_by_address(context, address, session=None):
|
|||||||
options(joinedload('instance')).\
|
options(joinedload('instance')).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No floating ip for address %s' % address)
|
raise exception.NotFound(_('No floating ip for address %s') % address)
|
||||||
|
|
||||||
if is_user_context(context):
|
if is_user_context(context):
|
||||||
authorize_project_context(context, result.instance.project_id)
|
authorize_project_context(context, result.instance.project_id)
|
||||||
@ -528,6 +528,8 @@ def fixed_ip_update(context, address, values):
|
|||||||
#TODO(gundlach): instance_create and volume_create are nearly identical
|
#TODO(gundlach): instance_create and volume_create are nearly identical
|
||||||
#and should be refactored. I expect there are other copy-and-paste
|
#and should be refactored. I expect there are other copy-and-paste
|
||||||
#functions between the two of them as well.
|
#functions between the two of them as well.
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def instance_create(context, values):
|
def instance_create(context, values):
|
||||||
"""Create a new Instance record in the database.
|
"""Create a new Instance record in the database.
|
||||||
@ -591,7 +593,7 @@ def instance_get(context, instance_id, session=None):
|
|||||||
filter_by(deleted=False).\
|
filter_by(deleted=False).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No instance for id %s' % instance_id)
|
raise exception.NotFound(_('No instance for id %s') % instance_id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -669,7 +671,7 @@ def instance_get_by_internal_id(context, internal_id):
|
|||||||
filter_by(deleted=False).\
|
filter_by(deleted=False).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('Instance %s not found' % (internal_id))
|
raise exception.NotFound(_('Instance %s not found') % (internal_id))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -747,6 +749,18 @@ def instance_add_security_group(context, instance_id, security_group_id):
|
|||||||
instance_ref.save(session=session)
|
instance_ref.save(session=session)
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def instance_action_create(context, values):
|
||||||
|
"""Create an instance action from the values dictionary."""
|
||||||
|
action_ref = models.InstanceActions()
|
||||||
|
action_ref.update(values)
|
||||||
|
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
action_ref.save(session=session)
|
||||||
|
return action_ref
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
@ -790,7 +804,7 @@ def key_pair_get(context, user_id, name, session=None):
|
|||||||
filter_by(deleted=can_read_deleted(context)).\
|
filter_by(deleted=can_read_deleted(context)).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('no keypair for user %s, name %s' %
|
raise exception.NotFound(_('no keypair for user %s, name %s') %
|
||||||
(user_id, name))
|
(user_id, name))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -905,7 +919,7 @@ def network_get(context, network_id, session=None):
|
|||||||
filter_by(deleted=False).\
|
filter_by(deleted=False).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No network for id %s' % network_id)
|
raise exception.NotFound(_('No network for id %s') % network_id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -913,6 +927,8 @@ def network_get(context, network_id, session=None):
|
|||||||
# NOTE(vish): pylint complains because of the long method name, but
|
# NOTE(vish): pylint complains because of the long method name, but
|
||||||
# it fits with the names of the rest of the methods
|
# it fits with the names of the rest of the methods
|
||||||
# pylint: disable-msg=C0103
|
# pylint: disable-msg=C0103
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def network_get_associated_fixed_ips(context, network_id):
|
def network_get_associated_fixed_ips(context, network_id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
@ -933,7 +949,7 @@ def network_get_by_bridge(context, bridge):
|
|||||||
first()
|
first()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No network for bridge %s' % bridge)
|
raise exception.NotFound(_('No network for bridge %s') % bridge)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -947,7 +963,7 @@ def network_get_by_instance(_context, instance_id):
|
|||||||
filter_by(deleted=False).\
|
filter_by(deleted=False).\
|
||||||
first()
|
first()
|
||||||
if not rv:
|
if not rv:
|
||||||
raise exception.NotFound('No network for instance %s' % instance_id)
|
raise exception.NotFound(_('No network for instance %s') % instance_id)
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
@ -961,7 +977,7 @@ def network_set_host(context, network_id, host_id):
|
|||||||
with_lockmode('update').\
|
with_lockmode('update').\
|
||||||
first()
|
first()
|
||||||
if not network_ref:
|
if not network_ref:
|
||||||
raise exception.NotFound('No network for id %s' % network_id)
|
raise exception.NotFound(_('No network for id %s') % network_id)
|
||||||
|
|
||||||
# NOTE(vish): if with_lockmode isn't supported, as in sqlite,
|
# NOTE(vish): if with_lockmode isn't supported, as in sqlite,
|
||||||
# then this has concurrency issues
|
# then this has concurrency issues
|
||||||
@ -1073,7 +1089,7 @@ def auth_get_token(_context, token_hash):
|
|||||||
filter_by(token_hash=token_hash).\
|
filter_by(token_hash=token_hash).\
|
||||||
first()
|
first()
|
||||||
if not tk:
|
if not tk:
|
||||||
raise exception.NotFound('Token %s does not exist' % token_hash)
|
raise exception.NotFound(_('Token %s does not exist') % token_hash)
|
||||||
return tk
|
return tk
|
||||||
|
|
||||||
|
|
||||||
@ -1097,7 +1113,7 @@ def quota_get(context, project_id, session=None):
|
|||||||
filter_by(deleted=can_read_deleted(context)).\
|
filter_by(deleted=can_read_deleted(context)).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No quota for project_id %s' % project_id)
|
raise exception.NotFound(_('No quota for project_id %s') % project_id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1252,7 +1268,7 @@ def volume_get(context, volume_id, session=None):
|
|||||||
filter_by(deleted=False).\
|
filter_by(deleted=False).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No volume for id %s' % volume_id)
|
raise exception.NotFound(_('No volume for id %s') % volume_id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1308,7 +1324,7 @@ def volume_get_by_ec2_id(context, ec2_id):
|
|||||||
raise exception.NotAuthorized()
|
raise exception.NotAuthorized()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('Volume %s not found' % ec2_id)
|
raise exception.NotFound(_('Volume %s not found') % ec2_id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1332,7 +1348,7 @@ def volume_get_instance(context, volume_id):
|
|||||||
options(joinedload('instance')).\
|
options(joinedload('instance')).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('Volume %s not found' % ec2_id)
|
raise exception.NotFound(_('Volume %s not found') % ec2_id)
|
||||||
|
|
||||||
return result.instance
|
return result.instance
|
||||||
|
|
||||||
@ -1344,7 +1360,7 @@ def volume_get_shelf_and_blade(context, volume_id):
|
|||||||
filter_by(volume_id=volume_id).\
|
filter_by(volume_id=volume_id).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No export device found for volume %s' %
|
raise exception.NotFound(_('No export device found for volume %s') %
|
||||||
volume_id)
|
volume_id)
|
||||||
|
|
||||||
return (result.shelf_id, result.blade_id)
|
return (result.shelf_id, result.blade_id)
|
||||||
@ -1357,7 +1373,7 @@ def volume_get_iscsi_target_num(context, volume_id):
|
|||||||
filter_by(volume_id=volume_id).\
|
filter_by(volume_id=volume_id).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No target id found for volume %s' %
|
raise exception.NotFound(_('No target id found for volume %s') %
|
||||||
volume_id)
|
volume_id)
|
||||||
|
|
||||||
return result.target_num
|
return result.target_num
|
||||||
@ -1402,7 +1418,7 @@ def security_group_get(context, security_group_id, session=None):
|
|||||||
options(joinedload_all('rules')).\
|
options(joinedload_all('rules')).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound("No secuity group with id %s" %
|
raise exception.NotFound(_("No security group with id %s") %
|
||||||
security_group_id)
|
security_group_id)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1419,7 +1435,7 @@ def security_group_get_by_name(context, project_id, group_name):
|
|||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound(
|
raise exception.NotFound(
|
||||||
'No security group named %s for project: %s' \
|
_('No security group named %s for project: %s')
|
||||||
% (group_name, project_id))
|
% (group_name, project_id))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1507,7 +1523,7 @@ def security_group_rule_get(context, security_group_rule_id, session=None):
|
|||||||
filter_by(id=security_group_rule_id).\
|
filter_by(id=security_group_rule_id).\
|
||||||
first()
|
first()
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound("No secuity group rule with id %s" %
|
raise exception.NotFound(_("No secuity group rule with id %s") %
|
||||||
security_group_rule_id)
|
security_group_rule_id)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1543,7 +1559,7 @@ def user_get(context, id, session=None):
|
|||||||
first()
|
first()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No user for id %s' % id)
|
raise exception.NotFound(_('No user for id %s') % id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1559,7 +1575,7 @@ def user_get_by_access_key(context, access_key, session=None):
|
|||||||
first()
|
first()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('No user for access key %s' % access_key)
|
raise exception.NotFound(_('No user for access key %s') % access_key)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1621,7 +1637,7 @@ def project_get(context, id, session=None):
|
|||||||
first()
|
first()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound("No project with id %s" % id)
|
raise exception.NotFound(_("No project with id %s") % id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ SQLAlchemy models for nova data.
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from sqlalchemy.orm import relationship, backref, object_mapper
|
from sqlalchemy.orm import relationship, backref, object_mapper
|
||||||
from sqlalchemy import Column, Integer, String, schema
|
from sqlalchemy import Column, Integer, Float, String, schema
|
||||||
from sqlalchemy import ForeignKey, DateTime, Boolean, Text
|
from sqlalchemy import ForeignKey, DateTime, Boolean, Text
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
@ -226,6 +226,31 @@ class Instance(BASE, NovaBase):
|
|||||||
# 'shutdown', 'shutoff', 'crashed'])
|
# 'shutdown', 'shutoff', 'crashed'])
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceDiagnostics(BASE, NovaBase):
|
||||||
|
"""Represents a guest VM's diagnostics"""
|
||||||
|
__tablename__ = "instance_diagnostics"
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
instance_id = Column(Integer, ForeignKey('instances.id'))
|
||||||
|
|
||||||
|
memory_available = Column(Float)
|
||||||
|
memory_free = Column(Float)
|
||||||
|
cpu_load = Column(Float)
|
||||||
|
disk_read = Column(Float)
|
||||||
|
disk_write = Column(Float)
|
||||||
|
net_tx = Column(Float)
|
||||||
|
net_rx = Column(Float)
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceActions(BASE, NovaBase):
|
||||||
|
"""Represents a guest VM's actions and results"""
|
||||||
|
__tablename__ = "instance_actions"
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
instance_id = Column(Integer, ForeignKey('instances.id'))
|
||||||
|
|
||||||
|
action = Column(String(255))
|
||||||
|
error = Column(Text)
|
||||||
|
|
||||||
|
|
||||||
class Volume(BASE, NovaBase):
|
class Volume(BASE, NovaBase):
|
||||||
"""Represents a block storage device that can be attached to a vm."""
|
"""Represents a block storage device that can be attached to a vm."""
|
||||||
__tablename__ = 'volumes'
|
__tablename__ = 'volumes'
|
||||||
@ -526,10 +551,11 @@ def register_models():
|
|||||||
it will never need to be called explicitly elsewhere.
|
it will never need to be called explicitly elsewhere.
|
||||||
"""
|
"""
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
models = (Service, Instance, Volume, ExportDevice, IscsiTarget, FixedIp,
|
models = (Service, Instance, InstanceDiagnostics, InstanceActions,
|
||||||
FloatingIp, Network, SecurityGroup,
|
Volume, ExportDevice, IscsiTarget, FixedIp, FloatingIp,
|
||||||
SecurityGroupIngressRule, SecurityGroupInstanceAssociation,
|
Network, SecurityGroup, SecurityGroupIngressRule,
|
||||||
AuthToken, User, Project) # , Image, Host
|
SecurityGroupInstanceAssociation, AuthToken, User,
|
||||||
|
Project) # , Image, Host
|
||||||
engine = create_engine(FLAGS.sql_connection, echo=False)
|
engine = create_engine(FLAGS.sql_connection, echo=False)
|
||||||
for model in models:
|
for model in models:
|
||||||
model.metadata.create_all(engine)
|
model.metadata.create_all(engine)
|
||||||
|
@ -27,23 +27,26 @@ import traceback
|
|||||||
|
|
||||||
|
|
||||||
class ProcessExecutionError(IOError):
|
class ProcessExecutionError(IOError):
|
||||||
|
|
||||||
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
|
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
|
||||||
description=None):
|
description=None):
|
||||||
if description is None:
|
if description is None:
|
||||||
description = "Unexpected error while running command."
|
description = _("Unexpected error while running command.")
|
||||||
if exit_code is None:
|
if exit_code is None:
|
||||||
exit_code = '-'
|
exit_code = '-'
|
||||||
message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % (
|
message = _("%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r")\
|
||||||
description, cmd, exit_code, stdout, stderr)
|
% (description, cmd, exit_code, stdout, stderr)
|
||||||
IOError.__init__(self, message)
|
IOError.__init__(self, message)
|
||||||
|
|
||||||
|
|
||||||
class Error(Exception):
|
class Error(Exception):
|
||||||
|
|
||||||
def __init__(self, message=None):
|
def __init__(self, message=None):
|
||||||
super(Error, self).__init__(message)
|
super(Error, self).__init__(message)
|
||||||
|
|
||||||
|
|
||||||
class ApiError(Error):
|
class ApiError(Error):
|
||||||
|
|
||||||
def __init__(self, message='Unknown', code='Unknown'):
|
def __init__(self, message='Unknown', code='Unknown'):
|
||||||
self.message = message
|
self.message = message
|
||||||
self.code = code
|
self.code = code
|
||||||
@ -81,7 +84,7 @@ def wrap_exception(f):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
if not isinstance(e, Error):
|
if not isinstance(e, Error):
|
||||||
#exc_type, exc_value, exc_traceback = sys.exc_info()
|
#exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
logging.exception('Uncaught exception')
|
logging.exception(_('Uncaught exception'))
|
||||||
#logging.error(traceback.extract_stack(exc_traceback))
|
#logging.error(traceback.extract_stack(exc_traceback))
|
||||||
raise Error(str(e))
|
raise Error(str(e))
|
||||||
raise
|
raise
|
||||||
|
@ -37,12 +37,12 @@ class Exchange(object):
|
|||||||
self._routes = {}
|
self._routes = {}
|
||||||
|
|
||||||
def publish(self, message, routing_key=None):
|
def publish(self, message, routing_key=None):
|
||||||
logging.debug('(%s) publish (key: %s) %s',
|
logging.debug(_('(%s) publish (key: %s) %s'),
|
||||||
self.name, routing_key, message)
|
self.name, routing_key, message)
|
||||||
routing_key = routing_key.split('.')[0]
|
routing_key = routing_key.split('.')[0]
|
||||||
if routing_key in self._routes:
|
if routing_key in self._routes:
|
||||||
for f in self._routes[routing_key]:
|
for f in self._routes[routing_key]:
|
||||||
logging.debug('Publishing to route %s', f)
|
logging.debug(_('Publishing to route %s'), f)
|
||||||
f(message, routing_key=routing_key)
|
f(message, routing_key=routing_key)
|
||||||
|
|
||||||
def bind(self, callback, routing_key):
|
def bind(self, callback, routing_key):
|
||||||
@ -82,16 +82,16 @@ class Backend(object):
|
|||||||
|
|
||||||
def queue_declare(self, queue, **kwargs):
|
def queue_declare(self, queue, **kwargs):
|
||||||
if queue not in self._queues:
|
if queue not in self._queues:
|
||||||
logging.debug('Declaring queue %s', queue)
|
logging.debug(_('Declaring queue %s'), queue)
|
||||||
self._queues[queue] = Queue(queue)
|
self._queues[queue] = Queue(queue)
|
||||||
|
|
||||||
def exchange_declare(self, exchange, type, *args, **kwargs):
|
def exchange_declare(self, exchange, type, *args, **kwargs):
|
||||||
if exchange not in self._exchanges:
|
if exchange not in self._exchanges:
|
||||||
logging.debug('Declaring exchange %s', exchange)
|
logging.debug(_('Declaring exchange %s'), exchange)
|
||||||
self._exchanges[exchange] = Exchange(exchange, type)
|
self._exchanges[exchange] = Exchange(exchange, type)
|
||||||
|
|
||||||
def queue_bind(self, queue, exchange, routing_key, **kwargs):
|
def queue_bind(self, queue, exchange, routing_key, **kwargs):
|
||||||
logging.debug('Binding %s to %s with key %s',
|
logging.debug(_('Binding %s to %s with key %s'),
|
||||||
queue, exchange, routing_key)
|
queue, exchange, routing_key)
|
||||||
self._exchanges[exchange].bind(self._queues[queue].push,
|
self._exchanges[exchange].bind(self._queues[queue].push,
|
||||||
routing_key)
|
routing_key)
|
||||||
@ -117,7 +117,7 @@ class Backend(object):
|
|||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
content_encoding=content_encoding)
|
content_encoding=content_encoding)
|
||||||
message.result = True
|
message.result = True
|
||||||
logging.debug('Getting from %s: %s', queue, message)
|
logging.debug(_('Getting from %s: %s'), queue, message)
|
||||||
return message
|
return message
|
||||||
|
|
||||||
def prepare_message(self, message_data, delivery_mode,
|
def prepare_message(self, message_data, delivery_mode,
|
||||||
|
@ -235,12 +235,11 @@ DEFINE_string('ec2_url', 'http://127.0.0.1:8773/services/Cloud',
|
|||||||
|
|
||||||
DEFINE_string('default_image', 'ami-11111',
|
DEFINE_string('default_image', 'ami-11111',
|
||||||
'default image to use, testing only')
|
'default image to use, testing only')
|
||||||
DEFINE_string('default_kernel', 'aki-11111',
|
|
||||||
'default kernel to use, testing only')
|
|
||||||
DEFINE_string('default_ramdisk', 'ari-11111',
|
|
||||||
'default ramdisk to use, testing only')
|
|
||||||
DEFINE_string('default_instance_type', 'm1.small',
|
DEFINE_string('default_instance_type', 'm1.small',
|
||||||
'default instance type to use, testing only')
|
'default instance type to use, testing only')
|
||||||
|
DEFINE_string('null_kernel', 'nokernel',
|
||||||
|
'kernel image that indicates not to use a kernel,'
|
||||||
|
' but to use a raw disk image instead')
|
||||||
|
|
||||||
DEFINE_string('vpn_image_id', 'ami-CLOUDPIPE', 'AMI for cloudpipe vpn server')
|
DEFINE_string('vpn_image_id', 'ami-CLOUDPIPE', 'AMI for cloudpipe vpn server')
|
||||||
DEFINE_string('vpn_key_suffix',
|
DEFINE_string('vpn_key_suffix',
|
||||||
|
@ -77,8 +77,8 @@ class ParallaxClient(object):
|
|||||||
data = json.loads(res.read())['images']
|
data = json.loads(res.read())['images']
|
||||||
return data
|
return data
|
||||||
else:
|
else:
|
||||||
logging.warn("Parallax returned HTTP error %d from "
|
logging.warn(_("Parallax returned HTTP error %d from "
|
||||||
"request for /images", res.status_int)
|
"request for /images"), res.status_int)
|
||||||
return []
|
return []
|
||||||
finally:
|
finally:
|
||||||
c.close()
|
c.close()
|
||||||
@ -96,8 +96,8 @@ class ParallaxClient(object):
|
|||||||
data = json.loads(res.read())['images']
|
data = json.loads(res.read())['images']
|
||||||
return data
|
return data
|
||||||
else:
|
else:
|
||||||
logging.warn("Parallax returned HTTP error %d from "
|
logging.warn(_("Parallax returned HTTP error %d from "
|
||||||
"request for /images/detail", res.status_int)
|
"request for /images/detail"), res.status_int)
|
||||||
return []
|
return []
|
||||||
finally:
|
finally:
|
||||||
c.close()
|
c.close()
|
||||||
|
@ -79,7 +79,8 @@ class S3ImageService(service.BaseImageService):
|
|||||||
result = self.index(context)
|
result = self.index(context)
|
||||||
result = [i for i in result if i['imageId'] == image_id]
|
result = [i for i in result if i['imageId'] == image_id]
|
||||||
if not result:
|
if not result:
|
||||||
raise exception.NotFound('Image %s could not be found' % image_id)
|
raise exception.NotFound(_('Image %s could not be found')
|
||||||
|
% image_id)
|
||||||
image = result[0]
|
image = result[0]
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ def ensure_vlan(vlan_num):
|
|||||||
"""Create a vlan unless it already exists"""
|
"""Create a vlan unless it already exists"""
|
||||||
interface = "vlan%s" % vlan_num
|
interface = "vlan%s" % vlan_num
|
||||||
if not _device_exists(interface):
|
if not _device_exists(interface):
|
||||||
logging.debug("Starting VLAN inteface %s", interface)
|
logging.debug(_("Starting VLAN inteface %s"), interface)
|
||||||
_execute("sudo vconfig set_name_type VLAN_PLUS_VID_NO_PAD")
|
_execute("sudo vconfig set_name_type VLAN_PLUS_VID_NO_PAD")
|
||||||
_execute("sudo vconfig add %s %s" % (FLAGS.vlan_interface, vlan_num))
|
_execute("sudo vconfig add %s %s" % (FLAGS.vlan_interface, vlan_num))
|
||||||
_execute("sudo ifconfig %s up" % interface)
|
_execute("sudo ifconfig %s up" % interface)
|
||||||
@ -145,7 +145,7 @@ def ensure_vlan(vlan_num):
|
|||||||
def ensure_bridge(bridge, interface, net_attrs=None):
|
def ensure_bridge(bridge, interface, net_attrs=None):
|
||||||
"""Create a bridge unless it already exists"""
|
"""Create a bridge unless it already exists"""
|
||||||
if not _device_exists(bridge):
|
if not _device_exists(bridge):
|
||||||
logging.debug("Starting Bridge interface for %s", interface)
|
logging.debug(_("Starting Bridge interface for %s"), interface)
|
||||||
_execute("sudo brctl addbr %s" % bridge)
|
_execute("sudo brctl addbr %s" % bridge)
|
||||||
_execute("sudo brctl setfd %s 0" % bridge)
|
_execute("sudo brctl setfd %s 0" % bridge)
|
||||||
# _execute("sudo brctl setageing %s 10" % bridge)
|
# _execute("sudo brctl setageing %s 10" % bridge)
|
||||||
@ -202,9 +202,9 @@ def update_dhcp(context, network_id):
|
|||||||
_execute('sudo kill -HUP %d' % pid)
|
_execute('sudo kill -HUP %d' % pid)
|
||||||
return
|
return
|
||||||
except Exception as exc: # pylint: disable-msg=W0703
|
except Exception as exc: # pylint: disable-msg=W0703
|
||||||
logging.debug("Hupping dnsmasq threw %s", exc)
|
logging.debug(_("Hupping dnsmasq threw %s"), exc)
|
||||||
else:
|
else:
|
||||||
logging.debug("Pid %d is stale, relaunching dnsmasq", pid)
|
logging.debug(_("Pid %d is stale, relaunching dnsmasq"), pid)
|
||||||
|
|
||||||
# FLAGFILE and DNSMASQ_INTERFACE in env
|
# FLAGFILE and DNSMASQ_INTERFACE in env
|
||||||
env = {'FLAGFILE': FLAGS.dhcpbridge_flagfile,
|
env = {'FLAGFILE': FLAGS.dhcpbridge_flagfile,
|
||||||
@ -276,7 +276,7 @@ def _stop_dnsmasq(network):
|
|||||||
try:
|
try:
|
||||||
_execute('sudo kill -TERM %d' % pid)
|
_execute('sudo kill -TERM %d' % pid)
|
||||||
except Exception as exc: # pylint: disable-msg=W0703
|
except Exception as exc: # pylint: disable-msg=W0703
|
||||||
logging.debug("Killing dnsmasq threw %s", exc)
|
logging.debug(_("Killing dnsmasq threw %s"), exc)
|
||||||
|
|
||||||
|
|
||||||
def _dhcp_file(bridge, kind):
|
def _dhcp_file(bridge, kind):
|
||||||
|
@ -115,7 +115,7 @@ class NetworkManager(manager.Manager):
|
|||||||
|
|
||||||
def set_network_host(self, context, network_id):
|
def set_network_host(self, context, network_id):
|
||||||
"""Safely sets the host of the network."""
|
"""Safely sets the host of the network."""
|
||||||
logging.debug("setting network host")
|
logging.debug(_("setting network host"))
|
||||||
host = self.db.network_set_host(context,
|
host = self.db.network_set_host(context,
|
||||||
network_id,
|
network_id,
|
||||||
self.host)
|
self.host)
|
||||||
@ -174,10 +174,10 @@ class NetworkManager(manager.Manager):
|
|||||||
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
|
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
|
||||||
instance_ref = fixed_ip_ref['instance']
|
instance_ref = fixed_ip_ref['instance']
|
||||||
if not instance_ref:
|
if not instance_ref:
|
||||||
raise exception.Error("IP %s leased that isn't associated" %
|
raise exception.Error(_("IP %s leased that isn't associated") %
|
||||||
address)
|
address)
|
||||||
if instance_ref['mac_address'] != mac:
|
if instance_ref['mac_address'] != mac:
|
||||||
raise exception.Error("IP %s leased to bad mac %s vs %s" %
|
raise exception.Error(_("IP %s leased to bad mac %s vs %s") %
|
||||||
(address, instance_ref['mac_address'], mac))
|
(address, instance_ref['mac_address'], mac))
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
self.db.fixed_ip_update(context,
|
self.db.fixed_ip_update(context,
|
||||||
@ -185,7 +185,8 @@ class NetworkManager(manager.Manager):
|
|||||||
{'leased': True,
|
{'leased': True,
|
||||||
'updated_at': now})
|
'updated_at': now})
|
||||||
if not fixed_ip_ref['allocated']:
|
if not fixed_ip_ref['allocated']:
|
||||||
logging.warn("IP %s leased that was already deallocated", address)
|
logging.warn(_("IP %s leased that was already deallocated"),
|
||||||
|
address)
|
||||||
|
|
||||||
def release_fixed_ip(self, context, mac, address):
|
def release_fixed_ip(self, context, mac, address):
|
||||||
"""Called by dhcp-bridge when ip is released."""
|
"""Called by dhcp-bridge when ip is released."""
|
||||||
@ -193,13 +194,13 @@ class NetworkManager(manager.Manager):
|
|||||||
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
|
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
|
||||||
instance_ref = fixed_ip_ref['instance']
|
instance_ref = fixed_ip_ref['instance']
|
||||||
if not instance_ref:
|
if not instance_ref:
|
||||||
raise exception.Error("IP %s released that isn't associated" %
|
raise exception.Error(_("IP %s released that isn't associated") %
|
||||||
address)
|
address)
|
||||||
if instance_ref['mac_address'] != mac:
|
if instance_ref['mac_address'] != mac:
|
||||||
raise exception.Error("IP %s released from bad mac %s vs %s" %
|
raise exception.Error(_("IP %s released from bad mac %s vs %s") %
|
||||||
(address, instance_ref['mac_address'], mac))
|
(address, instance_ref['mac_address'], mac))
|
||||||
if not fixed_ip_ref['leased']:
|
if not fixed_ip_ref['leased']:
|
||||||
logging.warn("IP %s released that was not leased", address)
|
logging.warn(_("IP %s released that was not leased"), address)
|
||||||
self.db.fixed_ip_update(context,
|
self.db.fixed_ip_update(context,
|
||||||
fixed_ip_ref['address'],
|
fixed_ip_ref['address'],
|
||||||
{'leased': False})
|
{'leased': False})
|
||||||
@ -361,8 +362,7 @@ class FlatDHCPManager(FlatManager):
|
|||||||
"""Sets up matching network for compute hosts."""
|
"""Sets up matching network for compute hosts."""
|
||||||
network_ref = db.network_get_by_instance(context, instance_id)
|
network_ref = db.network_get_by_instance(context, instance_id)
|
||||||
self.driver.ensure_bridge(network_ref['bridge'],
|
self.driver.ensure_bridge(network_ref['bridge'],
|
||||||
FLAGS.flat_interface,
|
FLAGS.flat_interface)
|
||||||
network_ref)
|
|
||||||
|
|
||||||
def setup_fixed_ip(self, context, address):
|
def setup_fixed_ip(self, context, address):
|
||||||
"""Setup dhcp for this network."""
|
"""Setup dhcp for this network."""
|
||||||
@ -408,7 +408,7 @@ class VlanManager(NetworkManager):
|
|||||||
self.host,
|
self.host,
|
||||||
time)
|
time)
|
||||||
if num:
|
if num:
|
||||||
logging.debug("Dissassociated %s stale fixed ip(s)", num)
|
logging.debug(_("Dissassociated %s stale fixed ip(s)"), num)
|
||||||
|
|
||||||
def init_host(self):
|
def init_host(self):
|
||||||
"""Do any initialization that needs to be run if this is a
|
"""Do any initialization that needs to be run if this is a
|
||||||
|
@ -102,7 +102,7 @@ def _render_parts(value, write_cb):
|
|||||||
_render_parts(subsubvalue, write_cb)
|
_render_parts(subsubvalue, write_cb)
|
||||||
write_cb('</' + utils.utf8(name) + '>')
|
write_cb('</' + utils.utf8(name) + '>')
|
||||||
else:
|
else:
|
||||||
raise Exception("Unknown S3 value type %r", value)
|
raise Exception(_("Unknown S3 value type %r"), value)
|
||||||
|
|
||||||
|
|
||||||
def get_argument(request, key, default_value):
|
def get_argument(request, key, default_value):
|
||||||
@ -134,7 +134,7 @@ def get_context(request):
|
|||||||
check_type='s3')
|
check_type='s3')
|
||||||
return context.RequestContext(user, project)
|
return context.RequestContext(user, project)
|
||||||
except exception.Error as ex:
|
except exception.Error as ex:
|
||||||
logging.debug("Authentication Failure: %s", ex)
|
logging.debug(_("Authentication Failure: %s"), ex)
|
||||||
raise exception.NotAuthorized()
|
raise exception.NotAuthorized()
|
||||||
|
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ class BucketResource(ErrorHandlingResource):
|
|||||||
|
|
||||||
def render_PUT(self, request):
|
def render_PUT(self, request):
|
||||||
"Creates the bucket resource"""
|
"Creates the bucket resource"""
|
||||||
logging.debug("Creating bucket %s", self.name)
|
logging.debug(_("Creating bucket %s"), self.name)
|
||||||
logging.debug("calling bucket.Bucket.create(%r, %r)",
|
logging.debug("calling bucket.Bucket.create(%r, %r)",
|
||||||
self.name,
|
self.name,
|
||||||
request.context)
|
request.context)
|
||||||
@ -237,7 +237,7 @@ class BucketResource(ErrorHandlingResource):
|
|||||||
|
|
||||||
def render_DELETE(self, request):
|
def render_DELETE(self, request):
|
||||||
"""Deletes the bucket resource"""
|
"""Deletes the bucket resource"""
|
||||||
logging.debug("Deleting bucket %s", self.name)
|
logging.debug(_("Deleting bucket %s"), self.name)
|
||||||
bucket_object = bucket.Bucket(self.name)
|
bucket_object = bucket.Bucket(self.name)
|
||||||
|
|
||||||
if not bucket_object.is_authorized(request.context):
|
if not bucket_object.is_authorized(request.context):
|
||||||
@ -261,7 +261,9 @@ class ObjectResource(ErrorHandlingResource):
|
|||||||
Raises NotAuthorized if user in request context is not
|
Raises NotAuthorized if user in request context is not
|
||||||
authorized to delete the object.
|
authorized to delete the object.
|
||||||
"""
|
"""
|
||||||
logging.debug("Getting object: %s / %s", self.bucket.name, self.name)
|
logging.debug(_("Getting object: %s / %s"),
|
||||||
|
self.bucket.name,
|
||||||
|
self.name)
|
||||||
|
|
||||||
if not self.bucket.is_authorized(request.context):
|
if not self.bucket.is_authorized(request.context):
|
||||||
raise exception.NotAuthorized()
|
raise exception.NotAuthorized()
|
||||||
@ -279,7 +281,9 @@ class ObjectResource(ErrorHandlingResource):
|
|||||||
Raises NotAuthorized if user in request context is not
|
Raises NotAuthorized if user in request context is not
|
||||||
authorized to delete the object.
|
authorized to delete the object.
|
||||||
"""
|
"""
|
||||||
logging.debug("Putting object: %s / %s", self.bucket.name, self.name)
|
logging.debug(_("Putting object: %s / %s"),
|
||||||
|
self.bucket.name,
|
||||||
|
self.name)
|
||||||
|
|
||||||
if not self.bucket.is_authorized(request.context):
|
if not self.bucket.is_authorized(request.context):
|
||||||
raise exception.NotAuthorized()
|
raise exception.NotAuthorized()
|
||||||
@ -298,7 +302,7 @@ class ObjectResource(ErrorHandlingResource):
|
|||||||
authorized to delete the object.
|
authorized to delete the object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logging.debug("Deleting object: %s / %s",
|
logging.debug(_("Deleting object: %s / %s"),
|
||||||
self.bucket.name,
|
self.bucket.name,
|
||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
@ -394,17 +398,17 @@ class ImagesResource(resource.Resource):
|
|||||||
image_id = get_argument(request, 'image_id', u'')
|
image_id = get_argument(request, 'image_id', u'')
|
||||||
image_object = image.Image(image_id)
|
image_object = image.Image(image_id)
|
||||||
if not image_object.is_authorized(request.context):
|
if not image_object.is_authorized(request.context):
|
||||||
logging.debug("not authorized for render_POST in images")
|
logging.debug(_("not authorized for render_POST in images"))
|
||||||
raise exception.NotAuthorized()
|
raise exception.NotAuthorized()
|
||||||
|
|
||||||
operation = get_argument(request, 'operation', u'')
|
operation = get_argument(request, 'operation', u'')
|
||||||
if operation:
|
if operation:
|
||||||
# operation implies publicity toggle
|
# operation implies publicity toggle
|
||||||
logging.debug("handling publicity toggle")
|
logging.debug(_("handling publicity toggle"))
|
||||||
image_object.set_public(operation == 'add')
|
image_object.set_public(operation == 'add')
|
||||||
else:
|
else:
|
||||||
# other attributes imply update
|
# other attributes imply update
|
||||||
logging.debug("update user fields")
|
logging.debug(_("update user fields"))
|
||||||
clean_args = {}
|
clean_args = {}
|
||||||
for arg in request.args.keys():
|
for arg in request.args.keys():
|
||||||
clean_args[arg] = request.args[arg][0]
|
clean_args[arg] = request.args[arg][0]
|
||||||
|
34
nova/rpc.py
34
nova/rpc.py
@ -91,15 +91,15 @@ class Consumer(messaging.Consumer):
|
|||||||
self.failed_connection = False
|
self.failed_connection = False
|
||||||
break
|
break
|
||||||
except: # Catching all because carrot sucks
|
except: # Catching all because carrot sucks
|
||||||
logging.exception("AMQP server on %s:%d is unreachable." \
|
logging.exception(_("AMQP server on %s:%d is unreachable."
|
||||||
" Trying again in %d seconds." % (
|
" Trying again in %d seconds.") % (
|
||||||
FLAGS.rabbit_host,
|
FLAGS.rabbit_host,
|
||||||
FLAGS.rabbit_port,
|
FLAGS.rabbit_port,
|
||||||
FLAGS.rabbit_retry_interval))
|
FLAGS.rabbit_retry_interval))
|
||||||
self.failed_connection = True
|
self.failed_connection = True
|
||||||
if self.failed_connection:
|
if self.failed_connection:
|
||||||
logging.exception("Unable to connect to AMQP server" \
|
logging.exception(_("Unable to connect to AMQP server"
|
||||||
" after %d tries. Shutting down." % FLAGS.rabbit_max_retries)
|
" after %d tries. Shutting down.") % FLAGS.rabbit_max_retries)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
|
def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False):
|
||||||
@ -116,14 +116,14 @@ class Consumer(messaging.Consumer):
|
|||||||
self.declare()
|
self.declare()
|
||||||
super(Consumer, self).fetch(no_ack, auto_ack, enable_callbacks)
|
super(Consumer, self).fetch(no_ack, auto_ack, enable_callbacks)
|
||||||
if self.failed_connection:
|
if self.failed_connection:
|
||||||
logging.error("Reconnected to queue")
|
logging.error(_("Reconnected to queue"))
|
||||||
self.failed_connection = False
|
self.failed_connection = False
|
||||||
# NOTE(vish): This is catching all errors because we really don't
|
# NOTE(vish): This is catching all errors because we really don't
|
||||||
# exceptions to be logged 10 times a second if some
|
# exceptions to be logged 10 times a second if some
|
||||||
# persistent failure occurs.
|
# persistent failure occurs.
|
||||||
except Exception: # pylint: disable-msg=W0703
|
except Exception: # pylint: disable-msg=W0703
|
||||||
if not self.failed_connection:
|
if not self.failed_connection:
|
||||||
logging.exception("Failed to fetch message from queue")
|
logging.exception(_("Failed to fetch message from queue"))
|
||||||
self.failed_connection = True
|
self.failed_connection = True
|
||||||
|
|
||||||
def attach_to_eventlet(self):
|
def attach_to_eventlet(self):
|
||||||
@ -153,7 +153,7 @@ class TopicConsumer(Consumer):
|
|||||||
class AdapterConsumer(TopicConsumer):
|
class AdapterConsumer(TopicConsumer):
|
||||||
"""Calls methods on a proxy object based on method and args"""
|
"""Calls methods on a proxy object based on method and args"""
|
||||||
def __init__(self, connection=None, topic="broadcast", proxy=None):
|
def __init__(self, connection=None, topic="broadcast", proxy=None):
|
||||||
LOG.debug('Initing the Adapter Consumer for %s' % (topic))
|
LOG.debug(_('Initing the Adapter Consumer for %s') % (topic))
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
super(AdapterConsumer, self).__init__(connection=connection,
|
super(AdapterConsumer, self).__init__(connection=connection,
|
||||||
topic=topic)
|
topic=topic)
|
||||||
@ -168,7 +168,7 @@ class AdapterConsumer(TopicConsumer):
|
|||||||
|
|
||||||
Example: {'method': 'echo', 'args': {'value': 42}}
|
Example: {'method': 'echo', 'args': {'value': 42}}
|
||||||
"""
|
"""
|
||||||
LOG.debug('received %s' % (message_data))
|
LOG.debug(_('received %s') % (message_data))
|
||||||
msg_id = message_data.pop('_msg_id', None)
|
msg_id = message_data.pop('_msg_id', None)
|
||||||
|
|
||||||
ctxt = _unpack_context(message_data)
|
ctxt = _unpack_context(message_data)
|
||||||
@ -181,8 +181,8 @@ class AdapterConsumer(TopicConsumer):
|
|||||||
# messages stay in the queue indefinitely, so for now
|
# messages stay in the queue indefinitely, so for now
|
||||||
# we just log the message and send an error string
|
# we just log the message and send an error string
|
||||||
# back to the caller
|
# back to the caller
|
||||||
LOG.warn('no method for message: %s' % (message_data))
|
LOG.warn(_('no method for message: %s') % (message_data))
|
||||||
msg_reply(msg_id, 'No method for message: %s' % message_data)
|
msg_reply(msg_id, _('No method for message: %s') % message_data)
|
||||||
return
|
return
|
||||||
|
|
||||||
node_func = getattr(self.proxy, str(method))
|
node_func = getattr(self.proxy, str(method))
|
||||||
@ -242,7 +242,7 @@ def msg_reply(msg_id, reply=None, failure=None):
|
|||||||
if failure:
|
if failure:
|
||||||
message = str(failure[1])
|
message = str(failure[1])
|
||||||
tb = traceback.format_exception(*failure)
|
tb = traceback.format_exception(*failure)
|
||||||
logging.error("Returning exception %s to caller", message)
|
logging.error(_("Returning exception %s to caller"), message)
|
||||||
logging.error(tb)
|
logging.error(tb)
|
||||||
failure = (failure[0].__name__, str(failure[1]), tb)
|
failure = (failure[0].__name__, str(failure[1]), tb)
|
||||||
conn = Connection.instance()
|
conn = Connection.instance()
|
||||||
@ -283,7 +283,7 @@ def _unpack_context(msg):
|
|||||||
if key.startswith('_context_'):
|
if key.startswith('_context_'):
|
||||||
value = msg.pop(key)
|
value = msg.pop(key)
|
||||||
context_dict[key[9:]] = value
|
context_dict[key[9:]] = value
|
||||||
LOG.debug('unpacked context: %s', context_dict)
|
LOG.debug(_('unpacked context: %s'), context_dict)
|
||||||
return context.RequestContext.from_dict(context_dict)
|
return context.RequestContext.from_dict(context_dict)
|
||||||
|
|
||||||
|
|
||||||
@ -302,10 +302,10 @@ def _pack_context(msg, context):
|
|||||||
|
|
||||||
def call(context, topic, msg):
|
def call(context, topic, msg):
|
||||||
"""Sends a message on a topic and wait for a response"""
|
"""Sends a message on a topic and wait for a response"""
|
||||||
LOG.debug("Making asynchronous call...")
|
LOG.debug(_("Making asynchronous call..."))
|
||||||
msg_id = uuid.uuid4().hex
|
msg_id = uuid.uuid4().hex
|
||||||
msg.update({'_msg_id': msg_id})
|
msg.update({'_msg_id': msg_id})
|
||||||
LOG.debug("MSG_ID is %s" % (msg_id))
|
LOG.debug(_("MSG_ID is %s") % (msg_id))
|
||||||
_pack_context(msg, context)
|
_pack_context(msg, context)
|
||||||
|
|
||||||
class WaitMessage(object):
|
class WaitMessage(object):
|
||||||
@ -353,7 +353,7 @@ def cast(context, topic, msg):
|
|||||||
|
|
||||||
def generic_response(message_data, message):
|
def generic_response(message_data, message):
|
||||||
"""Logs a result and exits"""
|
"""Logs a result and exits"""
|
||||||
LOG.debug('response %s', message_data)
|
LOG.debug(_('response %s'), message_data)
|
||||||
message.ack()
|
message.ack()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@ -362,8 +362,8 @@ def send_message(topic, message, wait=True):
|
|||||||
"""Sends a message for testing"""
|
"""Sends a message for testing"""
|
||||||
msg_id = uuid.uuid4().hex
|
msg_id = uuid.uuid4().hex
|
||||||
message.update({'_msg_id': msg_id})
|
message.update({'_msg_id': msg_id})
|
||||||
LOG.debug('topic is %s', topic)
|
LOG.debug(_('topic is %s'), topic)
|
||||||
LOG.debug('message %s', message)
|
LOG.debug(_('message %s'), message)
|
||||||
|
|
||||||
if wait:
|
if wait:
|
||||||
consumer = messaging.Consumer(connection=Connection.instance(),
|
consumer = messaging.Consumer(connection=Connection.instance(),
|
||||||
|
@ -34,5 +34,5 @@ class ChanceScheduler(driver.Scheduler):
|
|||||||
|
|
||||||
hosts = self.hosts_up(context, topic)
|
hosts = self.hosts_up(context, topic)
|
||||||
if not hosts:
|
if not hosts:
|
||||||
raise driver.NoValidHost("No hosts found")
|
raise driver.NoValidHost(_("No hosts found"))
|
||||||
return hosts[int(random.random() * len(hosts))]
|
return hosts[int(random.random() * len(hosts))]
|
||||||
|
@ -58,4 +58,4 @@ class Scheduler(object):
|
|||||||
|
|
||||||
def schedule(self, context, topic, *_args, **_kwargs):
|
def schedule(self, context, topic, *_args, **_kwargs):
|
||||||
"""Must override at least this method for scheduler to work."""
|
"""Must override at least this method for scheduler to work."""
|
||||||
raise NotImplementedError("Must implement a fallback schedule")
|
raise NotImplementedError(_("Must implement a fallback schedule"))
|
||||||
|
@ -65,4 +65,4 @@ class SchedulerManager(manager.Manager):
|
|||||||
db.queue_get_for(context, topic, host),
|
db.queue_get_for(context, topic, host),
|
||||||
{"method": method,
|
{"method": method,
|
||||||
"args": kwargs})
|
"args": kwargs})
|
||||||
logging.debug("Casting to %s %s for %s", topic, host, method)
|
logging.debug(_("Casting to %s %s for %s"), topic, host, method)
|
||||||
|
@ -47,7 +47,7 @@ class SimpleScheduler(chance.ChanceScheduler):
|
|||||||
for result in results:
|
for result in results:
|
||||||
(service, instance_cores) = result
|
(service, instance_cores) = result
|
||||||
if instance_cores + instance_ref['vcpus'] > FLAGS.max_cores:
|
if instance_cores + instance_ref['vcpus'] > FLAGS.max_cores:
|
||||||
raise driver.NoValidHost("All hosts have too many cores")
|
raise driver.NoValidHost(_("All hosts have too many cores"))
|
||||||
if self.service_is_up(service):
|
if self.service_is_up(service):
|
||||||
# NOTE(vish): this probably belongs in the manager, if we
|
# NOTE(vish): this probably belongs in the manager, if we
|
||||||
# can generalize this somehow
|
# can generalize this somehow
|
||||||
@ -57,7 +57,7 @@ class SimpleScheduler(chance.ChanceScheduler):
|
|||||||
{'host': service['host'],
|
{'host': service['host'],
|
||||||
'scheduled_at': now})
|
'scheduled_at': now})
|
||||||
return service['host']
|
return service['host']
|
||||||
raise driver.NoValidHost("No hosts found")
|
raise driver.NoValidHost(_("No hosts found"))
|
||||||
|
|
||||||
def schedule_create_volume(self, context, volume_id, *_args, **_kwargs):
|
def schedule_create_volume(self, context, volume_id, *_args, **_kwargs):
|
||||||
"""Picks a host that is up and has the fewest volumes."""
|
"""Picks a host that is up and has the fewest volumes."""
|
||||||
@ -66,7 +66,8 @@ class SimpleScheduler(chance.ChanceScheduler):
|
|||||||
for result in results:
|
for result in results:
|
||||||
(service, volume_gigabytes) = result
|
(service, volume_gigabytes) = result
|
||||||
if volume_gigabytes + volume_ref['size'] > FLAGS.max_gigabytes:
|
if volume_gigabytes + volume_ref['size'] > FLAGS.max_gigabytes:
|
||||||
raise driver.NoValidHost("All hosts have too many gigabytes")
|
raise driver.NoValidHost(_("All hosts have too many "
|
||||||
|
"gigabytes"))
|
||||||
if self.service_is_up(service):
|
if self.service_is_up(service):
|
||||||
# NOTE(vish): this probably belongs in the manager, if we
|
# NOTE(vish): this probably belongs in the manager, if we
|
||||||
# can generalize this somehow
|
# can generalize this somehow
|
||||||
@ -76,7 +77,7 @@ class SimpleScheduler(chance.ChanceScheduler):
|
|||||||
{'host': service['host'],
|
{'host': service['host'],
|
||||||
'scheduled_at': now})
|
'scheduled_at': now})
|
||||||
return service['host']
|
return service['host']
|
||||||
raise driver.NoValidHost("No hosts found")
|
raise driver.NoValidHost(_("No hosts found"))
|
||||||
|
|
||||||
def schedule_set_network_host(self, context, *_args, **_kwargs):
|
def schedule_set_network_host(self, context, *_args, **_kwargs):
|
||||||
"""Picks a host that is up and has the fewest networks."""
|
"""Picks a host that is up and has the fewest networks."""
|
||||||
@ -85,7 +86,7 @@ class SimpleScheduler(chance.ChanceScheduler):
|
|||||||
for result in results:
|
for result in results:
|
||||||
(service, instance_count) = result
|
(service, instance_count) = result
|
||||||
if instance_count >= FLAGS.max_networks:
|
if instance_count >= FLAGS.max_networks:
|
||||||
raise driver.NoValidHost("All hosts have too many networks")
|
raise driver.NoValidHost(_("All hosts have too many networks"))
|
||||||
if self.service_is_up(service):
|
if self.service_is_up(service):
|
||||||
return service['host']
|
return service['host']
|
||||||
raise driver.NoValidHost("No hosts found")
|
raise driver.NoValidHost(_("No hosts found"))
|
||||||
|
@ -151,7 +151,7 @@ class Service(object):
|
|||||||
report_interval = FLAGS.report_interval
|
report_interval = FLAGS.report_interval
|
||||||
if not periodic_interval:
|
if not periodic_interval:
|
||||||
periodic_interval = FLAGS.periodic_interval
|
periodic_interval = FLAGS.periodic_interval
|
||||||
logging.warn("Starting %s node", topic)
|
logging.warn(_("Starting %s node"), topic)
|
||||||
service_obj = cls(host, binary, topic, manager,
|
service_obj = cls(host, binary, topic, manager,
|
||||||
report_interval, periodic_interval)
|
report_interval, periodic_interval)
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ class Service(object):
|
|||||||
try:
|
try:
|
||||||
db.service_destroy(context.get_admin_context(), self.service_id)
|
db.service_destroy(context.get_admin_context(), self.service_id)
|
||||||
except exception.NotFound:
|
except exception.NotFound:
|
||||||
logging.warn("Service killed that has no database entry")
|
logging.warn(_("Service killed that has no database entry"))
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
for x in self.timers:
|
for x in self.timers:
|
||||||
@ -184,8 +184,8 @@ class Service(object):
|
|||||||
try:
|
try:
|
||||||
service_ref = db.service_get(ctxt, self.service_id)
|
service_ref = db.service_get(ctxt, self.service_id)
|
||||||
except exception.NotFound:
|
except exception.NotFound:
|
||||||
logging.debug("The service database object disappeared, "
|
logging.debug(_("The service database object disappeared, "
|
||||||
"Recreating it.")
|
"Recreating it."))
|
||||||
self._create_service_ref(ctxt)
|
self._create_service_ref(ctxt)
|
||||||
service_ref = db.service_get(ctxt, self.service_id)
|
service_ref = db.service_get(ctxt, self.service_id)
|
||||||
|
|
||||||
@ -196,13 +196,13 @@ class Service(object):
|
|||||||
# TODO(termie): make this pattern be more elegant.
|
# TODO(termie): make this pattern be more elegant.
|
||||||
if getattr(self, "model_disconnected", False):
|
if getattr(self, "model_disconnected", False):
|
||||||
self.model_disconnected = False
|
self.model_disconnected = False
|
||||||
logging.error("Recovered model server connection!")
|
logging.error(_("Recovered model server connection!"))
|
||||||
|
|
||||||
# TODO(vish): this should probably only catch connection errors
|
# TODO(vish): this should probably only catch connection errors
|
||||||
except Exception: # pylint: disable-msg=W0702
|
except Exception: # pylint: disable-msg=W0702
|
||||||
if not getattr(self, "model_disconnected", False):
|
if not getattr(self, "model_disconnected", False):
|
||||||
self.model_disconnected = True
|
self.model_disconnected = True
|
||||||
logging.exception("model server went away")
|
logging.exception(_("model server went away"))
|
||||||
|
|
||||||
|
|
||||||
def serve(*services):
|
def serve(*services):
|
||||||
@ -221,7 +221,7 @@ def serve(*services):
|
|||||||
else:
|
else:
|
||||||
logging.getLogger().setLevel(logging.WARNING)
|
logging.getLogger().setLevel(logging.WARNING)
|
||||||
|
|
||||||
logging.debug("Full set of FLAGS:")
|
logging.debug(_("Full set of FLAGS:"))
|
||||||
for flag in FLAGS:
|
for flag in FLAGS:
|
||||||
logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
|
logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
|
||||||
|
|
||||||
|
@ -56,11 +56,16 @@ def instance_address(context, instance_id):
|
|||||||
|
|
||||||
|
|
||||||
def stub_instance(id, user_id=1):
|
def stub_instance(id, user_id=1):
|
||||||
return Instance(id=id + 123456, state=0, image_id=10, user_id=user_id,
|
return Instance(id=int(id) + 123456, state=0, image_id=10, user_id=user_id,
|
||||||
display_name='server%s' % id, internal_id=id)
|
display_name='server%s' % id, internal_id=id)
|
||||||
|
|
||||||
|
|
||||||
|
def fake_compute_api(cls, req, id):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ServersTest(unittest.TestCase):
|
class ServersTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.stubs = stubout.StubOutForTesting()
|
self.stubs = stubout.StubOutForTesting()
|
||||||
fakes.FakeAuthManager.auth_data = {}
|
fakes.FakeAuthManager.auth_data = {}
|
||||||
@ -82,9 +87,15 @@ class ServersTest(unittest.TestCase):
|
|||||||
instance_address)
|
instance_address)
|
||||||
self.stubs.Set(nova.db.api, 'instance_get_floating_address',
|
self.stubs.Set(nova.db.api, 'instance_get_floating_address',
|
||||||
instance_address)
|
instance_address)
|
||||||
|
self.stubs.Set(nova.compute.api.ComputeAPI, 'pause',
|
||||||
|
fake_compute_api)
|
||||||
|
self.stubs.Set(nova.compute.api.ComputeAPI, 'unpause',
|
||||||
|
fake_compute_api)
|
||||||
|
self.allow_admin = FLAGS.allow_admin_api
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.stubs.UnsetAll()
|
self.stubs.UnsetAll()
|
||||||
|
FLAGS.allow_admin_api = self.allow_admin
|
||||||
|
|
||||||
def test_get_server_by_id(self):
|
def test_get_server_by_id(self):
|
||||||
req = webob.Request.blank('/v1.0/servers/1')
|
req = webob.Request.blank('/v1.0/servers/1')
|
||||||
@ -211,6 +222,30 @@ class ServersTest(unittest.TestCase):
|
|||||||
self.assertEqual(s['imageId'], 10)
|
self.assertEqual(s['imageId'], 10)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
def test_server_pause(self):
|
||||||
|
FLAGS.allow_admin_api = True
|
||||||
|
body = dict(server=dict(
|
||||||
|
name='server_test', imageId=2, flavorId=2, metadata={},
|
||||||
|
personality={}))
|
||||||
|
req = webob.Request.blank('/v1.0/servers/1/pause')
|
||||||
|
req.method = 'POST'
|
||||||
|
req.content_type = 'application/json'
|
||||||
|
req.body = json.dumps(body)
|
||||||
|
res = req.get_response(nova.api.API('os'))
|
||||||
|
self.assertEqual(res.status_int, 202)
|
||||||
|
|
||||||
|
def test_server_unpause(self):
|
||||||
|
FLAGS.allow_admin_api = True
|
||||||
|
body = dict(server=dict(
|
||||||
|
name='server_test', imageId=2, flavorId=2, metadata={},
|
||||||
|
personality={}))
|
||||||
|
req = webob.Request.blank('/v1.0/servers/1/unpause')
|
||||||
|
req.method = 'POST'
|
||||||
|
req.content_type = 'application/json'
|
||||||
|
req.body = json.dumps(body)
|
||||||
|
res = req.get_response(nova.api.API('os'))
|
||||||
|
self.assertEqual(res.status_int, 202)
|
||||||
|
|
||||||
def test_server_reboot(self):
|
def test_server_reboot(self):
|
||||||
body = dict(server=dict(
|
body = dict(server=dict(
|
||||||
name='server_test', imageId=2, flavorId=2, metadata={},
|
name='server_test', imageId=2, flavorId=2, metadata={},
|
||||||
|
@ -333,14 +333,10 @@ class AuthManagerLdapTestCase(AuthManagerTestCase, test.TestCase):
|
|||||||
AuthManagerTestCase.__init__(self)
|
AuthManagerTestCase.__init__(self)
|
||||||
test.TestCase.__init__(self, *args, **kwargs)
|
test.TestCase.__init__(self, *args, **kwargs)
|
||||||
import nova.auth.fakeldap as fakeldap
|
import nova.auth.fakeldap as fakeldap
|
||||||
FLAGS.redis_db = 8
|
|
||||||
if FLAGS.flush_db:
|
if FLAGS.flush_db:
|
||||||
logging.info("Flushing redis datastore")
|
logging.info("Flushing datastore")
|
||||||
try:
|
r = fakeldap.Store.instance()
|
||||||
r = fakeldap.Redis.instance()
|
|
||||||
r.flushdb()
|
r.flushdb()
|
||||||
except:
|
|
||||||
self.skip = True
|
|
||||||
|
|
||||||
|
|
||||||
class AuthManagerDbTestCase(AuthManagerTestCase, test.TestCase):
|
class AuthManagerDbTestCase(AuthManagerTestCase, test.TestCase):
|
||||||
|
@ -127,6 +127,14 @@ class ComputeTestCase(test.TestCase):
|
|||||||
self.assert_(instance_ref['launched_at'] < terminate)
|
self.assert_(instance_ref['launched_at'] < terminate)
|
||||||
self.assert_(instance_ref['deleted_at'] > terminate)
|
self.assert_(instance_ref['deleted_at'] > terminate)
|
||||||
|
|
||||||
|
def test_pause(self):
|
||||||
|
"""Ensure instance can be paused"""
|
||||||
|
instance_id = self._create_instance()
|
||||||
|
self.compute.run_instance(self.context, instance_id)
|
||||||
|
self.compute.pause_instance(self.context, instance_id)
|
||||||
|
self.compute.unpause_instance(self.context, instance_id)
|
||||||
|
self.compute.terminate_instance(self.context, instance_id)
|
||||||
|
|
||||||
def test_reboot(self):
|
def test_reboot(self):
|
||||||
"""Ensure instance can be rebooted"""
|
"""Ensure instance can be rebooted"""
|
||||||
instance_id = self._create_instance()
|
instance_id = self._create_instance()
|
||||||
|
@ -40,11 +40,8 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
self.network = utils.import_object(FLAGS.network_manager)
|
self.network = utils.import_object(FLAGS.network_manager)
|
||||||
FLAGS.instances_path = ''
|
FLAGS.instances_path = ''
|
||||||
|
|
||||||
def test_get_uri_and_template(self):
|
test_ip = '10.11.12.13'
|
||||||
ip = '10.11.12.13'
|
test_instance = {'memory_kb': '1024000',
|
||||||
|
|
||||||
instance = {'internal_id': 1,
|
|
||||||
'memory_kb': '1024000',
|
|
||||||
'basepath': '/some/path',
|
'basepath': '/some/path',
|
||||||
'bridge_name': 'br100',
|
'bridge_name': 'br100',
|
||||||
'mac_address': '02:12:34:46:56:67',
|
'mac_address': '02:12:34:46:56:67',
|
||||||
@ -53,6 +50,41 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
'bridge': 'br101',
|
'bridge': 'br101',
|
||||||
'instance_type': 'm1.small'}
|
'instance_type': 'm1.small'}
|
||||||
|
|
||||||
|
def test_xml_and_uri_no_ramdisk_no_kernel(self):
|
||||||
|
instance_data = dict(self.test_instance)
|
||||||
|
self.do_test_xml_and_uri(instance_data,
|
||||||
|
expect_kernel=False, expect_ramdisk=False)
|
||||||
|
|
||||||
|
def test_xml_and_uri_no_ramdisk(self):
|
||||||
|
instance_data = dict(self.test_instance)
|
||||||
|
instance_data['kernel_id'] = 'aki-deadbeef'
|
||||||
|
self.do_test_xml_and_uri(instance_data,
|
||||||
|
expect_kernel=True, expect_ramdisk=False)
|
||||||
|
|
||||||
|
def test_xml_and_uri_no_kernel(self):
|
||||||
|
instance_data = dict(self.test_instance)
|
||||||
|
instance_data['ramdisk_id'] = 'ari-deadbeef'
|
||||||
|
self.do_test_xml_and_uri(instance_data,
|
||||||
|
expect_kernel=False, expect_ramdisk=False)
|
||||||
|
|
||||||
|
def test_xml_and_uri(self):
|
||||||
|
instance_data = dict(self.test_instance)
|
||||||
|
instance_data['ramdisk_id'] = 'ari-deadbeef'
|
||||||
|
instance_data['kernel_id'] = 'aki-deadbeef'
|
||||||
|
self.do_test_xml_and_uri(instance_data,
|
||||||
|
expect_kernel=True, expect_ramdisk=True)
|
||||||
|
|
||||||
|
def test_xml_and_uri_rescue(self):
|
||||||
|
instance_data = dict(self.test_instance)
|
||||||
|
instance_data['ramdisk_id'] = 'ari-deadbeef'
|
||||||
|
instance_data['kernel_id'] = 'aki-deadbeef'
|
||||||
|
self.do_test_xml_and_uri(instance_data,
|
||||||
|
expect_kernel=True, expect_ramdisk=True,
|
||||||
|
rescue=True)
|
||||||
|
|
||||||
|
def do_test_xml_and_uri(self, instance,
|
||||||
|
expect_ramdisk, expect_kernel,
|
||||||
|
rescue=False):
|
||||||
user_context = context.RequestContext(project=self.project,
|
user_context = context.RequestContext(project=self.project,
|
||||||
user=self.user)
|
user=self.user)
|
||||||
instance_ref = db.instance_create(user_context, instance)
|
instance_ref = db.instance_create(user_context, instance)
|
||||||
@ -60,12 +92,13 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
self.network.set_network_host(context.get_admin_context(),
|
self.network.set_network_host(context.get_admin_context(),
|
||||||
network_ref['id'])
|
network_ref['id'])
|
||||||
|
|
||||||
fixed_ip = {'address': ip,
|
fixed_ip = {'address': self.test_ip,
|
||||||
'network_id': network_ref['id']}
|
'network_id': network_ref['id']}
|
||||||
|
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip)
|
fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip)
|
||||||
db.fixed_ip_update(ctxt, ip, {'allocated': True,
|
db.fixed_ip_update(ctxt, self.test_ip,
|
||||||
|
{'allocated': True,
|
||||||
'instance_id': instance_ref['id']})
|
'instance_id': instance_ref['id']})
|
||||||
|
|
||||||
type_uri_map = {'qemu': ('qemu:///system',
|
type_uri_map = {'qemu': ('qemu:///system',
|
||||||
@ -78,23 +111,73 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
(lambda t: t.find('./devices/emulator'), None)]),
|
(lambda t: t.find('./devices/emulator'), None)]),
|
||||||
'uml': ('uml:///system',
|
'uml': ('uml:///system',
|
||||||
[(lambda t: t.find('.').get('type'), 'uml'),
|
[(lambda t: t.find('.').get('type'), 'uml'),
|
||||||
(lambda t: t.find('./os/type').text, 'uml')])}
|
(lambda t: t.find('./os/type').text, 'uml')]),
|
||||||
|
'xen': ('xen:///',
|
||||||
|
[(lambda t: t.find('.').get('type'), 'xen'),
|
||||||
|
(lambda t: t.find('./os/type').text, 'linux')]),
|
||||||
|
}
|
||||||
|
|
||||||
|
for hypervisor_type in ['qemu', 'kvm', 'xen']:
|
||||||
|
check_list = type_uri_map[hypervisor_type][1]
|
||||||
|
|
||||||
|
if rescue:
|
||||||
|
check = (lambda t: t.find('./os/kernel').text.split('/')[1],
|
||||||
|
'rescue-kernel')
|
||||||
|
check_list.append(check)
|
||||||
|
check = (lambda t: t.find('./os/initrd').text.split('/')[1],
|
||||||
|
'rescue-ramdisk')
|
||||||
|
check_list.append(check)
|
||||||
|
else:
|
||||||
|
if expect_kernel:
|
||||||
|
check = (lambda t: t.find('./os/kernel').text.split(
|
||||||
|
'/')[1], 'kernel')
|
||||||
|
else:
|
||||||
|
check = (lambda t: t.find('./os/kernel'), None)
|
||||||
|
check_list.append(check)
|
||||||
|
|
||||||
|
if expect_ramdisk:
|
||||||
|
check = (lambda t: t.find('./os/initrd').text.split(
|
||||||
|
'/')[1], 'ramdisk')
|
||||||
|
else:
|
||||||
|
check = (lambda t: t.find('./os/initrd'), None)
|
||||||
|
check_list.append(check)
|
||||||
|
|
||||||
common_checks = [
|
common_checks = [
|
||||||
(lambda t: t.find('.').tag, 'domain'),
|
(lambda t: t.find('.').tag, 'domain'),
|
||||||
(lambda t: t.find('./devices/interface/filterref/parameter').\
|
(lambda t: t.find(
|
||||||
get('name'), 'IP'),
|
'./devices/interface/filterref/parameter').get('name'), 'IP'),
|
||||||
(lambda t: t.find('./devices/interface/filterref/parameter').\
|
(lambda t: t.find(
|
||||||
get('value'), '10.11.12.13')]
|
'./devices/interface/filterref/parameter').get(
|
||||||
|
'value'), '10.11.12.13'),
|
||||||
|
(lambda t: t.findall(
|
||||||
|
'./devices/interface/filterref/parameter')[1].get(
|
||||||
|
'name'), 'DHCPSERVER'),
|
||||||
|
(lambda t: t.findall(
|
||||||
|
'./devices/interface/filterref/parameter')[1].get(
|
||||||
|
'value'), '10.0.0.1'),
|
||||||
|
(lambda t: t.find('./devices/serial/source').get(
|
||||||
|
'path').split('/')[1], 'console.log'),
|
||||||
|
(lambda t: t.find('./memory').text, '2097152')]
|
||||||
|
|
||||||
|
if rescue:
|
||||||
|
common_checks += [
|
||||||
|
(lambda t: t.findall('./devices/disk/source')[0].get(
|
||||||
|
'file').split('/')[1], 'rescue-disk'),
|
||||||
|
(lambda t: t.findall('./devices/disk/source')[1].get(
|
||||||
|
'file').split('/')[1], 'disk')]
|
||||||
|
else:
|
||||||
|
common_checks += [(lambda t: t.findall(
|
||||||
|
'./devices/disk/source')[0].get('file').split('/')[1],
|
||||||
|
'disk')]
|
||||||
|
|
||||||
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
|
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
|
||||||
FLAGS.libvirt_type = libvirt_type
|
FLAGS.libvirt_type = libvirt_type
|
||||||
conn = libvirt_conn.LibvirtConnection(True)
|
conn = libvirt_conn.LibvirtConnection(True)
|
||||||
|
|
||||||
uri, _template, _rescue = conn.get_uri_and_templates()
|
uri = conn.get_uri()
|
||||||
self.assertEquals(uri, expected_uri)
|
self.assertEquals(uri, expected_uri)
|
||||||
|
|
||||||
xml = conn.to_xml(instance_ref)
|
xml = conn.to_xml(instance_ref, rescue)
|
||||||
tree = xml_to_tree(xml)
|
tree = xml_to_tree(xml)
|
||||||
for i, (check, expected_result) in enumerate(checks):
|
for i, (check, expected_result) in enumerate(checks):
|
||||||
self.assertEqual(check(tree),
|
self.assertEqual(check(tree),
|
||||||
@ -106,6 +189,9 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
expected_result,
|
expected_result,
|
||||||
'%s failed common check %d' % (xml, i))
|
'%s failed common check %d' % (xml, i))
|
||||||
|
|
||||||
|
# This test is supposed to make sure we don't override a specifically
|
||||||
|
# set uri
|
||||||
|
#
|
||||||
# Deliberately not just assigning this string to FLAGS.libvirt_uri and
|
# Deliberately not just assigning this string to FLAGS.libvirt_uri and
|
||||||
# checking against that later on. This way we make sure the
|
# checking against that later on. This way we make sure the
|
||||||
# implementation doesn't fiddle around with the FLAGS.
|
# implementation doesn't fiddle around with the FLAGS.
|
||||||
@ -114,7 +200,7 @@ class LibvirtConnTestCase(test.TestCase):
|
|||||||
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
|
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
|
||||||
FLAGS.libvirt_type = libvirt_type
|
FLAGS.libvirt_type = libvirt_type
|
||||||
conn = libvirt_conn.LibvirtConnection(True)
|
conn = libvirt_conn.LibvirtConnection(True)
|
||||||
uri, _template, _rescue = conn.get_uri_and_templates()
|
uri = conn.get_uri()
|
||||||
self.assertEquals(uri, testuri)
|
self.assertEquals(uri, testuri)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
@ -208,7 +208,7 @@ def stop(pidfile):
|
|||||||
pid = None
|
pid = None
|
||||||
|
|
||||||
if not pid:
|
if not pid:
|
||||||
message = "pidfile %s does not exist. Daemon not running?\n"
|
message = _("pidfile %s does not exist. Daemon not running?\n")
|
||||||
sys.stderr.write(message % pidfile)
|
sys.stderr.write(message % pidfile)
|
||||||
# Not an error in a restart
|
# Not an error in a restart
|
||||||
return
|
return
|
||||||
@ -229,7 +229,7 @@ def stop(pidfile):
|
|||||||
|
|
||||||
|
|
||||||
def serve(filename):
|
def serve(filename):
|
||||||
logging.debug("Serving %s" % filename)
|
logging.debug(_("Serving %s") % filename)
|
||||||
name = os.path.basename(filename)
|
name = os.path.basename(filename)
|
||||||
OptionsClass = WrapTwistedOptions(TwistdServerOptions)
|
OptionsClass = WrapTwistedOptions(TwistdServerOptions)
|
||||||
options = OptionsClass()
|
options = OptionsClass()
|
||||||
@ -281,7 +281,7 @@ def serve(filename):
|
|||||||
else:
|
else:
|
||||||
logging.getLogger().setLevel(logging.WARNING)
|
logging.getLogger().setLevel(logging.WARNING)
|
||||||
|
|
||||||
logging.debug("Full set of FLAGS:")
|
logging.debug(_("Full set of FLAGS:"))
|
||||||
for flag in FLAGS:
|
for flag in FLAGS:
|
||||||
logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
|
logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ def import_class(import_str):
|
|||||||
__import__(mod_str)
|
__import__(mod_str)
|
||||||
return getattr(sys.modules[mod_str], class_str)
|
return getattr(sys.modules[mod_str], class_str)
|
||||||
except (ImportError, ValueError, AttributeError):
|
except (ImportError, ValueError, AttributeError):
|
||||||
raise exception.NotFound('Class %s cannot be found' % class_str)
|
raise exception.NotFound(_('Class %s cannot be found') % class_str)
|
||||||
|
|
||||||
|
|
||||||
def import_object(import_str):
|
def import_object(import_str):
|
||||||
@ -64,7 +64,7 @@ def import_object(import_str):
|
|||||||
|
|
||||||
|
|
||||||
def fetchfile(url, target):
|
def fetchfile(url, target):
|
||||||
logging.debug("Fetching %s" % url)
|
logging.debug(_("Fetching %s") % url)
|
||||||
# c = pycurl.Curl()
|
# c = pycurl.Curl()
|
||||||
# fp = open(target, "wb")
|
# fp = open(target, "wb")
|
||||||
# c.setopt(c.URL, url)
|
# c.setopt(c.URL, url)
|
||||||
@ -76,7 +76,7 @@ def fetchfile(url, target):
|
|||||||
|
|
||||||
|
|
||||||
def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
|
def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
|
||||||
logging.debug("Running cmd (subprocess): %s", cmd)
|
logging.debug(_("Running cmd (subprocess): %s"), cmd)
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
if addl_env:
|
if addl_env:
|
||||||
env.update(addl_env)
|
env.update(addl_env)
|
||||||
@ -89,7 +89,7 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
|
|||||||
result = obj.communicate()
|
result = obj.communicate()
|
||||||
obj.stdin.close()
|
obj.stdin.close()
|
||||||
if obj.returncode:
|
if obj.returncode:
|
||||||
logging.debug("Result was %s" % (obj.returncode))
|
logging.debug(_("Result was %s") % (obj.returncode))
|
||||||
if check_exit_code and obj.returncode != 0:
|
if check_exit_code and obj.returncode != 0:
|
||||||
(stdout, stderr) = result
|
(stdout, stderr) = result
|
||||||
raise ProcessExecutionError(exit_code=obj.returncode,
|
raise ProcessExecutionError(exit_code=obj.returncode,
|
||||||
@ -127,7 +127,7 @@ def debug(arg):
|
|||||||
|
|
||||||
|
|
||||||
def runthis(prompt, cmd, check_exit_code=True):
|
def runthis(prompt, cmd, check_exit_code=True):
|
||||||
logging.debug("Running %s" % (cmd))
|
logging.debug(_("Running %s") % (cmd))
|
||||||
rv, err = execute(cmd, check_exit_code=check_exit_code)
|
rv, err = execute(cmd, check_exit_code=check_exit_code)
|
||||||
|
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ def get_my_ip():
|
|||||||
csock.close()
|
csock.close()
|
||||||
return addr
|
return addr
|
||||||
except socket.gaierror as ex:
|
except socket.gaierror as ex:
|
||||||
logging.warn("Couldn't get IP, using 127.0.0.1 %s", ex)
|
logging.warn(_("Couldn't get IP, using 127.0.0.1 %s"), ex)
|
||||||
return "127.0.0.1"
|
return "127.0.0.1"
|
||||||
|
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ class LazyPluggable(object):
|
|||||||
if not self.__backend:
|
if not self.__backend:
|
||||||
backend_name = self.__pivot.value
|
backend_name = self.__pivot.value
|
||||||
if backend_name not in self.__backends:
|
if backend_name not in self.__backends:
|
||||||
raise exception.Error('Invalid backend: %s' % backend_name)
|
raise exception.Error(_('Invalid backend: %s') % backend_name)
|
||||||
|
|
||||||
backend = self.__backends[backend_name]
|
backend = self.__backends[backend_name]
|
||||||
if type(backend) == type(tuple()):
|
if type(backend) == type(tuple()):
|
||||||
|
@ -66,6 +66,6 @@ def get_connection(read_only=False):
|
|||||||
raise Exception('Unknown connection type "%s"' % t)
|
raise Exception('Unknown connection type "%s"' % t)
|
||||||
|
|
||||||
if conn is None:
|
if conn is None:
|
||||||
logging.error('Failed to open connection to the hypervisor')
|
logging.error(_('Failed to open connection to the hypervisor'))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return conn
|
return conn
|
||||||
|
@ -136,6 +136,18 @@ class FakeConnection(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def pause(self, instance, callback):
|
||||||
|
"""
|
||||||
|
Pause the specified instance.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unpause(self, instance, callback):
|
||||||
|
"""
|
||||||
|
Unpause the specified instance.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def destroy(self, instance):
|
def destroy(self, instance):
|
||||||
"""
|
"""
|
||||||
Destroy (shutdown and delete) the specified instance.
|
Destroy (shutdown and delete) the specified instance.
|
||||||
@ -169,7 +181,8 @@ class FakeConnection(object):
|
|||||||
knowledge of the instance
|
knowledge of the instance
|
||||||
"""
|
"""
|
||||||
if instance_name not in self.instances:
|
if instance_name not in self.instances:
|
||||||
raise exception.NotFound("Instance %s Not Found" % instance_name)
|
raise exception.NotFound(_("Instance %s Not Found")
|
||||||
|
% instance_name)
|
||||||
i = self.instances[instance_name]
|
i = self.instances[instance_name]
|
||||||
return {'state': i._state,
|
return {'state': i._state,
|
||||||
'max_mem': 0,
|
'max_mem': 0,
|
||||||
@ -249,5 +262,6 @@ class FakeConnection(object):
|
|||||||
|
|
||||||
|
|
||||||
class FakeInstance(object):
|
class FakeInstance(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._state = power_state.NOSTATE
|
self._state = power_state.NOSTATE
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
<domain type='%(type)s'>
|
|
||||||
<name>%(name)s</name>
|
|
||||||
<os>
|
|
||||||
<type>hvm</type>
|
|
||||||
<kernel>%(basepath)s/kernel</kernel>
|
|
||||||
<initrd>%(basepath)s/ramdisk</initrd>
|
|
||||||
<cmdline>root=/dev/vda1 console=ttyS0</cmdline>
|
|
||||||
</os>
|
|
||||||
<features>
|
|
||||||
<acpi/>
|
|
||||||
</features>
|
|
||||||
<memory>%(memory_kb)s</memory>
|
|
||||||
<vcpu>%(vcpus)s</vcpu>
|
|
||||||
<devices>
|
|
||||||
<disk type='file'>
|
|
||||||
<source file='%(basepath)s/disk'/>
|
|
||||||
<target dev='vda' bus='virtio'/>
|
|
||||||
</disk>
|
|
||||||
<interface type='bridge'>
|
|
||||||
<source bridge='%(bridge_name)s'/>
|
|
||||||
<mac address='%(mac_address)s'/>
|
|
||||||
<!-- <model type='virtio'/> CANT RUN virtio network right now -->
|
|
||||||
<filterref filter="nova-instance-%(name)s">
|
|
||||||
<parameter name="IP" value="%(ip_address)s" />
|
|
||||||
<parameter name="DHCPSERVER" value="%(dhcp_server)s" />
|
|
||||||
%(extra_params)s
|
|
||||||
</filterref>
|
|
||||||
</interface>
|
|
||||||
<serial type="file">
|
|
||||||
<source path='%(basepath)s/console.log'/>
|
|
||||||
<target port='1'/>
|
|
||||||
</serial>
|
|
||||||
</devices>
|
|
||||||
</domain>
|
|
@ -1,34 +0,0 @@
|
|||||||
<domain type='%(type)s'>
|
|
||||||
<name>%(name)s</name>
|
|
||||||
<os>
|
|
||||||
<type>linux</type>
|
|
||||||
<kernel>%(basepath)s/kernel</kernel>
|
|
||||||
<initrd>%(basepath)s/ramdisk</initrd>
|
|
||||||
<root>/dev/xvda1</root>
|
|
||||||
<cmdline>ro</cmdline>
|
|
||||||
</os>
|
|
||||||
<features>
|
|
||||||
<acpi/>
|
|
||||||
</features>
|
|
||||||
<memory>%(memory_kb)s</memory>
|
|
||||||
<vcpu>%(vcpus)s</vcpu>
|
|
||||||
<devices>
|
|
||||||
<disk type='file'>
|
|
||||||
<source file='%(basepath)s/rescue-disk'/>
|
|
||||||
<target dev='sda' />
|
|
||||||
</disk>
|
|
||||||
<disk type='file'>
|
|
||||||
<source file='%(basepath)s/disk'/>
|
|
||||||
<target dev='sdb' />
|
|
||||||
</disk>
|
|
||||||
<interface type='bridge'>
|
|
||||||
<source bridge='%(bridge_name)s'/>
|
|
||||||
<mac address='%(mac_address)s'/>
|
|
||||||
</interface>
|
|
||||||
<console type="file">
|
|
||||||
<source path='%(basepath)s/console.log'/>
|
|
||||||
<target port='1'/>
|
|
||||||
</console>
|
|
||||||
</devices>
|
|
||||||
</domain>
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
<domain type='%(type)s'>
|
|
||||||
<name>%(name)s</name>
|
|
||||||
<os>
|
|
||||||
<type>linux</type>
|
|
||||||
<kernel>%(basepath)s/kernel</kernel>
|
|
||||||
<initrd>%(basepath)s/ramdisk</initrd>
|
|
||||||
<root>/dev/xvda1</root>
|
|
||||||
<cmdline>ro</cmdline>
|
|
||||||
</os>
|
|
||||||
<features>
|
|
||||||
<acpi/>
|
|
||||||
</features>
|
|
||||||
<memory>%(memory_kb)s</memory>
|
|
||||||
<vcpu>%(vcpus)s</vcpu>
|
|
||||||
<devices>
|
|
||||||
<disk type='file'>
|
|
||||||
<source file='%(basepath)s/disk'/>
|
|
||||||
<target dev='sda' />
|
|
||||||
</disk>
|
|
||||||
<interface type='bridge'>
|
|
||||||
<source bridge='%(bridge_name)s'/>
|
|
||||||
<mac address='%(mac_address)s'/>
|
|
||||||
</interface>
|
|
||||||
<console type="file">
|
|
||||||
<source path='%(basepath)s/console.log'/>
|
|
||||||
<target port='1'/>
|
|
||||||
</console>
|
|
||||||
</devices>
|
|
||||||
</domain>
|
|
||||||
|
|
79
nova/virt/libvirt.xml.template
Normal file
79
nova/virt/libvirt.xml.template
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<domain type='${type}'>
|
||||||
|
<name>${name}</name>
|
||||||
|
<memory>${memory_kb}</memory>
|
||||||
|
<os>
|
||||||
|
#if $type == 'uml'
|
||||||
|
#set $disk_prefix = 'ubd'
|
||||||
|
#set $disk_bus = 'uml'
|
||||||
|
<type>uml</type>
|
||||||
|
<kernel>/usr/bin/linux</kernel>
|
||||||
|
<root>/dev/ubda1</root>
|
||||||
|
#else
|
||||||
|
#if $type == 'xen'
|
||||||
|
#set $disk_prefix = 'sd'
|
||||||
|
#set $disk_bus = 'scsi'
|
||||||
|
<type>linux</type>
|
||||||
|
<root>/dev/xvda1</root>
|
||||||
|
#else
|
||||||
|
#set $disk_prefix = 'vd'
|
||||||
|
#set $disk_bus = 'virtio'
|
||||||
|
<type>hvm</type>
|
||||||
|
#end if
|
||||||
|
#if $getVar('rescue', False)
|
||||||
|
<kernel>${basepath}/rescue-kernel</kernel>
|
||||||
|
<initrd>${basepath}/rescue-ramdisk</initrd>
|
||||||
|
#else
|
||||||
|
#if $getVar('kernel', None)
|
||||||
|
<kernel>${kernel}</kernel>
|
||||||
|
#if $type == 'xen'
|
||||||
|
<cmdline>ro</cmdline>
|
||||||
|
#else
|
||||||
|
<cmdline>root=/dev/vda1 console=ttyS0</cmdline>
|
||||||
|
#end if
|
||||||
|
#if $getVar('ramdisk', None)
|
||||||
|
<initrd>${ramdisk}</initrd>
|
||||||
|
#end if
|
||||||
|
#else
|
||||||
|
<boot dev="hd" />
|
||||||
|
#end if
|
||||||
|
#end if
|
||||||
|
#end if
|
||||||
|
</os>
|
||||||
|
<features>
|
||||||
|
<acpi/>
|
||||||
|
</features>
|
||||||
|
<vcpu>${vcpus}</vcpu>
|
||||||
|
<devices>
|
||||||
|
#if $getVar('rescue', False)
|
||||||
|
<disk type='file'>
|
||||||
|
<source file='${basepath}/rescue-disk'/>
|
||||||
|
<target dev='${disk_prefix}a' bus='${disk_bus}'/>
|
||||||
|
</disk>
|
||||||
|
<disk type='file'>
|
||||||
|
<source file='${basepath}/disk'/>
|
||||||
|
<target dev='${disk_prefix}b' bus='${disk_bus}'/>
|
||||||
|
</disk>
|
||||||
|
#else
|
||||||
|
<disk type='file'>
|
||||||
|
<source file='${basepath}/disk'/>
|
||||||
|
<target dev='${disk_prefix}a' bus='${disk_bus}'/>
|
||||||
|
</disk>
|
||||||
|
#end if
|
||||||
|
<interface type='bridge'>
|
||||||
|
<source bridge='${bridge_name}'/>
|
||||||
|
<mac address='${mac_address}'/>
|
||||||
|
<!-- <model type='virtio'/> CANT RUN virtio network right now -->
|
||||||
|
<filterref filter="nova-instance-${name}">
|
||||||
|
<parameter name="IP" value="${ip_address}" />
|
||||||
|
<parameter name="DHCPSERVER" value="${dhcp_server}" />
|
||||||
|
#if $getVar('extra_params', False)
|
||||||
|
${extra_params}
|
||||||
|
#end if
|
||||||
|
</filterref>
|
||||||
|
</interface>
|
||||||
|
<serial type="file">
|
||||||
|
<source path='${basepath}/console.log'/>
|
||||||
|
<target port='1'/>
|
||||||
|
</serial>
|
||||||
|
</devices>
|
||||||
|
</domain>
|
@ -27,12 +27,7 @@ Supports KVM, QEMU, UML, and XEN.
|
|||||||
:libvirt_type: Libvirt domain type. Can be kvm, qemu, uml, xen
|
:libvirt_type: Libvirt domain type. Can be kvm, qemu, uml, xen
|
||||||
(default: kvm).
|
(default: kvm).
|
||||||
:libvirt_uri: Override for the default libvirt URI (depends on libvirt_type).
|
:libvirt_uri: Override for the default libvirt URI (depends on libvirt_type).
|
||||||
:libvirt_xml_template: Libvirt XML Template (QEmu/KVM).
|
:libvirt_xml_template: Libvirt XML Template.
|
||||||
:libvirt_xen_xml_template: Libvirt XML Template (Xen).
|
|
||||||
:libvirt_uml_xml_template: Libvirt XML Template (User Mode Linux).
|
|
||||||
:libvirt_rescue_xml_template: XML template for rescue mode (KVM & QEMU).
|
|
||||||
:libvirt_rescue_xen_xml_template: XML templage for rescue mode (XEN).
|
|
||||||
:libvirt_rescue_uml_xml_template: XML template for rescue mode (UML).
|
|
||||||
:rescue_image_id: Rescue ami image (default: ami-rescue).
|
:rescue_image_id: Rescue ami image (default: ami-rescue).
|
||||||
:rescue_kernel_id: Rescue aki image (default: aki-rescue).
|
:rescue_kernel_id: Rescue aki image (default: aki-rescue).
|
||||||
:rescue_ramdisk_id: Rescue ari image (default: ari-rescue).
|
:rescue_ramdisk_id: Rescue ari image (default: ari-rescue).
|
||||||
@ -62,36 +57,20 @@ from nova.compute import instance_types
|
|||||||
from nova.compute import power_state
|
from nova.compute import power_state
|
||||||
from nova.virt import images
|
from nova.virt import images
|
||||||
|
|
||||||
|
from Cheetah.Template import Template
|
||||||
|
|
||||||
libvirt = None
|
libvirt = None
|
||||||
libxml2 = None
|
libxml2 = None
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
flags.DEFINE_string('libvirt_rescue_xml_template',
|
|
||||||
utils.abspath('virt/libvirt.rescue.qemu.xml.template'),
|
|
||||||
'Libvirt RESCUE XML Template for QEmu/KVM')
|
|
||||||
flags.DEFINE_string('libvirt_rescue_xen_xml_template',
|
|
||||||
utils.abspath('virt/libvirt.rescue.xen.xml.template'),
|
|
||||||
'Libvirt RESCUE XML Template for xen')
|
|
||||||
flags.DEFINE_string('libvirt_rescue_uml_xml_template',
|
|
||||||
utils.abspath('virt/libvirt.rescue.uml.xml.template'),
|
|
||||||
'Libvirt RESCUE XML Template for user-mode-linux')
|
|
||||||
# TODO(vish): These flags should probably go into a shared location
|
# TODO(vish): These flags should probably go into a shared location
|
||||||
flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image')
|
flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image')
|
||||||
flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image')
|
flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image')
|
||||||
flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image')
|
flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image')
|
||||||
flags.DEFINE_string('libvirt_xml_template',
|
flags.DEFINE_string('libvirt_xml_template',
|
||||||
utils.abspath('virt/libvirt.qemu.xml.template'),
|
utils.abspath('virt/libvirt.xml.template'),
|
||||||
'Libvirt XML Template for QEmu/KVM')
|
'Libvirt XML Template')
|
||||||
flags.DEFINE_string('libvirt_xen_xml_template',
|
|
||||||
utils.abspath('virt/libvirt.xen.xml.template'),
|
|
||||||
'Libvirt XML Template for Xen')
|
|
||||||
flags.DEFINE_string('libvirt_uml_xml_template',
|
|
||||||
utils.abspath('virt/libvirt.uml.xml.template'),
|
|
||||||
'Libvirt XML Template for user-mode-linux')
|
|
||||||
flags.DEFINE_string('injected_network_template',
|
|
||||||
utils.abspath('virt/interfaces.template'),
|
|
||||||
'Template file for injected network')
|
|
||||||
flags.DEFINE_string('libvirt_type',
|
flags.DEFINE_string('libvirt_type',
|
||||||
'kvm',
|
'kvm',
|
||||||
'Libvirt domain type (valid options are: '
|
'Libvirt domain type (valid options are: '
|
||||||
@ -123,13 +102,11 @@ def _get_net_and_mask(cidr):
|
|||||||
|
|
||||||
|
|
||||||
class LibvirtConnection(object):
|
class LibvirtConnection(object):
|
||||||
def __init__(self, read_only):
|
|
||||||
(self.libvirt_uri,
|
|
||||||
template_file,
|
|
||||||
rescue_file) = self.get_uri_and_templates()
|
|
||||||
|
|
||||||
self.libvirt_xml = open(template_file).read()
|
def __init__(self, read_only):
|
||||||
self.rescue_xml = open(rescue_file).read()
|
self.libvirt_uri = self.get_uri()
|
||||||
|
|
||||||
|
self.libvirt_xml = open(FLAGS.libvirt_xml_template).read()
|
||||||
self._wrapped_conn = None
|
self._wrapped_conn = None
|
||||||
self.read_only = read_only
|
self.read_only = read_only
|
||||||
|
|
||||||
@ -139,7 +116,7 @@ class LibvirtConnection(object):
|
|||||||
@property
|
@property
|
||||||
def _conn(self):
|
def _conn(self):
|
||||||
if not self._wrapped_conn or not self._test_connection():
|
if not self._wrapped_conn or not self._test_connection():
|
||||||
logging.debug('Connecting to libvirt: %s' % self.libvirt_uri)
|
logging.debug(_('Connecting to libvirt: %s') % self.libvirt_uri)
|
||||||
self._wrapped_conn = self._connect(self.libvirt_uri,
|
self._wrapped_conn = self._connect(self.libvirt_uri,
|
||||||
self.read_only)
|
self.read_only)
|
||||||
return self._wrapped_conn
|
return self._wrapped_conn
|
||||||
@ -151,24 +128,18 @@ class LibvirtConnection(object):
|
|||||||
except libvirt.libvirtError as e:
|
except libvirt.libvirtError as e:
|
||||||
if e.get_error_code() == libvirt.VIR_ERR_SYSTEM_ERROR and \
|
if e.get_error_code() == libvirt.VIR_ERR_SYSTEM_ERROR and \
|
||||||
e.get_error_domain() == libvirt.VIR_FROM_REMOTE:
|
e.get_error_domain() == libvirt.VIR_FROM_REMOTE:
|
||||||
logging.debug('Connection to libvirt broke')
|
logging.debug(_('Connection to libvirt broke'))
|
||||||
return False
|
return False
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_uri_and_templates(self):
|
def get_uri(self):
|
||||||
if FLAGS.libvirt_type == 'uml':
|
if FLAGS.libvirt_type == 'uml':
|
||||||
uri = FLAGS.libvirt_uri or 'uml:///system'
|
uri = FLAGS.libvirt_uri or 'uml:///system'
|
||||||
template_file = FLAGS.libvirt_uml_xml_template
|
|
||||||
rescue_file = FLAGS.libvirt_rescue_uml_xml_template
|
|
||||||
elif FLAGS.libvirt_type == 'xen':
|
elif FLAGS.libvirt_type == 'xen':
|
||||||
uri = FLAGS.libvirt_uri or 'xen:///'
|
uri = FLAGS.libvirt_uri or 'xen:///'
|
||||||
template_file = FLAGS.libvirt_xen_xml_template
|
|
||||||
rescue_file = FLAGS.libvirt_rescue_xen_xml_template
|
|
||||||
else:
|
else:
|
||||||
uri = FLAGS.libvirt_uri or 'qemu:///system'
|
uri = FLAGS.libvirt_uri or 'qemu:///system'
|
||||||
template_file = FLAGS.libvirt_xml_template
|
return uri
|
||||||
rescue_file = FLAGS.libvirt_rescue_xml_template
|
|
||||||
return uri, template_file, rescue_file
|
|
||||||
|
|
||||||
def _connect(self, uri, read_only):
|
def _connect(self, uri, read_only):
|
||||||
auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],
|
auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],
|
||||||
@ -228,7 +199,7 @@ class LibvirtConnection(object):
|
|||||||
|
|
||||||
def _cleanup(self, instance):
|
def _cleanup(self, instance):
|
||||||
target = os.path.join(FLAGS.instances_path, instance['name'])
|
target = os.path.join(FLAGS.instances_path, instance['name'])
|
||||||
logging.info('instance %s: deleting instance files %s',
|
logging.info(_('instance %s: deleting instance files %s'),
|
||||||
instance['name'], target)
|
instance['name'], target)
|
||||||
if os.path.exists(target):
|
if os.path.exists(target):
|
||||||
shutil.rmtree(target)
|
shutil.rmtree(target)
|
||||||
@ -270,7 +241,7 @@ class LibvirtConnection(object):
|
|||||||
mount_device = mountpoint.rpartition("/")[2]
|
mount_device = mountpoint.rpartition("/")[2]
|
||||||
xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)
|
xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)
|
||||||
if not xml:
|
if not xml:
|
||||||
raise exception.NotFound("No disk at %s" % mount_device)
|
raise exception.NotFound(_("No disk at %s") % mount_device)
|
||||||
virt_dom.detachDevice(xml)
|
virt_dom.detachDevice(xml)
|
||||||
|
|
||||||
@exception.wrap_exception
|
@exception.wrap_exception
|
||||||
@ -286,10 +257,10 @@ class LibvirtConnection(object):
|
|||||||
db.instance_set_state(context.get_admin_context(),
|
db.instance_set_state(context.get_admin_context(),
|
||||||
instance['id'], state)
|
instance['id'], state)
|
||||||
if state == power_state.RUNNING:
|
if state == power_state.RUNNING:
|
||||||
logging.debug('instance %s: rebooted', instance['name'])
|
logging.debug(_('instance %s: rebooted'), instance['name'])
|
||||||
timer.stop()
|
timer.stop()
|
||||||
except Exception, exn:
|
except Exception, exn:
|
||||||
logging.error('_wait_for_reboot failed: %s', exn)
|
logging.error(_('_wait_for_reboot failed: %s'), exn)
|
||||||
db.instance_set_state(context.get_admin_context(),
|
db.instance_set_state(context.get_admin_context(),
|
||||||
instance['id'],
|
instance['id'],
|
||||||
power_state.SHUTDOWN)
|
power_state.SHUTDOWN)
|
||||||
@ -298,6 +269,14 @@ class LibvirtConnection(object):
|
|||||||
timer.f = _wait_for_reboot
|
timer.f = _wait_for_reboot
|
||||||
return timer.start(interval=0.5, now=True)
|
return timer.start(interval=0.5, now=True)
|
||||||
|
|
||||||
|
@exception.wrap_exception
|
||||||
|
def pause(self, instance, callback):
|
||||||
|
raise exception.APIError("pause not supported for libvirt.")
|
||||||
|
|
||||||
|
@exception.wrap_exception
|
||||||
|
def unpause(self, instance, callback):
|
||||||
|
raise exception.APIError("unpause not supported for libvirt.")
|
||||||
|
|
||||||
@exception.wrap_exception
|
@exception.wrap_exception
|
||||||
def rescue(self, instance):
|
def rescue(self, instance):
|
||||||
self.destroy(instance, False)
|
self.destroy(instance, False)
|
||||||
@ -316,10 +295,10 @@ class LibvirtConnection(object):
|
|||||||
state = self.get_info(instance['name'])['state']
|
state = self.get_info(instance['name'])['state']
|
||||||
db.instance_set_state(None, instance['id'], state)
|
db.instance_set_state(None, instance['id'], state)
|
||||||
if state == power_state.RUNNING:
|
if state == power_state.RUNNING:
|
||||||
logging.debug('instance %s: rescued', instance['name'])
|
logging.debug(_('instance %s: rescued'), instance['name'])
|
||||||
timer.stop()
|
timer.stop()
|
||||||
except Exception, exn:
|
except Exception, exn:
|
||||||
logging.error('_wait_for_rescue failed: %s', exn)
|
logging.error(_('_wait_for_rescue failed: %s'), exn)
|
||||||
db.instance_set_state(None,
|
db.instance_set_state(None,
|
||||||
instance['id'],
|
instance['id'],
|
||||||
power_state.SHUTDOWN)
|
power_state.SHUTDOWN)
|
||||||
@ -344,7 +323,7 @@ class LibvirtConnection(object):
|
|||||||
NWFilterFirewall(self._conn).setup_nwfilters_for_instance(instance)
|
NWFilterFirewall(self._conn).setup_nwfilters_for_instance(instance)
|
||||||
self._create_image(instance, xml)
|
self._create_image(instance, xml)
|
||||||
self._conn.createXML(xml, 0)
|
self._conn.createXML(xml, 0)
|
||||||
logging.debug("instance %s: is running", instance['name'])
|
logging.debug(_("instance %s: is running"), instance['name'])
|
||||||
|
|
||||||
timer = utils.LoopingCall(f=None)
|
timer = utils.LoopingCall(f=None)
|
||||||
|
|
||||||
@ -354,10 +333,10 @@ class LibvirtConnection(object):
|
|||||||
db.instance_set_state(context.get_admin_context(),
|
db.instance_set_state(context.get_admin_context(),
|
||||||
instance['id'], state)
|
instance['id'], state)
|
||||||
if state == power_state.RUNNING:
|
if state == power_state.RUNNING:
|
||||||
logging.debug('instance %s: booted', instance['name'])
|
logging.debug(_('instance %s: booted'), instance['name'])
|
||||||
timer.stop()
|
timer.stop()
|
||||||
except:
|
except:
|
||||||
logging.exception('instance %s: failed to boot',
|
logging.exception(_('instance %s: failed to boot'),
|
||||||
instance['name'])
|
instance['name'])
|
||||||
db.instance_set_state(context.get_admin_context(),
|
db.instance_set_state(context.get_admin_context(),
|
||||||
instance['id'],
|
instance['id'],
|
||||||
@ -372,7 +351,7 @@ class LibvirtConnection(object):
|
|||||||
virsh_output = virsh_output[0].strip()
|
virsh_output = virsh_output[0].strip()
|
||||||
|
|
||||||
if virsh_output.startswith('/dev/'):
|
if virsh_output.startswith('/dev/'):
|
||||||
logging.info('cool, it\'s a device')
|
logging.info(_('cool, it\'s a device'))
|
||||||
out, err = utils.execute("sudo dd if=%s iflag=nonblock" %
|
out, err = utils.execute("sudo dd if=%s iflag=nonblock" %
|
||||||
virsh_output, check_exit_code=False)
|
virsh_output, check_exit_code=False)
|
||||||
return out
|
return out
|
||||||
@ -380,7 +359,7 @@ class LibvirtConnection(object):
|
|||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _append_to_file(self, data, fpath):
|
def _append_to_file(self, data, fpath):
|
||||||
logging.info('data: %r, fpath: %r' % (data, fpath))
|
logging.info(_('data: %r, fpath: %r') % (data, fpath))
|
||||||
fp = open(fpath, 'a+')
|
fp = open(fpath, 'a+')
|
||||||
fp.write(data)
|
fp.write(data)
|
||||||
return fpath
|
return fpath
|
||||||
@ -422,7 +401,7 @@ class LibvirtConnection(object):
|
|||||||
|
|
||||||
# TODO(termie): these are blocking calls, it would be great
|
# TODO(termie): these are blocking calls, it would be great
|
||||||
# if they weren't.
|
# if they weren't.
|
||||||
logging.info('instance %s: Creating image', inst['name'])
|
logging.info(_('instance %s: Creating image'), inst['name'])
|
||||||
f = open(basepath('libvirt.xml'), 'w')
|
f = open(basepath('libvirt.xml'), 'w')
|
||||||
f.write(libvirt_xml)
|
f.write(libvirt_xml)
|
||||||
f.close()
|
f.close()
|
||||||
@ -441,18 +420,28 @@ class LibvirtConnection(object):
|
|||||||
if not os.path.exists(basepath('disk')):
|
if not os.path.exists(basepath('disk')):
|
||||||
images.fetch(inst.image_id, basepath('disk-raw'), user,
|
images.fetch(inst.image_id, basepath('disk-raw'), user,
|
||||||
project)
|
project)
|
||||||
|
|
||||||
|
if inst['kernel_id']:
|
||||||
if not os.path.exists(basepath('kernel')):
|
if not os.path.exists(basepath('kernel')):
|
||||||
images.fetch(inst.kernel_id, basepath('kernel'), user,
|
images.fetch(inst['kernel_id'], basepath('kernel'),
|
||||||
project)
|
user, project)
|
||||||
|
if inst['ramdisk_id']:
|
||||||
if not os.path.exists(basepath('ramdisk')):
|
if not os.path.exists(basepath('ramdisk')):
|
||||||
images.fetch(inst.ramdisk_id, basepath('ramdisk'), user,
|
images.fetch(inst['ramdisk_id'], basepath('ramdisk'),
|
||||||
project)
|
user, project)
|
||||||
|
|
||||||
def execute(cmd, process_input=None, check_exit_code=True):
|
def execute(cmd, process_input=None, check_exit_code=True):
|
||||||
return utils.execute(cmd=cmd,
|
return utils.execute(cmd=cmd,
|
||||||
process_input=process_input,
|
process_input=process_input,
|
||||||
check_exit_code=check_exit_code)
|
check_exit_code=check_exit_code)
|
||||||
|
|
||||||
|
# For now, we assume that if we're not using a kernel, we're using a
|
||||||
|
# partitioned disk image where the target partition is the first
|
||||||
|
# partition
|
||||||
|
target_partition = None
|
||||||
|
if not inst['kernel_id']:
|
||||||
|
target_partition = "1"
|
||||||
|
|
||||||
key = str(inst['key_data'])
|
key = str(inst['key_data'])
|
||||||
net = None
|
net = None
|
||||||
network_ref = db.network_get_by_instance(context.get_admin_context(),
|
network_ref = db.network_get_by_instance(context.get_admin_context(),
|
||||||
@ -468,14 +457,22 @@ class LibvirtConnection(object):
|
|||||||
'dns': network_ref['dns']}
|
'dns': network_ref['dns']}
|
||||||
if key or net:
|
if key or net:
|
||||||
if key:
|
if key:
|
||||||
logging.info('instance %s: injecting key into image %s',
|
logging.info(_('instance %s: injecting key into image %s'),
|
||||||
inst['name'], inst.image_id)
|
inst['name'], inst.image_id)
|
||||||
if net:
|
if net:
|
||||||
logging.info('instance %s: injecting net into image %s',
|
logging.info(_('instance %s: injecting net into image %s'),
|
||||||
inst['name'], inst.image_id)
|
inst['name'], inst.image_id)
|
||||||
|
try:
|
||||||
disk.inject_data(basepath('disk-raw'), key, net,
|
disk.inject_data(basepath('disk-raw'), key, net,
|
||||||
|
partition=target_partition,
|
||||||
execute=execute)
|
execute=execute)
|
||||||
|
except Exception as e:
|
||||||
|
# This could be a windows image, or a vmdk format disk
|
||||||
|
logging.warn(_('instance %s: ignoring error injecting data'
|
||||||
|
' into image %s (%s)'),
|
||||||
|
inst['name'], inst.image_id, e)
|
||||||
|
|
||||||
|
if inst['kernel_id']:
|
||||||
if os.path.exists(basepath('disk')):
|
if os.path.exists(basepath('disk')):
|
||||||
utils.execute('rm -f %s' % basepath('disk'))
|
utils.execute('rm -f %s' % basepath('disk'))
|
||||||
|
|
||||||
@ -486,15 +483,21 @@ class LibvirtConnection(object):
|
|||||||
resize = True
|
resize = True
|
||||||
if inst['instance_type'] == 'm1.tiny' or prefix == 'rescue-':
|
if inst['instance_type'] == 'm1.tiny' or prefix == 'rescue-':
|
||||||
resize = False
|
resize = False
|
||||||
|
|
||||||
|
if inst['kernel_id']:
|
||||||
disk.partition(basepath('disk-raw'), basepath('disk'),
|
disk.partition(basepath('disk-raw'), basepath('disk'),
|
||||||
local_bytes, resize, execute=execute)
|
local_bytes, resize, execute=execute)
|
||||||
|
else:
|
||||||
|
os.rename(basepath('disk-raw'), basepath('disk'))
|
||||||
|
disk.extend(basepath('disk'), local_bytes, execute=execute)
|
||||||
|
|
||||||
if FLAGS.libvirt_type == 'uml':
|
if FLAGS.libvirt_type == 'uml':
|
||||||
utils.execute('sudo chown root %s' % basepath('disk'))
|
utils.execute('sudo chown root %s' % basepath('disk'))
|
||||||
|
|
||||||
def to_xml(self, instance, rescue=False):
|
def to_xml(self, instance, rescue=False):
|
||||||
# TODO(termie): cache?
|
# TODO(termie): cache?
|
||||||
logging.debug('instance %s: starting toXML method', instance['name'])
|
logging.debug(_('instance %s: starting toXML method'),
|
||||||
|
instance['name'])
|
||||||
network = db.project_get_network(context.get_admin_context(),
|
network = db.project_get_network(context.get_admin_context(),
|
||||||
instance['project_id'])
|
instance['project_id'])
|
||||||
# FIXME(vish): stick this in db
|
# FIXME(vish): stick this in db
|
||||||
@ -523,20 +526,29 @@ class LibvirtConnection(object):
|
|||||||
'mac_address': instance['mac_address'],
|
'mac_address': instance['mac_address'],
|
||||||
'ip_address': ip_address,
|
'ip_address': ip_address,
|
||||||
'dhcp_server': dhcp_server,
|
'dhcp_server': dhcp_server,
|
||||||
'extra_params': extra_params}
|
'extra_params': extra_params,
|
||||||
if rescue:
|
'rescue': rescue}
|
||||||
libvirt_xml = self.rescue_xml % xml_info
|
if not rescue:
|
||||||
else:
|
if instance['kernel_id']:
|
||||||
libvirt_xml = self.libvirt_xml % xml_info
|
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
|
||||||
logging.debug('instance %s: finished toXML method', instance['name'])
|
|
||||||
|
|
||||||
return libvirt_xml
|
if instance['ramdisk_id']:
|
||||||
|
xml_info['ramdisk'] = xml_info['basepath'] + "/ramdisk"
|
||||||
|
|
||||||
|
xml_info['disk'] = xml_info['basepath'] + "/disk"
|
||||||
|
|
||||||
|
xml = str(Template(self.libvirt_xml, searchList=[xml_info]))
|
||||||
|
logging.debug(_('instance %s: finished toXML method'),
|
||||||
|
instance['name'])
|
||||||
|
|
||||||
|
return xml
|
||||||
|
|
||||||
def get_info(self, instance_name):
|
def get_info(self, instance_name):
|
||||||
try:
|
try:
|
||||||
virt_dom = self._conn.lookupByName(instance_name)
|
virt_dom = self._conn.lookupByName(instance_name)
|
||||||
except:
|
except:
|
||||||
raise exception.NotFound("Instance %s not found" % instance_name)
|
raise exception.NotFound(_("Instance %s not found")
|
||||||
|
% instance_name)
|
||||||
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
|
(state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info()
|
||||||
return {'state': state,
|
return {'state': state,
|
||||||
'max_mem': max_mem,
|
'max_mem': max_mem,
|
||||||
|
@ -25,6 +25,7 @@ class NetworkHelper():
|
|||||||
"""
|
"""
|
||||||
The class that wraps the helper methods together.
|
The class that wraps the helper methods together.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ class VMHelper():
|
|||||||
"""
|
"""
|
||||||
The class that wraps the helper methods together.
|
The class that wraps the helper methods together.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -228,11 +229,7 @@ class VMHelper():
|
|||||||
try:
|
try:
|
||||||
host = session.get_xenapi_host()
|
host = session.get_xenapi_host()
|
||||||
host_ip = session.get_xenapi().host.get_record(host)["address"]
|
host_ip = session.get_xenapi().host.get_record(host)["address"]
|
||||||
metrics = session.get_xenapi().VM_guest_metrics.get_record(
|
diags = {}
|
||||||
record["guest_metrics"])
|
|
||||||
diags = {
|
|
||||||
"Kernel": metrics["os_version"]["uname"],
|
|
||||||
"Distro": metrics["os_version"]["name"]}
|
|
||||||
xml = get_rrd(host_ip, record["uuid"])
|
xml = get_rrd(host_ip, record["uuid"])
|
||||||
if xml:
|
if xml:
|
||||||
rrd = minidom.parseString(xml)
|
rrd = minidom.parseString(xml)
|
||||||
|
@ -34,6 +34,7 @@ class VMOps(object):
|
|||||||
"""
|
"""
|
||||||
Management class for VM-related tasks
|
Management class for VM-related tasks
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
global XenAPI
|
global XenAPI
|
||||||
if XenAPI is None:
|
if XenAPI is None:
|
||||||
@ -44,8 +45,12 @@ class VMOps(object):
|
|||||||
|
|
||||||
def list_instances(self):
|
def list_instances(self):
|
||||||
"""List VM instances"""
|
"""List VM instances"""
|
||||||
return [self._session.get_xenapi().VM.get_name_label(vm) \
|
vms = []
|
||||||
for vm in self._session.get_xenapi().VM.get_all()]
|
for vm in self._session.get_xenapi().VM.get_all():
|
||||||
|
rec = self._session.get_xenapi().VM.get_record(vm)
|
||||||
|
if not rec["is_a_template"] and not rec["is_control_domain"]:
|
||||||
|
vms.append(rec["name_label"])
|
||||||
|
return vms
|
||||||
|
|
||||||
def spawn(self, instance):
|
def spawn(self, instance):
|
||||||
"""Create VM instance"""
|
"""Create VM instance"""
|
||||||
@ -86,7 +91,7 @@ class VMOps(object):
|
|||||||
if vm is None:
|
if vm is None:
|
||||||
raise Exception('instance not present %s' % instance_name)
|
raise Exception('instance not present %s' % instance_name)
|
||||||
task = self._session.call_xenapi('Async.VM.clean_reboot', vm)
|
task = self._session.call_xenapi('Async.VM.clean_reboot', vm)
|
||||||
self._session.wait_for_task(task)
|
self._session.wait_for_task(instance.id, task)
|
||||||
|
|
||||||
def destroy(self, instance):
|
def destroy(self, instance):
|
||||||
"""Destroy VM instance"""
|
"""Destroy VM instance"""
|
||||||
@ -100,7 +105,7 @@ class VMOps(object):
|
|||||||
try:
|
try:
|
||||||
task = self._session.call_xenapi('Async.VM.hard_shutdown',
|
task = self._session.call_xenapi('Async.VM.hard_shutdown',
|
||||||
vm)
|
vm)
|
||||||
self._session.wait_for_task(task)
|
self._session.wait_for_task(instance.id, task)
|
||||||
except XenAPI.Failure, exc:
|
except XenAPI.Failure, exc:
|
||||||
logging.warn(exc)
|
logging.warn(exc)
|
||||||
# Disk clean-up
|
# Disk clean-up
|
||||||
@ -108,15 +113,41 @@ class VMOps(object):
|
|||||||
for vdi in vdis:
|
for vdi in vdis:
|
||||||
try:
|
try:
|
||||||
task = self._session.call_xenapi('Async.VDI.destroy', vdi)
|
task = self._session.call_xenapi('Async.VDI.destroy', vdi)
|
||||||
self._session.wait_for_task(task)
|
self._session.wait_for_task(instance.id, task)
|
||||||
except XenAPI.Failure, exc:
|
except XenAPI.Failure, exc:
|
||||||
logging.warn(exc)
|
logging.warn(exc)
|
||||||
try:
|
try:
|
||||||
task = self._session.call_xenapi('Async.VM.destroy', vm)
|
task = self._session.call_xenapi('Async.VM.destroy', vm)
|
||||||
self._session.wait_for_task(task)
|
self._session.wait_for_task(instance.id, task)
|
||||||
except XenAPI.Failure, exc:
|
except XenAPI.Failure, exc:
|
||||||
logging.warn(exc)
|
logging.warn(exc)
|
||||||
|
|
||||||
|
def _wait_with_callback(self, instance_id, task, callback):
|
||||||
|
ret = None
|
||||||
|
try:
|
||||||
|
ret = self._session.wait_for_task(instance_id, task)
|
||||||
|
except XenAPI.Failure, exc:
|
||||||
|
logging.warn(exc)
|
||||||
|
callback(ret)
|
||||||
|
|
||||||
|
def pause(self, instance, callback):
|
||||||
|
"""Pause VM instance"""
|
||||||
|
instance_name = instance.name
|
||||||
|
vm = VMHelper.lookup(self._session, instance_name)
|
||||||
|
if vm is None:
|
||||||
|
raise Exception('instance not present %s' % instance_name)
|
||||||
|
task = self._session.call_xenapi('Async.VM.pause', vm)
|
||||||
|
self._wait_with_callback(instance.id, task, callback)
|
||||||
|
|
||||||
|
def unpause(self, instance, callback):
|
||||||
|
"""Unpause VM instance"""
|
||||||
|
instance_name = instance.name
|
||||||
|
vm = VMHelper.lookup(self._session, instance_name)
|
||||||
|
if vm is None:
|
||||||
|
raise Exception('instance not present %s' % instance_name)
|
||||||
|
task = self._session.call_xenapi('Async.VM.unpause', vm)
|
||||||
|
self._wait_with_callback(instance.id, task, callback)
|
||||||
|
|
||||||
def get_info(self, instance_id):
|
def get_info(self, instance_id):
|
||||||
"""Return data about VM instance"""
|
"""Return data about VM instance"""
|
||||||
vm = VMHelper.lookup_blocking(self._session, instance_id)
|
vm = VMHelper.lookup_blocking(self._session, instance_id)
|
||||||
|
@ -20,6 +20,7 @@ Management class for Storage-related functions (attach, detach, etc).
|
|||||||
|
|
||||||
|
|
||||||
class VolumeOps(object):
|
class VolumeOps(object):
|
||||||
|
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
self._session = session
|
self._session = session
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ import xmlrpclib
|
|||||||
from eventlet import event
|
from eventlet import event
|
||||||
from eventlet import tpool
|
from eventlet import tpool
|
||||||
|
|
||||||
|
from nova import context
|
||||||
|
from nova import db
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova.virt.xenapi.vmops import VMOps
|
from nova.virt.xenapi.vmops import VMOps
|
||||||
@ -93,15 +95,16 @@ def get_connection(_):
|
|||||||
username = FLAGS.xenapi_connection_username
|
username = FLAGS.xenapi_connection_username
|
||||||
password = FLAGS.xenapi_connection_password
|
password = FLAGS.xenapi_connection_password
|
||||||
if not url or password is None:
|
if not url or password is None:
|
||||||
raise Exception('Must specify xenapi_connection_url, '
|
raise Exception(_('Must specify xenapi_connection_url, '
|
||||||
'xenapi_connection_username (optionally), and '
|
'xenapi_connection_username (optionally), and '
|
||||||
'xenapi_connection_password to use '
|
'xenapi_connection_password to use '
|
||||||
'connection_type=xenapi')
|
'connection_type=xenapi'))
|
||||||
return XenAPIConnection(url, username, password)
|
return XenAPIConnection(url, username, password)
|
||||||
|
|
||||||
|
|
||||||
class XenAPIConnection(object):
|
class XenAPIConnection(object):
|
||||||
"""A connection to XenServer or Xen Cloud Platform"""
|
"""A connection to XenServer or Xen Cloud Platform"""
|
||||||
|
|
||||||
def __init__(self, url, user, pw):
|
def __init__(self, url, user, pw):
|
||||||
session = XenAPISession(url, user, pw)
|
session = XenAPISession(url, user, pw)
|
||||||
self._vmops = VMOps(session)
|
self._vmops = VMOps(session)
|
||||||
@ -123,6 +126,14 @@ class XenAPIConnection(object):
|
|||||||
"""Destroy VM instance"""
|
"""Destroy VM instance"""
|
||||||
self._vmops.destroy(instance)
|
self._vmops.destroy(instance)
|
||||||
|
|
||||||
|
def pause(self, instance, callback):
|
||||||
|
"""Pause VM instance"""
|
||||||
|
self._vmops.pause(instance, callback)
|
||||||
|
|
||||||
|
def unpause(self, instance, callback):
|
||||||
|
"""Unpause paused VM instance"""
|
||||||
|
self._vmops.unpause(instance, callback)
|
||||||
|
|
||||||
def get_info(self, instance_id):
|
def get_info(self, instance_id):
|
||||||
"""Return data about VM instance"""
|
"""Return data about VM instance"""
|
||||||
return self._vmops.get_info(instance_id)
|
return self._vmops.get_info(instance_id)
|
||||||
@ -148,6 +159,7 @@ class XenAPIConnection(object):
|
|||||||
|
|
||||||
class XenAPISession(object):
|
class XenAPISession(object):
|
||||||
"""The session to invoke XenAPI SDK calls"""
|
"""The session to invoke XenAPI SDK calls"""
|
||||||
|
|
||||||
def __init__(self, url, user, pw):
|
def __init__(self, url, user, pw):
|
||||||
self._session = XenAPI.Session(url)
|
self._session = XenAPI.Session(url)
|
||||||
self._session.login_with_password(user, pw)
|
self._session.login_with_password(user, pw)
|
||||||
@ -173,35 +185,46 @@ class XenAPISession(object):
|
|||||||
self._session.xenapi.Async.host.call_plugin,
|
self._session.xenapi.Async.host.call_plugin,
|
||||||
self.get_xenapi_host(), plugin, fn, args)
|
self.get_xenapi_host(), plugin, fn, args)
|
||||||
|
|
||||||
def wait_for_task(self, task):
|
def wait_for_task(self, instance_id, task):
|
||||||
"""Return a Deferred that will give the result of the given task.
|
"""Return a Deferred that will give the result of the given task.
|
||||||
The task is polled until it completes."""
|
The task is polled until it completes."""
|
||||||
|
|
||||||
done = event.Event()
|
done = event.Event()
|
||||||
loop = utils.LoopingCall(self._poll_task, task, done)
|
loop = utils.LoopingCall(self._poll_task, instance_id, task, done)
|
||||||
loop.start(FLAGS.xenapi_task_poll_interval, now=True)
|
loop.start(FLAGS.xenapi_task_poll_interval, now=True)
|
||||||
rv = done.wait()
|
rv = done.wait()
|
||||||
loop.stop()
|
loop.stop()
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
def _poll_task(self, task, done):
|
def _poll_task(self, instance_id, task, done):
|
||||||
"""Poll the given XenAPI task, and fire the given Deferred if we
|
"""Poll the given XenAPI task, and fire the given Deferred if we
|
||||||
get a result."""
|
get a result."""
|
||||||
try:
|
try:
|
||||||
#logging.debug('Polling task %s...', task)
|
name = self._session.xenapi.task.get_name_label(task)
|
||||||
status = self._session.xenapi.task.get_status(task)
|
status = self._session.xenapi.task.get_status(task)
|
||||||
if status == 'pending':
|
action = dict(
|
||||||
|
instance_id=int(instance_id),
|
||||||
|
action=name,
|
||||||
|
error=None)
|
||||||
|
if status == "pending":
|
||||||
return
|
return
|
||||||
elif status == 'success':
|
elif status == "success":
|
||||||
result = self._session.xenapi.task.get_result(task)
|
result = self._session.xenapi.task.get_result(task)
|
||||||
logging.info('Task %s status: success. %s', task, result)
|
logging.info(_("Task [%s] %s status: success %s") % (
|
||||||
|
name,
|
||||||
|
task,
|
||||||
|
result))
|
||||||
done.send(_parse_xmlrpc_value(result))
|
done.send(_parse_xmlrpc_value(result))
|
||||||
else:
|
else:
|
||||||
error_info = self._session.xenapi.task.get_error_info(task)
|
error_info = self._session.xenapi.task.get_error_info(task)
|
||||||
logging.warn('Task %s status: %s. %s', task, status,
|
action["error"] = str(error_info)
|
||||||
error_info)
|
logging.warn(_("Task [%s] %s status: %s %s") % (
|
||||||
|
name,
|
||||||
|
task,
|
||||||
|
status,
|
||||||
|
error_info))
|
||||||
done.send_exception(XenAPI.Failure(error_info))
|
done.send_exception(XenAPI.Failure(error_info))
|
||||||
#logging.debug('Polling task %s done.', task)
|
db.instance_action_create(context.get_admin_context(), action)
|
||||||
except XenAPI.Failure, exc:
|
except XenAPI.Failure, exc:
|
||||||
logging.warn(exc)
|
logging.warn(exc)
|
||||||
done.send_exception(*sys.exc_info())
|
done.send_exception(*sys.exc_info())
|
||||||
@ -212,7 +235,7 @@ def _unwrap_plugin_exceptions(func, *args, **kwargs):
|
|||||||
try:
|
try:
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
except XenAPI.Failure, exc:
|
except XenAPI.Failure, exc:
|
||||||
logging.debug("Got exception: %s", exc)
|
logging.debug(_("Got exception: %s"), exc)
|
||||||
if (len(exc.details) == 4 and
|
if (len(exc.details) == 4 and
|
||||||
exc.details[0] == 'XENAPI_PLUGIN_EXCEPTION' and
|
exc.details[0] == 'XENAPI_PLUGIN_EXCEPTION' and
|
||||||
exc.details[2] == 'Failure'):
|
exc.details[2] == 'Failure'):
|
||||||
@ -225,7 +248,7 @@ def _unwrap_plugin_exceptions(func, *args, **kwargs):
|
|||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
except xmlrpclib.ProtocolError, exc:
|
except xmlrpclib.ProtocolError, exc:
|
||||||
logging.debug("Got exception: %s", exc)
|
logging.debug(_("Got exception: %s"), exc)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,14 +73,14 @@ class VolumeDriver(object):
|
|||||||
tries = tries + 1
|
tries = tries + 1
|
||||||
if tries >= FLAGS.num_shell_tries:
|
if tries >= FLAGS.num_shell_tries:
|
||||||
raise
|
raise
|
||||||
logging.exception("Recovering from a failed execute."
|
logging.exception(_("Recovering from a failed execute."
|
||||||
"Try number %s", tries)
|
"Try number %s"), tries)
|
||||||
time.sleep(tries ** 2)
|
time.sleep(tries ** 2)
|
||||||
|
|
||||||
def check_for_setup_error(self):
|
def check_for_setup_error(self):
|
||||||
"""Returns an error if prerequisites aren't met"""
|
"""Returns an error if prerequisites aren't met"""
|
||||||
if not os.path.isdir("/dev/%s" % FLAGS.volume_group):
|
if not os.path.isdir("/dev/%s" % FLAGS.volume_group):
|
||||||
raise exception.Error("volume group %s doesn't exist"
|
raise exception.Error(_("volume group %s doesn't exist")
|
||||||
% FLAGS.volume_group)
|
% FLAGS.volume_group)
|
||||||
|
|
||||||
def create_volume(self, volume):
|
def create_volume(self, volume):
|
||||||
@ -205,7 +205,7 @@ class FakeAOEDriver(AOEDriver):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def fake_execute(cmd, *_args, **_kwargs):
|
def fake_execute(cmd, *_args, **_kwargs):
|
||||||
"""Execute that simply logs the command."""
|
"""Execute that simply logs the command."""
|
||||||
logging.debug("FAKE AOE: %s", cmd)
|
logging.debug(_("FAKE AOE: %s"), cmd)
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
|
|
||||||
@ -310,5 +310,5 @@ class FakeISCSIDriver(ISCSIDriver):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def fake_execute(cmd, *_args, **_kwargs):
|
def fake_execute(cmd, *_args, **_kwargs):
|
||||||
"""Execute that simply logs the command."""
|
"""Execute that simply logs the command."""
|
||||||
logging.debug("FAKE ISCSI: %s", cmd)
|
logging.debug(_("FAKE ISCSI: %s"), cmd)
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
@ -81,7 +81,7 @@ class VolumeManager(manager.Manager):
|
|||||||
self.driver.check_for_setup_error()
|
self.driver.check_for_setup_error()
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
volumes = self.db.volume_get_all_by_host(ctxt, self.host)
|
volumes = self.db.volume_get_all_by_host(ctxt, self.host)
|
||||||
logging.debug("Re-exporting %s volumes", len(volumes))
|
logging.debug(_("Re-exporting %s volumes"), len(volumes))
|
||||||
for volume in volumes:
|
for volume in volumes:
|
||||||
self.driver.ensure_export(ctxt, volume)
|
self.driver.ensure_export(ctxt, volume)
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class VolumeManager(manager.Manager):
|
|||||||
"""Creates and exports the volume."""
|
"""Creates and exports the volume."""
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
volume_ref = self.db.volume_get(context, volume_id)
|
volume_ref = self.db.volume_get(context, volume_id)
|
||||||
logging.info("volume %s: creating", volume_ref['name'])
|
logging.info(_("volume %s: creating"), volume_ref['name'])
|
||||||
|
|
||||||
self.db.volume_update(context,
|
self.db.volume_update(context,
|
||||||
volume_id,
|
volume_id,
|
||||||
@ -98,18 +98,18 @@ class VolumeManager(manager.Manager):
|
|||||||
# before passing it to the driver.
|
# before passing it to the driver.
|
||||||
volume_ref['host'] = self.host
|
volume_ref['host'] = self.host
|
||||||
|
|
||||||
logging.debug("volume %s: creating lv of size %sG",
|
logging.debug(_("volume %s: creating lv of size %sG"),
|
||||||
volume_ref['name'], volume_ref['size'])
|
volume_ref['name'], volume_ref['size'])
|
||||||
self.driver.create_volume(volume_ref)
|
self.driver.create_volume(volume_ref)
|
||||||
|
|
||||||
logging.debug("volume %s: creating export", volume_ref['name'])
|
logging.debug(_("volume %s: creating export"), volume_ref['name'])
|
||||||
self.driver.create_export(context, volume_ref)
|
self.driver.create_export(context, volume_ref)
|
||||||
|
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
self.db.volume_update(context,
|
self.db.volume_update(context,
|
||||||
volume_ref['id'], {'status': 'available',
|
volume_ref['id'], {'status': 'available',
|
||||||
'launched_at': now})
|
'launched_at': now})
|
||||||
logging.debug("volume %s: created successfully", volume_ref['name'])
|
logging.debug(_("volume %s: created successfully"), volume_ref['name'])
|
||||||
return volume_id
|
return volume_id
|
||||||
|
|
||||||
def delete_volume(self, context, volume_id):
|
def delete_volume(self, context, volume_id):
|
||||||
@ -117,15 +117,15 @@ class VolumeManager(manager.Manager):
|
|||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
volume_ref = self.db.volume_get(context, volume_id)
|
volume_ref = self.db.volume_get(context, volume_id)
|
||||||
if volume_ref['attach_status'] == "attached":
|
if volume_ref['attach_status'] == "attached":
|
||||||
raise exception.Error("Volume is still attached")
|
raise exception.Error(_("Volume is still attached"))
|
||||||
if volume_ref['host'] != self.host:
|
if volume_ref['host'] != self.host:
|
||||||
raise exception.Error("Volume is not local to this node")
|
raise exception.Error(_("Volume is not local to this node"))
|
||||||
logging.debug("volume %s: removing export", volume_ref['name'])
|
logging.debug(_("volume %s: removing export"), volume_ref['name'])
|
||||||
self.driver.remove_export(context, volume_ref)
|
self.driver.remove_export(context, volume_ref)
|
||||||
logging.debug("volume %s: deleting", volume_ref['name'])
|
logging.debug(_("volume %s: deleting"), volume_ref['name'])
|
||||||
self.driver.delete_volume(volume_ref)
|
self.driver.delete_volume(volume_ref)
|
||||||
self.db.volume_destroy(context, volume_id)
|
self.db.volume_destroy(context, volume_id)
|
||||||
logging.debug("volume %s: deleted successfully", volume_ref['name'])
|
logging.debug(_("volume %s: deleted successfully"), volume_ref['name'])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def setup_compute_volume(self, context, volume_id):
|
def setup_compute_volume(self, context, volume_id):
|
||||||
|
@ -2,6 +2,7 @@ SQLAlchemy==0.6.3
|
|||||||
pep8==0.5.0
|
pep8==0.5.0
|
||||||
pylint==0.19
|
pylint==0.19
|
||||||
IPy==0.70
|
IPy==0.70
|
||||||
|
Cheetah==2.4.2.1
|
||||||
M2Crypto==0.20.2
|
M2Crypto==0.20.2
|
||||||
amqplib==0.6.1
|
amqplib==0.6.1
|
||||||
anyjson==0.2.4
|
anyjson==0.2.4
|
||||||
|
Loading…
Reference in New Issue
Block a user