merge with trunk, resolve conflicts

This commit is contained in:
Lvov Maxim 2011-07-26 09:50:05 +04:00
commit 01409c0553
45 changed files with 15902 additions and 510 deletions

View File

@ -15,4 +15,5 @@ run_tests.log
tests.sqlite
nova/tests/instance-*
tags
.coverage
covhtml

View File

@ -8,6 +8,7 @@ Anne Gentle <anne@openstack.org>
Anthony Young <sleepsonthefloor@gmail.com>
Antony Messerli <ant@openstack.org>
Armando Migliaccio <Armando.Migliaccio@eu.citrix.com>
Arvind Somya <asomya@cisco.com>
Bilal Akhtar <bilalakhtar@ubuntu.com>
Brian Lamar <brian.lamar@rackspace.com>
Brian Schott <bschott@isi.edu>

View File

@ -530,7 +530,52 @@ class CloudController(object):
g['ipPermissions'] += [r]
return g
def _revoke_rule_args_to_dict(self, context, to_port=None, from_port=None,
def _rule_args_to_dict(self, context, kwargs):
rules = []
if not 'groups' in kwargs and not 'ip_ranges' in kwargs:
rule = self._rule_dict_last_step(context, **kwargs)
if rule:
rules.append(rule)
return rules
if 'ip_ranges' in kwargs:
rules = self._cidr_args_split(kwargs)
finalset = []
for rule in rules:
if 'groups' in rule:
groups_values = self._groups_args_split(rule)
for groups_value in groups_values:
finalset.append(groups_value)
else:
if rule:
finalset.append(rule)
return finalset
def _cidr_args_split(self, kwargs):
cidr_args_split = []
cidrs = kwargs['ip_ranges']
for key, cidr in cidrs.iteritems():
mykwargs = kwargs.copy()
del mykwargs['ip_ranges']
mykwargs['cidr_ip'] = cidr['cidr_ip']
cidr_args_split.append(mykwargs)
return cidr_args_split
def _groups_args_split(self, kwargs):
groups_args_split = []
groups = kwargs['groups']
for key, group in groups.iteritems():
mykwargs = kwargs.copy()
del mykwargs['groups']
if 'group_name' in group:
mykwargs['source_security_group_name'] = group['group_name']
if 'user_id' in group:
mykwargs['source_security_group_owner_id'] = group['user_id']
if 'group_id' in group:
mykwargs['source_security_group_id'] = group['group_id']
groups_args_split.append(mykwargs)
return groups_args_split
def _rule_dict_last_step(self, context, to_port=None, from_port=None,
ip_protocol=None, cidr_ip=None, user_id=None,
source_security_group_name=None,
source_security_group_owner_id=None):
@ -615,7 +660,7 @@ class CloudController(object):
msg = "Revoke security group ingress %s"
LOG.audit(_(msg), security_group['name'], context=context)
criteria = self._revoke_rule_args_to_dict(context, **kwargs)
criteria = self._rule_args_to_dict(context, kwargs)[0]
if criteria is None:
raise exception.ApiError(_("Not enough parameters to build a "
"valid rule."))
@ -656,21 +701,34 @@ class CloudController(object):
msg = "Authorize security group ingress %s"
LOG.audit(_(msg), security_group['name'], context=context)
values = self._revoke_rule_args_to_dict(context, **kwargs)
if values is None:
raise exception.ApiError(_("Not enough parameters to build a "
"valid rule."))
values['parent_group_id'] = security_group.id
prevalues = []
try:
prevalues = kwargs['ip_permissions']
except KeyError:
prevalues.append(kwargs)
postvalues = []
for values in prevalues:
rulesvalues = self._rule_args_to_dict(context, values)
if not rulesvalues:
err = "%s Not enough parameters to build a valid rule"
raise exception.ApiError(_(err % rulesvalues))
for values_for_rule in rulesvalues:
values_for_rule['parent_group_id'] = security_group.id
if self._security_group_rule_exists(security_group,
values_for_rule):
err = '%s - This rule already exists in group'
raise exception.ApiError(_(err) % values_for_rule)
postvalues.append(values_for_rule)
if self._security_group_rule_exists(security_group, values):
raise exception.ApiError(_('This rule already exists in group %s')
% group_name)
security_group_rule = db.security_group_rule_create(context, values)
for values_for_rule in postvalues:
security_group_rule = db.security_group_rule_create(context,
values_for_rule)
self.compute_api.trigger_security_group_rules_refresh(context,
security_group_id=security_group['id'])
security_group_id=security_group['id'])
group = db.security_group_get_by_name(context, context.project_id,
security_group['name'])
return True
def _get_source_project_id(self, context, source_security_group_owner_id):
@ -1147,7 +1205,7 @@ class CloudController(object):
def rescue_instance(self, context, instance_id, **kwargs):
"""This is an extension to the normal ec2_api"""
self._do_instance(self.compute_api.rescue, contect, instnace_id)
self._do_instance(self.compute_api.rescue, context, instance_id)
return True
def unrescue_instance(self, context, instance_id, **kwargs):

View File

@ -164,11 +164,17 @@ class APIRouterV11(APIRouter):
def _setup_routes(self, mapper):
super(APIRouterV11, self)._setup_routes(mapper, '1.1')
mapper.resource("image_meta", "meta",
controller=image_metadata.create_resource(),
image_metadata_controller = image_metadata.create_resource()
mapper.resource("image_meta", "metadata",
controller=image_metadata_controller,
parent_resource=dict(member_name='image',
collection_name='images'))
mapper.connect("metadata", "/images/{image_id}/metadata",
controller=image_metadata_controller,
action='update_all',
conditions={"method": ['PUT']})
mapper.resource("server_meta", "meta",
controller=server_metadata.create_resource(),
parent_resource=dict(member_name='server',

View File

@ -167,3 +167,28 @@ def remove_version_from_href(href):
msg = _('href does not contain version')
raise ValueError(msg)
return new_href
def get_version_from_href(href):
"""Returns the api version in the href.
Returns the api version in the href.
If no version is found, 1.0 is returned
Given: 'http://www.nova.com/123'
Returns: '1.0'
Given: 'http://www.nova.com/v1.1'
Returns: '1.1'
"""
try:
#finds the first instance that matches /v#.#/
version = re.findall(r'[/][v][0-9]+\.[0-9]+[/]', href)
#if no version was found, try finding /v#.# at the end of the string
if not version:
version = re.findall(r'[/][v][0-9]+\.[0-9]+$', href)
version = re.findall(r'[0-9]+\.[0-9]', version[0])[0]
except IndexError:
version = '1.0'
return version

View File

@ -71,9 +71,12 @@ class CreateInstanceHelper(object):
if not body:
raise exc.HTTPUnprocessableEntity()
context = req.environ['nova.context']
if not 'server' in body:
raise exc.HTTPUnprocessableEntity()
password = self.controller._get_server_admin_password(body['server'])
server_dict = body['server']
context = req.environ['nova.context']
password = self.controller._get_server_admin_password(server_dict)
key_name = None
key_data = None
@ -95,7 +98,7 @@ class CreateInstanceHelper(object):
locals())
raise exc.HTTPBadRequest(explanation=msg)
personality = body['server'].get('personality')
personality = server_dict.get('personality')
injected_files = []
if personality:
@ -107,18 +110,18 @@ class CreateInstanceHelper(object):
msg = _("Invalid flavorRef provided.")
raise exc.HTTPBadRequest(explanation=msg)
if not 'name' in body['server']:
if not 'name' in server_dict:
msg = _("Server name is not defined")
raise exc.HTTPBadRequest(explanation=msg)
zone_blob = body['server'].get('blob')
name = body['server']['name']
zone_blob = server_dict.get('blob')
name = server_dict['name']
self._validate_server_name(name)
name = name.strip()
reservation_id = body['server'].get('reservation_id')
min_count = body['server'].get('min_count')
max_count = body['server'].get('max_count')
reservation_id = server_dict.get('reservation_id')
min_count = server_dict.get('min_count')
max_count = server_dict.get('max_count')
# min_count and max_count are optional. If they exist, they come
# in as strings. We want to default 'min_count' to 1, and default
# 'max_count' to be 'min_count'.
@ -145,7 +148,7 @@ class CreateInstanceHelper(object):
display_description=name,
key_name=key_name,
key_data=key_data,
metadata=body['server'].get('metadata', {}),
metadata=server_dict.get('metadata', {}),
injected_files=injected_files,
admin_password=password,
zone_blob=zone_blob,
@ -282,7 +285,7 @@ class CreateInstanceHelper(object):
return password
class ServerXMLDeserializer(wsgi.XMLDeserializer):
class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
"""
Deserializer to handle xml-formatted server create requests.
@ -299,11 +302,12 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer):
def _extract_server(self, node):
"""Marshal the server attribute of a parsed request"""
server = {}
server_node = self._find_first_child_named(node, 'server')
server_node = self.find_first_child_named(node, 'server')
for attr in ["name", "imageId", "flavorId", "imageRef", "flavorRef"]:
if server_node.getAttribute(attr):
server[attr] = server_node.getAttribute(attr)
metadata = self._extract_metadata(server_node)
metadata_node = self.find_first_child_named(server_node, "metadata")
metadata = self.extract_metadata(metadata_node)
if metadata is not None:
server["metadata"] = metadata
personality = self._extract_personality(server_node)
@ -311,49 +315,17 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer):
server["personality"] = personality
return server
def _extract_metadata(self, server_node):
"""Marshal the metadata attribute of a parsed request"""
metadata_node = self._find_first_child_named(server_node, "metadata")
if metadata_node is None:
return None
metadata = {}
for meta_node in self._find_children_named(metadata_node, "meta"):
key = meta_node.getAttribute("key")
metadata[key] = self._extract_text(meta_node)
return metadata
def _extract_personality(self, server_node):
"""Marshal the personality attribute of a parsed request"""
personality_node = \
self._find_first_child_named(server_node, "personality")
self.find_first_child_named(server_node, "personality")
if personality_node is None:
return None
personality = []
for file_node in self._find_children_named(personality_node, "file"):
for file_node in self.find_children_named(personality_node, "file"):
item = {}
if file_node.hasAttribute("path"):
item["path"] = file_node.getAttribute("path")
item["contents"] = self._extract_text(file_node)
item["contents"] = self.extract_text(file_node)
personality.append(item)
return personality
def _find_first_child_named(self, parent, name):
"""Search a nodes children for the first child with a given name"""
for node in parent.childNodes:
if node.nodeName == name:
return node
return None
def _find_children_named(self, parent, name):
"""Return all of a nodes children who have the given name"""
for node in parent.childNodes:
if node.nodeName == name:
yield node
def _extract_text(self, node):
"""Get the text field contained by the given node"""
if len(node.childNodes) == 1:
child = node.childNodes[0]
if child.nodeType == child.TEXT_NODE:
return child.nodeValue
return ""

View File

@ -23,6 +23,7 @@ import sys
import routes
import webob.dec
import webob.exc
from xml.etree import ElementTree
from nova import exception
from nova import flags
@ -194,7 +195,7 @@ class ExtensionsResource(wsgi.Resource):
def show(self, req, id):
# NOTE(dprince): the extensions alias is used as the 'id' for show
ext = self.extension_manager.extensions[id]
return self._translate(ext)
return dict(extension=self._translate(ext))
def delete(self, req, id):
raise faults.Fault(webob.exc.HTTPNotFound())
@ -258,15 +259,18 @@ class ExtensionMiddleware(base_wsgi.Middleware):
mapper = routes.Mapper()
serializer = wsgi.ResponseSerializer(
{'application/xml': ExtensionsXMLSerializer()})
# extended resources
for resource in ext_mgr.get_resources():
LOG.debug(_('Extended resource: %s'),
resource.collection)
mapper.resource(resource.collection, resource.collection,
controller=wsgi.Resource(resource.controller),
collection=resource.collection_actions,
member=resource.member_actions,
parent_resource=resource.parent)
controller=wsgi.Resource(
resource.controller, serializer=serializer),
collection=resource.collection_actions,
member=resource.member_actions,
parent_resource=resource.parent)
# extended actions
action_resources = self._action_ext_resources(application, ext_mgr,
@ -462,3 +466,40 @@ class ResourceExtension(object):
self.parent = parent
self.collection_actions = collection_actions
self.member_actions = member_actions
class ExtensionsXMLSerializer(wsgi.XMLDictSerializer):
def show(self, ext_dict):
ext = self._create_ext_elem(ext_dict['extension'])
return self._to_xml(ext)
def index(self, exts_dict):
exts = ElementTree.Element('extensions')
for ext_dict in exts_dict['extensions']:
exts.append(self._create_ext_elem(ext_dict))
return self._to_xml(exts)
def _create_ext_elem(self, ext_dict):
"""Create an extension xml element from a dict."""
ext_elem = ElementTree.Element('extension')
ext_elem.set('name', ext_dict['name'])
ext_elem.set('namespace', ext_dict['namespace'])
ext_elem.set('alias', ext_dict['alias'])
ext_elem.set('updated', ext_dict['updated'])
desc = ElementTree.Element('description')
desc.text = ext_dict['description']
ext_elem.append(desc)
for link in ext_dict.get('links', []):
elem = ElementTree.Element('atom:link')
elem.set('rel', link['rel'])
elem.set('href', link['href'])
elem.set('type', link['type'])
ext_elem.append(elem)
return ext_elem
def _to_xml(self, root):
"""Convert the xml tree object to an xml string."""
root.set('xmlns', wsgi.XMLNS_V11)
root.set('xmlns:atom', wsgi.XMLNS_ATOM)
return ElementTree.tostring(root, encoding='UTF-8')

View File

@ -19,6 +19,7 @@
import webob.dec
import webob.exc
from nova.api.openstack import common
from nova.api.openstack import wsgi
@ -61,9 +62,13 @@ class Fault(webob.exc.HTTPException):
content_type = req.best_match_content_type()
xml_serializer = {
'1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
'1.1': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V11),
}[common.get_version_from_href(req.url)]
serializer = {
'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
xmlns=wsgi.XMLNS_V10),
'application/xml': xml_serializer,
'application/json': wsgi.JSONDictSerializer(),
}[content_type]
@ -100,9 +105,13 @@ class OverLimitFault(webob.exc.HTTPException):
content_type = request.best_match_content_type()
metadata = {"attributes": {"overLimitFault": "code"}}
xml_serializer = {
'1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
'1.1': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V11),
}[common.get_version_from_href(request.url)]
serializer = {
'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
xmlns=wsgi.XMLNS_V10),
'application/xml': xml_serializer,
'application/json': wsgi.JSONDictSerializer(),
}[content_type]

View File

@ -96,8 +96,16 @@ class Controller(object):
self._check_quota_limit(context, metadata)
img['properties'] = metadata
self.image_service.update(context, image_id, img, None)
return dict(meta=meta)
return req.body
def update_all(self, req, image_id, body):
context = req.environ['nova.context']
img = self.image_service.show(context, image_id)
metadata = body.get('metadata', {})
self._check_quota_limit(context, metadata)
img['properties'] = metadata
self.image_service.update(context, image_id, img, None)
return dict(metadata=metadata)
def delete(self, req, image_id, id):
context = req.environ['nova.context']
@ -110,6 +118,32 @@ class Controller(object):
self.image_service.update(context, image_id, img, None)
class ImageMetadataXMLDeserializer(wsgi.MetadataXMLDeserializer):
def _extract_metadata_container(self, datastring):
dom = minidom.parseString(datastring)
metadata_node = self.find_first_child_named(dom, "metadata")
metadata = self.extract_metadata(metadata_node)
return {'body': {'metadata': metadata}}
def create(self, datastring):
return self._extract_metadata_container(datastring)
def update_all(self, datastring):
return self._extract_metadata_container(datastring)
def update(self, datastring):
dom = minidom.parseString(datastring)
metadata_item = self.extract_metadata(dom)
return {'body': {'meta': metadata_item}}
class HeadersSerializer(wsgi.ResponseHeadersSerializer):
def delete(self, response, data):
response.status_int = 204
class ImageMetadataXMLSerializer(wsgi.XMLDictSerializer):
def __init__(self, xmlns=wsgi.XMLNS_V11):
super(ImageMetadataXMLSerializer, self).__init__(xmlns=xmlns)
@ -143,6 +177,9 @@ class ImageMetadataXMLSerializer(wsgi.XMLDictSerializer):
def create(self, metadata_dict):
return self._meta_list_to_xml_string(metadata_dict)
def update_all(self, metadata_dict):
return self._meta_list_to_xml_string(metadata_dict)
def _meta_item_to_xml_string(self, meta_item_dict):
xml_doc = minidom.Document()
item_key, item_value = meta_item_dict.items()[0]
@ -157,11 +194,21 @@ class ImageMetadataXMLSerializer(wsgi.XMLDictSerializer):
def update(self, meta_item_dict):
return self._meta_item_to_xml_string(meta_item_dict['meta'])
def default(self, *args, **kwargs):
return ''
def create_resource():
headers_serializer = HeadersSerializer()
body_deserializers = {
'application/xml': ImageMetadataXMLDeserializer(),
}
body_serializers = {
'application/xml': ImageMetadataXMLSerializer(),
}
serializer = wsgi.ResponseSerializer(body_serializers)
serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer)
deserializer = wsgi.RequestDeserializer(body_deserializers)
return wsgi.Resource(Controller(), serializer=serializer)
return wsgi.Resource(Controller(), deserializer, serializer)

View File

@ -16,6 +16,7 @@
# under the License.
import time
from xml.dom import minidom
from webob import exc
@ -100,17 +101,51 @@ class ControllerV11(Controller):
return nova.api.openstack.views.addresses.ViewBuilderV11()
class IPXMLSerializer(wsgi.XMLDictSerializer):
def __init__(self, xmlns=wsgi.XMLNS_V11):
super(IPXMLSerializer, self).__init__(xmlns=xmlns)
def _ip_to_xml(self, xml_doc, ip_dict):
ip_node = xml_doc.createElement('ip')
ip_node.setAttribute('addr', ip_dict['addr'])
ip_node.setAttribute('version', str(ip_dict['version']))
return ip_node
def _network_to_xml(self, xml_doc, network_id, ip_dicts):
network_node = xml_doc.createElement('network')
network_node.setAttribute('id', network_id)
for ip_dict in ip_dicts:
ip_node = self._ip_to_xml(xml_doc, ip_dict)
network_node.appendChild(ip_node)
return network_node
def networks_to_xml(self, xml_doc, networks_container):
addresses_node = xml_doc.createElement('addresses')
for (network_id, ip_dicts) in networks_container.items():
network_node = self._network_to_xml(xml_doc, network_id, ip_dicts)
addresses_node.appendChild(network_node)
return addresses_node
def show(self, network_container):
(network_id, ip_dicts) = network_container.items()[0]
xml_doc = minidom.Document()
node = self._network_to_xml(xml_doc, network_id, ip_dicts)
return self.to_xml_string(node, False)
def index(self, addresses_container):
xml_doc = minidom.Document()
node = self.networks_to_xml(xml_doc, addresses_container['addresses'])
return self.to_xml_string(node, False)
def create_resource(version):
controller = {
'1.0': ControllerV10,
'1.1': ControllerV11,
}[version]()
xmlns = {
'1.0': wsgi.XMLNS_V10,
'1.1': wsgi.XMLNS_V11,
}[version]
metadata = {
'list_collections': {
'public': {'item_name': 'ip', 'item_key': 'addr'},
@ -118,10 +153,11 @@ def create_resource(version):
},
}
body_serializers = {
'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
xmlns=xmlns),
}
serializer = wsgi.ResponseSerializer(body_serializers)
xml_serializer = {
'1.0': wsgi.XMLDictSerializer(metadata=metadata, xmlns=wsgi.XMLNS_V11),
'1.1': IPXMLSerializer(),
}[version]
serializer = wsgi.ResponseSerializer({'application/xml': xml_serializer})
return wsgi.Resource(controller, serializer=serializer)

View File

@ -13,6 +13,7 @@ from nova import wsgi
XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0'
XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
XMLNS_ATOM = 'http://www.w3.org/2005/Atom'
LOG = logging.getLogger('nova.api.openstack.wsgi')
@ -135,10 +136,44 @@ class XMLDeserializer(TextDeserializer):
listnames)
return result
def find_first_child_named(self, parent, name):
"""Search a nodes children for the first child with a given name"""
for node in parent.childNodes:
if node.nodeName == name:
return node
return None
def find_children_named(self, parent, name):
"""Return all of a nodes children who have the given name"""
for node in parent.childNodes:
if node.nodeName == name:
yield node
def extract_text(self, node):
"""Get the text field contained by the given node"""
if len(node.childNodes) == 1:
child = node.childNodes[0]
if child.nodeType == child.TEXT_NODE:
return child.nodeValue
return ""
def default(self, datastring):
return {'body': self._from_xml(datastring)}
class MetadataXMLDeserializer(XMLDeserializer):
def extract_metadata(self, metadata_node):
"""Marshal the metadata attribute of a parsed request"""
if metadata_node is None:
return None
metadata = {}
for meta_node in self.find_children_named(metadata_node, "meta"):
key = meta_node.getAttribute("key")
metadata[key] = self.extract_text(meta_node)
return metadata
class RequestHeadersDeserializer(ActionDispatcher):
"""Default request headers deserializer"""
@ -396,8 +431,9 @@ class ResponseSerializer(object):
def serialize_body(self, response, data, content_type, action):
response.headers['Content-Type'] = content_type
serializer = self.get_body_serializer(content_type)
response.body = serializer.serialize(data, action)
if data is not None:
serializer = self.get_body_serializer(content_type)
response.body = serializer.serialize(data, action)
def get_body_serializer(self, content_type):
try:
@ -443,7 +479,7 @@ class Resource(wsgi.Application):
action, args, accept = self.deserializer.deserialize(request)
except exception.InvalidContentType:
msg = _("Unsupported Content-Type")
return webob.exc.HTTPBadRequest(explanation=msg)
return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg))
except exception.MalformedRequestBody:
msg = _("Malformed request body")
return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg))
@ -454,7 +490,6 @@ class Resource(wsgi.Application):
LOG.info(_("HTTP exception thrown: %s"), unicode(ex))
action_result = faults.Fault(ex)
#TODO(bcwaldon): find a more elegant way to pass through non-dict types
if type(action_result) is dict or action_result is None:
response = self.serializer.serialize(action_result,
accept,

View File

@ -127,7 +127,7 @@ class API(base.Base):
quota_metadata = quota.allowed_metadata_items(context, num_metadata)
if quota_metadata < num_metadata:
pid = context.project_id
msg = _("Quota exceeeded for %(pid)s, tried to set "
msg = _("Quota exceeded for %(pid)s, tried to set "
"%(num_metadata)s metadata properties") % locals()
LOG.warn(msg)
raise quota.QuotaError(msg, "MetadataLimitExceeded")
@ -138,7 +138,7 @@ class API(base.Base):
for k, v in metadata.iteritems():
if len(k) > 255 or len(v) > 255:
pid = context.project_id
msg = _("Quota exceeeded for %(pid)s, metadata property "
msg = _("Quota exceeded for %(pid)s, metadata property "
"key or value too long") % locals()
LOG.warn(msg)
raise quota.QuotaError(msg, "MetadataLimitExceeded")
@ -165,7 +165,7 @@ class API(base.Base):
instance_type)
if num_instances < min_count:
pid = context.project_id
LOG.warn(_("Quota exceeeded for %(pid)s,"
LOG.warn(_("Quota exceeded for %(pid)s,"
" tried to run %(min_count)s instances") % locals())
if num_instances <= 0:
message = _("Instance quota exceeded. You cannot run any "

View File

@ -258,7 +258,7 @@ class FloatingIP(object):
# NOTE(tr3buchet): all networks hosts in zone now use the same pool
LOG.debug("QUOTA: %s" % quota.allowed_floating_ips(context, 1))
if quota.allowed_floating_ips(context, 1) < 1:
LOG.warn(_('Quota exceeeded for %s, tried to allocate '
LOG.warn(_('Quota exceeded for %s, tried to allocate '
'address'),
context.project_id)
raise quota.QuotaError(_('Address quota exceeded. You cannot '

View File

@ -247,3 +247,21 @@ class MiscFunctionsTest(test.TestCase):
self.assertRaises(ValueError,
common.get_id_from_href,
fixture)
def test_get_version_from_href(self):
fixture = 'http://www.testsite.com/v1.1/images'
expected = '1.1'
actual = common.get_version_from_href(fixture)
self.assertEqual(actual, expected)
def test_get_version_from_href_2(self):
fixture = 'http://www.testsite.com/v1.1'
expected = '1.1'
actual = common.get_version_from_href(fixture)
self.assertEqual(actual, expected)
def test_get_version_from_href_default(self):
fixture = 'http://www.testsite.com/images'
expected = '1.0'
actual = common.get_version_from_href(fixture)
self.assertEqual(actual, expected)

View File

@ -16,10 +16,11 @@
# under the License.
import json
import os.path
import stubout
import unittest
import webob
import os.path
from xml.etree import ElementTree
from nova import context
from nova import flags
@ -30,7 +31,8 @@ from nova.api.openstack import wsgi
from nova.tests.api.openstack import fakes
FLAGS = flags.FLAGS
NS = "{http://docs.openstack.org/compute/api/v1.1}"
ATOMNS = "{http://www.w3.org/2005/Atom}"
response_body = "Try to say this Mr. Knox, sir..."
@ -80,20 +82,99 @@ class StubExtensionManager(object):
class ExtensionControllerTest(unittest.TestCase):
def test_index(self):
def setUp(self):
FLAGS.osapi_extensions_path = os.path.join(
os.path.dirname(__file__), "extensions")
def test_list_extensions_json(self):
app = openstack.APIRouterV11()
ext_midware = extensions.ExtensionMiddleware(app)
request = webob.Request.blank("/extensions")
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
def test_get_by_alias(self):
# Make sure we have all the extensions.
data = json.loads(response.body)
names = [x['name'] for x in data['extensions']]
names.sort()
self.assertEqual(names, ["FlavorExtraSpecs", "Floating_ips",
"Fox In Socks", "Hosts", "Multinic", "Volumes"])
# Make sure that at least Fox in Sox is correct.
(fox_ext,) = [
x for x in data['extensions'] if x['alias'] == 'FOXNSOX']
self.assertEqual(fox_ext, {
'namespace': 'http://www.fox.in.socks/api/ext/pie/v1.0',
'name': 'Fox In Socks',
'updated': '2011-01-22T13:25:27-06:00',
'description': 'The Fox In Socks Extension',
'alias': 'FOXNSOX',
'links': []
}
)
def test_get_extension_json(self):
app = openstack.APIRouterV11()
ext_midware = extensions.ExtensionMiddleware(app)
request = webob.Request.blank("/extensions/FOXNSOX")
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
data = json.loads(response.body)
self.assertEqual(data['extension'], {
"namespace": "http://www.fox.in.socks/api/ext/pie/v1.0",
"name": "Fox In Socks",
"updated": "2011-01-22T13:25:27-06:00",
"description": "The Fox In Socks Extension",
"alias": "FOXNSOX",
"links": []
}
)
def test_list_extensions_xml(self):
app = openstack.APIRouterV11()
ext_midware = extensions.ExtensionMiddleware(app)
request = webob.Request.blank("/extensions")
request.accept = "application/xml"
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
print response.body
root = ElementTree.XML(response.body)
self.assertEqual(root.tag.split('extensions')[0], NS)
# Make sure we have all the extensions.
exts = root.findall('{0}extension'.format(NS))
self.assertEqual(len(exts), 6)
# Make sure that at least Fox in Sox is correct.
(fox_ext,) = [x for x in exts if x.get('alias') == 'FOXNSOX']
self.assertEqual(fox_ext.get('name'), 'Fox In Socks')
self.assertEqual(fox_ext.get('namespace'),
'http://www.fox.in.socks/api/ext/pie/v1.0')
self.assertEqual(fox_ext.get('updated'), '2011-01-22T13:25:27-06:00')
self.assertEqual(fox_ext.findtext('{0}description'.format(NS)),
'The Fox In Socks Extension')
def test_get_extension_xml(self):
app = openstack.APIRouterV11()
ext_midware = extensions.ExtensionMiddleware(app)
request = webob.Request.blank("/extensions/FOXNSOX")
request.accept = "application/xml"
response = request.get_response(ext_midware)
self.assertEqual(200, response.status_int)
print response.body
root = ElementTree.XML(response.body)
self.assertEqual(root.tag.split('extension')[0], NS)
self.assertEqual(root.get('alias'), 'FOXNSOX')
self.assertEqual(root.get('name'), 'Fox In Socks')
self.assertEqual(root.get('namespace'),
'http://www.fox.in.socks/api/ext/pie/v1.0')
self.assertEqual(root.get('updated'), '2011-01-22T13:25:27-06:00')
self.assertEqual(root.findtext('{0}description'.format(NS)),
'The Fox In Socks Extension')
class ResourceExtensionTest(unittest.TestCase):
@ -192,7 +273,7 @@ class ActionExtensionTest(unittest.TestCase):
def test_invalid_action(self):
body = dict(blah=dict(name="test"))
response = self._send_server_action_request("/asdf/1/action", body)
response = self._send_server_action_request("/fdsa/1/action", body)
self.assertEqual(404, response.status_int)
@ -244,3 +325,109 @@ class RequestExtensionTest(unittest.TestCase):
response_data = json.loads(response.body)
self.assertEqual('newblue', response_data['flavor']['googoose'])
self.assertEqual("Pig Bands!", response_data['big_bands'])
class ExtensionsXMLSerializerTest(unittest.TestCase):
def test_serialize_extenstion(self):
serializer = extensions.ExtensionsXMLSerializer()
data = {
'extension': {
'name': 'ext1',
'namespace': 'http://docs.rack.com/servers/api/ext/pie/v1.0',
'alias': 'RS-PIE',
'updated': '2011-01-22T13:25:27-06:00',
'description': 'Adds the capability to share an image.',
'links': [
{
'rel': 'describedby',
'type': 'application/pdf',
'href': 'http://docs.rack.com/servers/api/ext/cs.pdf'
},
{
'rel': 'describedby',
'type': 'application/vnd.sun.wadl+xml',
'href': 'http://docs.rack.com/servers/api/ext/cs.wadl'
}
]
}
}
xml = serializer.serialize(data, 'show')
root = ElementTree.XML(xml)
ext_dict = data['extension']
self.assertEqual(root.findtext('{0}description'.format(NS)),
ext_dict['description'])
for key in ['name', 'namespace', 'alias', 'updated']:
self.assertEqual(root.get(key), ext_dict[key])
link_nodes = root.findall('{0}link'.format(ATOMNS))
self.assertEqual(len(link_nodes), 2)
for i, link in enumerate(ext_dict['links']):
for key, value in link.items():
self.assertEqual(link_nodes[i].get(key), value)
def test_serialize_extensions(self):
serializer = extensions.ExtensionsXMLSerializer()
data = {
"extensions": [
{
"name": "Public Image Extension",
"namespace": "http://foo.com/api/ext/pie/v1.0",
"alias": "RS-PIE",
"updated": "2011-01-22T13:25:27-06:00",
"description": "Adds the capability to share an image.",
"links": [
{
"rel": "describedby",
"type": "application/pdf",
"href": "http://foo.com/api/ext/cs-pie.pdf"
},
{
"rel": "describedby",
"type": "application/vnd.sun.wadl+xml",
"href": "http://foo.com/api/ext/cs-pie.wadl"
}
]
},
{
"name": "Cloud Block Storage",
"namespace": "http://foo.com/api/ext/cbs/v1.0",
"alias": "RS-CBS",
"updated": "2011-01-12T11:22:33-06:00",
"description": "Allows mounting cloud block storage.",
"links": [
{
"rel": "describedby",
"type": "application/pdf",
"href": "http://foo.com/api/ext/cs-cbs.pdf"
},
{
"rel": "describedby",
"type": "application/vnd.sun.wadl+xml",
"href": "http://foo.com/api/ext/cs-cbs.wadl"
}
]
}
]
}
xml = serializer.serialize(data, 'index')
print xml
root = ElementTree.XML(xml)
ext_elems = root.findall('{0}extension'.format(NS))
self.assertEqual(len(ext_elems), 2)
for i, ext_elem in enumerate(ext_elems):
ext_dict = data['extensions'][i]
self.assertEqual(ext_elem.findtext('{0}description'.format(NS)),
ext_dict['description'])
for key in ['name', 'namespace', 'alias', 'updated']:
self.assertEqual(ext_elem.get(key), ext_dict[key])
link_nodes = ext_elem.findall('{0}link'.format(ATOMNS))
self.assertEqual(len(link_nodes), 2)
for i, link in enumerate(ext_dict['links']):
for key, value in link.items():
self.assertEqual(link_nodes[i].get(key), value)

View File

@ -16,6 +16,7 @@
# under the License.
import json
from xml.dom import minidom
import webob
import webob.dec
@ -24,6 +25,7 @@ import webob.exc
from nova import test
from nova.api.openstack import common
from nova.api.openstack import faults
from nova.api.openstack import wsgi
class TestFaults(test.TestCase):
@ -144,3 +146,108 @@ class TestFaults(test.TestCase):
"""Ensure the status_int is set correctly on faults"""
fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='what?'))
self.assertEqual(fault.status_int, 400)
def test_v10_xml_serializer(self):
"""Ensure that a v1.0 request responds with a v1.0 xmlns"""
request = webob.Request.blank('/',
headers={"Accept": "application/xml"})
fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram'))
response = request.get_response(fault)
self.assertTrue(common.XML_NS_V10 in response.body)
self.assertEqual(response.content_type, "application/xml")
self.assertEqual(response.status_int, 400)
def test_v11_xml_serializer(self):
"""Ensure that a v1.1 request responds with a v1.1 xmlns"""
request = webob.Request.blank('/v1.1',
headers={"Accept": "application/xml"})
fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram'))
response = request.get_response(fault)
self.assertTrue(common.XML_NS_V11 in response.body)
self.assertEqual(response.content_type, "application/xml")
self.assertEqual(response.status_int, 400)
class FaultsXMLSerializationTestV11(test.TestCase):
"""Tests covering `nova.api.openstack.faults:Fault` class."""
def _prepare_xml(self, xml_string):
xml_string = xml_string.replace(" ", "")
xml_string = xml_string.replace("\n", "")
xml_string = xml_string.replace("\t", "")
return xml_string
def test_400_fault(self):
metadata = {'attributes': {"badRequest": 'code'}}
serializer = wsgi.XMLDictSerializer(metadata=metadata,
xmlns=common.XML_NS_V11)
fixture = {
"badRequest": {
"message": "scram",
"code": 400,
},
}
output = serializer.serialize(fixture)
actual = minidom.parseString(self._prepare_xml(output))
expected = minidom.parseString(self._prepare_xml("""
<badRequest code="400" xmlns="%s">
<message>scram</message>
</badRequest>
""") % common.XML_NS_V11)
self.assertEqual(expected.toxml(), actual.toxml())
def test_413_fault(self):
metadata = {'attributes': {"overLimit": 'code'}}
serializer = wsgi.XMLDictSerializer(metadata=metadata,
xmlns=common.XML_NS_V11)
fixture = {
"overLimit": {
"message": "sorry",
"code": 413,
"retryAfter": 4,
},
}
output = serializer.serialize(fixture)
actual = minidom.parseString(self._prepare_xml(output))
expected = minidom.parseString(self._prepare_xml("""
<overLimit code="413" xmlns="%s">
<message>sorry</message>
<retryAfter>4</retryAfter>
</overLimit>
""") % common.XML_NS_V11)
self.assertEqual(expected.toxml(), actual.toxml())
def test_404_fault(self):
metadata = {'attributes': {"itemNotFound": 'code'}}
serializer = wsgi.XMLDictSerializer(metadata=metadata,
xmlns=common.XML_NS_V11)
fixture = {
"itemNotFound": {
"message": "sorry",
"code": 404,
},
}
output = serializer.serialize(fixture)
actual = minidom.parseString(self._prepare_xml(output))
expected = minidom.parseString(self._prepare_xml("""
<itemNotFound code="404" xmlns="%s">
<message>sorry</message>
</itemNotFound>
""") % common.XML_NS_V11)
self.assertEqual(expected.toxml(), actual.toxml())

View File

@ -103,8 +103,7 @@ class ImageMetaDataTest(test.TestCase):
super(ImageMetaDataTest, self).tearDown()
def test_index(self):
req = webob.Request.blank('/v1.1/images/1/meta')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
@ -114,8 +113,7 @@ class ImageMetaDataTest(test.TestCase):
self.assertEqual(value, res_dict['metadata'][key])
def test_show(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata/key1')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
@ -124,42 +122,66 @@ class ImageMetaDataTest(test.TestCase):
self.assertEqual('value1', res_dict['meta']['key1'])
def test_show_not_found(self):
req = webob.Request.blank('/v1.1/images/1/meta/key9')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata/key9')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
def test_create(self):
req = webob.Request.blank('/v1.1/images/2/meta')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/2/metadata')
req.method = 'POST'
req.body = '{"metadata": {"key9": "value9"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
self.assertEqual('value9', res_dict['metadata']['key9'])
# other items should not be modified
self.assertEqual('value1', res_dict['metadata']['key1'])
self.assertEqual('value2', res_dict['metadata']['key2'])
self.assertEqual(1, len(res_dict))
actual_output = json.loads(res.body)
expected_output = {
'metadata': {
'key1': 'value1',
'key2': 'value2',
'key9': 'value9',
},
}
self.assertEqual(expected_output, actual_output)
def test_update_all(self):
req = webob.Request.blank('/v1.1/images/2/metadata')
req.method = 'PUT'
req.body = '{"metadata": {"key9": "value9"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
actual_output = json.loads(res.body)
expected_output = {
'metadata': {
'key9': 'value9',
},
}
self.assertEqual(expected_output, actual_output)
def test_update_item(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata/key1')
req.method = 'PUT'
req.body = '{"meta": {"key1": "zz"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
res_dict = json.loads(res.body)
self.assertTrue('meta' in res_dict)
self.assertEqual(len(res_dict['meta']), 1)
self.assertEqual('zz', res_dict['meta']['key1'])
actual_output = json.loads(res.body)
expected_output = {
'meta': {
'key1': 'zz',
},
}
self.assertEqual(actual_output, expected_output)
def test_update_item_bad_body(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata/key1')
req.method = 'PUT'
req.body = '{"key1": "zz"}'
req.headers["content-type"] = "application/json"
@ -167,8 +189,7 @@ class ImageMetaDataTest(test.TestCase):
self.assertEqual(400, res.status_int)
def test_update_item_too_many_keys(self):
req = webob.Request.blank('/v1.1/images/1/meta/key1')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata/key1')
req.method = 'PUT'
req.body = '{"meta": {"key1": "value1", "key2": "value2"}}'
req.headers["content-type"] = "application/json"
@ -176,24 +197,38 @@ class ImageMetaDataTest(test.TestCase):
self.assertEqual(400, res.status_int)
def test_update_item_body_uri_mismatch(self):
req = webob.Request.blank('/v1.1/images/1/meta/bad')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/1/metadata/bad')
req.method = 'PUT'
req.body = '{"meta": {"key1": "value1"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
def test_update_item_xml(self):
req = webob.Request.blank('/v1.1/images/1/metadata/key1')
req.method = 'PUT'
req.body = '<meta key="key1">five</meta>'
req.headers["content-type"] = "application/xml"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
actual_output = json.loads(res.body)
expected_output = {
'meta': {
'key1': 'five',
},
}
self.assertEqual(actual_output, expected_output)
def test_delete(self):
req = webob.Request.blank('/v1.1/images/2/meta/key1')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/2/metadata/key1')
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
self.assertEqual(204, res.status_int)
self.assertEqual('', res.body)
def test_delete_not_found(self):
req = webob.Request.blank('/v1.1/images/2/meta/blah')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/2/metadata/blah')
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
@ -203,8 +238,7 @@ class ImageMetaDataTest(test.TestCase):
for num in range(FLAGS.quota_metadata_items + 1):
data['metadata']['key%i' % num] = "blah"
json_string = str(data).replace("\'", "\"")
req = webob.Request.blank('/v1.1/images/2/meta')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/2/metadata')
req.method = 'POST'
req.body = json_string
req.headers["content-type"] = "application/json"
@ -212,8 +246,7 @@ class ImageMetaDataTest(test.TestCase):
self.assertEqual(400, res.status_int)
def test_too_many_metadata_items_on_put(self):
req = webob.Request.blank('/v1.1/images/3/meta/blah')
req.environ['api.version'] = '1.1'
req = webob.Request.blank('/v1.1/images/3/metadata/blah')
req.method = 'PUT'
req.body = '{"meta": {"blah": "blah"}}'
req.headers["content-type"] = "application/json"
@ -221,9 +254,49 @@ class ImageMetaDataTest(test.TestCase):
self.assertEqual(400, res.status_int)
class ImageMetadataXMLDeserializationTest(test.TestCase):
deserializer = openstack.image_metadata.ImageMetadataXMLDeserializer()
def test_create(self):
request_body = """
<metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
<meta key='123'>asdf</meta>
<meta key='567'>jkl;</meta>
</metadata>"""
output = self.deserializer.deserialize(request_body, 'create')
expected = {"body": {"metadata": {"123": "asdf", "567": "jkl;"}}}
self.assertEquals(output, expected)
def test_create_empty(self):
request_body = """
<metadata xmlns="http://docs.openstack.org/compute/api/v1.1"/>"""
output = self.deserializer.deserialize(request_body, 'create')
expected = {"body": {"metadata": {}}}
self.assertEquals(output, expected)
def test_update_all(self):
request_body = """
<metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
<meta key='123'>asdf</meta>
<meta key='567'>jkl;</meta>
</metadata>"""
output = self.deserializer.deserialize(request_body, 'update_all')
expected = {"body": {"metadata": {"123": "asdf", "567": "jkl;"}}}
self.assertEquals(output, expected)
def test_update(self):
request_body = """
<meta xmlns="http://docs.openstack.org/compute/api/v1.1"
key='123'>asdf</meta>"""
output = self.deserializer.deserialize(request_body, 'update')
expected = {"body": {"meta": {"123": "asdf"}}}
self.assertEquals(output, expected)
class ImageMetadataXMLSerializationTest(test.TestCase):
def test_index_xml(self):
def test_index(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'metadata': {
@ -247,7 +320,7 @@ class ImageMetadataXMLSerializationTest(test.TestCase):
self.assertEqual(expected.toxml(), actual.toxml())
def test_index_xml_null(self):
def test_index_null(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'metadata': {
@ -267,7 +340,7 @@ class ImageMetadataXMLSerializationTest(test.TestCase):
self.assertEqual(expected.toxml(), actual.toxml())
def test_index_xml_unicode(self):
def test_index_unicode(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'metadata': {
@ -287,7 +360,7 @@ class ImageMetadataXMLSerializationTest(test.TestCase):
self.assertEqual(expected.toxml(), actual.toxml())
def test_show_xml(self):
def test_show(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'meta': {
@ -305,7 +378,31 @@ class ImageMetadataXMLSerializationTest(test.TestCase):
self.assertEqual(expected.toxml(), actual.toxml())
def test_update_item_xml(self):
def test_update_all(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'metadata': {
'key6': 'value6',
'key4': 'value4',
},
}
output = serializer.serialize(fixture, 'update_all')
actual = minidom.parseString(output.replace(" ", ""))
expected = minidom.parseString("""
<metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
<meta key="key6">
value6
</meta>
<meta key="key4">
value4
</meta>
</metadata>
""".replace(" ", ""))
self.assertEqual(expected.toxml(), actual.toxml())
def test_update_item(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'meta': {
@ -323,7 +420,7 @@ class ImageMetadataXMLSerializationTest(test.TestCase):
self.assertEqual(expected.toxml(), actual.toxml())
def test_create_xml(self):
def test_create(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
fixture = {
'metadata': {
@ -350,3 +447,8 @@ class ImageMetadataXMLSerializationTest(test.TestCase):
""".replace(" ", ""))
self.assertEqual(expected.toxml(), actual.toxml())
def test_delete(self):
serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
output = serializer.serialize(None, 'delete')
self.assertEqual(output, '')

View File

@ -538,7 +538,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
# because the element hasn't changed definition
expected = minidom.parseString("""
<itemNotFound code="404"
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
xmlns="http://docs.openstack.org/compute/api/v1.1">
<message>
Image not found.
</message>

View File

@ -30,8 +30,9 @@ from nova import flags
from nova import test
from nova import utils
import nova.api.openstack
from nova.api.openstack import servers
from nova.api.openstack import create_instance_helper
from nova.api.openstack import servers
from nova.api.openstack import wsgi
import nova.compute.api
from nova.compute import instance_types
from nova.compute import power_state
@ -941,6 +942,18 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
def test_create_instance_no_server_entity(self):
self._setup_for_create_instance()
body = {}
req = webob.Request.blank('/v1.0/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 422)
def test_create_instance_whitespace_name(self):
self._setup_for_create_instance()
@ -2188,6 +2201,62 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""",
"http://localhost:8774/v1.1/images/1")
class TextAddressesXMLSerialization(test.TestCase):
serializer = nova.api.openstack.ips.IPXMLSerializer()
def test_show(self):
fixture = {
'network_2': [
{'addr': '192.168.0.1', 'version': 4},
{'addr': 'fe80::beef', 'version': 6},
],
}
output = self.serializer.serialize(fixture, 'show')
actual = minidom.parseString(output.replace(" ", ""))
expected = minidom.parseString("""
<network xmlns="http://docs.openstack.org/compute/api/v1.1"
id="network_2">
<ip version="4" addr="192.168.0.1"/>
<ip version="6" addr="fe80::beef"/>
</network>
""".replace(" ", ""))
self.assertEqual(expected.toxml(), actual.toxml())
def test_index(self):
fixture = {
'addresses': {
'network_1': [
{'addr': '192.168.0.3', 'version': 4},
{'addr': '192.168.0.5', 'version': 4},
],
'network_2': [
{'addr': '192.168.0.1', 'version': 4},
{'addr': 'fe80::beef', 'version': 6},
],
},
}
output = self.serializer.serialize(fixture, 'index')
actual = minidom.parseString(output.replace(" ", ""))
expected = minidom.parseString("""
<addresses xmlns="http://docs.openstack.org/compute/api/v1.1">
<network id="network_2">
<ip version="4" addr="192.168.0.1"/>
<ip version="6" addr="fe80::beef"/>
</network>
<network id="network_1">
<ip version="4" addr="192.168.0.3"/>
<ip version="4" addr="192.168.0.5"/>
</network>
</addresses>
""".replace(" ", ""))
self.assertEqual(expected.toxml(), actual.toxml())
class TestServerInstanceCreation(test.TestCase):
def setUp(self):

View File

@ -256,6 +256,13 @@ class ResponseSerializerTest(test.TestCase):
self.assertEqual(response.body, 'pew_json')
self.assertEqual(response.status_int, 404)
def test_serialize_response_None(self):
response = self.serializer.serialize(None, 'application/json')
print response
self.assertEqual(response.headers['Content-Type'], 'application/json')
self.assertEqual(response.body, '')
self.assertEqual(response.status_int, 404)
def test_serialize_response_dict_to_unknown_content_type(self):
self.assertRaises(exception.InvalidContentType,
self.serializer.serialize,

View File

@ -269,25 +269,64 @@ class CloudTestCase(test.TestCase):
delete = self.cloud.delete_security_group
self.assertRaises(exception.ApiError, delete, self.context)
def test_authorize_revoke_security_group_ingress(self):
def test_authorize_security_group_ingress(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
sec = db.security_group_create(self.context, kwargs)
authz = self.cloud.authorize_security_group_ingress
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
authz(self.context, group_name=sec['name'], **kwargs)
self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs))
def test_authorize_security_group_ingress_ip_permissions_ip_ranges(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
sec = db.security_group_create(self.context, kwargs)
authz = self.cloud.authorize_security_group_ingress
kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81,
'ip_ranges':
{'1': {'cidr_ip': u'0.0.0.0/0'},
'2': {'cidr_ip': u'10.10.10.10/32'}},
'ip_protocol': u'tcp'}]}
self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs))
def test_authorize_security_group_ingress_ip_permissions_groups(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
sec = db.security_group_create(self.context, kwargs)
authz = self.cloud.authorize_security_group_ingress
kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81,
'ip_ranges':{'1': {'cidr_ip': u'0.0.0.0/0'},
'2': {'cidr_ip': u'10.10.10.10/32'}},
'groups': {'1': {'user_id': u'someuser',
'group_name': u'somegroup1'},
'2': {'user_id': u'someuser',
'group_name': u'othergroup2'}},
'ip_protocol': u'tcp'}]}
self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs))
def test_revoke_security_group_ingress(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
sec = db.security_group_create(self.context, kwargs)
authz = self.cloud.authorize_security_group_ingress
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
authz(self.context, group_id=sec['id'], **kwargs)
revoke = self.cloud.revoke_security_group_ingress
self.assertTrue(revoke(self.context, group_name=sec['name'], **kwargs))
def test_authorize_revoke_security_group_ingress_by_id(self):
sec = db.security_group_create(self.context,
{'project_id': self.context.project_id,
'name': 'test'})
def test_revoke_security_group_ingress_by_id(self):
kwargs = {'project_id': self.context.project_id, 'name': 'test'}
sec = db.security_group_create(self.context, kwargs)
authz = self.cloud.authorize_security_group_ingress
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
authz(self.context, group_id=sec['id'], **kwargs)
revoke = self.cloud.revoke_security_group_ingress
self.assertTrue(revoke(self.context, group_id=sec['id'], **kwargs))
def test_authorize_security_group_ingress_by_id(self):
sec = db.security_group_create(self.context,
{'project_id': self.context.project_id,
'name': 'test'})
authz = self.cloud.authorize_security_group_ingress
kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'}
self.assertTrue(authz(self.context, group_id=sec['id'], **kwargs))
def test_authorize_security_group_ingress_missing_protocol_params(self):
sec = db.security_group_create(self.context,
{'project_id': self.context.project_id,
@ -908,6 +947,21 @@ class CloudTestCase(test.TestCase):
self._wait_for_running(ec2_instance_id)
return ec2_instance_id
def test_rescue_unrescue_instance(self):
instance_id = self._run_instance(
image_id='ami-1',
instance_type=FLAGS.default_instance_type,
max_count=1)
self.cloud.rescue_instance(context=self.context,
instance_id=instance_id)
# NOTE(vish): This currently does no validation, it simply makes sure
# that the code path doesn't throw an exception.
self.cloud.unrescue_instance(context=self.context,
instance_id=instance_id)
# TODO(soren): We need this until we can stop polling in the rpc code
# for unit tests.
self.cloud.terminate_instances(self.context, [instance_id])
def test_console_output(self):
instance_id = self._run_instance(
image_id='ami-1',

View File

@ -82,9 +82,13 @@
</disk>
#end if
#for $vol in $volumes
<disk type='block'>
<disk type='${vol.type}'>
<driver type='raw'/>
#if $vol.type == 'network'
<source protocol='${vol.protocol}' name='${vol.name}'/>
#else
<source dev='${vol.device_path}'/>
#end if
<target dev='${vol.mount_device}' bus='${disk_bus}'/>
</disk>
#end for

View File

@ -335,21 +335,20 @@ class LibvirtConnection(driver.ComputeDriver):
def attach_volume(self, instance_name, device_path, mountpoint):
virt_dom = self._lookup_by_name(instance_name)
mount_device = mountpoint.rpartition("/")[2]
if device_path.startswith('/dev/'):
(type, protocol, name) = \
self._get_volume_device_info(vol['device_path'])
if type == 'block':
xml = """<disk type='block'>
<driver name='qemu' type='raw'/>
<source dev='%s'/>
<target dev='%s' bus='virtio'/>
</disk>""" % (device_path, mount_device)
elif ':' in device_path:
(protocol, name) = device_path.split(':')
elif type == 'network':
xml = """<disk type='network'>
<driver name='qemu' type='raw'/>
<source protocol='%s' name='%s'/>
<target dev='%s' bus='virtio'/>
</disk>""" % (protocol,
name,
mount_device)
</disk>""" % (protocol, name, mount_device)
else:
raise exception.InvalidDevicePath(path=device_path)
@ -973,6 +972,16 @@ class LibvirtConnection(driver.ComputeDriver):
return True
return False
@exception.wrap_exception
def _get_volume_device_info(self, device_path):
if device_path.startswith('/dev/'):
return ('block', None, None)
elif ':' in device_path:
(protocol, name) = device_path.split(':')
return ('network', protocol, name)
else:
raise exception.InvalidDevicePath(path=device_path)
def _prepare_xml_info(self, instance, rescue=False, network_info=None,
block_device_mapping=None):
block_device_mapping = block_device_mapping or []
@ -995,6 +1004,9 @@ class LibvirtConnection(driver.ComputeDriver):
for vol in block_device_mapping:
vol['mount_device'] = _strip_dev(vol['mount_device'])
(vol['type'], vol['protocol'], vol['name']) = \
self._get_volume_device_info(vol['device_path'])
ebs_root = self._volume_in_mapping(self.root_mount_device,
block_device_mapping)
if self._volume_in_mapping(self.local_mount_device,

View File

@ -45,10 +45,30 @@ def get_network_with_the_name(session, network_name="vmnet0"):
networks = session._call_method(vim_util,
"get_properties_for_a_collection_of_objects",
"Network", vm_networks, ["summary.name"])
for network in networks:
if network.propSet[0].val == network_name:
return network.obj
return None
network_obj = {}
for network in vm_networks:
# Get network properties
if network._type == 'DistributedVirtualPortgroup':
props = session._call_method(vim_util,
"get_dynamic_property", network,
"DistributedVirtualPortgroup", "config")
# NOTE(asomya): This only works on ESXi if the port binding is
# set to ephemeral
if props.name == network_name:
network_obj['type'] = 'DistributedVirtualPortgroup'
network_obj['dvpg'] = props.key
network_obj['dvsw'] = props.distributedVirtualSwitch.value
else:
props = session._call_method(vim_util,
"get_dynamic_property", network,
"Network", "summary.name")
if props == network_name:
network_obj['type'] = 'Network'
network_obj['name'] = network_name
if (len(network_obj) > 0):
return network_obj
else:
return None
def get_vswitch_for_vlan_interface(session, vlan_interface):

View File

@ -40,7 +40,7 @@ def split_datastore_path(datastore_path):
def get_vm_create_spec(client_factory, instance, data_store_name,
network_name="vmnet0",
os_type="otherGuest"):
os_type="otherGuest", network_ref=None):
"""Builds the VM Create spec."""
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
config_spec.name = instance.name
@ -93,7 +93,8 @@ def create_controller_spec(client_factory, key):
return virtual_device_config
def create_network_spec(client_factory, network_name, mac_address):
def create_network_spec(client_factory, network_name, mac_address,
network_ref=None):
"""
Builds a config spec for the addition of a new network
adapter to the VM.
@ -105,9 +106,24 @@ def create_network_spec(client_factory, network_name, mac_address):
# Get the recommended card type for the VM based on the guest OS of the VM
net_device = client_factory.create('ns0:VirtualPCNet32')
backing = \
client_factory.create('ns0:VirtualEthernetCardNetworkBackingInfo')
backing.deviceName = network_name
# NOTE(asomya): Only works on ESXi if the portgroup binding is set to
# ephemeral. Invalid configuration if set to static and the NIC does
# not come up on boot if set to dynamic.
backing = None
if (network_ref['type'] == "DistributedVirtualPortgroup"):
backing_name = \
'ns0:VirtualEthernetCardDistributedVirtualPortBackingInfo'
backing = \
client_factory.create(backing_name)
portgroup = \
client_factory.create('ns0:DistributedVirtualSwitchPortConnection')
portgroup.switchUuid = network_ref['dvsw']
portgroup.portgroupKey = network_ref['dvpg']
backing.port = portgroup
else:
backing = \
client_factory.create('ns0:VirtualEthernetCardNetworkBackingInfo')
backing.deviceName = network_name
connectable_spec = \
client_factory.create('ns0:VirtualDeviceConnectInfo')
@ -278,9 +294,11 @@ def get_dummy_vm_create_spec(client_factory, name, data_store_name):
return config_spec
def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask, gateway):
def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask,
gateway, broadcast, dns):
"""Builds the machine id change config spec."""
machine_id_str = "%s;%s;%s;%s" % (mac, ip_addr, netmask, gateway)
machine_id_str = "%s;%s;%s;%s;%s;%s" % (mac, ip_addr, netmask,
gateway, broadcast, dns)
virtual_machine_config_spec = \
client_factory.create('ns0:VirtualMachineConfigSpec')

View File

@ -116,8 +116,9 @@ class VMWareVMOps(object):
net_name)
if network_ref is None:
raise exception.NetworkNotFoundForBridge(bridge=net_name)
return network_ref
_check_if_network_bridge_exists()
network_obj = _check_if_network_bridge_exists()
def _get_datastore_ref():
"""Get the datastore list and choose the first local storage."""
@ -175,8 +176,10 @@ class VMWareVMOps(object):
vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors()
# Get the create vm config spec
config_spec = vm_util.get_vm_create_spec(client_factory, instance,
data_store_name, net_name, os_type)
config_spec = vm_util.get_vm_create_spec(
client_factory, instance,
data_store_name, net_name, os_type,
network_obj)
def _execute_create_vm():
"""Create VM on ESX host."""
@ -718,13 +721,17 @@ class VMWareVMOps(object):
net_mask = network["netmask"]
gateway = network["gateway"]
broadcast = network["broadcast"]
dns = network["dns"]
addresses = db.instance_get_fixed_addresses(admin_context,
instance['id'])
ip_addr = addresses[0] if addresses else None
machine_id_chanfge_spec = \
vm_util.get_machine_id_change_spec(client_factory, mac_address,
ip_addr, net_mask, gateway)
ip_addr, net_mask, gateway,
broadcast, dns)
LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "
"with ip - %(ip_addr)s") %
({'name': instance.name,

View File

@ -52,7 +52,7 @@ class API(base.Base):
if quota.allowed_volumes(context, 1, size) < 1:
pid = context.project_id
LOG.warn(_("Quota exceeeded for %(pid)s, tried to create"
LOG.warn(_("Quota exceeded for %(pid)s, tried to create"
" %(size)sG volume") % locals())
raise quota.QuotaError(_("Volume quota exceeded. You cannot "
"create a volume of size %sG") % size)

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-19 06:18+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:11+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-19 06:18+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:11+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-19 06:18+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: nova\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-02-21 10:03-0500\n"
"PO-Revision-Date: 2011-04-03 19:42+0000\n"
"Last-Translator: Matthias Loidolt <kedapperdrake@googlemail.com>\n"
"PO-Revision-Date: 2011-06-06 07:58+0000\n"
"Last-Translator: Christian Berendt <Unknown>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-04-04 05:19+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110
@ -85,6 +85,7 @@ msgstr ""
#, python-format
msgid "%(param)s property not found for image %(_image_id)s"
msgstr ""
"Die Property %(param)s konnte im Image %(_image_id)s nicht gefunden werden"
#: ../nova/api/openstack/servers.py:168
msgid "No keypairs defined"
@ -141,12 +142,12 @@ msgstr "PID-Datei %s existiert nicht. Läuft der Daemon nicht?\n"
#: ../nova/twistd.py:221
msgid "No such process"
msgstr ""
msgstr "Kein passender Prozess gefunden"
#: ../nova/twistd.py:230 ../nova/service.py:224
#, python-format
msgid "Serving %s"
msgstr ""
msgstr "Bedient %s"
#: ../nova/twistd.py:262 ../nova/service.py:225
msgid "Full set of FLAGS:"
@ -183,12 +184,13 @@ msgstr ""
#: ../nova/virt/xenapi/volumeops.py:91
#, python-format
msgid "Unable to attach volume to instance %s"
msgstr ""
msgstr "Nicht möglich Volumen zur Instanze %s hinzuzufügen"
#: ../nova/virt/xenapi/volumeops.py:93
#, python-format
msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
msgstr ""
"Einhängepunkt%(mountpoint)s zur Instanze %(instance_name)s hinzugefügt"
#. Detach VBD from VM
#: ../nova/virt/xenapi/volumeops.py:104
@ -199,7 +201,7 @@ msgstr ""
#: ../nova/virt/xenapi/volumeops.py:112
#, python-format
msgid "Unable to locate volume %s"
msgstr ""
msgstr "Nicht möglich volume %s zufinden"
#: ../nova/virt/xenapi/volumeops.py:120
#, python-format
@ -214,7 +216,7 @@ msgstr ""
#: ../nova/compute/instance_types.py:41
#, python-format
msgid "Unknown instance type: %s"
msgstr ""
msgstr "Unbekannter Instanztyp: %s"
#: ../nova/crypto.py:46
msgid "Filename of root CA"
@ -230,7 +232,7 @@ msgstr "Dateiname der Certificate Revocation List"
#: ../nova/crypto.py:53
msgid "Where we keep our keys"
msgstr ""
msgstr "Wo wir unsere Schlüssel aufbewahren"
#: ../nova/crypto.py:55
msgid "Where we keep our root CA"
@ -298,12 +300,12 @@ msgstr ""
#: ../nova/compute/manager.py:179
msgid "Instance has already been created"
msgstr ""
msgstr "Instanz wurde bereits erstellt"
#: ../nova/compute/manager.py:180
#, python-format
msgid "instance %s: starting..."
msgstr ""
msgstr "Instanz %s startet..."
#. pylint: disable=W0702
#: ../nova/compute/manager.py:219
@ -314,7 +316,7 @@ msgstr ""
#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
#, python-format
msgid "Terminating instance %s"
msgstr ""
msgstr "Beende Instanz %s"
#: ../nova/compute/manager.py:255
#, python-format
@ -377,7 +379,7 @@ msgstr ""
#: ../nova/compute/manager.py:372
#, python-format
msgid "instance %s: rescuing"
msgstr ""
msgstr "Instanz %s: Rettung"
#: ../nova/compute/manager.py:387
#, python-format
@ -387,12 +389,12 @@ msgstr ""
#: ../nova/compute/manager.py:406
#, python-format
msgid "instance %s: pausing"
msgstr ""
msgstr "Instanz %s pausiert"
#: ../nova/compute/manager.py:423
#, python-format
msgid "instance %s: unpausing"
msgstr ""
msgstr "Instanz %s wird fortgesetzt"
#: ../nova/compute/manager.py:440
#, python-format
@ -584,7 +586,7 @@ msgstr ""
#: ../nova/virt/connection.py:73
msgid "Failed to open connection to the hypervisor"
msgstr ""
msgstr "Konnte Verbindung zum Hypervisor nicht öffnen"
#: ../nova/network/linux_net.py:187
#, python-format
@ -637,7 +639,7 @@ msgstr "Klasse %s konnte nicht gefunden werden"
#: ../nova/utils.py:118
#, python-format
msgid "Fetching %s"
msgstr ""
msgstr "Hole %s"
#: ../nova/utils.py:130
#, python-format
@ -2562,7 +2564,7 @@ msgstr ""
#: ../nova/auth/manager.py:270
#, python-format
msgid "Using project name = user name (%s)"
msgstr ""
msgstr "Verwende Project-Name = User-Name (%s)"
#: ../nova/auth/manager.py:277
#, python-format
@ -2572,7 +2574,7 @@ msgstr ""
#: ../nova/auth/manager.py:279
#, python-format
msgid "No project called %s could be found"
msgstr ""
msgstr "Es konnte kein Projekt mit dem Namen %s gefunden werden"
#: ../nova/auth/manager.py:287
#, python-format
@ -2696,6 +2698,7 @@ msgstr ""
#: ../nova/service.py:195
msgid "The service database object disappeared, Recreating it."
msgstr ""
"Das Service-Datenbank-Objekt ist verschwunden, es wird erneut erzeugt."
#: ../nova/service.py:207
msgid "Recovered model server connection!"
@ -2723,7 +2726,7 @@ msgstr ""
#: ../nova/auth/ldapdriver.py:472
#, python-format
msgid "Group can't be created because group %s already exists"
msgstr ""
msgstr "Die Gruppe %s kann nicht angelegt werde, da sie bereits existiert"
#: ../nova/auth/ldapdriver.py:478
#, python-format
@ -2739,6 +2742,7 @@ msgstr ""
#, python-format
msgid "User %s can't be added to the group because the user doesn't exist"
msgstr ""
"Der User %s kann nicht zur Gruppe hinzugefügt werde, da er nicht existiert"
#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
#, python-format
@ -2755,6 +2759,7 @@ msgstr ""
msgid ""
"User %s can't be removed from the group because the user doesn't exist"
msgstr ""
"Der User %s kann nicht aus der Gruppe entfernt werden, da er nicht existiert"
#: ../nova/auth/ldapdriver.py:528
#, python-format
@ -2840,7 +2845,7 @@ msgstr ""
#: ../nova/api/ec2/admin.py:200
#, python-format
msgid "Delete project: %s"
msgstr ""
msgstr "Lösche Projekt %s"
#: ../nova/api/ec2/admin.py:214
#, python-format

2848
po/en_AU.po Normal file

File diff suppressed because it is too large Load Diff

2873
po/en_GB.po Normal file

File diff suppressed because it is too large Load Diff

139
po/es.po
View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: nova\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-02-21 10:03-0500\n"
"PO-Revision-Date: 2011-03-17 15:54+0000\n"
"Last-Translator: Erick Huezo <erickhuezo@gmail.com>\n"
"PO-Revision-Date: 2011-06-30 16:42+0000\n"
"Last-Translator: David Caro <Unknown>\n"
"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-19 06:19+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110
@ -36,10 +36,15 @@ msgid ""
"Stdout: %(stdout)r\n"
"Stderr: %(stderr)r"
msgstr ""
"%(description)s\n"
"Comando: %(cmd)s\n"
"Código de salida: %(exit_code)s\n"
"Stdout: %(stdout)r\n"
"Stderr: %(stderr)r"
#: ../nova/exception.py:107
msgid "DB exception wrapped"
msgstr ""
msgstr "Excepción DB encapsulada"
#. exc_type, exc_value, exc_traceback = sys.exc_info()
#: ../nova/exception.py:120
@ -49,12 +54,12 @@ msgstr "Excepción no controlada"
#: ../nova/volume/api.py:45
#, python-format
msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
msgstr ""
msgstr "Cuota excedida por %(pid)s, se intentó crear el volumen %(size)sG"
#: ../nova/volume/api.py:47
#, python-format
msgid "Volume quota exceeded. You cannot create a volume of size %sG"
msgstr "Cuota excedida. No puedes crear un volumen con tamaño %sG"
msgstr "Cuota excedida. No puede crear un volumen con tamaño %sG"
#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
msgid "Volume status must be available"
@ -83,7 +88,7 @@ msgstr "%(param)s propiedad no encontrada para la imagen %(_image_id)s"
#: ../nova/api/openstack/servers.py:168
msgid "No keypairs defined"
msgstr "No se definio una Keypairs"
msgstr "No se definio un par de llaves (Keypair)"
#: ../nova/api/openstack/servers.py:238
#, python-format
@ -103,7 +108,7 @@ msgstr "Compute.api::get_lock %s"
#: ../nova/api/openstack/servers.py:281
#, python-format
msgid "Compute.api::reset_network %s"
msgstr ""
msgstr "Compute.api::reset_network %s"
#: ../nova/api/openstack/servers.py:292
#, python-format
@ -127,16 +132,16 @@ msgstr "compute.api::resume %s"
#: ../nova/twistd.py:157
msgid "Wrong number of arguments."
msgstr "Numero de argumentos incorrectos"
msgstr "Cantidad de argumentos incorrecta"
#: ../nova/twistd.py:209
#, python-format
msgid "pidfile %s does not exist. Daemon not running?\n"
msgstr "el pidfile %s no existe. ¿No estará el demonio parado?\n"
msgstr "El \"pidfile\" %s no existe. Quizás el servicio no este corriendo.\n"
#: ../nova/twistd.py:221
msgid "No such process"
msgstr "No se encontró proceso"
msgstr "No existe el proceso"
#: ../nova/twistd.py:230 ../nova/service.py:224
#, python-format
@ -145,12 +150,12 @@ msgstr "Sirviendo %s"
#: ../nova/twistd.py:262 ../nova/service.py:225
msgid "Full set of FLAGS:"
msgstr "Conjunto completo de opciones:"
msgstr "Conjunto completo de opciones (FLAGS):"
#: ../nova/twistd.py:266
#, python-format
msgid "Starting %s"
msgstr "Comenzando %s"
msgstr "Iniciando %s"
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
@ -163,17 +168,19 @@ msgstr "La instancia %s no se ha encontrado"
#: ../nova/virt/xenapi/volumeops.py:51
#, python-format
msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
msgstr ""
msgstr "Volumen_unido: %(instance_name)s, %(device_path)s, %(mountpoint)s"
#: ../nova/virt/xenapi/volumeops.py:69
#, python-format
msgid "Unable to create VDI on SR %(sr_ref)s for instance %(instance_name)s"
msgstr ""
"No es posible crear el VDI en SR %(sr_ref)s para la instancia "
"%(instance_name)s"
#: ../nova/virt/xenapi/volumeops.py:80
#, python-format
msgid "Unable to use SR %(sr_ref)s for instance %(instance_name)s"
msgstr ""
msgstr "No es posible usar SR %(sr_ref)s para la instancia %(instance_name)s"
#: ../nova/virt/xenapi/volumeops.py:91
#, python-format
@ -184,12 +191,14 @@ msgstr "Imposible adjuntar volumen a la instancia %s"
#, python-format
msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
msgstr ""
"El punto de montaje %(mountpoint)s esta unido a la instancia "
"%(instance_name)s"
#. Detach VBD from VM
#: ../nova/virt/xenapi/volumeops.py:104
#, python-format
msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
msgstr ""
msgstr "Volume_separado: %(instance_name)s, %(mountpoint)s"
#: ../nova/virt/xenapi/volumeops.py:112
#, python-format
@ -205,6 +214,8 @@ msgstr "Imposible desasociar volumen %s"
#, python-format
msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
msgstr ""
"El punto de montaje %(mountpoint)s se desligó de la instancia "
"%(instance_name)s"
#: ../nova/compute/instance_types.py:41
#, python-format
@ -259,7 +270,7 @@ msgstr ""
#: ../nova/crypto.py:258
#, python-format
msgid "Flags path: %s"
msgstr ""
msgstr "Ruta a las opciones: %s"
#: ../nova/scheduler/manager.py:69
#, python-format
@ -276,6 +287,7 @@ msgstr "check_instance_lock: decorating: |%s|"
msgid ""
"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
msgstr ""
"check_instance_lock: argumentos: |%(self)s| |%(context)s| |%(instance_id)s|"
#: ../nova/compute/manager.py:84
#, python-format
@ -338,6 +350,8 @@ msgid ""
"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
"expected: %(running)s)"
msgstr ""
"intentando reiniciar una instancia no ejecutada: %(instance_id)s (state: "
"%(state)s expected: %(running)s)"
#: ../nova/compute/manager.py:311
#, python-format
@ -350,6 +364,8 @@ msgid ""
"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
"expected: %(running)s)"
msgstr ""
"intentando crear una imagen instantanea(snapshot) de una maquina no "
"ejecutada: %(instance_id)s (state: %(state)s expected: %(running)s)"
#: ../nova/compute/manager.py:332
#, python-format
@ -357,11 +373,13 @@ msgid ""
"trying to reset the password on a non-running instance: %(instance_id)s "
"(state: %(instance_state)s expected: %(expected_state)s)"
msgstr ""
"intentando restablecer el password en una instancia: %(instance_id)s "
"(estado: %(instance_state)s esperado: %(expected_state)s)"
#: ../nova/compute/manager.py:335
#, python-format
msgid "instance %s: setting admin password"
msgstr ""
msgstr "instancia %s: estableciendo password de administrador"
#: ../nova/compute/manager.py:353
#, python-format
@ -369,11 +387,13 @@ msgid ""
"trying to inject a file into a non-running instance: %(instance_id)s (state: "
"%(instance_state)s expected: %(expected_state)s)"
msgstr ""
"intentando inyectar un archivo dentro de una instancia parada: "
"%(instance_id)s (estado: %(instance_state)s esperado: %(expected_state)s)"
#: ../nova/compute/manager.py:362
#, python-format
msgid "instance %(nm)s: injecting file to %(plain_path)s"
msgstr ""
msgstr "instancia %(nm)s: inyectando archivo en %(plain_path)s"
#: ../nova/compute/manager.py:372
#, python-format
@ -393,7 +413,7 @@ msgstr "instancia %s: pausando"
#: ../nova/compute/manager.py:423
#, python-format
msgid "instance %s: unpausing"
msgstr "instnacia %s: continuando tras pausa"
msgstr "instancia %s: continuando tras pausa"
#: ../nova/compute/manager.py:440
#, python-format
@ -403,7 +423,7 @@ msgstr "instancia %s: obteniendo los diagnosticos"
#: ../nova/compute/manager.py:453
#, python-format
msgid "instance %s: suspending"
msgstr ""
msgstr "instancia %s: suspendiendo"
#: ../nova/compute/manager.py:472
#, python-format
@ -501,7 +521,7 @@ msgstr "Exportando de nuevo los volumenes %s"
#: ../nova/volume/manager.py:90
#, python-format
msgid "volume %s: skipping export"
msgstr ""
msgstr "volume %s: saltando exportación"
#: ../nova/volume/manager.py:96
#, python-format
@ -511,7 +531,7 @@ msgstr "volumen %s: creando"
#: ../nova/volume/manager.py:108
#, python-format
msgid "volume %(vol_name)s: creating lv of size %(vol_size)sG"
msgstr ""
msgstr "volume %(vol_name)s: creando lv del tamaño %(vol_size)sG"
#: ../nova/volume/manager.py:112
#, python-format
@ -549,7 +569,7 @@ msgstr "volumen %s: eliminado satisfactoriamente"
#: ../nova/virt/xenapi/fake.py:74
#, python-format
msgid "%(text)s: _db_content => %(content)s"
msgstr ""
msgstr "%(text)s: _db_content => %(content)s"
#: ../nova/virt/xenapi/fake.py:304 ../nova/virt/xenapi/fake.py:404
#: ../nova/virt/xenapi/fake.py:422 ../nova/virt/xenapi/fake.py:478
@ -564,7 +584,7 @@ msgstr "xenapi.fake no tiene una implementación para %s"
#: ../nova/virt/xenapi/fake.py:341
#, python-format
msgid "Calling %(localname)s %(impl)s"
msgstr ""
msgstr "Llamando %(localname)s %(impl)s"
#: ../nova/virt/xenapi/fake.py:346
#, python-format
@ -618,12 +638,12 @@ msgstr "El pid %d está pasado, relanzando dnsmasq"
#: ../nova/network/linux_net.py:358
#, python-format
msgid "killing radvd threw %s"
msgstr ""
msgstr "Matando radvd lanzado %s"
#: ../nova/network/linux_net.py:360
#, python-format
msgid "Pid %d is stale, relaunching radvd"
msgstr ""
msgstr "Pid %d corrupto, relanzando radvd"
#. pylint: disable=W0703
#: ../nova/network/linux_net.py:449
@ -659,7 +679,7 @@ msgstr "El resultado fue %s"
#: ../nova/utils.py:159
#, python-format
msgid "Running cmd (SSH): %s"
msgstr ""
msgstr "corriendo cmd (SSH): %s"
#: ../nova/utils.py:217
#, python-format
@ -674,12 +694,12 @@ msgstr "Ejecutando %s"
#: ../nova/utils.py:262
#, python-format
msgid "Link Local address is not found.:%s"
msgstr ""
msgstr "No se encuentra la dirección del enlace local.:%s"
#: ../nova/utils.py:265
#, python-format
msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
msgstr ""
msgstr "No se pudo obtener enlace de la ip local de %(interface)s :%(ex)s"
#: ../nova/utils.py:363
#, python-format
@ -694,7 +714,7 @@ msgstr "backend %s"
#: ../nova/fakerabbit.py:49
#, python-format
msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
msgstr ""
msgstr "(%(nm)s) publica (key: %(routing_key)s) %(message)s"
#: ../nova/fakerabbit.py:54
#, python-format
@ -714,12 +734,12 @@ msgstr "Declarando intercambio %s"
#: ../nova/fakerabbit.py:96
#, python-format
msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
msgstr ""
msgstr "Enlazando %(queue)s a %(exchange)s con la llave %(routing_key)s"
#: ../nova/fakerabbit.py:121
#, python-format
msgid "Getting from %(queue)s: %(message)s"
msgstr ""
msgstr "Obtendiendo desde %(queue)s: %(message)s"
#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
#, python-format
@ -729,17 +749,17 @@ msgstr "Creada VM %s..."
#: ../nova/virt/xenapi/vm_utils.py:138
#, python-format
msgid "Created VM %(instance_name)s as %(vm_ref)s."
msgstr ""
msgstr "VM creada %(instance_name)s como %(vm_ref)s."
#: ../nova/virt/xenapi/vm_utils.py:168
#, python-format
msgid "Creating VBD for VM %(vm_ref)s, VDI %(vdi_ref)s ... "
msgstr ""
msgstr "Creando VBD para VM %(vm_ref)s, VDI %(vdi_ref)s ... "
#: ../nova/virt/xenapi/vm_utils.py:171
#, python-format
msgid "Created VBD %(vbd_ref)s for VM %(vm_ref)s, VDI %(vdi_ref)s."
msgstr ""
msgstr "Creado el VBD %(vbd_ref)s para VM %(vm_ref)s, VDI %(vdi_ref)s"
#: ../nova/virt/xenapi/vm_utils.py:187
#, python-format
@ -759,12 +779,12 @@ msgstr "Imposible destruir VBD %s"
#: ../nova/virt/xenapi/vm_utils.py:224
#, python-format
msgid "Creating VIF for VM %(vm_ref)s, network %(network_ref)s."
msgstr ""
msgstr "Creando VIF para VM %(vm_ref)s, red %(network_ref)s."
#: ../nova/virt/xenapi/vm_utils.py:227
#, python-format
msgid "Created VIF %(vif_ref)s for VM %(vm_ref)s, network %(network_ref)s."
msgstr ""
msgstr "Creado el VIF %(vif_ref)s para VM %(vm_ref)s, red %(network_ref)s."
#: ../nova/virt/xenapi/vm_utils.py:246
#, python-format
@ -772,50 +792,52 @@ msgid ""
"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
"%(sr_ref)s."
msgstr ""
"VDI creado %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) "
"sobre %(sr_ref)s."
#. TODO(sirp): Add quiesce and VSS locking support when Windows support
#. is added
#: ../nova/virt/xenapi/vm_utils.py:258
#, python-format
msgid "Snapshotting VM %(vm_ref)s with label '%(label)s'..."
msgstr ""
msgstr "Creando snapshot de la VM %(vm_ref)s con etiqueta '%(label)s'..."
#: ../nova/virt/xenapi/vm_utils.py:272
#, python-format
msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
msgstr ""
msgstr "Instantánea creada %(template_vm_ref)s de la VM %(vm_ref)s."
#: ../nova/virt/xenapi/vm_utils.py:286
#, python-format
msgid "Asking xapi to upload %(vdi_uuids)s as ID %(image_id)s"
msgstr ""
msgstr "Pidiendo xapi a subir %(vdi_uuids)s como ID %(image_id)s"
#: ../nova/virt/xenapi/vm_utils.py:327
#, python-format
msgid "Size for image %(image)s:%(virtual_size)d"
msgstr ""
msgstr "Tamaño para imagen %(image)s:%(virtual_size)d"
#: ../nova/virt/xenapi/vm_utils.py:332
#, python-format
msgid "Glance image %s"
msgstr ""
msgstr "Imagen Glance %s"
#. we need to invoke a plugin for copying VDI's
#. content into proper path
#: ../nova/virt/xenapi/vm_utils.py:342
#, python-format
msgid "Copying VDI %s to /boot/guest on dom0"
msgstr ""
msgstr "Copiando VDI %s a /boot/guest on dom0"
#: ../nova/virt/xenapi/vm_utils.py:352
#, python-format
msgid "Kernel/Ramdisk VDI %s destroyed"
msgstr ""
msgstr "Kernel/Ramdisk VDI %s destruído"
#: ../nova/virt/xenapi/vm_utils.py:361
#, python-format
msgid "Asking xapi to fetch %(url)s as %(access)s"
msgstr ""
msgstr "Pidiendo a xapi que descargue %(url)s como %(access)s"
#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
#, python-format
@ -825,21 +847,21 @@ msgstr "Buscando vid %s para el kernel PV"
#: ../nova/virt/xenapi/vm_utils.py:397
#, python-format
msgid "PV Kernel in VDI:%s"
msgstr ""
msgstr "Kernel PV en VDI:%s"
#: ../nova/virt/xenapi/vm_utils.py:405
#, python-format
msgid "Running pygrub against %s"
msgstr ""
msgstr "Ejecutando pygrub contra %s"
#: ../nova/virt/xenapi/vm_utils.py:411
#, python-format
msgid "Found Xen kernel %s"
msgstr ""
msgstr "Kernel Xen Encontrado %s"
#: ../nova/virt/xenapi/vm_utils.py:413
msgid "No Xen kernel found. Booting HVM."
msgstr ""
msgstr "Kernel Xen no encontrado. Reiniciando HVM"
#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
#, python-format
@ -864,7 +886,7 @@ msgstr "(VM_UTILS) xenapi power_state -> |%s|"
#: ../nova/virt/xenapi/vm_utils.py:525
#, python-format
msgid "VHD %(vdi_uuid)s has parent %(parent_ref)s"
msgstr ""
msgstr "VHD %(vdi_uuid)s tiene origen en %(parent_ref)s"
#: ../nova/virt/xenapi/vm_utils.py:542
#, python-format
@ -893,18 +915,19 @@ msgstr "No se han encontrado VDI's para VM %s"
#, python-format
msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
msgstr ""
"Numero de VDIs inesperado (%(num_vdis)s) encontrados por VM %(vm_ref)s"
#: ../nova/virt/xenapi/vm_utils.py:653
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:188
#, python-format
msgid "Creating VBD for VDI %s ... "
msgstr ""
msgstr "Creando VBD para VDI %s ... "
#: ../nova/virt/xenapi/vm_utils.py:655
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:190
#, python-format
msgid "Creating VBD for VDI %s done."
msgstr ""
msgstr "Creando VBF para VDI %s terminado"
#: ../nova/virt/xenapi/vm_utils.py:657
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
@ -2850,12 +2873,12 @@ msgstr ""
#: ../nova/api/ec2/admin.py:177
#, python-format
msgid "Create project %(name)s managed by %(manager_user)s"
msgstr ""
msgstr "Crear proyecto %(name)s administrador por %(manager_user)s"
#: ../nova/api/ec2/admin.py:190
#, python-format
msgid "Modify project: %(name)s managed by %(manager_user)s"
msgstr ""
msgstr "Modificar proyecto: %(name)s administrado por %(manager_user)s"
#: ../nova/api/ec2/admin.py:200
#, python-format
@ -2865,12 +2888,12 @@ msgstr "Borrar proyecto: %s"
#: ../nova/api/ec2/admin.py:214
#, python-format
msgid "Adding user %(user)s to project %(project)s"
msgstr ""
msgstr "Agregando usuario %(user)s al proyecto %(project)s"
#: ../nova/api/ec2/admin.py:218
#, python-format
msgid "Removing user %(user)s from project %(project)s"
msgstr ""
msgstr "Eliminando el usuario %(user)s del proyecto %(project)s"
#, python-format
#~ msgid ""

2992
po/fr.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-19 06:19+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110

482
po/ja.po

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-25 05:22+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110

View File

@ -8,20 +8,20 @@ msgstr ""
"Project-Id-Version: nova\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-02-21 10:03-0500\n"
"PO-Revision-Date: 2011-03-30 07:06+0000\n"
"Last-Translator: Andrey Olykainen <Unknown>\n"
"PO-Revision-Date: 2011-07-09 07:20+0000\n"
"Last-Translator: ilya kislicyn <Unknown>\n"
"Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-31 05:58+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110
#: ../nova/scheduler/simple.py:122
msgid "No hosts found"
msgstr ""
msgstr "Узлы не найдены"
#: ../nova/exception.py:33
msgid "Unexpected error while running command."
@ -54,7 +54,7 @@ msgstr ""
#: ../nova/volume/api.py:47
#, python-format
msgid "Volume quota exceeded. You cannot create a volume of size %sG"
msgstr ""
msgstr "Квота тома превышена. Вы не можете создать том размером %sG"
#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
msgid "Volume status must be available"
@ -62,19 +62,19 @@ msgstr ""
#: ../nova/volume/api.py:98
msgid "Volume is already attached"
msgstr ""
msgstr "Том уже смотирован"
#: ../nova/volume/api.py:104
msgid "Volume is already detached"
msgstr ""
msgstr "Том уже отмонтирован"
#: ../nova/api/openstack/servers.py:72
msgid "Failed to read private ip"
msgstr ""
msgstr "Ошибка чтения приватного IP адреса"
#: ../nova/api/openstack/servers.py:79
msgid "Failed to read public ip(s)"
msgstr ""
msgstr "Ошибка чтения публичных IP адресов"
#: ../nova/api/openstack/servers.py:152
#, python-format
@ -83,7 +83,7 @@ msgstr ""
#: ../nova/api/openstack/servers.py:168
msgid "No keypairs defined"
msgstr ""
msgstr "Не определены ключевые пары"
#: ../nova/api/openstack/servers.py:238
#, python-format

2855
po/tl.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-03-19 06:19+0000\n"
"X-Generator: Launchpad (build 12559)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/scheduler/chance.py:37 ../nova/scheduler/zone.py:55
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: nova\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-02-21 10:03-0500\n"
"PO-Revision-Date: 2011-04-07 05:01+0000\n"
"Last-Translator: ben <Unknown>\n"
"PO-Revision-Date: 2011-06-14 14:44+0000\n"
"Last-Translator: chong <Unknown>\n"
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-04-08 05:28+0000\n"
"X-Generator: Launchpad (build 12735)\n"
"X-Launchpad-Export-Date: 2011-07-23 05:12+0000\n"
"X-Generator: Launchpad (build 13405)\n"
#: ../nova/twistd.py:266
#, python-format
@ -26,7 +26,7 @@ msgstr "启动 %s 中"
#: ../nova/scheduler/simple.py:75 ../nova/scheduler/simple.py:110
#: ../nova/scheduler/simple.py:122
msgid "No hosts found"
msgstr "找到主机"
msgstr "没有找到主机"
#: ../nova/exception.py:33
msgid "Unexpected error while running command."
@ -41,6 +41,11 @@ msgid ""
"Stdout: %(stdout)r\n"
"Stderr: %(stderr)r"
msgstr ""
"%(description)s\n"
"命令: %(cmd)s\n"
"退出代码: %(exit_code)s\n"
"标准输出: %(stdout)r\n"
"标准出错: %(stderr)r"
#: ../nova/exception.py:107
msgid "DB exception wrapped"
@ -309,17 +314,17 @@ msgstr ""
#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
#, python-format
msgid "Terminating instance %s"
msgstr ""
msgstr "正在结束实例 %s"
#: ../nova/compute/manager.py:255
#, python-format
msgid "Deallocating address %s"
msgstr ""
msgstr "取消分配地址 %s"
#: ../nova/compute/manager.py:268
#, python-format
msgid "trying to destroy already destroyed instance: %s"
msgstr ""
msgstr "尝试销毁已经销毁的实例: %s"
#: ../nova/compute/manager.py:282
#, python-format
@ -331,12 +336,12 @@ msgstr "重启虚拟机 %s"
msgid ""
"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
"expected: %(running)s)"
msgstr ""
msgstr "尝试重启没有在运行中实例: %(instance_id)s (状态: %(state)s 预料: %(running)s)"
#: ../nova/compute/manager.py:311
#, python-format
msgid "instance %s: snapshotting"
msgstr ""
msgstr "实例 %s: 快照中"
#: ../nova/compute/manager.py:316
#, python-format
@ -351,6 +356,8 @@ msgid ""
"trying to reset the password on a non-running instance: %(instance_id)s "
"(state: %(instance_state)s expected: %(expected_state)s)"
msgstr ""
"尝试对没有在运行的实例重置密码: %(instance_id)s (状态: %(instance_state)s 预料: "
"%(expected_state)s)"
#: ../nova/compute/manager.py:335
#, python-format

2848
po/zh_TW.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ function usage {
echo " -x, --stop Stop running tests after the first error or failure."
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
echo " -p, --pep8 Just run pep8"
echo " -c, --coverage Generate coverage report"
echo " -h, --help Print this usage message"
echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list"
echo ""
@ -29,6 +30,7 @@ function process_option {
-n|--no-recreate-db) let recreate_db=0;;
-f|--force) let force=1;;
-p|--pep8) let just_pep8=1;;
-c|--coverage) let coverage=1;;
-*) noseopts="$noseopts $1";;
*) noseargs="$noseargs $1"
esac
@ -43,12 +45,18 @@ noseargs=
noseopts=
wrapper=""
just_pep8=0
coverage=0
recreate_db=1
for arg in "$@"; do
process_option $arg
done
# If enabled, tell nose to collect coverage data
if [ $coverage -eq 1 ]; then
noseopts="$noseopts --with-coverage --cover-package=nova"
fi
function run_tests {
# Just run the test suites in current environment
${wrapper} $NOSETESTS 2> run_tests.log
@ -108,6 +116,11 @@ then
fi
fi
# Delete old coverage data from previous runs
if [ $coverage -eq 1 ]; then
${wrapper} coverage erase
fi
if [ $just_pep8 -eq 1 ]; then
run_pep8
exit
@ -126,3 +139,8 @@ run_tests || exit
if [ -z "$noseargs" ]; then
run_pep8
fi
if [ $coverage -eq 1 ]; then
echo "Generating coverage report in covhtml/"
${wrapper} coverage html -d covhtml -i
fi

View File

@ -21,6 +21,7 @@ On Windows we require pyWin32 installed on Python.
"""
import array
import gettext
import logging
import os
import platform
@ -30,6 +31,8 @@ import subprocess
import sys
import time
gettext.install('nova', unicode=1)
PLATFORM_WIN = 'win32'
PLATFORM_LINUX = 'linux2'
ARCH_32_BIT = '32bit'
@ -275,7 +278,8 @@ def _filter_duplicates(all_entries):
return final_list
def _set_rhel_networking(network_details=[]):
def _set_rhel_networking(network_details=None):
network_details = network_details or []
all_dns_servers = []
for network_detail in network_details:
mac_address, ip_address, subnet_mask, gateway, broadcast,\
@ -315,6 +319,46 @@ def _set_rhel_networking(network_details=[]):
_execute(['/sbin/service', 'network', 'restart'])
def _set_ubuntu_networking(network_details=None):
network_details = network_details or []
""" Set IPv4 network settings for Ubuntu """
all_dns_servers = []
for network_detail in network_details:
mac_address, ip_address, subnet_mask, gateway, broadcast,\
dns_servers = network_detail
all_dns_servers.extend(dns_servers)
adapter_name, current_ip_address = \
_get_linux_adapter_name_and_ip_address(mac_address)
if adapter_name and not ip_address == current_ip_address:
interface_file_name = \
'/etc/network/interfaces'
# Remove file
os.remove(interface_file_name)
# Touch file
_execute(['touch', interface_file_name])
interface_file = open(interface_file_name, 'w')
interface_file.write('\nauto %s' % adapter_name)
interface_file.write('\niface %s inet static' % adapter_name)
interface_file.write('\nbroadcast %s' % broadcast)
interface_file.write('\ngateway %s' % gateway)
interface_file.write('\nnetmask %s' % subnet_mask)
interface_file.write('\naddress %s' % ip_address)
interface_file.close()
if all_dns_servers:
dns_file_name = "/etc/resolv.conf"
os.remove(dns_file_name)
_execute(['touch', dns_file_name])
dns_file = open(dns_file_name, 'w')
dns_file.write("; generated by OpenStack guest tools")
unique_entries = _filter_duplicates(all_dns_servers)
for dns_server in unique_entries:
dns_file.write("\nnameserver %s" % dns_server)
dns_file.close()
print "\nRestarting networking....\n"
_execute(['/etc/init.d/networking', 'restart'])
def _linux_set_networking():
"""Set IP address for the Linux VM."""
vmware_tools_bin = None
@ -330,8 +374,13 @@ def _linux_set_networking():
cmd = [vmware_tools_bin, '--cmd', 'machine.id.get']
network_details = _parse_network_details(_execute(cmd,
check_exit_code=False))
# TODO(sateesh): For other distros like ubuntu, suse, debian, BSD, etc.
_set_rhel_networking(network_details)
# TODO(sateesh): For other distros like suse, debian, BSD, etc.
if(platform.dist()[0] == 'Ubuntu'):
_set_ubuntu_networking(network_details)
elif (platform.dist()[0] == 'redhat'):
_set_rhel_networking(network_details)
else:
logging.warn(_("Distro '%s' not supported") % platform.dist()[0])
else:
logging.warn(_("VMware Tools is not installed"))