summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Walker (Daviey) <DaveWalker@ubuntu.com>2011-08-06 19:08:08 +0100
committerDave Walker (Daviey) <DaveWalker@ubuntu.com>2011-08-06 19:08:08 +0100
commit43548ac4b2bf93dd6e6b1d0cbbc340ae005b4dbf (patch)
tree5dcf02ebbc9b93b4ea923a0c2364d3000c122aa5
parent2e3b199005d16ee3e35cd6c71b8512628e3631bc (diff)
parentc5cff2f02e887e518744f42f5a21605398a301a4 (diff)
downloadnova-43548ac4b2bf93dd6e6b1d0cbbc340ae005b4dbf.tar.gz
nova-43548ac4b2bf93dd6e6b1d0cbbc340ae005b4dbf.tar.xz
nova-43548ac4b2bf93dd6e6b1d0cbbc340ae005b4dbf.zip
Merge with trunk, resolving merge conflict
-rw-r--r--.bzrignore4
-rw-r--r--.mailmap1
-rw-r--r--Authors8
-rw-r--r--HACKING119
-rwxr-xr-xbin/nova-ajax-console-proxy10
-rwxr-xr-xbin/nova-dhcpbridge2
-rwxr-xr-xbin/nova-instancemonitor59
-rw-r--r--bin/nova-logspool1
-rwxr-xr-xbin/nova-manage566
-rwxr-xr-xbin/nova-objectstore2
-rwxr-xr-xcontrib/nova.sh2
-rw-r--r--doc/source/api/autoindex.rst3
-rw-r--r--doc/source/api/nova..compute.monitor.rst6
-rw-r--r--doc/source/api/nova..tests.test_twistd.rst6
-rw-r--r--doc/source/api/nova..twistd.rst6
-rw-r--r--doc/source/code.rst3
-rw-r--r--doc/source/devref/architecture.rst2
-rw-r--r--doc/source/devref/compute.rst13
-rw-r--r--doc/source/devref/development.environment.rst2
-rw-r--r--doc/source/devref/nova.rst20
-rw-r--r--nova/api/direct.py7
-rw-r--r--nova/api/ec2/__init__.py36
-rw-r--r--nova/api/ec2/apirequest.py2
-rw-r--r--nova/api/ec2/cloud.py142
-rw-r--r--nova/api/openstack/__init__.py29
-rw-r--r--nova/api/openstack/accounts.py6
-rw-r--r--nova/api/openstack/auth.py28
-rw-r--r--nova/api/openstack/backup_schedules.py9
-rw-r--r--nova/api/openstack/common.py164
-rw-r--r--nova/api/openstack/consoles.py10
-rw-r--r--nova/api/openstack/contrib/floating_ips.py4
-rw-r--r--nova/api/openstack/contrib/multinic.py5
-rw-r--r--nova/api/openstack/contrib/volumes.py58
-rw-r--r--nova/api/openstack/create_instance_helper.py252
-rw-r--r--nova/api/openstack/extensions.py51
-rw-r--r--nova/api/openstack/faults.py18
-rw-r--r--nova/api/openstack/flavors.py55
-rw-r--r--nova/api/openstack/image_metadata.py76
-rw-r--r--nova/api/openstack/images.py157
-rw-r--r--nova/api/openstack/ips.py67
-rw-r--r--nova/api/openstack/limits.py61
-rw-r--r--nova/api/openstack/server_metadata.py114
-rw-r--r--nova/api/openstack/servers.py517
-rw-r--r--nova/api/openstack/shared_ip_groups.py13
-rw-r--r--nova/api/openstack/users.py3
-rw-r--r--nova/api/openstack/versions.py373
-rw-r--r--nova/api/openstack/views/addresses.py26
-rw-r--r--nova/api/openstack/views/limits.py6
-rw-r--r--nova/api/openstack/views/servers.py48
-rw-r--r--nova/api/openstack/views/versions.py55
-rw-r--r--nova/api/openstack/wsgi.py70
-rw-r--r--nova/api/openstack/zones.py8
-rw-r--r--nova/auth/dbdriver.py2
-rw-r--r--nova/auth/manager.py14
-rw-r--r--nova/cloudpipe/pipelib.py33
-rw-r--r--nova/compute/api.py61
-rw-r--r--nova/compute/instance_types.py11
-rw-r--r--nova/compute/manager.py227
-rw-r--r--nova/compute/monitor.py435
-rw-r--r--nova/context.py95
-rw-r--r--nova/db/api.py28
-rw-r--r--nova/db/sqlalchemy/api.py109
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py44
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/034_change_instance_id_in_migrations.py52
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/035_secondary_dns.py38
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/036_change_flavor_id_in_migrations.py72
-rw-r--r--nova/db/sqlalchemy/models.py43
-rw-r--r--nova/exception.py26
-rw-r--r--nova/flags.py7
-rw-r--r--nova/image/__init__.py3
-rw-r--r--nova/image/fake.py41
-rw-r--r--nova/image/glance.py82
-rw-r--r--nova/image/s3.py16
-rw-r--r--nova/log.py5
-rw-r--r--nova/network/api.py28
-rw-r--r--nova/network/linux_net.py41
-rw-r--r--nova/network/manager.py368
-rw-r--r--nova/network/vmwareapi_net.py82
-rw-r--r--nova/network/xenapi_net.py87
-rw-r--r--nova/notifier/api.py4
-rw-r--r--nova/rpc/__init__.py66
-rw-r--r--nova/rpc/amqp.py (renamed from nova/rpc.py)23
-rw-r--r--nova/rpc/common.py23
-rw-r--r--nova/scheduler/least_cost.py1
-rw-r--r--nova/scheduler/zone_aware_scheduler.py2
-rw-r--r--nova/service.py28
-rw-r--r--nova/test.py59
-rw-r--r--nova/tests/__init__.py6
-rw-r--r--nova/tests/api/openstack/__init__.py3
-rw-r--r--nova/tests/api/openstack/contrib/test_floating_ips.py10
-rw-r--r--nova/tests/api/openstack/contrib/test_multinic_xs.py8
-rw-r--r--nova/tests/api/openstack/fakes.py43
-rw-r--r--nova/tests/api/openstack/test_accounts.py15
-rw-r--r--nova/tests/api/openstack/test_adminapi.py22
-rw-r--r--nova/tests/api/openstack/test_auth.py42
-rw-r--r--nova/tests/api/openstack/test_common.py199
-rw-r--r--nova/tests/api/openstack/test_extensions.py239
-rw-r--r--nova/tests/api/openstack/test_faults.py112
-rw-r--r--nova/tests/api/openstack/test_flavors.py379
-rw-r--r--nova/tests/api/openstack/test_flavors_extra_specs.py (renamed from nova/tests/api/openstack/extensions/test_flavors_extra_specs.py)69
-rw-r--r--nova/tests/api/openstack/test_image_metadata.py249
-rw-r--r--nova/tests/api/openstack/test_images.py502
-rw-r--r--nova/tests/api/openstack/test_limits.py218
-rw-r--r--nova/tests/api/openstack/test_server_actions.py1019
-rw-r--r--nova/tests/api/openstack/test_server_metadata.py278
-rw-r--r--nova/tests/api/openstack/test_servers.py2078
-rw-r--r--nova/tests/api/openstack/test_shared_ip_groups.py13
-rw-r--r--nova/tests/api/openstack/test_users.py15
-rw-r--r--nova/tests/api/openstack/test_versions.py891
-rw-r--r--nova/tests/api/openstack/test_wsgi.py7
-rw-r--r--nova/tests/api/openstack/test_zones.py26
-rw-r--r--nova/tests/db/fakes.py8
-rw-r--r--nova/tests/fake_flags.py1
-rw-r--r--nova/tests/glance/stubs.py5
-rw-r--r--nova/tests/hyperv_unittest.py14
-rw-r--r--nova/tests/image/test_glance.py3
-rw-r--r--nova/tests/image/test_s3.py10
-rw-r--r--nova/tests/integrated/integrated_helpers.py4
-rw-r--r--nova/tests/integrated/test_extensions.py5
-rw-r--r--nova/tests/integrated/test_login.py4
-rw-r--r--nova/tests/integrated/test_servers.py6
-rw-r--r--nova/tests/integrated/test_volumes.py5
-rw-r--r--nova/tests/integrated/test_xml.py5
-rw-r--r--nova/tests/scheduler/test_host_filter.py12
-rw-r--r--nova/tests/scheduler/test_least_cost_scheduler.py23
-rw-r--r--nova/tests/scheduler/test_scheduler.py29
-rw-r--r--nova/tests/scheduler/test_zone_aware_scheduler.py18
-rw-r--r--nova/tests/test_access.py21
-rw-r--r--nova/tests/test_adminapi.py18
-rw-r--r--nova/tests/test_api.py82
-rw-r--r--nova/tests/test_auth.py23
-rw-r--r--nova/tests/test_cloud.py142
-rw-r--r--nova/tests/test_compute.py139
-rw-r--r--nova/tests/test_console.py19
-rw-r--r--nova/tests/test_db_api.py78
-rw-r--r--nova/tests/test_host_filter.py12
-rw-r--r--nova/tests/test_image.py134
-rw-r--r--nova/tests/test_instance_types_extra_specs.py8
-rw-r--r--nova/tests/test_ipv6.py3
-rw-r--r--nova/tests/test_libvirt.py270
-rw-r--r--nova/tests/test_network.py40
-rw-r--r--nova/tests/test_nova_manage.py82
-rw-r--r--nova/tests/test_objectstore.py27
-rw-r--r--nova/tests/test_quota.py107
-rw-r--r--nova/tests/test_rpc.py63
-rw-r--r--nova/tests/test_rpc_amqp.py88
-rw-r--r--nova/tests/test_service.py171
-rw-r--r--nova/tests/test_skip_examples.py47
-rw-r--r--nova/tests/test_test.py13
-rw-r--r--nova/tests/test_twistd.py53
-rw-r--r--nova/tests/test_utils.py78
-rw-r--r--nova/tests/test_vmwareapi.py115
-rw-r--r--nova/tests/test_xenapi.py317
-rw-r--r--nova/tests/vmwareapi/db_fakes.py10
-rw-r--r--nova/tests/vmwareapi/stubs.py7
-rw-r--r--nova/tests/xenapi/stubs.py6
-rw-r--r--nova/twistd.py267
-rw-r--r--nova/utils.py115
-rw-r--r--nova/virt/driver.py56
-rw-r--r--nova/virt/fake.py27
-rw-r--r--nova/virt/hyperv.py13
-rw-r--r--nova/virt/images.py6
-rw-r--r--nova/virt/libvirt.xml.template24
-rw-r--r--nova/virt/libvirt/connection.py220
-rw-r--r--nova/virt/libvirt/firewall.py11
-rw-r--r--nova/virt/libvirt/netutils.py19
-rw-r--r--nova/virt/libvirt/vif.py135
-rw-r--r--nova/virt/vif.py30
-rw-r--r--nova/virt/vmwareapi/fake.py10
-rw-r--r--nova/virt/vmwareapi/network_utils.py29
-rw-r--r--nova/virt/vmwareapi/vif.py95
-rw-r--r--nova/virt/vmwareapi/vm_util.py33
-rw-r--r--nova/virt/vmwareapi/vmops.py58
-rw-r--r--nova/virt/vmwareapi_conn.py21
-rw-r--r--nova/virt/xenapi/vif.py140
-rw-r--r--nova/virt/xenapi/vm_utils.py200
-rw-r--r--nova/virt/xenapi/vmops.py156
-rw-r--r--nova/virt/xenapi_conn.py59
-rw-r--r--nova/vnc/proxy.py4
-rw-r--r--nova/volume/api.py2
-rw-r--r--nova/wsgi.py12
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/agent4
-rwxr-xr-x[-rw-r--r--]plugins/xenserver/xenapi/etc/xapi.d/plugins/glance42
-rwxr-xr-x[-rw-r--r--]plugins/xenserver/xenapi/etc/xapi.d/plugins/migration0
-rwxr-xr-x[-rw-r--r--]plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore0
-rw-r--r--[-rwxr-xr-x]plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py0
-rwxr-xr-x[-rw-r--r--]plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost0
-rw-r--r--po/ast.po63
-rw-r--r--po/cs.po63
-rw-r--r--po/da.po63
-rw-r--r--po/de.po104
-rw-r--r--po/en_AU.po2789
-rw-r--r--po/en_GB.po2814
-rw-r--r--po/es.po188
-rw-r--r--po/fr.po2931
-rw-r--r--po/it.po64
-rw-r--r--po/ja.po533
-rw-r--r--po/nova.pot59
-rw-r--r--po/pt_BR.po64
-rw-r--r--po/ru.po81
-rw-r--r--po/tl.po2796
-rw-r--r--po/uk.po63
-rw-r--r--po/zh_CN.po86
-rw-r--r--po/zh_TW.po2789
-rwxr-xr-xrun_tests.sh18
-rw-r--r--setup.py1
-rw-r--r--smoketests/test_netadmin.py3
-rw-r--r--smoketests/test_sysadmin.py33
-rw-r--r--tools/esx/guest_tool.py55
-rw-r--r--tools/eventlet-patch24
-rw-r--r--tools/install_venv.py9
-rw-r--r--tools/pip-requires4
212 files changed, 25341 insertions, 6473 deletions
diff --git a/.bzrignore b/.bzrignore
index 14d8028f7..91277d100 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -13,3 +13,7 @@ nova/vcsversion.py
clean.sqlite
run_tests.log
tests.sqlite
+nova/tests/instance-*
+tags
+.coverage
+covhtml
diff --git a/.mailmap b/.mailmap
index ff304c891..76e7bc669 100644
--- a/.mailmap
+++ b/.mailmap
@@ -14,6 +14,7 @@
<code@term.ie> <github@anarkystic.com>
<code@term.ie> <termie@preciousroy.local>
<corywright@gmail.com> <cory.wright@rackspace.com>
+<dan@nicira.com> <danwent@dan-xs3-cs>
<devin.carlen@gmail.com> <devcamcar@illian.local>
<ewan.mellor@citrix.com> <emellor@silver>
<itoumsn@nttdata.co.jp> <itoumsn@shayol>
diff --git a/Authors b/Authors
index 8ffb7d8d4..b216873df 100644
--- a/Authors
+++ b/Authors
@@ -1,3 +1,5 @@
+Adam Gandelman <adamg@canonical.com>
+Adam Johnson <adjohn@gmail.com>
Alex Meade <alex.meade@rackspace.com>
Alexander Sakhnov <asakhnov@mirantis.com>
Andrey Brindeyev <abrindeyev@griddynamics.com>
@@ -7,6 +9,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>
@@ -18,6 +21,7 @@ Christian Berendt <berendt@b1-systems.de>
Chuck Short <zulcss@ubuntu.com>
Cory Wright <corywright@gmail.com>
Dan Prince <dan.prince@rackspace.com>
+Dan Wendlandt <dan@nicira.com>
Dave Walker <DaveWalker@ubuntu.com>
David Pravec <David.Pravec@danix.org>
Dean Troyer <dtroyer@gmail.com>
@@ -60,9 +64,11 @@ Kirill Shileev <kshileev@gmail.com>
Koji Iida <iida.koji@lab.ntt.co.jp>
Lorin Hochstein <lorin@isi.edu>
Lvov Maxim <usrleon@gmail.com>
+Mandell Degerness <mdegerne@gmail.com>
Mark Washenberger <mark.washenberger@rackspace.com>
Masanori Itoh <itoumsn@nttdata.co.jp>
Matt Dietz <matt.dietz@rackspace.com>
+Matthew Hooker <matt@cloudscaling.com>
Michael Gundlach <michael.gundlach@rackspace.com>
Mike Scherbakov <mihgen@gmail.com>
Mohammed Naser <mnaser@vexxhost.com>
@@ -82,6 +88,7 @@ Rick Harris <rconradharris@gmail.com>
Rob Kost <kost@isi.edu>
Ryan Lane <rlane@wikimedia.org>
Ryan Lucio <rlucio@internap.com>
+Ryu Ishimoto <ryu@midokura.jp>
Salvatore Orlando <salvatore.orlando@eu.citrix.com>
Sandy Walsh <sandy.walsh@rackspace.com>
Sateesh Chodapuneedi <sateesh.chodapuneedi@citrix.com>
@@ -100,3 +107,4 @@ Yoshiaki Tamura <yoshi@midokura.jp>
Youcef Laribi <Youcef.Laribi@eu.citrix.com>
Yuriy Taraday <yorik.sar@gmail.com>
Zhixue Wu <Zhixue.Wu@citrix.com>
+Zed Shaw <zedshaw@zedshaw.com>
diff --git a/HACKING b/HACKING
index 2f364c894..232a353fd 100644
--- a/HACKING
+++ b/HACKING
@@ -5,12 +5,23 @@ Step 1: Read http://www.python.org/dev/peps/pep-0008/
Step 2: Read http://www.python.org/dev/peps/pep-0008/ again
Step 3: Read on
+
+General
+-------
+- Put two newlines between top-level code (funcs, classes, etc)
+- Put one newline between methods in classes and anywhere else
+- Do not write "except:", use "except Exception:" at the very least
+- Include your name with TODOs as in "#TODO(termie)"
+- Do not name anything the same name as a built-in or reserved word
+
+
Imports
-------
-- thou shalt not import objects, only modules
-- thou shalt not import more than one module per line
-- thou shalt not make relative imports
-- thou shalt organize your imports according to the following template
+- Do not import objects, only modules
+- Do not import more than one module per line
+- Do not make relative imports
+- Order your imports by the full module path
+- Organize your imports according to the following template
::
# vim: tabstop=4 shiftwidth=4 softtabstop=4
@@ -22,16 +33,6 @@ Imports
{{begin your code}}
-General
--------
-- thou shalt put two newlines twixt toplevel code (funcs, classes, etc)
-- thou shalt put one newline twixt methods in classes and anywhere else
-- thou shalt not write "except:", use "except Exception:" at the very least
-- thou shalt include your name with TODOs as in "TODO(termie)"
-- thou shalt not name anything the same name as a builtin or reserved word
-- thou shalt not violate causality in our time cone, or else
-
-
Human Alphabetical Order Examples
---------------------------------
::
@@ -42,11 +43,13 @@ Human Alphabetical Order Examples
import time
import unittest
- from nova import flags
- from nova import test
+ import nova.api.ec2
+ from nova.api import openstack
from nova.auth import users
- from nova.endpoint import api
+ import nova.flags
from nova.endpoint import cloud
+ from nova import test
+
Docstrings
----------
@@ -70,6 +73,88 @@ Docstrings
:param foo: the foo parameter
:param bar: the bar parameter
+ :returns: return_type -- description of the return value
:returns: description of the return value
+ :raises: AttributeError, KeyError
"""
+
+
+Dictionaries/Lists
+------------------
+ If a dictionary (dict) or list object is longer than 80 characters, its
+ items should be split with newlines. Embedded iterables should have their
+ items indented. Additionally, the last item in the dictionary should have
+ a trailing comma. This increases readability and simplifies future diffs.
+
+ Example:
+
+ my_dictionary = {
+ "image": {
+ "name": "Just a Snapshot",
+ "size": 2749573,
+ "properties": {
+ "user_id": 12,
+ "arch": "x86_64",
+ },
+ "things": [
+ "thing_one",
+ "thing_two",
+ ],
+ "status": "ACTIVE",
+ },
+ }
+
+
+Calling Methods
+---------------
+ Calls to methods 80 characters or longer should format each argument with
+ newlines. This is not a requirement, but a guideline.
+
+ unnecessarily_long_function_name('string one',
+ 'string two',
+ kwarg1=constants.ACTIVE,
+ kwarg2=['a', 'b', 'c'])
+
+
+ Rather than constructing parameters inline, it is better to break things up:
+
+ list_of_strings = [
+ 'what_a_long_string',
+ 'not as long',
+ ]
+
+ dict_of_numbers = {
+ 'one': 1,
+ 'two': 2,
+ 'twenty four': 24,
+ }
+
+ object_one.call_a_method('string three',
+ 'string four',
+ kwarg1=list_of_strings,
+ kwarg2=dict_of_numbers)
+
+
+Internationalization (i18n) Strings
+-----------------------------------
+ In order to support multiple languages, we have a mechanism to support
+ automatic translations of exception and log strings.
+
+ Example:
+ msg = _("An error occurred")
+ raise HTTPBadRequest(explanation=msg)
+
+ If you have a variable to place within the string, first internationalize
+ the template string then do the replacement.
+
+ Example:
+ msg = _("Missing parameter: %s") % ("flavor",)
+ LOG.error(msg)
+
+ If you have multiple variables to place in the string, use keyword
+ parameters. This helps our translators reorder parameters when needed.
+
+ Example:
+ msg = _("The server with id %(s_id)s has no key %(m_key)s")
+ LOG.error(msg % {"s_id": "1234", "m_key": "imageId"})
diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy
index 21cf68007..2329581a2 100755
--- a/bin/nova-ajax-console-proxy
+++ b/bin/nova-ajax-console-proxy
@@ -114,11 +114,11 @@ class AjaxConsoleProxy(object):
AjaxConsoleProxy.tokens[kwargs['token']] = \
{'args': kwargs, 'last_activity': time.time()}
- conn = rpc.Connection.instance(new=True)
- consumer = rpc.TopicAdapterConsumer(
- connection=conn,
- proxy=TopicProxy,
- topic=FLAGS.ajax_console_proxy_topic)
+ conn = rpc.create_connection(new=True)
+ consumer = rpc.create_consumer(
+ conn,
+ FLAGS.ajax_console_proxy_topic,
+ TopicProxy)
def delete_expired_tokens():
now = time.time()
diff --git a/bin/nova-dhcpbridge b/bin/nova-dhcpbridge
index 6d9d85896..325642d52 100755
--- a/bin/nova-dhcpbridge
+++ b/bin/nova-dhcpbridge
@@ -91,7 +91,7 @@ def init_leases(interface):
"""Get the list of hosts for an interface."""
ctxt = context.get_admin_context()
network_ref = db.network_get_by_bridge(ctxt, interface)
- return linux_net.get_dhcp_leases(ctxt, network_ref['id'])
+ return linux_net.get_dhcp_leases(ctxt, network_ref)
def main():
diff --git a/bin/nova-instancemonitor b/bin/nova-instancemonitor
deleted file mode 100755
index b9d4e49d7..000000000
--- a/bin/nova-instancemonitor
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
- Daemon for Nova RRD based instance resource monitoring.
-"""
-
-import gettext
-import os
-import sys
-from twisted.application import service
-
-# If ../nova/__init__.py exists, add ../ to Python search path, so that
-# it will override what happens to be installed in /usr/(local/)lib/python...
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
- sys.path.insert(0, possible_topdir)
-
-gettext.install('nova', unicode=1)
-
-from nova import log as logging
-from nova import utils
-from nova import twistd
-from nova.compute import monitor
-
-LOG = logging.getLogger('nova.instancemonitor')
-
-
-if __name__ == '__main__':
- utils.default_flagfile()
- twistd.serve(__file__)
-
-if __name__ == '__builtin__':
- LOG.warn(_('Starting instance monitor'))
- # pylint: disable=C0103
- monitor = monitor.InstanceMonitor()
-
- # This is the parent service that twistd will be looking for when it
- # parses this file, return it so that we can get it into globals below
- application = service.Application('nova-instancemonitor')
- monitor.setServiceParent(application)
diff --git a/bin/nova-logspool b/bin/nova-logspool
index 097459b12..a876f4c71 100644
--- a/bin/nova-logspool
+++ b/bin/nova-logspool
@@ -81,7 +81,6 @@ class LogReader(object):
if level == 'ERROR':
self.handle_logged_error(line)
elif level == '[-]' and self.last_error:
- # twisted stack trace line
clean_line = " ".join(line.split(" ")[6:])
self.last_error.trace = self.last_error.trace + clean_line
else:
diff --git a/bin/nova-manage b/bin/nova-manage
index b892d958a..40f22c19c 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -56,11 +56,13 @@
import gettext
import glob
import json
+import math
import netaddr
import os
import sys
import time
+from optparse import OptionParser
# If ../nova/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
@@ -103,6 +105,14 @@ flags.DEFINE_flag(flags.HelpshortFlag())
flags.DEFINE_flag(flags.HelpXMLFlag())
+# Decorators for actions
+def args(*args, **kwargs):
+ def _decorator(func):
+ func.__dict__.setdefault('options', []).insert(0, (args, kwargs))
+ return func
+ return _decorator
+
+
def param2id(object_id):
"""Helper function to convert various id types to internal id.
args: [object_id], e.g. 'vol-0000000a' or 'volume-0000000a' or '10'
@@ -120,10 +130,11 @@ class VpnCommands(object):
self.manager = manager.AuthManager()
self.pipe = pipelib.CloudPipe()
+ @args('--project', dest="project", metavar='<Project name>',
+ help='Project name')
def list(self, project=None):
- """Print a listing of the VPN data for one or all projects.
+ """Print a listing of the VPN data for one or all projects."""
- args: [project=all]"""
print "%-12s\t" % 'project',
print "%-20s\t" % 'ip:port',
print "%-20s\t" % 'private_ip',
@@ -165,17 +176,23 @@ class VpnCommands(object):
self.pipe.launch_vpn_instance(p.id)
time.sleep(10)
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
def run(self, project_id):
"""Start the VPN for a given project."""
self.pipe.launch_vpn_instance(project_id)
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
+ @args('--ip', dest="ip", metavar='<IP Address>', help='IP Address')
+ @args('--port', dest="port", metavar='<Port>', help='Port')
def change(self, project_id, ip, port):
"""Change the ip and port for a vpn.
this will update all networks associated with a project
not sure if that's the desired behavior or not, patches accepted
- args: project, ip, port"""
+ """
# TODO(tr3buchet): perhaps this shouldn't update all networks
# associated with a project in the future
project = self.manager.get_project(project_id)
@@ -210,10 +227,10 @@ class ShellCommands(object):
Falls back to Python shell if unavailable"""
self.run('python')
+ @args('--shell', dest="shell", metavar='<bpython|ipython|python >',
+ help='Python shell')
def run(self, shell=None):
- """Runs a Python interactive interpreter.
-
- args: [shell=bpython]"""
+ """Runs a Python interactive interpreter."""
if not shell:
shell = 'bpython'
@@ -247,6 +264,7 @@ class ShellCommands(object):
readline.parse_and_bind("tab:complete")
code.interact()
+ @args('--path', dest='path', metavar='<path>', help='Script path')
def script(self, path):
"""Runs the script from the specifed path with flags set properly.
arguments: path"""
@@ -259,10 +277,13 @@ class RoleCommands(object):
def __init__(self):
self.manager = manager.AuthManager()
+ @args('--user', dest="user", metavar='<user name>', help='User name')
+ @args('--role', dest="role", metavar='<user role>', help='User role')
+ @args('--project', dest="project", metavar='<Project name>',
+ help='Project name')
def add(self, user, role, project=None):
"""adds role to user
- if project is specified, adds project specific role
- arguments: user, role [project]"""
+ if project is specified, adds project specific role"""
if project:
projobj = self.manager.get_project(project)
if not projobj.has_member(user):
@@ -270,17 +291,23 @@ class RoleCommands(object):
return
self.manager.add_role(user, role, project)
+ @args('--user', dest="user", metavar='<user name>', help='User name')
+ @args('--role', dest="role", metavar='<user role>', help='User role')
+ @args('--project', dest="project", metavar='<Project name>',
+ help='Project name')
def has(self, user, role, project=None):
"""checks to see if user has role
if project is specified, returns True if user has
- the global role and the project role
- arguments: user, role [project]"""
+ the global role and the project role"""
print self.manager.has_role(user, role, project)
+ @args('--user', dest="user", metavar='<user name>', help='User name')
+ @args('--role', dest="role", metavar='<user role>', help='User role')
+ @args('--project', dest="project", metavar='<Project name>',
+ help='Project name')
def remove(self, user, role, project=None):
"""removes role from user
- if project is specified, removes project specific role
- arguments: user, role [project]"""
+ if project is specified, removes project specific role"""
self.manager.remove_role(user, role, project)
@@ -304,32 +331,37 @@ class UserCommands(object):
def __init__(self):
self.manager = manager.AuthManager()
+ @args('--name', dest="name", metavar='<admin name>', help='Admin name')
+ @args('--access', dest="access", metavar='<access>', help='Access')
+ @args('--secret', dest="secret", metavar='<secret>', help='Secret')
def admin(self, name, access=None, secret=None):
- """creates a new admin and prints exports
- arguments: name [access] [secret]"""
+ """creates a new admin and prints exports"""
try:
user = self.manager.create_user(name, access, secret, True)
except exception.DBError, e:
_db_error(e)
self._print_export(user)
+ @args('--name', dest="name", metavar='<name>', help='User name')
+ @args('--access', dest="access", metavar='<access>', help='Access')
+ @args('--secret', dest="secret", metavar='<secret>', help='Secret')
def create(self, name, access=None, secret=None):
- """creates a new user and prints exports
- arguments: name [access] [secret]"""
+ """creates a new user and prints exports"""
try:
user = self.manager.create_user(name, access, secret, False)
except exception.DBError, e:
_db_error(e)
self._print_export(user)
+ @args('--name', dest="name", metavar='<name>', help='User name')
def delete(self, name):
"""deletes an existing user
arguments: name"""
self.manager.delete_user(name)
+ @args('--name', dest="name", metavar='<admin name>', help='User name')
def exports(self, name):
- """prints access and secrets for user in export format
- arguments: name"""
+ """prints access and secrets for user in export format"""
user = self.manager.get_user(name)
if user:
self._print_export(user)
@@ -337,11 +369,17 @@ class UserCommands(object):
print "User %s doesn't exist" % name
def list(self):
- """lists all users
- arguments: <none>"""
+ """lists all users"""
for user in self.manager.get_users():
print user.name
+ @args('--name', dest="name", metavar='<name>', help='User name')
+ @args('--access', dest="access_key", metavar='<access>',
+ help='Access key')
+ @args('--secret', dest="secret_key", metavar='<secret>',
+ help='Secret key')
+ @args('--is_admin', dest='is_admin', metavar="<'T'|'F'>",
+ help='Is admin?')
def modify(self, name, access_key, secret_key, is_admin):
"""update a users keys & admin flag
arguments: accesskey secretkey admin
@@ -355,9 +393,11 @@ class UserCommands(object):
is_admin = False
self.manager.modify_user(name, access_key, secret_key, is_admin)
+ @args('--name', dest="user_id", metavar='<name>', help='User name')
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
def revoke(self, user_id, project_id=None):
- """revoke certs for a user
- arguments: user_id [project_id]"""
+ """revoke certs for a user"""
if project_id:
crypto.revoke_certs_by_user_and_project(user_id, project_id)
else:
@@ -370,45 +410,62 @@ class ProjectCommands(object):
def __init__(self):
self.manager = manager.AuthManager()
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
+ @args('--user', dest="user_id", metavar='<name>', help='User name')
def add(self, project_id, user_id):
- """Adds user to project
- arguments: project_id user_id"""
+ """Adds user to project"""
try:
self.manager.add_to_project(user_id, project_id)
except exception.UserNotFound as ex:
print ex
raise
+ @args('--project', dest="name", metavar='<Project name>',
+ help='Project name')
+ @args('--user', dest="project_manager", metavar='<user>',
+ help='Project manager')
+ @args('--desc', dest="description", metavar='<description>',
+ help='Description')
def create(self, name, project_manager, description=None):
- """Creates a new project
- arguments: name project_manager [description]"""
+ """Creates a new project"""
try:
self.manager.create_project(name, project_manager, description)
except exception.UserNotFound as ex:
print ex
raise
+ @args('--project', dest="name", metavar='<Project name>',
+ help='Project name')
+ @args('--user', dest="project_manager", metavar='<user>',
+ help='Project manager')
+ @args('--desc', dest="description", metavar='<description>',
+ help='Description')
def modify(self, name, project_manager, description=None):
- """Modifies a project
- arguments: name project_manager [description]"""
+ """Modifies a project"""
try:
self.manager.modify_project(name, project_manager, description)
except exception.UserNotFound as ex:
print ex
raise
+ @args('--project', dest="name", metavar='<Project name>',
+ help='Project name')
def delete(self, name):
- """Deletes an existing project
- arguments: name"""
+ """Deletes an existing project"""
try:
self.manager.delete_project(name)
except exception.ProjectNotFound as ex:
print ex
raise
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
+ @args('--user', dest="user_id", metavar='<name>', help='User name')
+ @args('--file', dest="filename", metavar='<filename>',
+ help='File name(Default: novarc)')
def environment(self, project_id, user_id, filename='novarc'):
- """Exports environment variables to an sourcable file
- arguments: project_id user_id [filename='novarc]"""
+ """Exports environment variables to an sourcable file"""
try:
rc = self.manager.get_environment_rc(user_id, project_id)
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
@@ -420,15 +477,18 @@ class ProjectCommands(object):
with open(filename, 'w') as f:
f.write(rc)
+ @args('--user', dest="username", metavar='<username>', help='User name')
def list(self, username=None):
- """Lists all projects
- arguments: [username]"""
+ """Lists all projects"""
for project in self.manager.get_projects(username):
print project.name
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
+ @args('--key', dest="key", metavar='<key>', help='Key')
+ @args('--value', dest="value", metavar='<value>', help='Value')
def quota(self, project_id, key=None, value=None):
- """Set or display quotas for project
- arguments: project_id [key] [value]"""
+ """Set or display quotas for project"""
ctxt = context.get_admin_context()
if key:
if value.lower() == 'unlimited':
@@ -443,18 +503,21 @@ class ProjectCommands(object):
value = 'unlimited'
print '%s: %s' % (key, value)
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
+ @args('--user', dest="user_id", metavar='<name>', help='User name')
def remove(self, project_id, user_id):
- """Removes user from project
- arguments: project_id user_id"""
+ """Removes user from project"""
try:
self.manager.remove_from_project(user_id, project_id)
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
print ex
raise
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
def scrub(self, project_id):
- """Deletes data associated with project
- arguments: project_id"""
+ """Deletes data associated with project"""
admin_context = context.get_admin_context()
networks = db.project_get_networks(admin_context, project_id)
for network in networks:
@@ -463,9 +526,13 @@ class ProjectCommands(object):
for group in groups:
db.security_group_destroy(admin_context, group['id'])
+ @args('--project', dest="project_id", metavar='<Project name>',
+ help='Project name')
+ @args('--user', dest="user_id", metavar='<name>', help='User name')
+ @args('--file', dest="filename", metavar='<filename>',
+ help='File name(Default: nova.zip)')
def zipfile(self, project_id, user_id, filename='nova.zip'):
- """Exports credentials for project to a zip file
- arguments: project_id user_id [filename='nova.zip]"""
+ """Exports credentials for project to a zip file"""
try:
zip_file = self.manager.get_credentials(user_id, project_id)
if filename == "-":
@@ -479,12 +546,12 @@ class ProjectCommands(object):
except db.api.NoMoreNetworks:
print _('No more networks available. If this is a new '
'installation, you need\nto call something like this:\n\n'
- ' nova-manage network create 10.0.0.0/8 10 64\n\n')
+ ' nova-manage network create pvt 10.0.0.0/8 10 64\n\n')
except exception.ProcessExecutionError, e:
print e
- print _("The above error may show that the certificate db has not "
- "been created.\nPlease create a database by running a "
- "nova-api server on this host.")
+ print _("The above error may show that the certificate db has "
+ "not been created.\nPlease create a database by running "
+ "a nova-api server on this host.")
AccountCommands = ProjectCommands
@@ -492,15 +559,16 @@ AccountCommands = ProjectCommands
class FixedIpCommands(object):
"""Class for managing fixed ip."""
+ @args('--host', dest="host", metavar='<host>', help='Host')
def list(self, host=None):
- """Lists all fixed ips (optionally by host) arguments: [host]"""
+ """Lists all fixed ips (optionally by host)"""
ctxt = context.get_admin_context()
try:
if host is None:
fixed_ips = db.fixed_ip_get_all(ctxt)
else:
- fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host)
+ fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host)
except exception.NotFound as ex:
print "error: %s" % ex
sys.exit(2)
@@ -518,33 +586,58 @@ class FixedIpCommands(object):
instance = fixed_ip['instance']
hostname = instance['hostname']
host = instance['host']
- mac_address = fixed_ip['mac_address']['address']
+ mac_address = fixed_ip['virtual_interface']['address']
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (
fixed_ip['network']['cidr'],
fixed_ip['address'],
mac_address, hostname, host)
+ @args('--address', dest="address", metavar='<ip address>',
+ help='IP address')
+ def reserve(self, address):
+ """Mark fixed ip as reserved
+ arguments: address"""
+ self._set_reserved(address, True)
+
+ @args('--address', dest="address", metavar='<ip address>',
+ help='IP address')
+ def unreserve(self, address):
+ """Mark fixed ip as free to use
+ arguments: address"""
+ self._set_reserved(address, False)
+
+ def _set_reserved(self, address, reserved):
+ ctxt = context.get_admin_context()
+
+ try:
+ fixed_ip = db.fixed_ip_get_by_address(ctxt, address)
+ db.fixed_ip_update(ctxt, fixed_ip['address'],
+ {'reserved': reserved})
+ except exception.NotFound as ex:
+ print "error: %s" % ex
+ sys.exit(2)
+
class FloatingIpCommands(object):
"""Class for managing floating ip."""
+ @args('--ip_range', dest="range", metavar='<range>', help='IP range')
def create(self, range):
- """Creates floating ips for zone by range
- arguments: ip_range"""
+ """Creates floating ips for zone by range"""
for address in netaddr.IPNetwork(range):
db.floating_ip_create(context.get_admin_context(),
{'address': str(address)})
+ @args('--ip_range', dest="ip_range", metavar='<range>', help='IP range')
def delete(self, ip_range):
- """Deletes floating ips by range
- arguments: range"""
+ """Deletes floating ips by range"""
for address in netaddr.IPNetwork(ip_range):
db.floating_ip_destroy(context.get_admin_context(),
str(address))
+ @args('--host', dest="host", metavar='<host>', help='Host')
def list(self, host=None):
"""Lists all floating ips (optionally by host)
- arguments: [host]
Note: if host is given, only active floating IPs are returned"""
ctxt = context.get_admin_context()
if host is None:
@@ -563,78 +656,131 @@ class FloatingIpCommands(object):
class NetworkCommands(object):
"""Class for managing networks."""
- def create(self, label=None, fixed_range=None, num_networks=None,
- network_size=None, vlan_start=None,
+ @args('--label', dest="label", metavar='<label>',
+ help='Label for network (ex: public)')
+ @args('--fixed_range_v4', dest="fixed_range_v4", metavar='<x.x.x.x/yy>',
+ help='IPv4 subnet (ex: 10.0.0.0/8)')
+ @args('--num_networks', dest="num_networks", metavar='<number>',
+ help='Number of networks to create')
+ @args('--network_size', dest="network_size", metavar='<number>',
+ help='Number of IPs per network')
+ @args('--vlan', dest="vlan_start", metavar='<vlan id>', help='vlan id')
+ @args('--vpn', dest="vpn_start", help='vpn start')
+ @args('--fixed_range_v6', dest="fixed_range_v6",
+ help='IPv6 subnet (ex: fe80::/64')
+ @args('--gateway_v6', dest="gateway_v6", help='ipv6 gateway')
+ @args('--bridge', dest="bridge",
+ metavar='<bridge>',
+ help='VIFs on this network are connected to this bridge')
+ @args('--bridge_interface', dest="bridge_interface",
+ metavar='<bridge interface>',
+ help='the bridge is connected to this interface')
+ @args('--multi_host', dest="multi_host", metavar="<'T'|'F'>",
+ help='Multi host')
+ @args('--dns1', dest="dns1", metavar="<DNS Address>", help='First DNS')
+ @args('--dns2', dest="dns2", metavar="<DNS Address>", help='Second DNS')
+ def create(self, label=None, fixed_range_v4=None, num_networks=None,
+ network_size=None, multi_host=None, vlan_start=None,
vpn_start=None, fixed_range_v6=None, gateway_v6=None,
- flat_network_bridge=None, bridge_interface=None):
- """Creates fixed ips for host by range
- arguments: label, fixed_range, [num_networks=FLAG],
- [network_size=FLAG], [vlan_start=FLAG],
- [vpn_start=FLAG], [fixed_range_v6=FLAG], [gateway_v6=FLAG],
- [flat_network_bridge=FLAG], [bridge_interface=FLAG]
- If you wish to use a later argument fill in the gaps with 0s
- Ex: network create private 10.0.0.0/8 1 15 0 0 0 0 xenbr1 eth1
- network create private 10.0.0.0/8 1 15
- """
+ bridge=None, bridge_interface=None, dns1=None, dns2=None):
+ """Creates fixed ips for host by range"""
+
+ # check for certain required inputs
if not label:
- msg = _('a label (ex: public) is required to create networks.')
- print msg
- raise TypeError(msg)
- if not fixed_range:
- msg = _('Fixed range in the form of 10.0.0.0/8 is '
- 'required to create networks.')
- print msg
- raise TypeError(msg)
+ raise exception.NetworkNotCreated(req='--label')
+ if not (fixed_range_v4 or fixed_range_v6):
+ req = '--fixed_range_v4 or --fixed_range_v6'
+ raise exception.NetworkNotCreated(req=req)
+
+ bridge = bridge or FLAGS.flat_network_bridge
+ if not bridge:
+ bridge_required = ['nova.network.manager.FlatManager',
+ 'nova.network.manager.FlatDHCPManager']
+ if FLAGS.network_manager in bridge_required:
+ # TODO(tr3buchet) - swap print statement and following line for
+ # raise statement in diablo 4
+ print _('--bridge parameter required or FLAG '
+ 'flat_network_bridge must be set to create networks\n'
+ 'WARNING! ACHTUNG! Setting the bridge to br100 '
+ 'automatically is deprecated and will be removed in '
+ 'Diablo milestone 4. Prepare yourself accordingly.')
+ time.sleep(10)
+ bridge = 'br100'
+ #raise exception.NetworkNotCreated(req='--bridge')
+
+ bridge_interface = bridge_interface or FLAGS.flat_interface or \
+ FLAGS.vlan_interface
+ if not bridge_interface:
+ interface_required = ['nova.network.manager.FlatDHCPManager',
+ 'nova.network.manager.VlanManager']
+ if FLAGS.network_manager in interface_required:
+ raise exception.NetworkNotCreated(req='--bridge_interface')
+
+ # sanitize other input using FLAGS if necessary
if not num_networks:
num_networks = FLAGS.num_networks
if not network_size:
- network_size = FLAGS.network_size
+ fixnet = netaddr.IPNetwork(fixed_range_v4)
+ each_subnet_size = fixnet.size / int(num_networks)
+ if each_subnet_size > FLAGS.network_size:
+ network_size = FLAGS.network_size
+ subnet = 32 - int(math.log(network_size, 2))
+ oversize_msg = _('Subnet(s) too large, defaulting to /%s.'
+ ' To override, specify network_size flag.'
+ ) % subnet
+ print oversize_msg
+ else:
+ network_size = fixnet.size
+ if not multi_host:
+ multi_host = FLAGS.multi_host
+ else:
+ multi_host = multi_host == 'T'
if not vlan_start:
vlan_start = FLAGS.vlan_start
if not vpn_start:
vpn_start = FLAGS.vpn_start
- if not fixed_range_v6:
- fixed_range_v6 = FLAGS.fixed_range_v6
- if not flat_network_bridge:
- flat_network_bridge = FLAGS.flat_network_bridge
- if not bridge_interface:
- bridge_interface = FLAGS.flat_interface or FLAGS.vlan_interface
- if not gateway_v6:
- gateway_v6 = FLAGS.gateway_v6
- net_manager = utils.import_object(FLAGS.network_manager)
+ if not dns1 and FLAGS.flat_network_dns:
+ dns1 = FLAGS.flat_network_dns
- try:
- net_manager.create_networks(context.get_admin_context(),
- label=label,
- cidr=fixed_range,
- num_networks=int(num_networks),
- network_size=int(network_size),
- vlan_start=int(vlan_start),
- vpn_start=int(vpn_start),
- cidr_v6=fixed_range_v6,
- gateway_v6=gateway_v6,
- bridge=flat_network_bridge,
- bridge_interface=bridge_interface)
- except ValueError, e:
- print e
- raise e
+ # create the network
+ net_manager = utils.import_object(FLAGS.network_manager)
+ net_manager.create_networks(context.get_admin_context(),
+ label=label,
+ cidr=fixed_range_v4,
+ multi_host=multi_host,
+ num_networks=int(num_networks),
+ network_size=int(network_size),
+ vlan_start=int(vlan_start),
+ vpn_start=int(vpn_start),
+ cidr_v6=fixed_range_v6,
+ gateway_v6=gateway_v6,
+ bridge=bridge,
+ bridge_interface=bridge_interface,
+ dns1=dns1,
+ dns2=dns2)
def list(self):
"""List all created networks"""
- print "%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s" % (_('network'),
- _('netmask'),
+ print "%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s" % (
+ _('IPv4'),
+ _('IPv6'),
_('start address'),
- _('DNS'),
+ _('DNS1'),
+ _('DNS2'),
_('VlanID'),
'project')
for network in db.network_get_all(context.get_admin_context()):
- print "%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s" % (network.cidr,
- network.netmask,
+ print "%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s" % (
+ network.cidr,
+ network.cidr_v6,
network.dhcp_start,
- network.dns,
+ network.dns1,
+ network.dns2,
network.vlan,
network.project_id)
+ @args('--network', dest="fixed_range", metavar='<x.x.x.x/yy>',
+ help='Network to delete')
def delete(self, fixed_range):
"""Deletes a network"""
network = db.network_get_by_cidr(context.get_admin_context(), \
@@ -648,12 +794,10 @@ class NetworkCommands(object):
class VmCommands(object):
"""Class for mangaging VM instances."""
+ @args('--host', dest="host", metavar='<host>', help='Host')
def list(self, host=None):
- """Show a list of all instances
+ """Show a list of all instances"""
- :param host: show all instance on specified host.
- :param instance: show specificed instance.
- """
print "%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s" \
" %-10s %-10s %-10s %-5s" % (
_('instance'),
@@ -691,13 +835,11 @@ class VmCommands(object):
instance['availability_zone'],
instance['launch_index'])
+ @args('--ec2_id', dest='ec2_id', metavar='<ec2 id>', help='EC2 ID')
+ @args('--dest', dest='dest', metavar='<Destanation>',
+ help='destanation node')
def live_migration(self, ec2_id, dest):
- """Migrates a running instance to a new machine.
-
- :param ec2_id: instance id which comes from euca-describe-instance.
- :param dest: destination host name.
-
- """
+ """Migrates a running instance to a new machine."""
ctxt = context.get_admin_context()
instance_id = ec2utils.ec2_id_to_id(ec2_id)
@@ -727,9 +869,13 @@ class VmCommands(object):
class ServiceCommands(object):
"""Enable and disable running services"""
+ @args('--host', dest='host', metavar='<host>', help='Host')
+ @args('--service', dest='service', metavar='<service>',
+ help='Nova service')
def list(self, host=None, service=None):
- """Show a list of all running services. Filter by host & service name.
- args: [host] [service]"""
+ """
+ Show a list of all running services. Filter by host & service name.
+ """
ctxt = context.get_admin_context()
now = utils.utcnow()
services = db.service_get_all(ctxt)
@@ -748,9 +894,11 @@ class ServiceCommands(object):
active, art,
svc['updated_at'])
+ @args('--host', dest='host', metavar='<host>', help='Host')
+ @args('--service', dest='service', metavar='<service>',
+ help='Nova service')
def enable(self, host, service):
- """Enable scheduling for a service
- args: host service"""
+ """Enable scheduling for a service"""
ctxt = context.get_admin_context()
svc = db.service_get_by_args(ctxt, host, service)
if not svc:
@@ -758,9 +906,11 @@ class ServiceCommands(object):
return
db.service_update(ctxt, svc['id'], {'disabled': False})
+ @args('--host', dest='host', metavar='<host>', help='Host')
+ @args('--service', dest='service', metavar='<service>',
+ help='Nova service')
def disable(self, host, service):
- """Disable scheduling for a service
- args: host service"""
+ """Disable scheduling for a service"""
ctxt = context.get_admin_context()
svc = db.service_get_by_args(ctxt, host, service)
if not svc:
@@ -768,12 +918,9 @@ class ServiceCommands(object):
return
db.service_update(ctxt, svc['id'], {'disabled': True})
+ @args('--host', dest='host', metavar='<host>', help='Host')
def describe_resource(self, host):
- """Describes cpu/memory/hdd info for host.
-
- :param host: hostname.
-
- """
+ """Describes cpu/memory/hdd info for host."""
result = rpc.call(context.get_admin_context(),
FLAGS.scheduler_topic,
@@ -801,12 +948,9 @@ class ServiceCommands(object):
val['memory_mb'],
val['local_gb'])
+ @args('--host', dest='host', metavar='<host>', help='Host')
def update_resource(self, host):
- """Updates available vcpu/memory/disk info for host.
-
- :param host: hostname.
-
- """
+ """Updates available vcpu/memory/disk info for host."""
ctxt = context.get_admin_context()
service_refs = db.service_get_all_by_host(ctxt, host)
@@ -850,6 +994,8 @@ class DbCommands(object):
def __init__(self):
pass
+ @args('--version', dest='version', metavar='<version>',
+ help='Database version')
def sync(self, version=None):
"""Sync the database up to the most recent version."""
return migration.db_sync(version)
@@ -869,14 +1015,18 @@ class VersionCommands(object):
print _("%s (%s)") %\
(version.version_string(), version.version_string_with_vcs())
+ def __call__(self):
+ self.list()
+
class VolumeCommands(object):
"""Methods for dealing with a cloud in an odd state"""
+ @args('--volume', dest='volume_id', metavar='<volume id>',
+ help='Volume ID')
def delete(self, volume_id):
"""Delete a volume, bypassing the check that it
- must be available.
- args: volume_id_id"""
+ must be available."""
ctxt = context.get_admin_context()
volume = db.volume_get(ctxt, param2id(volume_id))
host = volume['host']
@@ -897,11 +1047,12 @@ class VolumeCommands(object):
{"method": "delete_volume",
"args": {"volume_id": volume['id']}})
+ @args('--volume', dest='volume_id', metavar='<volume id>',
+ help='Volume ID')
def reattach(self, volume_id):
"""Re-attach a volume that has previously been attached
to an instance. Typically called after a compute host
- has been rebooted.
- args: volume_id_id"""
+ has been rebooted."""
ctxt = context.get_admin_context()
volume = db.volume_get(ctxt, param2id(volume_id))
if not volume['instance_id']:
@@ -928,12 +1079,23 @@ class InstanceTypeCommands(object):
val["flavorid"], val["swap"], val["rxtx_quota"],
val["rxtx_cap"], deleted)
+ @args('--name', dest='name', metavar='<name>',
+ help='Name of instance type/flavor')
+ @args('--memory', dest='memory', metavar='<memory size>',
+ help='Memory size')
+ @args('--cpu', dest='vcpus', metavar='<num cores>', help='Number cpus')
+ @args('--local_gb', dest='local_gb', metavar='<local_gb>',
+ help='local_gb')
+ @args('--flavor', dest='flavorid', metavar='<flavor id>',
+ help='Flavor ID')
+ @args('--swap', dest='swap', metavar='<swap>', help='Swap')
+ @args('--rxtx_quota', dest='rxtx_quota', metavar='<rxtx_quota>',
+ help='rxtx_quota')
+ @args('--rxtx_cap', dest='rxtx_cap', metavar='<rxtx_cap>',
+ help='rxtx_cap')
def create(self, name, memory, vcpus, local_gb, flavorid,
swap=0, rxtx_quota=0, rxtx_cap=0):
- """Creates instance types / flavors
- arguments: name memory vcpus local_gb flavorid [swap] [rxtx_quota]
- [rxtx_cap]
- """
+ """Creates instance types / flavors"""
try:
instance_types.create(name, memory, vcpus, local_gb,
flavorid, swap, rxtx_quota, rxtx_cap)
@@ -956,9 +1118,10 @@ class InstanceTypeCommands(object):
else:
print "%s created" % name
+ @args('--name', dest='name', metavar='<name>',
+ help='Name of instance type/flavor')
def delete(self, name, purge=None):
- """Marks instance types / flavors as deleted
- arguments: name"""
+ """Marks instance types / flavors as deleted"""
try:
if purge == "--purge":
instance_types.purge(name)
@@ -977,9 +1140,10 @@ class InstanceTypeCommands(object):
else:
print "%s %s" % (name, verb)
+ @args('--name', dest='name', metavar='<name>',
+ help='Name of instance type/flavor')
def list(self, name=None):
- """Lists all active or specific instance types / flavors
- arguments: [name]"""
+ """Lists all active or specific instance types / flavors"""
try:
if name is None:
inst_types = instance_types.get_all_types()
@@ -1027,11 +1191,18 @@ class ImageCommands(object):
except Exception as exc:
print _("Failed to register %(path)s: %(exc)s") % locals()
+ @args('--image', dest='image', metavar='<image>', help='Image')
+ @args('--kernel', dest='kernel', metavar='<kernel>', help='Kernel')
+ @args('--ram', dest='ramdisk', metavar='<ramdisk>', help='RAM disk')
+ @args('--owner', dest='owner', metavar='<owner>', help='Image owner')
+ @args('--name', dest='name', metavar='<name>', help='Image name')
+ @args('--public', dest='is_public', metavar="<'T'|'F'>",
+ help='Image public or not')
+ @args('--arch', dest='architecture', metavar='<arch>',
+ help='Architecture')
def all_register(self, image, kernel, ramdisk, owner, name=None,
is_public='T', architecture='x86_64'):
- """Uploads an image, kernel, and ramdisk into the image_service
- arguments: image kernel ramdisk owner [name] [is_public='T']
- [architecture='x86_64']"""
+ """Uploads an image, kernel, and ramdisk into the image_service"""
kernel_id = self.kernel_register(kernel, owner, None,
is_public, architecture)
ramdisk_id = self.ramdisk_register(ramdisk, owner, None,
@@ -1040,40 +1211,61 @@ class ImageCommands(object):
architecture, 'ami', 'ami',
kernel_id, ramdisk_id)
+ @args('--path', dest='path', metavar='<path>', help='Image path')
+ @args('--owner', dest='owner', metavar='<owner>', help='Image owner')
+ @args('--name', dest='name', metavar='<name>', help='Image name')
+ @args('--public', dest='is_public', metavar="<'T'|'F'>",
+ help='Image public or not')
+ @args('--arch', dest='architecture', metavar='<arch>',
+ help='Architecture')
+ @args('--cont_format', dest='container_format',
+ metavar='<container format>',
+ help='Container format(default bare)')
+ @args('--disk_format', dest='disk_format', metavar='<disk format>',
+ help='Disk format(default: raw)')
+ @args('--kernel', dest='kernel_id', metavar='<kernel>', help='Kernel')
+ @args('--ram', dest='ramdisk_id', metavar='<ramdisk>', help='RAM disk')
def image_register(self, path, owner, name=None, is_public='T',
architecture='x86_64', container_format='bare',
disk_format='raw', kernel_id=None, ramdisk_id=None):
- """Uploads an image into the image_service
- arguments: path owner [name] [is_public='T'] [architecture='x86_64']
- [container_format='bare'] [disk_format='raw']
- [kernel_id=None] [ramdisk_id=None]
- """
+ """Uploads an image into the image_service"""
return self._register(container_format, disk_format, path,
owner, name, is_public, architecture,
kernel_id, ramdisk_id)
+ @args('--path', dest='path', metavar='<path>', help='Image path')
+ @args('--owner', dest='owner', metavar='<owner>', help='Image owner')
+ @args('--name', dest='name', metavar='<name>', help='Image name')
+ @args('--public', dest='is_public', metavar="<'T'|'F'>",
+ help='Image public or not')
+ @args('--arch', dest='architecture', metavar='<arch>',
+ help='Architecture')
def kernel_register(self, path, owner, name=None, is_public='T',
architecture='x86_64'):
- """Uploads a kernel into the image_service
- arguments: path owner [name] [is_public='T'] [architecture='x86_64']
- """
+ """Uploads a kernel into the image_service"""
return self._register('aki', 'aki', path, owner, name,
is_public, architecture)
+ @args('--path', dest='path', metavar='<path>', help='Image path')
+ @args('--owner', dest='owner', metavar='<owner>', help='Image owner')
+ @args('--name', dest='name', metavar='<name>', help='Image name')
+ @args('--public', dest='is_public', metavar="<'T'|'F'>",
+ help='Image public or not')
+ @args('--arch', dest='architecture', metavar='<arch>',
+ help='Architecture')
def ramdisk_register(self, path, owner, name=None, is_public='T',
architecture='x86_64'):
- """Uploads a ramdisk into the image_service
- arguments: path owner [name] [is_public='T'] [architecture='x86_64']
- """
+ """Uploads a ramdisk into the image_service"""
return self._register('ari', 'ari', path, owner, name,
is_public, architecture)
def _lookup(self, old_image_id):
+ elevated = context.get_admin_context()
try:
internal_id = ec2utils.ec2_id_to_id(old_image_id)
- image = self.image_service.show(context, internal_id)
+ image = self.image_service.show(elevated, internal_id)
except (exception.InvalidEc2Id, exception.ImageNotFound):
- image = self.image_service.show_by_name(context, old_image_id)
+ image = self.image_service.show_by_name(elevated, old_image_id)
return image['id']
def _old_to_new(self, old):
@@ -1113,9 +1305,10 @@ class ImageCommands(object):
except Exception as exc:
print _("Failed to convert %(old)s: %(exc)s") % locals()
+ @args('--dir', dest='directory', metavar='<path>',
+ help='Images directory')
def convert(self, directory):
- """Uploads old objectstore images in directory to new service
- arguments: directory"""
+ """Uploads old objectstore images in directory to new service"""
machine_images = {}
other_images = {}
directory = os.path.abspath(directory)
@@ -1140,8 +1333,7 @@ class AgentBuildCommands(object):
def create(self, os, architecture, version, url, md5hash,
hypervisor='xen'):
- """Creates a new agent build.
- arguments: os architecture version url md5hash [hypervisor='xen']"""
+ """Creates a new agent build."""
ctxt = context.get_admin_context()
agent_build = db.agent_build_create(ctxt,
{'hypervisor': hypervisor,
@@ -1152,8 +1344,7 @@ class AgentBuildCommands(object):
'md5hash': md5hash})
def delete(self, os, architecture, hypervisor='xen'):
- """Deletes an existing agent build.
- arguments: os architecture [hypervisor='xen']"""
+ """Deletes an existing agent build."""
ctxt = context.get_admin_context()
agent_build_ref = db.agent_build_get_by_triple(ctxt,
hypervisor, os, architecture)
@@ -1187,9 +1378,7 @@ class AgentBuildCommands(object):
def modify(self, os, architecture, version, url, md5hash,
hypervisor='xen'):
- """Update an existing agent build.
- arguments: os architecture version url md5hash [hypervisor='xen']
- """
+ """Update an existing agent build."""
ctxt = context.get_admin_context()
agent_build_ref = db.agent_build_get_by_triple(ctxt,
hypervisor, os, architecture)
@@ -1285,21 +1474,42 @@ def main():
command_object = fn()
actions = methods_of(command_object)
if len(argv) < 1:
- print script_name + " category action [<args>]"
- print _("Available actions for %s category:") % category
- for k, _v in actions:
- print "\t%s" % k
- sys.exit(2)
- action = argv.pop(0)
- matches = lazy_match(action, actions)
- action, fn = matches[0]
+ if hasattr(command_object, '__call__'):
+ action = ''
+ fn = command_object.__call__
+ else:
+ print script_name + " category action [<args>]"
+ print _("Available actions for %s category:") % category
+ for k, _v in actions:
+ print "\t%s" % k
+ sys.exit(2)
+ else:
+ action = argv.pop(0)
+ matches = lazy_match(action, actions)
+ action, fn = matches[0]
+
+ # For not decorated methods
+ options = getattr(fn, 'options', [])
+
+ usage = "%%prog %s %s <args> [options]" % (category, action)
+ parser = OptionParser(usage=usage)
+ for ar, kw in options:
+ parser.add_option(*ar, **kw)
+ (opts, fn_args) = parser.parse_args(argv)
+ fn_kwargs = vars(opts)
+
+ for k, v in fn_kwargs.items():
+ if v is None:
+ del fn_kwargs[k]
+
# call the action with the remaining arguments
try:
- fn(*argv)
+ fn(*fn_args, **fn_kwargs)
sys.exit(0)
except TypeError:
print _("Possible wrong number of arguments supplied")
- print "%s %s: %s" % (category, action, fn.__doc__)
+ print fn.__doc__
+ parser.print_help()
raise
except Exception:
print _("Command failed, please check log for more info")
diff --git a/bin/nova-objectstore b/bin/nova-objectstore
index 1aef3a255..4d5aec445 100755
--- a/bin/nova-objectstore
+++ b/bin/nova-objectstore
@@ -18,7 +18,7 @@
# under the License.
"""
- Twisted daemon for nova objectstore. Supports S3 API.
+ Daemon for nova objectstore. Supports S3 API.
"""
import gettext
diff --git a/contrib/nova.sh b/contrib/nova.sh
index eab680580..7994e5133 100755
--- a/contrib/nova.sh
+++ b/contrib/nova.sh
@@ -75,7 +75,7 @@ if [ "$CMD" == "install" ]; then
sudo modprobe kvm
sudo /etc/init.d/libvirt-bin restart
sudo modprobe nbd
- sudo apt-get install -y python-twisted python-mox python-ipy python-paste
+ sudo apt-get install -y python-mox python-ipy python-paste
sudo apt-get install -y python-migrate python-gflags python-greenlet
sudo apt-get install -y python-libvirt python-libxml2 python-routes
sudo apt-get install -y python-netaddr python-pastedeploy python-eventlet
diff --git a/doc/source/api/autoindex.rst b/doc/source/api/autoindex.rst
index 329a465db..d99d16eaa 100644
--- a/doc/source/api/autoindex.rst
+++ b/doc/source/api/autoindex.rst
@@ -26,7 +26,6 @@
nova..compute.api.rst
nova..compute.instance_types.rst
nova..compute.manager.rst
- nova..compute.monitor.rst
nova..compute.power_state.rst
nova..console.api.rst
nova..console.fake.rst
@@ -115,13 +114,11 @@
nova..tests.test_scheduler.rst
nova..tests.test_service.rst
nova..tests.test_test.rst
- nova..tests.test_twistd.rst
nova..tests.test_utils.rst
nova..tests.test_virt.rst
nova..tests.test_volume.rst
nova..tests.test_xenapi.rst
nova..tests.xenapi.stubs.rst
- nova..twistd.rst
nova..utils.rst
nova..version.rst
nova..virt.connection.rst
diff --git a/doc/source/api/nova..compute.monitor.rst b/doc/source/api/nova..compute.monitor.rst
deleted file mode 100644
index a91169ecd..000000000
--- a/doc/source/api/nova..compute.monitor.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-The :mod:`nova..compute.monitor` Module
-==============================================================================
-.. automodule:: nova..compute.monitor
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/source/api/nova..tests.test_twistd.rst b/doc/source/api/nova..tests.test_twistd.rst
deleted file mode 100644
index cae0c0a28..000000000
--- a/doc/source/api/nova..tests.test_twistd.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-The :mod:`nova..tests.test_twistd` Module
-==============================================================================
-.. automodule:: nova..tests.test_twistd
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/source/api/nova..twistd.rst b/doc/source/api/nova..twistd.rst
deleted file mode 100644
index d4145396d..000000000
--- a/doc/source/api/nova..twistd.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-The :mod:`nova..twistd` Module
-==============================================================================
-.. automodule:: nova..twistd
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/source/code.rst b/doc/source/code.rst
index 6b8d5661f..73fc31e1a 100644
--- a/doc/source/code.rst
+++ b/doc/source/code.rst
@@ -21,7 +21,6 @@ Generating source/api/nova..cloudpipe.pipelib.rst
Generating source/api/nova..compute.disk.rst
Generating source/api/nova..compute.instance_types.rst
Generating source/api/nova..compute.manager.rst
-Generating source/api/nova..compute.monitor.rst
Generating source/api/nova..compute.power_state.rst
Generating source/api/nova..context.rst
Generating source/api/nova..crypto.rst
@@ -79,11 +78,9 @@ Generating source/api/nova..tests.rpc_unittest.rst
Generating source/api/nova..tests.runtime_flags.rst
Generating source/api/nova..tests.scheduler_unittest.rst
Generating source/api/nova..tests.service_unittest.rst
-Generating source/api/nova..tests.twistd_unittest.rst
Generating source/api/nova..tests.validator_unittest.rst
Generating source/api/nova..tests.virt_unittest.rst
Generating source/api/nova..tests.volume_unittest.rst
-Generating source/api/nova..twistd.rst
Generating source/api/nova..utils.rst
Generating source/api/nova..validate.rst
Generating source/api/nova..virt.connection.rst
diff --git a/doc/source/devref/architecture.rst b/doc/source/devref/architecture.rst
index 233cd6f08..7f44ecdf2 100644
--- a/doc/source/devref/architecture.rst
+++ b/doc/source/devref/architecture.rst
@@ -45,7 +45,7 @@ Below you will find a helpful explanation of the different components.
* Web Dashboard: potential external component that talks to the api
* api: component that receives http requests, converts commands and communicates with other components via the queue or http (in the case of objectstore)
* Auth Manager: component responsible for users/projects/and roles. Can backend to DB or LDAP. This is not a separate binary, but rather a python class that is used by most components in the system.
-* objectstore: twisted http server that replicates s3 api and allows storage and retrieval of images
+* objectstore: http server that replicates s3 api and allows storage and retrieval of images
* scheduler: decides which host gets each vm and volume
* volume: manages dynamically attachable block devices.
* network: manages ip forwarding, bridges, and vlans
diff --git a/doc/source/devref/compute.rst b/doc/source/devref/compute.rst
index 31cc2037f..50397cbec 100644
--- a/doc/source/devref/compute.rst
+++ b/doc/source/devref/compute.rst
@@ -118,19 +118,6 @@ The :mod:`nova.virt.fake` Driver
:show-inheritance:
-Monitoring
-----------
-
-The :mod:`nova.compute.monitor` Module
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: nova.compute.monitor
- :noindex:
- :members:
- :undoc-members:
- :show-inheritance:
-
-
Tests
-----
diff --git a/doc/source/devref/development.environment.rst b/doc/source/devref/development.environment.rst
index f3c454d64..09f1eb2c2 100644
--- a/doc/source/devref/development.environment.rst
+++ b/doc/source/devref/development.environment.rst
@@ -51,7 +51,7 @@ To activate the Nova virtualenv for the extent of your current shell session
Also, make test will automatically use the virtualenv.
-If you don't want to create a virtualenv every time you branch (which takes a while as long as we have the large Twisted project as a dependency) you can reuse a single virtualenv for all branches.
+If you don't want to create a virtualenv every time you branch you can reuse a single virtualenv for all branches.
#. If you don't have a nova/ directory containing trunk/ and other branches, do so now.
#. Go into nova/trunk and install a virtualenv.
diff --git a/doc/source/devref/nova.rst b/doc/source/devref/nova.rst
index 093fbb3ee..beca99ecd 100644
--- a/doc/source/devref/nova.rst
+++ b/doc/source/devref/nova.rst
@@ -102,16 +102,6 @@ The :mod:`nova.test` Module
:show-inheritance:
-The :mod:`nova.twistd` Module
------------------------------
-
-.. automodule:: nova.twistd
- :noindex:
- :members:
- :undoc-members:
- :show-inheritance:
-
-
The :mod:`nova.utils` Module
----------------------------
@@ -215,16 +205,6 @@ The :mod:`runtime_flags` Module
:show-inheritance:
-The :mod:`twistd_unittest` Module
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: nova.tests.twistd_unittest
- :noindex:
- :members:
- :undoc-members:
- :show-inheritance:
-
-
The :mod:`validator_unittest` Module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/nova/api/direct.py b/nova/api/direct.py
index ec79151b1..fdd2943d2 100644
--- a/nova/api/direct.py
+++ b/nova/api/direct.py
@@ -107,7 +107,8 @@ class DelegatedAuthMiddleware(wsgi.Middleware):
def process_request(self, request):
os_user = request.headers['X-OpenStack-User']
os_project = request.headers['X-OpenStack-Project']
- context_ref = context.RequestContext(user=os_user, project=os_project)
+ context_ref = context.RequestContext(user_id=os_user,
+ project_id=os_project)
request.environ['openstack.context'] = context_ref
@@ -295,8 +296,8 @@ class ServiceWrapper(object):
'application/json': nova.api.openstack.wsgi.JSONDictSerializer(),
}[content_type]
return serializer.serialize(result)
- except:
- raise exception.Error("returned non-serializable type: %s"
+ except Exception, e:
+ raise exception.Error(_("Returned non-serializable type: %s")
% result)
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index 9c4a4adf9..8b6e47cfb 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -66,7 +66,7 @@ class RequestLogging(wsgi.Middleware):
else:
controller = None
action = None
- ctxt = request.environ.get('ec2.context', None)
+ ctxt = request.environ.get('nova.context', None)
delta = utils.utcnow() - start
seconds = delta.seconds
microseconds = delta.microseconds
@@ -139,8 +139,7 @@ class Lockout(wsgi.Middleware):
class Authenticate(wsgi.Middleware):
-
- """Authenticate an EC2 request and add 'ec2.context' to WSGI environ."""
+ """Authenticate an EC2 request and add 'nova.context' to WSGI environ."""
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
@@ -148,7 +147,7 @@ class Authenticate(wsgi.Middleware):
try:
signature = req.params['Signature']
access = req.params['AWSAccessKeyId']
- except:
+ except KeyError, e:
raise webob.exc.HTTPBadRequest()
# Make a copy of args for authentication and signature verification.
@@ -157,8 +156,9 @@ class Authenticate(wsgi.Middleware):
auth_params.pop('Signature')
# Authenticate the request.
+ authman = manager.AuthManager()
try:
- (user, project) = manager.AuthManager().authenticate(
+ (user, project) = authman.authenticate(
access,
signature,
auth_params,
@@ -174,14 +174,17 @@ class Authenticate(wsgi.Middleware):
remote_address = req.remote_addr
if FLAGS.use_forwarded_for:
remote_address = req.headers.get('X-Forwarded-For', remote_address)
- ctxt = context.RequestContext(user=user,
- project=project,
+ roles = authman.get_active_roles(user, project)
+ ctxt = context.RequestContext(user_id=user.id,
+ project_id=project.id,
+ is_admin=user.is_admin(),
+ roles=roles,
remote_address=remote_address)
- req.environ['ec2.context'] = ctxt
+ req.environ['nova.context'] = ctxt
uname = user.name
pname = project.name
msg = _('Authenticated Request For %(uname)s:%(pname)s)') % locals()
- LOG.audit(msg, context=req.environ['ec2.context'])
+ LOG.audit(msg, context=req.environ['nova.context'])
return self.application
@@ -208,7 +211,7 @@ class Requestify(wsgi.Middleware):
for non_arg in non_args:
# Remove, but raise KeyError if omitted
args.pop(non_arg)
- except:
+ except KeyError, e:
raise webob.exc.HTTPBadRequest()
LOG.debug(_('action: %s'), action)
@@ -228,7 +231,7 @@ class Authorizer(wsgi.Middleware):
"""Authorize an EC2 API request.
Return a 401 if ec2.controller and ec2.action in WSGI environ may not be
- executed in ec2.context.
+ executed in nova.context.
"""
def __init__(self, application):
@@ -282,7 +285,7 @@ class Authorizer(wsgi.Middleware):
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
- context = req.environ['ec2.context']
+ context = req.environ['nova.context']
controller = req.environ['ec2.request'].controller.__class__.__name__
action = req.environ['ec2.request'].action
allowed_roles = self.action_roles[controller].get(action, ['none'])
@@ -295,28 +298,27 @@ class Authorizer(wsgi.Middleware):
def _matches_any_role(self, context, roles):
"""Return True if any role in roles is allowed in context."""
- if context.user.is_superuser():
+ if context.is_admin:
return True
if 'all' in roles:
return True
if 'none' in roles:
return False
- return any(context.project.has_role(context.user_id, role)
- for role in roles)
+ return any(role in context.roles for role in roles)
class Executor(wsgi.Application):
"""Execute an EC2 API request.
- Executes 'ec2.action' upon 'ec2.controller', passing 'ec2.context' and
+ Executes 'ec2.action' upon 'ec2.controller', passing 'nova.context' and
'ec2.action_args' (all variables in WSGI environ.) Returns an XML
response, or a 400 upon failure.
"""
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
- context = req.environ['ec2.context']
+ context = req.environ['nova.context']
api_request = req.environ['ec2.request']
result = None
try:
diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py
index 7d78c5cfa..9a3e55925 100644
--- a/nova/api/ec2/apirequest.py
+++ b/nova/api/ec2/apirequest.py
@@ -104,7 +104,7 @@ class APIRequest(object):
for key in data.keys():
val = data[key]
el.appendChild(self._render_data(xml, key, val))
- except:
+ except Exception:
LOG.debug(data)
raise
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 371837d19..5f8b1007a 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -531,7 +531,55 @@ 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)
+ else:
+ rules = [kwargs]
+ finalset = []
+ for rule in rules:
+ if 'groups' in rule:
+ groups_values = self._groups_args_split(rule)
+ for groups_value in groups_values:
+ final = self._rule_dict_last_step(context, **groups_value)
+ finalset.append(final)
+ else:
+ final = self._rule_dict_last_step(context, **rule)
+ finalset.append(final)
+ 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):
@@ -546,6 +594,9 @@ class CloudController(object):
db.security_group_get_by_name(context.elevated(),
source_project_id,
source_security_group_name)
+ notfound = exception.SecurityGroupNotFound
+ if not source_security_group:
+ raise notfound(security_group_id=source_security_group_name)
values['group_id'] = source_security_group['id']
elif cidr_ip:
# If this fails, it throws an exception. This is what we want.
@@ -584,7 +635,7 @@ class CloudController(object):
for rule in security_group.rules:
if 'group_id' in values:
if rule['group_id'] == values['group_id']:
- return True
+ return rule['id']
else:
is_duplicate = True
for key in ('cidr', 'from_port', 'to_port', 'protocol'):
@@ -592,7 +643,7 @@ class CloudController(object):
is_duplicate = False
break
if is_duplicate:
- return True
+ return rule['id']
return False
def revoke_security_group_ingress(self, context, group_name=None,
@@ -615,22 +666,30 @@ 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)
- if criteria is None:
- raise exception.ApiError(_("Not enough parameters to build a "
- "valid rule."))
-
- for rule in security_group.rules:
- match = True
- for (k, v) in criteria.iteritems():
- if getattr(rule, k, False) != v:
- match = False
- if match:
- db.security_group_rule_destroy(context, rule['id'])
- self.compute_api.trigger_security_group_rules_refresh(context,
- security_group_id=security_group['id'])
- return True
+ prevalues = []
+ try:
+ prevalues = kwargs['ip_permissions']
+ except KeyError:
+ prevalues.append(kwargs)
+ rule_id = None
+ 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
+ rule_id = self._security_group_rule_exists(security_group,
+ values_for_rule)
+ if rule_id:
+ db.security_group_rule_destroy(context, rule_id)
+ if rule_id:
+ # NOTE(vish): we removed a rule, so refresh
+ self.compute_api.trigger_security_group_rules_refresh(
+ context,
+ security_group_id=security_group['id'])
+ return True
raise exception.ApiError(_("No rule for the specified parameters."))
# TODO(soren): This has only been tested with Boto as the client.
@@ -657,22 +716,37 @@ 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
-
- 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)
+ 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)
+
+ 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'])
+ if postvalues:
+ self.compute_api.trigger_security_group_rules_refresh(
+ context,
+ security_group_id=security_group['id'])
+ return True
- return True
+ raise exception.ApiError(_("No rule for the specified parameters."))
def _get_source_project_id(self, context, source_security_group_owner_id):
if source_security_group_owner_id:
@@ -1164,7 +1238,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):
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index e87d7c754..d6a98c2cd 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -40,6 +40,7 @@ from nova.api.openstack import servers
from nova.api.openstack import server_metadata
from nova.api.openstack import shared_ip_groups
from nova.api.openstack import users
+from nova.api.openstack import versions
from nova.api.openstack import wsgi
from nova.api.openstack import zones
@@ -96,6 +97,7 @@ class APIRouter(base_wsgi.Router):
server_members['suspend'] = 'POST'
server_members['resume'] = 'POST'
server_members['rescue'] = 'POST'
+ server_members['migrate'] = 'POST'
server_members['unrescue'] = 'POST'
server_members['reset_network'] = 'POST'
server_members['inject_network_info'] = 'POST'
@@ -115,6 +117,10 @@ class APIRouter(base_wsgi.Router):
'select': 'POST',
'boot': 'POST'})
+ mapper.connect("versions", "/",
+ controller=versions.create_resource(version),
+ action='show')
+
mapper.resource("console", "consoles",
controller=consoles.create_resource(),
parent_resource=dict(member_name='server',
@@ -164,12 +170,27 @@ 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.resource("server_meta", "meta",
- controller=server_metadata.create_resource(),
+ mapper.connect("metadata", "/images/{image_id}/metadata",
+ controller=image_metadata_controller,
+ action='update_all',
+ conditions={"method": ['PUT']})
+
+ server_metadata_controller = server_metadata.create_resource()
+
+ mapper.resource("server_meta", "metadata",
+ controller=server_metadata_controller,
parent_resource=dict(member_name='server',
collection_name='servers'))
+
+ mapper.connect("metadata", "/servers/{server_id}/metadata",
+ controller=server_metadata_controller,
+ action='update_all',
+ conditions={"method": ['PUT']})
diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py
index e3201b14f..a13a758ab 100644
--- a/nova/api/openstack/accounts.py
+++ b/nova/api/openstack/accounts.py
@@ -47,10 +47,10 @@ class Controller(object):
raise exception.AdminRequired()
def index(self, req):
- raise faults.Fault(webob.exc.HTTPNotImplemented())
+ raise webob.exc.HTTPNotImplemented()
def detail(self, req):
- raise faults.Fault(webob.exc.HTTPNotImplemented())
+ raise webob.exc.HTTPNotImplemented()
def show(self, req, id):
"""Return data about the given account id"""
@@ -65,7 +65,7 @@ class Controller(object):
def create(self, req, body):
"""We use update with create-or-update semantics
because the id comes from an external source"""
- raise faults.Fault(webob.exc.HTTPNotImplemented())
+ raise webob.exc.HTTPNotImplemented()
def update(self, req, id, body):
"""This is really create or update."""
diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py
index 7c3e683d6..d42abe1f8 100644
--- a/nova/api/openstack/auth.py
+++ b/nova/api/openstack/auth.py
@@ -48,31 +48,35 @@ class AuthMiddleware(wsgi.Middleware):
def __call__(self, req):
if not self.has_authentication(req):
return self.authenticate(req)
- user = self.get_user_by_authentication(req)
- if not user:
+ user_id = self.get_user_by_authentication(req)
+ if not user_id:
token = req.headers["X-Auth-Token"]
- msg = _("%(user)s could not be found with token '%(token)s'")
+ msg = _("%(user_id)s could not be found with token '%(token)s'")
LOG.warn(msg % locals())
return faults.Fault(webob.exc.HTTPUnauthorized())
try:
- account = req.headers["X-Auth-Project-Id"]
+ project_id = req.headers["X-Auth-Project-Id"]
except KeyError:
# FIXME(usrleon): It needed only for compatibility
# while osapi clients don't use this header
- accounts = self.auth.get_projects(user=user)
- if accounts:
- account = accounts[0]
+ projects = self.auth.get_projects(user_id)
+ if projects:
+ project_id = projects[0].id
else:
return faults.Fault(webob.exc.HTTPUnauthorized())
- if not self.auth.is_admin(user) and \
- not self.auth.is_project_member(user, account):
- msg = _("%(user)s must be an admin or a member of %(account)s")
+ is_admin = self.auth.is_admin(user_id)
+ req.environ['nova.context'] = context.RequestContext(user_id,
+ project_id,
+ is_admin)
+ if not is_admin and not self.auth.is_project_member(user_id,
+ project_id):
+ msg = _("%(user_id)s must be an admin or a "
+ "member of %(project_id)s")
LOG.warn(msg % locals())
return faults.Fault(webob.exc.HTTPUnauthorized())
- req.environ['nova.context'] = context.RequestContext(user, account)
return self.application
def has_authentication(self, req):
@@ -133,7 +137,7 @@ class AuthMiddleware(wsgi.Middleware):
if delta.days >= 2:
self.db.auth_token_destroy(ctxt, token['token_hash'])
else:
- return self.auth.get_user(token['user_id'])
+ return token['user_id']
return None
def _authorize_user(self, username, key, req):
diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py
index 3e95aedf3..7ff0d999e 100644
--- a/nova/api/openstack/backup_schedules.py
+++ b/nova/api/openstack/backup_schedules.py
@@ -19,7 +19,6 @@ import time
from webob import exc
-from nova.api.openstack import faults
from nova.api.openstack import wsgi
@@ -36,20 +35,20 @@ class Controller(object):
def index(self, req, server_id, **kwargs):
""" Returns the list of backup schedules for a given instance """
- return faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def show(self, req, server_id, id, **kwargs):
""" Returns a single backup schedule for a given instance """
- return faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def create(self, req, server_id, **kwargs):
""" No actual update method required, since the existing API allows
both create and update through a POST """
- return faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def delete(self, req, server_id, id, **kwargs):
""" Deletes an existing backup schedule """
- return faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def create_resource():
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index 8e12ce0c0..4548c2c75 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -16,13 +16,15 @@
# under the License.
import re
-from urlparse import urlparse
+import urlparse
+from xml.dom import minidom
import webob
from nova import exception
from nova import flags
from nova import log as logging
+from nova.api.openstack import wsgi
LOG = logging.getLogger('nova.api.openstack.common')
@@ -53,10 +55,10 @@ def get_pagination_params(request):
params[param] = int(request.GET[param])
except ValueError:
msg = _('%s param must be an integer') % param
- raise webob.exc.HTTPBadRequest(msg)
+ raise webob.exc.HTTPBadRequest(explanation=msg)
if params[param] < 0:
msg = _('%s param must be positive') % param
- raise webob.exc.HTTPBadRequest(msg)
+ raise webob.exc.HTTPBadRequest(explanation=msg)
return params
@@ -77,18 +79,22 @@ def limited(items, request, max_limit=FLAGS.osapi_max_limit):
try:
offset = int(request.GET.get('offset', 0))
except ValueError:
- raise webob.exc.HTTPBadRequest(_('offset param must be an integer'))
+ msg = _('offset param must be an integer')
+ raise webob.exc.HTTPBadRequest(explanation=msg)
try:
limit = int(request.GET.get('limit', max_limit))
except ValueError:
- raise webob.exc.HTTPBadRequest(_('limit param must be an integer'))
+ msg = _('limit param must be an integer')
+ raise webob.exc.HTTPBadRequest(explanation=msg)
if limit < 0:
- raise webob.exc.HTTPBadRequest(_('limit param must be positive'))
+ msg = _('limit param must be positive')
+ raise webob.exc.HTTPBadRequest(explanation=msg)
if offset < 0:
- raise webob.exc.HTTPBadRequest(_('offset param must be positive'))
+ msg = _('offset param must be positive')
+ raise webob.exc.HTTPBadRequest(explanation=msg)
limit = min(max_limit, limit or max_limit)
range_end = offset + limit
@@ -111,7 +117,8 @@ def limited_by_marker(items, request, max_limit=FLAGS.osapi_max_limit):
start_index = i + 1
break
if start_index < 0:
- raise webob.exc.HTTPBadRequest(_('marker [%s] not found' % marker))
+ msg = _('marker [%s] not found') % marker
+ raise webob.exc.HTTPBadRequest(explanation=msg)
range_end = start_index + limit
return items[start_index:range_end]
@@ -130,8 +137,8 @@ def get_id_from_href(href):
if re.match(r'\d+$', str(href)):
return int(href)
try:
- return int(urlparse(href).path.split('/')[-1])
- except:
+ return int(urlparse.urlsplit(href).path.split('/')[-1])
+ except ValueError, e:
LOG.debug(_("Error extracting id from href: %s") % href)
raise ValueError(_('could not parse id from href'))
@@ -146,19 +153,130 @@ def remove_version_from_href(href):
Returns: 'http://www.nova.com'
"""
- try:
- #removes the first instance that matches /v#.#/
- new_href = re.sub(r'[/][v][0-9]+\.[0-9]+[/]', '/', href, count=1)
+ parsed_url = urlparse.urlsplit(href)
+ new_path = re.sub(r'^/v[0-9]+\.[0-9]+(/|$)', r'\1', parsed_url.path,
+ count=1)
- #if no version was found, try finding /v#.# at the end of the string
- if new_href == href:
- new_href = re.sub(r'[/][v][0-9]+\.[0-9]+$', '', href, count=1)
- except:
- LOG.debug(_("Error removing version from href: %s") % href)
- msg = _('could not parse version from href')
+ if new_path == parsed_url.path:
+ msg = _('href %s does not contain version') % href
+ LOG.debug(msg)
raise ValueError(msg)
- if new_href == href:
- msg = _('href does not contain version')
- raise ValueError(msg)
- return new_href
+ parsed_url = list(parsed_url)
+ parsed_url[2] = new_path
+ return urlparse.urlunsplit(parsed_url)
+
+
+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
+
+
+class MetadataXMLDeserializer(wsgi.XMLDeserializer):
+
+ def extract_metadata(self, metadata_node):
+ """Marshal the metadata attribute of a parsed request"""
+ if metadata_node is None:
+ return {}
+ 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_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 MetadataHeadersSerializer(wsgi.ResponseHeadersSerializer):
+
+ def delete(self, response, data):
+ response.status_int = 204
+
+
+class MetadataXMLSerializer(wsgi.XMLDictSerializer):
+ def __init__(self, xmlns=wsgi.XMLNS_V11):
+ super(MetadataXMLSerializer, self).__init__(xmlns=xmlns)
+
+ def _meta_item_to_xml(self, doc, key, value):
+ node = doc.createElement('meta')
+ doc.appendChild(node)
+ node.setAttribute('key', '%s' % key)
+ text = doc.createTextNode('%s' % value)
+ node.appendChild(text)
+ return node
+
+ def meta_list_to_xml(self, xml_doc, meta_items):
+ container_node = xml_doc.createElement('metadata')
+ for (key, value) in meta_items:
+ item_node = self._meta_item_to_xml(xml_doc, key, value)
+ container_node.appendChild(item_node)
+ return container_node
+
+ def _meta_list_to_xml_string(self, metadata_dict):
+ xml_doc = minidom.Document()
+ items = metadata_dict['metadata'].items()
+ container_node = self.meta_list_to_xml(xml_doc, items)
+ xml_doc.appendChild(container_node)
+ self._add_xmlns(container_node)
+ return xml_doc.toxml('UTF-8')
+
+ def index(self, metadata_dict):
+ return self._meta_list_to_xml_string(metadata_dict)
+
+ 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]
+ item_node = self._meta_item_to_xml(xml_doc, item_key, item_value)
+ xml_doc.appendChild(item_node)
+ self._add_xmlns(item_node)
+ return xml_doc.toxml('UTF-8')
+
+ def show(self, meta_item_dict):
+ return self._meta_item_to_xml_string(meta_item_dict['meta'])
+
+ def update(self, meta_item_dict):
+ return self._meta_item_to_xml_string(meta_item_dict['meta'])
+
+ def default(self, *args, **kwargs):
+ return ''
diff --git a/nova/api/openstack/consoles.py b/nova/api/openstack/consoles.py
index 7a43fba96..d2655acfa 100644
--- a/nova/api/openstack/consoles.py
+++ b/nova/api/openstack/consoles.py
@@ -16,10 +16,10 @@
# under the License.
from webob import exc
+import webob
from nova import console
from nova import exception
-from nova.api.openstack import faults
from nova.api.openstack import wsgi
@@ -71,12 +71,12 @@ class Controller(object):
int(server_id),
int(id))
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
return _translate_detail_keys(console)
def update(self, req, server_id, id):
"""You can't update a console"""
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def delete(self, req, server_id, id):
"""Deletes a console"""
@@ -85,8 +85,8 @@ class Controller(object):
int(server_id),
int(id))
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
- return exc.HTTPAccepted()
+ raise exc.HTTPNotFound()
+ return webob.Response(status_int=202)
def create_resource():
diff --git a/nova/api/openstack/contrib/floating_ips.py b/nova/api/openstack/contrib/floating_ips.py
index b4a211857..3d8049324 100644
--- a/nova/api/openstack/contrib/floating_ips.py
+++ b/nova/api/openstack/contrib/floating_ips.py
@@ -27,9 +27,9 @@ from nova.api.openstack import extensions
def _translate_floating_ip_view(floating_ip):
result = {'id': floating_ip['id'],
'ip': floating_ip['address']}
- if 'fixed_ip' in floating_ip:
+ try:
result['fixed_ip'] = floating_ip['fixed_ip']['address']
- else:
+ except (TypeError, KeyError):
result['fixed_ip'] = None
if 'instance' in floating_ip:
result['instance_id'] = floating_ip['instance']['id']
diff --git a/nova/api/openstack/contrib/multinic.py b/nova/api/openstack/contrib/multinic.py
index 841061721..da8dcee5d 100644
--- a/nova/api/openstack/contrib/multinic.py
+++ b/nova/api/openstack/contrib/multinic.py
@@ -16,6 +16,7 @@
"""The multinic extension."""
from webob import exc
+import webob
from nova import compute
from nova import log as logging
@@ -103,7 +104,7 @@ class Multinic(extensions.ExtensionDescriptor):
except Exception, e:
LOG.exception(_("Error in addFixedIp %s"), e)
return faults.Fault(exc.HTTPBadRequest())
- return exc.HTTPAccepted()
+ return webob.Response(status_int=202)
def _remove_fixed_ip(self, input_dict, req, id):
"""Removes an IP from an instance."""
@@ -122,4 +123,4 @@ class Multinic(extensions.ExtensionDescriptor):
except Exception, e:
LOG.exception(_("Error in removeFixedIp %s"), e)
return faults.Fault(exc.HTTPBadRequest())
- return exc.HTTPAccepted()
+ return webob.Response(status_int=202)
diff --git a/nova/api/openstack/contrib/volumes.py b/nova/api/openstack/contrib/volumes.py
index e5e2c5b50..867fe301e 100644
--- a/nova/api/openstack/contrib/volumes.py
+++ b/nova/api/openstack/contrib/volumes.py
@@ -16,15 +16,18 @@
"""The volumes extension."""
from webob import exc
+import webob
from nova import compute
from nova import exception
from nova import flags
from nova import log as logging
+from nova import quota
from nova import volume
from nova.api.openstack import common
from nova.api.openstack import extensions
from nova.api.openstack import faults
+from nova.api.openstack import servers
LOG = logging.getLogger("nova.api.volumes")
@@ -104,7 +107,7 @@ class VolumeController(object):
self.volume_api.delete(context, volume_id=id)
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
- return exc.HTTPAccepted()
+ return webob.Response(status_int=202)
def index(self, req):
"""Returns a summary list of volumes."""
@@ -279,7 +282,7 @@ class VolumeAttachmentController(object):
self.compute_api.detach_volume(context,
volume_id=volume_id)
- return exc.HTTPAccepted()
+ return webob.Response(status_int=202)
def _items(self, req, server_id, entity_maker):
"""Returns a list of attachments, transformed through entity_maker."""
@@ -296,6 +299,53 @@ class VolumeAttachmentController(object):
return {'volumeAttachments': res}
+class BootFromVolumeController(servers.ControllerV11):
+ """The boot from volume API controller for the Openstack API."""
+
+ def _create_instance(self, context, instance_type, image_href, **kwargs):
+ try:
+ return self.compute_api.create(context, instance_type,
+ image_href, **kwargs)
+ except quota.QuotaError as error:
+ self.helper._handle_quota_error(error)
+ except exception.ImageNotFound as error:
+ msg = _("Can not find requested image")
+ raise faults.Fault(exc.HTTPBadRequest(explanation=msg))
+
+ def create(self, req, body):
+ """ Creates a new server for a given user """
+ extra_values = None
+ try:
+
+ def get_kwargs(context, instance_type, image_href, **kwargs):
+ kwargs['context'] = context
+ kwargs['instance_type'] = instance_type
+ kwargs['image_href'] = image_href
+ return kwargs
+
+ extra_values, kwargs = self.helper.create_instance(req, body,
+ get_kwargs)
+
+ block_device_mapping = body['server'].get('block_device_mapping')
+ kwargs['block_device_mapping'] = block_device_mapping
+
+ instances = self._create_instance(**kwargs)
+ except faults.Fault, f:
+ return f
+
+ # We can only return 1 instance via the API, if we happen to
+ # build more than one... instances is a list, so we'll just
+ # use the first one..
+ inst = instances[0]
+ for key in ['instance_type', 'image_ref']:
+ inst[key] = extra_values[key]
+
+ builder = self._get_view_builder(req)
+ server = builder.build(inst, is_detail=True)
+ server['server']['adminPass'] = extra_values['password']
+ return server
+
+
class Volumes(extensions.ExtensionDescriptor):
def get_name(self):
return "Volumes"
@@ -329,4 +379,8 @@ class Volumes(extensions.ExtensionDescriptor):
collection_name='servers'))
resources.append(res)
+ res = extensions.ResourceExtension('os-volumes_boot',
+ BootFromVolumeController())
+ resources.append(res)
+
return resources
diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py
index 2654e3c40..894d47beb 100644
--- a/nova/api/openstack/create_instance_helper.py
+++ b/nova/api/openstack/create_instance_helper.py
@@ -20,6 +20,7 @@ import webob
from webob import exc
from xml.dom import minidom
+from nova import db
from nova import exception
from nova import flags
from nova import log as logging
@@ -28,9 +29,8 @@ from nova import quota
from nova import utils
from nova.compute import instance_types
-from nova.api.openstack import faults
+from nova.api.openstack import common
from nova.api.openstack import wsgi
-from nova.auth import manager as auth_manager
LOG = logging.getLogger('nova.api.openstack.create_instance_helper')
@@ -70,21 +70,32 @@ class CreateInstanceHelper(object):
return type from this method is left to the caller.
"""
if not body:
- raise faults.Fault(exc.HTTPUnprocessableEntity())
+ 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
- key_pairs = auth_manager.AuthManager.get_key_pairs(context)
+ # TODO(vish): Key pair access should move into a common library
+ # instead of being accessed directly from the db.
+ key_pairs = db.key_pair_get_all_by_user(context.elevated(),
+ context.user_id)
if key_pairs:
key_pair = key_pairs[0]
key_name = key_pair['name']
key_data = key_pair['public_key']
image_href = self.controller._image_ref_from_req_data(body)
+ # If the image href was generated by nova api, strip image_href
+ # down to an id and use the default glance connection params
+
+ if str(image_href).startswith(req.application_url):
+ image_href = image_href.split('/').pop()
try:
image_service, image_id = nova.image.get_image_service(image_href)
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(
@@ -94,28 +105,32 @@ class CreateInstanceHelper(object):
except Exception, e:
msg = _("Cannot find requested image %(image_href)s: %(e)s" %
locals())
- raise faults.Fault(exc.HTTPBadRequest(explanation=msg))
+ raise exc.HTTPBadRequest(explanation=msg)
- personality = body['server'].get('personality')
+ personality = server_dict.get('personality')
injected_files = []
if personality:
injected_files = self._get_injected_files(personality)
- flavor_id = self.controller._flavor_id_from_req_data(body)
+ try:
+ flavor_id = self.controller._flavor_id_from_req_data(body)
+ except ValueError as error:
+ 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'.
@@ -142,7 +157,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,
@@ -153,8 +168,10 @@ class CreateInstanceHelper(object):
self._handle_quota_error(error)
except exception.ImageNotFound as error:
msg = _("Can not find requested image")
- raise faults.Fault(exc.HTTPBadRequest(explanation=msg))
-
+ raise exc.HTTPBadRequest(explanation=msg)
+ except exception.FlavorNotFound as error:
+ msg = _("Invalid flavorRef provided.")
+ raise exc.HTTPBadRequest(explanation=msg)
# Let the caller deal with unhandled exceptions.
def _handle_quota_error(self, error):
@@ -180,7 +197,7 @@ class CreateInstanceHelper(object):
Overrides normal behavior in the case of xml content
"""
if request.content_type == "application/xml":
- deserializer = ServerCreateRequestXMLDeserializer()
+ deserializer = ServerXMLDeserializer()
return deserializer.deserialize(request.body)
else:
return self._deserialize(request.body, request.get_content_type())
@@ -285,6 +302,8 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer):
and personality attributes
"""
+ metadata_deserializer = common.MetadataXMLDeserializer()
+
def create(self, string):
"""Deserialize an xml-formatted server create request"""
dom = minidom.parseString(string)
@@ -294,61 +313,162 @@ 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')
- for attr in ["name", "imageId", "flavorId", "imageRef", "flavorRef"]:
+ server_node = self.find_first_child_named(node, 'server')
+
+ attributes = ["name", "imageId", "flavorId", "adminPass"]
+ for attr in attributes:
if server_node.getAttribute(attr):
server[attr] = server_node.getAttribute(attr)
- metadata = self._extract_metadata(server_node)
- if metadata is not None:
- server["metadata"] = metadata
- personality = self._extract_personality(server_node)
- if personality is not None:
- 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
+ metadata_node = self.find_first_child_named(server_node, "metadata")
+ server["metadata"] = self.metadata_deserializer.extract_metadata(
+ metadata_node)
+
+ server["personality"] = self._extract_personality(server_node)
+
+ return server
def _extract_personality(self, server_node):
"""Marshal the personality attribute of a parsed request"""
- personality_node = \
- self._find_first_child_named(server_node, "personality")
- if personality_node is None:
- return None
+ node = self.find_first_child_named(server_node, "personality")
personality = []
- 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)
- personality.append(item)
+ if node is not None:
+ for file_node in self.find_children_named(node, "file"):
+ item = {}
+ if file_node.hasAttribute("path"):
+ item["path"] = file_node.getAttribute("path")
+ 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
+
+class ServerXMLDeserializerV11(wsgi.MetadataXMLDeserializer):
+ """
+ Deserializer to handle xml-formatted server create requests.
+
+ Handles standard server attributes as well as optional metadata
+ and personality attributes
+ """
+
+ metadata_deserializer = common.MetadataXMLDeserializer()
+
+ def action(self, string):
+ dom = minidom.parseString(string)
+ action_node = dom.childNodes[0]
+ action_name = action_node.tagName
+
+ action_deserializer = {
+ 'createImage': self._action_create_image,
+ 'createBackup': self._action_create_backup,
+ 'changePassword': self._action_change_password,
+ 'reboot': self._action_reboot,
+ 'rebuild': self._action_rebuild,
+ 'resize': self._action_resize,
+ 'confirmResize': self._action_confirm_resize,
+ 'revertResize': self._action_revert_resize,
+ }.get(action_name, self.default)
+
+ action_data = action_deserializer(action_node)
+
+ return {'body': {action_name: action_data}}
+
+ def _action_create_image(self, node):
+ return self._deserialize_image_action(node, ('name',))
+
+ def _action_create_backup(self, node):
+ attributes = ('name', 'backup_type', 'rotation')
+ return self._deserialize_image_action(node, attributes)
+
+ def _action_change_password(self, node):
+ if not node.hasAttribute("adminPass"):
+ raise AttributeError("No adminPass was specified in request")
+ return {"adminPass": node.getAttribute("adminPass")}
+
+ def _action_reboot(self, node):
+ if not node.hasAttribute("type"):
+ raise AttributeError("No reboot type was specified in request")
+ return {"type": node.getAttribute("type")}
+
+ def _action_rebuild(self, node):
+ rebuild = {}
+ if node.hasAttribute("name"):
+ rebuild['name'] = node.getAttribute("name")
+
+ metadata_node = self.find_first_child_named(node, "metadata")
+ if metadata_node is not None:
+ rebuild["metadata"] = self.extract_metadata(metadata_node)
+
+ personality = self._extract_personality(node)
+ if personality is not None:
+ rebuild["personality"] = personality
+
+ if not node.hasAttribute("imageRef"):
+ raise AttributeError("No imageRef was specified in request")
+ rebuild["imageRef"] = node.getAttribute("imageRef")
+
+ return rebuild
+
+ def _action_resize(self, node):
+ if not node.hasAttribute("flavorRef"):
+ raise AttributeError("No flavorRef was specified in request")
+ return {"flavorRef": node.getAttribute("flavorRef")}
+
+ def _action_confirm_resize(self, 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 _action_revert_resize(self, node):
+ return None
+
+ def _deserialize_image_action(self, node, allowed_attributes):
+ data = {}
+ for attribute in allowed_attributes:
+ value = node.getAttribute(attribute)
+ if value:
+ data[attribute] = value
+ metadata_node = self.find_first_child_named(node, 'metadata')
+ if metadata_node is not None:
+ metadata = self.metadata_deserializer.extract_metadata(
+ metadata_node)
+ data['metadata'] = metadata
+ return data
+
+ def create(self, string):
+ """Deserialize an xml-formatted server create request"""
+ dom = minidom.parseString(string)
+ server = self._extract_server(dom)
+ return {'body': {'server': server}}
+
+ def _extract_server(self, node):
+ """Marshal the server attribute of a parsed request"""
+ server = {}
+ server_node = self.find_first_child_named(node, 'server')
+
+ attributes = ["name", "imageRef", "flavorRef", "adminPass"]
+ for attr in attributes:
+ if server_node.getAttribute(attr):
+ server[attr] = server_node.getAttribute(attr)
+
+ metadata_node = self.find_first_child_named(server_node, "metadata")
+ if metadata_node is not None:
+ server["metadata"] = self.extract_metadata(metadata_node)
+
+ personality = self._extract_personality(server_node)
+ if personality is not None:
+ server["personality"] = personality
+
+ return server
+
+ def _extract_personality(self, server_node):
+ """Marshal the personality attribute of a parsed request"""
+ node = self.find_first_child_named(server_node, "personality")
+ if node is not None:
+ personality = []
+ for file_node in self.find_children_named(node, "file"):
+ item = {}
+ if file_node.hasAttribute("path"):
+ item["path"] = file_node.getAttribute("path")
+ item["contents"] = self.extract_text(file_node)
+ personality.append(item)
+ return personality
+ else:
+ return None
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py
index da06ecd15..cc889703e 100644
--- a/nova/api/openstack/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -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')
diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py
index b9a23c126..1ab45d4f1 100644
--- a/nova/api/openstack/faults.py
+++ b/nova/api/openstack/faults.py
@@ -19,6 +19,7 @@
import webob.dec
import webob.exc
+from nova.api.openstack import common
from nova.api.openstack import wsgi
@@ -40,6 +41,7 @@ class Fault(webob.exc.HTTPException):
def __init__(self, exception):
"""Create a Fault for the given webob.exc.exception."""
self.wrapped_exc = exception
+ self.status_int = exception.status_int
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
@@ -60,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]
@@ -99,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]
diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py
index 6fab13147..b4bda68d4 100644
--- a/nova/api/openstack/flavors.py
+++ b/nova/api/openstack/flavors.py
@@ -16,6 +16,7 @@
# under the License.
import webob
+import xml.dom.minidom as minidom
from nova import db
from nova import exception
@@ -74,19 +75,65 @@ class ControllerV11(Controller):
return views.flavors.ViewBuilderV11(base_url)
+class FlavorXMLSerializer(wsgi.XMLDictSerializer):
+
+ def __init__(self):
+ super(FlavorXMLSerializer, self).__init__(xmlns=wsgi.XMLNS_V11)
+
+ def _flavor_to_xml(self, xml_doc, flavor, detailed):
+ flavor_node = xml_doc.createElement('flavor')
+ flavor_node.setAttribute('id', str(flavor['id']))
+ flavor_node.setAttribute('name', flavor['name'])
+
+ if detailed:
+ flavor_node.setAttribute('ram', str(flavor['ram']))
+ flavor_node.setAttribute('disk', str(flavor['disk']))
+
+ link_nodes = self._create_link_nodes(xml_doc, flavor['links'])
+ for link_node in link_nodes:
+ flavor_node.appendChild(link_node)
+ return flavor_node
+
+ def _flavors_list_to_xml(self, xml_doc, flavors, detailed):
+ container_node = xml_doc.createElement('flavors')
+
+ for flavor in flavors:
+ item_node = self._flavor_to_xml(xml_doc, flavor, detailed)
+ container_node.appendChild(item_node)
+ return container_node
+
+ def show(self, flavor_container):
+ xml_doc = minidom.Document()
+ flavor = flavor_container['flavor']
+ node = self._flavor_to_xml(xml_doc, flavor, True)
+ return self.to_xml_string(node, True)
+
+ def detail(self, flavors_container):
+ xml_doc = minidom.Document()
+ flavors = flavors_container['flavors']
+ node = self._flavors_list_to_xml(xml_doc, flavors, True)
+ return self.to_xml_string(node, True)
+
+ def index(self, flavors_container):
+ xml_doc = minidom.Document()
+ flavors = flavors_container['flavors']
+ node = self._flavors_list_to_xml(xml_doc, flavors, False)
+ return self.to_xml_string(node, True)
+
+
def create_resource(version='1.0'):
controller = {
'1.0': ControllerV10,
'1.1': ControllerV11,
}[version]()
- xmlns = {
- '1.0': wsgi.XMLNS_V10,
- '1.1': wsgi.XMLNS_V11,
+ xml_serializer = {
+ '1.0': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V10),
+ '1.1': FlavorXMLSerializer(),
}[version]
body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(xmlns=xmlns),
+ 'application/xml': xml_serializer,
}
serializer = wsgi.ResponseSerializer(body_serializers)
diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py
index 4f33844fa..aaf64a123 100644
--- a/nova/api/openstack/image_metadata.py
+++ b/nova/api/openstack/image_metadata.py
@@ -16,13 +16,12 @@
# under the License.
from webob import exc
-from xml.dom import minidom
from nova import flags
from nova import image
from nova import quota
from nova import utils
-from nova.api.openstack import faults
+from nova.api.openstack import common
from nova.api.openstack import wsgi
@@ -62,7 +61,7 @@ class Controller(object):
if id in metadata:
return {'meta': {id: metadata[id]}}
else:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
def create(self, req, image_id, body):
context = req.environ['nova.context']
@@ -97,72 +96,39 @@ 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']
img = self.image_service.show(context, image_id)
metadata = self._get_metadata(context, image_id)
if not id in metadata:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
metadata.pop(id)
img['properties'] = metadata
self.image_service.update(context, image_id, img, None)
-class ImageMetadataXMLSerializer(wsgi.XMLDictSerializer):
- def __init__(self, xmlns=wsgi.XMLNS_V11):
- super(ImageMetadataXMLSerializer, self).__init__(xmlns=xmlns)
-
- def _meta_item_to_xml(self, doc, key, value):
- node = doc.createElement('meta')
- doc.appendChild(node)
- node.setAttribute('key', '%s' % key)
- text = doc.createTextNode('%s' % value)
- node.appendChild(text)
- return node
-
- def meta_list_to_xml(self, xml_doc, meta_items):
- container_node = xml_doc.createElement('metadata')
- for (key, value) in meta_items:
- item_node = self._meta_item_to_xml(xml_doc, key, value)
- container_node.appendChild(item_node)
- return container_node
-
- def _meta_list_to_xml_string(self, metadata_dict):
- xml_doc = minidom.Document()
- items = metadata_dict['metadata'].items()
- container_node = self.meta_list_to_xml(xml_doc, items)
- xml_doc.appendChild(container_node)
- self._add_xmlns(container_node)
- return xml_doc.toprettyxml(indent=' ', encoding='UTF-8')
-
- def index(self, metadata_dict):
- return self._meta_list_to_xml_string(metadata_dict)
-
- def create(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]
- item_node = self._meta_item_to_xml(xml_doc, item_key, item_value)
- xml_doc.appendChild(item_node)
- self._add_xmlns(item_node)
- return xml_doc.toprettyxml(indent=' ', encoding='UTF-8')
-
- def show(self, meta_item_dict):
- return self._meta_item_to_xml_string(meta_item_dict['meta'])
-
- def update(self, meta_item_dict):
- return self._meta_item_to_xml_string(meta_item_dict['meta'])
+def create_resource():
+ headers_serializer = common.MetadataHeadersSerializer()
+ body_deserializers = {
+ 'application/xml': common.MetadataXMLDeserializer(),
+ }
-def create_resource():
body_serializers = {
- 'application/xml': ImageMetadataXMLSerializer(),
+ 'application/xml': common.MetadataXMLSerializer(),
}
- 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)
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index d0317583e..b9bc83fde 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -25,7 +25,6 @@ from nova import flags
import nova.image
from nova import log
from nova.api.openstack import common
-from nova.api.openstack import faults
from nova.api.openstack import image_metadata
from nova.api.openstack import servers
from nova.api.openstack.views import images as images_view
@@ -35,7 +34,13 @@ from nova.api.openstack import wsgi
LOG = log.getLogger('nova.api.openstack.images')
FLAGS = flags.FLAGS
-SUPPORTED_FILTERS = ['name', 'status']
+SUPPORTED_FILTERS = {
+ 'name': 'name',
+ 'status': 'status',
+ 'changes-since': 'changes-since',
+ 'server': 'property-instance_ref',
+ 'type': 'property-image_type',
+}
class Controller(object):
@@ -62,8 +67,9 @@ class Controller(object):
filters = {}
for param in req.str_params:
if param in SUPPORTED_FILTERS or param.startswith('property-'):
- filters[param] = req.str_params.get(param)
-
+ # map filter name or carry through if property-*
+ filter_name = SUPPORTED_FILTERS.get(param, param)
+ filters[filter_name] = req.str_params.get(param)
return filters
def show(self, req, id):
@@ -78,7 +84,7 @@ class Controller(object):
image = self._image_service.show(context, id)
except (exception.NotFound, exception.InvalidImageRef):
explanation = _("Image not found.")
- raise faults.Fault(webob.exc.HTTPNotFound(explanation=explanation))
+ raise webob.exc.HTTPNotFound(explanation=explanation)
return dict(image=self.get_builder(req).build(image, detail=True))
@@ -92,79 +98,38 @@ class Controller(object):
self._image_service.delete(context, id)
return webob.exc.HTTPNoContent()
- def create(self, req, body):
- """Snapshot or backup a server instance and save the image.
-
- Images now have an `image_type` associated with them, which can be
- 'snapshot' or the backup type, like 'daily' or 'weekly'.
-
- If the image_type is backup-like, then the rotation factor can be
- included and that will cause the oldest backups that exceed the
- rotation factor to be deleted.
-
- :param req: `wsgi.Request` object
- """
- def get_param(param):
- try:
- return body["image"][param]
- except KeyError:
- raise webob.exc.HTTPBadRequest(explanation="Missing required "
- "param: %s" % param)
-
- context = req.environ['nova.context']
- content_type = req.get_content_type()
-
- if not body:
- raise webob.exc.HTTPBadRequest()
-
- image_type = body["image"].get("image_type", "snapshot")
-
- try:
- server_id = self._server_id_from_req(req, body)
- except KeyError:
- raise webob.exc.HTTPBadRequest()
-
- image_name = get_param("name")
- props = self._get_extra_properties(req, body)
-
- if image_type == "snapshot":
- image = self._compute_service.snapshot(
- context, server_id, image_name,
- extra_properties=props)
- elif image_type == "backup":
- # NOTE(sirp): Unlike snapshot, backup is not a customer facing
- # API call; rather, it's used by the internal backup scheduler
- if not FLAGS.allow_admin_api:
- raise webob.exc.HTTPBadRequest(
- explanation="Admin API Required")
-
- backup_type = get_param("backup_type")
- rotation = int(get_param("rotation"))
-
- image = self._compute_service.backup(
- context, server_id, image_name,
- backup_type, rotation, extra_properties=props)
- else:
- LOG.error(_("Invalid image_type '%s' passed") % image_type)
- raise webob.exc.HTTPBadRequest(explanation="Invalue image_type: "
- "%s" % image_type)
-
- return dict(image=self.get_builder(req).build(image, detail=True))
-
def get_builder(self, request):
"""Indicates that you must use a Controller subclass."""
raise NotImplementedError()
- def _server_id_from_req(self, req, data):
- raise NotImplementedError()
-
- def _get_extra_properties(self, req, data):
- return {}
-
class ControllerV10(Controller):
"""Version 1.0 specific controller logic."""
+ def create(self, req, body):
+ """Snapshot a server instance and save the image."""
+ try:
+ image = body["image"]
+ except (KeyError, TypeError):
+ msg = _("Invalid image entity")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ try:
+ image_name = image["name"]
+ instance_id = image["serverId"]
+ except KeyError as missing_key:
+ msg = _("Image entity requires %s") % missing_key
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ context = req.environ["nova.context"]
+ props = {'instance_id': instance_id}
+ image = self._compute_service.snapshot(context,
+ instance_id,
+ image_name,
+ extra_properties=props)
+
+ return dict(image=self.get_builder(req).build(image, detail=True))
+
def get_builder(self, request):
"""Property to get the ViewBuilder class we need to use."""
base_url = request.application_url
@@ -178,7 +143,7 @@ class ControllerV10(Controller):
"""
context = req.environ['nova.context']
filters = self._get_filters(req)
- images = self._image_service.index(context, filters)
+ images = self._image_service.index(context, filters=filters)
images = common.limited(images, req)
builder = self.get_builder(req).build
return dict(images=[builder(image, detail=False) for image in images])
@@ -191,18 +156,11 @@ class ControllerV10(Controller):
"""
context = req.environ['nova.context']
filters = self._get_filters(req)
- images = self._image_service.detail(context, filters)
+ images = self._image_service.detail(context, filters=filters)
images = common.limited(images, req)
builder = self.get_builder(req).build
return dict(images=[builder(image, detail=True) for image in images])
- def _server_id_from_req(self, req, data):
- try:
- return data['image']['serverId']
- except KeyError:
- msg = _("Expected serverId attribute on server entity.")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
class ControllerV11(Controller):
"""Version 1.1 specific controller logic."""
@@ -240,37 +198,8 @@ class ControllerV11(Controller):
builder = self.get_builder(req).build
return dict(images=[builder(image, detail=True) for image in images])
- def _server_id_from_req(self, req, data):
- try:
- server_ref = data['image']['serverRef']
- except KeyError:
- msg = _("Expected serverRef attribute on server entity.")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
- if not server_ref.startswith('http'):
- return server_ref
-
- passed = urlparse.urlparse(server_ref)
- expected = urlparse.urlparse(req.application_url)
- version = expected.path.split('/')[1]
- expected_prefix = "/%s/servers/" % version
- _empty, _sep, server_id = passed.path.partition(expected_prefix)
- scheme_ok = passed.scheme == expected.scheme
- host_ok = passed.hostname == expected.hostname
- port_ok = (passed.port == expected.port or
- passed.port == FLAGS.osapi_port)
- if not (scheme_ok and port_ok and host_ok and server_id):
- msg = _("serverRef must match request url")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
- return server_id
-
- def _get_extra_properties(self, req, data):
- server_ref = data['image']['serverRef']
- if not server_ref.startswith('http'):
- server_ref = os.path.join(req.application_url, 'servers',
- server_ref)
- return {'instance_ref': server_ref}
+ def create(self, *args, **kwargs):
+ raise webob.exc.HTTPMethodNotAllowed()
class ImageXMLSerializer(wsgi.XMLDictSerializer):
@@ -278,7 +207,7 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer):
xmlns = wsgi.XMLNS_V11
def __init__(self):
- self.metadata_serializer = image_metadata.ImageMetadataXMLSerializer()
+ self.metadata_serializer = common.MetadataXMLSerializer()
def _image_to_xml(self, xml_doc, image):
image_node = xml_doc.createElement('image')
@@ -363,12 +292,6 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer):
image_dict['image'])
return self.to_xml_string(node, True)
- def create(self, image_dict):
- xml_doc = minidom.Document()
- node = self._image_to_xml_detailed(xml_doc,
- image_dict['image'])
- return self.to_xml_string(node, True)
-
def create_resource(version='1.0'):
controller = {
diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py
index 1ebfdb831..a74fae487 100644
--- a/nova/api/openstack/ips.py
+++ b/nova/api/openstack/ips.py
@@ -16,11 +16,11 @@
# under the License.
import time
+from xml.dom import minidom
from webob import exc
import nova
-from nova.api.openstack import faults
import nova.api.openstack.views.addresses
from nova.api.openstack import wsgi
from nova import db
@@ -37,14 +37,14 @@ class Controller(object):
instance = self.compute_api.get(
req.environ['nova.context'], server_id)
except nova.exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
return instance
def create(self, req, server_id, body):
- return faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def delete(self, req, server_id, id):
- return faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
class ControllerV10(Controller):
@@ -63,7 +63,7 @@ class ControllerV10(Controller):
view = builder.build_public_parts(instance)
else:
msg = _("Only private and public networks available")
- return faults.Fault(exc.HTTPNotFound(explanation=msg))
+ raise exc.HTTPNotFound(explanation=msg)
return {id: view}
@@ -86,7 +86,7 @@ class ControllerV11(Controller):
if network is None:
msg = _("Instance is not a member of specified network")
- return faults.Fault(exc.HTTPNotFound(explanation=msg))
+ raise exc.HTTPNotFound(explanation=msg)
return network
@@ -101,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'},
@@ -119,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)
diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py
index bc76547d8..86afa3b62 100644
--- a/nova/api/openstack/limits.py
+++ b/nova/api/openstack/limits.py
@@ -25,6 +25,7 @@ import re
import time
import urllib
import webob.exc
+from xml.dom import minidom
from collections import defaultdict
@@ -76,6 +77,58 @@ class LimitsControllerV11(LimitsController):
return limits_views.ViewBuilderV11()
+class LimitsXMLSerializer(wsgi.XMLDictSerializer):
+
+ xmlns = wsgi.XMLNS_V11
+
+ def __init__(self):
+ pass
+
+ def _create_rates_node(self, xml_doc, rates):
+ rates_node = xml_doc.createElement('rates')
+ for rate in rates:
+ rate_node = xml_doc.createElement('rate')
+ rate_node.setAttribute('uri', rate['uri'])
+ rate_node.setAttribute('regex', rate['regex'])
+
+ for limit in rate['limit']:
+ limit_node = xml_doc.createElement('limit')
+ limit_node.setAttribute('value', str(limit['value']))
+ limit_node.setAttribute('verb', limit['verb'])
+ limit_node.setAttribute('remaining', str(limit['remaining']))
+ limit_node.setAttribute('unit', limit['unit'])
+ limit_node.setAttribute('next-available',
+ str(limit['next-available']))
+ rate_node.appendChild(limit_node)
+
+ rates_node.appendChild(rate_node)
+ return rates_node
+
+ def _create_absolute_node(self, xml_doc, absolutes):
+ absolute_node = xml_doc.createElement('absolute')
+ for key, value in absolutes.iteritems():
+ limit_node = xml_doc.createElement('limit')
+ limit_node.setAttribute('name', key)
+ limit_node.setAttribute('value', str(value))
+ absolute_node.appendChild(limit_node)
+ return absolute_node
+
+ def _limits_to_xml(self, xml_doc, limits):
+ limits_node = xml_doc.createElement('limits')
+ rates_node = self._create_rates_node(xml_doc, limits['rate'])
+ limits_node.appendChild(rates_node)
+
+ absolute_node = self._create_absolute_node(xml_doc, limits['absolute'])
+ limits_node.appendChild(absolute_node)
+
+ return limits_node
+
+ def index(self, limits_dict):
+ xml_doc = minidom.Document()
+ node = self._limits_to_xml(xml_doc, limits_dict['limits'])
+ return self.to_xml_string(node, False)
+
+
def create_resource(version='1.0'):
controller = {
'1.0': LimitsControllerV10,
@@ -97,9 +150,13 @@ def create_resource(version='1.0'):
},
}
+ xml_serializer = {
+ '1.0': wsgi.XMLDictSerializer(xmlns=xmlns, metadata=metadata),
+ '1.1': LimitsXMLSerializer(),
+ }[version]
+
body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(xmlns=xmlns,
- metadata=metadata),
+ 'application/xml': xml_serializer,
}
serializer = wsgi.ResponseSerializer(body_serializers)
diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py
index 3b9169f81..b0b014f86 100644
--- a/nova/api/openstack/server_metadata.py
+++ b/nova/api/openstack/server_metadata.py
@@ -18,7 +18,7 @@
from webob import exc
from nova import compute
-from nova.api.openstack import faults
+from nova.api.openstack import common
from nova.api.openstack import wsgi
from nova import exception
from nova import quota
@@ -32,36 +32,37 @@ class Controller(object):
super(Controller, self).__init__()
def _get_metadata(self, context, server_id):
- metadata = self.compute_api.get_instance_metadata(context, server_id)
+ try:
+ meta = self.compute_api.get_instance_metadata(context, server_id)
+ except exception.InstanceNotFound:
+ msg = _('Server does not exist')
+ raise exc.HTTPNotFound(explanation=msg)
+
meta_dict = {}
- for key, value in metadata.iteritems():
+ for key, value in meta.iteritems():
meta_dict[key] = value
- return dict(metadata=meta_dict)
-
- def _check_body(self, body):
- if body == None or body == "":
- expl = _('No Request Body')
- raise exc.HTTPBadRequest(explanation=expl)
+ return meta_dict
def index(self, req, server_id):
""" Returns the list of metadata for a given instance """
context = req.environ['nova.context']
- try:
- return self._get_metadata(context, server_id)
- except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
- raise exc.HTTPNotFound(explanation=msg)
+ return {'metadata': self._get_metadata(context, server_id)}
def create(self, req, server_id, body):
- self._check_body(body)
+ try:
+ metadata = body['metadata']
+ except (KeyError, TypeError):
+ msg = _("Malformed request body")
+ raise exc.HTTPBadRequest(explanation=msg)
+
context = req.environ['nova.context']
- metadata = body.get('metadata')
+
try:
self.compute_api.update_or_create_instance_metadata(context,
server_id,
metadata)
except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
+ msg = _('Server does not exist')
raise exc.HTTPNotFound(explanation=msg)
except quota.QuotaError as error:
@@ -70,51 +71,80 @@ class Controller(object):
return body
def update(self, req, server_id, id, body):
- self._check_body(body)
- context = req.environ['nova.context']
- if not id in body:
+ try:
+ meta_item = body['meta']
+ except (TypeError, KeyError):
+ expl = _('Malformed request body')
+ raise exc.HTTPBadRequest(explanation=expl)
+
+ try:
+ meta_value = meta_item.pop(id)
+ except (AttributeError, KeyError):
expl = _('Request body and URI mismatch')
raise exc.HTTPBadRequest(explanation=expl)
- if len(body) > 1:
+
+ if len(meta_item) > 0:
expl = _('Request body contains too many items')
raise exc.HTTPBadRequest(explanation=expl)
+
+ context = req.environ['nova.context']
+ self._set_instance_metadata(context, server_id, meta_item)
+
+ return {'meta': {id: meta_value}}
+
+ def update_all(self, req, server_id, body):
+ try:
+ metadata = body['metadata']
+ except (TypeError, KeyError):
+ expl = _('Malformed request body')
+ raise exc.HTTPBadRequest(explanation=expl)
+
+ context = req.environ['nova.context']
+ self._set_instance_metadata(context, server_id, metadata)
+
+ return {'metadata': metadata}
+
+ def _set_instance_metadata(self, context, server_id, metadata):
try:
self.compute_api.update_or_create_instance_metadata(context,
server_id,
- body)
+ metadata)
except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
+ msg = _('Server does not exist')
raise exc.HTTPNotFound(explanation=msg)
+ except ValueError:
+ msg = _("Malformed request body")
+ raise exc.HTTPBadRequest(explanation=msg)
+
except quota.QuotaError as error:
self._handle_quota_error(error)
- return body
-
def show(self, req, server_id, id):
""" Return a single metadata item """
context = req.environ['nova.context']
- try:
- data = self._get_metadata(context, server_id)
- except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
- raise exc.HTTPNotFound(explanation=msg)
+ data = self._get_metadata(context, server_id)
try:
- return {id: data['metadata'][id]}
+ return {'meta': {id: data[id]}}
except KeyError:
- msg = _("metadata item %s was not found" % (id))
+ msg = _("Metadata item was not found")
raise exc.HTTPNotFound(explanation=msg)
def delete(self, req, server_id, id):
""" Deletes an existing metadata """
context = req.environ['nova.context']
+
+ metadata = self._get_metadata(context, server_id)
+
try:
- self.compute_api.delete_instance_metadata(context, server_id, id)
- except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
+ meta_key = metadata[id]
+ except KeyError:
+ msg = _("Metadata item was not found")
raise exc.HTTPNotFound(explanation=msg)
+ self.compute_api.delete_instance_metadata(context, server_id, meta_key)
+
def _handle_quota_error(self, error):
"""Reraise quota errors as api-specific http exceptions."""
if error.code == "MetadataLimitExceeded":
@@ -123,10 +153,16 @@ class Controller(object):
def create_resource():
- body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V11),
+ headers_serializer = common.MetadataHeadersSerializer()
+
+ body_deserializers = {
+ 'application/xml': common.MetadataXMLDeserializer(),
}
- serializer = wsgi.ResponseSerializer(body_serializers)
+ body_serializers = {
+ 'application/xml': common.MetadataXMLSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer)
+ deserializer = wsgi.RequestDeserializer(body_deserializers)
- return wsgi.Resource(Controller(), serializer=serializer)
+ return wsgi.Resource(Controller(), deserializer, serializer)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 93f8e832c..1051ba571 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -14,26 +14,29 @@
# under the License.
import base64
+import os
import traceback
from webob import exc
+from xml.dom import minidom
+import webob
from nova import compute
-from nova import db
from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
from nova.api.openstack import common
from nova.api.openstack import create_instance_helper as helper
-from nova.api.openstack import faults
+from nova.api.openstack import ips
+from nova.api.openstack import wsgi
+from nova.compute import instance_types
+from nova.scheduler import api as scheduler_api
+import nova.api.openstack
import nova.api.openstack.views.addresses
import nova.api.openstack.views.flavors
import nova.api.openstack.views.images
import nova.api.openstack.views.servers
-from nova.api.openstack import wsgi
-import nova.api.openstack
-from nova.scheduler import api as scheduler_api
LOG = logging.getLogger('nova.api.openstack.servers')
@@ -101,17 +104,14 @@ class Controller(object):
req.environ['nova.context'], id)
return self._build_view(req, instance, is_detail=True)
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
def create(self, req, body):
""" Creates a new server for a given user """
extra_values = None
result = None
- try:
- extra_values, instances = self.helper.create_instance(
- req, body, self.compute_api.create)
- except faults.Fault, f:
- return f
+ extra_values, instances = self.helper.create_instance(
+ req, body, self.compute_api.create)
# We can only return 1 instance via the API, if we happen to
# build more than one... instances is a list, so we'll just
@@ -131,7 +131,7 @@ class Controller(object):
raise exc.HTTPUnprocessableEntity()
if not body:
- return faults.Fault(exc.HTTPUnprocessableEntity())
+ raise exc.HTTPUnprocessableEntity()
ctxt = req.environ['nova.context']
update_dict = {}
@@ -146,7 +146,7 @@ class Controller(object):
try:
self.compute_api.update(ctxt, id, **update_dict)
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
return exc.HTTPNoContent()
@@ -155,22 +155,93 @@ class Controller(object):
@scheduler_api.redirect_handler
def action(self, req, id, body):
- """Multi-purpose method used to reboot, rebuild, or
- resize a server"""
+ """Multi-purpose method used to take actions on a server"""
- actions = {
+ self.actions = {
'changePassword': self._action_change_password,
'reboot': self._action_reboot,
'resize': self._action_resize,
'confirmResize': self._action_confirm_resize,
'revertResize': self._action_revert_resize,
'rebuild': self._action_rebuild,
- 'migrate': self._action_migrate}
+ 'createImage': self._action_create_image,
+ }
+
+ if FLAGS.allow_admin_api:
+ admin_actions = {
+ 'createBackup': self._action_create_backup,
+ }
+ self.actions.update(admin_actions)
- for key in actions.keys():
+ for key in self.actions.keys():
if key in body:
- return actions[key](body, req, id)
- return faults.Fault(exc.HTTPNotImplemented())
+ return self.actions[key](body, req, id)
+
+ raise exc.HTTPNotImplemented()
+
+ def _action_create_backup(self, input_dict, req, instance_id):
+ """Backup a server instance.
+
+ Images now have an `image_type` associated with them, which can be
+ 'snapshot' or the backup type, like 'daily' or 'weekly'.
+
+ If the image_type is backup-like, then the rotation factor can be
+ included and that will cause the oldest backups that exceed the
+ rotation factor to be deleted.
+
+ """
+ entity = input_dict["createBackup"]
+
+ try:
+ image_name = entity["name"]
+ backup_type = entity["backup_type"]
+ rotation = entity["rotation"]
+
+ except KeyError as missing_key:
+ msg = _("createBackup entity requires %s attribute") % missing_key
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ except TypeError:
+ msg = _("Malformed createBackup entity")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ try:
+ rotation = int(rotation)
+ except ValueError:
+ msg = _("createBackup attribute 'rotation' must be an integer")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ # preserve link to server in image properties
+ server_ref = os.path.join(req.application_url,
+ 'servers',
+ str(instance_id))
+ props = {'instance_ref': server_ref}
+
+ metadata = entity.get('metadata', {})
+ try:
+ props.update(metadata)
+ except ValueError:
+ msg = _("Invalid metadata")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ context = req.environ["nova.context"]
+ image = self.compute_api.backup(context,
+ instance_id,
+ image_name,
+ backup_type,
+ rotation,
+ extra_properties=props)
+
+ # build location of newly-created image entity
+ image_id = str(image['id'])
+ image_ref = os.path.join(req.application_url, 'images', image_id)
+
+ resp = webob.Response(status_int=202)
+ resp.headers['Location'] = image_ref
+ return resp
+
+ def _action_create_image(self, input_dict, req, id):
+ return exc.HTTPNotImplemented()
def _action_change_password(self, input_dict, req, id):
return exc.HTTPNotImplemented()
@@ -180,7 +251,7 @@ class Controller(object):
self.compute_api.confirm_resize(req.environ['nova.context'], id)
except Exception, e:
LOG.exception(_("Error in confirm-resize %s"), e)
- return faults.Fault(exc.HTTPBadRequest())
+ raise exc.HTTPBadRequest()
return exc.HTTPNoContent()
def _action_revert_resize(self, input_dict, req, id):
@@ -188,34 +259,32 @@ class Controller(object):
self.compute_api.revert_resize(req.environ['nova.context'], id)
except Exception, e:
LOG.exception(_("Error in revert-resize %s"), e)
- return faults.Fault(exc.HTTPBadRequest())
- return exc.HTTPAccepted()
+ raise exc.HTTPBadRequest()
+ return webob.Response(status_int=202)
def _action_resize(self, input_dict, req, id):
return exc.HTTPNotImplemented()
def _action_reboot(self, input_dict, req, id):
if 'reboot' in input_dict and 'type' in input_dict['reboot']:
- reboot_type = input_dict['reboot']['type']
+ valid_reboot_types = ['HARD', 'SOFT']
+ reboot_type = input_dict['reboot']['type'].upper()
+ if not valid_reboot_types.count(reboot_type):
+ msg = _("Argument 'type' for reboot is not HARD or SOFT")
+ LOG.exception(msg)
+ raise exc.HTTPBadRequest(explanation=msg)
else:
- LOG.exception(_("Missing argument 'type' for reboot"))
- return faults.Fault(exc.HTTPUnprocessableEntity())
+ msg = _("Missing argument 'type' for reboot")
+ LOG.exception(msg)
+ raise exc.HTTPBadRequest(explanation=msg)
try:
# TODO(gundlach): pass reboot_type, support soft reboot in
# virt driver
self.compute_api.reboot(req.environ['nova.context'], id)
except Exception, e:
LOG.exception(_("Error in reboot %s"), e)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
-
- def _action_migrate(self, input_dict, req, id):
- try:
- self.compute_api.resize(req.environ['nova.context'], id)
- except Exception, e:
- LOG.exception(_("Error in migrate %s"), e)
- return faults.Fault(exc.HTTPBadRequest())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def lock(self, req, id):
@@ -227,11 +296,11 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.lock(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::lock %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def unlock(self, req, id):
@@ -243,11 +312,11 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.unlock(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unlock %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def get_lock(self, req, id):
@@ -258,14 +327,14 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.get_lock(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::get_lock %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
- def reset_network(self, req, id, body):
+ def reset_network(self, req, id):
"""
Reset networking on an instance (admin only).
@@ -273,14 +342,14 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.reset_network(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::reset_network %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
- def inject_network_info(self, req, id, body):
+ def inject_network_info(self, req, id):
"""
Inject network info for an instance (admin only).
@@ -288,59 +357,68 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.inject_network_info(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::inject_network_info %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
- def pause(self, req, id, body):
+ def pause(self, req, id):
""" Permit Admins to Pause the server. """
ctxt = req.environ['nova.context']
try:
self.compute_api.pause(ctxt, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::pause %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
- def unpause(self, req, id, body):
+ def unpause(self, req, id):
""" Permit Admins to Unpause the server. """
ctxt = req.environ['nova.context']
try:
self.compute_api.unpause(ctxt, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unpause %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
- def suspend(self, req, id, body):
+ def suspend(self, req, id):
"""permit admins to suspend the server"""
context = req.environ['nova.context']
try:
self.compute_api.suspend(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::suspend %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
- def resume(self, req, id, body):
+ def resume(self, req, id):
"""permit admins to resume the server from suspend"""
context = req.environ['nova.context']
try:
self.compute_api.resume(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::resume %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
+
+ @scheduler_api.redirect_handler
+ def migrate(self, req, id):
+ try:
+ self.compute_api.resize(req.environ['nova.context'], id)
+ except Exception, e:
+ LOG.exception(_("Error in migrate %s"), e)
+ raise exc.HTTPBadRequest()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def rescue(self, req, id):
@@ -348,11 +426,11 @@ class Controller(object):
context = req.environ["nova.context"]
try:
self.compute_api.rescue(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::rescue %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def unrescue(self, req, id):
@@ -360,11 +438,11 @@ class Controller(object):
context = req.environ["nova.context"]
try:
self.compute_api.unrescue(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::unrescue %s"), readable)
- return faults.Fault(exc.HTTPUnprocessableEntity())
- return exc.HTTPAccepted()
+ raise exc.HTTPUnprocessableEntity()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def get_ajax_console(self, req, id):
@@ -373,8 +451,8 @@ class Controller(object):
self.compute_api.get_ajax_console(req.environ['nova.context'],
int(id))
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
- return exc.HTTPAccepted()
+ raise exc.HTTPNotFound()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def get_vnc_console(self, req, id):
@@ -383,8 +461,8 @@ class Controller(object):
self.compute_api.get_vnc_console(req.environ['nova.context'],
int(id))
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
- return exc.HTTPAccepted()
+ raise exc.HTTPNotFound()
+ return webob.Response(status_int=202)
@scheduler_api.redirect_handler
def diagnostics(self, req, id):
@@ -406,6 +484,24 @@ class Controller(object):
error=item.error))
return dict(actions=actions)
+ def resize(self, req, instance_id, flavor_id):
+ """Begin the resize process with given instance/flavor."""
+ context = req.environ["nova.context"]
+
+ try:
+ self.compute_api.resize(context, instance_id, flavor_id)
+ except exception.FlavorNotFound:
+ msg = _("Unable to locate requested flavor.")
+ raise exc.HTTPBadRequest(explanation=msg)
+ except exception.CannotResizeToSameSize:
+ msg = _("Resize requires a change in size.")
+ raise exc.HTTPBadRequest(explanation=msg)
+ except exception.CannotResizeToSmallerSize:
+ msg = _("Resizing to a smaller size is not supported.")
+ raise exc.HTTPBadRequest(explanation=msg)
+
+ return webob.Response(status_int=202)
+
class ControllerV10(Controller):
@@ -415,8 +511,8 @@ class ControllerV10(Controller):
try:
self.compute_api.delete(req.environ['nova.context'], id)
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
- return exc.HTTPAccepted()
+ raise exc.HTTPNotFound()
+ return webob.Response(status_int=202)
def _image_ref_from_req_data(self, data):
return data['server']['imageId']
@@ -440,39 +536,31 @@ class ControllerV10(Controller):
def _action_resize(self, input_dict, req, id):
""" Resizes a given instance to the flavor size requested """
try:
- if 'resize' in input_dict and 'flavorId' in input_dict['resize']:
- flavor_id = input_dict['resize']['flavorId']
- self.compute_api.resize(req.environ['nova.context'], id,
- flavor_id)
- else:
- LOG.exception(_("Missing 'flavorId' argument for resize"))
- return faults.Fault(exc.HTTPUnprocessableEntity())
- except Exception, e:
- LOG.exception(_("Error in resize %s"), e)
- return faults.Fault(exc.HTTPBadRequest())
- return exc.HTTPAccepted()
+ flavor_id = input_dict["resize"]["flavorId"]
+ except (KeyError, TypeError):
+ msg = _("Resize requests require 'flavorId' attribute.")
+ raise exc.HTTPBadRequest(explanation=msg)
+
+ return self.resize(req, id, flavor_id)
def _action_rebuild(self, info, request, instance_id):
context = request.environ['nova.context']
- instance_id = int(instance_id)
try:
image_id = info["rebuild"]["imageId"]
except (KeyError, TypeError):
msg = _("Could not parse imageId from request.")
LOG.debug(msg)
- return faults.Fault(exc.HTTPBadRequest(explanation=msg))
+ raise exc.HTTPBadRequest(explanation=msg)
try:
self.compute_api.rebuild(context, instance_id, image_id)
except exception.BuildInProgress:
- msg = _("Instance %d is currently being rebuilt.") % instance_id
+ msg = _("Instance %s is currently being rebuilt.") % instance_id
LOG.debug(msg)
- return faults.Fault(exc.HTTPConflict(explanation=msg))
+ raise exc.HTTPConflict(explanation=msg)
- response = exc.HTTPAccepted()
- response.empty_body = True
- return response
+ return webob.Response(status_int=202)
def _get_server_admin_password(self, server):
""" Determine the admin password for a server on creation """
@@ -487,14 +575,23 @@ class ControllerV11(Controller):
try:
self.compute_api.delete(req.environ['nova.context'], id)
except exception.NotFound:
- return faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
def _image_ref_from_req_data(self, data):
- return data['server']['imageRef']
+ try:
+ return data['server']['imageRef']
+ except (TypeError, KeyError):
+ msg = _("Missing imageRef attribute")
+ raise exc.HTTPBadRequest(explanation=msg)
def _flavor_id_from_req_data(self, data):
- href = data['server']['flavorRef']
- return common.get_id_from_href(href)
+ try:
+ flavor_ref = data['server']['flavorRef']
+ except (TypeError, KeyError):
+ msg = _("Missing flavorRef attribute")
+ raise exc.HTTPBadRequest(explanation=msg)
+
+ return common.get_id_from_href(flavor_ref)
def _build_view(self, req, instance, is_detail=False):
base_url = req.application_url
@@ -519,7 +616,7 @@ class ControllerV11(Controller):
msg = _("Invalid adminPass")
return exc.HTTPBadRequest(explanation=msg)
self.compute_api.set_admin_password(context, id, password)
- return exc.HTTPAccepted()
+ return webob.Response(status_int=202)
def _limit_items(self, items, req):
return common.limited_by_marker(items, req)
@@ -531,7 +628,7 @@ class ControllerV11(Controller):
except AttributeError as ex:
msg = _("Unable to parse metadata key/value pairs.")
LOG.debug(msg)
- raise faults.Fault(exc.HTTPBadRequest(explanation=msg))
+ raise exc.HTTPBadRequest(explanation=msg)
def _decode_personalities(self, personalities):
"""Decode the Base64-encoded personalities."""
@@ -542,41 +639,37 @@ class ControllerV11(Controller):
except (KeyError, TypeError):
msg = _("Unable to parse personality path/contents.")
LOG.info(msg)
- raise faults.Fault(exc.HTTPBadRequest(explanation=msg))
+ raise exc.HTTPBadRequest(explanation=msg)
try:
personality["contents"] = base64.b64decode(contents)
except TypeError:
msg = _("Personality content could not be Base64 decoded.")
LOG.info(msg)
- raise faults.Fault(exc.HTTPBadRequest(explanation=msg))
+ raise exc.HTTPBadRequest(explanation=msg)
def _action_resize(self, input_dict, req, id):
""" Resizes a given instance to the flavor size requested """
try:
- if 'resize' in input_dict and 'flavorRef' in input_dict['resize']:
- flavor_ref = input_dict['resize']['flavorRef']
- flavor_id = common.get_id_from_href(flavor_ref)
- self.compute_api.resize(req.environ['nova.context'], id,
- flavor_id)
- else:
- LOG.exception(_("Missing 'flavorRef' argument for resize"))
- return faults.Fault(exc.HTTPUnprocessableEntity())
- except Exception, e:
- LOG.exception(_("Error in resize %s"), e)
- return faults.Fault(exc.HTTPBadRequest())
- return exc.HTTPAccepted()
+ flavor_ref = input_dict["resize"]["flavorRef"]
+ if not flavor_ref:
+ msg = _("Resize request has invalid 'flavorRef' attribute.")
+ raise exc.HTTPBadRequest(explanation=msg)
+ except (KeyError, TypeError):
+ msg = _("Resize requests require 'flavorRef' attribute.")
+ raise exc.HTTPBadRequest(explanation=msg)
+
+ return self.resize(req, id, flavor_ref)
def _action_rebuild(self, info, request, instance_id):
context = request.environ['nova.context']
- instance_id = int(instance_id)
try:
image_href = info["rebuild"]["imageRef"]
except (KeyError, TypeError):
msg = _("Could not parse imageRef from request.")
LOG.debug(msg)
- return faults.Fault(exc.HTTPBadRequest(explanation=msg))
+ raise exc.HTTPBadRequest(explanation=msg)
personalities = info["rebuild"].get("personality", [])
metadata = info["rebuild"].get("metadata")
@@ -590,13 +683,53 @@ class ControllerV11(Controller):
self.compute_api.rebuild(context, instance_id, image_href, name,
metadata, personalities)
except exception.BuildInProgress:
- msg = _("Instance %d is currently being rebuilt.") % instance_id
+ msg = _("Instance %s is currently being rebuilt.") % instance_id
LOG.debug(msg)
- return faults.Fault(exc.HTTPConflict(explanation=msg))
+ raise exc.HTTPConflict(explanation=msg)
+
+ return webob.Response(status_int=202)
- response = exc.HTTPAccepted()
- response.empty_body = True
- return response
+ def _action_create_image(self, input_dict, req, instance_id):
+ """Snapshot a server instance."""
+ entity = input_dict.get("createImage", {})
+
+ try:
+ image_name = entity["name"]
+
+ except KeyError:
+ msg = _("createImage entity requires name attribute")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ except TypeError:
+ msg = _("Malformed createImage entity")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ # preserve link to server in image properties
+ server_ref = os.path.join(req.application_url,
+ 'servers',
+ str(instance_id))
+ props = {'instance_ref': server_ref}
+
+ metadata = entity.get('metadata', {})
+ try:
+ props.update(metadata)
+ except ValueError:
+ msg = _("Invalid metadata")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ context = req.environ['nova.context']
+ image = self.compute_api.snapshot(context,
+ instance_id,
+ image_name,
+ extra_properties=props)
+
+ # build location of newly-created image entity
+ image_id = str(image['id'])
+ image_ref = os.path.join(req.application_url, 'images', image_id)
+
+ resp = webob.Response(status_int=202)
+ resp.headers['Location'] = image_ref
+ return resp
def get_default_xmlns(self, req):
return common.XML_NS_V11
@@ -612,6 +745,123 @@ class HeadersSerializer(wsgi.ResponseHeadersSerializer):
response.status_int = 204
+class ServerXMLSerializer(wsgi.XMLDictSerializer):
+
+ xmlns = wsgi.XMLNS_V11
+
+ def __init__(self):
+ self.metadata_serializer = common.MetadataXMLSerializer()
+ self.addresses_serializer = ips.IPXMLSerializer()
+
+ def _create_basic_entity_node(self, xml_doc, id, links, name):
+ basic_node = xml_doc.createElement(name)
+ basic_node.setAttribute('id', str(id))
+ link_nodes = self._create_link_nodes(xml_doc, links)
+ for link_node in link_nodes:
+ basic_node.appendChild(link_node)
+ return basic_node
+
+ def _create_metadata_node(self, xml_doc, metadata):
+ return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata)
+
+ def _create_addresses_node(self, xml_doc, addresses):
+ return self.addresses_serializer.networks_to_xml(xml_doc, addresses)
+
+ def _add_server_attributes(self, node, server):
+ node.setAttribute('id', str(server['id']))
+ node.setAttribute('uuid', str(server['uuid']))
+ node.setAttribute('hostId', str(server['hostId']))
+ node.setAttribute('name', server['name'])
+ node.setAttribute('created', str(server['created']))
+ node.setAttribute('updated', str(server['updated']))
+ node.setAttribute('status', server['status'])
+ if 'progress' in server:
+ node.setAttribute('progress', str(server['progress']))
+
+ def _server_to_xml(self, xml_doc, server):
+ server_node = xml_doc.createElement('server')
+ server_node.setAttribute('id', str(server['id']))
+ server_node.setAttribute('name', server['name'])
+ link_nodes = self._create_link_nodes(xml_doc,
+ server['links'])
+ for link_node in link_nodes:
+ server_node.appendChild(link_node)
+ return server_node
+
+ def _server_to_xml_detailed(self, xml_doc, server):
+ server_node = xml_doc.createElement('server')
+ self._add_server_attributes(server_node, server)
+
+ link_nodes = self._create_link_nodes(xml_doc,
+ server['links'])
+ for link_node in link_nodes:
+ server_node.appendChild(link_node)
+
+ if 'image' in server:
+ image_node = self._create_basic_entity_node(xml_doc,
+ server['image']['id'],
+ server['image']['links'],
+ 'image')
+ server_node.appendChild(image_node)
+
+ if 'flavor' in server:
+ flavor_node = self._create_basic_entity_node(xml_doc,
+ server['flavor']['id'],
+ server['flavor']['links'],
+ 'flavor')
+ server_node.appendChild(flavor_node)
+
+ metadata = server.get('metadata', {}).items()
+ if len(metadata) > 0:
+ metadata_node = self._create_metadata_node(xml_doc, metadata)
+ server_node.appendChild(metadata_node)
+
+ addresses_node = self._create_addresses_node(xml_doc,
+ server['addresses'])
+ server_node.appendChild(addresses_node)
+
+ return server_node
+
+ def _server_list_to_xml(self, xml_doc, servers, detailed):
+ container_node = xml_doc.createElement('servers')
+ if detailed:
+ server_to_xml = self._server_to_xml_detailed
+ else:
+ server_to_xml = self._server_to_xml
+
+ for server in servers:
+ item_node = server_to_xml(xml_doc, server)
+ container_node.appendChild(item_node)
+ return container_node
+
+ def index(self, servers_dict):
+ xml_doc = minidom.Document()
+ node = self._server_list_to_xml(xml_doc,
+ servers_dict['servers'],
+ detailed=False)
+ return self.to_xml_string(node, True)
+
+ def detail(self, servers_dict):
+ xml_doc = minidom.Document()
+ node = self._server_list_to_xml(xml_doc,
+ servers_dict['servers'],
+ detailed=True)
+ return self.to_xml_string(node, True)
+
+ def show(self, server_dict):
+ xml_doc = minidom.Document()
+ node = self._server_to_xml_detailed(xml_doc,
+ server_dict['server'])
+ return self.to_xml_string(node, True)
+
+ def create(self, server_dict):
+ xml_doc = minidom.Document()
+ node = self._server_to_xml_detailed(xml_doc,
+ server_dict['server'])
+ node.setAttribute('adminPass', server_dict['server']['adminPass'])
+ return self.to_xml_string(node, True)
+
+
def create_resource(version='1.0'):
controller = {
'1.0': ControllerV10,
@@ -641,13 +891,22 @@ def create_resource(version='1.0'):
headers_serializer = HeadersSerializer()
+ xml_serializer = {
+ '1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
+ '1.1': ServerXMLSerializer(),
+ }[version]
+
body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
- xmlns=xmlns),
+ 'application/xml': xml_serializer,
}
+ xml_deserializer = {
+ '1.0': helper.ServerXMLDeserializer(),
+ '1.1': helper.ServerXMLDeserializerV11(),
+ }[version]
+
body_deserializers = {
- 'application/xml': helper.ServerXMLDeserializer(),
+ 'application/xml': xml_deserializer,
}
serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer)
diff --git a/nova/api/openstack/shared_ip_groups.py b/nova/api/openstack/shared_ip_groups.py
index cf2ddbabb..54d0a8334 100644
--- a/nova/api/openstack/shared_ip_groups.py
+++ b/nova/api/openstack/shared_ip_groups.py
@@ -17,7 +17,6 @@
from webob import exc
-from nova.api.openstack import faults
from nova.api.openstack import wsgi
@@ -26,27 +25,27 @@ class Controller(object):
def index(self, req, **kwargs):
""" Returns a list of Shared IP Groups for the user """
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def show(self, req, id, **kwargs):
""" Shows in-depth information on a specific Shared IP Group """
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def update(self, req, id, **kwargs):
""" You can't update a Shared IP Group """
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def delete(self, req, id, **kwargs):
""" Deletes a Shared IP Group """
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def detail(self, req, **kwargs):
""" Returns a complete list of Shared IP Groups """
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def create(self, req, **kwargs):
""" Creates a new Shared IP group """
- raise faults.Fault(exc.HTTPNotImplemented())
+ raise exc.HTTPNotImplemented()
def create_resource():
diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py
index 6ae1eaf2a..8dd72d559 100644
--- a/nova/api/openstack/users.py
+++ b/nova/api/openstack/users.py
@@ -19,7 +19,6 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova.api.openstack import common
-from nova.api.openstack import faults
from nova.api.openstack import wsgi
from nova.auth import manager
@@ -69,7 +68,7 @@ class Controller(object):
user = None
if user is None:
- raise faults.Fault(exc.HTTPNotFound())
+ raise exc.HTTPNotFound()
return dict(user=_translate_keys(user))
diff --git a/nova/api/openstack/versions.py b/nova/api/openstack/versions.py
index a634c3267..e2f892fb6 100644
--- a/nova/api/openstack/versions.py
+++ b/nova/api/openstack/versions.py
@@ -15,13 +15,77 @@
# License for the specific language governing permissions and limitations
# under the License.
+from datetime import datetime
import webob
import webob.dec
+from xml.dom import minidom
import nova.api.openstack.views.versions
from nova.api.openstack import wsgi
+VERSIONS = {
+ "v1.0": {
+ "id": "v1.0",
+ "status": "DEPRECATED",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.0+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.0+json",
+ }
+ ],
+ },
+ "v1.1": {
+ "id": "v1.1",
+ "status": "CURRENT",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.1+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.1+json",
+ }
+ ],
+ },
+}
+
+
class Versions(wsgi.Resource):
def __init__(self):
metadata = {
@@ -31,26 +95,303 @@ class Versions(wsgi.Resource):
}
}
+ headers_serializer = VersionsHeadersSerializer()
+
body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(metadata=metadata),
+ 'application/atom+xml': VersionsAtomSerializer(metadata=metadata),
+ 'application/xml': VersionsXMLSerializer(metadata=metadata),
}
- serializer = wsgi.ResponseSerializer(body_serializers)
+ serializer = wsgi.ResponseSerializer(
+ body_serializers=body_serializers,
+ headers_serializer=headers_serializer)
+
+ supported_content_types = ('application/json',
+ 'application/xml',
+ 'application/atom+xml')
+ deserializer = VersionsRequestDeserializer(
+ supported_content_types=supported_content_types)
- wsgi.Resource.__init__(self, None, serializer=serializer)
+ wsgi.Resource.__init__(self, None, serializer=serializer,
+ deserializer=deserializer)
def dispatch(self, request, *args):
"""Respond to a request for all OpenStack API versions."""
- version_objs = [
- {
- "id": "v1.1",
- "status": "CURRENT",
- },
- {
- "id": "v1.0",
- "status": "DEPRECATED",
- },
- ]
-
builder = nova.api.openstack.views.versions.get_view_builder(request)
- versions = [builder.build(version) for version in version_objs]
- return dict(versions=versions)
+ if request.path == '/':
+ # List Versions
+ return builder.build_versions(VERSIONS)
+ else:
+ # Versions Multiple Choice
+ return builder.build_choices(VERSIONS, request)
+
+
+class VersionV10(object):
+ def show(self, req):
+ builder = nova.api.openstack.views.versions.get_view_builder(req)
+ return builder.build_version(VERSIONS['v1.0'])
+
+
+class VersionV11(object):
+ def show(self, req):
+ builder = nova.api.openstack.views.versions.get_view_builder(req)
+ return builder.build_version(VERSIONS['v1.1'])
+
+
+class VersionsRequestDeserializer(wsgi.RequestDeserializer):
+ def get_expected_content_type(self, request):
+ supported_content_types = list(self.supported_content_types)
+ if request.path != '/':
+ # Remove atom+xml accept type for 300 responses
+ if 'application/atom+xml' in supported_content_types:
+ supported_content_types.remove('application/atom+xml')
+
+ return request.best_match_content_type(supported_content_types)
+
+ def get_action_args(self, request_environment):
+ """Parse dictionary created by routes library."""
+ args = {}
+ if request_environment['PATH_INFO'] == '/':
+ args['action'] = 'index'
+ else:
+ args['action'] = 'multi'
+
+ return args
+
+
+class VersionsXMLSerializer(wsgi.XMLDictSerializer):
+ #TODO(wwolf): this is temporary until we get rid of toprettyxml
+ # in the base class (XMLDictSerializer), which I plan to do in
+ # another branch
+ def to_xml_string(self, node, has_atom=False):
+ self._add_xmlns(node, has_atom)
+ return node.toxml(encoding='UTF-8')
+
+ def _versions_to_xml(self, versions, name="versions", xmlns=None):
+ root = self._xml_doc.createElement(name)
+ root.setAttribute("xmlns", wsgi.XMLNS_V11)
+ root.setAttribute("xmlns:atom", wsgi.XMLNS_ATOM)
+
+ for version in versions:
+ root.appendChild(self._create_version_node(version))
+
+ return root
+
+ def _create_media_types(self, media_types):
+ base = self._xml_doc.createElement('media-types')
+ for type in media_types:
+ node = self._xml_doc.createElement('media-type')
+ node.setAttribute('base', type['base'])
+ node.setAttribute('type', type['type'])
+ base.appendChild(node)
+
+ return base
+
+ def _create_version_node(self, version, create_ns=False):
+ version_node = self._xml_doc.createElement('version')
+ if create_ns:
+ xmlns = wsgi.XMLNS_V11
+ xmlns_atom = wsgi.XMLNS_ATOM
+ version_node.setAttribute('xmlns', xmlns)
+ version_node.setAttribute('xmlns:atom', xmlns_atom)
+
+ version_node.setAttribute('id', version['id'])
+ version_node.setAttribute('status', version['status'])
+ if 'updated' in version:
+ version_node.setAttribute('updated', version['updated'])
+
+ if 'media-types' in version:
+ media_types = self._create_media_types(version['media-types'])
+ version_node.appendChild(media_types)
+
+ link_nodes = self._create_link_nodes(self._xml_doc, version['links'])
+ for link in link_nodes:
+ version_node.appendChild(link)
+
+ return version_node
+
+ def index(self, data):
+ self._xml_doc = minidom.Document()
+ node = self._versions_to_xml(data['versions'])
+
+ return self.to_xml_string(node)
+
+ def show(self, data):
+ self._xml_doc = minidom.Document()
+ node = self._create_version_node(data['version'], True)
+
+ return self.to_xml_string(node)
+
+ def multi(self, data):
+ self._xml_doc = minidom.Document()
+ node = self._versions_to_xml(data['choices'], 'choices',
+ xmlns=wsgi.XMLNS_V11)
+
+ return self.to_xml_string(node)
+
+
+class VersionsAtomSerializer(wsgi.XMLDictSerializer):
+ #TODO(wwolf): this is temporary until we get rid of toprettyxml
+ # in the base class (XMLDictSerializer), which I plan to do in
+ # another branch
+ def to_xml_string(self, node, has_atom=False):
+ self._add_xmlns(node, has_atom)
+ return node.toxml(encoding='UTF-8')
+
+ def __init__(self, metadata=None, xmlns=None):
+ self.metadata = metadata or {}
+ if not xmlns:
+ self.xmlns = wsgi.XMLNS_ATOM
+ else:
+ self.xmlns = xmlns
+
+ def _create_text_elem(self, name, text, type=None):
+ elem = self._xml_doc.createElement(name)
+ if type:
+ elem.setAttribute('type', type)
+ elem_text = self._xml_doc.createTextNode(text)
+ elem.appendChild(elem_text)
+ return elem
+
+ def _get_most_recent_update(self, versions):
+ recent = None
+ for version in versions:
+ updated = datetime.strptime(version['updated'],
+ '%Y-%m-%dT%H:%M:%SZ')
+ if not recent:
+ recent = updated
+ elif updated > recent:
+ recent = updated
+
+ return recent.strftime('%Y-%m-%dT%H:%M:%SZ')
+
+ def _get_base_url(self, link_href):
+ # Make sure no trailing /
+ link_href = link_href.rstrip('/')
+ return link_href.rsplit('/', 1)[0] + '/'
+
+ def _create_detail_meta(self, root, version):
+ title = self._create_text_elem('title', "About This Version",
+ type='text')
+
+ updated = self._create_text_elem('updated', version['updated'])
+
+ uri = version['links'][0]['href']
+ id = self._create_text_elem('id', uri)
+
+ link = self._xml_doc.createElement('link')
+ link.setAttribute('rel', 'self')
+ link.setAttribute('href', uri)
+
+ author = self._xml_doc.createElement('author')
+ author_name = self._create_text_elem('name', 'Rackspace')
+ author_uri = self._create_text_elem('uri', 'http://www.rackspace.com/')
+ author.appendChild(author_name)
+ author.appendChild(author_uri)
+
+ root.appendChild(title)
+ root.appendChild(updated)
+ root.appendChild(id)
+ root.appendChild(author)
+ root.appendChild(link)
+
+ def _create_list_meta(self, root, versions):
+ title = self._create_text_elem('title', "Available API Versions",
+ type='text')
+ # Set this updated to the most recently updated version
+ recent = self._get_most_recent_update(versions)
+ updated = self._create_text_elem('updated', recent)
+
+ base_url = self._get_base_url(versions[0]['links'][0]['href'])
+ id = self._create_text_elem('id', base_url)
+
+ link = self._xml_doc.createElement('link')
+ link.setAttribute('rel', 'self')
+ link.setAttribute('href', base_url)
+
+ author = self._xml_doc.createElement('author')
+ author_name = self._create_text_elem('name', 'Rackspace')
+ author_uri = self._create_text_elem('uri', 'http://www.rackspace.com/')
+ author.appendChild(author_name)
+ author.appendChild(author_uri)
+
+ root.appendChild(title)
+ root.appendChild(updated)
+ root.appendChild(id)
+ root.appendChild(author)
+ root.appendChild(link)
+
+ def _create_version_entries(self, root, versions):
+ for version in versions:
+ entry = self._xml_doc.createElement('entry')
+
+ id = self._create_text_elem('id', version['links'][0]['href'])
+ title = self._create_text_elem('title',
+ 'Version %s' % version['id'],
+ type='text')
+ updated = self._create_text_elem('updated', version['updated'])
+
+ entry.appendChild(id)
+ entry.appendChild(title)
+ entry.appendChild(updated)
+
+ for link in version['links']:
+ link_node = self._xml_doc.createElement('link')
+ link_node.setAttribute('rel', link['rel'])
+ link_node.setAttribute('href', link['href'])
+ if 'type' in link:
+ link_node.setAttribute('type', link['type'])
+
+ entry.appendChild(link_node)
+
+ content = self._create_text_elem('content',
+ 'Version %s %s (%s)' %
+ (version['id'],
+ version['status'],
+ version['updated']),
+ type='text')
+
+ entry.appendChild(content)
+ root.appendChild(entry)
+
+ def index(self, data):
+ self._xml_doc = minidom.Document()
+ node = self._xml_doc.createElementNS(self.xmlns, 'feed')
+ self._create_list_meta(node, data['versions'])
+ self._create_version_entries(node, data['versions'])
+
+ return self.to_xml_string(node)
+
+ def show(self, data):
+ self._xml_doc = minidom.Document()
+ node = self._xml_doc.createElementNS(self.xmlns, 'feed')
+ self._create_detail_meta(node, data['version'])
+ self._create_version_entries(node, [data['version']])
+
+ return self.to_xml_string(node)
+
+
+class VersionsHeadersSerializer(wsgi.ResponseHeadersSerializer):
+ def multi(self, response, data):
+ response.status_int = 300
+
+
+def create_resource(version='1.0'):
+ controller = {
+ '1.0': VersionV10,
+ '1.1': VersionV11,
+ }[version]()
+
+ body_serializers = {
+ 'application/xml': VersionsXMLSerializer(),
+ 'application/atom+xml': VersionsAtomSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
+ supported_content_types = ('application/json',
+ 'application/xml',
+ 'application/atom+xml')
+ deserializer = wsgi.RequestDeserializer(
+ supported_content_types=supported_content_types)
+
+ return wsgi.Resource(controller, serializer=serializer,
+ deserializer=deserializer)
diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py
index a242efa45..ddbf7a144 100644
--- a/nova/api/openstack/views/addresses.py
+++ b/nova/api/openstack/views/addresses.py
@@ -15,9 +15,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from nova import flags
from nova import utils
from nova.api.openstack import common
+FLAGS = flags.FLAGS
+
class ViewBuilder(object):
"""Models a server addresses response as a python dictionary."""
@@ -50,22 +53,37 @@ class ViewBuilderV11(ViewBuilder):
if network_label not in networks:
networks[network_label] = []
- networks[network_label].extend(self._extract_ipv4(interface))
+ ip_addresses = list(self._extract_ipv4_addresses(interface))
+
+ if FLAGS.use_ipv6:
+ ipv6_address = self._extract_ipv6_address(interface)
+ if ipv6_address is not None:
+ ip_addresses.append(ipv6_address)
+
+ networks[network_label].extend(ip_addresses)
return networks
def build_network(self, interfaces, network_label):
for interface in interfaces:
if interface['network']['label'] == network_label:
- ips = self._extract_ipv4(interface)
- return {network_label: list(ips)}
+ ips = list(self._extract_ipv4_addresses(interface))
+ ipv6 = self._extract_ipv6_address(interface)
+ if ipv6 is not None:
+ ips.append(ipv6)
+ return {network_label: ips}
return None
- def _extract_ipv4(self, interface):
+ def _extract_ipv4_addresses(self, interface):
for fixed_ip in interface['fixed_ips']:
yield self._build_ip_entity(fixed_ip['address'], 4)
for floating_ip in fixed_ip.get('floating_ips', []):
yield self._build_ip_entity(floating_ip['address'], 4)
+ def _extract_ipv6_address(self, interface):
+ fixed_ipv6 = interface.get('fixed_ipv6')
+ if fixed_ipv6 is not None:
+ return self._build_ip_entity(fixed_ipv6, 6)
+
def _build_ip_entity(self, address, version):
return {'addr': address, 'version': version}
diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py
index 934b4921a..f603d7cb4 100644
--- a/nova/api/openstack/views/limits.py
+++ b/nova/api/openstack/views/limits.py
@@ -15,9 +15,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import datetime
import time
from nova.api.openstack import common
+from nova import utils
class ViewBuilder(object):
@@ -113,10 +115,12 @@ class ViewBuilderV11(ViewBuilder):
return limits
def _build_rate_limit(self, rate_limit):
+ next_avail = \
+ datetime.datetime.utcfromtimestamp(rate_limit["resetTime"])
return {
"verb": rate_limit["verb"],
"value": rate_limit["value"],
"remaining": int(rate_limit["remaining"]),
"unit": rate_limit["unit"],
- "next-available": rate_limit["resetTime"],
+ "next-available": utils.isotime(at=next_avail),
}
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index ab7e8da61..2873a8e0f 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import datetime
import hashlib
import os
@@ -50,7 +51,7 @@ class ViewBuilder(object):
else:
server = self._build_simple(inst)
- self._build_extra(server, inst)
+ self._build_extra(server['server'], inst)
return server
@@ -82,7 +83,7 @@ class ViewBuilder(object):
ctxt = nova.context.get_admin_context()
compute_api = nova.compute.API()
- if compute_api.has_finished_migration(ctxt, inst['id']):
+ if compute_api.has_finished_migration(ctxt, inst['uuid']):
inst_dict['status'] = 'RESIZE-CONFIRM'
# Return the metadata as a dictionary
@@ -99,7 +100,6 @@ class ViewBuilder(object):
self._build_flavor(inst_dict, inst)
self._build_addresses(inst_dict, inst)
- inst_dict['uuid'] = inst['uuid']
return dict(server=inst_dict)
def _build_addresses(self, response, inst):
@@ -121,6 +121,9 @@ class ViewBuilder(object):
class ViewBuilderV10(ViewBuilder):
"""Model an Openstack API V1.0 server response."""
+ def _build_extra(self, response, inst):
+ response['uuid'] = inst['uuid']
+
def _build_image(self, response, inst):
if 'image_ref' in dict(inst):
image_ref = inst['image_ref']
@@ -145,18 +148,46 @@ class ViewBuilderV11(ViewBuilder):
self.image_builder = image_builder
self.base_url = base_url
+ def _build_detail(self, inst):
+ response = super(ViewBuilderV11, self)._build_detail(inst)
+ response['server']['created'] = utils.isotime(inst['created_at'])
+ response['server']['updated'] = utils.isotime(inst['updated_at'])
+ if 'status' in response['server']:
+ if response['server']['status'] == "ACTIVE":
+ response['server']['progress'] = 100
+ elif response['server']['status'] == "BUILD":
+ response['server']['progress'] = 0
+ return response
+
def _build_image(self, response, inst):
if 'image_ref' in dict(inst):
image_href = inst['image_ref']
- if str(image_href).isdigit():
- image_href = int(image_href)
- response['imageRef'] = image_href
+ image_id = str(common.get_id_from_href(image_href))
+ _bookmark = self.image_builder.generate_bookmark(image_id)
+ response['image'] = {
+ "id": image_id,
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": _bookmark,
+ },
+ ]
+ }
def _build_flavor(self, response, inst):
if "instance_type" in dict(inst):
flavor_id = inst["instance_type"]['flavorid']
flavor_ref = self.flavor_builder.generate_href(flavor_id)
- response["flavorRef"] = flavor_ref
+ flavor_bookmark = self.flavor_builder.generate_bookmark(flavor_id)
+ response["flavor"] = {
+ "id": str(common.get_id_from_href(flavor_ref)),
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ]
+ }
def _build_addresses(self, response, inst):
interfaces = inst.get('virtual_interfaces', [])
@@ -164,6 +195,7 @@ class ViewBuilderV11(ViewBuilder):
def _build_extra(self, response, inst):
self._build_links(response, inst)
+ response['uuid'] = inst['uuid']
def _build_links(self, response, inst):
href = self.generate_href(inst["id"])
@@ -180,7 +212,7 @@ class ViewBuilderV11(ViewBuilder):
},
]
- response["server"]["links"] = links
+ response["links"] = links
def generate_href(self, server_id):
"""Create an url that refers to a specific server id."""
diff --git a/nova/api/openstack/views/versions.py b/nova/api/openstack/views/versions.py
index d0145c94a..03da80818 100644
--- a/nova/api/openstack/views/versions.py
+++ b/nova/api/openstack/views/versions.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import copy
import os
@@ -31,15 +32,44 @@ class ViewBuilder(object):
"""
self.base_url = base_url
- def build(self, version_data):
- """Generic method used to generate a version entity."""
- version = {
- "id": version_data["id"],
- "status": version_data["status"],
- "links": self._build_links(version_data),
- }
+ def build_choices(self, VERSIONS, req):
+ version_objs = []
+ for version in VERSIONS:
+ version = VERSIONS[version]
+ version_objs.append({
+ "id": version['id'],
+ "status": version['status'],
+ "links": [
+ {
+ "rel": "self",
+ "href": self.generate_href(version['id'], req.path),
+ },
+ ],
+ "media-types": version['media-types'],
+ })
- return version
+ return dict(choices=version_objs)
+
+ def build_versions(self, versions):
+ version_objs = []
+ for version in versions:
+ version = versions[version]
+ version_objs.append({
+ "id": version['id'],
+ "status": version['status'],
+ "updated": version['updated'],
+ "links": self._build_links(version),
+ })
+
+ return dict(versions=version_objs)
+
+ def build_version(self, version):
+ reval = copy.deepcopy(version)
+ reval['links'].insert(0, {
+ "rel": "self",
+ "href": self.base_url.rstrip('/') + '/',
+ })
+ return dict(version=reval)
def _build_links(self, version_data):
"""Generate a container of links that refer to the provided version."""
@@ -54,6 +84,11 @@ class ViewBuilder(object):
return links
- def generate_href(self, version_number):
+ def generate_href(self, version_number, path=None):
"""Create an url that refers to a specific version_number."""
- return os.path.join(self.base_url, version_number)
+ version_number = version_number.strip('/')
+ if path:
+ path = path.strip('/')
+ return os.path.join(self.base_url, version_number, path)
+ else:
+ return os.path.join(self.base_url, version_number) + '/'
diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py
index c3f841aa5..0eb47044e 100644
--- a/nova/api/openstack/wsgi.py
+++ b/nova/api/openstack/wsgi.py
@@ -14,27 +14,30 @@ 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')
class Request(webob.Request):
"""Add some Openstack API-specific logic to the base webob.Request."""
- def best_match_content_type(self):
+ def best_match_content_type(self, supported_content_types=None):
"""Determine the requested response content-type.
Based on the query extension then the Accept header.
"""
- supported = ('application/json', 'application/xml')
+ supported_content_types = supported_content_types or \
+ ('application/json', 'application/xml')
parts = self.path.rsplit('.', 1)
if len(parts) > 1:
ctype = 'application/{0}'.format(parts[1])
- if ctype in supported:
+ if ctype in supported_content_types:
return ctype
- bm = self.accept.best_match(supported)
+ bm = self.accept.best_match(supported_content_types)
# default to application/json if we don't find a preference
return bm or 'application/json'
@@ -134,10 +137,43 @@ 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"""
+ metadata = {}
+ if metadata_node is not None:
+ 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"""
@@ -151,7 +187,12 @@ class RequestHeadersDeserializer(ActionDispatcher):
class RequestDeserializer(object):
"""Break up a Request object into more useful pieces."""
- def __init__(self, body_deserializers=None, headers_deserializer=None):
+ def __init__(self, body_deserializers=None, headers_deserializer=None,
+ supported_content_types=None):
+
+ self.supported_content_types = supported_content_types or \
+ ('application/json', 'application/xml')
+
self.body_deserializers = {
'application/xml': XMLDeserializer(),
'application/json': JSONDeserializer(),
@@ -213,7 +254,7 @@ class RequestDeserializer(object):
raise exception.InvalidContentType(content_type=content_type)
def get_expected_content_type(self, request):
- return request.best_match_content_type()
+ return request.best_match_content_type(self.supported_content_types)
def get_action_args(self, request_environment):
"""Parse dictionary created by routes library."""
@@ -346,6 +387,8 @@ class XMLDictSerializer(DictSerializer):
link_node = xml_doc.createElement('atom:link')
link_node.setAttribute('rel', link['rel'])
link_node.setAttribute('href', link['href'])
+ if 'type' in link:
+ link_node.setAttribute('type', link['type'])
link_nodes.append(link_node)
return link_nodes
@@ -390,8 +433,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:
@@ -412,6 +456,7 @@ class Resource(wsgi.Application):
serialized by requested content type.
"""
+
def __init__(self, controller, deserializer=None, serializer=None):
"""
:param controller: object that implement methods created by routes lib
@@ -436,14 +481,17 @@ 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))
- action_result = self.dispatch(request, action, args)
+ try:
+ action_result = self.dispatch(request, action, args)
+ except webob.exc.HTTPException as ex:
+ 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,
diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py
index 2e02ec380..f7fd87bcd 100644
--- a/nova/api/openstack/zones.py
+++ b/nova/api/openstack/zones.py
@@ -27,7 +27,6 @@ from nova.scheduler import api
from nova.api.openstack import create_instance_helper as helper
from nova.api.openstack import common
-from nova.api.openstack import faults
from nova.api.openstack import wsgi
@@ -127,11 +126,8 @@ class Controller(object):
Returns a reservation ID (a UUID).
"""
result = None
- try:
- extra_values, result = self.helper.create_instance(req, body,
- self.compute_api.create_all_at_once)
- except faults.Fault, f:
- return f
+ extra_values, result = self.helper.create_instance(req, body,
+ self.compute_api.create_all_at_once)
reservation_id = result
return {'reservation_id': reservation_id}
diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py
index a429b7812..c6d81ee04 100644
--- a/nova/auth/dbdriver.py
+++ b/nova/auth/dbdriver.py
@@ -127,7 +127,7 @@ class DbDriver(object):
try:
project = db.project_create(context.get_admin_context(), values)
- except exception.Duplicate:
+ except exception.DBError:
raise exception.ProjectExists(project=name)
for member in members:
diff --git a/nova/auth/manager.py b/nova/auth/manager.py
index b6131fb7f..6205cfb56 100644
--- a/nova/auth/manager.py
+++ b/nova/auth/manager.py
@@ -518,6 +518,14 @@ class AuthManager(object):
return drv.get_user_roles(User.safe_id(user),
Project.safe_id(project))
+ def get_active_roles(self, user, project=None):
+ """Get all active roles for context"""
+ if project:
+ roles = FLAGS.allowed_roles + ['projectmanager']
+ else:
+ roles = FLAGS.global_roles
+ return [role for role in roles if self.has_role(user, role, project)]
+
def get_project(self, pid):
"""Get project object by id"""
with self.driver() as drv:
@@ -730,10 +738,6 @@ class AuthManager(object):
with self.driver() as drv:
drv.modify_user(uid, access_key, secret_key, admin)
- @staticmethod
- def get_key_pairs(context):
- return db.key_pair_get_all_by_user(context.elevated(), context.user_id)
-
def get_credentials(self, user, project=None, use_dmz=True):
"""Get credential zip for user in project"""
if not isinstance(user, User):
@@ -785,7 +789,7 @@ class AuthManager(object):
return read_buffer
def get_environment_rc(self, user, project=None, use_dmz=True):
- """Get credential zip for user in project"""
+ """Get environment rc for user in project"""
if not isinstance(user, User):
user = self.get_user(user)
if project is None:
diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py
index 7844d31e1..2c4673f9e 100644
--- a/nova/cloudpipe/pipelib.py
+++ b/nova/cloudpipe/pipelib.py
@@ -96,8 +96,8 @@ class CloudPipe(object):
def launch_vpn_instance(self, project_id):
LOG.debug(_("Launching VPN for %s") % (project_id))
project = self.manager.get_project(project_id)
- ctxt = context.RequestContext(user=project.project_manager,
- project=project)
+ ctxt = context.RequestContext(user=project.project_manager_id,
+ project=project.id)
key_name = self.setup_key_pair(ctxt)
group_name = self.setup_security_group(ctxt)
@@ -112,11 +112,11 @@ class CloudPipe(object):
security_group=[group_name])
def setup_security_group(self, context):
- group_name = '%s%s' % (context.project.id, FLAGS.vpn_key_suffix)
- if db.security_group_exists(context, context.project.id, group_name):
+ group_name = '%s%s' % (context.project_id, FLAGS.vpn_key_suffix)
+ if db.security_group_exists(context, context.project_id, group_name):
return group_name
- group = {'user_id': context.user.id,
- 'project_id': context.project.id,
+ group = {'user_id': context.user_id,
+ 'project_id': context.project_id,
'name': group_name,
'description': 'Group for vpn'}
group_ref = db.security_group_create(context, group)
@@ -137,19 +137,16 @@ class CloudPipe(object):
return group_name
def setup_key_pair(self, context):
- key_name = '%s%s' % (context.project.id, FLAGS.vpn_key_suffix)
+ key_name = '%s%s' % (context.project_id, FLAGS.vpn_key_suffix)
try:
- result = cloud._gen_key(context, context.user.id, key_name)
+ result = cloud._gen_key(context, context.user_id, key_name)
private_key = result['private_key']
- try:
- key_dir = os.path.join(FLAGS.keys_path, context.user.id)
- if not os.path.exists(key_dir):
- os.makedirs(key_dir)
- key_path = os.path.join(key_dir, '%s.pem' % key_name)
- with open(key_path, 'w') as f:
- f.write(private_key)
- except:
- pass
- except exception.Duplicate:
+ key_dir = os.path.join(FLAGS.keys_path, context.user_id)
+ if not os.path.exists(key_dir):
+ os.makedirs(key_dir)
+ key_path = os.path.join(key_dir, '%s.pem' % key_name)
+ with open(key_path, 'w') as f:
+ f.write(private_key)
+ except (exception.Duplicate, os.error, IOError):
pass
return key_name
diff --git a/nova/compute/api.py b/nova/compute/api.py
index acafc7760..80d54d029 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -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 "
@@ -467,10 +467,10 @@ class API(base.Base):
return [dict(x.iteritems()) for x in instances]
- def has_finished_migration(self, context, instance_id):
+ def has_finished_migration(self, context, instance_uuid):
"""Returns true if an instance has a finished migration."""
try:
- db.migration_get_by_instance_and_status(context, instance_id,
+ db.migration_get_by_instance_and_status(context, instance_uuid,
'finished')
return True
except exception.NotFound:
@@ -561,6 +561,7 @@ class API(base.Base):
self.db.queue_get_for(context, FLAGS.compute_topic, host),
{'method': 'refresh_provider_fw_rules', 'args': {}})
+ @scheduler_api.reroute_compute("update")
def update(self, context, instance_id, **kwargs):
"""Updates the instance in the datastore.
@@ -688,7 +689,7 @@ class API(base.Base):
raise
instances = None
elif project_id or not context.is_admin:
- if not context.project:
+ if not context.project_id:
instances = self.db.instance_get_all_by_user(
context, context.user_id)
else:
@@ -776,6 +777,7 @@ class API(base.Base):
raise exception.Error(_("Unable to find host for Instance %s")
% instance_id)
+ @scheduler_api.reroute_compute("backup")
def backup(self, context, instance_id, name, backup_type, rotation,
extra_properties=None):
"""Backup the given instance
@@ -792,6 +794,7 @@ class API(base.Base):
extra_properties=extra_properties)
return recv_meta
+ @scheduler_api.reroute_compute("snapshot")
def snapshot(self, context, instance_id, name, extra_properties=None):
"""Snapshot the given instance.
@@ -834,10 +837,12 @@ class API(base.Base):
params=params)
return recv_meta
+ @scheduler_api.reroute_compute("reboot")
def reboot(self, context, instance_id):
"""Reboot the given instance."""
self._cast_compute_message('reboot_instance', context, instance_id)
+ @scheduler_api.reroute_compute("rebuild")
def rebuild(self, context, instance_id, image_href, name=None,
metadata=None, files_to_inject=None):
"""Rebuild the given instance with the provided metadata."""
@@ -868,39 +873,50 @@ class API(base.Base):
instance_id,
params=rebuild_params)
+ @scheduler_api.reroute_compute("revert_resize")
def revert_resize(self, context, instance_id):
"""Reverts a resize, deleting the 'new' instance in the process."""
context = context.elevated()
+ instance_ref = self._get_instance(context, instance_id,
+ 'revert_resize')
migration_ref = self.db.migration_get_by_instance_and_status(context,
- instance_id, 'finished')
+ instance_ref['uuid'], 'finished')
if not migration_ref:
raise exception.MigrationNotFoundByStatus(instance_id=instance_id,
status='finished')
params = {'migration_id': migration_ref['id']}
- self._cast_compute_message('revert_resize', context, instance_id,
- migration_ref['dest_compute'], params=params)
+ self._cast_compute_message('revert_resize', context,
+ instance_ref['uuid'],
+ migration_ref['dest_compute'],
+ params=params)
+
self.db.migration_update(context, migration_ref['id'],
{'status': 'reverted'})
+ @scheduler_api.reroute_compute("confirm_resize")
def confirm_resize(self, context, instance_id):
"""Confirms a migration/resize and deletes the 'old' instance."""
context = context.elevated()
+ instance_ref = self._get_instance(context, instance_id,
+ 'confirm_resize')
migration_ref = self.db.migration_get_by_instance_and_status(context,
- instance_id, 'finished')
+ instance_ref['uuid'], 'finished')
if not migration_ref:
raise exception.MigrationNotFoundByStatus(instance_id=instance_id,
status='finished')
- instance_ref = self.db.instance_get(context, instance_id)
params = {'migration_id': migration_ref['id']}
- self._cast_compute_message('confirm_resize', context, instance_id,
- migration_ref['source_compute'], params=params)
+ self._cast_compute_message('confirm_resize', context,
+ instance_ref['uuid'],
+ migration_ref['source_compute'],
+ params=params)
self.db.migration_update(context, migration_ref['id'],
{'status': 'confirmed'})
self.db.instance_update(context, instance_id,
{'host': migration_ref['dest_compute'], })
+ @scheduler_api.reroute_compute("resize")
def resize(self, context, instance_id, flavor_id=None):
"""Resize (ie, migrate) a running instance.
@@ -908,8 +924,8 @@ class API(base.Base):
the original flavor_id. If flavor_id is not None, the instance should
be migrated to a new host and resized to the new flavor_id.
"""
- instance = self.db.instance_get(context, instance_id)
- current_instance_type = instance['instance_type']
+ instance_ref = self._get_instance(context, instance_id, 'resize')
+ current_instance_type = instance_ref['instance_type']
# If flavor_id is not provided, only migrate the instance.
if not flavor_id:
@@ -924,24 +940,22 @@ class API(base.Base):
LOG.debug(_("Old instance type %(current_instance_type_name)s, "
" new instance type %(new_instance_type_name)s") % locals())
if not new_instance_type:
- raise exception.ApiError(_("Requested flavor %(flavor_id)d "
- "does not exist") % locals())
+ raise exception.FlavorNotFound(flavor_id=flavor_id)
current_memory_mb = current_instance_type['memory_mb']
new_memory_mb = new_instance_type['memory_mb']
if current_memory_mb > new_memory_mb:
- raise exception.ApiError(_("Invalid flavor: cannot downsize"
- "instances"))
+ raise exception.CannotResizeToSmallerSize()
if (current_memory_mb == new_memory_mb) and flavor_id:
- raise exception.ApiError(_("Invalid flavor: cannot use"
- "the same flavor. "))
+ raise exception.CannotResizeToSameSize()
+ instance_ref = self._get_instance(context, instance_id, 'resize')
self._cast_scheduler_message(context,
{"method": "prep_resize",
"args": {"topic": FLAGS.compute_topic,
- "instance_id": instance_id,
- "flavor_id": new_instance_type['id']}})
+ "instance_id": instance_ref['uuid'],
+ "instance_type_id": new_instance_type['id']}})
@scheduler_api.reroute_compute("add_fixed_ip")
def add_fixed_ip(self, context, instance_id, network_id):
@@ -1012,6 +1026,7 @@ class API(base.Base):
"""Unrescue the given instance."""
self._cast_compute_message('unrescue_instance', context, instance_id)
+ @scheduler_api.reroute_compute("set_admin_password")
def set_admin_password(self, context, instance_id, password=None):
"""Set the root/admin password for the given instance."""
host = self._find_host(context, instance_id)
diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py
index 1d246e445..824416514 100644
--- a/nova/compute/instance_types.py
+++ b/nova/compute/instance_types.py
@@ -112,7 +112,7 @@ def get_instance_type(id):
return get_default_instance_type()
try:
ctxt = context.get_admin_context()
- return db.instance_type_get_by_id(ctxt, id)
+ return db.instance_type_get(ctxt, id)
except exception.DBError:
raise exception.ApiError(_("Unknown instance type: %s") % id)
@@ -132,11 +132,8 @@ def get_instance_type_by_name(name):
# flavors.
def get_instance_type_by_flavor_id(flavor_id):
"""Retrieve instance type by flavor_id."""
- if flavor_id is None:
- return get_default_instance_type()
+ ctxt = context.get_admin_context()
try:
- ctxt = context.get_admin_context()
return db.instance_type_get_by_flavor_id(ctxt, flavor_id)
- except exception.DBError, e:
- LOG.exception(_('DB error: %s') % e)
- raise exception.ApiError(_("Unknown flavor: %s") % flavor_id)
+ except ValueError:
+ raise exception.FlavorNotFound(flavor_id=flavor_id)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 47becdcc6..69acf6e95 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -44,6 +44,7 @@ import functools
from eventlet import greenthread
+import nova.context
from nova import exception
from nova import flags
import nova.image
@@ -77,8 +78,6 @@ flags.DEFINE_integer('live_migration_retry_count', 30,
flags.DEFINE_integer("rescue_timeout", 0,
"Automatically unrescue an instance after N seconds."
" Set to 0 to disable.")
-flags.DEFINE_bool('auto_assign_floating_ip', False,
- 'Autoassigning floating ip to VM')
flags.DEFINE_integer('host_state_interval', 120,
'Interval in seconds for querying the host status')
@@ -93,6 +92,10 @@ def checks_instance_lock(function):
"""Decorator to prevent action against locked instances for non-admins."""
@functools.wraps(function)
def decorated_function(self, context, instance_id, *args, **kwargs):
+ #TODO(anyone): this being called instance_id is forcing a slightly
+ # confusing convention of pushing instance_uuids
+ # through an "instance_id" key in the queue args dict when
+ # casting through the compute API
LOG.info(_("check_instance_lock: decorating: |%s|"), function,
context=context)
LOG.info(_("check_instance_lock: arguments: |%(self)s| |%(context)s|"
@@ -145,6 +148,31 @@ class ComputeManager(manager.SchedulerDependentManager):
def init_host(self):
"""Initialization for a standalone compute service."""
self.driver.init_host(host=self.host)
+ context = nova.context.get_admin_context()
+ instances = self.db.instance_get_all_by_host(context, self.host)
+ for instance in instances:
+ inst_name = instance['name']
+ db_state = instance['state']
+ drv_state = self._update_state(context, instance['id'])
+
+ expect_running = db_state == power_state.RUNNING \
+ and drv_state != db_state
+
+ LOG.debug(_('Current state of %(inst_name)s is %(drv_state)s, '
+ 'state in DB is %(db_state)s.'), locals())
+
+ if (expect_running and FLAGS.resume_guests_state_on_host_boot)\
+ or FLAGS.start_guests_on_host_boot:
+ LOG.info(_('Rebooting instance %(inst_name)s after '
+ 'nova-compute restart.'), locals())
+ self.reboot_instance(context, instance['id'])
+ elif drv_state == power_state.RUNNING:
+ # Hyper-V and VMWareAPI drivers will raise and exception
+ try:
+ self.driver.ensure_filtering_rules_for_instance(instance)
+ except NotImplementedError:
+ LOG.warning(_('Hypervisor driver does not '
+ 'support firewall rules'))
def _update_state(self, context, instance_id, state=None):
"""Update the state of an instance from the driver info."""
@@ -152,6 +180,7 @@ class ComputeManager(manager.SchedulerDependentManager):
if state is None:
try:
+ LOG.debug(_('Checking state of %s'), instance_ref['name'])
info = self.driver.get_info(instance_ref['name'])
except exception.NotFound:
info = None
@@ -162,6 +191,7 @@ class ComputeManager(manager.SchedulerDependentManager):
state = power_state.FAILED
self.db.instance_set_state(context, instance_id, state)
+ return state
def _update_launched_at(self, context, instance_id, launched_at=None):
"""Update the launched_at parameter of the given instance."""
@@ -212,6 +242,15 @@ class ComputeManager(manager.SchedulerDependentManager):
"""This call passes straight through to the virtualization driver."""
return self.driver.refresh_provider_fw_rules()
+ def _get_instance_nw_info(self, context, instance):
+ """Get a list of dictionaries of network data of an instance.
+ Returns an empty list if stub_network flag is set."""
+ network_info = []
+ if not FLAGS.stub_network:
+ network_info = self.network_api.get_instance_nw_info(context,
+ instance)
+ return network_info
+
def _setup_block_device_mapping(self, context, instance_id):
"""setup volumes for block device mapping"""
self.db.instance_set_state(context,
@@ -274,16 +313,19 @@ class ComputeManager(manager.SchedulerDependentManager):
"""Launch a new instance with specified options."""
context = context.elevated()
instance = self.db.instance_get(context, instance_id)
- instance.injected_files = kwargs.get('injected_files', [])
- instance.admin_pass = kwargs.get('admin_password', None)
if instance['name'] in self.driver.list_instances():
raise exception.Error(_("Instance has already been created"))
LOG.audit(_("instance %s: starting..."), instance_id,
context=context)
- self.db.instance_update(context,
- instance_id,
- {'host': self.host, 'launched_on': self.host})
-
+ updates = {}
+ updates['host'] = self.host
+ updates['launched_on'] = self.host
+ # NOTE(vish): used by virt but not in database
+ updates['injected_files'] = kwargs.get('injected_files', [])
+ updates['admin_pass'] = kwargs.get('admin_password', None)
+ instance = self.db.instance_update(context,
+ instance_id,
+ updates)
self.db.instance_set_state(context,
instance_id,
power_state.NOSTATE,
@@ -299,8 +341,6 @@ class ComputeManager(manager.SchedulerDependentManager):
network_info = self.network_api.allocate_for_instance(context,
instance, vpn=is_vpn)
LOG.debug(_("instance network_info: |%s|"), network_info)
- self.network_manager.setup_compute_network(context,
- instance_id)
else:
# TODO(tr3buchet) not really sure how this should be handled.
# virt requires network_info to be passed in but stub_network
@@ -314,7 +354,7 @@ class ComputeManager(manager.SchedulerDependentManager):
self._update_state(context, instance_id, power_state.BUILDING)
try:
- self.driver.spawn(instance, network_info, bd_mapping)
+ self.driver.spawn(context, instance, network_info, bd_mapping)
except Exception as ex: # pylint: disable=W0702
msg = _("Instance '%(instance_id)s' failed to spawn. Is "
"virtualization enabled in the BIOS? Details: "
@@ -354,6 +394,7 @@ class ComputeManager(manager.SchedulerDependentManager):
{'action_str': action_str, 'instance_id': instance_id},
context=context)
+ network_info = self._get_instance_nw_info(context, instance)
if not FLAGS.stub_network:
self.network_api.deallocate_for_instance(context, instance)
@@ -366,7 +407,7 @@ class ComputeManager(manager.SchedulerDependentManager):
self.db.instance_destroy(context, instance_id)
raise exception.Error(_('trying to destroy already destroyed'
' instance: %s') % instance_id)
- self.driver.destroy(instance)
+ self.driver.destroy(instance, network_info)
if action_str == 'Terminating':
terminate_volumes(self.db, context, instance_id)
@@ -411,11 +452,16 @@ class ComputeManager(manager.SchedulerDependentManager):
self._update_state(context, instance_id, power_state.BUILDING)
- self.driver.destroy(instance_ref)
+ network_info = self._get_instance_nw_info(context, instance_ref)
+
+ self.driver.destroy(instance_ref, network_info)
image_ref = kwargs.get('image_ref')
instance_ref.image_ref = image_ref
instance_ref.injected_files = kwargs.get('injected_files', [])
- self.driver.spawn(instance_ref)
+ network_info = self.network_api.get_instance_nw_info(context,
+ instance_ref)
+ bd_mapping = self._setup_block_device_mapping(context, instance_id)
+ self.driver.spawn(context, instance_ref, network_info, bd_mapping)
self._update_image_ref(context, instance_id, image_ref)
self._update_launched_at(context, instance_id)
@@ -448,8 +494,8 @@ class ComputeManager(manager.SchedulerDependentManager):
instance_id,
power_state.NOSTATE,
'rebooting')
- self.network_manager.setup_compute_network(context, instance_id)
- self.driver.reboot(instance_ref)
+ network_info = self._get_instance_nw_info(context, instance_ref)
+ self.driver.reboot(instance_ref, network_info)
self._update_state(context, instance_id)
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@@ -483,7 +529,7 @@ class ComputeManager(manager.SchedulerDependentManager):
'instance: %(instance_id)s (state: %(state)s '
'expected: %(running)s)') % locals())
- self.driver.snapshot(instance_ref, image_id)
+ self.driver.snapshot(context, instance_ref, image_id)
if image_type == 'snapshot':
if rotation:
@@ -639,10 +685,10 @@ class ComputeManager(manager.SchedulerDependentManager):
instance_id,
power_state.NOSTATE,
'rescuing')
- self.network_manager.setup_compute_network(context, instance_id)
_update_state = lambda result: self._update_state_callback(
self, context, instance_id, result)
- self.driver.rescue(instance_ref, _update_state)
+ network_info = self._get_instance_nw_info(context, instance_ref)
+ self.driver.rescue(context, instance_ref, _update_state, network_info)
self._update_state(context, instance_id)
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@@ -658,7 +704,8 @@ class ComputeManager(manager.SchedulerDependentManager):
'unrescuing')
_update_state = lambda result: self._update_state_callback(
self, context, instance_id, result)
- self.driver.unrescue(instance_ref, _update_state)
+ network_info = self._get_instance_nw_info(context, instance_ref)
+ self.driver.unrescue(instance_ref, _update_state, network_info)
self._update_state(context, instance_id)
@staticmethod
@@ -670,9 +717,12 @@ class ComputeManager(manager.SchedulerDependentManager):
@checks_instance_lock
def confirm_resize(self, context, instance_id, migration_id):
"""Destroys the source instance."""
- context = context.elevated()
- instance_ref = self.db.instance_get(context, instance_id)
- self.driver.destroy(instance_ref)
+ migration_ref = self.db.migration_get(context, migration_id)
+ instance_ref = self.db.instance_get_by_uuid(context,
+ migration_ref.instance_uuid)
+
+ network_info = self._get_instance_nw_info(context, instance_ref)
+ self.driver.destroy(instance_ref, network_info)
usage_info = utils.usage_from_instance(instance_ref)
notifier.notify('compute.%s' % self.host,
'compute.instance.resize.confirm',
@@ -688,17 +738,18 @@ class ComputeManager(manager.SchedulerDependentManager):
source machine.
"""
- instance_ref = self.db.instance_get(context, instance_id)
migration_ref = self.db.migration_get(context, migration_id)
+ instance_ref = self.db.instance_get_by_uuid(context,
+ migration_ref.instance_uuid)
- self.driver.destroy(instance_ref)
+ network_info = self._get_instance_nw_info(context, instance_ref)
+ self.driver.destroy(instance_ref, network_info)
topic = self.db.queue_get_for(context, FLAGS.compute_topic,
instance_ref['host'])
rpc.cast(context, topic,
{'method': 'finish_revert_resize',
- 'args': {
- 'migration_id': migration_ref['id'],
- 'instance_id': instance_id, },
+ 'args': {'instance_id': instance_ref['uuid'],
+ 'migration_id': migration_ref['id']},
})
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@@ -710,19 +761,22 @@ class ComputeManager(manager.SchedulerDependentManager):
in the database.
"""
- instance_ref = self.db.instance_get(context, instance_id)
migration_ref = self.db.migration_get(context, migration_id)
- instance_type = self.db.instance_type_get_by_flavor_id(context,
- migration_ref['old_flavor_id'])
+ instance_ref = self.db.instance_get_by_uuid(context,
+ migration_ref.instance_uuid)
+
+ instance_type = self.db.instance_type_get(context,
+ migration_ref['old_instance_type_id'])
# Just roll back the record. There's no need to resize down since
# the 'old' VM already has the preferred attributes
- self.db.instance_update(context, instance_id,
+ self.db.instance_update(context, instance_ref['uuid'],
dict(memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
- local_gb=instance_type['local_gb']))
+ local_gb=instance_type['local_gb'],
+ instance_type_id=instance_type['id']))
- self.driver.revert_resize(instance_ref)
+ self.driver.revert_migration(instance_ref)
self.db.migration_update(context, migration_id,
{'status': 'reverted'})
usage_info = utils.usage_from_instance(instance_ref)
@@ -733,42 +787,49 @@ class ComputeManager(manager.SchedulerDependentManager):
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@checks_instance_lock
- def prep_resize(self, context, instance_id, flavor_id):
+ def prep_resize(self, context, instance_id, instance_type_id):
"""Initiates the process of moving a running instance to another host.
Possibly changes the RAM and disk size in the process.
"""
context = context.elevated()
- instance_ref = self.db.instance_get(context, instance_id)
+
+ # Because of checks_instance_lock, this must currently be called
+ # instance_id. However, the compute API is always passing the UUID
+ # of the instance down
+ instance_ref = self.db.instance_get_by_uuid(context, instance_id)
+
if instance_ref['host'] == FLAGS.host:
raise exception.Error(_(
'Migration error: destination same as source!'))
- instance_type = self.db.instance_type_get_by_flavor_id(context,
- flavor_id)
+ old_instance_type = self.db.instance_type_get(context,
+ instance_ref['instance_type_id'])
+ new_instance_type = self.db.instance_type_get(context,
+ instance_type_id)
+
migration_ref = self.db.migration_create(context,
- {'instance_id': instance_id,
+ {'instance_uuid': instance_ref['uuid'],
'source_compute': instance_ref['host'],
'dest_compute': FLAGS.host,
'dest_host': self.driver.get_host_ip_addr(),
- 'old_flavor_id': instance_type['flavorid'],
- 'new_flavor_id': flavor_id,
+ 'old_instance_type_id': old_instance_type['id'],
+ 'new_instance_type_id': instance_type_id,
'status': 'pre-migrating'})
- LOG.audit(_('instance %s: migrating to '), instance_id,
+ LOG.audit(_('instance %s: migrating'), instance_ref['uuid'],
context=context)
topic = self.db.queue_get_for(context, FLAGS.compute_topic,
instance_ref['host'])
rpc.cast(context, topic,
{'method': 'resize_instance',
- 'args': {
- 'migration_id': migration_ref['id'],
- 'instance_id': instance_id, },
- })
+ 'args': {'instance_id': instance_ref['uuid'],
+ 'migration_id': migration_ref['id']}})
+
usage_info = utils.usage_from_instance(instance_ref,
- new_instance_type=instance_type['name'],
- new_instance_type_id=instance_type['id'])
+ new_instance_type=new_instance_type['name'],
+ new_instance_type_id=new_instance_type['id'])
notifier.notify('compute.%s' % self.host,
'compute.instance.resize.prep',
notifier.INFO,
@@ -779,7 +840,9 @@ class ComputeManager(manager.SchedulerDependentManager):
def resize_instance(self, context, instance_id, migration_id):
"""Starts the migration of a running instance to another host."""
migration_ref = self.db.migration_get(context, migration_id)
- instance_ref = self.db.instance_get(context, instance_id)
+ instance_ref = self.db.instance_get_by_uuid(context,
+ migration_ref.instance_uuid)
+
self.db.migration_update(context,
migration_id,
{'status': 'migrating'})
@@ -795,10 +858,11 @@ class ComputeManager(manager.SchedulerDependentManager):
topic = self.db.queue_get_for(context,
FLAGS.compute_topic,
migration_ref['dest_compute'])
+ params = {'migration_id': migration_id,
+ 'disk_info': disk_info,
+ 'instance_id': instance_ref['uuid']}
rpc.cast(context, topic, {'method': 'finish_resize',
- 'args': {'migration_id': migration_id,
- 'instance_id': instance_id,
- 'disk_info': disk_info}})
+ 'args': params})
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@checks_instance_lock
@@ -810,24 +874,27 @@ class ComputeManager(manager.SchedulerDependentManager):
"""
migration_ref = self.db.migration_get(context, migration_id)
- instance_ref = self.db.instance_get(context,
- migration_ref['instance_id'])
- # TODO(mdietz): apply the rest of the instance_type attributes going
- # after they're supported
- instance_type = self.db.instance_type_get_by_flavor_id(context,
- migration_ref['new_flavor_id'])
- self.db.instance_update(context, instance_id,
- dict(instance_type_id=instance_type['id'],
- memory_mb=instance_type['memory_mb'],
- vcpus=instance_type['vcpus'],
- local_gb=instance_type['local_gb']))
-
- # reload the updated instance ref
- # FIXME(mdietz): is there reload functionality?
- instance = self.db.instance_get(context, instance_id)
- network_info = self.network_api.get_instance_nw_info(context,
- instance)
- self.driver.finish_resize(instance, disk_info, network_info)
+
+ resize_instance = False
+ instance_ref = self.db.instance_get_by_uuid(context,
+ migration_ref.instance_uuid)
+ if migration_ref['old_instance_type_id'] != \
+ migration_ref['new_instance_type_id']:
+ instance_type = self.db.instance_type_get(context,
+ migration_ref['new_instance_type_id'])
+ self.db.instance_update(context, instance_ref.uuid,
+ dict(instance_type_id=instance_type['id'],
+ memory_mb=instance_type['memory_mb'],
+ vcpus=instance_type['vcpus'],
+ local_gb=instance_type['local_gb']))
+ resize_instance = True
+
+ instance_ref = self.db.instance_get_by_uuid(context,
+ instance_ref.uuid)
+
+ network_info = self._get_instance_nw_info(context, instance_ref)
+ self.driver.finish_migration(context, instance_ref, disk_info,
+ network_info, resize_instance)
self.db.migration_update(context, migration_id,
{'status': 'finished', })
@@ -840,7 +907,7 @@ class ComputeManager(manager.SchedulerDependentManager):
"""
self.network_api.add_fixed_ip_to_instance(context, instance_id,
- network_id)
+ self.host, network_id)
self.inject_network_info(context, instance_id)
self.reset_network(context, instance_id)
@@ -959,7 +1026,11 @@ class ComputeManager(manager.SchedulerDependentManager):
context = context.elevated()
LOG.debug(_('instance %s: getting locked state'), instance_id,
context=context)
- instance_ref = self.db.instance_get(context, instance_id)
+ if utils.is_uuid_like(instance_id):
+ uuid = instance_id
+ instance_ref = self.db.instance_get_by_uuid(context, uuid)
+ else:
+ instance_ref = self.db.instance_get(context, instance_id)
return instance_ref['locked']
@checks_instance_lock
@@ -976,8 +1047,7 @@ class ComputeManager(manager.SchedulerDependentManager):
LOG.debug(_('instance %s: inject network info'), instance_id,
context=context)
instance = self.db.instance_get(context, instance_id)
- network_info = self.network_api.get_instance_nw_info(context,
- instance)
+ network_info = self._get_instance_nw_info(context, instance)
LOG.debug(_("network_info to inject: |%s|"), network_info)
self.driver.inject_network_info(instance, network_info)
@@ -1195,17 +1265,17 @@ class ComputeManager(manager.SchedulerDependentManager):
#
# Retry operation is necessary because continuously request comes,
# concorrent request occurs to iptables, then it complains.
+ network_info = self._get_instance_nw_info(context, instance_ref)
max_retry = FLAGS.live_migration_retry_count
for cnt in range(max_retry):
try:
- self.network_manager.setup_compute_network(context,
- instance_id)
+ self.driver.plug_vifs(instance_ref, network_info)
break
except exception.ProcessExecutionError:
if cnt == max_retry - 1:
raise
else:
- LOG.warn(_("setup_compute_network() failed %(cnt)d."
+ LOG.warn(_("plug_vifs() failed %(cnt)d."
"Retry up to %(max_retry)d for %(hostname)s.")
% locals())
time.sleep(1)
@@ -1283,8 +1353,9 @@ class ComputeManager(manager.SchedulerDependentManager):
# Releasing vlan.
# (not necessary in current implementation?)
+ network_info = self._get_instance_nw_info(ctxt, instance_ref)
# Releasing security group ingress rule.
- self.driver.unfilter_instance(instance_ref)
+ self.driver.unfilter_instance(instance_ref, network_info)
# Database updating.
i_name = instance_ref.name
diff --git a/nova/compute/monitor.py b/nova/compute/monitor.py
deleted file mode 100644
index 9d8e2a25d..000000000
--- a/nova/compute/monitor.py
+++ /dev/null
@@ -1,435 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Instance Monitoring:
-
- Optionally may be run on each compute node. Provides RRD
- based statistics and graphs and makes them internally available
- in the object store.
-"""
-
-import datetime
-import os
-import time
-
-import boto
-import boto.s3
-import rrdtool
-from twisted.internet import task
-from twisted.application import service
-
-from nova import flags
-from nova import log as logging
-from nova import utils
-from nova.virt import connection as virt_connection
-
-
-FLAGS = flags.FLAGS
-flags.DEFINE_integer('monitoring_instances_delay', 5,
- 'Sleep time between updates')
-flags.DEFINE_integer('monitoring_instances_step', 300,
- 'Interval of RRD updates')
-flags.DEFINE_string('monitoring_rrd_path', '$state_path/monitor/instances',
- 'Location of RRD files')
-
-
-RRD_VALUES = {
- 'cpu': [
- 'DS:cpu:GAUGE:600:0:100',
- 'RRA:AVERAGE:0.5:1:800',
- 'RRA:AVERAGE:0.5:6:800',
- 'RRA:AVERAGE:0.5:24:800',
- 'RRA:AVERAGE:0.5:288:800',
- 'RRA:MAX:0.5:1:800',
- 'RRA:MAX:0.5:6:800',
- 'RRA:MAX:0.5:24:800',
- 'RRA:MAX:0.5:288:800',
- ],
- 'net': [
- 'DS:rx:COUNTER:600:0:1250000',
- 'DS:tx:COUNTER:600:0:1250000',
- 'RRA:AVERAGE:0.5:1:800',
- 'RRA:AVERAGE:0.5:6:800',
- 'RRA:AVERAGE:0.5:24:800',
- 'RRA:AVERAGE:0.5:288:800',
- 'RRA:MAX:0.5:1:800',
- 'RRA:MAX:0.5:6:800',
- 'RRA:MAX:0.5:24:800',
- 'RRA:MAX:0.5:288:800',
- ],
- 'disk': [
- 'DS:rd:COUNTER:600:U:U',
- 'DS:wr:COUNTER:600:U:U',
- 'RRA:AVERAGE:0.5:1:800',
- 'RRA:AVERAGE:0.5:6:800',
- 'RRA:AVERAGE:0.5:24:800',
- 'RRA:AVERAGE:0.5:288:800',
- 'RRA:MAX:0.5:1:800',
- 'RRA:MAX:0.5:6:800',
- 'RRA:MAX:0.5:24:800',
- 'RRA:MAX:0.5:444:800',
- ]}
-
-
-utcnow = utils.utcnow
-
-
-LOG = logging.getLogger('nova.compute.monitor')
-
-
-def update_rrd(instance, name, data):
- """
- Updates the specified RRD file.
- """
- filename = os.path.join(instance.get_rrd_path(), '%s.rrd' % name)
-
- if not os.path.exists(filename):
- init_rrd(instance, name)
-
- timestamp = int(time.mktime(utcnow().timetuple()))
- rrdtool.update(filename, '%d:%s' % (timestamp, data))
-
-
-def init_rrd(instance, name):
- """
- Initializes the specified RRD file.
- """
- path = os.path.join(FLAGS.monitoring_rrd_path, instance.instance_id)
-
- if not os.path.exists(path):
- os.makedirs(path)
-
- filename = os.path.join(path, '%s.rrd' % name)
-
- if not os.path.exists(filename):
- rrdtool.create(
- filename,
- '--step', '%d' % FLAGS.monitoring_instances_step,
- '--start', '0',
- *RRD_VALUES[name])
-
-
-def graph_cpu(instance, duration):
- """
- Creates a graph of cpu usage for the specified instance and duration.
- """
- path = instance.get_rrd_path()
- filename = os.path.join(path, 'cpu-%s.png' % duration)
-
- rrdtool.graph(
- filename,
- '--disable-rrdtool-tag',
- '--imgformat', 'PNG',
- '--width', '400',
- '--height', '120',
- '--start', 'now-%s' % duration,
- '--vertical-label', '% cpu used',
- '-l', '0',
- '-u', '100',
- 'DEF:cpu=%s:cpu:AVERAGE' % os.path.join(path, 'cpu.rrd'),
- 'AREA:cpu#eacc00:% CPU',)
-
- store_graph(instance.instance_id, filename)
-
-
-def graph_net(instance, duration):
- """
- Creates a graph of network usage for the specified instance and duration.
- """
- path = instance.get_rrd_path()
- filename = os.path.join(path, 'net-%s.png' % duration)
-
- rrdtool.graph(
- filename,
- '--disable-rrdtool-tag',
- '--imgformat', 'PNG',
- '--width', '400',
- '--height', '120',
- '--start', 'now-%s' % duration,
- '--vertical-label', 'bytes/s',
- '--logarithmic',
- '--units', 'si',
- '--lower-limit', '1000',
- '--rigid',
- 'DEF:rx=%s:rx:AVERAGE' % os.path.join(path, 'net.rrd'),
- 'DEF:tx=%s:tx:AVERAGE' % os.path.join(path, 'net.rrd'),
- 'AREA:rx#00FF00:In traffic',
- 'LINE1:tx#0000FF:Out traffic',)
-
- store_graph(instance.instance_id, filename)
-
-
-def graph_disk(instance, duration):
- """
- Creates a graph of disk usage for the specified duration.
- """
- path = instance.get_rrd_path()
- filename = os.path.join(path, 'disk-%s.png' % duration)
-
- rrdtool.graph(
- filename,
- '--disable-rrdtool-tag',
- '--imgformat', 'PNG',
- '--width', '400',
- '--height', '120',
- '--start', 'now-%s' % duration,
- '--vertical-label', 'bytes/s',
- '--logarithmic',
- '--units', 'si',
- '--lower-limit', '1000',
- '--rigid',
- 'DEF:rd=%s:rd:AVERAGE' % os.path.join(path, 'disk.rrd'),
- 'DEF:wr=%s:wr:AVERAGE' % os.path.join(path, 'disk.rrd'),
- 'AREA:rd#00FF00:Read',
- 'LINE1:wr#0000FF:Write',)
-
- store_graph(instance.instance_id, filename)
-
-
-def store_graph(instance_id, filename):
- """
- Transmits the specified graph file to internal object store on cloud
- controller.
- """
- # TODO(devcamcar): Need to use an asynchronous method to make this
- # connection. If boto has some separate method that generates
- # the request it would like to make and another method to parse
- # the response we can make our own client that does the actual
- # request and hands it off to the response parser.
- s3 = boto.s3.connection.S3Connection(
- aws_access_key_id=FLAGS.aws_access_key_id,
- aws_secret_access_key=FLAGS.aws_secret_access_key,
- is_secure=False,
- calling_format=boto.s3.connection.OrdinaryCallingFormat(),
- port=FLAGS.s3_port,
- host=FLAGS.s3_host)
- bucket_name = '_%s.monitor' % instance_id
-
- # Object store isn't creating the bucket like it should currently
- # when it is first requested, so have to catch and create manually.
- try:
- bucket = s3.get_bucket(bucket_name)
- except Exception:
- bucket = s3.create_bucket(bucket_name)
-
- key = boto.s3.Key(bucket)
- key.key = os.path.basename(filename)
- key.set_contents_from_filename(filename)
-
-
-class Instance(object):
- def __init__(self, conn, instance_id):
- self.conn = conn
- self.instance_id = instance_id
- self.last_updated = datetime.datetime.min
- self.cputime = 0
- self.cputime_last_updated = None
-
- init_rrd(self, 'cpu')
- init_rrd(self, 'net')
- init_rrd(self, 'disk')
-
- def needs_update(self):
- """
- Indicates whether this instance is due to have its statistics updated.
- """
- delta = utcnow() - self.last_updated
- return delta.seconds >= FLAGS.monitoring_instances_step
-
- def update(self):
- """
- Updates the instances statistics and stores the resulting graphs
- in the internal object store on the cloud controller.
- """
- LOG.debug(_('updating %s...'), self.instance_id)
-
- try:
- data = self.fetch_cpu_stats()
- if data is not None:
- LOG.debug('CPU: %s', data)
- update_rrd(self, 'cpu', data)
-
- data = self.fetch_net_stats()
- LOG.debug('NET: %s', data)
- update_rrd(self, 'net', data)
-
- data = self.fetch_disk_stats()
- LOG.debug('DISK: %s', data)
- update_rrd(self, 'disk', data)
-
- # TODO(devcamcar): Turn these into pool.ProcessPool.execute() calls
- # and make the methods @defer.inlineCallbacks.
- graph_cpu(self, '1d')
- graph_cpu(self, '1w')
- graph_cpu(self, '1m')
-
- graph_net(self, '1d')
- graph_net(self, '1w')
- graph_net(self, '1m')
-
- graph_disk(self, '1d')
- graph_disk(self, '1w')
- graph_disk(self, '1m')
- except Exception:
- LOG.exception(_('unexpected error during update'))
-
- self.last_updated = utcnow()
-
- def get_rrd_path(self):
- """
- Returns the path to where RRD files are stored.
- """
- return os.path.join(FLAGS.monitoring_rrd_path, self.instance_id)
-
- def fetch_cpu_stats(self):
- """
- Returns cpu usage statistics for this instance.
- """
- info = self.conn.get_info(self.instance_id)
-
- # Get the previous values.
- cputime_last = self.cputime
- cputime_last_updated = self.cputime_last_updated
-
- # Get the raw CPU time used in nanoseconds.
- self.cputime = float(info['cpu_time'])
- self.cputime_last_updated = utcnow()
-
- LOG.debug('CPU: %d', self.cputime)
-
- # Skip calculation on first pass. Need delta to get a meaningful value.
- if cputime_last_updated is None:
- return None
-
- # Calculate the number of seconds between samples.
- d = self.cputime_last_updated - cputime_last_updated
- t = d.days * 86400 + d.seconds
-
- LOG.debug('t = %d', t)
-
- # Calculate change over time in number of nanoseconds of CPU time used.
- cputime_delta = self.cputime - cputime_last
-
- LOG.debug('cputime_delta = %s', cputime_delta)
-
- # Get the number of virtual cpus in this domain.
- vcpus = int(info['num_cpu'])
-
- LOG.debug('vcpus = %d', vcpus)
-
- # Calculate CPU % used and cap at 100.
- return min(cputime_delta / (t * vcpus * 1.0e9) * 100, 100)
-
- def fetch_disk_stats(self):
- """
- Returns disk usage statistics for this instance.
- """
- rd = 0
- wr = 0
-
- disks = self.conn.get_disks(self.instance_id)
-
- # Aggregate the read and write totals.
- for disk in disks:
- try:
- rd_req, rd_bytes, wr_req, wr_bytes, errs = \
- self.conn.block_stats(self.instance_id, disk)
- rd += rd_bytes
- wr += wr_bytes
- except TypeError:
- iid = self.instance_id
- LOG.error(_('Cannot get blockstats for "%(disk)s"'
- ' on "%(iid)s"') % locals())
- raise
-
- return '%d:%d' % (rd, wr)
-
- def fetch_net_stats(self):
- """
- Returns network usage statistics for this instance.
- """
- rx = 0
- tx = 0
-
- interfaces = self.conn.get_interfaces(self.instance_id)
-
- # Aggregate the in and out totals.
- for interface in interfaces:
- try:
- stats = self.conn.interface_stats(self.instance_id, interface)
- rx += stats[0]
- tx += stats[4]
- except TypeError:
- iid = self.instance_id
- LOG.error(_('Cannot get ifstats for "%(interface)s"'
- ' on "%(iid)s"') % locals())
- raise
-
- return '%d:%d' % (rx, tx)
-
-
-class InstanceMonitor(object, service.Service):
- """
- Monitors the running instances of the current machine.
- """
-
- def __init__(self):
- """
- Initialize the monitoring loop.
- """
- self._instances = {}
- self._loop = task.LoopingCall(self.updateInstances)
-
- def startService(self):
- self._instances = {}
- self._loop.start(interval=FLAGS.monitoring_instances_delay)
- service.Service.startService(self)
-
- def stopService(self):
- self._loop.stop()
- service.Service.stopService(self)
-
- def updateInstances(self):
- """
- Update resource usage for all running instances.
- """
- try:
- conn = virt_connection.get_connection(read_only=True)
- except Exception, exn:
- LOG.exception(_('unexpected exception getting connection'))
- time.sleep(FLAGS.monitoring_instances_delay)
- return
-
- domain_ids = conn.list_instances()
- try:
- self.updateInstances_(conn, domain_ids)
- except Exception, exn:
- LOG.exception('updateInstances_')
-
- def updateInstances_(self, conn, domain_ids):
- for domain_id in domain_ids:
- if not domain_id in self._instances:
- instance = Instance(conn, domain_id)
- self._instances[domain_id] = instance
- LOG.debug(_('Found instance: %s'), domain_id)
-
- for key in self._instances.keys():
- instance = self._instances[key]
- if instance.needs_update():
- instance.update()
diff --git a/nova/context.py b/nova/context.py
index 99085ed75..b917a1d81 100644
--- a/nova/context.py
+++ b/nova/context.py
@@ -18,9 +18,8 @@
"""RequestContext: context for requests that persist through all of nova."""
-import random
+import uuid
-from nova import exception
from nova import utils
@@ -31,86 +30,54 @@ class RequestContext(object):
"""
- def __init__(self, user, project, is_admin=None, read_deleted=False,
- remote_address=None, timestamp=None, request_id=None):
- if hasattr(user, 'id'):
- self._user = user
- self.user_id = user.id
- else:
- self._user = None
- self.user_id = user
- if hasattr(project, 'id'):
- self._project = project
- self.project_id = project.id
- else:
- self._project = None
- self.project_id = project
- if is_admin is None:
- if self.user_id and self.user:
- self.is_admin = self.user.is_admin()
- else:
- self.is_admin = False
- else:
- self.is_admin = is_admin
+ def __init__(self, user_id, project_id, is_admin=None, read_deleted=False,
+ roles=None, remote_address=None, timestamp=None,
+ request_id=None, auth_token=None):
+ self.user_id = user_id
+ self.project_id = project_id
+ self.roles = roles or []
+ self.is_admin = is_admin
+ if self.is_admin is None:
+ self.admin = 'admin' in self.roles
self.read_deleted = read_deleted
self.remote_address = remote_address
if not timestamp:
timestamp = utils.utcnow()
- if isinstance(timestamp, str) or isinstance(timestamp, unicode):
- timestamp = utils.parse_isotime(timestamp)
+ if isinstance(timestamp, basestring):
+ timestamp = utils.parse_strtime(timestamp)
self.timestamp = timestamp
if not request_id:
- chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-'
- request_id = ''.join([random.choice(chars) for x in xrange(20)])
+ request_id = unicode(uuid.uuid4())
self.request_id = request_id
-
- @property
- def user(self):
- # NOTE(vish): Delay import of manager, so that we can import this
- # file from manager.
- from nova.auth import manager
- if not self._user:
- try:
- self._user = manager.AuthManager().get_user(self.user_id)
- except exception.NotFound:
- pass
- return self._user
-
- @property
- def project(self):
- # NOTE(vish): Delay import of manager, so that we can import this
- # file from manager.
- from nova.auth import manager
- if not self._project:
- try:
- auth_manager = manager.AuthManager()
- self._project = auth_manager.get_project(self.project_id)
- except exception.NotFound:
- pass
- return self._project
+ self.auth_token = auth_token
def to_dict(self):
- return {'user': self.user_id,
- 'project': self.project_id,
+ return {'user_id': self.user_id,
+ 'project_id': self.project_id,
'is_admin': self.is_admin,
'read_deleted': self.read_deleted,
+ 'roles': self.roles,
'remote_address': self.remote_address,
- 'timestamp': utils.isotime(self.timestamp),
- 'request_id': self.request_id}
+ 'timestamp': utils.strtime(self.timestamp),
+ 'request_id': self.request_id,
+ 'auth_token': self.auth_token}
@classmethod
def from_dict(cls, values):
return cls(**values)
- def elevated(self, read_deleted=False):
+ def elevated(self, read_deleted=None):
"""Return a version of this context with admin flag set."""
- return RequestContext(self.user_id,
- self.project_id,
- True,
- read_deleted,
- self.remote_address,
- self.timestamp,
- self.request_id)
+ rd = self.read_deleted if read_deleted is None else read_deleted
+ return RequestContext(user_id=self.user_id,
+ project_id=self.project_id,
+ is_admin=True,
+ read_deleted=rd,
+ roles=self.roles,
+ remote_address=self.remote_address,
+ timestamp=self.timestamp,
+ request_id=self.request_id,
+ auth_token=self.auth_token)
def get_admin_context(read_deleted=False):
diff --git a/nova/db/api.py b/nova/db/api.py
index cb4da169c..47308bdba 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -314,9 +314,9 @@ def migration_get(context, migration_id):
return IMPL.migration_get(context, migration_id)
-def migration_get_by_instance_and_status(context, instance_id, status):
- """Finds a migration by the instance id its migrating."""
- return IMPL.migration_get_by_instance_and_status(context, instance_id,
+def migration_get_by_instance_and_status(context, instance_uuid, status):
+ """Finds a migration by the instance uuid its migrating."""
+ return IMPL.migration_get_by_instance_and_status(context, instance_uuid,
status)
@@ -332,13 +332,14 @@ def fixed_ip_associate(context, address, instance_id):
return IMPL.fixed_ip_associate(context, address, instance_id)
-def fixed_ip_associate_pool(context, network_id, instance_id):
- """Find free ip in network and associate it to instance.
+def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None):
+ """Find free ip in network and associate it to instance or host.
Raises if one is not available.
"""
- return IMPL.fixed_ip_associate_pool(context, network_id, instance_id)
+ return IMPL.fixed_ip_associate_pool(context, network_id,
+ instance_id, host)
def fixed_ip_create(context, values):
@@ -361,9 +362,9 @@ def fixed_ip_get_all(context):
return IMPL.fixed_ip_get_all(context)
-def fixed_ip_get_all_by_host(context, host):
- """Get all defined fixed ips used by a host."""
- return IMPL.fixed_ip_get_all_by_host(context, host)
+def fixed_ip_get_all_by_instance_host(context, host):
+ """Get all allocated fixed ips filtered by instance host."""
+ return IMPL.fixed_ip_get_all_instance_by_host(context, host)
def fixed_ip_get_by_address(context, address):
@@ -376,6 +377,11 @@ def fixed_ip_get_by_instance(context, instance_id):
return IMPL.fixed_ip_get_by_instance(context, instance_id)
+def fixed_ip_get_by_network_host(context, network_id, host):
+ """Get fixed ip for a host in a network."""
+ return IMPL.fixed_ip_get_by_network_host(context, network_id, host)
+
+
def fixed_ip_get_by_virtual_interface(context, vif_id):
"""Get fixed ips by virtual interface or raise if none exist."""
return IMPL.fixed_ip_get_by_virtual_interface(context, vif_id)
@@ -1305,9 +1311,9 @@ def instance_type_get_all(context, inactive=False):
return IMPL.instance_type_get_all(context, inactive)
-def instance_type_get_by_id(context, id):
+def instance_type_get(context, id):
"""Get instance type by id."""
- return IMPL.instance_type_get_by_id(context, id)
+ return IMPL.instance_type_get(context, id)
def instance_type_get_by_name(context, name):
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 189be0714..f469dc0e5 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -18,7 +18,6 @@
"""
Implementation of SQLAlchemy backend.
"""
-import traceback
import warnings
from nova import db
@@ -33,7 +32,6 @@ from sqlalchemy import or_
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import joinedload_all
-from sqlalchemy.sql import exists
from sqlalchemy.sql import func
from sqlalchemy.sql.expression import literal_column
@@ -64,7 +62,7 @@ def is_user_context(context):
def authorize_project_context(context, project_id):
"""Ensures a request has permission to access the given project."""
if is_user_context(context):
- if not context.project:
+ if not context.project_id:
raise exception.NotAuthorized()
elif context.project_id != project_id:
raise exception.NotAuthorized()
@@ -73,7 +71,7 @@ def authorize_project_context(context, project_id):
def authorize_user_context(context, user_id):
"""Ensures a request has permission to access the given user."""
if is_user_context(context):
- if not context.user:
+ if not context.user_id:
raise exception.NotAuthorized()
elif context.user_id != user_id:
raise exception.NotAuthorized()
@@ -672,7 +670,7 @@ def fixed_ip_associate(context, address, instance_id):
@require_admin_context
-def fixed_ip_associate_pool(context, network_id, instance_id):
+def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None):
session = get_session()
with session.begin():
network_or_none = or_(models.FixedIp.network_id == network_id,
@@ -682,6 +680,7 @@ def fixed_ip_associate_pool(context, network_id, instance_id):
filter_by(reserved=False).\
filter_by(deleted=False).\
filter_by(instance=None).\
+ filter_by(host=None).\
with_lockmode('update').\
first()
# NOTE(vish): if with_lockmode isn't supported, as in sqlite,
@@ -692,9 +691,12 @@ def fixed_ip_associate_pool(context, network_id, instance_id):
fixed_ip_ref.network = network_get(context,
network_id,
session=session)
- fixed_ip_ref.instance = instance_get(context,
- instance_id,
- session=session)
+ if instance_id:
+ fixed_ip_ref.instance = instance_get(context,
+ instance_id,
+ session=session)
+ if host:
+ fixed_ip_ref.host = host
session.add(fixed_ip_ref)
return fixed_ip_ref['address']
@@ -750,7 +752,7 @@ def fixed_ip_get_all(context, session=None):
@require_admin_context
-def fixed_ip_get_all_by_host(context, host=None):
+def fixed_ip_get_all_by_instance_host(context, host=None):
session = get_session()
result = session.query(models.FixedIp).\
@@ -800,6 +802,20 @@ def fixed_ip_get_by_instance(context, instance_id):
@require_context
+def fixed_ip_get_by_network_host(context, network_id, host):
+ session = get_session()
+ rv = session.query(models.FixedIp).\
+ filter_by(network_id=network_id).\
+ filter_by(host=host).\
+ filter_by(deleted=False).\
+ first()
+ if not rv:
+ raise exception.FixedIpNotFoundForNetworkHost(network_id=network_id,
+ host=host)
+ return rv
+
+
+@require_context
def fixed_ip_get_by_virtual_interface(context, vif_id):
session = get_session()
rv = session.query(models.FixedIp).\
@@ -1157,9 +1173,9 @@ def instance_get_active_by_window(context, begin, end=None):
"""Return instances that were continuously active over the given window"""
session = get_session()
query = session.query(models.Instance).\
- options(joinedload_all('fixed_ip.floating_ips')).\
+ options(joinedload_all('fixed_ips.floating_ips')).\
options(joinedload('security_groups')).\
- options(joinedload_all('fixed_ip.network')).\
+ options(joinedload_all('fixed_ips.network')).\
options(joinedload('instance_type')).\
filter(models.Instance.launched_at < begin)
if end:
@@ -1253,7 +1269,7 @@ def instance_get_project_vpn(context, project_id):
options(joinedload_all('fixed_ips.floating_ips')).\
options(joinedload('virtual_interfaces')).\
options(joinedload('security_groups')).\
- options(joinedload_all('fixed_ip.network')).\
+ options(joinedload_all('fixed_ips.network')).\
options(joinedload('metadata')).\
options(joinedload('instance_type')).\
filter_by(project_id=project_id).\
@@ -1296,7 +1312,7 @@ def instance_get_fixed_addresses_v6(context, instance_id):
# combine prefixes, macs, and project_id into (prefix,mac,p_id) tuples
prefix_mac_tuples = zip(prefixes, macs, [project_id for m in macs])
# return list containing ipv6 address for each tuple
- return [ipv6.to_global_ipv6(*t) for t in prefix_mac_tuples]
+ return [ipv6.to_global(*t) for t in prefix_mac_tuples]
@require_context
@@ -1333,7 +1349,11 @@ def instance_update(context, instance_id, values):
instance_metadata_update_or_create(context, instance_id,
values.pop('metadata'))
with session.begin():
- instance_ref = instance_get(context, instance_id, session=session)
+ if utils.is_uuid_like(instance_id):
+ instance_ref = instance_get_by_uuid(context, instance_id,
+ session=session)
+ else:
+ instance_ref = instance_get(context, instance_id, session=session)
instance_ref.update(values)
instance_ref.save(session=session)
return instance_ref
@@ -1406,9 +1426,14 @@ def instance_action_create(context, values):
def instance_get_actions(context, instance_id):
"""Return the actions associated to the given instance id"""
session = get_session()
+
+ if utils.is_uuid_like(instance_id):
+ instance = instance_get_by_uuid(context, instance_id, session)
+ instance_id = instance.id
+
return session.query(models.InstanceActions).\
filter_by(instance_id=instance_id).\
- all()
+ all()
###################
@@ -1480,8 +1505,6 @@ def network_associate(context, project_id, force=False):
called by project_get_networks under certain conditions
and network manager add_network_to_project()
- only associates projects with networks that have configured hosts
-
only associate if the project doesn't already have a network
or if force is True
@@ -1497,7 +1520,6 @@ def network_associate(context, project_id, force=False):
def network_query(project_filter):
return session.query(models.Network).\
filter_by(deleted=False).\
- filter(models.Network.host != None).\
filter_by(project_id=project_filter).\
with_lockmode('update').\
first()
@@ -1663,7 +1685,8 @@ def network_get_by_bridge(context, bridge):
def network_get_by_cidr(context, cidr):
session = get_session()
result = session.query(models.Network).\
- filter_by(cidr=cidr).first()
+ filter(or_(models.Network.cidr == cidr,
+ models.Network.cidr_v6 == cidr)).first()
if not result:
raise exception.NetworkNotFoundForCidr(cidr=cidr)
@@ -1704,9 +1727,16 @@ def network_get_all_by_instance(_context, instance_id):
def network_get_all_by_host(context, host):
session = get_session()
with session.begin():
+ # NOTE(vish): return networks that have host set
+ # or that have a fixed ip with host set
+ host_filter = or_(models.Network.host == host,
+ models.FixedIp.host == host)
+
return session.query(models.Network).\
filter_by(deleted=False).\
- filter_by(host=host).\
+ join(models.Network.fixed_ips).\
+ filter(host_filter).\
+ filter_by(deleted=False).\
all()
@@ -1738,6 +1768,7 @@ def network_update(context, network_id, values):
network_ref = network_get(context, network_id, session=session)
network_ref.update(values)
network_ref.save(session=session)
+ return network_ref
###################
@@ -2798,13 +2829,13 @@ def migration_get(context, id, session=None):
@require_admin_context
-def migration_get_by_instance_and_status(context, instance_id, status):
+def migration_get_by_instance_and_status(context, instance_uuid, status):
session = get_session()
result = session.query(models.Migration).\
- filter_by(instance_id=instance_id).\
+ filter_by(instance_uuid=instance_uuid).\
filter_by(status=status).first()
if not result:
- raise exception.MigrationNotFoundByStatus(instance_id=instance_id,
+ raise exception.MigrationNotFoundByStatus(instance_id=instance_uuid,
status=status)
return result
@@ -2985,7 +3016,7 @@ def instance_type_get_all(context, inactive=False):
@require_context
-def instance_type_get_by_id(context, id):
+def instance_type_get(context, id):
"""Returns a dict describing specific instance_type"""
session = get_session()
inst_type = session.query(models.InstanceTypes).\
@@ -3016,13 +3047,18 @@ def instance_type_get_by_name(context, name):
@require_context
def instance_type_get_by_flavor_id(context, id):
"""Returns a dict describing specific flavor_id"""
+ try:
+ flavor_id = int(id)
+ except ValueError:
+ raise exception.FlavorNotFound(flavor_id=id)
+
session = get_session()
inst_type = session.query(models.InstanceTypes).\
options(joinedload('extra_specs')).\
- filter_by(flavorid=int(id)).\
+ filter_by(flavorid=flavor_id).\
first()
if not inst_type:
- raise exception.FlavorNotFound(flavor_id=id)
+ raise exception.FlavorNotFound(flavor_id=flavor_id)
else:
return _dict_with_extra_specs(inst_type)
@@ -3147,8 +3183,9 @@ def instance_metadata_delete_all(context, instance_id):
@require_context
@require_instance_exists
-def instance_metadata_get_item(context, instance_id, key):
- session = get_session()
+def instance_metadata_get_item(context, instance_id, key, session=None):
+ if not session:
+ session = get_session()
meta_result = session.query(models.InstanceMetadata).\
filter_by(instance_id=instance_id).\
@@ -3174,7 +3211,7 @@ def instance_metadata_update_or_create(context, instance_id, metadata):
try:
meta_ref = instance_metadata_get_item(context, instance_id, key,
session)
- except:
+ except exception.InstanceMetadataNotFound, e:
meta_ref = models.InstanceMetadata()
meta_ref.update({"key": key, "value": value,
"instance_id": instance_id,
@@ -3222,8 +3259,8 @@ def agent_build_destroy(context, agent_build_id):
with session.begin():
session.query(models.AgentBuild).\
filter_by(id=agent_build_id).\
- update({'deleted': 1,
- 'deleted_at': datetime.datetime.utcnow(),
+ update({'deleted': True,
+ 'deleted_at': utils.utcnow(),
'updated_at': literal_column('updated_at')})
@@ -3269,10 +3306,12 @@ def instance_type_extra_specs_delete(context, instance_type_id, key):
@require_context
-def instance_type_extra_specs_get_item(context, instance_type_id, key):
- session = get_session()
+def instance_type_extra_specs_get_item(context, instance_type_id, key,
+ session=None):
+ if not session:
+ session = get_session()
- sppec_result = session.query(models.InstanceTypeExtraSpecs).\
+ spec_result = session.query(models.InstanceTypeExtraSpecs).\
filter_by(instance_type_id=instance_type_id).\
filter_by(key=key).\
filter_by(deleted=False).\
@@ -3296,7 +3335,7 @@ def instance_type_extra_specs_update_or_create(context, instance_type_id,
instance_type_id,
key,
session)
- except:
+ except exception.InstanceTypeExtraSpecsNotFound, e:
spec_ref = models.InstanceTypeExtraSpecs()
spec_ref.update({"key": key, "value": value,
"instance_type_id": instance_type_id,
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py b/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py
new file mode 100644
index 000000000..3a5f7eba8
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py
@@ -0,0 +1,44 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 OpenStack, LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import Column, Table, MetaData, Boolean, String
+
+meta = MetaData()
+
+fixed_ips_host = Column('host', String(255))
+
+networks_multi_host = Column('multi_host', Boolean, default=False)
+
+
+def upgrade(migrate_engine):
+ meta.bind = migrate_engine
+
+ fixed_ips = Table('fixed_ips', meta, autoload=True)
+ fixed_ips.create_column(fixed_ips_host)
+
+ networks = Table('networks', meta, autoload=True)
+ networks.create_column(networks_multi_host)
+
+
+def downgrade(migrate_engine):
+ meta.bind = migrate_engine
+
+ fixed_ips = Table('fixed_ips', meta, autoload=True)
+ fixed_ips.drop_column(fixed_ips_host)
+
+ networks = Table('networks', meta, autoload=True)
+ networks.drop_column(networks_multi_host)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/034_change_instance_id_in_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/034_change_instance_id_in_migrations.py
new file mode 100644
index 000000000..4e8eaf0fd
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/034_change_instance_id_in_migrations.py
@@ -0,0 +1,52 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.from sqlalchemy import *
+
+from sqlalchemy import Column, Integer, String, MetaData, Table
+
+
+meta = MetaData()
+
+
+#
+# Tables to alter
+#
+#
+
+instance_id = Column('instance_id', Integer())
+instance_uuid = Column('instance_uuid', String(255))
+
+
+def upgrade(migrate_engine):
+ meta.bind = migrate_engine
+ migrations = Table('migrations', meta, autoload=True)
+ migrations.create_column(instance_uuid)
+
+ if migrate_engine.name == "mysql":
+ try:
+ migrate_engine.execute("ALTER TABLE migrations DROP FOREIGN KEY " \
+ "`migrations_ibfk_1`;")
+ except Exception: # Don't care, just fail silently.
+ pass
+
+ migrations.c.instance_id.drop()
+
+
+def downgrade(migrate_engine):
+ meta.bind = migrate_engine
+ migrations = Table('migrations', meta, autoload=True)
+ migrations.c.instance_uuid.drop()
+ migrations.create_column(instance_id)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/035_secondary_dns.py b/nova/db/sqlalchemy/migrate_repo/versions/035_secondary_dns.py
new file mode 100644
index 000000000..c938eb716
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/035_secondary_dns.py
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 OpenStack, LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import Column, Table, MetaData, Boolean, String
+
+meta = MetaData()
+
+dns2 = Column('dns2', String(255))
+
+
+def upgrade(migrate_engine):
+ meta.bind = migrate_engine
+
+ networks = Table('networks', meta, autoload=True)
+ networks.c.dns.alter(Column('dns1', String(255)))
+ networks.create_column(dns2)
+
+
+def downgrade(migrate_engine):
+ meta.bind = migrate_engine
+
+ networks = Table('networks', meta, autoload=True)
+ networks.c.dns1.alter(Column('dns', String(255)))
+ networks.drop_column(dns2)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/036_change_flavor_id_in_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/036_change_flavor_id_in_migrations.py
new file mode 100644
index 000000000..f3244033b
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/036_change_flavor_id_in_migrations.py
@@ -0,0 +1,72 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.from sqlalchemy import *
+
+from sqlalchemy import Column, Integer, MetaData, Table
+
+
+meta = MetaData()
+
+
+#
+# Tables to alter
+#
+#
+
+old_flavor_id = Column('old_flavor_id', Integer())
+new_flavor_id = Column('new_flavor_id', Integer())
+old_instance_type_id = Column('old_instance_type_id', Integer())
+new_instance_type_id = Column('new_instance_type_id', Integer())
+
+
+def upgrade(migrate_engine):
+ meta.bind = migrate_engine
+ instance_types = Table('instance_types', meta, autoload=True)
+ migrations = Table('migrations', meta, autoload=True)
+ migrations.create_column(old_instance_type_id)
+ migrations.create_column(new_instance_type_id)
+
+ # Convert flavor_id to instance_type_id
+ for instance_type in migrate_engine.execute(instance_types.select()):
+ migrate_engine.execute(migrations.update()\
+ .where(migrations.c.old_flavor_id == instance_type.flavorid)\
+ .values(old_instance_type_id=instance_type.id))
+ migrate_engine.execute(migrations.update()\
+ .where(migrations.c.new_flavor_id == instance_type.flavorid)\
+ .values(new_instance_type_id=instance_type.id))
+
+ migrations.c.old_flavor_id.drop()
+ migrations.c.new_flavor_id.drop()
+
+
+def downgrade(migrate_engine):
+ meta.bind = migrate_engine
+ instance_types = Table('instance_types', meta, autoload=True)
+ migrations = Table('migrations', meta, autoload=True)
+ migrations.create_column(old_flavor_id)
+ migrations.create_column(new_flavor_id)
+
+ # Convert instance_type_id to flavor_id
+ for instance_type in migrate_engine.execute(instance_types.select()):
+ migrate_engine.execute(migrations.update()\
+ .where(migrations.c.old_instance_type_id == instance_type.id)\
+ .values(old_flavor_id=instance_type.flavorid))
+ migrate_engine.execute(migrations.update()\
+ .where(migrations.c.new_instance_type_id == instance_type.id)\
+ .values(new_flavor_id=instance_type.flavorid))
+
+ migrations.c.old_instance_type_id.drop()
+ migrations.c.new_instance_type_id.drop()
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 1bcc8eaec..9f4c7a0aa 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -31,6 +31,7 @@ from nova.db.sqlalchemy.session import get_session
from nova import auth
from nova import exception
from nova import flags
+from nova import ipv6
from nova import utils
@@ -176,14 +177,6 @@ class Instance(BASE, NovaBase):
user_id = Column(String(255))
project_id = Column(String(255))
- @property
- def user(self):
- return auth.manager.AuthManager().get_user(self.user_id)
-
- @property
- def project(self):
- return auth.manager.AuthManager().get_project(self.project_id)
-
image_ref = Column(String(255))
kernel_id = Column(String(255))
ramdisk_id = Column(String(255))
@@ -209,7 +202,7 @@ class Instance(BASE, NovaBase):
hostname = Column(String(255))
host = Column(String(255)) # , ForeignKey('hosts.id'))
- # aka flavor_id
+ # *not* flavor_id
instance_type_id = Column(Integer)
user_data = Column(Text)
@@ -464,14 +457,6 @@ class SecurityGroup(BASE, NovaBase):
'Instance.deleted == False)',
backref='security_groups')
- @property
- def user(self):
- return auth.manager.AuthManager().get_user(self.user_id)
-
- @property
- def project(self):
- return auth.manager.AuthManager().get_project(self.project_id)
-
class SecurityGroupIngressRule(BASE, NovaBase):
"""Represents a rule in a security group."""
@@ -526,9 +511,10 @@ class Migration(BASE, NovaBase):
source_compute = Column(String(255))
dest_compute = Column(String(255))
dest_host = Column(String(255))
- old_flavor_id = Column(Integer())
- new_flavor_id = Column(Integer())
- instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
+ old_instance_type_id = Column(Integer())
+ new_instance_type_id = Column(Integer())
+ instance_uuid = Column(String(255), ForeignKey('instances.uuid'),
+ nullable=True)
#TODO(_cerberus_): enum
status = Column(String(255))
@@ -545,6 +531,7 @@ class Network(BASE, NovaBase):
injected = Column(Boolean, default=False)
cidr = Column(String(255), unique=True)
cidr_v6 = Column(String(255), unique=True)
+ multi_host = Column(Boolean, default=False)
gateway_v6 = Column(String(255))
netmask_v6 = Column(String(255))
@@ -553,7 +540,8 @@ class Network(BASE, NovaBase):
bridge_interface = Column(String(255))
gateway = Column(String(255))
broadcast = Column(String(255))
- dns = Column(String(255))
+ dns1 = Column(String(255))
+ dns2 = Column(String(255))
vlan = Column(Integer)
vpn_public_address = Column(String(255))
@@ -577,6 +565,18 @@ class VirtualInterface(BASE, NovaBase):
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=False)
instance = relationship(Instance, backref=backref('virtual_interfaces'))
+ @property
+ def fixed_ipv6(self):
+ cidr_v6 = self.network.cidr_v6
+ if cidr_v6 is None:
+ ipv6_address = None
+ else:
+ project_id = self.instance.project_id
+ mac = self.address
+ ipv6_address = ipv6.to_global(cidr_v6, mac, project_id)
+
+ return ipv6_address
+
# TODO(vish): can these both come from the same baseclass?
class FixedIp(BASE, NovaBase):
@@ -603,6 +603,7 @@ class FixedIp(BASE, NovaBase):
# leased means dhcp bridge has leased the ip
leased = Column(Boolean, default=False)
reserved = Column(Boolean, default=False)
+ host = Column(String(255))
class FloatingIp(BASE, NovaBase):
diff --git a/nova/exception.py b/nova/exception.py
index 8f3cf0af6..5374d2a90 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -78,8 +78,8 @@ def wrap_db_error(f):
except Exception, e:
LOG.exception(_('DB exception wrapped.'))
raise DBError(e)
- return _wrap
_wrap.func_name = f.func_name
+ return _wrap
def wrap_exception(notifier=None, publisher_id=None, event_type=None,
@@ -116,7 +116,8 @@ def wrap_exception(notifier=None, publisher_id=None, event_type=None,
notifier.notify(publisher_id, temp_type, temp_level,
payload)
- if not isinstance(e, Error):
+ if (not isinstance(e, Error) and
+ not isinstance(e, NovaException)):
#exc_type, exc_value, exc_traceback = sys.exc_info()
LOG.exception(_('Uncaught exception'))
#logging.error(traceback.extract_stack(exc_traceback))
@@ -149,6 +150,10 @@ class NovaException(Exception):
return self._error_string
+class ImagePaginationFailed(NovaException):
+ message = _("Failed to paginate through images from image service")
+
+
class VirtualInterfaceCreateException(NovaException):
message = _("Virtual Interface creation failed")
@@ -378,6 +383,10 @@ class StorageRepositoryNotFound(NotFound):
message = _("Cannot find SR to read/write VDI.")
+class NetworkNotCreated(NovaException):
+ message = _("%(req)s is required to create a network.")
+
+
class NetworkNotFound(NotFound):
message = _("Network %(network_id)s could not be found.")
@@ -414,6 +423,11 @@ class FixedIpNotFoundForInstance(FixedIpNotFound):
message = _("Instance %(instance_id)s has zero fixed ips.")
+class FixedIpNotFoundForNetworkHost(FixedIpNotFound):
+ message = _("Network host %(host)s has zero fixed ips "
+ "in network %(network_id)s.")
+
+
class FixedIpNotFoundForSpecificInstance(FixedIpNotFound):
message = _("Instance %(instance_id)s doesn't have fixed ip '%(ip)s'.")
@@ -688,3 +702,11 @@ class PasteConfigNotFound(NotFound):
class PasteAppNotFound(NotFound):
message = _("Could not load paste app '%(name)s' from %(path)s")
+
+
+class CannotResizeToSameSize(NovaException):
+ message = _("When resizing, instances must change size!")
+
+
+class CannotResizeToSmallerSize(NovaException):
+ message = _("Resizing to a smaller size is not supported.")
diff --git a/nova/flags.py b/nova/flags.py
index 49355b436..12c6d1356 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -343,7 +343,7 @@ DEFINE_string('lock_path', os.path.join(os.path.dirname(__file__), '../'),
'Directory for lock files')
DEFINE_string('logdir', None, 'output to a per-service log file in named '
'directory')
-
+DEFINE_integer('logfile_mode', 0644, 'Default file mode of the logs.')
DEFINE_string('sqlite_db', 'nova.sqlite', 'file name for sqlite')
DEFINE_string('sql_connection',
'sqlite:///$state_path/$sqlite_db',
@@ -387,3 +387,8 @@ DEFINE_list('zone_capabilities',
'Key/Multi-value list representng capabilities of this zone')
DEFINE_string('build_plan_encryption_key', None,
'128bit (hex) encryption key for scheduler build plans.')
+
+DEFINE_bool('start_guests_on_host_boot', False,
+ 'Whether to restart guests when the host reboots')
+DEFINE_bool('resume_guests_state_on_host_boot', False,
+ 'Whether to start guests, that was running before the host reboot')
diff --git a/nova/image/__init__.py b/nova/image/__init__.py
index a27d649d4..5447c8a3a 100644
--- a/nova/image/__init__.py
+++ b/nova/image/__init__.py
@@ -35,6 +35,7 @@ def _parse_image_ref(image_href):
:param image_href: href of an image
:returns: a tuple of the form (image_id, host, port)
+ :raises ValueError
"""
o = urlparse(image_href)
@@ -72,7 +73,7 @@ def get_glance_client(image_href):
try:
(image_id, host, port) = _parse_image_ref(image_href)
- except:
+ except ValueError:
raise exception.InvalidImageRef(image_href=image_href)
glance_client = GlanceClient(host, port)
return (glance_client, image_id)
diff --git a/nova/image/fake.py b/nova/image/fake.py
index 28e912534..97af81711 100644
--- a/nova/image/fake.py
+++ b/nova/image/fake.py
@@ -45,9 +45,12 @@ class _FakeImageService(service.BaseImageService):
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
+ 'deleted_at': None,
+ 'deleted': False,
'status': 'active',
- 'container_format': 'ami',
- 'disk_format': 'raw',
+ 'is_public': False,
+# 'container_format': 'ami',
+# 'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel,
'architecture': 'x86_64'}}
@@ -56,9 +59,12 @@ class _FakeImageService(service.BaseImageService):
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
+ 'deleted_at': None,
+ 'deleted': False,
'status': 'active',
- 'container_format': 'ami',
- 'disk_format': 'raw',
+ 'is_public': True,
+# 'container_format': 'ami',
+# 'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
@@ -66,9 +72,12 @@ class _FakeImageService(service.BaseImageService):
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
+ 'deleted_at': None,
+ 'deleted': False,
'status': 'active',
- 'container_format': 'ami',
- 'disk_format': 'raw',
+ 'is_public': True,
+# 'container_format': 'ami',
+# 'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
@@ -76,9 +85,12 @@ class _FakeImageService(service.BaseImageService):
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
+ 'deleted_at': None,
+ 'deleted': False,
'status': 'active',
- 'container_format': 'ami',
- 'disk_format': 'raw',
+ 'is_public': True,
+# 'container_format': 'ami',
+# 'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
@@ -86,9 +98,12 @@ class _FakeImageService(service.BaseImageService):
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
+ 'deleted_at': None,
+ 'deleted': False,
'status': 'active',
- 'container_format': 'ami',
- 'disk_format': 'raw',
+ 'is_public': True,
+# 'container_format': 'ami',
+# 'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
@@ -101,7 +116,11 @@ class _FakeImageService(service.BaseImageService):
def index(self, context, filters=None, marker=None, limit=None):
"""Returns list of images."""
- return copy.deepcopy(self.images.values())
+ retval = []
+ for img in self.images.values():
+ retval += [dict([(k, v) for k, v in img.iteritems()
+ if k in ['id', 'name']])]
+ return retval
def detail(self, context, filters=None, marker=None, limit=None):
"""Return list of detailed image information."""
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 55d948a32..da93f0d1c 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -83,35 +83,79 @@ class GlanceImageService(service.BaseImageService):
client = property(_get_client, _set_client)
- def index(self, context, filters=None, marker=None, limit=None):
+ def _set_client_context(self, context):
+ """Sets the client's auth token."""
+ self.client.set_auth_token(context.auth_token)
+
+ def index(self, context, **kwargs):
"""Calls out to Glance for a list of images available."""
- # NOTE(sirp): We need to use `get_images_detailed` and not
- # `get_images` here because we need `is_public` and `properties`
- # included so we can filter by user
- filtered = []
- image_metas = self.client.get_images_detailed(filters=filters,
- marker=marker,
- limit=limit)
+ params = self._extract_query_params(kwargs)
+ image_metas = self._get_images(context, **params)
+
+ images = []
for image_meta in image_metas:
+ # NOTE(sirp): We need to use `get_images_detailed` and not
+ # `get_images` here because we need `is_public` and `properties`
+ # included so we can filter by user
if self._is_image_available(context, image_meta):
meta_subset = utils.subset_dict(image_meta, ('id', 'name'))
- filtered.append(meta_subset)
- return filtered
+ images.append(meta_subset)
+ return images
- def detail(self, context, filters=None, marker=None, limit=None):
+ def detail(self, context, **kwargs):
"""Calls out to Glance for a list of detailed image information."""
- filtered = []
- image_metas = self.client.get_images_detailed(filters=filters,
- marker=marker,
- limit=limit)
+ params = self._extract_query_params(kwargs)
+ image_metas = self._get_images(context, **params)
+
+ images = []
for image_meta in image_metas:
if self._is_image_available(context, image_meta):
base_image_meta = self._translate_to_base(image_meta)
- filtered.append(base_image_meta)
- return filtered
+ images.append(base_image_meta)
+ return images
+
+ def _extract_query_params(self, params):
+ _params = {}
+ accepted_params = ('filters', 'marker', 'limit',
+ 'sort_key', 'sort_dir')
+ for param in accepted_params:
+ if param in params:
+ _params[param] = params.get(param)
+
+ return _params
+
+ def _get_images(self, context, **kwargs):
+ """Get image entitites from images service"""
+ self._set_client_context(context)
+
+ # ensure filters is a dict
+ kwargs['filters'] = kwargs.get('filters') or {}
+ # NOTE(vish): don't filter out private images
+ kwargs['filters'].setdefault('is_public', 'none')
+
+ return self._fetch_images(self.client.get_images_detailed, **kwargs)
+
+ def _fetch_images(self, fetch_func, **kwargs):
+ """Paginate through results from glance server"""
+ images = fetch_func(**kwargs)
+
+ for image in images:
+ yield image
+ else:
+ # break out of recursive loop to end pagination
+ return
+
+ try:
+ # attempt to advance the marker in order to fetch next page
+ kwargs['marker'] = images[-1]['id']
+ except KeyError:
+ raise exception.ImagePaginationFailed()
+
+ self._fetch_images(fetch_func, **kwargs)
def show(self, context, image_id):
"""Returns a dict with image data for the given opaque image id."""
+ self._set_client_context(context)
try:
image_meta = self.client.get_image_meta(image_id)
except glance_exception.NotFound:
@@ -135,6 +179,7 @@ class GlanceImageService(service.BaseImageService):
def get(self, context, image_id, data):
"""Calls out to Glance for metadata and data and writes data."""
+ self._set_client_context(context)
try:
image_meta, image_chunks = self.client.get_image(image_id)
except glance_exception.NotFound:
@@ -152,6 +197,7 @@ class GlanceImageService(service.BaseImageService):
:raises: AlreadyExists if the image already exist.
"""
+ self._set_client_context(context)
# Translate Base -> Service
LOG.debug(_('Creating image in Glance. Metadata passed in %s'),
image_meta)
@@ -174,6 +220,7 @@ class GlanceImageService(service.BaseImageService):
:raises: ImageNotFound if the image does not exist.
"""
+ self._set_client_context(context)
# NOTE(vish): show is to check if image is available
self.show(context, image_id)
try:
@@ -190,6 +237,7 @@ class GlanceImageService(service.BaseImageService):
:raises: ImageNotFound if the image does not exist.
"""
+ self._set_client_context(context)
# NOTE(vish): show is to check if image is available
self.show(context, image_id)
try:
diff --git a/nova/image/s3.py b/nova/image/s3.py
index 4a3df98ba..ccbfa89cd 100644
--- a/nova/image/s3.py
+++ b/nova/image/s3.py
@@ -34,7 +34,6 @@ from nova import flags
from nova import image
from nova import log as logging
from nova import utils
-from nova.auth import manager
from nova.image import service
from nova.api.ec2 import ec2utils
@@ -43,6 +42,10 @@ LOG = logging.getLogger("nova.image.s3")
FLAGS = flags.FLAGS
flags.DEFINE_string('image_decryption_dir', '/tmp',
'parent dir for tempdir used for image decryption')
+flags.DEFINE_string('s3_access_key', 'notchecked',
+ 'access key to use for s3 server for images')
+flags.DEFINE_string('s3_secret_key', 'notchecked',
+ 'secret key to use for s3 server for images')
class S3ImageService(service.BaseImageService):
@@ -82,11 +85,10 @@ class S3ImageService(service.BaseImageService):
@staticmethod
def _conn(context):
- # TODO(vish): is there a better way to get creds to sign
- # for the user?
- access = manager.AuthManager().get_access_key(context.user,
- context.project)
- secret = str(context.user.secret)
+ # NOTE(vish): access and secret keys for s3 server are not
+ # checked in nova-objectstore
+ access = FLAGS.s3_access_key
+ secret = FLAGS.s3_secret_key
calling = boto.s3.connection.OrdinaryCallingFormat()
return boto.s3.connection.S3Connection(aws_access_key_id=access,
aws_secret_access_key=secret,
@@ -168,7 +170,7 @@ class S3ImageService(service.BaseImageService):
metadata.update({'disk_format': image_format,
'container_format': image_format,
'status': 'queued',
- 'is_public': True,
+ 'is_public': False,
'properties': properties})
metadata['properties']['image_state'] = 'pending'
image = self.service.create(context, metadata)
diff --git a/nova/log.py b/nova/log.py
index f8c0ba68d..222b8c5fb 100644
--- a/nova/log.py
+++ b/nova/log.py
@@ -43,8 +43,8 @@ from nova import version
FLAGS = flags.FLAGS
flags.DEFINE_string('logging_context_format_string',
'%(asctime)s %(levelname)s %(name)s '
- '[%(request_id)s %(user)s '
- '%(project)s] %(message)s',
+ '[%(request_id)s %(user_id)s '
+ '%(project_id)s] %(message)s',
'format string to use for log messages with context')
flags.DEFINE_string('logging_default_format_string',
'%(asctime)s %(levelname)s %(name)s [-] '
@@ -257,6 +257,7 @@ class NovaRootLogger(NovaLogger):
self.filelog = WatchedFileHandler(logpath)
self.addHandler(self.filelog)
self.logpath = logpath
+ os.chmod(self.logpath, FLAGS.logfile_mode)
else:
self.removeHandler(self.filelog)
self.addHandler(self.streamlog)
diff --git a/nova/network/api.py b/nova/network/api.py
index 70b1099f0..247768722 100644
--- a/nova/network/api.py
+++ b/nova/network/api.py
@@ -18,7 +18,6 @@
"""Handles all requests relating to instances (guest vms)."""
-from nova import db
from nova import exception
from nova import flags
from nova import log as logging
@@ -46,6 +45,10 @@ class API(base.Base):
context.project_id)
return ips
+ def get_vifs_by_instance(self, context, instance_id):
+ vifs = self.db.virtual_interface_get_by_instance(context, instance_id)
+ return vifs
+
def allocate_floating_ip(self, context):
"""Adds a floating ip to a project."""
# NOTE(vish): We don't know which network host should get the ip
@@ -61,6 +64,9 @@ class API(base.Base):
affect_auto_assigned=False):
"""Removes floating ip with address from a project."""
floating_ip = self.db.floating_ip_get_by_address(context, address)
+ if floating_ip['fixed_ip']:
+ raise exception.ApiError(_('Floating ip is in use. '
+ 'Disassociate it before releasing.'))
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
# NOTE(vish): We don't know which network host should get the ip
@@ -105,7 +111,11 @@ class API(base.Base):
'(%(project)s)') %
{'address': floating_ip['address'],
'project': context.project_id})
- host = fixed_ip['network']['host']
+ # NOTE(vish): if we are multi_host, send to the instances host
+ if fixed_ip['network']['multi_host']:
+ host = fixed_ip['instance']['host']
+ else:
+ host = fixed_ip['network']['host']
rpc.cast(context,
self.db.queue_get_for(context, FLAGS.network_topic, host),
{'method': 'associate_floating_ip',
@@ -120,7 +130,11 @@ class API(base.Base):
return
if not floating_ip.get('fixed_ip'):
raise exception.ApiError('Address is not associated.')
- host = floating_ip['fixed_ip']['network']['host']
+ # NOTE(vish): if we are multi_host, send to the instances host
+ if floating_ip['fixed_ip']['network']['multi_host']:
+ host = floating_ip['fixed_ip']['instance']['host']
+ else:
+ host = floating_ip['fixed_ip']['network']['host']
rpc.call(context,
self.db.queue_get_for(context, FLAGS.network_topic, host),
{'method': 'disassociate_floating_ip',
@@ -134,7 +148,9 @@ class API(base.Base):
args = kwargs
args['instance_id'] = instance['id']
args['project_id'] = instance['project_id']
+ args['host'] = instance['host']
args['instance_type_id'] = instance['instance_type_id']
+
return rpc.call(context, FLAGS.network_topic,
{'method': 'allocate_for_instance',
'args': args})
@@ -148,9 +164,10 @@ class API(base.Base):
{'method': 'deallocate_for_instance',
'args': args})
- def add_fixed_ip_to_instance(self, context, instance_id, network_id):
+ def add_fixed_ip_to_instance(self, context, instance_id, host, network_id):
"""Adds a fixed ip to instance from specified network."""
args = {'instance_id': instance_id,
+ 'host': host,
'network_id': network_id}
rpc.cast(context, FLAGS.network_topic,
{'method': 'add_fixed_ip_to_instance',
@@ -173,7 +190,8 @@ class API(base.Base):
def get_instance_nw_info(self, context, instance):
"""Returns all network info related to an instance."""
args = {'instance_id': instance['id'],
- 'instance_type_id': instance['instance_type_id']}
+ 'instance_type_id': instance['instance_type_id'],
+ 'host': instance['host']}
return rpc.call(context, FLAGS.network_topic,
{'method': 'get_instance_nw_info',
'args': args})
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 283a5aca1..8ace07884 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -455,6 +455,7 @@ def ensure_vlan_bridge(vlan_num, bridge, bridge_interface, net_attrs=None):
"""Create a vlan and bridge unless they already exist."""
interface = ensure_vlan(vlan_num, bridge_interface)
ensure_bridge(bridge, interface, net_attrs)
+ return interface
@utils.synchronized('ensure_vlan', external=True)
@@ -497,7 +498,7 @@ def ensure_bridge(bridge, interface, net_attrs=None):
suffix = net_attrs['cidr'].rpartition('/')[2]
out, err = _execute('sudo', 'ip', 'addr', 'add',
'%s/%s' %
- (net_attrs['gateway'], suffix),
+ (net_attrs['dhcp_server'], suffix),
'brd',
net_attrs['broadcast'],
'dev',
@@ -551,21 +552,27 @@ def ensure_bridge(bridge, interface, net_attrs=None):
bridge)
-def get_dhcp_leases(context, network_id):
+def get_dhcp_leases(context, network_ref):
"""Return a network's hosts config in dnsmasq leasefile format."""
hosts = []
- for fixed_ip_ref in db.network_get_associated_fixed_ips(context,
- network_id):
- hosts.append(_host_lease(fixed_ip_ref))
+ for fixed_ref in db.network_get_associated_fixed_ips(context,
+ network_ref['id']):
+ host = fixed_ref['instance']['host']
+ if network_ref['multi_host'] and FLAGS.host != host:
+ continue
+ hosts.append(_host_lease(fixed_ref))
return '\n'.join(hosts)
-def get_dhcp_hosts(context, network_id):
+def get_dhcp_hosts(context, network_ref):
"""Get network's hosts config in dhcp-host format."""
hosts = []
- for fixed_ip_ref in db.network_get_associated_fixed_ips(context,
- network_id):
- hosts.append(_host_dhcp(fixed_ip_ref))
+ for fixed_ref in db.network_get_associated_fixed_ips(context,
+ network_ref['id']):
+ host = fixed_ref['instance']['host']
+ if network_ref['multi_host'] and FLAGS.host != host:
+ continue
+ hosts.append(_host_dhcp(fixed_ref))
return '\n'.join(hosts)
@@ -573,18 +580,16 @@ def get_dhcp_hosts(context, network_id):
# configuration options (like dchp-range, vlan, ...)
# aren't reloaded.
@utils.synchronized('dnsmasq_start')
-def update_dhcp(context, network_id):
+def update_dhcp(context, network_ref):
"""(Re)starts a dnsmasq server for a given network.
If a dnsmasq instance is already running then send a HUP
signal causing it to reload, otherwise spawn a new instance.
"""
- network_ref = db.network_get(context, network_id)
-
conffile = _dhcp_file(network_ref['bridge'], 'conf')
with open(conffile, 'w') as f:
- f.write(get_dhcp_hosts(context, network_id))
+ f.write(get_dhcp_hosts(context, network_ref))
# Make sure dnsmasq can actually read it (it setuid()s to "nobody")
os.chmod(conffile, 0644)
@@ -612,9 +617,7 @@ def update_dhcp(context, network_id):
@utils.synchronized('radvd_start')
-def update_ra(context, network_id):
- network_ref = db.network_get(context, network_id)
-
+def update_ra(context, network_ref):
conffile = _ra_file(network_ref['bridge'], 'conf')
with open(conffile, 'w') as f:
conf_str = """
@@ -650,9 +653,6 @@ interface %s
LOG.debug(_('Pid %d is stale, relaunching radvd'), pid)
command = _ra_cmd(network_ref)
_execute(*command)
- db.network_update(context, network_id,
- {'gateway_v6':
- utils.get_my_linklocal(network_ref['bridge'])})
def _host_lease(fixed_ip_ref):
@@ -701,10 +701,11 @@ def _dnsmasq_cmd(net):
cmd = ['sudo', '-E', 'dnsmasq',
'--strict-order',
'--bind-interfaces',
+ '--interface=%s' % net['bridge'],
'--conf-file=%s' % FLAGS.dnsmasq_config_file,
'--domain=%s' % FLAGS.dhcp_domain,
'--pid-file=%s' % _dhcp_file(net['bridge'], 'pid'),
- '--listen-address=%s' % net['gateway'],
+ '--listen-address=%s' % net['dhcp_server'],
'--except-interface=lo',
'--dhcp-range=%s,static,120s' % net['dhcp_start'],
'--dhcp-lease-max=%s' % len(netaddr.IPNetwork(net['cidr'])),
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 24736f53d..8fc6a295f 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -28,7 +28,6 @@ topologies. All of the network commands are issued to a subclass of
:flat_network_bridge: Bridge device for simple network instances
:flat_interface: FlatDhcp will bridge into this interface if set
:flat_network_dns: Dns for simple network
-:flat_network_dhcp_start: Dhcp start for FlatDhcp
:vlan_start: First VLAN for private networks
:vpn_ip: Public IP for the cloudpipe VPN servers
:vpn_start: First Vpn port for private networks
@@ -49,7 +48,6 @@ import datetime
import math
import netaddr
import socket
-import pickle
from eventlet import greenpool
from nova import context
@@ -70,7 +68,7 @@ LOG = logging.getLogger("nova.network.manager")
FLAGS = flags.FLAGS
-flags.DEFINE_string('flat_network_bridge', 'br100',
+flags.DEFINE_string('flat_network_bridge', None,
'Bridge for simple network instances')
flags.DEFINE_string('flat_network_dns', '8.8.4.4',
'Dns for simple network')
@@ -78,8 +76,6 @@ flags.DEFINE_bool('flat_injected', True,
'Whether to attempt to inject network setup into guest')
flags.DEFINE_string('flat_interface', None,
'FlatDhcp will bridge into this interface if set')
-flags.DEFINE_string('flat_network_dhcp_start', '10.0.0.2',
- 'Dhcp start for FlatDhcp')
flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks')
flags.DEFINE_string('vlan_interface', None,
'vlans will bridge into this interface if set')
@@ -87,6 +83,8 @@ flags.DEFINE_integer('num_networks', 1, 'Number of networks to support')
flags.DEFINE_string('vpn_ip', '$my_ip',
'Public IP for the cloudpipe VPN servers')
flags.DEFINE_integer('vpn_start', 1000, 'First Vpn port for private networks')
+flags.DEFINE_bool('multi_host', False,
+ 'Default value for multi_host in networks')
flags.DEFINE_integer('network_size', 256,
'Number of addresses in each private subnet')
flags.DEFINE_string('floating_range', '4.4.4.0/24',
@@ -104,7 +102,8 @@ flags.DEFINE_integer('fixed_ip_disassociate_timeout', 600,
'Seconds after which a deallocated ip is disassociated')
flags.DEFINE_integer('create_unique_mac_address_attempts', 5,
'Number of attempts to create unique mac address')
-
+flags.DEFINE_bool('auto_assign_floating_ip', False,
+ 'Autoassigning floating ip to VM')
flags.DEFINE_bool('use_ipv6', False,
'use the ipv6')
flags.DEFINE_string('network_host', socket.gethostname(),
@@ -124,16 +123,26 @@ class RPCAllocateFixedIP(object):
used since they share code to RPC.call allocate_fixed_ip on the
correct network host to configure dnsmasq
"""
- def _allocate_fixed_ips(self, context, instance_id, networks, **kwargs):
+ def _allocate_fixed_ips(self, context, instance_id, host, networks,
+ **kwargs):
"""Calls allocate_fixed_ip once for each network."""
green_pool = greenpool.GreenPool()
vpn = kwargs.pop('vpn')
for network in networks:
- if network['host'] != self.host:
+ # NOTE(vish): if we are not multi_host pass to the network host
+ if not network['multi_host']:
+ host = network['host']
+ # NOTE(vish): if there is no network host, set one
+ if host == None:
+ host = rpc.call(context, FLAGS.network_topic,
+ {'method': 'set_network_host',
+ 'args': {'network_ref': network}})
+ if host != self.host:
# need to call allocate_fixed_ip to correct network host
- topic = self.db.queue_get_for(context, FLAGS.network_topic,
- network['host'])
+ topic = self.db.queue_get_for(context,
+ FLAGS.network_topic,
+ host)
args = {}
args['instance_id'] = instance_id
args['network_id'] = network['id']
@@ -149,12 +158,13 @@ class RPCAllocateFixedIP(object):
# wait for all of the allocates (if any) to finish
green_pool.waitall()
- def _rpc_allocate_fixed_ip(self, context, instance_id, network_id):
+ def _rpc_allocate_fixed_ip(self, context, instance_id, network_id,
+ **kwargs):
"""Sits in between _allocate_fixed_ips and allocate_fixed_ip to
perform network lookup on the far side of rpc.
"""
network = self.db.network_get(context, network_id)
- self.allocate_fixed_ip(context, instance_id, network)
+ self.allocate_fixed_ip(context, instance_id, network, **kwargs)
class FloatingIP(object):
@@ -193,7 +203,7 @@ class FloatingIP(object):
# which is currently the NetworkManager version
# do this first so fixed ip is already allocated
ips = super(FloatingIP, self).allocate_for_instance(context, **kwargs)
- if hasattr(FLAGS, 'auto_assign_floating_ip'):
+ if FLAGS.auto_assign_floating_ip:
# allocate a floating ip (public_ip is just the address string)
public_ip = self.allocate_floating_ip(context, project_id)
# set auto_assigned column to true for the floating ip
@@ -248,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 '
@@ -290,6 +300,12 @@ class NetworkManager(manager.SchedulerDependentManager):
The one at a time part is to flatten the layout to help scale
"""
+ # If True, this manager requires VIF to create a bridge.
+ SHOULD_CREATE_BRIDGE = False
+
+ # If True, this manager requires VIF to create VLAN tag.
+ SHOULD_CREATE_VLAN = False
+
timeout_fixed_ips = True
def __init__(self, network_driver=None, *args, **kwargs):
@@ -300,15 +316,36 @@ class NetworkManager(manager.SchedulerDependentManager):
super(NetworkManager, self).__init__(service_name='network',
*args, **kwargs)
+ @utils.synchronized('get_dhcp')
+ def _get_dhcp_ip(self, context, network_ref, host=None):
+ """Get the proper dhcp address to listen on."""
+ # NOTE(vish): this is for compatibility
+ if not network_ref['multi_host']:
+ return network_ref['gateway']
+
+ if not host:
+ host = self.host
+ network_id = network_ref['id']
+ try:
+ fip = self.db.fixed_ip_get_by_network_host(context,
+ network_id,
+ host)
+ return fip['address']
+ except exception.FixedIpNotFoundForNetworkHost:
+ elevated = context.elevated()
+ return self.db.fixed_ip_associate_pool(elevated,
+ network_id,
+ host=host)
+
def init_host(self):
"""Do any initialization that needs to be run if this is a
standalone service.
"""
- # Set up this host for networks in which it's already
- # the designated network host.
+ # NOTE(vish): Set up networks for which this host already has
+ # an ip address.
ctxt = context.get_admin_context()
for network in self.db.network_get_all_by_host(ctxt, self.host):
- self._on_set_network_host(ctxt, network['id'])
+ self._setup_network(ctxt, network)
def periodic_tasks(self, context=None):
"""Tasks to be run at a periodic interval."""
@@ -323,33 +360,14 @@ class NetworkManager(manager.SchedulerDependentManager):
if num:
LOG.debug(_('Dissassociated %s stale fixed ip(s)'), num)
- # setup any new networks which have been created
- self.set_network_hosts(context)
-
- def set_network_host(self, context, network_id):
+ def set_network_host(self, context, network_ref):
"""Safely sets the host of the network."""
LOG.debug(_('setting network host'), context=context)
host = self.db.network_set_host(context,
- network_id,
+ network_ref['id'],
self.host)
- if host == self.host:
- self._on_set_network_host(context, network_id)
return host
- def set_network_hosts(self, context):
- """Set the network hosts for any networks which are unset."""
- try:
- networks = self.db.network_get_all(context)
- except exception.NoNetworksFound:
- # we don't care if no networks are found
- pass
-
- for network in networks:
- host = network['host']
- if not host:
- # return so worker will only grab 1 (to help scale flatter)
- return self.set_network_host(context, network['id'])
-
def _get_networks_for_instance(self, context, instance_id, project_id):
"""Determine & return which networks an instance should connect to."""
# TODO(tr3buchet) maybe this needs to be updated in the future if
@@ -358,12 +376,11 @@ class NetworkManager(manager.SchedulerDependentManager):
try:
networks = self.db.network_get_all(context)
except exception.NoNetworksFound:
- # we don't care if no networks are found
- pass
+ return []
- # return only networks which are not vlan networks and have host set
+ # return only networks which are not vlan networks
return [network for network in networks if
- not network['vlan'] and network['host']]
+ not network['vlan']]
def allocate_for_instance(self, context, **kwargs):
"""Handles allocating the various network resources for an instance.
@@ -371,6 +388,7 @@ class NetworkManager(manager.SchedulerDependentManager):
rpc.called by network_api
"""
instance_id = kwargs.pop('instance_id')
+ host = kwargs.pop('host')
project_id = kwargs.pop('project_id')
type_id = kwargs.pop('instance_type_id')
vpn = kwargs.pop('vpn')
@@ -379,9 +397,11 @@ class NetworkManager(manager.SchedulerDependentManager):
context=context)
networks = self._get_networks_for_instance(admin_context, instance_id,
project_id)
+ LOG.warn(networks)
self._allocate_mac_addresses(context, instance_id, networks)
- self._allocate_fixed_ips(admin_context, instance_id, networks, vpn=vpn)
- return self.get_instance_nw_info(context, instance_id, type_id)
+ self._allocate_fixed_ips(admin_context, instance_id, host, networks,
+ vpn=vpn)
+ return self.get_instance_nw_info(context, instance_id, type_id, host)
def deallocate_for_instance(self, context, **kwargs):
"""Handles deallocating various network resources for an instance.
@@ -390,8 +410,11 @@ class NetworkManager(manager.SchedulerDependentManager):
kwargs can contain fixed_ips to circumvent another db lookup
"""
instance_id = kwargs.pop('instance_id')
- fixed_ips = kwargs.get('fixed_ips') or \
+ try:
+ fixed_ips = kwargs.get('fixed_ips') or \
self.db.fixed_ip_get_by_instance(context, instance_id)
+ except exceptions.FixedIpNotFoundForInstance:
+ fixed_ips = []
LOG.debug(_("network deallocation for instance |%s|"), instance_id,
context=context)
# deallocate fixed ips
@@ -401,7 +424,8 @@ class NetworkManager(manager.SchedulerDependentManager):
# deallocate vifs (mac addresses)
self.db.virtual_interface_delete_by_instance(context, instance_id)
- def get_instance_nw_info(self, context, instance_id, instance_type_id):
+ def get_instance_nw_info(self, context, instance_id,
+ instance_type_id, host):
"""Creates network info list for instance.
called by allocate_for_instance and netowrk_api
@@ -411,10 +435,14 @@ class NetworkManager(manager.SchedulerDependentManager):
and info = dict containing pertinent networking data
"""
# TODO(tr3buchet) should handle floating IPs as well?
- fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
+ try:
+ fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
+ except exception.FixedIpNotFoundForInstance:
+ LOG.warn(_('No fixed IPs for instance %s'), instance_id)
+ fixed_ips = []
+
vifs = self.db.virtual_interface_get_by_instance(context, instance_id)
- flavor = self.db.instance_type_get_by_id(context,
- instance_type_id)
+ flavor = self.db.instance_type_get(context, instance_type_id)
network_info = []
# a vif has an address, instance_id, and network_id
# it is also joined to the instance and network given by those IDs
@@ -444,20 +472,38 @@ class NetworkManager(manager.SchedulerDependentManager):
'id': network['id'],
'cidr': network['cidr'],
'cidr_v6': network['cidr_v6'],
- 'injected': network['injected']}
+ 'injected': network['injected'],
+ 'vlan': network['vlan'],
+ 'bridge_interface': network['bridge_interface'],
+ 'multi_host': network['multi_host']}
+ if network['multi_host']:
+ dhcp_server = self._get_dhcp_ip(context, network, host)
+ else:
+ dhcp_server = self._get_dhcp_ip(context,
+ network,
+ network['host'])
info = {
'label': network['label'],
'gateway': network['gateway'],
+ 'dhcp_server': dhcp_server,
'broadcast': network['broadcast'],
'mac': vif['address'],
'rxtx_cap': flavor['rxtx_cap'],
- 'dns': [network['dns']],
- 'ips': [ip_dict(ip) for ip in network_IPs]}
+ 'dns': [],
+ 'ips': [ip_dict(ip) for ip in network_IPs],
+ 'should_create_bridge': self.SHOULD_CREATE_BRIDGE,
+ 'should_create_vlan': self.SHOULD_CREATE_VLAN}
+
if network['cidr_v6']:
info['ip6s'] = [ip6_dict()]
# TODO(tr3buchet): handle ip6 routes here as well
if network['gateway_v6']:
info['gateway6'] = network['gateway_v6']
+ if network['dns1']:
+ info['dns'].append(network['dns1'])
+ if network['dns2']:
+ info['dns'].append(network['dns2'])
+
network_info.append((network_dict, info))
return network_info
@@ -487,10 +533,10 @@ class NetworkManager(manager.SchedulerDependentManager):
random.randint(0x00, 0xff)]
return ':'.join(map(lambda x: "%02x" % x, mac))
- def add_fixed_ip_to_instance(self, context, instance_id, network_id):
+ def add_fixed_ip_to_instance(self, context, instance_id, host, network_id):
"""Adds a fixed ip to an instance from specified network."""
networks = [self.db.network_get(context, network_id)]
- self._allocate_fixed_ips(context, instance_id, networks)
+ self._allocate_fixed_ips(context, instance_id, host, networks)
def remove_fixed_ip_from_instance(self, context, instance_id, address):
"""Removes a fixed ip from an instance from specified network."""
@@ -508,15 +554,18 @@ class NetworkManager(manager.SchedulerDependentManager):
# with a network, or a cluster of computes with a network
# and use that network here with a method like
# network_get_by_compute_host
- address = self.db.fixed_ip_associate_pool(context.elevated(),
- network['id'],
- instance_id)
- vif = self.db.virtual_interface_get_by_instance_and_network(context,
- instance_id,
- network['id'])
- values = {'allocated': True,
- 'virtual_interface_id': vif['id']}
- self.db.fixed_ip_update(context, address, values)
+ address = None
+ if network['cidr']:
+ address = self.db.fixed_ip_associate_pool(context.elevated(),
+ network['id'],
+ instance_id)
+ get_vif = self.db.virtual_interface_get_by_instance_and_network
+ vif = get_vif(context, instance_id, network['id'])
+ values = {'allocated': True,
+ 'virtual_interface_id': vif['id']}
+ self.db.fixed_ip_update(context, address, values)
+
+ self._setup_network(context, network)
return address
def deallocate_fixed_ip(self, context, address, **kwargs):
@@ -562,38 +611,47 @@ class NetworkManager(manager.SchedulerDependentManager):
# means there will stale entries in the conf file
# the code below will update the file if necessary
if FLAGS.update_dhcp_on_disassociate:
- network = self.db.fixed_ip_get_network(context, address)
- self.driver.update_dhcp(context, network['id'])
+ network_ref = self.db.fixed_ip_get_network(context, address)
+ self._setup_network(context, network_ref)
- def create_networks(self, context, label, cidr, num_networks,
+ def create_networks(self, context, label, cidr, multi_host, num_networks,
network_size, cidr_v6, gateway_v6, bridge,
- bridge_interface, **kwargs):
+ bridge_interface, dns1=None, dns2=None, **kwargs):
"""Create networks based on parameters."""
- fixed_net = netaddr.IPNetwork(cidr)
- fixed_net_v6 = netaddr.IPNetwork(cidr_v6)
- significant_bits_v6 = 64
- network_size_v6 = 1 << 64
- for index in range(num_networks):
- start = index * network_size
- start_v6 = index * network_size_v6
+ if cidr_v6:
+ fixed_net_v6 = netaddr.IPNetwork(cidr_v6)
+ significant_bits_v6 = 64
+ network_size_v6 = 1 << 64
+
+ if cidr:
+ fixed_net = netaddr.IPNetwork(cidr)
significant_bits = 32 - int(math.log(network_size, 2))
- cidr = '%s/%s' % (fixed_net[start], significant_bits)
- project_net = netaddr.IPNetwork(cidr)
+
+ for index in range(num_networks):
net = {}
net['bridge'] = bridge
net['bridge_interface'] = bridge_interface
- net['dns'] = FLAGS.flat_network_dns
- net['cidr'] = cidr
- net['netmask'] = str(project_net.netmask)
- net['gateway'] = str(project_net[1])
- net['broadcast'] = str(project_net.broadcast)
- net['dhcp_start'] = str(project_net[2])
+ net['dns1'] = dns1
+ net['dns2'] = dns2
+
+ if cidr:
+ start = index * network_size
+ project_net = netaddr.IPNetwork('%s/%s' % (fixed_net[start],
+ significant_bits))
+ net['cidr'] = str(project_net)
+ net['multi_host'] = multi_host
+ net['netmask'] = str(project_net.netmask)
+ net['gateway'] = str(project_net[1])
+ net['broadcast'] = str(project_net.broadcast)
+ net['dhcp_start'] = str(project_net[2])
+
if num_networks > 1:
net['label'] = '%s_%d' % (label, index)
else:
net['label'] = label
- if FLAGS.use_ipv6:
+ if cidr_v6:
+ start_v6 = index * network_size_v6
cidr_v6 = '%s/%s' % (fixed_net_v6[start_v6],
significant_bits_v6)
net['cidr_v6'] = cidr_v6
@@ -610,7 +668,8 @@ class NetworkManager(manager.SchedulerDependentManager):
if kwargs.get('vpn', False):
# this bit here is for vlan-manager
- del net['dns']
+ del net['dns1']
+ del net['dns2']
vlan = kwargs['vlan_start'] + index
net['vpn_private_address'] = str(project_net[2])
net['dhcp_start'] = str(project_net[3])
@@ -624,11 +683,11 @@ class NetworkManager(manager.SchedulerDependentManager):
# None if network with cidr or cidr_v6 already exists
network = self.db.network_create_safe(context, net)
- if network:
+ if not network:
+ raise ValueError(_('Network already exists!'))
+
+ if network and cidr:
self._create_fixed_ips(context, network['id'])
- else:
- raise ValueError(_('Network with cidr %s already exists') %
- cidr)
@property
def _bottom_reserved_ips(self): # pylint: disable=R0201
@@ -659,20 +718,13 @@ class NetworkManager(manager.SchedulerDependentManager):
'address': address,
'reserved': reserved})
- def _allocate_fixed_ips(self, context, instance_id, networks, **kwargs):
+ def _allocate_fixed_ips(self, context, instance_id, host, networks,
+ **kwargs):
"""Calls allocate_fixed_ip once for each network."""
raise NotImplementedError()
- def _on_set_network_host(self, context, network_id):
- """Called when this host becomes the host for a network."""
- raise NotImplementedError()
-
- def setup_compute_network(self, context, instance_id):
- """Sets up matching network for compute hosts.
-
- this code is run on and by the compute host, not on network
- hosts
- """
+ def _setup_network(self, context, network_ref):
+ """Sets up network on this host."""
raise NotImplementedError()
@@ -680,9 +732,9 @@ class FlatManager(NetworkManager):
"""Basic network where no vlans are used.
FlatManager does not do any bridge or vlan creation. The user is
- responsible for setting up whatever bridge is specified in
- flat_network_bridge (br100 by default). This bridge needs to be created
- on all compute hosts.
+ responsible for setting up whatever bridges are specified when creating
+ networks through nova-manage. This bridge needs to be created on all
+ compute hosts.
The idea is to create a single network for the host with a command like:
nova-manage network create 192.168.0.0/24 1 256. Creating multiple
@@ -706,7 +758,8 @@ class FlatManager(NetworkManager):
timeout_fixed_ips = False
- def _allocate_fixed_ips(self, context, instance_id, networks, **kwargs):
+ def _allocate_fixed_ips(self, context, instance_id, host, networks,
+ **kwargs):
"""Calls allocate_fixed_ip once for each network."""
for network in networks:
self.allocate_fixed_ip(context, instance_id, network)
@@ -717,19 +770,11 @@ class FlatManager(NetworkManager):
**kwargs)
self.db.fixed_ip_disassociate(context, address)
- def setup_compute_network(self, context, instance_id):
- """Network is created manually.
-
- this code is run on and by the compute host, not on network hosts
- """
- pass
-
- def _on_set_network_host(self, context, network_id):
- """Called when this host becomes the host for a network."""
+ def _setup_network(self, context, network_ref):
+ """Setup Network on this host."""
net = {}
net['injected'] = FLAGS.flat_injected
- net['dns'] = FLAGS.flat_network_dns
- self.db.network_update(context, network_id, net)
+ self.db.network_update(context, network_ref['id'], net)
class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager):
@@ -741,6 +786,8 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager):
"""
+ SHOULD_CREATE_BRIDGE = True
+
def init_host(self):
"""Do any initialization that needs to be run if this is a
standalone service.
@@ -753,37 +800,19 @@ class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager):
self.driver.metadata_forward()
- def setup_compute_network(self, context, instance_id):
- """Sets up matching networks for compute hosts.
-
- this code is run on and by the compute host, not on network hosts
- """
- networks = db.network_get_all_by_instance(context, instance_id)
- for network in networks:
- self.driver.ensure_bridge(network['bridge'],
- network['bridge_interface'])
-
- def allocate_fixed_ip(self, context, instance_id, network, **kwargs):
- """Allocate flat_network fixed_ip, then setup dhcp for this network."""
- address = super(FlatDHCPManager, self).allocate_fixed_ip(context,
- instance_id,
- network)
- if not FLAGS.fake_network:
- self.driver.update_dhcp(context, network['id'])
-
- def _on_set_network_host(self, context, network_id):
- """Called when this host becomes the host for a project."""
- net = {}
- net['dhcp_start'] = FLAGS.flat_network_dhcp_start
- self.db.network_update(context, network_id, net)
- network = db.network_get(context, network_id)
- self.driver.ensure_bridge(network['bridge'],
- network['bridge_interface'],
- network)
+ def _setup_network(self, context, network_ref):
+ """Sets up network on this host."""
+ network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref)
+ self.driver.ensure_bridge(network_ref['bridge'],
+ network_ref['bridge_interface'],
+ network_ref)
if not FLAGS.fake_network:
- self.driver.update_dhcp(context, network_id)
+ self.driver.update_dhcp(context, network_ref)
if(FLAGS.use_ipv6):
- self.driver.update_ra(context, network_id)
+ self.driver.update_ra(context, network_ref)
+ gateway = utils.get_my_linklocal(network_ref['bridge'])
+ self.db.network_update(context, network_ref['id'],
+ {'gateway_v6': gateway})
class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
@@ -801,6 +830,9 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
"""
+ SHOULD_CREATE_BRIDGE = True
+ SHOULD_CREATE_VLAN = True
+
def init_host(self):
"""Do any initialization that needs to be run if this is a
standalone service.
@@ -832,30 +864,17 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
values = {'allocated': True,
'virtual_interface_id': vif['id']}
self.db.fixed_ip_update(context, address, values)
- if not FLAGS.fake_network:
- self.driver.update_dhcp(context, network['id'])
+ self._setup_network(context, network)
+ return address
def add_network_to_project(self, context, project_id):
"""Force adds another network to a project."""
self.db.network_associate(context, project_id, force=True)
- def setup_compute_network(self, context, instance_id):
- """Sets up matching network for compute hosts.
- this code is run on and by the compute host, not on network hosts
- """
- networks = self.db.network_get_all_by_instance(context, instance_id)
- for network in networks:
- self.driver.ensure_vlan_bridge(network['vlan'],
- network['bridge'],
- network['bridge_interface'])
-
def _get_networks_for_instance(self, context, instance_id, project_id):
"""Determine which networks an instance should connect to."""
# get networks associated with project
- networks = self.db.project_get_networks(context, project_id)
-
- # return only networks which have host set
- return [network for network in networks if network['host']]
+ return self.db.project_get_networks(context, project_id)
def create_networks(self, context, **kwargs):
"""Create networks based on parameters."""
@@ -874,32 +893,35 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
NetworkManager.create_networks(self, context, vpn=True, **kwargs)
- def _on_set_network_host(self, context, network_id):
- """Called when this host becomes the host for a network."""
- network = self.db.network_get(context, network_id)
- if not network['vpn_public_address']:
+ def _setup_network(self, context, network_ref):
+ """Sets up network on this host."""
+ if not network_ref['vpn_public_address']:
net = {}
address = FLAGS.vpn_ip
net['vpn_public_address'] = address
- db.network_update(context, network_id, net)
+ network_ref = db.network_update(context, network_ref['id'], net)
else:
- address = network['vpn_public_address']
- self.driver.ensure_vlan_bridge(network['vlan'],
- network['bridge'],
- network['bridge_interface'],
- network)
+ address = network_ref['vpn_public_address']
+ network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref)
+ self.driver.ensure_vlan_bridge(network_ref['vlan'],
+ network_ref['bridge'],
+ network_ref['bridge_interface'],
+ network_ref)
# NOTE(vish): only ensure this forward if the address hasn't been set
# manually.
if address == FLAGS.vpn_ip and hasattr(self.driver,
"ensure_vlan_forward"):
self.driver.ensure_vlan_forward(FLAGS.vpn_ip,
- network['vpn_public_port'],
- network['vpn_private_address'])
+ network_ref['vpn_public_port'],
+ network_ref['vpn_private_address'])
if not FLAGS.fake_network:
- self.driver.update_dhcp(context, network_id)
+ self.driver.update_dhcp(context, network_ref)
if(FLAGS.use_ipv6):
- self.driver.update_ra(context, network_id)
+ self.driver.update_ra(context, network_ref)
+ gateway = utils.get_my_linklocal(network_ref['bridge'])
+ self.db.network_update(context, network_ref['id'],
+ {'gateway_v6': gateway})
@property
def _bottom_reserved_ips(self):
diff --git a/nova/network/vmwareapi_net.py b/nova/network/vmwareapi_net.py
deleted file mode 100644
index b32cf3303..000000000
--- a/nova/network/vmwareapi_net.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright (c) 2011 Citrix Systems, Inc.
-# Copyright 2011 OpenStack LLC.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""Implements vlans for vmwareapi."""
-
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import utils
-from nova.virt.vmwareapi_conn import VMWareAPISession
-from nova.virt.vmwareapi import network_utils
-
-
-LOG = logging.getLogger("nova.network.vmwareapi_net")
-
-
-FLAGS = flags.FLAGS
-FLAGS['vlan_interface'].SetDefault('vmnic0')
-
-
-def ensure_vlan_bridge(vlan_num, bridge, bridge_interface, net_attrs=None):
- """Create a vlan and bridge unless they already exist."""
- # Open vmwareapi session
- host_ip = FLAGS.vmwareapi_host_ip
- host_username = FLAGS.vmwareapi_host_username
- host_password = FLAGS.vmwareapi_host_password
- if not host_ip or host_username is None or host_password is None:
- raise Exception(_('Must specify vmwareapi_host_ip, '
- 'vmwareapi_host_username '
- 'and vmwareapi_host_password to use '
- 'connection_type=vmwareapi'))
- session = VMWareAPISession(host_ip, host_username, host_password,
- FLAGS.vmwareapi_api_retry_count)
- vlan_interface = bridge_interface
- # Check if the vlan_interface physical network adapter exists on the host
- if not network_utils.check_if_vlan_interface_exists(session,
- vlan_interface):
- raise exception.NetworkAdapterNotFound(adapter=vlan_interface)
-
- # Get the vSwitch associated with the Physical Adapter
- vswitch_associated = network_utils.get_vswitch_for_vlan_interface(
- session, vlan_interface)
- if vswitch_associated is None:
- raise exception.SwicthNotFoundForNetworkAdapter(adapter=vlan_interface)
- # Check whether bridge already exists and retrieve the the ref of the
- # network whose name_label is "bridge"
- network_ref = network_utils.get_network_with_the_name(session, bridge)
- if network_ref is None:
- # Create a port group on the vSwitch associated with the vlan_interface
- # corresponding physical network adapter on the ESX host
- network_utils.create_port_group(session, bridge, vswitch_associated,
- vlan_num)
- else:
- # Get the vlan id and vswitch corresponding to the port group
- pg_vlanid, pg_vswitch = \
- network_utils.get_vlanid_and_vswitch_for_portgroup(session, bridge)
-
- # Check if the vswitch associated is proper
- if pg_vswitch != vswitch_associated:
- raise exception.InvalidVLANPortGroup(bridge=bridge,
- expected=vswitch_associated,
- actual=pg_vswitch)
-
- # Check if the vlan id is proper for the port group
- if pg_vlanid != vlan_num:
- raise exception.InvalidVLANTag(bridge=bridge, tag=vlan_num,
- pgroup=pg_vlanid)
diff --git a/nova/network/xenapi_net.py b/nova/network/xenapi_net.py
deleted file mode 100644
index e86f4017d..000000000
--- a/nova/network/xenapi_net.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright (c) 2011 Citrix Systems, Inc.
-# Copyright 2011 OpenStack LLC.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""Implements vlans, bridges, and iptables rules using linux utilities."""
-
-import os
-
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import utils
-from nova.virt import xenapi_conn
-from nova.virt.xenapi import network_utils
-
-
-LOG = logging.getLogger("nova.xenapi_net")
-
-
-FLAGS = flags.FLAGS
-
-
-def ensure_vlan_bridge(vlan_num, bridge, bridge_interface, net_attrs=None):
- """Create a vlan and bridge unless they already exist."""
- # Open xenapi session
- LOG.debug('ENTERING ensure_vlan_bridge in xenapi net')
- url = FLAGS.xenapi_connection_url
- username = FLAGS.xenapi_connection_username
- password = FLAGS.xenapi_connection_password
- session = xenapi_conn.XenAPISession(url, username, password)
- # Check whether bridge already exists
- # Retrieve network whose name_label is "bridge"
- network_ref = network_utils.NetworkHelper.find_network_with_name_label(
- session,
- bridge)
- if network_ref is None:
- # If bridge does not exists
- # 1 - create network
- description = 'network for nova bridge %s' % bridge
- network_rec = {'name_label': bridge,
- 'name_description': description,
- 'other_config': {}}
- network_ref = session.call_xenapi('network.create', network_rec)
- # 2 - find PIF for VLAN
- # NOTE(salvatore-orlando): using double quotes inside single quotes
- # as xapi filter only support tokens in double quotes
- expr = 'field "device" = "%s" and \
- field "VLAN" = "-1"' % bridge_interface
- pifs = session.call_xenapi('PIF.get_all_records_where', expr)
- pif_ref = None
- # Multiple PIF are ok: we are dealing with a pool
- if len(pifs) == 0:
- raise Exception(
- _('Found no PIF for device %s') % bridge_interface)
- # 3 - create vlan for network
- for pif_ref in pifs.keys():
- session.call_xenapi('VLAN.create',
- pif_ref,
- str(vlan_num),
- network_ref)
- else:
- # Check VLAN tag is appropriate
- network_rec = session.call_xenapi('network.get_record', network_ref)
- # Retrieve PIFs from network
- for pif_ref in network_rec['PIFs']:
- # Retrieve VLAN from PIF
- pif_rec = session.call_xenapi('PIF.get_record', pif_ref)
- pif_vlan = int(pif_rec['VLAN'])
- # Raise an exception if VLAN != vlan_num
- if pif_vlan != vlan_num:
- raise Exception(_("PIF %(pif_rec['uuid'])s for network "
- "%(bridge)s has VLAN id %(pif_vlan)d. "
- "Expected %(vlan_num)d") % locals())
diff --git a/nova/notifier/api.py b/nova/notifier/api.py
index 98969fd3e..e18f3e280 100644
--- a/nova/notifier/api.py
+++ b/nova/notifier/api.py
@@ -80,6 +80,10 @@ def notify(publisher_id, event_type, priority, payload):
if priority not in log_levels:
raise BadPriorityException(
_('%s not in valid priorities' % priority))
+
+ # Ensure everything is JSON serializable.
+ payload = utils.to_primitive(payload, convert_instances=True)
+
driver = utils.import_object(FLAGS.notification_driver)
msg = dict(message_id=str(uuid.uuid4()),
publisher_id=publisher_id,
diff --git a/nova/rpc/__init__.py b/nova/rpc/__init__.py
new file mode 100644
index 000000000..bdf7f705b
--- /dev/null
+++ b/nova/rpc/__init__.py
@@ -0,0 +1,66 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from nova.utils import import_object
+from nova.rpc.common import RemoteError, LOG
+from nova import flags
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('rpc_backend',
+ 'nova.rpc.amqp',
+ "The messaging module to use, defaults to AMQP.")
+
+RPCIMPL = import_object(FLAGS.rpc_backend)
+
+
+def create_connection(new=True):
+ return RPCIMPL.Connection.instance(new=True)
+
+
+def create_consumer(conn, topic, proxy, fanout=False):
+ if fanout:
+ return RPCIMPL.FanoutAdapterConsumer(
+ connection=conn,
+ topic=topic,
+ proxy=proxy)
+ else:
+ return RPCIMPL.TopicAdapterConsumer(
+ connection=conn,
+ topic=topic,
+ proxy=proxy)
+
+
+def create_consumer_set(conn, consumers):
+ return RPCIMPL.ConsumerSet(connection=conn, consumer_list=consumers)
+
+
+def call(context, topic, msg):
+ return RPCIMPL.call(context, topic, msg)
+
+
+def cast(context, topic, msg):
+ return RPCIMPL.cast(context, topic, msg)
+
+
+def fanout_cast(context, topic, msg):
+ return RPCIMPL.fanout_cast(context, topic, msg)
+
+
+def multicall(context, topic, msg):
+ return RPCIMPL.multicall(context, topic, msg)
diff --git a/nova/rpc.py b/nova/rpc/amqp.py
index e2771ca88..61555795a 100644
--- a/nova/rpc.py
+++ b/nova/rpc/amqp.py
@@ -44,9 +44,7 @@ from nova import fakerabbit
from nova import flags
from nova import log as logging
from nova import utils
-
-
-LOG = logging.getLogger('nova.rpc')
+from nova.rpc.common import RemoteError, LOG
FLAGS = flags.FLAGS
@@ -418,25 +416,6 @@ def msg_reply(msg_id, reply=None, failure=None):
publisher.close()
-class RemoteError(exception.Error):
- """Signifies that a remote class has raised an exception.
-
- Containes a string representation of the type of the original exception,
- the value of the original exception, and the traceback. These are
- sent to the parent as a joined string so printing the exception
- contains all of the relevent info.
-
- """
-
- def __init__(self, exc_type, value, traceback):
- self.exc_type = exc_type
- self.value = value
- self.traceback = traceback
- super(RemoteError, self).__init__('%s %s\n%s' % (exc_type,
- value,
- traceback))
-
-
def _unpack_context(msg):
"""Unpack context from msg."""
context_dict = {}
diff --git a/nova/rpc/common.py b/nova/rpc/common.py
new file mode 100644
index 000000000..1d3065a83
--- /dev/null
+++ b/nova/rpc/common.py
@@ -0,0 +1,23 @@
+from nova import exception
+from nova import log as logging
+
+LOG = logging.getLogger('nova.rpc')
+
+
+class RemoteError(exception.Error):
+ """Signifies that a remote class has raised an exception.
+
+ Containes a string representation of the type of the original exception,
+ the value of the original exception, and the traceback. These are
+ sent to the parent as a joined string so printing the exception
+ contains all of the relevent info.
+
+ """
+
+ def __init__(self, exc_type, value, traceback):
+ self.exc_type = exc_type
+ self.value = value
+ self.traceback = traceback
+ super(RemoteError, self).__init__('%s %s\n%s' % (exc_type,
+ value,
+ traceback))
diff --git a/nova/scheduler/least_cost.py b/nova/scheduler/least_cost.py
index 6f5eb66fd..8c400d476 100644
--- a/nova/scheduler/least_cost.py
+++ b/nova/scheduler/least_cost.py
@@ -28,6 +28,7 @@ from nova import flags
from nova import log as logging
from nova.scheduler import zone_aware_scheduler
from nova import utils
+from nova import exception
LOG = logging.getLogger('nova.scheduler.least_cost')
diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py
index c429fdfcc..d99d7214c 100644
--- a/nova/scheduler/zone_aware_scheduler.py
+++ b/nova/scheduler/zone_aware_scheduler.py
@@ -81,7 +81,7 @@ class ZoneAwareScheduler(driver.Scheduler):
decryptor = crypto.decryptor(FLAGS.build_plan_encryption_key)
try:
json_entry = decryptor(blob)
- return json.dumps(entry)
+ return json.dumps(json_entry)
except M2Crypto.EVP.EVPError:
pass
return None
diff --git a/nova/service.py b/nova/service.py
index 00e4f61e5..6e9eddc5a 100644
--- a/nova/service.py
+++ b/nova/service.py
@@ -149,26 +149,22 @@ class Service(object):
if 'nova-compute' == self.binary:
self.manager.update_available_resource(ctxt)
- self.conn = rpc.Connection.instance(new=True)
+ self.conn = rpc.create_connection(new=True)
logging.debug("Creating Consumer connection for Service %s" %
self.topic)
# Share this same connection for these Consumers
- consumer_all = rpc.TopicAdapterConsumer(
- connection=self.conn,
- topic=self.topic,
- proxy=self)
- consumer_node = rpc.TopicAdapterConsumer(
- connection=self.conn,
- topic='%s.%s' % (self.topic, self.host),
- proxy=self)
- fanout = rpc.FanoutAdapterConsumer(
- connection=self.conn,
- topic=self.topic,
- proxy=self)
- consumer_set = rpc.ConsumerSet(
- connection=self.conn,
- consumer_list=[consumer_all, consumer_node, fanout])
+ consumer_all = rpc.create_consumer(self.conn, self.topic, self,
+ fanout=False)
+
+ node_topic = '%s.%s' % (self.topic, self.host)
+ consumer_node = rpc.create_consumer(self.conn, node_topic, self,
+ fanout=False)
+
+ fanout = rpc.create_consumer(self.conn, self.topic, self, fanout=True)
+
+ consumers = [consumer_all, consumer_node, fanout]
+ consumer_set = rpc.create_consumer_set(self.conn, consumers)
# Wait forever, processing these consumers
def _wait():
diff --git a/nova/test.py b/nova/test.py
index 9790b0aa1..88f1489e8 100644
--- a/nova/test.py
+++ b/nova/test.py
@@ -60,11 +60,42 @@ class skip_test(object):
self.message = msg
def __call__(self, func):
+ @functools.wraps(func)
def _skipper(*args, **kw):
"""Wrapped skipper function."""
raise nose.SkipTest(self.message)
- _skipper.__name__ = func.__name__
- _skipper.__doc__ = func.__doc__
+ return _skipper
+
+
+class skip_if(object):
+ """Decorator that skips a test if contition is true."""
+ def __init__(self, condition, msg):
+ self.condition = condition
+ self.message = msg
+
+ def __call__(self, func):
+ @functools.wraps(func)
+ def _skipper(*args, **kw):
+ """Wrapped skipper function."""
+ if self.condition:
+ raise nose.SkipTest(self.message)
+ func(*args, **kw)
+ return _skipper
+
+
+class skip_unless(object):
+ """Decorator that skips a test if condition is not true."""
+ def __init__(self, condition, msg):
+ self.condition = condition
+ self.message = msg
+
+ def __call__(self, func):
+ @functools.wraps(func)
+ def _skipper(*args, **kw):
+ """Wrapped skipper function."""
+ if not self.condition:
+ raise nose.SkipTest(self.message)
+ func(*args, **kw)
return _skipper
@@ -99,9 +130,7 @@ class TestCase(unittest.TestCase):
self.flag_overrides = {}
self.injected = []
self._services = []
- self._monkey_patch_attach()
self._original_flags = FLAGS.FlagValuesDict()
- rpc.ConnectionPool = rpc.Pool(max_size=FLAGS.rpc_conn_pool_size)
def tearDown(self):
"""Runs after each test method to tear down test environment."""
@@ -126,9 +155,6 @@ class TestCase(unittest.TestCase):
# Reset any overriden flags
self.reset_flags()
- # Reset our monkey-patches
- rpc.Consumer.attach_to_eventlet = self.original_attach
-
# Stop any timers
for x in self.injected:
try:
@@ -146,11 +172,9 @@ class TestCase(unittest.TestCase):
def flags(self, **kw):
"""Override flag variables for a test."""
for k, v in kw.iteritems():
- if k in self.flag_overrides:
- self.reset_flags()
- raise Exception(
- 'trying to override already overriden flag: %s' % k)
- self.flag_overrides[k] = getattr(FLAGS, k)
+ # Store original flag value if it's not been overriden yet
+ if k not in self.flag_overrides:
+ self.flag_overrides[k] = getattr(FLAGS, k)
setattr(FLAGS, k, v)
def reset_flags(self):
@@ -172,17 +196,6 @@ class TestCase(unittest.TestCase):
self._services.append(svc)
return svc
- def _monkey_patch_attach(self):
- self.original_attach = rpc.Consumer.attach_to_eventlet
-
- def _wrapped(inner_self):
- rv = self.original_attach(inner_self)
- self.injected.append(rv)
- return rv
-
- _wrapped.func_name = self.original_attach.func_name
- rpc.Consumer.attach_to_eventlet = _wrapped
-
# Useful assertions
def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
"""Assert two dicts are equivalent.
diff --git a/nova/tests/__init__.py b/nova/tests/__init__.py
index e4ed75d37..720d5b0e6 100644
--- a/nova/tests/__init__.py
+++ b/nova/tests/__init__.py
@@ -59,6 +59,7 @@ def setup():
network.create_networks(ctxt,
label='test',
cidr=FLAGS.fixed_range,
+ multi_host=FLAGS.multi_host,
num_networks=FLAGS.num_networks,
network_size=FLAGS.network_size,
cidr_v6=FLAGS.fixed_range_v6,
@@ -66,9 +67,10 @@ def setup():
bridge=FLAGS.flat_network_bridge,
bridge_interface=bridge_interface,
vpn_start=FLAGS.vpn_start,
- vlan_start=FLAGS.vlan_start)
+ vlan_start=FLAGS.vlan_start,
+ dns1=FLAGS.flat_network_dns)
for net in db.network_get_all(ctxt):
- network.set_network_host(ctxt, net['id'])
+ network.set_network_host(ctxt, net)
cleandb = os.path.join(FLAGS.state_path, FLAGS.sqlite_clean_db)
shutil.copyfile(testdb, cleandb)
diff --git a/nova/tests/api/openstack/__init__.py b/nova/tests/api/openstack/__init__.py
index bfb424afe..458434a81 100644
--- a/nova/tests/api/openstack/__init__.py
+++ b/nova/tests/api/openstack/__init__.py
@@ -22,14 +22,11 @@ import webob.dec
from nova import test
from nova import context
-from nova import flags
from nova.api.openstack.limits import RateLimitingMiddleware
from nova.api.openstack.common import limited
from nova.tests.api.openstack import fakes
from webob import Request
-FLAGS = flags.FLAGS
-
@webob.dec.wsgify
def simple_wsgi(req):
diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py
index de006d088..ab7ae2e54 100644
--- a/nova/tests/api/openstack/contrib/test_floating_ips.py
+++ b/nova/tests/api/openstack/contrib/test_floating_ips.py
@@ -74,12 +74,8 @@ class FloatingIpTest(test.TestCase):
def setUp(self):
super(FloatingIpTest, self).setUp()
self.controller = FloatingIPController()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
self.stubs.Set(network.api.API, "get_floating_ip",
network_api_get_floating_ip)
self.stubs.Set(network.api.API, "list_floating_ips",
@@ -96,7 +92,6 @@ class FloatingIpTest(test.TestCase):
self._create_floating_ip()
def tearDown(self):
- self.stubs.UnsetAll()
self._delete_floating_ip()
super(FloatingIpTest, self).tearDown()
@@ -111,6 +106,11 @@ class FloatingIpTest(test.TestCase):
self.assertEqual(view['floating_ip']['fixed_ip'], None)
self.assertEqual(view['floating_ip']['instance_id'], None)
+ def test_translate_floating_ip_view_dict(self):
+ floating_ip = {'id': 0, 'address': '10.0.0.10', 'fixed_ip': None}
+ view = _translate_floating_ip_view(floating_ip)
+ self.assertTrue('floating_ip' in view)
+
def test_floating_ips_list(self):
req = webob.Request.blank('/v1.1/os-floating-ips')
res = req.get_response(fakes.wsgi_app())
diff --git a/nova/tests/api/openstack/contrib/test_multinic_xs.py b/nova/tests/api/openstack/contrib/test_multinic_xs.py
index b0a9f7676..ac28f6be6 100644
--- a/nova/tests/api/openstack/contrib/test_multinic_xs.py
+++ b/nova/tests/api/openstack/contrib/test_multinic_xs.py
@@ -42,22 +42,14 @@ def compute_api_remove_fixed_ip(self, context, instance_id, address):
class FixedIpTest(test.TestCase):
def setUp(self):
super(FixedIpTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
self.stubs.Set(compute.api.API, "add_fixed_ip",
compute_api_add_fixed_ip)
self.stubs.Set(compute.api.API, "remove_fixed_ip",
compute_api_remove_fixed_ip)
self.context = context.get_admin_context()
- def tearDown(self):
- self.stubs.UnsetAll()
- super(FixedIpTest, self).tearDown()
-
def test_add_fixed_ip(self):
global last_add_fixed_ip
last_add_fixed_ip = (None, None)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 26b1de818..a67a28a4e 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -29,6 +29,7 @@ from glance.common import exception as glance_exc
from nova import context
from nova import exception as exc
from nova import utils
+from nova import wsgi
import nova.api.openstack.auth
from nova.api import openstack
from nova.api.openstack import auth
@@ -40,14 +41,13 @@ import nova.image.fake
from nova.image import glance
from nova.image import service
from nova.tests import fake_flags
-from nova.wsgi import Router
class Context(object):
pass
-class FakeRouter(Router):
+class FakeRouter(wsgi.Router):
def __init__(self):
pass
@@ -68,21 +68,30 @@ def fake_auth_init(self, application):
@webob.dec.wsgify
def fake_wsgi(self, req):
- req.environ['nova.context'] = context.RequestContext(1, 1)
return self.application
-def wsgi_app(inner_app10=None, inner_app11=None):
+def wsgi_app(inner_app10=None, inner_app11=None, fake_auth=True):
if not inner_app10:
inner_app10 = openstack.APIRouterV10()
if not inner_app11:
inner_app11 = openstack.APIRouterV11()
- mapper = urlmap.URLMap()
- api10 = openstack.FaultWrapper(auth.AuthMiddleware(
+
+ if fake_auth:
+ ctxt = context.RequestContext('fake', 'fake')
+ api10 = openstack.FaultWrapper(wsgi.InjectContext(ctxt,
+ limits.RateLimitingMiddleware(inner_app10)))
+ api11 = openstack.FaultWrapper(wsgi.InjectContext(ctxt,
+ limits.RateLimitingMiddleware(
+ extensions.ExtensionMiddleware(inner_app11))))
+ else:
+ api10 = openstack.FaultWrapper(auth.AuthMiddleware(
limits.RateLimitingMiddleware(inner_app10)))
- api11 = openstack.FaultWrapper(auth.AuthMiddleware(
+ api11 = openstack.FaultWrapper(auth.AuthMiddleware(
limits.RateLimitingMiddleware(
extensions.ExtensionMiddleware(inner_app11))))
+ Auth = auth
+ mapper = urlmap.URLMap()
mapper['/v1.0'] = api10
mapper['/v1.1'] = api11
mapper['/'] = openstack.FaultWrapper(versions.Versions())
@@ -104,8 +113,7 @@ def stub_out_key_pair_funcs(stubs, have_key_pair=True):
def stub_out_image_service(stubs):
def fake_get_image_service(image_href):
- image_id = int(str(image_href).split('/')[-1])
- return (nova.image.fake.FakeImageService(), image_id)
+ return (nova.image.fake.FakeImageService(), image_href)
stubs.Set(nova.image, 'get_image_service', fake_get_image_service)
stubs.Set(nova.image, 'get_default_image_service',
lambda: nova.image.fake.FakeImageService())
@@ -359,17 +367,18 @@ class FakeAuthManager(object):
if admin is not None:
user.admin = admin
- def is_admin(self, user):
+ def is_admin(self, user_id):
+ user = self.get_user(user_id)
return user.admin
- def is_project_member(self, user, project):
+ def is_project_member(self, user_id, project):
if not isinstance(project, Project):
try:
project = self.get_project(project)
except exc.NotFound:
raise webob.exc.HTTPUnauthorized()
- return ((user.id in project.member_ids) or
- (user.id == project.project_manager_id))
+ return ((user_id in project.member_ids) or
+ (user_id == project.project_manager_id))
def create_project(self, name, manager_user, description=None,
member_users=None):
@@ -396,13 +405,13 @@ class FakeAuthManager(object):
else:
raise exc.NotFound
- def get_projects(self, user=None):
- if not user:
+ def get_projects(self, user_id=None):
+ if not user_id:
return FakeAuthManager.projects.values()
else:
return [p for p in FakeAuthManager.projects.values()
- if (user.id in p.member_ids) or
- (user.id == p.project_manager_id)]
+ if (user_id in p.member_ids) or
+ (user_id == p.project_manager_id)]
class FakeRateLimiter(object):
diff --git a/nova/tests/api/openstack/test_accounts.py b/nova/tests/api/openstack/test_accounts.py
index 64abcf48c..707a2599f 100644
--- a/nova/tests/api/openstack/test_accounts.py
+++ b/nova/tests/api/openstack/test_accounts.py
@@ -16,20 +16,14 @@
import json
-import stubout
import webob
-from nova import flags
from nova import test
from nova.api.openstack import accounts
from nova.auth.manager import User
from nova.tests.api.openstack import fakes
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
def fake_init(self):
self.manager = fakes.FakeAuthManager()
@@ -41,7 +35,7 @@ def fake_admin_check(self, req):
class AccountsTest(test.TestCase):
def setUp(self):
super(AccountsTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
+ self.flags(verbose=True, allow_admin_api=True)
self.stubs.Set(accounts.Controller, '__init__',
fake_init)
self.stubs.Set(accounts.Controller, '_check_admin',
@@ -52,8 +46,6 @@ class AccountsTest(test.TestCase):
fakes.stub_out_rate_limiting(self.stubs)
fakes.stub_out_auth(self.stubs)
- self.allow_admin = FLAGS.allow_admin_api
- FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
joeuser = User('id1', 'guy1', 'acc1', 'secret1', False)
superuser = User('id2', 'guy2', 'acc2', 'secret2', True)
@@ -62,11 +54,6 @@ class AccountsTest(test.TestCase):
fakemgr.create_project('test1', joeuser)
fakemgr.create_project('test2', superuser)
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.allow_admin_api = self.allow_admin
- super(AccountsTest, self).tearDown()
-
def test_get_account(self):
req = webob.Request.blank('/v1.0/accounts/test1')
res = req.get_response(fakes.wsgi_app())
diff --git a/nova/tests/api/openstack/test_adminapi.py b/nova/tests/api/openstack/test_adminapi.py
index e87255b18..c9e66dc4c 100644
--- a/nova/tests/api/openstack/test_adminapi.py
+++ b/nova/tests/api/openstack/test_adminapi.py
@@ -16,38 +16,22 @@
# under the License.
-import stubout
import webob
-from paste import urlmap
-from nova import flags
from nova import test
-from nova.api import openstack
-from nova.api.openstack import auth
from nova.tests.api.openstack import fakes
-FLAGS = flags.FLAGS
-
class AdminAPITest(test.TestCase):
def setUp(self):
super(AdminAPITest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
- self.allow_admin = FLAGS.allow_admin_api
-
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.allow_admin_api = self.allow_admin
- super(AdminAPITest, self).tearDown()
+ self.flags(verbose=True)
def test_admin_enabled(self):
- FLAGS.allow_admin_api = True
+ self.flags(allow_admin_api=True)
# We should still be able to access public operations.
req = webob.Request.blank('/v1.0/flavors')
res = req.get_response(fakes.wsgi_app())
@@ -55,7 +39,7 @@ class AdminAPITest(test.TestCase):
# TODO: Confirm admin operations are available.
def test_admin_disabled(self):
- FLAGS.allow_admin_api = False
+ self.flags(allow_admin_api=False)
# We should still be able to access public operations.
req = webob.Request.blank('/v1.0/flavors')
res = req.get_response(fakes.wsgi_app())
diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py
index af3478c7d..306ae1aa0 100644
--- a/nova/tests/api/openstack/test_auth.py
+++ b/nova/tests/api/openstack/test_auth.py
@@ -17,14 +17,12 @@
import datetime
-import stubout
import webob
import webob.dec
import nova.api
import nova.api.openstack.auth
import nova.auth.manager
-from nova import auth
from nova import context
from nova import db
from nova import test
@@ -35,7 +33,6 @@ class Test(test.TestCase):
def setUp(self):
super(Test, self).setUp()
- self.stubs = stubout.StubOutForTesting()
self.stubs.Set(nova.api.openstack.auth.AuthMiddleware,
'__init__', fakes.fake_auth_init)
self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
@@ -45,7 +42,6 @@ class Test(test.TestCase):
fakes.stub_out_networking(self.stubs)
def tearDown(self):
- self.stubs.UnsetAll()
fakes.fake_data_store = {}
super(Test, self).tearDown()
@@ -57,7 +53,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'user1'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '204 No Content')
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
self.assertEqual(result.headers['X-CDN-Management-Url'],
@@ -73,7 +69,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
req.headers['X-Auth-User'] = 'user1'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '204 No Content')
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
self.assertEqual(result.headers['X-Server-Management-Url'],
@@ -86,7 +82,7 @@ class Test(test.TestCase):
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
req = webob.Request.blank('/v1.0/fake')
req.headers['X-Auth-Token'] = token
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '200 OK')
self.assertEqual(result.headers['X-Test-Success'], 'True')
@@ -110,7 +106,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-Token'] = 'token_hash'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
self.assertEqual(self.destroy_called, True)
@@ -124,7 +120,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
req.headers['X-Auth-User'] = 'user1'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '204 No Content')
token = result.headers['X-Auth-Token']
@@ -132,7 +128,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/fake')
req.headers['X-Auth-Token'] = token
req.headers['X-Auth-Project-Id'] = 'user2_project'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '200 OK')
self.assertEqual(result.headers['X-Test-Success'], 'True')
@@ -140,7 +136,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'unknown_user'
req.headers['X-Auth-Key'] = 'unknown_user_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
def test_bad_user_good_key(self):
@@ -151,18 +147,18 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'unknown_user'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
def test_no_user(self):
req = webob.Request.blank('/v1.0/')
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
def test_bad_token(self):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-Token'] = 'unknown_token'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
def test_bad_project(self):
@@ -177,7 +173,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
req.headers['X-Auth-User'] = 'user1'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '204 No Content')
token = result.headers['X-Auth-Token']
@@ -185,7 +181,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/fake')
req.headers['X-Auth-Token'] = token
req.headers['X-Auth-Project-Id'] = 'user2_project'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
def test_not_existing_project(self):
@@ -197,7 +193,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
req.headers['X-Auth-User'] = 'user1'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '204 No Content')
token = result.headers['X-Auth-Token']
@@ -205,7 +201,7 @@ class Test(test.TestCase):
req = webob.Request.blank('/v1.0/fake')
req.headers['X-Auth-Token'] = token
req.headers['X-Auth-Project-Id'] = 'unknown_project'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
@@ -226,20 +222,19 @@ class TestFunctional(test.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-Token'] = 'test_token_hash'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
def test_token_doesnotexist(self):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-Token'] = 'nonexistant_token_hash'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '401 Unauthorized')
class TestLimiter(test.TestCase):
def setUp(self):
super(TestLimiter, self).setUp()
- self.stubs = stubout.StubOutForTesting()
self.stubs.Set(nova.api.openstack.auth.AuthMiddleware,
'__init__', fakes.fake_auth_init)
self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
@@ -248,7 +243,6 @@ class TestLimiter(test.TestCase):
fakes.stub_out_networking(self.stubs)
def tearDown(self):
- self.stubs.UnsetAll()
fakes.fake_data_store = {}
super(TestLimiter, self).tearDown()
@@ -261,7 +255,7 @@ class TestLimiter(test.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'user1'
req.headers['X-Auth-Key'] = 'user1_key'
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
token = result.headers['X-Auth-Token']
@@ -269,6 +263,6 @@ class TestLimiter(test.TestCase):
req = webob.Request.blank('/v1.0/fake')
req.method = 'POST'
req.headers['X-Auth-Token'] = token
- result = req.get_response(fakes.wsgi_app())
+ result = req.get_response(fakes.wsgi_app(fake_auth=False))
self.assertEqual(result.status, '200 OK')
self.assertEqual(result.headers['X-Test-Success'], 'True')
diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py
index 4c4d03995..5a6e43579 100644
--- a/nova/tests/api/openstack/test_common.py
+++ b/nova/tests/api/openstack/test_common.py
@@ -20,6 +20,7 @@ Test suites for 'common' code used throughout the OpenStack HTTP API.
"""
import webob.exc
+import xml.dom.minidom as minidom
from webob import Request
@@ -247,3 +248,201 @@ 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)
+
+
+class MetadataXMLDeserializationTest(test.TestCase):
+
+ deserializer = common.MetadataXMLDeserializer()
+
+ 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 MetadataXMLSerializationTest(test.TestCase):
+
+ def test_index(self):
+ serializer = common.MetadataXMLSerializer()
+ fixture = {
+ 'metadata': {
+ 'one': 'two',
+ 'three': 'four',
+ },
+ }
+ output = serializer.serialize(fixture, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="three">four</meta>
+ <meta key="one">two</meta>
+ </metadata>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_index_null(self):
+ serializer = common.MetadataXMLSerializer()
+ fixture = {
+ 'metadata': {
+ None: None,
+ },
+ }
+ output = serializer.serialize(fixture, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="None">None</meta>
+ </metadata>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_index_unicode(self):
+ serializer = common.MetadataXMLSerializer()
+ fixture = {
+ 'metadata': {
+ u'three': u'Jos\xe9',
+ },
+ }
+ output = serializer.serialize(fixture, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString(u"""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="three">Jos\xe9</meta>
+ </metadata>
+ """.encode("UTF-8").replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_show(self):
+ serializer = common.MetadataXMLSerializer()
+ fixture = {
+ 'meta': {
+ 'one': 'two',
+ },
+ }
+ output = serializer.serialize(fixture, 'show')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <meta xmlns="http://docs.openstack.org/compute/api/v1.1"
+ key="one">two</meta>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_update_all(self):
+ serializer = common.MetadataXMLSerializer()
+ 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(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_update_item(self):
+ serializer = common.MetadataXMLSerializer()
+ fixture = {
+ 'meta': {
+ 'one': 'two',
+ },
+ }
+ output = serializer.serialize(fixture, 'update')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <meta xmlns="http://docs.openstack.org/compute/api/v1.1"
+ key="one">two</meta>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_create(self):
+ serializer = common.MetadataXMLSerializer()
+ fixture = {
+ 'metadata': {
+ 'key9': 'value9',
+ 'key2': 'value2',
+ 'key1': 'value1',
+ },
+ }
+ output = serializer.serialize(fixture, 'create')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="key2">value2</meta>
+ <meta key="key9">value9</meta>
+ <meta key="key1">value1</meta>
+ </metadata>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_delete(self):
+ serializer = common.MetadataXMLSerializer()
+ output = serializer.serialize(None, 'delete')
+ self.assertEqual(output, '')
diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py
index 697c62e5c..409fa0e71 100644
--- a/nova/tests/api/openstack/test_extensions.py
+++ b/nova/tests/api/openstack/test_extensions.py
@@ -16,21 +16,20 @@
# under the License.
import json
-import stubout
-import unittest
-import webob
import os.path
+import webob
+from xml.etree import ElementTree
from nova import context
-from nova import flags
+from nova import test
from nova.api import openstack
from nova.api.openstack import extensions
from nova.api.openstack import flavors
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..."
@@ -78,24 +77,109 @@ class StubExtensionManager(object):
return request_extensions
-class ExtensionControllerTest(unittest.TestCase):
+class ExtensionControllerTest(test.TestCase):
+
+ def setUp(self):
+ super(ExtensionControllerTest, self).setUp()
+ ext_path = os.path.join(os.path.dirname(__file__), "extensions")
+ self.flags(osapi_extensions_path=ext_path)
+
+ 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)
+
+ # 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)
- def test_index(self):
+ 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_by_alias(self):
+ 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):
+
+class ResourceExtensionTest(test.TestCase):
+
+ def setUp(self):
+ super(ResourceExtensionTest, self).setUp()
+ ext_path = os.path.join(os.path.dirname(__file__), "extensions")
+ self.flags(osapi_extensions_path=ext_path)
def test_no_extension_present(self):
manager = StubExtensionManager(None)
@@ -133,13 +217,14 @@ class InvalidExtension(object):
return "THIRD"
-class ExtensionManagerTest(unittest.TestCase):
+class ExtensionManagerTest(test.TestCase):
response_body = "Try to say this Mr. Knox, sir..."
def setUp(self):
- FLAGS.osapi_extensions_path = os.path.join(os.path.dirname(__file__),
- "extensions")
+ super(ExtensionManagerTest, self).setUp()
+ ext_path = os.path.join(os.path.dirname(__file__), "extensions")
+ self.flags(osapi_extensions_path=ext_path)
def test_get_resources(self):
app = openstack.APIRouterV11()
@@ -158,11 +243,12 @@ class ExtensionManagerTest(unittest.TestCase):
self.assertTrue('THIRD' not in ext_mgr.extensions)
-class ActionExtensionTest(unittest.TestCase):
+class ActionExtensionTest(test.TestCase):
def setUp(self):
- FLAGS.osapi_extensions_path = os.path.join(os.path.dirname(__file__),
- "extensions")
+ super(ActionExtensionTest, self).setUp()
+ ext_path = os.path.join(os.path.dirname(__file__), "extensions")
+ self.flags(osapi_extensions_path=ext_path)
def _send_server_action_request(self, url, body):
app = openstack.APIRouterV11()
@@ -192,23 +278,16 @@ 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)
-class RequestExtensionTest(unittest.TestCase):
+class RequestExtensionTest(test.TestCase):
def setUp(self):
super(RequestExtensionTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
- fakes.stub_out_auth(self.stubs)
- self.context = context.get_admin_context()
-
- def tearDown(self):
- self.stubs.UnsetAll()
- super(RequestExtensionTest, self).tearDown()
+ ext_path = os.path.join(os.path.dirname(__file__), "extensions")
+ self.flags(osapi_extensions_path=ext_path)
def test_get_resources_with_stub_mgr(self):
@@ -244,3 +323,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(test.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)
diff --git a/nova/tests/api/openstack/test_faults.py b/nova/tests/api/openstack/test_faults.py
index 4d86ffb26..6da27540a 100644
--- a/nova/tests/api/openstack/test_faults.py
+++ b/nova/tests/api/openstack/test_faults.py
@@ -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):
@@ -139,3 +141,113 @@ class TestFaults(test.TestCase):
self.assertEqual(resp.content_type, "application/xml")
self.assertEqual(resp.status_int, 404)
self.assertTrue('whut?' in resp.body)
+
+ def test_fault_has_status_int(self):
+ """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())
diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py
index 689647cc6..d0fe72001 100644
--- a/nova/tests/api/openstack/test_flavors.py
+++ b/nova/tests/api/openstack/test_flavors.py
@@ -16,14 +16,15 @@
# under the License.
import json
-import stubout
import webob
+import xml.dom.minidom as minidom
+from nova.api.openstack import flavors
import nova.db.api
-from nova import context
from nova import exception
from nova import test
from nova.tests.api.openstack import fakes
+from nova import wsgi
def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"):
@@ -54,17 +55,12 @@ def return_instance_type_not_found(context, flavor_id):
class FlavorsTest(test.TestCase):
def setUp(self):
super(FlavorsTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
self.stubs.Set(nova.db.api, "instance_type_get_all",
return_instance_types)
self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",
return_instance_type_by_flavor_id)
- self.context = context.get_admin_context()
def tearDown(self):
self.stubs.UnsetAll()
@@ -146,61 +142,65 @@ class FlavorsTest(test.TestCase):
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
- flavor = json.loads(res.body)["flavor"]
+ flavor = json.loads(res.body)
expected = {
- "id": "12",
- "name": "flavor 12",
- "ram": "256",
- "disk": "10",
- "links": [
- {
- "rel": "self",
- "href": "http://localhost/v1.1/flavors/12",
- },
- {
- "rel": "bookmark",
- "href": "http://localhost/flavors/12",
- },
- ],
- }
- self.assertEqual(flavor, expected)
-
- def test_get_flavor_list_v1_1(self):
- req = webob.Request.blank('/v1.1/flavors')
- req.environ['api.version'] = '1.1'
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 200)
- flavor = json.loads(res.body)["flavors"]
- expected = [
- {
- "id": "1",
- "name": "flavor 1",
- "links": [
- {
- "rel": "self",
- "href": "http://localhost/v1.1/flavors/1",
- },
- {
- "rel": "bookmark",
- "href": "http://localhost/flavors/1",
- },
- ],
- },
- {
- "id": "2",
- "name": "flavor 2",
+ "flavor": {
+ "id": "12",
+ "name": "flavor 12",
+ "ram": "256",
+ "disk": "10",
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/flavors/2",
+ "href": "http://localhost/v1.1/flavors/12",
},
{
"rel": "bookmark",
- "href": "http://localhost/flavors/2",
+ "href": "http://localhost/flavors/12",
},
],
},
- ]
+ }
+ self.assertEqual(flavor, expected)
+
+ def test_get_flavor_list_v1_1(self):
+ req = webob.Request.blank('/v1.1/flavors')
+ req.environ['api.version'] = '1.1'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ flavor = json.loads(res.body)
+ expected = {
+ "flavors": [
+ {
+ "id": "1",
+ "name": "flavor 1",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/1",
+ },
+ ],
+ },
+ {
+ "id": "2",
+ "name": "flavor 2",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/2",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/2",
+ },
+ ],
+ },
+ ],
+ }
self.assertEqual(flavor, expected)
def test_get_flavor_list_detail_v1_1(self):
@@ -208,52 +208,273 @@ class FlavorsTest(test.TestCase):
req.environ['api.version'] = '1.1'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
- flavor = json.loads(res.body)["flavors"]
- expected = [
- {
- "id": "1",
- "name": "flavor 1",
+ flavor = json.loads(res.body)
+ expected = {
+ "flavors": [
+ {
+ "id": "1",
+ "name": "flavor 1",
+ "ram": "256",
+ "disk": "10",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/1",
+ },
+ ],
+ },
+ {
+ "id": "2",
+ "name": "flavor 2",
+ "ram": "256",
+ "disk": "10",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/2",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/2",
+ },
+ ],
+ },
+ ],
+ }
+ self.assertEqual(flavor, expected)
+
+ def test_get_empty_flavor_list_v1_1(self):
+ def _return_empty(self):
+ return {}
+ self.stubs.Set(nova.db.api, "instance_type_get_all", _return_empty)
+
+ req = webob.Request.blank('/v1.1/flavors')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ flavors = json.loads(res.body)["flavors"]
+ expected = []
+ self.assertEqual(flavors, expected)
+
+
+class FlavorsXMLSerializationTest(test.TestCase):
+
+ def test_show(self):
+ serializer = flavors.FlavorXMLSerializer()
+
+ input = {
+ "flavor": {
+ "id": "12",
+ "name": "asdf",
"ram": "256",
"disk": "10",
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/flavors/1",
+ "href": "http://localhost/v1.1/flavors/12",
},
{
"rel": "bookmark",
- "href": "http://localhost/flavors/1",
+ "href": "http://localhost/flavors/12",
},
],
},
- {
- "id": "2",
- "name": "flavor 2",
- "ram": "256",
- "disk": "10",
+ }
+
+ output = serializer.serialize(input, 'show')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <flavor xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ id="12"
+ name="asdf"
+ ram="256"
+ disk="10">
+ <atom:link href="http://localhost/v1.1/flavors/12" rel="self"/>
+ <atom:link href="http://localhost/flavors/12" rel="bookmark"/>
+ </flavor>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_show_handles_integers(self):
+ serializer = flavors.FlavorXMLSerializer()
+
+ input = {
+ "flavor": {
+ "id": 12,
+ "name": "asdf",
+ "ram": 256,
+ "disk": 10,
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/flavors/2",
+ "href": "http://localhost/v1.1/flavors/12",
},
{
"rel": "bookmark",
- "href": "http://localhost/flavors/2",
+ "href": "http://localhost/flavors/12",
},
],
},
- ]
- self.assertEqual(flavor, expected)
+ }
- def test_get_empty_flavor_list_v1_1(self):
- def _return_empty(self):
- return {}
- self.stubs.Set(nova.db.api, "instance_type_get_all",
- _return_empty)
+ output = serializer.serialize(input, 'show')
+ actual = minidom.parseString(output.replace(" ", ""))
- req = webob.Request.blank('/v1.1/flavors')
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 200)
- flavors = json.loads(res.body)["flavors"]
- expected = []
- self.assertEqual(flavors, expected)
+ expected = minidom.parseString("""
+ <flavor xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ id="12"
+ name="asdf"
+ ram="256"
+ disk="10">
+ <atom:link href="http://localhost/v1.1/flavors/12" rel="self"/>
+ <atom:link href="http://localhost/flavors/12" rel="bookmark"/>
+ </flavor>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_detail(self):
+ serializer = flavors.FlavorXMLSerializer()
+
+ input = {
+ "flavors": [
+ {
+ "id": "23",
+ "name": "flavor 23",
+ "ram": "512",
+ "disk": "20",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/23",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/23",
+ },
+ ],
+ }, {
+ "id": "13",
+ "name": "flavor 13",
+ "ram": "256",
+ "disk": "10",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/13",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/13",
+ },
+ ],
+ },
+ ],
+ }
+
+ output = serializer.serialize(input, 'detail')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <flavors xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom">
+ <flavor id="23"
+ name="flavor 23"
+ ram="512"
+ disk="20">
+ <atom:link href="http://localhost/v1.1/flavors/23" rel="self"/>
+ <atom:link href="http://localhost/flavors/23" rel="bookmark"/>
+ </flavor>
+ <flavor id="13"
+ name="flavor 13"
+ ram="256"
+ disk="10">
+ <atom:link href="http://localhost/v1.1/flavors/13" rel="self"/>
+ <atom:link href="http://localhost/flavors/13" rel="bookmark"/>
+ </flavor>
+ </flavors>
+ """.replace(" ", "") % locals())
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_index(self):
+ serializer = flavors.FlavorXMLSerializer()
+
+ input = {
+ "flavors": [
+ {
+ "id": "23",
+ "name": "flavor 23",
+ "ram": "512",
+ "disk": "20",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/23",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/23",
+ },
+ ],
+ }, {
+ "id": "13",
+ "name": "flavor 13",
+ "ram": "256",
+ "disk": "10",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/flavors/13",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/flavors/13",
+ },
+ ],
+ },
+ ],
+ }
+
+ output = serializer.serialize(input, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <flavors xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom">
+ <flavor id="23" name="flavor 23">
+ <atom:link href="http://localhost/v1.1/flavors/23" rel="self"/>
+ <atom:link href="http://localhost/flavors/23" rel="bookmark"/>
+ </flavor>
+ <flavor id="13" name="flavor 13">
+ <atom:link href="http://localhost/v1.1/flavors/13" rel="self"/>
+ <atom:link href="http://localhost/flavors/13" rel="bookmark"/>
+ </flavor>
+ </flavors>
+ """.replace(" ", "") % locals())
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_index_empty(self):
+ serializer = flavors.FlavorXMLSerializer()
+
+ input = {
+ "flavors": [],
+ }
+
+ output = serializer.serialize(input, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <flavors xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom" />
+ """.replace(" ", "") % locals())
+
+ self.assertEqual(expected.toxml(), actual.toxml())
diff --git a/nova/tests/api/openstack/extensions/test_flavors_extra_specs.py b/nova/tests/api/openstack/test_flavors_extra_specs.py
index 2c1c335b0..ccd1b0d9f 100644
--- a/nova/tests/api/openstack/extensions/test_flavors_extra_specs.py
+++ b/nova/tests/api/openstack/test_flavors_extra_specs.py
@@ -17,20 +17,16 @@
import json
import stubout
-import unittest
import webob
import os.path
-from nova import flags
+from nova import test
from nova.api import openstack
-from nova.api.openstack import auth
from nova.api.openstack import extensions
from nova.tests.api.openstack import fakes
import nova.wsgi
-FLAGS = flags.FLAGS
-
def return_create_flavor_extra_specs(context, flavor_id, extra_specs):
return stub_flavor_extra_specs()
@@ -40,10 +36,6 @@ def return_flavor_extra_specs(context, flavor_id):
return stub_flavor_extra_specs()
-def return_flavor_extra_specs(context, flavor_id):
- return stub_flavor_extra_specs()
-
-
def return_empty_flavor_extra_specs(context, flavor_id):
return {}
@@ -62,30 +54,17 @@ def stub_flavor_extra_specs():
return specs
-class FlavorsExtraSpecsTest(unittest.TestCase):
+class FlavorsExtraSpecsTest(test.TestCase):
def setUp(self):
super(FlavorsExtraSpecsTest, self).setUp()
- FLAGS.osapi_extensions_path = os.path.join(os.path.dirname(__file__),
- "extensions")
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.auth_data = {}
- fakes.FakeAuthDatabase.data = {}
- fakes.stub_out_auth(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
- self.mware = auth.AuthMiddleware(
- extensions.ExtensionMiddleware(
- openstack.APIRouterV11()))
-
- def tearDown(self):
- self.stubs.UnsetAll()
- super(FlavorsExtraSpecsTest, self).tearDown()
def test_index(self):
self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
return_flavor_extra_specs)
- request = webob.Request.blank('/flavors/1/os-extra_specs')
- res = request.get_response(self.mware)
+ request = webob.Request.blank('/v1.1/flavors/1/os-extra_specs')
+ res = request.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
res_dict = json.loads(res.body)
self.assertEqual('application/json', res.headers['Content-Type'])
@@ -94,8 +73,8 @@ class FlavorsExtraSpecsTest(unittest.TestCase):
def test_index_no_data(self):
self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
return_empty_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs')
- res = req.get_response(self.mware)
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs')
+ res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
self.assertEqual('application/json', res.headers['Content-Type'])
@@ -104,8 +83,8 @@ class FlavorsExtraSpecsTest(unittest.TestCase):
def test_show(self):
self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
return_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/key5')
- res = req.get_response(self.mware)
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/key5')
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
res_dict = json.loads(res.body)
self.assertEqual('application/json', res.headers['Content-Type'])
@@ -114,28 +93,28 @@ class FlavorsExtraSpecsTest(unittest.TestCase):
def test_show_spec_not_found(self):
self.stubs.Set(nova.db.api, 'instance_type_extra_specs_get',
return_empty_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/key6')
- res = req.get_response(self.mware)
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/key6')
+ res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(404, res.status_int)
def test_delete(self):
self.stubs.Set(nova.db.api, 'instance_type_extra_specs_delete',
delete_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/key5')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/key5')
req.method = 'DELETE'
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
def test_create(self):
self.stubs.Set(nova.db.api,
'instance_type_extra_specs_update_or_create',
return_create_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs')
req.method = 'POST'
req.body = '{"extra_specs": {"key1": "value1"}}'
req.headers["content-type"] = "application/json"
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
self.assertEqual('application/json', res.headers['Content-Type'])
@@ -145,21 +124,21 @@ class FlavorsExtraSpecsTest(unittest.TestCase):
self.stubs.Set(nova.db.api,
'instance_type_extra_specs_update_or_create',
return_create_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs')
req.method = 'POST'
req.headers["content-type"] = "application/json"
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
def test_update_item(self):
self.stubs.Set(nova.db.api,
'instance_type_extra_specs_update_or_create',
return_create_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/key1')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/key1')
req.method = 'PUT'
req.body = '{"key1": "value1"}'
req.headers["content-type"] = "application/json"
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
self.assertEqual('application/json', res.headers['Content-Type'])
res_dict = json.loads(res.body)
@@ -169,30 +148,30 @@ class FlavorsExtraSpecsTest(unittest.TestCase):
self.stubs.Set(nova.db.api,
'instance_type_extra_specs_update_or_create',
return_create_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/key1')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/key1')
req.method = 'PUT'
req.headers["content-type"] = "application/json"
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
def test_update_item_too_many_keys(self):
self.stubs.Set(nova.db.api,
'instance_type_extra_specs_update_or_create',
return_create_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/key1')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/key1')
req.method = 'PUT'
req.body = '{"key1": "value1", "key2": "value2"}'
req.headers["content-type"] = "application/json"
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(nova.db.api,
'instance_type_extra_specs_update_or_create',
return_create_flavor_extra_specs)
- req = webob.Request.blank('/flavors/1/os-extra_specs/bad')
+ req = webob.Request.blank('/v1.1/flavors/1/os-extra_specs/bad')
req.method = 'PUT'
req.body = '{"key1": "value1"}'
req.headers["content-type"] = "application/json"
- res = req.get_response(self.mware)
+ res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
diff --git a/nova/tests/api/openstack/test_image_metadata.py b/nova/tests/api/openstack/test_image_metadata.py
index d9fb61e2a..56a0932e7 100644
--- a/nova/tests/api/openstack/test_image_metadata.py
+++ b/nova/tests/api/openstack/test_image_metadata.py
@@ -16,10 +16,7 @@
# under the License.
import json
-import stubout
-import unittest
import webob
-import xml.dom.minidom as minidom
from nova import flags
@@ -85,26 +82,15 @@ class ImageMetaDataTest(test.TestCase):
def setUp(self):
super(ImageMetaDataTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- self.orig_image_service = FLAGS.image_service
- FLAGS.image_service = 'nova.image.glance.GlanceImageService'
- fakes.FakeAuthManager.auth_data = {}
- fakes.FakeAuthDatabase.data = {}
- fakes.stub_out_auth(self.stubs)
+ self.flags(image_service='nova.image.glance.GlanceImageService')
# NOTE(dprince) max out properties/metadata in image 3 for testing
img3 = self.IMAGE_FIXTURES[2]
for num in range(FLAGS.quota_metadata_items):
img3['properties']['key%i' % num] = "blah"
fakes.stub_out_glance(self.stubs, self.IMAGE_FIXTURES)
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.image_service = self.orig_image_service
- 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 +100,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 +109,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)
+ 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)
- 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': {
+ '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 +176,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 +184,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 +225,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,141 +233,9 @@ 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"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
-
-
-class ImageMetadataXMLSerializationTest(test.TestCase):
-
- def test_index_xml(self):
- serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
- fixture = {
- 'metadata': {
- 'one': 'two',
- 'three': 'four',
- },
- }
- output = serializer.serialize(fixture, 'index')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
- <meta key="three">
- four
- </meta>
- <meta key="one">
- two
- </meta>
- </metadata>
- """.replace(" ", ""))
-
- self.assertEqual(expected.toxml(), actual.toxml())
-
- def test_index_xml_null(self):
- serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
- fixture = {
- 'metadata': {
- None: None,
- },
- }
- output = serializer.serialize(fixture, 'index')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
- <meta key="None">
- None
- </meta>
- </metadata>
- """.replace(" ", ""))
-
- self.assertEqual(expected.toxml(), actual.toxml())
-
- def test_index_xml_unicode(self):
- serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
- fixture = {
- 'metadata': {
- u'three': u'Jos\xe9',
- },
- }
- output = serializer.serialize(fixture, 'index')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString(u"""
- <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
- <meta key="three">
- Jos\xe9
- </meta>
- </metadata>
- """.encode("UTF-8").replace(" ", ""))
-
- self.assertEqual(expected.toxml(), actual.toxml())
-
- def test_show_xml(self):
- serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
- fixture = {
- 'meta': {
- 'one': 'two',
- },
- }
- output = serializer.serialize(fixture, 'show')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one">
- two
- </meta>
- """.replace(" ", ""))
-
- self.assertEqual(expected.toxml(), actual.toxml())
-
- def test_update_item_xml(self):
- serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
- fixture = {
- 'meta': {
- 'one': 'two',
- },
- }
- output = serializer.serialize(fixture, 'update')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one">
- two
- </meta>
- """.replace(" ", ""))
-
- self.assertEqual(expected.toxml(), actual.toxml())
-
- def test_create_xml(self):
- serializer = openstack.image_metadata.ImageMetadataXMLSerializer()
- fixture = {
- 'metadata': {
- 'key9': 'value9',
- 'key2': 'value2',
- 'key1': 'value1',
- },
- }
- output = serializer.serialize(fixture, 'create')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
- <meta key="key2">
- value2
- </meta>
- <meta key="key9">
- value9
- </meta>
- <meta key="key1">
- value1
- </meta>
- </metadata>
- """.replace(" ", ""))
-
- self.assertEqual(expected.toxml(), actual.toxml())
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index 534460d46..8e2e3f390 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -34,7 +34,6 @@ import webob
from glance import client as glance_client
from nova import context
from nova import exception
-from nova import flags
from nova import test
from nova import utils
import nova.api.openstack
@@ -42,9 +41,6 @@ from nova.api.openstack import images
from nova.tests.api.openstack import fakes
-FLAGS = flags.FLAGS
-
-
class _BaseImageServiceTests(test.TestCase):
"""Tasks to test for all image services"""
@@ -155,7 +151,7 @@ class GlanceImageServiceTest(_BaseImageServiceTests):
fakes.stub_out_compute_api_snapshot(self.stubs)
service_class = 'nova.image.glance.GlanceImageService'
self.service = utils.import_object(service_class)
- self.context = context.RequestContext(1, None)
+ self.context = context.RequestContext('fake', 'fake')
self.service.delete_all()
self.sent_to_glance = {}
fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance)
@@ -168,7 +164,7 @@ class GlanceImageServiceTest(_BaseImageServiceTests):
"""Ensure instance_id is persisted as an image-property"""
fixture = {'name': 'test image',
'is_public': False,
- 'properties': {'instance_id': '42', 'user_id': '1'}}
+ 'properties': {'instance_id': '42', 'user_id': 'fake'}}
image_id = self.service.create(self.context, fixture)['id']
expected = fixture
@@ -178,7 +174,7 @@ class GlanceImageServiceTest(_BaseImageServiceTests):
expected = {'id': image_id,
'name': 'test image',
'is_public': False,
- 'properties': {'instance_id': '42', 'user_id': '1'}}
+ 'properties': {'instance_id': '42', 'user_id': 'fake'}}
self.assertDictMatch(image_meta, expected)
image_metas = self.service.detail(self.context)
@@ -328,14 +324,10 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
def setUp(self):
"""Run before each test."""
super(ImageControllerWithGlanceServiceTest, self).setUp()
- self.orig_image_service = FLAGS.image_service
- FLAGS.image_service = 'nova.image.glance.GlanceImageService'
+ self.flags(image_service='nova.image.glance.GlanceImageService')
self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
self.fixtures = self._make_image_fixtures()
fakes.stub_out_glance(self.stubs, initial_fixtures=self.fixtures)
@@ -345,14 +337,13 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
def tearDown(self):
"""Run after each test."""
self.stubs.UnsetAll()
- FLAGS.image_service = self.orig_image_service
super(ImageControllerWithGlanceServiceTest, self).tearDown()
def _applicable_fixture(self, fixture, user_id):
"""Determine if this fixture is applicable for given user id."""
is_public = fixture["is_public"]
try:
- uid = int(fixture["properties"]["user_id"])
+ uid = fixture["properties"]["user_id"]
except KeyError:
uid = None
return uid == user_id or is_public
@@ -424,7 +415,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
},
"metadata": {
"instance_ref": "http://localhost/v1.1/servers/42",
- "user_id": "1",
+ "user_id": "fake",
},
"links": [{
"rel": "self",
@@ -538,7 +529,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>
@@ -559,7 +550,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
fixtures = copy.copy(self.fixtures)
for image in fixtures:
- if not self._applicable_fixture(image, 1):
+ if not self._applicable_fixture(image, "fake"):
fixtures.remove(image)
continue
@@ -666,7 +657,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
'name': 'queued snapshot',
'metadata': {
u'instance_ref': u'http://localhost/v1.1/servers/42',
- u'user_id': u'1',
+ u'user_id': u'fake',
},
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
@@ -696,7 +687,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
'name': 'saving snapshot',
'metadata': {
u'instance_ref': u'http://localhost/v1.1/servers/42',
- u'user_id': u'1',
+ u'user_id': u'fake',
},
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
@@ -727,7 +718,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
'name': 'active snapshot',
'metadata': {
u'instance_ref': u'http://localhost/v1.1/servers/42',
- u'user_id': u'1',
+ u'user_id': u'fake',
},
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
@@ -757,7 +748,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
'name': 'killed snapshot',
'metadata': {
u'instance_ref': u'http://localhost/v1.1/servers/42',
- u'user_id': u'1',
+ u'user_id': u'fake',
},
'updated': self.NOW_API_FORMAT,
'created': self.NOW_API_FORMAT,
@@ -803,154 +794,206 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
self.assertDictListMatch(expected, response_list)
def test_image_filter_with_name(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'name': 'testname'}
- image_service.index(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images?name=testname')
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?name=testname')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.index(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_image_filter_with_status(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'status': 'ACTIVE'}
- image_service.index(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images?status=ACTIVE')
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?status=ACTIVE')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.index(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_image_filter_with_property(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'property-test': '3'}
- image_service.index(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images?property-test=3')
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?property-test=3')
+ request.environ['nova.context'] = context
+ controller = images.ControllerV11(image_service=image_service)
+ controller.index(request)
+ self.mox.VerifyAll()
+
+ def test_image_filter_server(self):
+ image_service = self.mox.CreateMockAnything()
+ context = object()
+ # 'server' should be converted to 'property-instance_ref'
+ filters = {'property-instance_ref': 'http://localhost:8774/servers/12'}
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?server='
+ 'http://localhost:8774/servers/12')
+ request.environ['nova.context'] = context
+ controller = images.ControllerV11(image_service=image_service)
+ controller.index(request)
+ self.mox.VerifyAll()
+
+ def test_image_filter_changes_since(self):
+ image_service = self.mox.CreateMockAnything()
+ context = object()
+ filters = {'changes-since': '2011-01-24T17:08Z'}
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?changes-since='
+ '2011-01-24T17:08Z')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.index(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
+
+ def test_image_filter_with_type(self):
+ image_service = self.mox.CreateMockAnything()
+ context = object()
+ filters = {'property-image_type': 'BASE'}
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?type=BASE')
+ request.environ['nova.context'] = context
+ controller = images.ControllerV11(image_service=image_service)
+ controller.index(request)
+ self.mox.VerifyAll()
def test_image_filter_not_supported(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'status': 'ACTIVE'}
- image_service.index(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images?status=ACTIVE&UNSUPPORTEDFILTER=testname')
+ image_service.detail(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images?status=ACTIVE&'
+ 'UNSUPPORTEDFILTER=testname')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
- controller.index(request)
- mocker.VerifyAll()
+ controller.detail(request)
+ self.mox.VerifyAll()
def test_image_no_filters(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {}
image_service.index(
context, filters=filters).AndReturn([])
- mocker.ReplayAll()
+ self.mox.ReplayAll()
request = webob.Request.blank(
'/v1.1/images')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.index(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_image_detail_filter_with_name(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'name': 'testname'}
- image_service.detail(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images/detail?name=testname')
+ image_service.detail(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?name=testname')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.detail(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_image_detail_filter_with_status(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'status': 'ACTIVE'}
- image_service.detail(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images/detail?status=ACTIVE')
+ image_service.detail(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?status=ACTIVE')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.detail(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_image_detail_filter_with_property(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'property-test': '3'}
- image_service.detail(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images/detail?property-test=3')
+ image_service.detail(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?property-test=3')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.detail(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
+
+ def test_image_detail_filter_server(self):
+ image_service = self.mox.CreateMockAnything()
+ context = object()
+ # 'server' should be converted to 'property-instance_ref'
+ filters = {'property-instance_ref': 'http://localhost:8774/servers/12'}
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?server='
+ 'http://localhost:8774/servers/12')
+ request.environ['nova.context'] = context
+ controller = images.ControllerV11(image_service=image_service)
+ controller.index(request)
+ self.mox.VerifyAll()
+
+ def test_image_detail_filter_changes_since(self):
+ image_service = self.mox.CreateMockAnything()
+ context = object()
+ filters = {'changes-since': '2011-01-24T17:08Z'}
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?changes-since='
+ '2011-01-24T17:08Z')
+ request.environ['nova.context'] = context
+ controller = images.ControllerV11(image_service=image_service)
+ controller.index(request)
+ self.mox.VerifyAll()
+
+ def test_image_detail_filter_with_type(self):
+ image_service = self.mox.CreateMockAnything()
+ context = object()
+ filters = {'property-image_type': 'BASE'}
+ image_service.index(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?type=BASE')
+ request.environ['nova.context'] = context
+ controller = images.ControllerV11(image_service=image_service)
+ controller.index(request)
+ self.mox.VerifyAll()
def test_image_detail_filter_not_supported(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {'status': 'ACTIVE'}
- image_service.detail(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images/detail?status=ACTIVE&UNSUPPORTEDFILTER=testname')
+ image_service.detail(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail?status=ACTIVE&'
+ 'UNSUPPORTEDFILTER=testname')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.detail(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_image_detail_no_filters(self):
- mocker = mox.Mox()
- image_service = mocker.CreateMockAnything()
+ image_service = self.mox.CreateMockAnything()
context = object()
filters = {}
- image_service.detail(
- context, filters=filters).AndReturn([])
- mocker.ReplayAll()
- request = webob.Request.blank(
- '/v1.1/images/detail')
+ image_service.detail(context, filters=filters).AndReturn([])
+ self.mox.ReplayAll()
+ request = webob.Request.blank('/v1.1/images/detail')
request.environ['nova.context'] = context
controller = images.ControllerV11(image_service=image_service)
controller.detail(request)
- mocker.VerifyAll()
+ self.mox.VerifyAll()
def test_get_image_found(self):
req = webob.Request.blank('/v1.0/images/123')
@@ -982,6 +1025,9 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
req.headers["content-type"] = "application/json"
response = req.get_response(fakes.wsgi_app())
self.assertEqual(200, response.status_int)
+ image_meta = json.loads(response.body)['image']
+ self.assertEqual(123, image_meta['serverId'])
+ self.assertEqual('Snapshot 1', image_meta['name'])
def test_create_snapshot_no_name(self):
"""Name is required for snapshots"""
@@ -993,82 +1039,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
response = req.get_response(fakes.wsgi_app())
self.assertEqual(400, response.status_int)
- def test_create_backup_no_name(self):
- """Name is also required for backups"""
- body = dict(image=dict(serverId='123', image_type='backup',
- backup_type='daily', rotation=1))
- req = webob.Request.blank('/v1.0/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
- def test_create_backup_with_rotation_and_backup_type(self):
- """The happy path for creating backups
-
- Creating a backup is an admin-only operation, as opposed to snapshots
- which are available to anybody.
- """
- # FIXME(sirp): teardown needed?
- FLAGS.allow_admin_api = True
-
- # FIXME(sirp): should the fact that backups are admin_only be a FLAG
- body = dict(image=dict(serverId='123', image_type='backup',
- name='Backup 1',
- backup_type='daily', rotation=1))
- req = webob.Request.blank('/v1.0/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(200, response.status_int)
-
- def test_create_backup_no_rotation(self):
- """Rotation is required for backup requests"""
- # FIXME(sirp): teardown needed?
- FLAGS.allow_admin_api = True
-
- # FIXME(sirp): should the fact that backups are admin_only be a FLAG
- body = dict(image=dict(serverId='123', name='daily',
- image_type='backup', backup_type='daily'))
- req = webob.Request.blank('/v1.0/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
- def test_create_backup_no_backup_type(self):
- """Backup Type (daily or weekly) is required for backup requests"""
- # FIXME(sirp): teardown needed?
- FLAGS.allow_admin_api = True
-
- # FIXME(sirp): should the fact that backups are admin_only be a FLAG
- body = dict(image=dict(serverId='123', name='daily',
- image_type='backup', rotation=1))
- req = webob.Request.blank('/v1.0/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
- def test_create_image_with_invalid_image_type(self):
- """Valid image_types are snapshot | daily | weekly"""
- # FIXME(sirp): teardown needed?
- FLAGS.allow_admin_api = True
-
- # FIXME(sirp): should the fact that backups are admin_only be a FLAG
- body = dict(image=dict(serverId='123', image_type='monthly',
- rotation=1))
- req = webob.Request.blank('/v1.0/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
def test_create_image_no_server_id(self):
body = dict(image=dict(name='Snapshot 1'))
@@ -1079,113 +1049,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
response = req.get_response(fakes.wsgi_app())
self.assertEqual(400, response.status_int)
- def test_create_image_v1_1(self):
-
- body = dict(image=dict(serverRef='123', name='Snapshot 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(200, response.status_int)
-
- def test_create_image_v1_1_actual_server_ref(self):
-
- serverRef = 'http://localhost/v1.1/servers/1'
- serverBookmark = 'http://localhost/servers/1'
- body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(200, response.status_int)
- result = json.loads(response.body)
- expected = {
- 'id': 1,
- 'links': [
- {
- 'rel': 'self',
- 'href': serverRef,
- },
- {
- 'rel': 'bookmark',
- 'href': serverBookmark,
- },
- ]
- }
- self.assertEqual(result['image']['server'], expected)
-
- def test_create_image_v1_1_actual_server_ref_port(self):
-
- serverRef = 'http://localhost:8774/v1.1/servers/1'
- serverBookmark = 'http://localhost:8774/servers/1'
- body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(200, response.status_int)
- result = json.loads(response.body)
- expected = {
- 'id': 1,
- 'links': [
- {
- 'rel': 'self',
- 'href': serverRef,
- },
- {
- 'rel': 'bookmark',
- 'href': serverBookmark,
- },
- ]
- }
- self.assertEqual(result['image']['server'], expected)
-
- def test_create_image_v1_1_server_ref_bad_hostname(self):
-
- serverRef = 'http://asdf/v1.1/servers/1'
- body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
- def test_create_image_v1_1_no_server_ref(self):
-
- body = dict(image=dict(name='Snapshot 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
- def test_create_image_v1_1_server_ref_missing_version(self):
-
- serverRef = 'http://localhost/servers/1'
- body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
- def test_create_image_v1_1_server_ref_missing_id(self):
-
- serverRef = 'http://localhost/v1.1/servers'
- body = dict(image=dict(serverRef=serverRef, name='Backup 1'))
- req = webob.Request.blank('/v1.1/images')
- req.method = 'POST'
- req.body = json.dumps(body)
- req.headers["content-type"] = "application/json"
- response = req.get_response(fakes.wsgi_app())
- self.assertEqual(400, response.status_int)
-
@classmethod
def _make_image_fixtures(cls):
image_id = 123
@@ -1207,7 +1070,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
# Snapshot for User 1
server_ref = 'http://localhost/v1.1/servers/42'
- snapshot_properties = {'instance_ref': server_ref, 'user_id': '1'}
+ snapshot_properties = {'instance_ref': server_ref, 'user_id': 'fake'}
for status in ('queued', 'saving', 'active', 'killed'):
add_fixture(id=image_id, name='%s snapshot' % status,
is_public=False, status=status,
@@ -1215,7 +1078,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
image_id += 1
# Snapshot for User 2
- other_snapshot_properties = {'instance_id': '43', 'user_id': '2'}
+ other_snapshot_properties = {'instance_id': '43', 'user_id': 'other'}
add_fixture(id=image_id, name='someone elses snapshot',
is_public=False, status='active',
properties=other_snapshot_properties)
@@ -1664,76 +1527,3 @@ class ImageXMLSerializationTest(test.TestCase):
""".replace(" ", "") % (locals()))
self.assertEqual(expected.toxml(), actual.toxml())
-
- def test_create(self):
- serializer = images.ImageXMLSerializer()
-
- fixture = {
- 'image': {
- 'id': 1,
- 'name': 'Image1',
- 'created': self.TIMESTAMP,
- 'updated': self.TIMESTAMP,
- 'status': 'SAVING',
- 'progress': 80,
- 'server': {
- 'id': 1,
- 'links': [
- {
- 'href': self.SERVER_HREF,
- 'rel': 'self',
- },
- {
- 'href': self.SERVER_BOOKMARK,
- 'rel': 'bookmark',
- },
- ],
- },
- 'metadata': {
- 'key1': 'value1',
- },
- 'links': [
- {
- 'href': self.IMAGE_HREF % 1,
- 'rel': 'self',
- },
- {
- 'href': self.IMAGE_BOOKMARK % 1,
- 'rel': 'bookmark',
- },
- ],
- },
- }
-
- output = serializer.serialize(fixture, 'create')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected_server_href = self.SERVER_HREF
- expected_server_bookmark = self.SERVER_BOOKMARK
- expected_href = self.IMAGE_HREF % 1
- expected_bookmark = self.IMAGE_BOOKMARK % 1
- expected_now = self.TIMESTAMP
- expected = minidom.parseString("""
- <image id="1"
- xmlns="http://docs.openstack.org/compute/api/v1.1"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Image1"
- updated="%(expected_now)s"
- created="%(expected_now)s"
- status="SAVING"
- progress="80">
- <server id="1">
- <atom:link rel="self" href="%(expected_server_href)s"/>
- <atom:link rel="bookmark" href="%(expected_server_bookmark)s"/>
- </server>
- <metadata>
- <meta key="key1">
- value1
- </meta>
- </metadata>
- <atom:link href="%(expected_href)s" rel="self"/>
- <atom:link href="%(expected_bookmark)s" rel="bookmark"/>
- </image>
- """.replace(" ", "") % (locals()))
-
- self.assertEqual(expected.toxml(), actual.toxml())
diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py
index 76363450d..6c3d531e3 100644
--- a/nova/tests/api/openstack/test_limits.py
+++ b/nova/tests/api/openstack/test_limits.py
@@ -24,11 +24,12 @@ import stubout
import time
import unittest
import webob
-
-from xml.dom.minidom import parseString
+from xml.dom import minidom
import nova.context
from nova.api.openstack import limits
+from nova.api.openstack import views
+from nova import test
TEST_LIMITS = [
@@ -166,7 +167,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite):
request = self._get_index_request("application/xml")
response = request.get_response(self.controller)
- expected = parseString("""
+ expected = minidom.parseString("""
<limits
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
<rate/>
@@ -174,7 +175,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite):
</limits>
""".replace(" ", ""))
- body = parseString(response.body.replace(" ", ""))
+ body = minidom.parseString(response.body.replace(" ", ""))
self.assertEqual(expected.toxml(), body.toxml())
@@ -184,7 +185,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite):
request = self._populate_limits(request)
response = request.get_response(self.controller)
- expected = parseString("""
+ expected = minidom.parseString("""
<limits
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
<rate>
@@ -196,7 +197,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite):
<absolute/>
</limits>
""".replace(" ", ""))
- body = parseString(response.body.replace(" ", ""))
+ body = minidom.parseString(response.body.replace(" ", ""))
self.assertEqual(expected.toxml(), body.toxml())
@@ -210,6 +211,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite):
"""Run before each test."""
BaseLimitTestSuite.setUp(self)
self.controller = limits.create_resource('1.1')
+ self.maxDiff = None
def _get_index_request(self, accept_header="application/json"):
"""Helper to set routing arguments."""
@@ -266,14 +268,14 @@ class LimitsControllerV11Test(BaseLimitTestSuite):
"limit": [
{
"verb": "GET",
- "next-available": 0,
+ "next-available": "1970-01-01T00:00:00Z",
"unit": "MINUTE",
"value": 10,
"remaining": 10,
},
{
"verb": "POST",
- "next-available": 0,
+ "next-available": "1970-01-01T00:00:00Z",
"unit": "HOUR",
"value": 5,
"remaining": 5,
@@ -286,7 +288,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite):
"limit": [
{
"verb": "GET",
- "next-available": 0,
+ "next-available": "1970-01-01T00:00:00Z",
"unit": "MINUTE",
"value": 5,
"remaining": 5,
@@ -328,7 +330,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite):
"limit": [
{
"verb": "GET",
- "next-available": 0,
+ "next-available": "1970-01-01T00:00:00Z",
"unit": "MINUTE",
"value": 10,
"remaining": 10,
@@ -341,7 +343,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite):
"limit": [
{
"verb": "GET",
- "next-available": 0,
+ "next-available": "1970-01-01T00:00:00Z",
"unit": "MINUTE",
"value": 10,
"remaining": 10,
@@ -458,7 +460,7 @@ class LimitMiddlewareTest(BaseLimitTestSuite):
response = request.get_response(self.app)
self.assertEqual(response.status_int, 403)
- root = parseString(response.body).childNodes[0]
+ root = minidom.parseString(response.body).childNodes[0]
expected = "Only 1 GET request(s) can be made to * every minute."
details = root.getElementsByTagName("details")
@@ -904,3 +906,195 @@ class WsgiLimiterProxyTest(BaseLimitTestSuite):
"made to /delayed every minute.")
self.assertEqual((delay, error), expected)
+
+
+class LimitsViewBuilderV11Test(test.TestCase):
+
+ def setUp(self):
+ self.view_builder = views.limits.ViewBuilderV11()
+ self.rate_limits = [
+ {
+ "URI": "*",
+ "regex": ".*",
+ "value": 10,
+ "verb": "POST",
+ "remaining": 2,
+ "unit": "MINUTE",
+ "resetTime": 1311272226,
+ },
+ {
+ "URI": "*/servers",
+ "regex": "^/servers",
+ "value": 50,
+ "verb": "POST",
+ "remaining": 10,
+ "unit": "DAY",
+ "resetTime": 1311272226,
+ },
+ ]
+ self.absolute_limits = {
+ "metadata_items": 1,
+ "injected_files": 5,
+ "injected_file_content_bytes": 5,
+ }
+
+ def tearDown(self):
+ pass
+
+ def test_build_limits(self):
+ expected_limits = {
+ "limits": {
+ "rate": [
+ {
+ "uri": "*",
+ "regex": ".*",
+ "limit": [
+ {
+ "value": 10,
+ "verb": "POST",
+ "remaining": 2,
+ "unit": "MINUTE",
+ "next-available": "2011-07-21T18:17:06Z",
+ },
+ ]
+ },
+ {
+ "uri": "*/servers",
+ "regex": "^/servers",
+ "limit": [
+ {
+ "value": 50,
+ "verb": "POST",
+ "remaining": 10,
+ "unit": "DAY",
+ "next-available": "2011-07-21T18:17:06Z",
+ },
+ ]
+ },
+ ],
+ "absolute": {
+ "maxServerMeta": 1,
+ "maxImageMeta": 1,
+ "maxPersonality": 5,
+ "maxPersonalitySize": 5
+ }
+ }
+ }
+
+ output = self.view_builder.build(self.rate_limits,
+ self.absolute_limits)
+ self.assertDictMatch(output, expected_limits)
+
+ def test_build_limits_empty_limits(self):
+ expected_limits = {
+ "limits": {
+ "rate": [],
+ "absolute": {},
+ }
+ }
+
+ abs_limits = {}
+ rate_limits = []
+ output = self.view_builder.build(rate_limits, abs_limits)
+ self.assertDictMatch(output, expected_limits)
+
+
+class LimitsXMLSerializationTest(test.TestCase):
+
+ def setUp(self):
+ self.maxDiff = None
+
+ def tearDown(self):
+ pass
+
+ def test_index(self):
+ serializer = limits.LimitsXMLSerializer()
+
+ fixture = {
+ "limits": {
+ "rate": [
+ {
+ "uri": "*",
+ "regex": ".*",
+ "limit": [
+ {
+ "value": 10,
+ "verb": "POST",
+ "remaining": 2,
+ "unit": "MINUTE",
+ "next-available": "2011-12-15T22:42:45Z",
+ },
+ ]
+ },
+ {
+ "uri": "*/servers",
+ "regex": "^/servers",
+ "limit": [
+ {
+ "value": 50,
+ "verb": "POST",
+ "remaining": 10,
+ "unit": "DAY",
+ "next-available": "2011-12-15T22:42:45Z"
+ },
+ ]
+ },
+ ],
+ "absolute": {
+ "maxServerMeta": 1,
+ "maxImageMeta": 1,
+ "maxPersonality": 5,
+ "maxPersonalitySize": 10240
+ }
+ }
+ }
+
+ output = serializer.serialize(fixture, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <limits xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <rates>
+ <rate uri="*" regex=".*">
+ <limit value="10" verb="POST" remaining="2"
+ unit="MINUTE"
+ next-available="2011-12-15T22:42:45Z"/>
+ </rate>
+ <rate uri="*/servers" regex="^/servers">
+ <limit value="50" verb="POST" remaining="10"
+ unit="DAY"
+ next-available="2011-12-15T22:42:45Z"/>
+ </rate>
+ </rates>
+ <absolute>
+ <limit name="maxServerMeta" value="1"/>
+ <limit name="maxPersonality" value="5"/>
+ <limit name="maxImageMeta" value="1"/>
+ <limit name="maxPersonalitySize" value="10240"/>
+ </absolute>
+ </limits>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_index_no_limits(self):
+ serializer = limits.LimitsXMLSerializer()
+
+ fixture = {
+ "limits": {
+ "rate": [],
+ "absolute": {},
+ }
+ }
+
+ output = serializer.serialize(fixture, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <limits xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <rates />
+ <absolute />
+ </limits>
+ """.replace(" ", ""))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py
new file mode 100644
index 000000000..7e24d24fd
--- /dev/null
+++ b/nova/tests/api/openstack/test_server_actions.py
@@ -0,0 +1,1019 @@
+import base64
+import json
+import unittest
+from xml.dom import minidom
+
+import stubout
+import webob
+
+from nova import context
+from nova import db
+from nova import utils
+from nova.api.openstack import create_instance_helper
+from nova.compute import instance_types
+from nova.compute import power_state
+import nova.db.api
+from nova import test
+from nova.tests.api.openstack import common
+from nova.tests.api.openstack import fakes
+
+
+def return_server_by_id(context, id):
+ return _get_instance()
+
+
+def instance_update(context, instance_id, kwargs):
+ return _get_instance()
+
+
+def return_server_with_power_state(power_state):
+ def _return_server(context, id):
+ instance = _get_instance()
+ instance['state'] = power_state
+ return instance
+ return _return_server
+
+
+def return_server_with_uuid_and_power_state(power_state):
+ def _return_server(context, id):
+ return return_server_with_power_state(power_state)
+ return _return_server
+
+
+class MockSetAdminPassword(object):
+ def __init__(self):
+ self.instance_id = None
+ self.password = None
+
+ def __call__(self, context, instance_id, password):
+ self.instance_id = instance_id
+ self.password = password
+
+
+def _get_instance():
+ instance = {
+ "id": 1,
+ "created_at": "2010-10-10 12:00:00",
+ "updated_at": "2010-11-11 11:00:00",
+ "admin_pass": "",
+ "user_id": "",
+ "project_id": "",
+ "image_ref": "5",
+ "kernel_id": "",
+ "ramdisk_id": "",
+ "launch_index": 0,
+ "key_name": "",
+ "key_data": "",
+ "state": 0,
+ "state_description": "",
+ "memory_mb": 0,
+ "vcpus": 0,
+ "local_gb": 0,
+ "hostname": "",
+ "host": "",
+ "instance_type": {
+ "flavorid": 1,
+ },
+ "user_data": "",
+ "reservation_id": "",
+ "mac_address": "",
+ "scheduled_at": utils.utcnow(),
+ "launched_at": utils.utcnow(),
+ "terminated_at": utils.utcnow(),
+ "availability_zone": "",
+ "display_name": "test_server",
+ "display_description": "",
+ "locked": False,
+ "metadata": [],
+ #"address": ,
+ #"floating_ips": [{"address":ip} for ip in public_addresses]}
+ "uuid": "deadbeef-feed-edee-beef-d0ea7beefedd"}
+
+ return instance
+
+
+class ServerActionsTest(test.TestCase):
+
+ def setUp(self):
+ self.maxDiff = None
+ super(ServerActionsTest, self).setUp()
+ self.flags(verbose=True)
+ self.stubs = stubout.StubOutForTesting()
+ fakes.FakeAuthManager.reset_fake_data()
+ fakes.FakeAuthDatabase.data = {}
+ fakes.stub_out_auth(self.stubs)
+ self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
+ self.stubs.Set(nova.db.api, 'instance_update', instance_update)
+
+ self.webreq = common.webob_factory('/v1.0/servers')
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+
+ def test_server_change_password(self):
+ body = {'changePassword': {'adminPass': '1234pass'}}
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 501)
+
+ def test_server_change_password_xml(self):
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/xml'
+ req.body = '<changePassword adminPass="1234pass">'
+# res = req.get_response(fakes.wsgi_app())
+# self.assertEqual(res.status_int, 501)
+
+ def test_server_reboot(self):
+ body = dict(server=dict(
+ name='server_test', imageId=2, flavorId=2, metadata={},
+ personality={}))
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+
+ def test_server_rebuild_accepted(self):
+ body = {
+ "rebuild": {
+ "imageId": 2,
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(res.body, "")
+
+ def test_server_rebuild_rejected_when_building(self):
+ body = {
+ "rebuild": {
+ "imageId": 2,
+ },
+ }
+
+ state = power_state.BUILDING
+ new_return_server = return_server_with_power_state(state)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ self.stubs.Set(nova.db, 'instance_get_by_uuid',
+ return_server_with_uuid_and_power_state(state))
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 409)
+
+ def test_server_rebuild_bad_entity(self):
+ body = {
+ "rebuild": {
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_resize_server(self):
+ req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
+
+ self.resize_called = False
+
+ def resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.resize_called, True)
+
+ def test_resize_bad_flavor_fails(self):
+ req = self.webreq('/1/action', 'POST', dict(resize=dict(derp=3)))
+
+ self.resize_called = False
+
+ def resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+ self.assertEqual(self.resize_called, False)
+
+ def test_resize_raises_fails(self):
+ req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
+
+ def resize_mock(*args):
+ raise Exception('hurr durr')
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 500)
+
+ def test_resized_server_has_correct_status(self):
+ req = self.webreq('/1', 'GET')
+
+ def fake_migration_get(*args):
+ return {}
+
+ self.stubs.Set(nova.db, 'migration_get_by_instance_and_status',
+ fake_migration_get)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ body = json.loads(res.body)
+ self.assertEqual(body['server']['status'], 'RESIZE-CONFIRM')
+
+ def test_confirm_resize_server(self):
+ req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
+
+ self.resize_called = False
+
+ def confirm_resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'confirm_resize',
+ confirm_resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 204)
+ self.assertEqual(self.resize_called, True)
+
+ def test_confirm_resize_server_fails(self):
+ req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
+
+ def confirm_resize_mock(*args):
+ raise Exception('hurr durr')
+
+ self.stubs.Set(nova.compute.api.API, 'confirm_resize',
+ confirm_resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_revert_resize_server(self):
+ req = self.webreq('/1/action', 'POST', dict(revertResize=None))
+
+ self.resize_called = False
+
+ def revert_resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'revert_resize',
+ revert_resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.resize_called, True)
+
+ def test_revert_resize_server_fails(self):
+ req = self.webreq('/1/action', 'POST', dict(revertResize=None))
+
+ def revert_resize_mock(*args):
+ raise Exception('hurr durr')
+
+ self.stubs.Set(nova.compute.api.API, 'revert_resize',
+ revert_resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_migrate_server(self):
+ """This is basically the same as resize, only we provide the `migrate`
+ attribute in the body's dict.
+ """
+ req = self.webreq('/1/migrate', 'POST')
+
+ self.resize_called = False
+
+ def resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.resize_called, True)
+
+ def test_create_backup(self):
+ """The happy path for creating backups"""
+ self.flags(allow_admin_api=True)
+
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'backup_type': 'daily',
+ 'rotation': 1,
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(202, response.status_int)
+ self.assertTrue(response.headers['Location'])
+
+ def test_create_backup_admin_api_off(self):
+ """The happy path for creating backups"""
+ self.flags(allow_admin_api=False)
+
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'backup_type': 'daily',
+ 'rotation': 1,
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(501, response.status_int)
+
+ def test_create_backup_with_metadata(self):
+ self.flags(allow_admin_api=True)
+
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'backup_type': 'daily',
+ 'rotation': 1,
+ 'metadata': {'123': 'asdf'},
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(202, response.status_int)
+ self.assertTrue(response.headers['Location'])
+
+ def test_create_backup_no_name(self):
+ """Name is required for backups"""
+ self.flags(allow_admin_api=True)
+
+ body = {
+ 'createBackup': {
+ 'backup_type': 'daily',
+ 'rotation': 1,
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
+ def test_create_backup_no_rotation(self):
+ """Rotation is required for backup requests"""
+ self.flags(allow_admin_api=True)
+
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'backup_type': 'daily',
+ },
+ }
+
+ req = webob.Request.blank('/v1.0/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
+ def test_create_backup_no_backup_type(self):
+ """Backup Type (daily or weekly) is required for backup requests"""
+ self.flags(allow_admin_api=True)
+
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'rotation': 1,
+ },
+ }
+ req = webob.Request.blank('/v1.0/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
+ def test_create_backup_bad_entity(self):
+ self.flags(allow_admin_api=True)
+
+ body = {'createBackup': 'go'}
+ req = webob.Request.blank('/v1.0/images')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
+
+class ServerActionsTestV11(test.TestCase):
+
+ def setUp(self):
+ self.maxDiff = None
+ super(ServerActionsTestV11, self).setUp()
+ self.stubs = stubout.StubOutForTesting()
+ fakes.FakeAuthManager.reset_fake_data()
+ fakes.FakeAuthDatabase.data = {}
+ fakes.stub_out_auth(self.stubs)
+ self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
+ self.stubs.Set(nova.db.api, 'instance_update', instance_update)
+
+ fakes.stub_out_glance(self.stubs)
+ fakes.stub_out_compute_api_snapshot(self.stubs)
+ service_class = 'nova.image.glance.GlanceImageService'
+ self.service = utils.import_object(service_class)
+ self.context = context.RequestContext(1, None)
+ self.service.delete_all()
+ self.sent_to_glance = {}
+ fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance)
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+
+ def test_server_change_password(self):
+ mock_method = MockSetAdminPassword()
+ self.stubs.Set(nova.compute.api.API, 'set_admin_password', mock_method)
+ body = {'changePassword': {'adminPass': '1234pass'}}
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(mock_method.instance_id, '1')
+ self.assertEqual(mock_method.password, '1234pass')
+
+ def test_server_change_password_xml(self):
+ mock_method = MockSetAdminPassword()
+ self.stubs.Set(nova.compute.api.API, 'set_admin_password', mock_method)
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = "application/xml"
+ req.body = """<?xml version="1.0" encoding="UTF-8"?>
+ <changePassword
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ adminPass="1234pass"/>"""
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(mock_method.instance_id, '1')
+ self.assertEqual(mock_method.password, '1234pass')
+
+ def test_server_change_password_not_a_string(self):
+ body = {'changePassword': {'adminPass': 1234}}
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_change_password_bad_request(self):
+ body = {'changePassword': {'pass': '12345'}}
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_change_password_empty_string(self):
+ body = {'changePassword': {'adminPass': ''}}
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_change_password_none(self):
+ body = {'changePassword': {'adminPass': None}}
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_reboot_hard(self):
+ body = dict(reboot=dict(type="HARD"))
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_server_reboot_soft(self):
+ body = dict(reboot=dict(type="SOFT"))
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_server_reboot_incorrect_type(self):
+ body = dict(reboot=dict(type="NOT_A_TYPE"))
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_reboot_missing_type(self):
+ body = dict(reboot=dict())
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_accepted_minimum(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_server_rebuild_rejected_when_building(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ },
+ }
+
+ state = power_state.BUILDING
+ new_return_server = return_server_with_power_state(state)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+ self.stubs.Set(nova.db, 'instance_get_by_uuid',
+ return_server_with_uuid_and_power_state(state))
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 409)
+
+ def test_server_rebuild_accepted_with_metadata(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "metadata": {
+ "new": "metadata",
+ },
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_server_rebuild_accepted_with_bad_metadata(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "metadata": "stack",
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_bad_entity(self):
+ body = {
+ "rebuild": {
+ "imageId": 2,
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_bad_personality(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "personality": [{
+ "path": "/path/to/file",
+ "contents": "INVALID b64",
+ }]
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_server_rebuild_personality(self):
+ body = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/2",
+ "personality": [{
+ "path": "/path/to/file",
+ "contents": base64.b64encode("Test String"),
+ }]
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.content_type = 'application/json'
+ req.body = json.dumps(body)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+
+ def test_resize_server(self):
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.content_type = 'application/json'
+ req.method = 'POST'
+ body_dict = dict(resize=dict(flavorRef="http://localhost/3"))
+ req.body = json.dumps(body_dict)
+
+ self.resize_called = False
+
+ def resize_mock(*args):
+ self.resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.resize_called, True)
+
+ def test_resize_server_no_flavor(self):
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.content_type = 'application/json'
+ req.method = 'POST'
+ body_dict = dict(resize=dict())
+ req.body = json.dumps(body_dict)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_resize_server_no_flavor_ref(self):
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.content_type = 'application/json'
+ req.method = 'POST'
+ body_dict = dict(resize=dict(flavorRef=None))
+ req.body = json.dumps(body_dict)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
+ def test_confirm_resize_server(self):
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.content_type = 'application/json'
+ req.method = 'POST'
+ body_dict = dict(confirmResize=None)
+ req.body = json.dumps(body_dict)
+
+ self.confirm_resize_called = False
+
+ def cr_mock(*args):
+ self.confirm_resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'confirm_resize', cr_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 204)
+ self.assertEqual(self.confirm_resize_called, True)
+
+ def test_revert_resize_server(self):
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.content_type = 'application/json'
+ req.method = 'POST'
+ body_dict = dict(revertResize=None)
+ req.body = json.dumps(body_dict)
+
+ self.revert_resize_called = False
+
+ def revert_mock(*args):
+ self.revert_resize_called = True
+
+ self.stubs.Set(nova.compute.api.API, 'revert_resize', revert_mock)
+
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 202)
+ self.assertEqual(self.revert_resize_called, True)
+
+ def test_create_image(self):
+ body = {
+ 'createImage': {
+ 'name': 'Snapshot 1',
+ },
+ }
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(202, response.status_int)
+ location = response.headers['Location']
+ self.assertEqual('http://localhost/v1.1/images/123', location)
+
+ def test_create_image_with_metadata(self):
+ body = {
+ 'createImage': {
+ 'name': 'Snapshot 1',
+ 'metadata': {'key': 'asdf'},
+ },
+ }
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(202, response.status_int)
+ location = response.headers['Location']
+ self.assertEqual('http://localhost/v1.1/images/123', location)
+
+ def test_create_image_no_name(self):
+ body = {
+ 'createImage': {},
+ }
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
+ def test_create_image_bad_metadata(self):
+ body = {
+ 'createImage': {
+ 'name': 'geoff',
+ 'metadata': 'henry',
+ },
+ }
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, response.status_int)
+
+ def test_create_backup(self):
+ """The happy path for creating backups"""
+ self.flags(allow_admin_api=True)
+
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'backup_type': 'daily',
+ 'rotation': 1,
+ },
+ }
+
+ req = webob.Request.blank('/v1.1/servers/1/action')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+ response = req.get_response(fakes.wsgi_app())
+ self.assertEqual(202, response.status_int)
+ self.assertTrue(response.headers['Location'])
+
+
+class TestServerActionXMLDeserializerV11(test.TestCase):
+
+ def setUp(self):
+ self.deserializer = create_instance_helper.ServerXMLDeserializerV11()
+
+ def tearDown(self):
+ pass
+
+ def test_create_image(self):
+ serial_request = """
+<createImage xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"/>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "createImage": {
+ "name": "new-server-test",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_create_image_with_metadata(self):
+ serial_request = """
+<createImage xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test">
+ <metadata>
+ <meta key="key1">value1</meta>
+ </metadata>
+</createImage>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "createImage": {
+ "name": "new-server-test",
+ "metadata": {"key1": "value1"},
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_change_pass(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <changePassword
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ adminPass="1234pass"/> """
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "changePassword": {
+ "adminPass": "1234pass",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_change_pass_no_pass(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <changePassword
+ xmlns="http://docs.openstack.org/compute/api/v1.1"/> """
+ self.assertRaises(AttributeError,
+ self.deserializer.deserialize,
+ serial_request,
+ 'action')
+
+ def test_reboot(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <reboot
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ type="HARD"/>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "reboot": {
+ "type": "HARD",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_reboot_no_type(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <reboot
+ xmlns="http://docs.openstack.org/compute/api/v1.1"/>"""
+ self.assertRaises(AttributeError,
+ self.deserializer.deserialize,
+ serial_request,
+ 'action')
+
+ def test_resize(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <resize
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ flavorRef="http://localhost/flavors/3"/>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "resize": {
+ "flavorRef": "http://localhost/flavors/3"
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_resize_no_flavor_ref(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <resize
+ xmlns="http://docs.openstack.org/compute/api/v1.1"/>"""
+ self.assertRaises(AttributeError,
+ self.deserializer.deserialize,
+ serial_request,
+ 'action')
+
+ def test_confirm_resize(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <confirmResize
+ xmlns="http://docs.openstack.org/compute/api/v1.1"/>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "confirmResize": None,
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_revert_resize(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <revertResize
+ xmlns="http://docs.openstack.org/compute/api/v1.1"/>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "revertResize": None,
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_rebuild(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <rebuild
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="http://localhost/images/1">
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <personality>
+ <file path="/etc/banner.txt">Mg==</file>
+ </personality>
+ </rebuild>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "rebuild": {
+ "name": "new-server-test",
+ "imageRef": "http://localhost/images/1",
+ "metadata": {
+ "My Server Name": "Apache1",
+ },
+ "personality": [
+ {"path": "/etc/banner.txt", "contents": "Mg=="},
+ ],
+ },
+ }
+ self.assertDictMatch(request['body'], expected)
+
+ def test_rebuild_minimum(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <rebuild
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ imageRef="http://localhost/images/1"/>"""
+ request = self.deserializer.deserialize(serial_request, 'action')
+ expected = {
+ "rebuild": {
+ "imageRef": "http://localhost/images/1",
+ },
+ }
+ self.assertDictMatch(request['body'], expected)
+
+ def test_rebuild_no_imageRef(self):
+ serial_request = """<?xml version="1.0" encoding="UTF-8"?>
+ <rebuild
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test">
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <personality>
+ <file path="/etc/banner.txt">Mg==</file>
+ </personality>
+ </rebuild>"""
+ self.assertRaises(AttributeError,
+ self.deserializer.deserialize,
+ serial_request,
+ 'action')
diff --git a/nova/tests/api/openstack/test_server_metadata.py b/nova/tests/api/openstack/test_server_metadata.py
index 0431e68d2..08a6a062a 100644
--- a/nova/tests/api/openstack/test_server_metadata.py
+++ b/nova/tests/api/openstack/test_server_metadata.py
@@ -16,14 +16,12 @@
# under the License.
import json
-import stubout
-import unittest
import webob
-
+from xml.dom import minidom
from nova import exception
from nova import flags
-from nova.api import openstack
+from nova import test
from nova.tests.api.openstack import fakes
import nova.wsgi
@@ -53,11 +51,10 @@ def delete_server_metadata(context, server_id, key):
def stub_server_metadata():
metadata = {
- "key1": "value1",
- "key2": "value2",
- "key3": "value3",
- "key4": "value4",
- "key5": "value5"}
+ "key1": "value1",
+ "key2": "value2",
+ "key3": "value3",
+ }
return metadata
@@ -76,89 +73,130 @@ def return_server_nonexistant(context, server_id):
raise exception.InstanceNotFound()
-class ServerMetaDataTest(unittest.TestCase):
+class ServerMetaDataTest(test.TestCase):
def setUp(self):
super(ServerMetaDataTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.auth_data = {}
- fakes.FakeAuthDatabase.data = {}
- fakes.stub_out_auth(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
self.stubs.Set(nova.db.api, 'instance_get', return_server)
- def tearDown(self):
- self.stubs.UnsetAll()
- super(ServerMetaDataTest, self).tearDown()
-
def test_index(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
return_server_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
res = req.get_response(fakes.wsgi_app())
- res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
self.assertEqual('application/json', res.headers['Content-Type'])
- self.assertEqual('value1', res_dict['metadata']['key1'])
+ expected = {
+ 'metadata': {
+ 'key1': 'value1',
+ 'key2': 'value2',
+ 'key3': 'value3',
+ },
+ }
+ self.assertEqual(expected, res_dict)
+
+ def test_index_xml(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_get',
+ return_server_metadata)
+ request = webob.Request.blank("/v1.1/servers/1/metadata")
+ request.accept = "application/xml"
+ response = request.get_response(fakes.wsgi_app())
+ self.assertEqual(200, response.status_int)
+ self.assertEqual("application/xml", response.content_type)
+
+ actual_metadata = minidom.parseString(response.body.replace(" ", ""))
+
+ expected_metadata = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="key3">value3</meta>
+ <meta key="key2">value2</meta>
+ <meta key="key1">value1</meta>
+ </metadata>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected_metadata.toxml(), actual_metadata.toxml())
def test_index_nonexistant_server(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant)
- req = webob.Request.blank('/v1.1/servers/1/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
def test_index_no_data(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
return_empty_server_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
res = req.get_response(fakes.wsgi_app())
- res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
- self.assertEqual('application/json', res.headers['Content-Type'])
- self.assertEqual(0, len(res_dict['metadata']))
+ res_dict = json.loads(res.body)
+ expected = {'metadata': {}}
+ self.assertEqual(expected, res_dict)
def test_show(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
return_server_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/key5')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key2')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(200, res.status_int)
- self.assertEqual('application/json', res.headers['Content-Type'])
- self.assertEqual('value5', res_dict['key5'])
+ expected = {'meta': {'key2': 'value2'}}
+ self.assertEqual(expected, res_dict)
+
+ def test_show_xml(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_get',
+ return_server_metadata)
+ request = webob.Request.blank("/v1.1/servers/1/metadata/key2")
+ request.accept = "application/xml"
+ response = request.get_response(fakes.wsgi_app())
+ self.assertEqual(200, response.status_int)
+ self.assertEqual("application/xml", response.content_type)
+
+ actual_metadata = minidom.parseString(response.body.replace(" ", ""))
+
+ expected_metadata = minidom.parseString("""
+ <meta xmlns="http://docs.openstack.org/compute/api/v1.1"
+ key="key2">value2</meta>
+ """.replace(" ", "").replace("\n", ""))
+
+ self.assertEqual(expected_metadata.toxml(), actual_metadata.toxml())
def test_show_nonexistant_server(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant)
- req = webob.Request.blank('/v1.1/servers/1/meta/key5')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key2')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
def test_show_meta_not_found(self):
self.stubs.Set(nova.db.api, 'instance_metadata_get',
return_empty_server_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/key6')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key6')
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
def test_delete(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_get',
+ return_server_metadata)
self.stubs.Set(nova.db.api, 'instance_metadata_delete',
delete_server_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/key5')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key2')
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_nonexistant_server(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant)
- req = webob.Request.blank('/v1.1/servers/1/meta/key5')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
+ req.method = 'DELETE'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(404, res.status_int)
+
+ def test_delete_meta_not_found(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_get',
+ return_empty_server_metadata)
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key6')
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
@@ -166,22 +204,45 @@ class ServerMetaDataTest(unittest.TestCase):
def test_create(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
req.method = 'POST'
- req.body = '{"metadata": {"key1": "value1"}}'
- req.headers["content-type"] = "application/json"
+ req.content_type = "application/json"
+ expected = {"metadata": {"key1": "value1"}}
+ req.body = json.dumps(expected)
res = req.get_response(fakes.wsgi_app())
+
self.assertEqual(200, res.status_int)
res_dict = json.loads(res.body)
- self.assertEqual('application/json', res.headers['Content-Type'])
- self.assertEqual('value1', res_dict['metadata']['key1'])
+ self.assertEqual(expected, res_dict)
+
+ def test_create_xml(self):
+ self.stubs.Set(nova.db.api, "instance_metadata_update_or_create",
+ return_create_instance_metadata)
+ req = webob.Request.blank("/v1.1/servers/1/metadata")
+ req.method = "POST"
+ req.content_type = "application/xml"
+ req.accept = "application/xml"
+
+ request_metadata = minidom.parseString("""
+ <metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <meta key="key3">value3</meta>
+ <meta key="key2">value2</meta>
+ <meta key="key1">value1</meta>
+ </metadata>
+ """.replace(" ", "").replace("\n", ""))
+
+ req.body = str(request_metadata.toxml())
+ response = req.get_response(fakes.wsgi_app())
+
+ self.assertEqual(200, response.status_int)
+ actual_metadata = minidom.parseString(response.body)
+
+ self.assertEqual(request_metadata.toxml(), actual_metadata.toxml())
def test_create_empty_body(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
req.method = 'POST'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
@@ -189,34 +250,112 @@ class ServerMetaDataTest(unittest.TestCase):
def test_create_nonexistant_server(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant)
- req = webob.Request.blank('/v1.1/servers/100/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/100/metadata')
req.method = 'POST'
req.body = '{"metadata": {"key1": "value1"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
+ def test_update_all(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata)
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
+ req.method = 'PUT'
+ req.content_type = "application/json"
+ expected = {
+ 'metadata': {
+ 'key10': 'value10',
+ 'key99': 'value99',
+ },
+ }
+ req.body = json.dumps(expected)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual(expected, res_dict)
+
+ def test_update_all_empty_container(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata)
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
+ req.method = 'PUT'
+ req.content_type = "application/json"
+ expected = {'metadata': {}}
+ req.body = json.dumps(expected)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual(expected, res_dict)
+
+ def test_update_all_malformed_container(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata)
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
+ req.method = 'PUT'
+ req.content_type = "application/json"
+ expected = {'meta': {}}
+ req.body = json.dumps(expected)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_update_all_malformed_data(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata)
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
+ req.method = 'PUT'
+ req.content_type = "application/json"
+ expected = {'metadata': ['asdf']}
+ req.body = json.dumps(expected)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_update_all_nonexistant_server(self):
+ self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant)
+ req = webob.Request.blank('/v1.1/servers/100/metadata')
+ req.method = 'PUT'
+ req.content_type = "application/json"
+ req.body = json.dumps({'metadata': {'key10': 'value10'}})
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(404, res.status_int)
+
def test_update_item(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/key1')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
req.method = 'PUT'
- req.body = '{"key1": "value1"}'
+ req.body = '{"meta": {"key1": "value1"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
self.assertEqual('application/json', res.headers['Content-Type'])
res_dict = json.loads(res.body)
- self.assertEqual('value1', res_dict['key1'])
+ expected = {'meta': {'key1': 'value1'}}
+ self.assertEqual(expected, res_dict)
+
+ def test_update_item_xml(self):
+ self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
+ return_create_instance_metadata)
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key9')
+ req.method = 'PUT'
+ req.accept = "application/json"
+ req.content_type = "application/xml"
+ req.body = """
+ <meta xmlns="http://docs.openstack.org/compute/api/v1.1"
+ key="key9">value9</meta>
+ """
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ res_dict = json.loads(res.body)
+ expected = {'meta': {'key9': 'value9'}}
+ self.assertEqual(expected, res_dict)
def test_update_item_nonexistant_server(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_nonexistant)
- req = webob.Request.blank('/v1.1/servers/asdf/100/key1')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/asdf/metadata/key1')
req.method = 'PUT'
- req.body = '{"key1": "value1"}'
+ req.body = '{"meta":{"key1": "value1"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int)
@@ -224,8 +363,7 @@ class ServerMetaDataTest(unittest.TestCase):
def test_update_item_empty_body(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/key1')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
req.method = 'PUT'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
@@ -234,10 +372,9 @@ class ServerMetaDataTest(unittest.TestCase):
def test_update_item_too_many_keys(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/key1')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
req.method = 'PUT'
- req.body = '{"key1": "value1", "key2": "value2"}'
+ req.body = '{"meta": {"key1": "value1", "key2": "value2"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
@@ -245,10 +382,9 @@ class ServerMetaDataTest(unittest.TestCase):
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata)
- req = webob.Request.blank('/v1.1/servers/1/meta/bad')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/bad')
req.method = 'PUT'
- req.body = '{"key1": "value1"}'
+ req.body = '{"meta": {"key1": "value1"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
@@ -260,8 +396,7 @@ class ServerMetaDataTest(unittest.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/servers/1/meta')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata')
req.method = 'POST'
req.body = json_string
req.headers["content-type"] = "application/json"
@@ -271,10 +406,9 @@ class ServerMetaDataTest(unittest.TestCase):
def test_to_many_metadata_items_on_update_item(self):
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
return_create_instance_metadata_max)
- req = webob.Request.blank('/v1.1/servers/1/meta/key1')
- req.environ['api.version'] = '1.1'
+ req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
req.method = 'PUT'
- req.body = '{"a new key": "a new value"}'
+ req.body = '{"meta": {"a new key": "a new value"}}'
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(400, res.status_int)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 1577c922b..fd06b2e64 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -16,22 +16,22 @@
# under the License.
import base64
+import datetime
import json
import unittest
from xml.dom import minidom
-import stubout
import webob
from nova import context
from nova import db
from nova import exception
-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
@@ -45,10 +45,6 @@ from nova.tests.api.openstack import common
from nova.tests.api.openstack import fakes
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
@@ -77,6 +73,12 @@ def return_virtual_interface_instance_nonexistant(interfaces):
return _return_virtual_interface_by_instance
+def return_server_with_attributes(**kwargs):
+ def _return_server(context, id):
+ return stub_instance(id, **kwargs)
+ return _return_server
+
+
def return_server_with_addresses(private, public):
def _return_server(context, id):
return stub_instance(id, private_address=private,
@@ -84,20 +86,20 @@ def return_server_with_addresses(private, public):
return _return_server
-def return_server_with_interfaces(interfaces):
+def return_server_with_power_state(power_state):
def _return_server(context, id):
- return stub_instance(id, interfaces=interfaces)
+ return stub_instance(id, power_state=power_state)
return _return_server
-def return_server_with_power_state(power_state):
+def return_server_with_uuid_and_power_state(power_state):
def _return_server(context, id):
- return stub_instance(id, power_state=power_state)
+ return stub_instance(id, uuid=FAKE_UUID, power_state=power_state)
return _return_server
-def return_servers(context, user_id=1):
- return [stub_instance(i, user_id) for i in xrange(5)]
+def return_servers(context, *args, **kwargs):
+ return [stub_instance(i, 'fake', 'fake') for i in xrange(5)]
def return_servers_by_reservation(context, reservation_id=""):
@@ -140,16 +142,17 @@ def instance_addresses(context, instance_id):
return None
-def stub_instance(id, user_id=1, private_address=None, public_addresses=None,
- host=None, power_state=0, reservation_id="",
- uuid=FAKE_UUID, interfaces=None):
+def stub_instance(id, user_id='fake', project_id='fake', private_address=None,
+ public_addresses=None, host=None, power_state=0,
+ reservation_id="", uuid=FAKE_UUID, image_ref="10",
+ flavor_id="1", interfaces=None):
metadata = []
metadata.append(InstanceMetadata(key='seq', value=id))
if interfaces is None:
interfaces = []
- inst_type = instance_types.get_instance_type_by_flavor_id(1)
+ inst_type = instance_types.get_instance_type_by_flavor_id(int(flavor_id))
if public_addresses is None:
public_addresses = list()
@@ -164,10 +167,12 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None,
instance = {
"id": int(id),
+ "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0),
+ "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0),
"admin_pass": "",
"user_id": user_id,
- "project_id": "",
- "image_ref": "10",
+ "project_id": project_id,
+ "image_ref": image_ref,
"kernel_id": "",
"ramdisk_id": "",
"launch_index": 0,
@@ -223,13 +228,11 @@ class MockSetAdminPassword(object):
class ServersTest(test.TestCase):
def setUp(self):
+ self.maxDiff = None
super(ServersTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
+ self.flags(verbose=True)
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
fakes.stub_out_image_service(self.stubs)
self.stubs.Set(utils, 'gen_uuid', fake_gen_uuid)
@@ -237,7 +240,7 @@ class ServersTest(test.TestCase):
self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
self.stubs.Set(nova.db, 'instance_get_by_uuid',
return_server_by_uuid)
- self.stubs.Set(nova.db.api, 'instance_get_all_by_user',
+ self.stubs.Set(nova.db.api, 'instance_get_all_by_project',
return_servers)
self.stubs.Set(nova.db.api, 'instance_add_security_group',
return_security_group)
@@ -252,15 +255,9 @@ class ServersTest(test.TestCase):
self.stubs.Set(nova.compute.API, 'resume', fake_compute_api)
self.stubs.Set(nova.compute.API, "get_diagnostics", fake_compute_api)
self.stubs.Set(nova.compute.API, "get_actions", fake_compute_api)
- self.allow_admin = FLAGS.allow_admin_api
self.webreq = common.webob_factory('/v1.0/servers')
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.allow_admin_api = self.allow_admin
- super(ServersTest, self).tearDown()
-
def test_get_server_by_id(self):
req = webob.Request.blank('/v1.0/servers/1')
res = req.get_response(fakes.wsgi_app())
@@ -299,24 +296,346 @@ class ServersTest(test.TestCase):
self.assertEqual(res_dict['server']['name'], 'server1')
def test_get_server_by_id_v1_1(self):
+ image_bookmark = "http://localhost/images/10"
+ flavor_ref = "http://localhost/v1.1/flavors/1"
+ flavor_id = "1"
+ flavor_bookmark = "http://localhost/flavors/1"
+
+ public_ip = '192.168.0.3'
+ private_ip = '172.19.0.1'
+ interfaces = [
+ {
+ 'network': {'label': 'public'},
+ 'fixed_ips': [
+ {'address': public_ip},
+ ],
+ },
+ {
+ 'network': {'label': 'private'},
+ 'fixed_ips': [
+ {'address': private_ip},
+ ],
+ },
+ ]
+ new_return_server = return_server_with_attributes(
+ interfaces=interfaces)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
req = webob.Request.blank('/v1.1/servers/1')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
- self.assertEqual(res_dict['server']['id'], 1)
- self.assertEqual(res_dict['server']['name'], 'server1')
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": FAKE_UUID,
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 0,
+ "name": "server1",
+ "status": "BUILD",
+ "hostId": '',
+ "image": {
+ "id": "10",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {
+ "public": [
+ {
+ "version": 4,
+ "addr": public_ip,
+ },
+ ],
+ "private": [
+ {
+ "version": 4,
+ "addr": private_ip,
+ },
+ ],
+ },
+ "metadata": {
+ "seq": "1",
+ },
+ "links": [
+ {
+ "rel": "self",
+ #FIXME(wwolf) Do we want the links to be id or uuid?
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
- expected_links = [
+ self.assertDictMatch(res_dict, expected_server)
+
+ def test_get_server_by_id_v1_1_xml(self):
+ image_bookmark = "http://localhost/images/10"
+ flavor_ref = "http://localhost/v1.1/flavors/1"
+ flavor_id = "1"
+ flavor_bookmark = "http://localhost/flavors/1"
+ server_href = "http://localhost/v1.1/servers/1"
+ server_bookmark = "http://localhost/servers/1"
+
+ public_ip = '192.168.0.3'
+ private_ip = '172.19.0.1'
+ interfaces = [
{
- "rel": "self",
- "href": "http://localhost/v1.1/servers/1",
+ 'network': {'label': 'public'},
+ 'fixed_ips': [
+ {'address': public_ip},
+ ],
},
{
- "rel": "bookmark",
- "href": "http://localhost/servers/1",
+ 'network': {'label': 'private'},
+ 'fixed_ips': [
+ {'address': private_ip},
+ ],
+ },
+ ]
+ new_return_server = return_server_with_attributes(
+ interfaces=interfaces)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
+ req = webob.Request.blank('/v1.1/servers/1')
+ req.headers['Accept'] = 'application/xml'
+ res = req.get_response(fakes.wsgi_app())
+ actual = minidom.parseString(res.body.replace(' ', ''))
+ expected_uuid = FAKE_UUID
+ expected_updated = "2010-11-11T11:00:00Z"
+ expected_created = "2010-10-10T12:00:00Z"
+ expected = minidom.parseString("""
+ <server id="1"
+ uuid="%(expected_uuid)s"
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ name="server1"
+ updated="%(expected_updated)s"
+ created="%(expected_created)s"
+ hostId=""
+ status="BUILD"
+ progress="0">
+ <atom:link href="%(server_href)s" rel="self"/>
+ <atom:link href="%(server_bookmark)s" rel="bookmark"/>
+ <image id="10">
+ <atom:link rel="bookmark" href="%(image_bookmark)s"/>
+ </image>
+ <flavor id="1">
+ <atom:link rel="bookmark" href="%(flavor_bookmark)s"/>
+ </flavor>
+ <metadata>
+ <meta key="seq">
+ 1
+ </meta>
+ </metadata>
+ <addresses>
+ <network id="public">
+ <ip version="4" addr="%(public_ip)s"/>
+ </network>
+ <network id="private">
+ <ip version="4" addr="%(private_ip)s"/>
+ </network>
+ </addresses>
+ </server>
+ """.replace(" ", "") % (locals()))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_get_server_with_active_status_by_id_v1_1(self):
+ image_bookmark = "http://localhost/images/10"
+ flavor_ref = "http://localhost/v1.1/flavors/1"
+ flavor_id = "1"
+ flavor_bookmark = "http://localhost/flavors/1"
+ private_ip = "192.168.0.3"
+ public_ip = "1.2.3.4"
+
+ interfaces = [
+ {
+ 'network': {'label': 'public'},
+ 'fixed_ips': [
+ {'address': public_ip},
+ ],
+ },
+ {
+ 'network': {'label': 'private'},
+ 'fixed_ips': [
+ {'address': private_ip},
+ ],
},
]
+ new_return_server = return_server_with_attributes(
+ interfaces=interfaces, power_state=1)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
+ req = webob.Request.blank('/v1.1/servers/1')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": FAKE_UUID,
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 100,
+ "name": "server1",
+ "status": "ACTIVE",
+ "hostId": '',
+ "image": {
+ "id": "10",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {
+ "public": [
+ {
+ "version": 4,
+ "addr": public_ip,
+ },
+ ],
+ "private": [
+ {
+ "version": 4,
+ "addr": private_ip,
+ },
+ ],
+ },
+ "metadata": {
+ "seq": "1",
+ },
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ self.assertDictMatch(res_dict, expected_server)
- self.assertEqual(res_dict['server']['links'], expected_links)
+ def test_get_server_with_id_image_ref_by_id_v1_1(self):
+ image_ref = "10"
+ image_bookmark = "http://localhost/images/10"
+ flavor_ref = "http://localhost/v1.1/flavors/1"
+ flavor_id = "1"
+ flavor_bookmark = "http://localhost/flavors/1"
+ private_ip = "192.168.0.3"
+ public_ip = "1.2.3.4"
+
+ interfaces = [
+ {
+ 'network': {'label': 'public'},
+ 'fixed_ips': [
+ {'address': public_ip},
+ ],
+ },
+ {
+ 'network': {'label': 'private'},
+ 'fixed_ips': [
+ {'address': private_ip},
+ ],
+ },
+ ]
+ new_return_server = return_server_with_attributes(
+ interfaces=interfaces, power_state=1, image_ref=image_ref,
+ flavor_id=flavor_id)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
+ req = webob.Request.blank('/v1.1/servers/1')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": FAKE_UUID,
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 100,
+ "name": "server1",
+ "status": "ACTIVE",
+ "hostId": '',
+ "image": {
+ "id": "10",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {
+ "public": [
+ {
+ "version": 4,
+ "addr": public_ip,
+ },
+ ],
+ "private": [
+ {
+ "version": 4,
+ "addr": private_ip,
+ },
+ ],
+ },
+ "metadata": {
+ "seq": "1",
+ },
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ self.assertDictMatch(res_dict, expected_server)
def test_get_server_by_id_with_addresses_xml(self):
private = "192.168.0.3"
@@ -433,6 +752,51 @@ class ServersTest(test.TestCase):
self.assertEquals(ip.getAttribute('addr'), private)
def test_get_server_by_id_with_addresses_v1_1(self):
+ self.flags(use_ipv6=True)
+ interfaces = [
+ {
+ 'network': {'label': 'network_1'},
+ 'fixed_ips': [
+ {'address': '192.168.0.3'},
+ {'address': '192.168.0.4'},
+ ],
+ },
+ {
+ 'network': {'label': 'network_2'},
+ 'fixed_ips': [
+ {'address': '172.19.0.1'},
+ {'address': '172.19.0.2'},
+ ],
+ 'fixed_ipv6': '2001:4860::12',
+ },
+ ]
+ new_return_server = return_server_with_attributes(
+ interfaces=interfaces)
+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
+
+ req = webob.Request.blank('/v1.1/servers/1')
+ res = req.get_response(fakes.wsgi_app())
+
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['server']['id'], 1)
+ self.assertEqual(res_dict['server']['name'], 'server1')
+ addresses = res_dict['server']['addresses']
+ expected = {
+ 'network_1': [
+ {'addr': '192.168.0.3', 'version': 4},
+ {'addr': '192.168.0.4', 'version': 4},
+ ],
+ 'network_2': [
+ {'addr': '172.19.0.1', 'version': 4},
+ {'addr': '172.19.0.2', 'version': 4},
+ {'addr': '2001:4860::12', 'version': 6},
+ ],
+ }
+
+ self.assertEqual(addresses, expected)
+
+ def test_get_server_by_id_with_addresses_v1_1_ipv6_disabled(self):
+ self.flags(use_ipv6=False)
interfaces = [
{
'network': {'label': 'network_1'},
@@ -447,9 +811,11 @@ class ServersTest(test.TestCase):
{'address': '172.19.0.1'},
{'address': '172.19.0.2'},
],
+ 'fixed_ipv6': '2001:4860::12',
},
]
- new_return_server = return_server_with_interfaces(interfaces)
+ new_return_server = return_server_with_attributes(
+ interfaces=interfaces)
self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
req = webob.Request.blank('/v1.1/servers/1')
@@ -473,6 +839,7 @@ class ServersTest(test.TestCase):
self.assertEqual(addresses, expected)
def test_get_server_addresses_v1_1(self):
+ self.flags(use_ipv6=True)
interfaces = [
{
'network': {'label': 'network_1'},
@@ -492,6 +859,7 @@ class ServersTest(test.TestCase):
},
{'address': '172.19.0.2'},
],
+ 'fixed_ipv6': '2001:4860::12',
},
]
@@ -514,6 +882,7 @@ class ServersTest(test.TestCase):
{'version': 4, 'addr': '172.19.0.1'},
{'version': 4, 'addr': '1.2.3.4'},
{'version': 4, 'addr': '172.19.0.2'},
+ {'version': 6, 'addr': '2001:4860::12'},
],
},
}
@@ -521,6 +890,7 @@ class ServersTest(test.TestCase):
self.assertEqual(res_dict, expected)
def test_get_server_addresses_single_network_v1_1(self):
+ self.flags(use_ipv6=True)
interfaces = [
{
'network': {'label': 'network_1'},
@@ -540,6 +910,7 @@ class ServersTest(test.TestCase):
},
{'address': '172.19.0.2'},
],
+ 'fixed_ipv6': '2001:4860::12',
},
]
_return_vifs = return_virtual_interface_by_instance(interfaces)
@@ -556,6 +927,7 @@ class ServersTest(test.TestCase):
{'version': 4, 'addr': '172.19.0.1'},
{'version': 4, 'addr': '1.2.3.4'},
{'version': 4, 'addr': '172.19.0.2'},
+ {'version': 6, 'addr': '2001:4860::12'},
],
}
self.assertEqual(res_dict, expected)
@@ -585,6 +957,7 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
+ self.assertEqual(len(res_dict['servers']), 5)
i = 0
for s in res_dict['servers']:
self.assertEqual(s['id'], i)
@@ -648,23 +1021,24 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
+ self.assertEqual(len(res_dict['servers']), 5)
for i, s in enumerate(res_dict['servers']):
self.assertEqual(s['id'], i)
self.assertEqual(s['name'], 'server%d' % i)
- self.assertEqual(s.get('imageId', None), None)
+ self.assertEqual(s.get('image', None), None)
expected_links = [
- {
- "rel": "self",
- "href": "http://localhost/v1.1/servers/%d" % (i,),
- },
- {
- "rel": "bookmark",
- "href": "http://localhost/servers/%d" % (i,),
- },
- ]
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/%s" % s['id'],
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/%s" % s['id'],
+ },
+ ]
- self.assertEqual(s['links'], expected_links)
+ self.assertEqual(s['links'], expected_links)
def test_get_servers_with_limit(self):
req = webob.Request.blank('/v1.0/servers?limit=3')
@@ -710,13 +1084,13 @@ class ServersTest(test.TestCase):
req = webob.Request.blank('/v1.1/servers?marker=2')
res = req.get_response(fakes.wsgi_app())
servers = json.loads(res.body)['servers']
- self.assertEqual([s['id'] for s in servers], [3, 4])
+ self.assertEqual([s['name'] for s in servers], ["server3", "server4"])
def test_get_servers_with_limit_and_marker(self):
req = webob.Request.blank('/v1.1/servers?limit=2&marker=1')
res = req.get_response(fakes.wsgi_app())
servers = json.loads(res.body)['servers']
- self.assertEqual([s['id'] for s in servers], [2, 3])
+ self.assertEqual([s['name'] for s in servers], ['server2', 'server3'])
def test_get_servers_with_bad_marker(self):
req = webob.Request.blank('/v1.1/servers?limit=2&marker=asdf')
@@ -727,8 +1101,16 @@ class ServersTest(test.TestCase):
def _setup_for_create_instance(self):
"""Shared implementation for tests below that create instance"""
def instance_create(context, inst):
- return {'id': 1, 'display_name': 'server_test',
- 'uuid': FAKE_UUID}
+ inst_type = instance_types.get_instance_type_by_flavor_id(3)
+ image_ref = 'http://localhost/images/2'
+ return {'id': 1,
+ 'display_name': 'server_test',
+ 'uuid': FAKE_UUID,
+ 'instance_type': dict(inst_type),
+ 'image_ref': image_ref,
+ "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0),
+ "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0),
+ }
def server_update(context, id, params):
return instance_create(context, id)
@@ -777,6 +1159,7 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
server = json.loads(res.body)['server']
self.assertEqual(16, len(server['adminPass']))
self.assertEqual('server_test', server['name'])
@@ -784,7 +1167,6 @@ class ServersTest(test.TestCase):
self.assertEqual(2, server['flavorId'])
self.assertEqual(3, server['imageId'])
self.assertEqual(FAKE_UUID, server['uuid'])
- self.assertEqual(res.status_int, 200)
def test_create_instance(self):
self._test_create_instance_helper()
@@ -802,7 +1184,7 @@ class ServersTest(test.TestCase):
def test_create_instance_via_zones(self):
"""Server generated ReservationID"""
self._setup_for_create_instance()
- FLAGS.allow_admin_api = True
+ self.flags(allow_admin_api=True)
body = dict(server=dict(
name='server_test', imageId=3, flavorId=2,
@@ -824,7 +1206,7 @@ class ServersTest(test.TestCase):
def test_create_instance_via_zones_with_resid(self):
"""User supplied ReservationID"""
self._setup_for_create_instance()
- FLAGS.allow_admin_api = True
+ self.flags(allow_admin_api=True)
body = dict(server=dict(
name='server_test', imageId=3, flavorId=2,
@@ -890,6 +1272,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()
@@ -916,8 +1310,27 @@ class ServersTest(test.TestCase):
def test_create_instance_v1_1(self):
self._setup_for_create_instance()
+ # proper local hrefs must start with 'http://localhost/v1.1/'
image_href = 'http://localhost/v1.1/images/2'
- flavor_ref = 'http://localhost/v1.1/flavors/3'
+ flavor_ref = 'http://localhost/flavors/3'
+ expected_flavor = {
+ "id": "3",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/flavors/3',
+ },
+ ],
+ }
+ expected_image = {
+ "id": "2",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/images/2',
+ },
+ ],
+ }
body = {
'server': {
'name': 'server_test',
@@ -927,7 +1340,12 @@ class ServersTest(test.TestCase):
'hello': 'world',
'open': 'stack',
},
- 'personality': {},
+ 'personality': [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "MQ==",
+ },
+ ],
},
}
@@ -941,10 +1359,43 @@ class ServersTest(test.TestCase):
self.assertEqual(res.status_int, 200)
server = json.loads(res.body)['server']
self.assertEqual(16, len(server['adminPass']))
- self.assertEqual('server_test', server['name'])
self.assertEqual(1, server['id'])
- self.assertEqual(flavor_ref, server['flavorRef'])
- self.assertEqual(image_href, server['imageRef'])
+ self.assertEqual(0, server['progress'])
+ self.assertEqual('server_test', server['name'])
+ self.assertEqual(expected_flavor, server['flavor'])
+ self.assertEqual(expected_image, server['image'])
+
+ def test_create_instance_v1_1_invalid_flavor_href(self):
+ self._setup_for_create_instance()
+
+ image_href = 'http://localhost/v1.1/images/2'
+ flavor_ref = 'http://localhost/v1.1/flavors/asdf'
+ body = dict(server=dict(
+ name='server_test', imageRef=image_href, flavorRef=flavor_ref,
+ metadata={'hello': 'world', 'open': 'stack'},
+ personality={}))
+ req = webob.Request.blank('/v1.1/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, 400)
+
+ def test_create_instance_v1_1_bad_flavor_href(self):
+ self._setup_for_create_instance()
+
+ image_href = 'http://localhost/v1.1/images/2'
+ flavor_ref = 'http://localhost/v1.1/flavors/17'
+ body = dict(server=dict(
+ name='server_test', imageRef=image_href, flavorRef=flavor_ref,
+ metadata={'hello': 'world', 'open': 'stack'},
+ personality={}))
+ req = webob.Request.blank('/v1.1/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, 400)
def test_create_instance_v1_1_bad_href(self):
self._setup_for_create_instance()
@@ -965,8 +1416,26 @@ class ServersTest(test.TestCase):
def test_create_instance_v1_1_local_href(self):
self._setup_for_create_instance()
- image_id = 2
+ image_id = "2"
flavor_ref = 'http://localhost/v1.1/flavors/3'
+ expected_flavor = {
+ "id": "3",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/flavors/3',
+ },
+ ],
+ }
+ expected_image = {
+ "id": "2",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/images/2',
+ },
+ ],
+ }
body = {
'server': {
'name': 'server_test',
@@ -982,11 +1451,10 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
- server = json.loads(res.body)['server']
- self.assertEqual(1, server['id'])
- self.assertEqual(flavor_ref, server['flavorRef'])
- self.assertEqual(image_id, server['imageRef'])
self.assertEqual(res.status_int, 200)
+ server = json.loads(res.body)['server']
+ self.assertEqual(expected_flavor, server['flavor'])
+ self.assertEqual(expected_image, server['image'])
def test_create_instance_with_admin_pass_v1_0(self):
self._setup_for_create_instance()
@@ -1009,7 +1477,7 @@ class ServersTest(test.TestCase):
self.assertNotEqual(res['server']['adminPass'],
body['server']['adminPass'])
- def test_create_instance_with_admin_pass_v1_1(self):
+ def test_create_instance_v1_1_admin_pass(self):
self._setup_for_create_instance()
image_href = 'http://localhost/v1.1/images/2'
@@ -1017,8 +1485,8 @@ class ServersTest(test.TestCase):
body = {
'server': {
'name': 'server_test',
- 'imageRef': image_href,
- 'flavorRef': flavor_ref,
+ 'imageRef': 3,
+ 'flavorRef': 3,
'adminPass': 'testpass',
},
}
@@ -1028,19 +1496,18 @@ class ServersTest(test.TestCase):
req.body = json.dumps(body)
req.headers['content-type'] = "application/json"
res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
server = json.loads(res.body)['server']
self.assertEqual(server['adminPass'], body['server']['adminPass'])
- def test_create_instance_with_empty_admin_pass_v1_1(self):
+ def test_create_instance_v1_1_admin_pass_empty(self):
self._setup_for_create_instance()
- image_href = 'http://localhost/v1.1/images/2'
- flavor_ref = 'http://localhost/v1.1/flavors/3'
body = {
'server': {
'name': 'server_test',
- 'imageRef': image_href,
- 'flavorRef': flavor_ref,
+ 'imageRef': 3,
+ 'flavorRef': 3,
'adminPass': '',
},
}
@@ -1210,6 +1677,24 @@ class ServersTest(test.TestCase):
self.assertEqual(s['metadata']['seq'], str(i))
def test_get_all_server_details_v1_1(self):
+ expected_flavor = {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/flavors/1',
+ },
+ ],
+ }
+ expected_image = {
+ "id": "10",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/images/10',
+ },
+ ],
+ }
req = webob.Request.blank('/v1.1/servers/detail')
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
@@ -1218,8 +1703,8 @@ class ServersTest(test.TestCase):
self.assertEqual(s['id'], i)
self.assertEqual(s['hostId'], '')
self.assertEqual(s['name'], 'server%d' % i)
- self.assertEqual(s['imageRef'], 10)
- self.assertEqual(s['flavorRef'], 'http://localhost/v1.1/flavors/1')
+ self.assertEqual(s['image'], expected_image)
+ self.assertEqual(s['flavor'], expected_flavor)
self.assertEqual(s['status'], 'BUILD')
self.assertEqual(s['metadata']['seq'], str(i))
@@ -1231,10 +1716,11 @@ class ServersTest(test.TestCase):
instances - 2 on one host and 3 on another.
'''
- def return_servers_with_host(context, user_id=1):
- return [stub_instance(i, 1, None, None, i % 2) for i in xrange(5)]
+ def return_servers_with_host(context, *args, **kwargs):
+ return [stub_instance(i, 'fake', 'fake', None, None, i % 2)
+ for i in xrange(5)]
- self.stubs.Set(nova.db.api, 'instance_get_all_by_user',
+ self.stubs.Set(nova.db.api, 'instance_get_all_by_project',
return_servers_with_host)
req = webob.Request.blank('/v1.0/servers/detail')
@@ -1254,336 +1740,68 @@ class ServersTest(test.TestCase):
self.assertEqual(s['flavorId'], 1)
def test_server_pause(self):
- FLAGS.allow_admin_api = True
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/pause')
req.method = 'POST'
req.content_type = 'application/json'
- req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_unpause(self):
- FLAGS.allow_admin_api = True
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/unpause')
req.method = 'POST'
req.content_type = 'application/json'
- req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_suspend(self):
- FLAGS.allow_admin_api = True
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/suspend')
req.method = 'POST'
req.content_type = 'application/json'
- req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_resume(self):
- FLAGS.allow_admin_api = True
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/resume')
req.method = 'POST'
req.content_type = 'application/json'
- req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_reset_network(self):
- FLAGS.allow_admin_api = True
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/reset_network')
req.method = 'POST'
req.content_type = 'application/json'
- req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_inject_network_info(self):
- FLAGS.allow_admin_api = True
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
+ self.flags(allow_admin_api=True)
req = webob.Request.blank(
'/v1.0/servers/1/inject_network_info')
req.method = 'POST'
req.content_type = 'application/json'
- req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_diagnostics(self):
+ self.flags(allow_admin_api=False)
req = webob.Request.blank("/v1.0/servers/1/diagnostics")
req.method = "GET"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404)
def test_server_actions(self):
+ self.flags(allow_admin_api=False)
req = webob.Request.blank("/v1.0/servers/1/actions")
req.method = "GET"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 404)
- def test_server_change_password(self):
- body = {'changePassword': {'adminPass': '1234pass'}}
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 501)
-
- def test_server_change_password_xml(self):
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/xml'
- req.body = '<changePassword adminPass="1234pass">'
-# res = req.get_response(fakes.wsgi_app())
-# self.assertEqual(res.status_int, 501)
-
- def test_server_change_password_v1_1(self):
- mock_method = MockSetAdminPassword()
- self.stubs.Set(nova.compute.api.API, 'set_admin_password', mock_method)
- body = {'changePassword': {'adminPass': '1234pass'}}
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
- self.assertEqual(mock_method.instance_id, '1')
- self.assertEqual(mock_method.password, '1234pass')
-
- def test_server_change_password_bad_request_v1_1(self):
- body = {'changePassword': {'pass': '12345'}}
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_change_password_empty_string_v1_1(self):
- body = {'changePassword': {'adminPass': ''}}
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_change_password_none_v1_1(self):
- body = {'changePassword': {'adminPass': None}}
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_change_password_not_a_string_v1_1(self):
- body = {'changePassword': {'adminPass': 1234}}
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_reboot(self):
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
-
- def test_server_rebuild_accepted(self):
- body = {
- "rebuild": {
- "imageId": 2,
- },
- }
-
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
- self.assertEqual(res.body, "")
-
- def test_server_rebuild_rejected_when_building(self):
- body = {
- "rebuild": {
- "imageId": 2,
- },
- }
-
- state = power_state.BUILDING
- new_return_server = return_server_with_power_state(state)
- self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
-
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 409)
-
- def test_server_rebuild_bad_entity(self):
- body = {
- "rebuild": {
- },
- }
-
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_rebuild_accepted_minimum_v1_1(self):
- body = {
- "rebuild": {
- "imageRef": "http://localhost/images/2",
- },
- }
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
-
- def test_server_rebuild_rejected_when_building_v1_1(self):
- body = {
- "rebuild": {
- "imageRef": "http://localhost/images/2",
- },
- }
-
- state = power_state.BUILDING
- new_return_server = return_server_with_power_state(state)
- self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 409)
-
- def test_server_rebuild_accepted_with_metadata_v1_1(self):
- body = {
- "rebuild": {
- "imageRef": "http://localhost/images/2",
- "metadata": {
- "new": "metadata",
- },
- },
- }
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
-
- def test_server_rebuild_accepted_with_bad_metadata_v1_1(self):
- body = {
- "rebuild": {
- "imageRef": "http://localhost/images/2",
- "metadata": "stack",
- },
- }
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_rebuild_bad_entity_v1_1(self):
- body = {
- "rebuild": {
- "imageId": 2,
- },
- }
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_rebuild_bad_personality_v1_1(self):
- body = {
- "rebuild": {
- "imageRef": "http://localhost/images/2",
- "personality": [{
- "path": "/path/to/file",
- "contents": "INVALID b64",
- }]
- },
- }
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_server_rebuild_personality_v1_1(self):
- body = {
- "rebuild": {
- "imageRef": "http://localhost/images/2",
- "personality": [{
- "path": "/path/to/file",
- "contents": base64.b64encode("Test String"),
- }]
- },
- }
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
-
def test_delete_server_instance(self):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'DELETE'
@@ -1601,7 +1819,7 @@ class ServersTest(test.TestCase):
self.assertEqual(self.server_delete_called, True)
def test_rescue_accepted(self):
- FLAGS.allow_admin_api = True
+ self.flags(allow_admin_api=True)
body = {}
self.called = False
@@ -1620,7 +1838,7 @@ class ServersTest(test.TestCase):
self.assertEqual(res.status_int, 202)
def test_rescue_raises_handled(self):
- FLAGS.allow_admin_api = True
+ self.flags(allow_admin_api=True)
body = {}
def rescue_mock(*args, **kwargs):
@@ -1651,147 +1869,6 @@ class ServersTest(test.TestCase):
self.assertEqual(res.status_int, 204)
self.assertEqual(self.server_delete_called, True)
- def test_resize_server(self):
- req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
-
- self.resize_called = False
-
- def resize_mock(*args):
- self.resize_called = True
-
- self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
- self.assertEqual(self.resize_called, True)
-
- def test_resize_server_v11(self):
-
- req = webob.Request.blank('/v1.1/servers/1/action')
- req.content_type = 'application/json'
- req.method = 'POST'
- body_dict = dict(resize=dict(flavorRef="http://localhost/3"))
- req.body = json.dumps(body_dict)
-
- self.resize_called = False
-
- def resize_mock(*args):
- self.resize_called = True
-
- self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
- self.assertEqual(self.resize_called, True)
-
- def test_resize_bad_flavor_fails(self):
- req = self.webreq('/1/action', 'POST', dict(resize=dict(derp=3)))
-
- self.resize_called = False
-
- def resize_mock(*args):
- self.resize_called = True
-
- self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 422)
- self.assertEqual(self.resize_called, False)
-
- def test_resize_raises_fails(self):
- req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
-
- def resize_mock(*args):
- raise Exception('hurr durr')
-
- self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_resized_server_has_correct_status(self):
- req = self.webreq('/1', 'GET')
-
- def fake_migration_get(*args):
- return {}
-
- self.stubs.Set(nova.db, 'migration_get_by_instance_and_status',
- fake_migration_get)
- res = req.get_response(fakes.wsgi_app())
- body = json.loads(res.body)
- self.assertEqual(body['server']['status'], 'RESIZE-CONFIRM')
-
- def test_confirm_resize_server(self):
- req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
-
- self.resize_called = False
-
- def confirm_resize_mock(*args):
- self.resize_called = True
-
- self.stubs.Set(nova.compute.api.API, 'confirm_resize',
- confirm_resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 204)
- self.assertEqual(self.resize_called, True)
-
- def test_confirm_resize_server_fails(self):
- req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
-
- def confirm_resize_mock(*args):
- raise Exception('hurr durr')
-
- self.stubs.Set(nova.compute.api.API, 'confirm_resize',
- confirm_resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_revert_resize_server(self):
- req = self.webreq('/1/action', 'POST', dict(revertResize=None))
-
- self.resize_called = False
-
- def revert_resize_mock(*args):
- self.resize_called = True
-
- self.stubs.Set(nova.compute.api.API, 'revert_resize',
- revert_resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
- self.assertEqual(self.resize_called, True)
-
- def test_revert_resize_server_fails(self):
- req = self.webreq('/1/action', 'POST', dict(revertResize=None))
-
- def revert_resize_mock(*args):
- raise Exception('hurr durr')
-
- self.stubs.Set(nova.compute.api.API, 'revert_resize',
- revert_resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 400)
-
- def test_migrate_server(self):
- """This is basically the same as resize, only we provide the `migrate`
- attribute in the body's dict.
- """
- req = self.webreq('/1/action', 'POST', dict(migrate=None))
-
- self.resize_called = False
-
- def resize_mock(*args):
- self.resize_called = True
-
- self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
-
- res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 202)
- self.assertEqual(self.resize_called, True)
-
def test_shutdown_status(self):
new_server = return_server_with_power_state(power_state.SHUTDOWN)
self.stubs.Set(nova.db.api, 'instance_get', new_server)
@@ -1811,7 +1888,7 @@ class ServersTest(test.TestCase):
self.assertEqual(res_dict['server']['status'], 'SHUTOFF')
-class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
+class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase):
def setUp(self):
self.deserializer = create_instance_helper.ServerXMLDeserializer()
@@ -1825,6 +1902,8 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"name": "new-server-test",
"imageId": "1",
"flavorId": "1",
+ "metadata": {},
+ "personality": [],
}}
self.assertEquals(request['body'], expected)
@@ -1840,6 +1919,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"imageId": "1",
"flavorId": "1",
"metadata": {},
+ "personality": [],
}}
self.assertEquals(request['body'], expected)
@@ -1854,6 +1934,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase):
"name": "new-server-test",
"imageId": "1",
"flavorId": "1",
+ "metadata": {},
"personality": [],
}}
self.assertEquals(request['body'], expected)
@@ -2091,36 +2172,243 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""",
request = self.deserializer.deserialize(serial_request, 'create')
self.assertEqual(request['body'], expected)
- def test_request_xmlser_with_flavor_image_href(self):
+
+class TestServerCreateRequestXMLDeserializerV11(test.TestCase):
+
+ def setUp(self):
+ super(TestServerCreateRequestXMLDeserializerV11, self).setUp()
+ self.deserializer = create_instance_helper.ServerXMLDeserializerV11()
+
+ def test_minimal_request(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_admin_pass(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2"
+ adminPass="1234"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "adminPass": "1234",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_image_link(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="http://localhost:8774/v1.1/images/2"
+ flavorRef="3"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "http://localhost:8774/v1.1/images/2",
+ "flavorRef": "3",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_flavor_link(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="http://localhost:8774/v1.1/flavors/3"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "http://localhost:8774/v1.1/flavors/3",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_empty_metadata_personality(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2">
+ <metadata/>
+ <personality/>
+</server>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "metadata": {},
+ "personality": [],
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_multiple_metadata_items(self):
serial_request = """
- <server xmlns="http://docs.openstack.org/compute/api/v1.1"
- name="new-server-test"
- imageRef="http://localhost:8774/v1.1/images/1"
- flavorRef="http://localhost:8774/v1.1/flavors/1">
- </server>"""
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2">
+ <metadata>
+ <meta key="one">two</meta>
+ <meta key="open">snack</meta>
+ </metadata>
+</server>"""
request = self.deserializer.deserialize(serial_request, 'create')
- self.assertEquals(request['body']["server"]["flavorRef"],
- "http://localhost:8774/v1.1/flavors/1")
- self.assertEquals(request['body']["server"]["imageRef"],
- "http://localhost:8774/v1.1/images/1")
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "metadata": {"one": "two", "open": "snack"},
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_multiple_personality_files(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2">
+ <personality>
+ <file path="/etc/banner.txt">MQ==</file>
+ <file path="/etc/hosts">Mg==</file>
+ </personality>
+</server>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "personality": [
+ {"path": "/etc/banner.txt", "contents": "MQ=="},
+ {"path": "/etc/hosts", "contents": "Mg=="},
+ ],
+ },
+ }
+ self.assertDictMatch(request['body'], expected)
+
+ def test_spec_request(self):
+ image_bookmark_link = "http://servers.api.openstack.org/1234/" + \
+ "images/52415800-8b69-11e0-9b19-734f6f006e54"
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ imageRef="%s"
+ flavorRef="52415800-8b69-11e0-9b19-734f1195ff37"
+ name="new-server-test">
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <personality>
+ <file path="/etc/banner.txt">Mg==</file>
+ </personality>
+</server>""" % (image_bookmark_link)
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "http://servers.api.openstack.org/1234/" + \
+ "images/52415800-8b69-11e0-9b19-734f6f006e54",
+ "flavorRef": "52415800-8b69-11e0-9b19-734f1195ff37",
+ "metadata": {"My Server Name": "Apache1"},
+ "personality": [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "Mg==",
+ },
+ ],
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+
+class TestAddressesXMLSerialization(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):
super(TestServerInstanceCreation, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.auth_data = {}
- fakes.FakeAuthDatabase.data = {}
- fakes.stub_out_auth(self.stubs)
fakes.stub_out_image_service(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
- self.allow_admin = FLAGS.allow_admin_api
-
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.allow_admin_api = self.allow_admin
- super(TestServerInstanceCreation, self).tearDown()
def _setup_mock_compute_api_for_personality(self):
@@ -2407,3 +2695,753 @@ class TestGetKernelRamdiskFromImage(test.TestCase):
kernel_id, ramdisk_id = create_instance_helper.CreateInstanceHelper. \
_do_get_kernel_ramdisk_from_image(image_meta)
return kernel_id, ramdisk_id
+
+
+class ServersViewBuilderV11Test(test.TestCase):
+
+ def setUp(self):
+ self.instance = self._get_instance()
+ self.view_builder = self._get_view_builder()
+
+ def tearDown(self):
+ pass
+
+ def _get_instance(self):
+ created_at = datetime.datetime(2010, 10, 10, 12, 0, 0)
+ updated_at = datetime.datetime(2010, 11, 11, 11, 0, 0)
+ instance = {
+ "id": 1,
+ "created_at": created_at,
+ "updated_at": updated_at,
+ "admin_pass": "",
+ "user_id": "",
+ "project_id": "",
+ "image_ref": "5",
+ "kernel_id": "",
+ "ramdisk_id": "",
+ "launch_index": 0,
+ "key_name": "",
+ "key_data": "",
+ "state": 0,
+ "state_description": "",
+ "memory_mb": 0,
+ "vcpus": 0,
+ "local_gb": 0,
+ "hostname": "",
+ "host": "",
+ "instance_type": {
+ "flavorid": 1,
+ },
+ "user_data": "",
+ "reservation_id": "",
+ "mac_address": "",
+ "scheduled_at": utils.utcnow(),
+ "launched_at": utils.utcnow(),
+ "terminated_at": utils.utcnow(),
+ "availability_zone": "",
+ "display_name": "test_server",
+ "display_description": "",
+ "locked": False,
+ "metadata": [],
+ #"address": ,
+ #"floating_ips": [{"address":ip} for ip in public_addresses]}
+ "uuid": "deadbeef-feed-edee-beef-d0ea7beefedd"}
+
+ return instance
+
+ def _get_view_builder(self):
+ base_url = "http://localhost/v1.1"
+ views = nova.api.openstack.views
+ address_builder = views.addresses.ViewBuilderV11()
+ flavor_builder = views.flavors.ViewBuilderV11(base_url)
+ image_builder = views.images.ViewBuilderV11(base_url)
+
+ view_builder = nova.api.openstack.views.servers.ViewBuilderV11(
+ address_builder,
+ flavor_builder,
+ image_builder,
+ base_url,
+ )
+ return view_builder
+
+ def test_build_server(self):
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": self.instance['uuid'],
+ "name": "test_server",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ output = self.view_builder.build(self.instance, False)
+ self.assertDictMatch(output, expected_server)
+
+ def test_build_server_detail(self):
+ image_bookmark = "http://localhost/images/5"
+ flavor_bookmark = "http://localhost/flavors/1"
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": self.instance['uuid'],
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": '',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {},
+ "metadata": {},
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ output = self.view_builder.build(self.instance, True)
+ self.assertDictMatch(output, expected_server)
+
+ def test_build_server_detail_active_status(self):
+ #set the power state of the instance to running
+ self.instance['state'] = 1
+ image_bookmark = "http://localhost/images/5"
+ flavor_bookmark = "http://localhost/flavors/1"
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": self.instance['uuid'],
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 100,
+ "name": "test_server",
+ "status": "ACTIVE",
+ "hostId": '',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {},
+ "metadata": {},
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ output = self.view_builder.build(self.instance, True)
+ self.assertDictMatch(output, expected_server)
+
+ def test_build_server_detail_with_metadata(self):
+
+ metadata = []
+ metadata.append(InstanceMetadata(key="Open", value="Stack"))
+ metadata.append(InstanceMetadata(key="Number", value=1))
+ self.instance['metadata'] = metadata
+
+ image_bookmark = "http://localhost/images/5"
+ flavor_bookmark = "http://localhost/flavors/1"
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": self.instance['uuid'],
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": '',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {},
+ "metadata": {
+ "Open": "Stack",
+ "Number": "1",
+ },
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ output = self.view_builder.build(self.instance, True)
+ self.assertDictMatch(output, expected_server)
+
+
+class ServerXMLSerializationTest(test.TestCase):
+
+ TIMESTAMP = "2010-10-11T10:30:22Z"
+ SERVER_HREF = 'http://localhost/v1.1/servers/123'
+ SERVER_BOOKMARK = 'http://localhost/servers/123'
+ IMAGE_BOOKMARK = 'http://localhost/images/5'
+ FLAVOR_BOOKMARK = 'http://localhost/flavors/1'
+
+ def setUp(self):
+ self.maxDiff = None
+ test.TestCase.setUp(self)
+
+ def test_show(self):
+ serializer = servers.ServerXMLSerializer()
+
+ fixture = {
+ "server": {
+ "id": 1,
+ "uuid": FAKE_UUID,
+ 'created': self.TIMESTAMP,
+ 'updated': self.TIMESTAMP,
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": self.IMAGE_BOOKMARK,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": self.FLAVOR_BOOKMARK,
+ },
+ ],
+ },
+ "addresses": {
+ "network_one": [
+ {
+ "version": 4,
+ "addr": "67.23.10.138",
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.138",
+ },
+ ],
+ "network_two": [
+ {
+ "version": 4,
+ "addr": "67.23.10.139",
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.139",
+ },
+ ],
+ },
+ "metadata": {
+ "Open": "Stack",
+ "Number": "1",
+ },
+ 'links': [
+ {
+ 'href': self.SERVER_HREF,
+ 'rel': 'self',
+ },
+ {
+ 'href': self.SERVER_BOOKMARK,
+ 'rel': 'bookmark',
+ },
+ ],
+ }
+ }
+
+ output = serializer.serialize(fixture, 'show')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected_server_href = self.SERVER_HREF
+ expected_server_bookmark = self.SERVER_BOOKMARK
+ expected_image_bookmark = self.IMAGE_BOOKMARK
+ expected_flavor_bookmark = self.FLAVOR_BOOKMARK
+ expected_now = self.TIMESTAMP
+ expected_uuid = FAKE_UUID
+ expected = minidom.parseString("""
+ <server id="1"
+ uuid="%(expected_uuid)s"
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ name="test_server"
+ updated="%(expected_now)s"
+ created="%(expected_now)s"
+ hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
+ status="BUILD"
+ progress="0">
+ <atom:link href="%(expected_server_href)s" rel="self"/>
+ <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
+ <image id="5">
+ <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
+ </image>
+ <flavor id="1">
+ <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
+ </flavor>
+ <metadata>
+ <meta key="Open">
+ Stack
+ </meta>
+ <meta key="Number">
+ 1
+ </meta>
+ </metadata>
+ <addresses>
+ <network id="network_one">
+ <ip version="4" addr="67.23.10.138"/>
+ <ip version="6" addr="::babe:67.23.10.138"/>
+ </network>
+ <network id="network_two">
+ <ip version="4" addr="67.23.10.139"/>
+ <ip version="6" addr="::babe:67.23.10.139"/>
+ </network>
+ </addresses>
+ </server>
+ """.replace(" ", "") % (locals()))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_create(self):
+ serializer = servers.ServerXMLSerializer()
+
+ fixture = {
+ "server": {
+ "id": 1,
+ "uuid": FAKE_UUID,
+ 'created': self.TIMESTAMP,
+ 'updated': self.TIMESTAMP,
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": "e4d909c290d0fb1ca068ffaddf22cbd0",
+ "adminPass": "test_password",
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": self.IMAGE_BOOKMARK,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": self.FLAVOR_BOOKMARK,
+ },
+ ],
+ },
+ "addresses": {
+ "network_one": [
+ {
+ "version": 4,
+ "addr": "67.23.10.138",
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.138",
+ },
+ ],
+ "network_two": [
+ {
+ "version": 4,
+ "addr": "67.23.10.139",
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.139",
+ },
+ ],
+ },
+ "metadata": {
+ "Open": "Stack",
+ "Number": "1",
+ },
+ 'links': [
+ {
+ 'href': self.SERVER_HREF,
+ 'rel': 'self',
+ },
+ {
+ 'href': self.SERVER_BOOKMARK,
+ 'rel': 'bookmark',
+ },
+ ],
+ }
+ }
+
+ output = serializer.serialize(fixture, 'create')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected_server_href = self.SERVER_HREF
+ expected_server_bookmark = self.SERVER_BOOKMARK
+ expected_image_bookmark = self.IMAGE_BOOKMARK
+ expected_flavor_bookmark = self.FLAVOR_BOOKMARK
+ expected_now = self.TIMESTAMP
+ expected_uuid = FAKE_UUID
+ expected = minidom.parseString("""
+ <server id="1"
+ uuid="%(expected_uuid)s"
+ xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ name="test_server"
+ updated="%(expected_now)s"
+ created="%(expected_now)s"
+ hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
+ status="BUILD"
+ adminPass="test_password"
+ progress="0">
+ <atom:link href="%(expected_server_href)s" rel="self"/>
+ <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
+ <image id="5">
+ <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
+ </image>
+ <flavor id="1">
+ <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
+ </flavor>
+ <metadata>
+ <meta key="Open">
+ Stack
+ </meta>
+ <meta key="Number">
+ 1
+ </meta>
+ </metadata>
+ <addresses>
+ <network id="network_one">
+ <ip version="4" addr="67.23.10.138"/>
+ <ip version="6" addr="::babe:67.23.10.138"/>
+ </network>
+ <network id="network_two">
+ <ip version="4" addr="67.23.10.139"/>
+ <ip version="6" addr="::babe:67.23.10.139"/>
+ </network>
+ </addresses>
+ </server>
+ """.replace(" ", "") % (locals()))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_index(self):
+ serializer = servers.ServerXMLSerializer()
+
+ expected_server_href = 'http://localhost/v1.1/servers/1'
+ expected_server_bookmark = 'http://localhost/servers/1'
+ expected_server_href_2 = 'http://localhost/v1.1/servers/2'
+ expected_server_bookmark_2 = 'http://localhost/servers/2'
+ fixture = {"servers": [
+ {
+ "id": 1,
+ "name": "test_server",
+ 'links': [
+ {
+ 'href': expected_server_href,
+ 'rel': 'self',
+ },
+ {
+ 'href': expected_server_bookmark,
+ 'rel': 'bookmark',
+ },
+ ],
+ },
+ {
+ "id": 2,
+ "name": "test_server_2",
+ 'links': [
+ {
+ 'href': expected_server_href_2,
+ 'rel': 'self',
+ },
+ {
+ 'href': expected_server_bookmark_2,
+ 'rel': 'bookmark',
+ },
+ ],
+ },
+ ]}
+
+ output = serializer.serialize(fixture, 'index')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <servers xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom">
+ <server id="1" name="test_server">
+ <atom:link href="%(expected_server_href)s" rel="self"/>
+ <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
+ </server>
+ <server id="2" name="test_server_2">
+ <atom:link href="%(expected_server_href_2)s" rel="self"/>
+ <atom:link href="%(expected_server_bookmark_2)s" rel="bookmark"/>
+ </server>
+ </servers>
+ """.replace(" ", "") % (locals()))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
+
+ def test_detail(self):
+ serializer = servers.ServerXMLSerializer()
+
+ expected_server_href = 'http://localhost/v1.1/servers/1'
+ expected_server_bookmark = 'http://localhost/servers/1'
+ expected_image_bookmark = self.IMAGE_BOOKMARK
+ expected_flavor_bookmark = self.FLAVOR_BOOKMARK
+ expected_now = self.TIMESTAMP
+ expected_uuid = FAKE_UUID
+
+ expected_server_href_2 = 'http://localhost/v1.1/servers/2'
+ expected_server_bookmark_2 = 'http://localhost/servers/2'
+ fixture = {"servers": [
+ {
+ "id": 1,
+ "uuid": FAKE_UUID,
+ 'created': self.TIMESTAMP,
+ 'updated': self.TIMESTAMP,
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": expected_image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": expected_flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {
+ "network_one": [
+ {
+ "version": 4,
+ "addr": "67.23.10.138",
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.138",
+ },
+ ],
+ },
+ "metadata": {
+ "Number": "1",
+ },
+ "links": [
+ {
+ "href": expected_server_href,
+ "rel": "self",
+ },
+ {
+ "href": expected_server_bookmark,
+ "rel": "bookmark",
+ },
+ ],
+ },
+ {
+ "id": 2,
+ "uuid": FAKE_UUID,
+ 'created': self.TIMESTAMP,
+ 'updated': self.TIMESTAMP,
+ "progress": 100,
+ "name": "test_server_2",
+ "status": "ACTIVE",
+ "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": expected_image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": expected_flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {
+ "network_one": [
+ {
+ "version": 4,
+ "addr": "67.23.10.138",
+ },
+ {
+ "version": 6,
+ "addr": "::babe:67.23.10.138",
+ },
+ ],
+ },
+ "metadata": {
+ "Number": "2",
+ },
+ "links": [
+ {
+ "href": expected_server_href_2,
+ "rel": "self",
+ },
+ {
+ "href": expected_server_bookmark_2,
+ "rel": "bookmark",
+ },
+ ],
+ },
+ ]}
+
+ output = serializer.serialize(fixture, 'detail')
+ actual = minidom.parseString(output.replace(" ", ""))
+
+ expected = minidom.parseString("""
+ <servers xmlns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns:atom="http://www.w3.org/2005/Atom">
+ <server id="1"
+ uuid="%(expected_uuid)s"
+ name="test_server"
+ updated="%(expected_now)s"
+ created="%(expected_now)s"
+ hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
+ status="BUILD"
+ progress="0">
+ <atom:link href="%(expected_server_href)s" rel="self"/>
+ <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
+ <image id="5">
+ <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
+ </image>
+ <flavor id="1">
+ <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
+ </flavor>
+ <metadata>
+ <meta key="Number">
+ 1
+ </meta>
+ </metadata>
+ <addresses>
+ <network id="network_one">
+ <ip version="4" addr="67.23.10.138"/>
+ <ip version="6" addr="::babe:67.23.10.138"/>
+ </network>
+ </addresses>
+ </server>
+ <server id="2"
+ uuid="%(expected_uuid)s"
+ name="test_server_2"
+ updated="%(expected_now)s"
+ created="%(expected_now)s"
+ hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
+ status="ACTIVE"
+ progress="100">
+ <atom:link href="%(expected_server_href_2)s" rel="self"/>
+ <atom:link href="%(expected_server_bookmark_2)s" rel="bookmark"/>
+ <image id="5">
+ <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
+ </image>
+ <flavor id="1">
+ <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
+ </flavor>
+ <metadata>
+ <meta key="Number">
+ 2
+ </meta>
+ </metadata>
+ <addresses>
+ <network id="network_one">
+ <ip version="4" addr="67.23.10.138"/>
+ <ip version="6" addr="::babe:67.23.10.138"/>
+ </network>
+ </addresses>
+ </server>
+ </servers>
+ """.replace(" ", "") % (locals()))
+
+ self.assertEqual(expected.toxml(), actual.toxml())
diff --git a/nova/tests/api/openstack/test_shared_ip_groups.py b/nova/tests/api/openstack/test_shared_ip_groups.py
index c2bd7e45a..36fa1de0f 100644
--- a/nova/tests/api/openstack/test_shared_ip_groups.py
+++ b/nova/tests/api/openstack/test_shared_ip_groups.py
@@ -15,26 +15,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-import stubout
import webob
from nova import test
-from nova.api.openstack import shared_ip_groups
from nova.tests.api.openstack import fakes
class SharedIpGroupsTest(test.TestCase):
- def setUp(self):
- super(SharedIpGroupsTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
- fakes.stub_out_auth(self.stubs)
-
- def tearDown(self):
- self.stubs.UnsetAll()
- super(SharedIpGroupsTest, self).tearDown()
-
def test_get_shared_ip_groups(self):
req = webob.Request.blank('/v1.0/shared_ip_groups')
res = req.get_response(fakes.wsgi_app())
diff --git a/nova/tests/api/openstack/test_users.py b/nova/tests/api/openstack/test_users.py
index effb2f592..1d133f9ab 100644
--- a/nova/tests/api/openstack/test_users.py
+++ b/nova/tests/api/openstack/test_users.py
@@ -15,10 +15,8 @@
import json
-import stubout
import webob
-from nova import flags
from nova import test
from nova import utils
from nova.api.openstack import users
@@ -26,10 +24,6 @@ from nova.auth.manager import User, Project
from nova.tests.api.openstack import fakes
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
def fake_init(self):
self.manager = fakes.FakeAuthManager()
@@ -41,7 +35,7 @@ def fake_admin_check(self, req):
class UsersTest(test.TestCase):
def setUp(self):
super(UsersTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
+ self.flags(verbose=True, allow_admin_api=True)
self.stubs.Set(users.Controller, '__init__',
fake_init)
self.stubs.Set(users.Controller, '_check_admin',
@@ -57,17 +51,10 @@ class UsersTest(test.TestCase):
fakes.stub_out_rate_limiting(self.stubs)
fakes.stub_out_auth(self.stubs)
- self.allow_admin = FLAGS.allow_admin_api
- FLAGS.allow_admin_api = True
fakemgr = fakes.FakeAuthManager()
fakemgr.add_user(User('id1', 'guy1', 'acc1', 'secret1', False))
fakemgr.add_user(User('id2', 'guy2', 'acc2', 'secret2', True))
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.allow_admin_api = self.allow_admin
- super(UsersTest, self).tearDown()
-
def test_get_user_list(self):
req = webob.Request.blank('/v1.0/users')
res = req.get_response(fakes.wsgi_app())
diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py
index fd8d50904..1269f13c9 100644
--- a/nova/tests/api/openstack/test_versions.py
+++ b/nova/tests/api/openstack/test_versions.py
@@ -16,20 +16,92 @@
# under the License.
import json
+import stubout
import webob
+import xml.etree.ElementTree
+
from nova import context
from nova import test
from nova.tests.api.openstack import fakes
+from nova.api.openstack import versions
from nova.api.openstack import views
+from nova.api.openstack import wsgi
+
+VERSIONS = {
+ "v1.0": {
+ "id": "v1.0",
+ "status": "DEPRECATED",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.0+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.0+json",
+ },
+ ],
+ },
+ "v1.1": {
+ "id": "v1.1",
+ "status": "CURRENT",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.1+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.1+json",
+ },
+ ],
+ },
+}
class VersionsTest(test.TestCase):
def setUp(self):
super(VersionsTest, self).setUp()
self.context = context.get_admin_context()
+ self.stubs = stubout.StubOutForTesting()
+ fakes.stub_out_auth(self.stubs)
+ #Stub out VERSIONS
+ self.old_versions = versions.VERSIONS
+ versions.VERSIONS = VERSIONS
def tearDown(self):
+ versions.VERSIONS = self.old_versions
super(VersionsTest, self).tearDown()
def test_get_version_list(self):
@@ -43,24 +115,203 @@ class VersionsTest(test.TestCase):
{
"id": "v1.1",
"status": "CURRENT",
+ "updated": "2011-01-21T11:33:21Z",
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1",
+ "href": "http://localhost/v1.1/",
}],
},
{
"id": "v1.0",
"status": "DEPRECATED",
+ "updated": "2011-01-21T11:33:21Z",
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.0",
+ "href": "http://localhost/v1.0/",
}],
},
]
self.assertEqual(versions, expected)
+ def test_get_version_1_0_detail(self):
+ req = webob.Request.blank('/v1.0/')
+ req.accept = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual(res.content_type, "application/json")
+ version = json.loads(res.body)
+ expected = {
+ "version": {
+ "id": "v1.0",
+ "status": "DEPRECATED",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.0/",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/"
+ "vnd.openstack.compute-v1.0+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/"
+ "vnd.openstack.compute-v1.0+json",
+ },
+ ],
+ },
+ }
+ self.assertEqual(expected, version)
+
+ def test_get_version_1_1_detail(self):
+ req = webob.Request.blank('/v1.1/')
+ req.accept = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual(res.content_type, "application/json")
+ version = json.loads(res.body)
+ expected = {
+ "version": {
+ "id": "v1.1",
+ "status": "CURRENT",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/"
+ "vnd.openstack.compute-v1.1+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/"
+ "vnd.openstack.compute-v1.1+json",
+ },
+ ],
+ },
+ }
+ self.assertEqual(expected, version)
+
+ def test_get_version_1_0_detail_xml(self):
+ req = webob.Request.blank('/v1.0/')
+ req.accept = "application/xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual(res.content_type, "application/xml")
+ root = xml.etree.ElementTree.XML(res.body)
+ self.assertEqual(root.tag.split('}')[1], "version")
+ self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11)
+
+ children = list(root)
+ media_types = children[0]
+ media_type_nodes = list(media_types)
+ links = (children[1], children[2], children[3])
+
+ self.assertEqual(media_types.tag.split('}')[1], 'media-types')
+ for media_node in media_type_nodes:
+ self.assertEqual(media_node.tag.split('}')[1], 'media-type')
+
+ expected = """
+ <version id="v1.0" status="DEPRECATED"
+ updated="2011-01-21T11:33:21Z"
+ xmlns="%s"
+ xmlns:atom="http://www.w3.org/2005/Atom">
+
+ <media-types>
+ <media-type base="application/xml"
+ type="application/vnd.openstack.compute-v1.0+xml"/>
+ <media-type base="application/json"
+ type="application/vnd.openstack.compute-v1.0+json"/>
+ </media-types>
+
+ <atom:link href="http://localhost/v1.0/"
+ rel="self"/>
+
+ <atom:link href="http://docs.rackspacecloud.com/servers/
+ api/v1.0/cs-devguide-20110125.pdf"
+ rel="describedby"
+ type="application/pdf"/>
+
+ <atom:link href="http://docs.rackspacecloud.com/servers/
+ api/v1.0/application.wadl"
+ rel="describedby"
+ type="application/vnd.sun.wadl+xml"/>
+ </version>""".replace(" ", "").replace("\n", "") % wsgi.XMLNS_V11
+
+ actual = res.body.replace(" ", "").replace("\n", "")
+ self.assertEqual(expected, actual)
+
+ def test_get_version_1_1_detail_xml(self):
+ req = webob.Request.blank('/v1.1/')
+ req.accept = "application/xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual(res.content_type, "application/xml")
+ expected = """
+ <version id="v1.1" status="CURRENT"
+ updated="2011-01-21T11:33:21Z"
+ xmlns="%s"
+ xmlns:atom="http://www.w3.org/2005/Atom">
+
+ <media-types>
+ <media-type base="application/xml"
+ type="application/vnd.openstack.compute-v1.1+xml"/>
+ <media-type base="application/json"
+ type="application/vnd.openstack.compute-v1.1+json"/>
+ </media-types>
+
+ <atom:link href="http://localhost/v1.1/"
+ rel="self"/>
+
+ <atom:link href="http://docs.rackspacecloud.com/servers/
+ api/v1.1/cs-devguide-20110125.pdf"
+ rel="describedby"
+ type="application/pdf"/>
+
+ <atom:link href="http://docs.rackspacecloud.com/servers/
+ api/v1.1/application.wadl"
+ rel="describedby"
+ type="application/vnd.sun.wadl+xml"/>
+ </version>""".replace(" ", "").replace("\n", "") % wsgi.XMLNS_V11
+
+ actual = res.body.replace(" ", "").replace("\n", "")
+ self.assertEqual(expected, actual)
+
def test_get_version_list_xml(self):
req = webob.Request.blank('/')
req.accept = "application/xml"
@@ -68,44 +319,316 @@ class VersionsTest(test.TestCase):
self.assertEqual(res.status_int, 200)
self.assertEqual(res.content_type, "application/xml")
- expected = """<versions>
- <version id="v1.1" status="CURRENT">
- <links>
- <link href="http://localhost/v1.1" rel="self"/>
- </links>
+ expected = """
+ <versions xmlns="%s" xmlns:atom="%s">
+ <version id="v1.1" status="CURRENT" updated="2011-01-21T11:33:21Z">
+ <atom:link href="http://localhost/v1.1/" rel="self"/>
</version>
- <version id="v1.0" status="DEPRECATED">
- <links>
- <link href="http://localhost/v1.0" rel="self"/>
- </links>
+ <version id="v1.0" status="DEPRECATED"
+ updated="2011-01-21T11:33:21Z">
+ <atom:link href="http://localhost/v1.0/" rel="self"/>
</version>
- </versions>""".replace(" ", "").replace("\n", "")
+ </versions>""".replace(" ", "").replace("\n", "") % (wsgi.XMLNS_V11,
+ wsgi.XMLNS_ATOM)
+
+ actual = res.body.replace(" ", "").replace("\n", "")
+
+ self.assertEqual(expected, actual)
+
+ def test_get_version_1_0_detail_atom(self):
+ req = webob.Request.blank('/v1.0/')
+ req.accept = "application/atom+xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual("application/atom+xml", res.content_type)
+ expected = """
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <title type="text">About This Version</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <id>http://localhost/v1.0/</id>
+ <author>
+ <name>Rackspace</name>
+ <uri>http://www.rackspace.com/</uri>
+ </author>
+ <link href="http://localhost/v1.0/" rel="self"/>
+ <entry>
+ <id>http://localhost/v1.0/</id>
+ <title type="text">Version v1.0</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <link href="http://localhost/v1.0/"
+ rel="self"/>
+ <link href="http://docs.rackspacecloud.com/servers/
+ api/v1.0/cs-devguide-20110125.pdf"
+ rel="describedby" type="application/pdf"/>
+ <link href="http://docs.rackspacecloud.com/servers/
+ api/v1.0/application.wadl"
+ rel="describedby" type="application/vnd.sun.wadl+xml"/>
+ <content type="text">
+ Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)
+ </content>
+ </entry>
+ </feed>""".replace(" ", "").replace("\n", "")
+
+ actual = res.body.replace(" ", "").replace("\n", "")
+ self.assertEqual(expected, actual)
+
+ def test_get_version_1_1_detail_atom(self):
+ req = webob.Request.blank('/v1.1/')
+ req.accept = "application/atom+xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual("application/atom+xml", res.content_type)
+ expected = """
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <title type="text">About This Version</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <id>http://localhost/v1.1/</id>
+ <author>
+ <name>Rackspace</name>
+ <uri>http://www.rackspace.com/</uri>
+ </author>
+ <link href="http://localhost/v1.1/" rel="self"/>
+ <entry>
+ <id>http://localhost/v1.1/</id>
+ <title type="text">Version v1.1</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <link href="http://localhost/v1.1/"
+ rel="self"/>
+ <link href="http://docs.rackspacecloud.com/servers/
+ api/v1.1/cs-devguide-20110125.pdf"
+ rel="describedby" type="application/pdf"/>
+ <link href="http://docs.rackspacecloud.com/servers/
+ api/v1.1/application.wadl"
+ rel="describedby" type="application/vnd.sun.wadl+xml"/>
+ <content type="text">
+ Version v1.1 CURRENT (2011-01-21T11:33:21Z)
+ </content>
+ </entry>
+ </feed>""".replace(" ", "").replace("\n", "")
+
+ actual = res.body.replace(" ", "").replace("\n", "")
+ self.assertEqual(expected, actual)
+
+ def test_get_version_list_atom(self):
+ req = webob.Request.blank('/')
+ req.accept = "application/atom+xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ self.assertEqual(res.content_type, "application/atom+xml")
+
+ expected = """
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <title type="text">Available API Versions</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <id>http://localhost/</id>
+ <author>
+ <name>Rackspace</name>
+ <uri>http://www.rackspace.com/</uri>
+ </author>
+ <link href="http://localhost/" rel="self"/>
+ <entry>
+ <id>http://localhost/v1.1/</id>
+ <title type="text">Version v1.1</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <link href="http://localhost/v1.1/" rel="self"/>
+ <content type="text">
+ Version v1.1 CURRENT (2011-01-21T11:33:21Z)
+ </content>
+ </entry>
+ <entry>
+ <id>http://localhost/v1.0/</id>
+ <title type="text">Version v1.0</title>
+ <updated>2011-01-21T11:33:21Z</updated>
+ <link href="http://localhost/v1.0/" rel="self"/>
+ <content type="text">
+ Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)
+ </content>
+ </entry>
+ </feed>
+ """.replace(" ", "").replace("\n", "")
actual = res.body.replace(" ", "").replace("\n", "")
self.assertEqual(expected, actual)
+ def test_multi_choice_image(self):
+ req = webob.Request.blank('/images/1')
+ req.accept = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 300)
+ self.assertEqual(res.content_type, "application/json")
+
+ expected = {
+ "choices": [
+ {
+ "id": "v1.1",
+ "status": "CURRENT",
+ "links": [
+ {
+ "href": "http://localhost/v1.1/images/1",
+ "rel": "self",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.1+xml"
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.1+json"
+ },
+ ],
+ },
+ {
+ "id": "v1.0",
+ "status": "DEPRECATED",
+ "links": [
+ {
+ "href": "http://localhost/v1.0/images/1",
+ "rel": "self",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.0+xml"
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.0+json"
+ },
+ ],
+ },
+ ], }
+
+ self.assertDictMatch(expected, json.loads(res.body))
+
+ def test_multi_choice_image_xml(self):
+ req = webob.Request.blank('/images/1')
+ req.accept = "application/xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 300)
+ self.assertEqual(res.content_type, "application/xml")
+
+ expected = """
+ <choices xmlns="%s" xmlns:atom="%s">
+ <version id="v1.1" status="CURRENT">
+ <media-types>
+ <media-type base="application/xml"
+ type="application/vnd.openstack.compute-v1.1+xml"/>
+ <media-type base="application/json"
+ type="application/vnd.openstack.compute-v1.1+json"/>
+ </media-types>
+ <atom:link href="http://localhost/v1.1/images/1" rel="self"/>
+ </version>
+ <version id="v1.0" status="DEPRECATED">
+ <media-types>
+ <media-type base="application/xml"
+ type="application/vnd.openstack.compute-v1.0+xml"/>
+ <media-type base="application/json"
+ type="application/vnd.openstack.compute-v1.0+json"/>
+ </media-types>
+ <atom:link href="http://localhost/v1.0/images/1" rel="self"/>
+ </version>
+ </choices>""".replace(" ", "").replace("\n", "") % (wsgi.XMLNS_V11,
+ wsgi.XMLNS_ATOM)
+
+ def test_multi_choice_server_atom(self):
+ """
+ Make sure multi choice responses do not have content-type
+ application/atom+xml (should use default of json)
+ """
+ req = webob.Request.blank('/servers/2')
+ req.accept = "application/atom+xml"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 300)
+ self.assertEqual(res.content_type, "application/json")
+
+ def test_multi_choice_server(self):
+ req = webob.Request.blank('/servers/2')
+ req.accept = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 300)
+ self.assertEqual(res.content_type, "application/json")
+
+ expected = {
+ "choices": [
+ {
+ "id": "v1.1",
+ "status": "CURRENT",
+ "links": [
+ {
+ "href": "http://localhost/v1.1/servers/2",
+ "rel": "self",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.1+xml"
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.1+json"
+ },
+ ],
+ },
+ {
+ "id": "v1.0",
+ "status": "DEPRECATED",
+ "links": [
+ {
+ "href": "http://localhost/v1.0/servers/2",
+ "rel": "self",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.0+xml"
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.0+json"
+ },
+ ],
+ },
+ ], }
+
+ self.assertDictMatch(expected, json.loads(res.body))
+
+
+class VersionsViewBuilderTests(test.TestCase):
def test_view_builder(self):
base_url = "http://example.org/"
version_data = {
- "id": "3.2.1",
- "status": "CURRENT",
+ "v3.2.1": {
+ "id": "3.2.1",
+ "status": "CURRENT",
+ "updated": "2011-07-18T11:30:00Z",
+ }
}
expected = {
- "id": "3.2.1",
- "status": "CURRENT",
- "links": [
+ "versions": [
{
- "rel": "self",
- "href": "http://example.org/3.2.1",
- },
- ],
+ "id": "3.2.1",
+ "status": "CURRENT",
+ "updated": "2011-07-18T11:30:00Z",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://example.org/3.2.1/",
+ },
+ ],
+ }
+ ]
}
builder = views.versions.ViewBuilder(base_url)
- output = builder.build(version_data)
+ output = builder.build_versions(version_data)
self.assertEqual(output, expected)
@@ -113,9 +636,331 @@ class VersionsTest(test.TestCase):
base_url = "http://example.org/app/"
version_number = "v1.4.6"
- expected = "http://example.org/app/v1.4.6"
+ expected = "http://example.org/app/v1.4.6/"
builder = views.versions.ViewBuilder(base_url)
actual = builder.generate_href(version_number)
self.assertEqual(actual, expected)
+
+
+class VersionsSerializerTests(test.TestCase):
+ def test_versions_list_xml_serializer(self):
+ versions_data = {
+ 'versions': [
+ {
+ "id": "2.7.1",
+ "updated": "2011-07-18T11:30:00Z",
+ "status": "DEPRECATED",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://test/2.7.1",
+ },
+ ],
+ },
+ ]
+ }
+
+ serializer = versions.VersionsXMLSerializer()
+ response = serializer.index(versions_data)
+
+ root = xml.etree.ElementTree.XML(response)
+ self.assertEqual(root.tag.split('}')[1], "versions")
+ self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11)
+ version = list(root)[0]
+ self.assertEqual(version.tag.split('}')[1], "version")
+ self.assertEqual(version.get('id'),
+ versions_data['versions'][0]['id'])
+ self.assertEqual(version.get('status'),
+ versions_data['versions'][0]['status'])
+
+ link = list(version)[0]
+
+ self.assertEqual(link.tag.split('}')[1], "link")
+ self.assertEqual(link.tag.split('}')[0].strip('{'), wsgi.XMLNS_ATOM)
+ for key, val in versions_data['versions'][0]['links'][0].items():
+ self.assertEqual(link.get(key), val)
+
+ def test_versions_multi_xml_serializer(self):
+ versions_data = {
+ 'choices': [
+ {
+ "id": "2.7.1",
+ "updated": "2011-07-18T11:30:00Z",
+ "status": "DEPRECATED",
+ "media-types": VERSIONS['v1.1']['media-types'],
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://test/2.7.1/images",
+ },
+ ],
+ },
+ ]
+ }
+
+ serializer = versions.VersionsXMLSerializer()
+ response = serializer.multi(versions_data)
+
+ root = xml.etree.ElementTree.XML(response)
+ self.assertEqual(root.tag.split('}')[1], "choices")
+ self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11)
+ version = list(root)[0]
+ self.assertEqual(version.tag.split('}')[1], "version")
+ self.assertEqual(version.get('id'), versions_data['choices'][0]['id'])
+ self.assertEqual(version.get('status'),
+ versions_data['choices'][0]['status'])
+
+ media_types = list(version)[0]
+ media_type_nodes = list(media_types)
+ self.assertEqual(media_types.tag.split('}')[1], "media-types")
+
+ set_types = versions_data['choices'][0]['media-types']
+ for i, type in enumerate(set_types):
+ node = media_type_nodes[i]
+ self.assertEqual(node.tag.split('}')[1], "media-type")
+ for key, val in set_types[i].items():
+ self.assertEqual(node.get(key), val)
+
+ link = list(version)[1]
+
+ self.assertEqual(link.tag.split('}')[1], "link")
+ self.assertEqual(link.tag.split('}')[0].strip('{'), wsgi.XMLNS_ATOM)
+ for key, val in versions_data['choices'][0]['links'][0].items():
+ self.assertEqual(link.get(key), val)
+
+ def test_version_detail_xml_serializer(self):
+ version_data = {
+ "version": {
+ "id": "v1.0",
+ "status": "CURRENT",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.0/",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.0/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.0+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.0+json",
+ },
+ ],
+ },
+ }
+
+ serializer = versions.VersionsXMLSerializer()
+ response = serializer.show(version_data)
+
+ root = xml.etree.ElementTree.XML(response)
+ self.assertEqual(root.tag.split('}')[1], "version")
+ self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11)
+
+ children = list(root)
+ media_types = children[0]
+ media_type_nodes = list(media_types)
+ links = (children[1], children[2], children[3])
+
+ self.assertEqual(media_types.tag.split('}')[1], 'media-types')
+ for i, media_node in enumerate(media_type_nodes):
+ self.assertEqual(media_node.tag.split('}')[1], 'media-type')
+ for key, val in version_data['version']['media-types'][i].items():
+ self.assertEqual(val, media_node.get(key))
+
+ for i, link in enumerate(links):
+ self.assertEqual(link.tag.split('}')[0].strip('{'),
+ 'http://www.w3.org/2005/Atom')
+ self.assertEqual(link.tag.split('}')[1], 'link')
+ for key, val in version_data['version']['links'][i].items():
+ self.assertEqual(val, link.get(key))
+
+ def test_versions_list_atom_serializer(self):
+ versions_data = {
+ 'versions': [
+ {
+ "id": "2.9.8",
+ "updated": "2011-07-20T11:40:00Z",
+ "status": "CURRENT",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://test/2.9.8",
+ },
+ ],
+ },
+ ]
+ }
+
+ serializer = versions.VersionsAtomSerializer()
+ response = serializer.index(versions_data)
+
+ root = xml.etree.ElementTree.XML(response)
+ self.assertEqual(root.tag.split('}')[1], "feed")
+ self.assertEqual(root.tag.split('}')[0].strip('{'),
+ "http://www.w3.org/2005/Atom")
+
+ children = list(root)
+ title = children[0]
+ updated = children[1]
+ id = children[2]
+ author = children[3]
+ link = children[4]
+ entry = children[5]
+
+ self.assertEqual(title.tag.split('}')[1], 'title')
+ self.assertEqual(title.text, 'Available API Versions')
+ self.assertEqual(updated.tag.split('}')[1], 'updated')
+ self.assertEqual(updated.text, '2011-07-20T11:40:00Z')
+ self.assertEqual(id.tag.split('}')[1], 'id')
+ self.assertEqual(id.text, 'http://test/')
+
+ self.assertEqual(author.tag.split('}')[1], 'author')
+ author_name = list(author)[0]
+ author_uri = list(author)[1]
+ self.assertEqual(author_name.tag.split('}')[1], 'name')
+ self.assertEqual(author_name.text, 'Rackspace')
+ self.assertEqual(author_uri.tag.split('}')[1], 'uri')
+ self.assertEqual(author_uri.text, 'http://www.rackspace.com/')
+
+ self.assertEqual(link.get('href'), 'http://test/')
+ self.assertEqual(link.get('rel'), 'self')
+
+ self.assertEqual(entry.tag.split('}')[1], 'entry')
+ entry_children = list(entry)
+ entry_id = entry_children[0]
+ entry_title = entry_children[1]
+ entry_updated = entry_children[2]
+ entry_link = entry_children[3]
+ entry_content = entry_children[4]
+ self.assertEqual(entry_id.tag.split('}')[1], "id")
+ self.assertEqual(entry_id.text, "http://test/2.9.8")
+ self.assertEqual(entry_title.tag.split('}')[1], "title")
+ self.assertEqual(entry_title.get('type'), "text")
+ self.assertEqual(entry_title.text, "Version 2.9.8")
+ self.assertEqual(entry_updated.tag.split('}')[1], "updated")
+ self.assertEqual(entry_updated.text, "2011-07-20T11:40:00Z")
+ self.assertEqual(entry_link.tag.split('}')[1], "link")
+ self.assertEqual(entry_link.get('href'), "http://test/2.9.8")
+ self.assertEqual(entry_link.get('rel'), "self")
+ self.assertEqual(entry_content.tag.split('}')[1], "content")
+ self.assertEqual(entry_content.get('type'), "text")
+ self.assertEqual(entry_content.text,
+ "Version 2.9.8 CURRENT (2011-07-20T11:40:00Z)")
+
+ def test_version_detail_atom_serializer(self):
+ versions_data = {
+ "version": {
+ "id": "v1.1",
+ "status": "CURRENT",
+ "updated": "2011-01-21T11:33:21Z",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/cs-devguide-20110125.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.compute-v1.1+xml",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.compute-v1.1+json",
+ }
+ ],
+ },
+ }
+
+ serializer = versions.VersionsAtomSerializer()
+ response = serializer.show(versions_data)
+
+ root = xml.etree.ElementTree.XML(response)
+ self.assertEqual(root.tag.split('}')[1], "feed")
+ self.assertEqual(root.tag.split('}')[0].strip('{'),
+ "http://www.w3.org/2005/Atom")
+
+ children = list(root)
+ title = children[0]
+ updated = children[1]
+ id = children[2]
+ author = children[3]
+ link = children[4]
+ entry = children[5]
+
+ self.assertEqual(root.tag.split('}')[1], 'feed')
+ self.assertEqual(title.tag.split('}')[1], 'title')
+ self.assertEqual(title.text, 'About This Version')
+ self.assertEqual(updated.tag.split('}')[1], 'updated')
+ self.assertEqual(updated.text, '2011-01-21T11:33:21Z')
+ self.assertEqual(id.tag.split('}')[1], 'id')
+ self.assertEqual(id.text, 'http://localhost/v1.1/')
+
+ self.assertEqual(author.tag.split('}')[1], 'author')
+ author_name = list(author)[0]
+ author_uri = list(author)[1]
+ self.assertEqual(author_name.tag.split('}')[1], 'name')
+ self.assertEqual(author_name.text, 'Rackspace')
+ self.assertEqual(author_uri.tag.split('}')[1], 'uri')
+ self.assertEqual(author_uri.text, 'http://www.rackspace.com/')
+
+ self.assertEqual(link.get('href'),
+ 'http://localhost/v1.1/')
+ self.assertEqual(link.get('rel'), 'self')
+
+ self.assertEqual(entry.tag.split('}')[1], 'entry')
+ entry_children = list(entry)
+ entry_id = entry_children[0]
+ entry_title = entry_children[1]
+ entry_updated = entry_children[2]
+ entry_links = (entry_children[3], entry_children[4], entry_children[5])
+ entry_content = entry_children[6]
+
+ self.assertEqual(entry_id.tag.split('}')[1], "id")
+ self.assertEqual(entry_id.text,
+ "http://localhost/v1.1/")
+ self.assertEqual(entry_title.tag.split('}')[1], "title")
+ self.assertEqual(entry_title.get('type'), "text")
+ self.assertEqual(entry_title.text, "Version v1.1")
+ self.assertEqual(entry_updated.tag.split('}')[1], "updated")
+ self.assertEqual(entry_updated.text, "2011-01-21T11:33:21Z")
+
+ for i, link in enumerate(versions_data["version"]["links"]):
+ self.assertEqual(entry_links[i].tag.split('}')[1], "link")
+ for key, val in versions_data["version"]["links"][i].items():
+ self.assertEqual(entry_links[i].get(key), val)
+
+ self.assertEqual(entry_content.tag.split('}')[1], "content")
+ self.assertEqual(entry_content.get('type'), "text")
+ self.assertEqual(entry_content.text,
+ "Version v1.1 CURRENT (2011-01-21T11:33:21Z)")
diff --git a/nova/tests/api/openstack/test_wsgi.py b/nova/tests/api/openstack/test_wsgi.py
index 5bdda7c7e..6dea78d17 100644
--- a/nova/tests/api/openstack/test_wsgi.py
+++ b/nova/tests/api/openstack/test_wsgi.py
@@ -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,
diff --git a/nova/tests/api/openstack/test_zones.py b/nova/tests/api/openstack/test_zones.py
index 6a6e13d93..4a46a5764 100644
--- a/nova/tests/api/openstack/test_zones.py
+++ b/nova/tests/api/openstack/test_zones.py
@@ -29,7 +29,6 @@ from nova.scheduler import api
FLAGS = flags.FLAGS
-FLAGS.verbose = True
def zone_get(context, zone_id):
@@ -95,31 +94,15 @@ def zone_select(context, specs):
class ZonesTest(test.TestCase):
def setUp(self):
super(ZonesTest, self).setUp()
- self.stubs = stubout.StubOutForTesting()
- fakes.FakeAuthManager.reset_fake_data()
- fakes.FakeAuthDatabase.data = {}
+ self.flags(verbose=True, allow_admin_api=True)
fakes.stub_out_networking(self.stubs)
fakes.stub_out_rate_limiting(self.stubs)
- fakes.stub_out_auth(self.stubs)
-
- self.allow_admin = FLAGS.allow_admin_api
- FLAGS.allow_admin_api = True
self.stubs.Set(nova.db, 'zone_get', zone_get)
self.stubs.Set(nova.db, 'zone_update', zone_update)
self.stubs.Set(nova.db, 'zone_create', zone_create)
self.stubs.Set(nova.db, 'zone_delete', zone_delete)
- self.old_zone_name = FLAGS.zone_name
- self.old_zone_capabilities = FLAGS.zone_capabilities
-
- def tearDown(self):
- self.stubs.UnsetAll()
- FLAGS.allow_admin_api = self.allow_admin
- FLAGS.zone_name = self.old_zone_name
- FLAGS.zone_capabilities = self.old_zone_capabilities
- super(ZonesTest, self).tearDown()
-
def test_get_zone_list_scheduler(self):
self.stubs.Set(api, '_call_scheduler', zone_get_all_scheduler)
req = webob.Request.blank('/v1.0/zones')
@@ -190,8 +173,8 @@ class ZonesTest(test.TestCase):
self.assertFalse('username' in res_dict['zone'])
def test_zone_info(self):
- FLAGS.zone_name = 'darksecret'
- FLAGS.zone_capabilities = ['cap1=a;b', 'cap2=c;d']
+ caps = ['cap1=a;b', 'cap2=c;d']
+ self.flags(zone_name='darksecret', zone_capabilities=caps)
self.stubs.Set(api, '_call_scheduler', zone_capabilities)
body = dict(zone=dict(username='zeb', password='sneaky'))
@@ -205,7 +188,8 @@ class ZonesTest(test.TestCase):
self.assertEqual(res_dict['zone']['cap2'], 'c;d')
def test_zone_select(self):
- FLAGS.build_plan_encryption_key = 'c286696d887c9aa0611bbb3e2025a45a'
+ key = 'c286696d887c9aa0611bbb3e2025a45a'
+ self.flags(build_plan_encryption_key=key)
self.stubs.Set(api, 'select', zone_select)
req = webob.Request.blank('/v1.0/zones/select')
diff --git a/nova/tests/db/fakes.py b/nova/tests/db/fakes.py
index 7762df41c..19028a451 100644
--- a/nova/tests/db/fakes.py
+++ b/nova/tests/db/fakes.py
@@ -230,7 +230,7 @@ def stub_out_db_network_api(stubs):
continue
fixed_ip_fields['virtual_interface'] = FakeModel(vif[0])
- def fake_instance_type_get_by_id(context, id):
+ def fake_instance_type_get(context, id):
if flavor_fields['id'] == id:
return FakeModel(flavor_fields)
@@ -323,7 +323,7 @@ def stub_out_db_network_api(stubs):
fake_fixed_ip_get_by_address,
fake_fixed_ip_get_network,
fake_fixed_ip_update,
- fake_instance_type_get_by_id,
+ fake_instance_type_get,
fake_virtual_interface_create,
fake_virtual_interface_delete_by_instance,
fake_virtual_interface_get_by_instance,
@@ -415,7 +415,7 @@ def stub_out_db_instance_api(stubs, injected=True):
def fake_instance_type_get_by_name(context, name):
return INSTANCE_TYPES[name]
- def fake_instance_type_get_by_id(context, id):
+ def fake_instance_type_get(context, id):
for name, inst_type in INSTANCE_TYPES.iteritems():
if str(inst_type['id']) == str(id):
return inst_type
@@ -448,7 +448,7 @@ def stub_out_db_instance_api(stubs, injected=True):
fake_network_get_all_by_instance,
fake_instance_type_get_all,
fake_instance_type_get_by_name,
- fake_instance_type_get_by_id,
+ fake_instance_type_get,
fake_instance_get_fixed_addresses,
fake_instance_get_fixed_addresses_v6,
fake_network_get_all_by_instance,
diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py
index 2297d2f0e..073216495 100644
--- a/nova/tests/fake_flags.py
+++ b/nova/tests/fake_flags.py
@@ -42,3 +42,4 @@ FLAGS['iscsi_num_targets'].SetDefault(8)
FLAGS['verbose'].SetDefault(True)
FLAGS['sqlite_db'].SetDefault("tests.sqlite")
FLAGS['use_ipv6'].SetDefault(True)
+FLAGS['flat_network_bridge'].SetDefault('br100')
diff --git a/nova/tests/glance/stubs.py b/nova/tests/glance/stubs.py
index aac3ff330..d51b19ccd 100644
--- a/nova/tests/glance/stubs.py
+++ b/nova/tests/glance/stubs.py
@@ -60,7 +60,10 @@ class FakeGlance(object):
'container_format': 'ovf'},
'image_data': StringIO.StringIO('')}}
- def __init__(self, host, port=None, use_ssl=False):
+ def __init__(self, host, port=None, use_ssl=False, auth_tok=None):
+ pass
+
+ def set_auth_token(self, auth_tok):
pass
def get_image_meta(self, image_id):
diff --git a/nova/tests/hyperv_unittest.py b/nova/tests/hyperv_unittest.py
index 042819b9c..d346d0a70 100644
--- a/nova/tests/hyperv_unittest.py
+++ b/nova/tests/hyperv_unittest.py
@@ -21,24 +21,18 @@ import random
from nova import context
from nova import db
-from nova import flags
from nova import test
-from nova.auth import manager
from nova.virt import hyperv
-FLAGS = flags.FLAGS
-FLAGS.connection_type = 'hyperv'
-
class HyperVTestCase(test.TestCase):
"""Test cases for the Hyper-V driver"""
def setUp(self):
super(HyperVTestCase, self).setUp()
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake',
- admin=True)
- self.project = self.manager.create_project('fake', 'fake', 'fake')
- self.context = context.RequestContext(self.user, self.project)
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
+ self.flags(connection_type='hyperv')
def test_create_destroy(self):
"""Create a VM and destroy it"""
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 223e7ae57..5a40f578f 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -31,6 +31,9 @@ class StubGlanceClient(object):
self.add_response = add_response
self.update_response = update_response
+ def set_auth_token(self, auth_tok):
+ pass
+
def get_image_meta(self, image_id):
return self.images[image_id]
diff --git a/nova/tests/image/test_s3.py b/nova/tests/image/test_s3.py
index 231e109f8..f1ceeb7fe 100644
--- a/nova/tests/image/test_s3.py
+++ b/nova/tests/image/test_s3.py
@@ -16,12 +16,9 @@
# under the License.
from nova import context
-from nova import flags
from nova import test
from nova.image import s3
-FLAGS = flags.FLAGS
-
ami_manifest_xml = """<?xml version="1.0" ?>
<manifest>
@@ -59,15 +56,10 @@ ami_manifest_xml = """<?xml version="1.0" ?>
class TestS3ImageService(test.TestCase):
def setUp(self):
super(TestS3ImageService, self).setUp()
- self.orig_image_service = FLAGS.image_service
- FLAGS.image_service = 'nova.image.fake.FakeImageService'
+ self.flags(image_service='nova.image.fake.FakeImageService')
self.image_service = s3.S3ImageService()
self.context = context.RequestContext(None, None)
- def tearDown(self):
- super(TestS3ImageService, self).tearDown()
- FLAGS.image_service = self.orig_image_service
-
def _assertEqualList(self, list0, list1, keys):
self.assertEqual(len(list0), len(list1))
key = keys[0]
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
index 47bd8c1e4..fb2f88502 100644
--- a/nova/tests/integrated/integrated_helpers.py
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -23,7 +23,6 @@ import random
import string
from nova import exception
-from nova import flags
from nova import service
from nova import test # For the flags
from nova.auth import manager
@@ -32,8 +31,6 @@ from nova.log import logging
from nova.tests.integrated.api import client
-FLAGS = flags.FLAGS
-
LOG = logging.getLogger('nova.tests.integrated')
@@ -151,6 +148,7 @@ class _IntegratedTestBase(test.TestCase):
f = self._get_flags()
self.flags(**f)
+ self.flags(verbose=True)
def fake_get_image_service(image_href):
image_id = int(str(image_href).split('/')[-1])
diff --git a/nova/tests/integrated/test_extensions.py b/nova/tests/integrated/test_extensions.py
index 0d4ee8cab..c22cf0be0 100644
--- a/nova/tests/integrated/test_extensions.py
+++ b/nova/tests/integrated/test_extensions.py
@@ -17,7 +17,6 @@
import os
-from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
@@ -25,10 +24,6 @@ from nova.tests.integrated import integrated_helpers
LOG = logging.getLogger('nova.tests.integrated')
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
class ExtensionsTest(integrated_helpers._IntegratedTestBase):
def _get_flags(self):
f = super(ExtensionsTest, self)._get_flags()
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index a5180b6bc..06359a52f 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -17,7 +17,6 @@
import unittest
-from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
@@ -25,9 +24,6 @@ from nova.tests.integrated.api import client
LOG = logging.getLogger('nova.tests.integrated')
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
class LoginTest(integrated_helpers._IntegratedTestBase):
def test_login(self):
diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py
index 4e8e85c7b..150279a95 100644
--- a/nova/tests/integrated/test_servers.py
+++ b/nova/tests/integrated/test_servers.py
@@ -18,7 +18,6 @@
import time
import unittest
-from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
@@ -27,10 +26,6 @@ from nova.tests.integrated.api import client
LOG = logging.getLogger('nova.tests.integrated')
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
class ServersTest(integrated_helpers._IntegratedTestBase):
def test_get_servers(self):
"""Simple check that listing servers works."""
@@ -305,5 +300,6 @@ class ServersTest(integrated_helpers._IntegratedTestBase):
# Cleanup
self._delete_server(server_id)
+
if __name__ == "__main__":
unittest.main()
diff --git a/nova/tests/integrated/test_volumes.py b/nova/tests/integrated/test_volumes.py
index e9fb3c4d1..d3e936462 100644
--- a/nova/tests/integrated/test_volumes.py
+++ b/nova/tests/integrated/test_volumes.py
@@ -18,7 +18,6 @@
import unittest
import time
-from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
@@ -28,10 +27,6 @@ from nova.volume import driver
LOG = logging.getLogger('nova.tests.integrated')
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
class VolumesTest(integrated_helpers._IntegratedTestBase):
def setUp(self):
super(VolumesTest, self).setUp()
diff --git a/nova/tests/integrated/test_xml.py b/nova/tests/integrated/test_xml.py
index fde32f797..74baaacc2 100644
--- a/nova/tests/integrated/test_xml.py
+++ b/nova/tests/integrated/test_xml.py
@@ -15,7 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.api.openstack import common
@@ -24,10 +23,6 @@ from nova.api.openstack import common
LOG = logging.getLogger('nova.tests.integrated')
-FLAGS = flags.FLAGS
-FLAGS.verbose = True
-
-
class XmlTests(integrated_helpers._IntegratedTestBase):
""""Some basic XML sanity checks."""
diff --git a/nova/tests/scheduler/test_host_filter.py b/nova/tests/scheduler/test_host_filter.py
index b1892dab4..7e664d3f9 100644
--- a/nova/tests/scheduler/test_host_filter.py
+++ b/nova/tests/scheduler/test_host_filter.py
@@ -19,12 +19,9 @@ Tests For Scheduler Host Filters.
import json
from nova import exception
-from nova import flags
from nova import test
from nova.scheduler import host_filter
-FLAGS = flags.FLAGS
-
class FakeZoneManager:
pass
@@ -57,9 +54,9 @@ class HostFilterTestCase(test.TestCase):
'host_name-label': 'xs-%s' % multiplier}
def setUp(self):
- self.old_flag = FLAGS.default_host_filter
- FLAGS.default_host_filter = \
- 'nova.scheduler.host_filter.AllHostsFilter'
+ super(HostFilterTestCase, self).setUp()
+ default_host_filter = 'nova.scheduler.host_filter.AllHostsFilter'
+ self.flags(default_host_filter=default_host_filter)
self.instance_type = dict(name='tiny',
memory_mb=50,
vcpus=10,
@@ -98,9 +95,6 @@ class HostFilterTestCase(test.TestCase):
host09['xpu_arch'] = 'fermi'
host09['xpu_info'] = 'Tesla 2150'
- def tearDown(self):
- FLAGS.default_host_filter = self.old_flag
-
def test_choose_filter(self):
# Test default filter ...
hf = host_filter.choose_host_filter()
diff --git a/nova/tests/scheduler/test_least_cost_scheduler.py b/nova/tests/scheduler/test_least_cost_scheduler.py
index 49791053e..fbe6b2f77 100644
--- a/nova/tests/scheduler/test_least_cost_scheduler.py
+++ b/nova/tests/scheduler/test_least_cost_scheduler.py
@@ -16,13 +16,11 @@
Tests For Least Cost Scheduler
"""
-from nova import flags
from nova import test
from nova.scheduler import least_cost
from nova.tests.scheduler import test_zone_aware_scheduler
MB = 1024 * 1024
-FLAGS = flags.FLAGS
class FakeHost(object):
@@ -95,10 +93,9 @@ class LeastCostSchedulerTestCase(test.TestCase):
self.assertWeights(expected, num, request_spec, hosts)
def test_noop_cost_fn(self):
- FLAGS.least_cost_scheduler_cost_functions = [
- 'nova.scheduler.least_cost.noop_cost_fn',
- ]
- FLAGS.noop_cost_fn_weight = 1
+ self.flags(least_cost_scheduler_cost_functions=[
+ 'nova.scheduler.least_cost.noop_cost_fn'],
+ noop_cost_fn_weight=1)
num = 1
request_spec = {}
@@ -109,10 +106,9 @@ class LeastCostSchedulerTestCase(test.TestCase):
self.assertWeights(expected, num, request_spec, hosts)
def test_cost_fn_weights(self):
- FLAGS.least_cost_scheduler_cost_functions = [
- 'nova.scheduler.least_cost.noop_cost_fn',
- ]
- FLAGS.noop_cost_fn_weight = 2
+ self.flags(least_cost_scheduler_cost_functions=[
+ 'nova.scheduler.least_cost.noop_cost_fn'],
+ noop_cost_fn_weight=2)
num = 1
request_spec = {}
@@ -123,10 +119,9 @@ class LeastCostSchedulerTestCase(test.TestCase):
self.assertWeights(expected, num, request_spec, hosts)
def test_compute_fill_first_cost_fn(self):
- FLAGS.least_cost_scheduler_cost_functions = [
- 'nova.scheduler.least_cost.compute_fill_first_cost_fn',
- ]
- FLAGS.compute_fill_first_cost_fn_weight = 1
+ self.flags(least_cost_scheduler_cost_functions=[
+ 'nova.scheduler.least_cost.compute_fill_first_cost_fn'],
+ compute_fill_first_cost_fn_weight=1)
num = 1
instance_type = {'memory_mb': 1024}
diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py
index daea826fd..f60eb6433 100644
--- a/nova/tests/scheduler/test_scheduler.py
+++ b/nova/tests/scheduler/test_scheduler.py
@@ -23,7 +23,6 @@ import datetime
import mox
import novaclient.exceptions
import stubout
-import webob
from mox import IgnoreArg
from nova import context
@@ -34,12 +33,10 @@ from nova import service
from nova import test
from nova import rpc
from nova import utils
-from nova.auth import manager as auth_manager
from nova.scheduler import api
from nova.scheduler import manager
from nova.scheduler import driver
from nova.compute import power_state
-from nova.db.sqlalchemy import models
FLAGS = flags.FLAGS
@@ -250,23 +247,17 @@ class SimpleDriverTestCase(test.TestCase):
volume_driver='nova.volume.driver.FakeISCSIDriver',
scheduler_driver='nova.scheduler.simple.SimpleScheduler')
self.scheduler = manager.SchedulerManager()
- self.manager = auth_manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake')
- self.project = self.manager.create_project('fake', 'fake', 'fake')
self.context = context.get_admin_context()
-
- def tearDown(self):
- self.manager.delete_user(self.user)
- self.manager.delete_project(self.project)
- super(SimpleDriverTestCase, self).tearDown()
+ self.user_id = 'fake'
+ self.project_id = 'fake'
def _create_instance(self, **kwargs):
"""Create a test instance"""
inst = {}
inst['image_id'] = 1
inst['reservation_id'] = 'r-fakeres'
- inst['user_id'] = self.user.id
- inst['project_id'] = self.project.id
+ inst['user_id'] = self.user_id
+ inst['project_id'] = self.project_id
inst['instance_type_id'] = '1'
inst['vcpus'] = kwargs.get('vcpus', 1)
inst['ami_launch_index'] = 0
@@ -485,11 +476,6 @@ class SimpleDriverTestCase(test.TestCase):
self.assertEqual(host, 'host2')
volume1.delete_volume(self.context, volume_id1)
db.volume_destroy(self.context, volume_id2)
- dic = {'service_id': s_ref['id'],
- 'vcpus': 16, 'memory_mb': 32, 'local_gb': 100,
- 'vcpus_used': 16, 'memory_mb_used': 12, 'local_gb_used': 10,
- 'hypervisor_type': 'qemu', 'hypervisor_version': 12003,
- 'cpu_info': ''}
def test_doesnt_report_disabled_hosts_as_up(self):
"""Ensures driver doesn't find hosts before they are enabled"""
@@ -976,13 +962,10 @@ class ZoneRedirectTest(test.TestCase):
self.stubs.Set(db, 'zone_get_all', zone_get_all)
self.stubs.Set(db, 'instance_get_by_uuid',
fake_instance_get_by_uuid)
-
- self.enable_zone_routing = FLAGS.enable_zone_routing
- FLAGS.enable_zone_routing = True
+ self.flags(enable_zone_routing=True)
def tearDown(self):
self.stubs.UnsetAll()
- FLAGS.enable_zone_routing = self.enable_zone_routing
super(ZoneRedirectTest, self).tearDown()
def test_trap_found_locally(self):
@@ -1012,7 +995,7 @@ class ZoneRedirectTest(test.TestCase):
self.assertEquals(e.results['magic'], 'found me')
def test_routing_flags(self):
- FLAGS.enable_zone_routing = False
+ self.flags(enable_zone_routing=False)
decorator = FakeRerouteCompute("foo")
self.assertRaises(exception.InstanceNotFound, decorator(go_boom),
None, None, 1)
diff --git a/nova/tests/scheduler/test_zone_aware_scheduler.py b/nova/tests/scheduler/test_zone_aware_scheduler.py
index d74b71fb6..7833028c3 100644
--- a/nova/tests/scheduler/test_zone_aware_scheduler.py
+++ b/nova/tests/scheduler/test_zone_aware_scheduler.py
@@ -16,6 +16,8 @@
Tests For Zone Aware Scheduler.
"""
+import json
+
import nova.db
from nova import exception
@@ -327,3 +329,19 @@ class ZoneAwareSchedulerTestCase(test.TestCase):
sched._provision_resource_from_blob(None, request_spec, 1,
request_spec, {})
self.assertTrue(was_called)
+
+ def test_decrypt_blob(self):
+ """Test that the decrypt method works."""
+
+ fixture = FakeZoneAwareScheduler()
+ test_data = {"foo": "bar"}
+
+ class StubDecryptor(object):
+ def decryptor(self, key):
+ return lambda blob: blob
+
+ self.stubs.Set(zone_aware_scheduler, 'crypto',
+ StubDecryptor())
+
+ self.assertEqual(fixture._decrypt_blob(test_data),
+ json.dumps(test_data))
diff --git a/nova/tests/test_access.py b/nova/tests/test_access.py
index e170ccee6..3b54fc249 100644
--- a/nova/tests/test_access.py
+++ b/nova/tests/test_access.py
@@ -16,7 +16,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import unittest
import webob
from nova import context
@@ -41,7 +40,7 @@ class FakeApiRequest(object):
class AccessTestCase(test.TestCase):
def _env_for(self, ctxt, action):
env = {}
- env['ec2.context'] = ctxt
+ env['nova.context'] = ctxt
env['ec2.request'] = FakeApiRequest(action)
return env
@@ -93,7 +92,11 @@ class AccessTestCase(test.TestCase):
super(AccessTestCase, self).tearDown()
def response_status(self, user, methodName):
- ctxt = context.RequestContext(user, self.project)
+ roles = manager.AuthManager().get_active_roles(user, self.project)
+ ctxt = context.RequestContext(user.id,
+ self.project.id,
+ is_admin=user.is_admin(),
+ roles=roles)
environ = self._env_for(ctxt, methodName)
req = webob.Request.blank('/', environ)
resp = req.get_response(self.mw)
@@ -105,30 +108,26 @@ class AccessTestCase(test.TestCase):
def shouldDeny(self, user, methodName):
self.assertEqual(401, self.response_status(user, methodName))
- def test_001_allow_all(self):
+ def test_allow_all(self):
users = [self.testadmin, self.testpmsys, self.testnet, self.testsys]
for user in users:
self.shouldAllow(user, '_allow_all')
- def test_002_allow_none(self):
+ def test_allow_none(self):
self.shouldAllow(self.testadmin, '_allow_none')
users = [self.testpmsys, self.testnet, self.testsys]
for user in users:
self.shouldDeny(user, '_allow_none')
- def test_003_allow_project_manager(self):
+ def test_allow_project_manager(self):
for user in [self.testadmin, self.testpmsys]:
self.shouldAllow(user, '_allow_project_manager')
for user in [self.testnet, self.testsys]:
self.shouldDeny(user, '_allow_project_manager')
- def test_004_allow_sys_and_net(self):
+ def test_allow_sys_and_net(self):
for user in [self.testadmin, self.testnet, self.testsys]:
self.shouldAllow(user, '_allow_sys_and_net')
# denied because it doesn't have the per project sysadmin
for user in [self.testpmsys]:
self.shouldDeny(user, '_allow_sys_and_net')
-
-if __name__ == "__main__":
- # TODO: Implement use_fake as an option
- unittest.main()
diff --git a/nova/tests/test_adminapi.py b/nova/tests/test_adminapi.py
index 877cf4ea1..06cc498ac 100644
--- a/nova/tests/test_adminapi.py
+++ b/nova/tests/test_adminapi.py
@@ -25,7 +25,6 @@ from nova import log as logging
from nova import rpc
from nova import test
from nova import utils
-from nova.auth import manager
from nova.api.ec2 import admin
from nova.image import fake
@@ -39,7 +38,7 @@ class AdminApiTestCase(test.TestCase):
super(AdminApiTestCase, self).setUp()
self.flags(connection_type='fake')
- self.conn = rpc.Connection.instance()
+ self.conn = rpc.create_connection()
# set up our cloud
self.api = admin.AdminController()
@@ -51,11 +50,11 @@ class AdminApiTestCase(test.TestCase):
self.volume = self.start_service('volume')
self.image_service = utils.import_object(FLAGS.image_service)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('admin', 'admin', 'admin', True)
- self.project = self.manager.create_project('proj', 'admin', 'proj')
- self.context = context.RequestContext(user=self.user,
- project=self.project)
+ self.user_id = 'admin'
+ self.project_id = 'admin'
+ self.context = context.RequestContext(self.user_id,
+ self.project_id,
+ True)
def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
@@ -73,11 +72,6 @@ class AdminApiTestCase(test.TestCase):
self.stubs.Set(rpc, 'cast', finish_cast)
- def tearDown(self):
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
- super(AdminApiTestCase, self).tearDown()
-
def test_block_external_ips(self):
"""Make sure provider firewall rules are created."""
result = self.api.block_external_addresses(self.context, '1.1.1.1/32')
diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py
index 40e62ac76..3af1563fa 100644
--- a/nova/tests/test_api.py
+++ b/nova/tests/test_api.py
@@ -30,11 +30,11 @@ import webob
from nova import context
from nova import exception
from nova import test
+from nova import wsgi
from nova.api import ec2
from nova.api.ec2 import apirequest
from nova.api.ec2 import cloud
from nova.api.ec2 import ec2utils
-from nova.auth import manager
class FakeHttplibSocket(object):
@@ -192,10 +192,13 @@ class ApiEc2TestCase(test.TestCase):
"""Unit test for the cloud controller on an EC2 API"""
def setUp(self):
super(ApiEc2TestCase, self).setUp()
- self.manager = manager.AuthManager()
self.host = '127.0.0.1'
- self.app = ec2.Authenticate(ec2.Requestify(ec2.Executor(),
- 'nova.api.ec2.cloud.CloudController'))
+ # NOTE(vish): skipping the Authorizer
+ roles = ['sysadmin', 'netadmin']
+ ctxt = context.RequestContext('fake', 'fake', roles=roles)
+ self.app = wsgi.InjectContext(ctxt,
+ ec2.Requestify(ec2.Authorizer(ec2.Executor()),
+ 'nova.api.ec2.cloud.CloudController'))
def expect_http(self, host=None, is_secure=False, api_version=None):
"""Returns a new EC2 connection"""
@@ -213,7 +216,11 @@ class ApiEc2TestCase(test.TestCase):
self.http = FakeHttplibConnection(
self.app, '%s:8773' % (self.host), False)
# pylint: disable=E1103
- self.ec2.new_http_connection(host, is_secure).AndReturn(self.http)
+ if boto.Version >= '2':
+ self.ec2.new_http_connection(host or '%s:8773' % (self.host),
+ is_secure).AndReturn(self.http)
+ else:
+ self.ec2.new_http_connection(host, is_secure).AndReturn(self.http)
return self.http
def test_return_valid_isoformat(self):
@@ -242,39 +249,25 @@ class ApiEc2TestCase(test.TestCase):
self.expect_http(api_version='2010-10-30')
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
-
# Any request should be fine
self.ec2.get_all_instances()
self.assertTrue(self.ec2.APIVersion in self.http.getresponsebody(),
'The version in the xmlns of the response does '
'not match the API version given in the request.')
- self.manager.delete_project(project)
- self.manager.delete_user(user)
-
def test_describe_instances(self):
"""Test that, after creating a user and a project, the describe
instances call to the API works properly"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
self.assertEqual(self.ec2.get_all_instances(), [])
- self.manager.delete_project(project)
- self.manager.delete_user(user)
def test_terminate_invalid_instance(self):
"""Attempt to terminate an invalid instance"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
self.assertRaises(EC2ResponseError, self.ec2.terminate_instances,
"i-00000005")
- self.manager.delete_project(project)
- self.manager.delete_user(user)
def test_get_all_key_pairs(self):
"""Test that, after creating a user and project and generating
@@ -283,16 +276,12 @@ class ApiEc2TestCase(test.TestCase):
self.mox.ReplayAll()
keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
for x in range(random.randint(4, 8)))
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
# NOTE(vish): create depends on pool, so call helper directly
- cloud._gen_key(context.get_admin_context(), user.id, keyname)
+ cloud._gen_key(context.get_admin_context(), 'fake', keyname)
rv = self.ec2.get_all_key_pairs()
results = [k for k in rv if k.name == keyname]
self.assertEquals(len(results), 1)
- self.manager.delete_project(project)
- self.manager.delete_user(user)
def test_create_duplicate_key_pair(self):
"""Test that, after successfully generating a keypair,
@@ -301,8 +290,6 @@ class ApiEc2TestCase(test.TestCase):
self.mox.ReplayAll()
keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") \
for x in range(random.randint(4, 8)))
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
# NOTE(vish): create depends on pool, so call helper directly
self.ec2.create_key_pair('test')
@@ -321,27 +308,16 @@ class ApiEc2TestCase(test.TestCase):
"""Test that we can retrieve security groups"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
- project = self.manager.create_project('fake', 'fake', 'fake')
rv = self.ec2.get_all_security_groups()
self.assertEquals(len(rv), 1)
self.assertEquals(rv[0].name, 'default')
- self.manager.delete_project(project)
- self.manager.delete_user(user)
-
def test_create_delete_security_group(self):
"""Test that we can create a security group"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
- project = self.manager.create_project('fake', 'fake', 'fake')
-
- # At the moment, you need both of these to actually be netadmin
- self.manager.add_role('fake', 'netadmin')
- project.add_role('fake', 'netadmin')
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd")
for x in range(random.randint(4, 8)))
@@ -360,9 +336,6 @@ class ApiEc2TestCase(test.TestCase):
self.ec2.delete_security_group(security_group_name)
- self.manager.delete_project(project)
- self.manager.delete_user(user)
-
def test_group_name_valid_chars_security_group(self):
""" Test that we sanely handle invalid security group names.
API Spec states we should only accept alphanumeric characters,
@@ -409,12 +382,6 @@ class ApiEc2TestCase(test.TestCase):
"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
-
- # At the moment, you need both of these to actually be netadmin
- self.manager.add_role('fake', 'netadmin')
- project.add_role('fake', 'netadmin')
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd")
for x in range(random.randint(4, 8)))
@@ -461,9 +428,6 @@ class ApiEc2TestCase(test.TestCase):
self.assertEqual(len(rv), 1)
self.assertEqual(rv[0].name, 'default')
- self.manager.delete_project(project)
- self.manager.delete_user(user)
-
return
def test_authorize_revoke_security_group_cidr_v6(self):
@@ -473,12 +437,6 @@ class ApiEc2TestCase(test.TestCase):
"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake')
- project = self.manager.create_project('fake', 'fake', 'fake')
-
- # At the moment, you need both of these to actually be netadmin
- self.manager.add_role('fake', 'netadmin')
- project.add_role('fake', 'netadmin')
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd")
for x in range(random.randint(4, 8)))
@@ -524,9 +482,6 @@ class ApiEc2TestCase(test.TestCase):
self.assertEqual(len(rv), 1)
self.assertEqual(rv[0].name, 'default')
- self.manager.delete_project(project)
- self.manager.delete_user(user)
-
return
def test_authorize_revoke_security_group_foreign_group(self):
@@ -536,12 +491,6 @@ class ApiEc2TestCase(test.TestCase):
"""
self.expect_http()
self.mox.ReplayAll()
- user = self.manager.create_user('fake', 'fake', 'fake', admin=True)
- project = self.manager.create_project('fake', 'fake', 'fake')
-
- # At the moment, you need both of these to actually be netadmin
- self.manager.add_role('fake', 'netadmin')
- project.add_role('fake', 'netadmin')
rand_string = 'sdiuisudfsdcnpaqwertasd'
security_group_name = "".join(random.choice(rand_string)
@@ -595,8 +544,3 @@ class ApiEc2TestCase(test.TestCase):
self.mox.ReplayAll()
self.ec2.delete_security_group(security_group_name)
-
- self.manager.delete_project(project)
- self.manager.delete_user(user)
-
- return
diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py
index 71e0d17c9..2e24b7d6e 100644
--- a/nova/tests/test_auth.py
+++ b/nova/tests/test_auth.py
@@ -83,9 +83,9 @@ class user_and_project_generator(object):
class _AuthManagerBaseTestCase(test.TestCase):
def setUp(self):
- FLAGS.auth_driver = self.auth_driver
super(_AuthManagerBaseTestCase, self).setUp()
- self.flags(connection_type='fake')
+ self.flags(auth_driver=self.auth_driver,
+ connection_type='fake')
self.manager = manager.AuthManager(new=True)
self.manager.mc.cache = {}
@@ -102,7 +102,7 @@ class _AuthManagerBaseTestCase(test.TestCase):
self.assertEqual('classified', u.secret)
self.assertEqual('private-party', u.access)
- def test_004_signature_is_valid(self):
+ def test_signature_is_valid(self):
with user_generator(self.manager, name='admin', secret='admin',
access='admin'):
with project_generator(self.manager, name="admin",
@@ -141,15 +141,14 @@ class _AuthManagerBaseTestCase(test.TestCase):
'127.0.0.1',
'/services/Cloud'))
- def test_005_can_get_credentials(self):
- return
- credentials = self.manager.get_user('test1').get_credentials()
- self.assertEqual(credentials,
- 'export EC2_ACCESS_KEY="access"\n' +
- 'export EC2_SECRET_KEY="secret"\n' +
- 'export EC2_URL="http://127.0.0.1:8773/services/Cloud"\n' +
- 'export S3_URL="http://127.0.0.1:3333/"\n' +
- 'export EC2_USER_ID="test1"\n')
+ def test_can_get_credentials(self):
+ st = {'access': 'access', 'secret': 'secret'}
+ with user_and_project_generator(self.manager, user_state=st) as (u, p):
+ credentials = self.manager.get_environment_rc(u, p)
+ LOG.debug(credentials)
+ self.assertTrue('export EC2_ACCESS_KEY="access:testproj"\n'
+ in credentials)
+ self.assertTrue('export EC2_SECRET_KEY="secret"\n' in credentials)
def test_can_list_users(self):
with user_generator(self.manager):
diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py
index a0d50b287..e891fa197 100644
--- a/nova/tests/test_cloud.py
+++ b/nova/tests/test_cloud.py
@@ -15,6 +15,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+import mox
from base64 import b64decode
from M2Crypto import BIO
@@ -29,10 +30,10 @@ from nova import db
from nova import exception
from nova import flags
from nova import log as logging
+from nova import network
from nova import rpc
from nova import test
from nova import utils
-from nova.auth import manager
from nova.api.ec2 import cloud
from nova.api.ec2 import ec2utils
from nova.image import fake
@@ -48,7 +49,7 @@ class CloudTestCase(test.TestCase):
self.flags(connection_type='fake',
stub_network=True)
- self.conn = rpc.Connection.instance()
+ self.conn = rpc.create_connection()
# set up our cloud
self.cloud = cloud.CloudController()
@@ -60,12 +61,11 @@ class CloudTestCase(test.TestCase):
self.volume = self.start_service('volume')
self.image_service = utils.import_object(FLAGS.image_service)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('admin', 'admin', 'admin', True)
- self.project = self.manager.create_project('proj', 'admin', 'proj')
- self.context = context.RequestContext(user=self.user,
- project=self.project)
- host = self.network.host
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id,
+ self.project_id,
+ True)
def fake_show(meh, context, id):
return {'id': 1, 'container_format': 'ami',
@@ -85,27 +85,23 @@ class CloudTestCase(test.TestCase):
self.stubs.Set(rpc, 'cast', finish_cast)
def tearDown(self):
- networks = db.project_get_networks(self.context, self.project.id,
+ networks = db.project_get_networks(self.context, self.project_id,
associate=False)
for network in networks:
db.network_disassociate(self.context, network['id'])
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
super(CloudTestCase, self).tearDown()
def _create_key(self, name):
# NOTE(vish): create depends on pool, so just call helper directly
- return cloud._gen_key(self.context, self.context.user.id, name)
+ return cloud._gen_key(self.context, self.context.user_id, name)
def test_describe_regions(self):
"""Makes sure describe regions runs without raising an exception"""
result = self.cloud.describe_regions(self.context)
self.assertEqual(len(result['regionInfo']), 1)
- regions = FLAGS.region_list
- FLAGS.region_list = ["one=test_host1", "two=test_host2"]
+ self.flags(region_list=["one=test_host1", "two=test_host2"])
result = self.cloud.describe_regions(self.context)
self.assertEqual(len(result['regionInfo']), 2)
- FLAGS.region_list = regions
def test_describe_addresses(self):
"""Makes sure describe addresses runs without raising an exception"""
@@ -119,7 +115,6 @@ class CloudTestCase(test.TestCase):
public_ip=address)
db.floating_ip_destroy(self.context, address)
- @test.skip_test("Skipping this pending future merge")
def test_allocate_address(self):
address = "10.10.10.10"
allocate = self.cloud.allocate_address
@@ -132,13 +127,37 @@ class CloudTestCase(test.TestCase):
allocate,
self.context)
- @test.skip_test("Skipping this pending future merge")
- def test_associate_disassociate_address(self):
- """Verifies associate runs cleanly without raising an exception"""
+ def test_release_address(self):
address = "10.10.10.10"
+ allocate = self.cloud.allocate_address
db.floating_ip_create(self.context,
{'address': address,
'host': self.network.host})
+ result = self.cloud.release_address(self.context, address)
+ self.assertEqual(result['releaseResponse'], ['Address released.'])
+
+ def test_release_address_still_associated(self):
+ address = "10.10.10.10"
+ fixed_ip = {'instance': {'id': 1}}
+ floating_ip = {'id': 0,
+ 'address': address,
+ 'fixed_ip_id': 0,
+ 'fixed_ip': fixed_ip,
+ 'project_id': None,
+ 'auto_assigned': False}
+ network_api = network.api.API()
+ self.mox.StubOutWithMock(network_api.db, 'floating_ip_get_by_address')
+ network_api.db.floating_ip_get_by_address(mox.IgnoreArg(),
+ mox.IgnoreArg()).AndReturn(floating_ip)
+ self.mox.ReplayAll()
+ release = self.cloud.release_address
+ # ApiError: Floating ip is in use. Disassociate it before releasing.
+ self.assertRaises(exception.ApiError, release, self.context, address)
+
+ def test_associate_disassociate_address(self):
+ """Verifies associate runs cleanly without raising an exception"""
+ address = "10.10.10.10"
+ db.floating_ip_create(self.context, {'address': address})
self.cloud.allocate_address(self.context)
# TODO(jkoelker) Probably need to query for instance_type_id and
# make sure we get a valid one
@@ -146,11 +165,14 @@ class CloudTestCase(test.TestCase):
'instance_type_id': 1})
networks = db.network_get_all(self.context)
for network in networks:
- self.network.set_network_host(self.context, network['id'])
+ db.network_update(self.context, network['id'],
+ {'host': self.network.host})
project_id = self.context.project_id
type_id = inst['instance_type_id']
ips = self.network.allocate_for_instance(self.context,
instance_id=inst['id'],
+ host=inst['host'],
+ vpn=None,
instance_type_id=type_id,
project_id=project_id)
# TODO(jkoelker) Make this mas bueno
@@ -240,12 +262,61 @@ 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_fail_missing_source_group(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'}},
+ 'ip_protocol': u'tcp'}]}
+ self.assertRaises(exception.SecurityGroupNotFound, 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,
+ {'project_id': 'someuser',
+ 'name': 'somegroup1'})
+ sec = db.security_group_create(self.context,
+ {'project_id': 'someuser',
+ 'name': 'othergroup2'})
+ sec = db.security_group_create(self.context, kwargs)
+ authz = self.cloud.authorize_security_group_ingress
+ kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81,
+ '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))
@@ -337,8 +408,6 @@ class CloudTestCase(test.TestCase):
db.service_destroy(self.context, service1['id'])
db.service_destroy(self.context, service2['id'])
- # NOTE(jkoelker): this test relies on fixed_ip being in instances
- @test.skip_test("EC2 stuff needs fixed_ip in instance_ref")
def test_describe_snapshots(self):
"""Makes sure describe_snapshots works and filters results."""
vol = db.volume_create(self.context, {})
@@ -907,7 +976,7 @@ class CloudTestCase(test.TestCase):
key = RSA.load_key_string(private_key, callback=lambda: None)
bio = BIO.MemoryBuffer()
public_key = db.key_pair_get(self.context,
- self.context.user.id,
+ self.context.user_id,
'test')['public_key']
key.save_pub_key_bio(bio)
converted = crypto.ssl_pub_to_ssh_pub(bio.read())
@@ -931,7 +1000,7 @@ class CloudTestCase(test.TestCase):
'mytestfprint')
self.assertTrue(result1)
keydata = db.key_pair_get(self.context,
- self.context.user.id,
+ self.context.user_id,
'testimportkey1')
self.assertEqual('mytestpubkey', keydata['public_key'])
self.assertEqual('mytestfprint', keydata['fingerprint'])
@@ -948,7 +1017,7 @@ class CloudTestCase(test.TestCase):
dummypub)
self.assertTrue(result2)
keydata = db.key_pair_get(self.context,
- self.context.user.id,
+ self.context.user_id,
'testimportkey2')
self.assertEqual(dummypub, keydata['public_key'])
self.assertEqual(dummyfprint, keydata['fingerprint'])
@@ -958,12 +1027,6 @@ class CloudTestCase(test.TestCase):
self.cloud.delete_key_pair(self.context, 'test')
def test_run_instances(self):
- # stub out the rpc call
- def stub_cast(*args, **kwargs):
- pass
-
- self.stubs.Set(rpc, 'cast', stub_cast)
-
kwargs = {'image_id': FLAGS.default_image,
'instance_type': FLAGS.default_instance_type,
'max_count': 1}
@@ -973,7 +1036,7 @@ class CloudTestCase(test.TestCase):
self.assertEqual(instance['imageId'], 'ami-00000001')
self.assertEqual(instance['displayName'], 'Server 1')
self.assertEqual(instance['instanceId'], 'i-00000001')
- self.assertEqual(instance['instanceState']['name'], 'scheduling')
+ self.assertEqual(instance['instanceState']['name'], 'running')
self.assertEqual(instance['instanceType'], 'm1.small')
def test_run_instances_image_state_none(self):
@@ -1045,16 +1108,15 @@ class CloudTestCase(test.TestCase):
self.assertEqual('c00l 1m4g3', inst['display_name'])
db.instance_destroy(self.context, inst['id'])
- # NOTE(jkoelker): This test relies on mac_address in instance
- @test.skip_test("EC2 stuff needs mac_address in instance_ref")
def test_update_of_instance_wont_update_private_fields(self):
inst = db.instance_create(self.context, {})
+ host = inst['host']
ec2_id = ec2utils.id_to_ec2_id(inst['id'])
self.cloud.update_instance(self.context, ec2_id,
display_name='c00l 1m4g3',
- mac_address='DE:AD:BE:EF')
+ host='otherhost')
inst = db.instance_get(self.context, inst['id'])
- self.assertEqual(None, inst['mac_address'])
+ self.assertEqual(host, inst['host'])
db.instance_destroy(self.context, inst['id'])
def test_update_of_volume_display_fields(self):
@@ -1110,7 +1172,6 @@ class CloudTestCase(test.TestCase):
elevated = self.context.elevated(read_deleted=True)
self._wait_for_state(elevated, instance_id, is_deleted)
- @test.skip_test("skipping, test is hanging with multinic for rpc reasons")
def test_stop_start_instance(self):
"""Makes sure stop/start instance works"""
# enforce periodic tasks run in short time to avoid wait for 60s.
@@ -1168,7 +1229,6 @@ class CloudTestCase(test.TestCase):
self.assertEqual(vol['status'], "available")
self.assertEqual(vol['attach_status'], "detached")
- @test.skip_test("skipping, test is hanging with multinic for rpc reasons")
def test_stop_start_with_volume(self):
"""Make sure run instance with block device mapping works"""
@@ -1237,7 +1297,6 @@ class CloudTestCase(test.TestCase):
self._restart_compute_service()
- @test.skip_test("skipping, test is hanging with multinic for rpc reasons")
def test_stop_with_attached_volume(self):
"""Make sure attach info is reflected to block device mapping"""
# enforce periodic tasks run in short time to avoid wait for 60s.
@@ -1313,7 +1372,6 @@ class CloudTestCase(test.TestCase):
greenthread.sleep(0.3)
return result['snapshotId']
- @test.skip_test("skipping, test is hanging with multinic for rpc reasons")
def test_run_with_snapshot(self):
"""Makes sure run/stop/start instance with snapshot works."""
vol = self._volume_create()
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 2900c594e..bbf9ddcc6 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -19,10 +19,6 @@
Tests For Compute
"""
-import mox
-import stubout
-
-from nova.auth import manager
from nova import compute
from nova.compute import instance_types
from nova.compute import manager as compute_manager
@@ -67,10 +63,9 @@ class ComputeTestCase(test.TestCase):
network_manager='nova.network.manager.FlatManager')
self.compute = utils.import_object(FLAGS.compute_manager)
self.compute_api = compute.API()
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake')
- self.project = self.manager.create_project('fake', 'fake', 'fake')
- self.context = context.RequestContext('fake', 'fake', False)
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
test_notifier.NOTIFICATIONS = []
def fake_show(meh, context, id):
@@ -78,19 +73,14 @@ class ComputeTestCase(test.TestCase):
self.stubs.Set(nova.image.fake._FakeImageService, 'show', fake_show)
- def tearDown(self):
- self.manager.delete_user(self.user)
- self.manager.delete_project(self.project)
- super(ComputeTestCase, self).tearDown()
-
def _create_instance(self, params={}):
"""Create a test instance"""
inst = {}
inst['image_ref'] = 1
inst['reservation_id'] = 'r-fakeres'
inst['launch_time'] = '10'
- inst['user_id'] = self.user.id
- inst['project_id'] = self.project.id
+ inst['user_id'] = self.user_id
+ inst['project_id'] = self.project_id
type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
inst['instance_type_id'] = type_id
inst['ami_launch_index'] = 0
@@ -115,8 +105,8 @@ class ComputeTestCase(test.TestCase):
def _create_group(self):
values = {'name': 'testgroup',
'description': 'testgroup',
- 'user_id': self.user.id,
- 'project_id': self.project.id}
+ 'user_id': self.user_id,
+ 'project_id': self.project_id}
return db.security_group_create(self.context, values)
def _get_dummy_instance(self):
@@ -350,8 +340,8 @@ class ComputeTestCase(test.TestCase):
self.assertEquals(msg['priority'], 'INFO')
self.assertEquals(msg['event_type'], 'compute.instance.create')
payload = msg['payload']
- self.assertEquals(payload['tenant_id'], self.project.id)
- self.assertEquals(payload['user_id'], self.user.id)
+ self.assertEquals(payload['tenant_id'], self.project_id)
+ self.assertEquals(payload['user_id'], self.user_id)
self.assertEquals(payload['instance_id'], instance_id)
self.assertEquals(payload['instance_type'], 'm1.tiny')
type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
@@ -374,8 +364,8 @@ class ComputeTestCase(test.TestCase):
self.assertEquals(msg['priority'], 'INFO')
self.assertEquals(msg['event_type'], 'compute.instance.delete')
payload = msg['payload']
- self.assertEquals(payload['tenant_id'], self.project.id)
- self.assertEquals(payload['user_id'], self.user.id)
+ self.assertEquals(payload['tenant_id'], self.project_id)
+ self.assertEquals(payload['user_id'], self.user_id)
self.assertEquals(payload['instance_id'], instance_id)
self.assertEquals(payload['instance_type'], 'm1.tiny')
type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
@@ -420,15 +410,16 @@ class ComputeTestCase(test.TestCase):
def fake(*args, **kwargs):
pass
- self.stubs.Set(self.compute.driver, 'finish_resize', fake)
+ self.stubs.Set(self.compute.driver, 'finish_migration', fake)
self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake)
context = self.context.elevated()
instance_id = self._create_instance()
- self.compute.prep_resize(context, instance_id, 1)
+ instance_ref = db.instance_get(context, instance_id)
+ self.compute.prep_resize(context, instance_ref['uuid'], 1)
migration_ref = db.migration_get_by_instance_and_status(context,
- instance_id, 'pre-migrating')
+ instance_ref['uuid'], 'pre-migrating')
try:
- self.compute.finish_resize(context, instance_id,
+ self.compute.finish_resize(context, instance_ref['uuid'],
int(migration_ref['id']), {})
except KeyError, e:
# Only catch key errors. We want other reasons for the test to
@@ -441,22 +432,23 @@ class ComputeTestCase(test.TestCase):
"""Ensure notifications on instance migrate/resize"""
instance_id = self._create_instance()
context = self.context.elevated()
+ inst_ref = db.instance_get(context, instance_id)
self.compute.run_instance(self.context, instance_id)
test_notifier.NOTIFICATIONS = []
db.instance_update(self.context, instance_id, {'host': 'foo'})
- self.compute.prep_resize(context, instance_id, 1)
+ self.compute.prep_resize(context, inst_ref['uuid'], 1)
migration_ref = db.migration_get_by_instance_and_status(context,
- instance_id, 'pre-migrating')
+ inst_ref['uuid'], 'pre-migrating')
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
msg = test_notifier.NOTIFICATIONS[0]
self.assertEquals(msg['priority'], 'INFO')
self.assertEquals(msg['event_type'], 'compute.instance.resize.prep')
payload = msg['payload']
- self.assertEquals(payload['tenant_id'], self.project.id)
- self.assertEquals(payload['user_id'], self.user.id)
+ self.assertEquals(payload['tenant_id'], self.project_id)
+ self.assertEquals(payload['user_id'], self.user_id)
self.assertEquals(payload['instance_id'], instance_id)
self.assertEquals(payload['instance_type'], 'm1.tiny')
type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
@@ -471,13 +463,15 @@ class ComputeTestCase(test.TestCase):
"""Ensure instance can be migrated/resized"""
instance_id = self._create_instance()
context = self.context.elevated()
+ inst_ref = db.instance_get(context, instance_id)
self.compute.run_instance(self.context, instance_id)
- db.instance_update(self.context, instance_id, {'host': 'foo'})
- self.compute.prep_resize(context, instance_id, 1)
+ db.instance_update(self.context, inst_ref['uuid'],
+ {'host': 'foo'})
+ self.compute.prep_resize(context, inst_ref['uuid'], 1)
migration_ref = db.migration_get_by_instance_and_status(context,
- instance_id, 'pre-migrating')
- self.compute.resize_instance(context, instance_id,
+ inst_ref['uuid'], 'pre-migrating')
+ self.compute.resize_instance(context, inst_ref['uuid'],
migration_ref['id'])
self.compute.terminate_instance(context, instance_id)
@@ -502,8 +496,8 @@ class ComputeTestCase(test.TestCase):
db.instance_update(self.context, instance_id,
{'instance_type_id': inst_type['id']})
- self.assertRaises(exception.ApiError, self.compute_api.resize,
- context, instance_id, 1)
+ self.assertRaises(exception.CannotResizeToSmallerSize,
+ self.compute_api.resize, context, instance_id, 1)
self.compute.terminate_instance(context, instance_id)
@@ -514,8 +508,61 @@ class ComputeTestCase(test.TestCase):
self.compute.run_instance(self.context, instance_id)
- self.assertRaises(exception.ApiError, self.compute_api.resize,
- context, instance_id, 1)
+ self.assertRaises(exception.CannotResizeToSameSize,
+ self.compute_api.resize, context, instance_id, 1)
+
+ self.compute.terminate_instance(context, instance_id)
+
+ def test_finish_revert_resize(self):
+ """Ensure that the flavor is reverted to the original on revert"""
+ context = self.context.elevated()
+ instance_id = self._create_instance()
+
+ def fake(*args, **kwargs):
+ pass
+
+ self.stubs.Set(self.compute.driver, 'finish_migration', fake)
+ self.stubs.Set(self.compute.driver, 'revert_migration', fake)
+ self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake)
+
+ self.compute.run_instance(self.context, instance_id)
+
+ # Confirm the instance size before the resize starts
+ inst_ref = db.instance_get(context, instance_id)
+ instance_type_ref = db.instance_type_get(context,
+ inst_ref['instance_type_id'])
+ self.assertEqual(instance_type_ref['flavorid'], 1)
+
+ db.instance_update(self.context, instance_id, {'host': 'foo'})
+
+ new_instance_type_ref = db.instance_type_get_by_flavor_id(context, 3)
+ self.compute.prep_resize(context, inst_ref['uuid'],
+ new_instance_type_ref['id'])
+
+ migration_ref = db.migration_get_by_instance_and_status(context,
+ inst_ref['uuid'], 'pre-migrating')
+
+ self.compute.resize_instance(context, inst_ref['uuid'],
+ migration_ref['id'])
+ self.compute.finish_resize(context, inst_ref['uuid'],
+ int(migration_ref['id']), {})
+
+ # Prove that the instance size is now the new size
+ inst_ref = db.instance_get(context, instance_id)
+ instance_type_ref = db.instance_type_get(context,
+ inst_ref['instance_type_id'])
+ self.assertEqual(instance_type_ref['flavorid'], 3)
+
+ # Finally, revert and confirm the old flavor has been applied
+ self.compute.revert_resize(context, inst_ref['uuid'],
+ migration_ref['id'])
+ self.compute.finish_revert_resize(context, inst_ref['uuid'],
+ migration_ref['id'])
+
+ inst_ref = db.instance_get(context, instance_id)
+ instance_type_ref = db.instance_type_get(context,
+ inst_ref['instance_type_id'])
+ self.assertEqual(instance_type_ref['flavorid'], 1)
self.compute.terminate_instance(context, instance_id)
@@ -528,8 +575,9 @@ class ComputeTestCase(test.TestCase):
the same host"""
instance_id = self._create_instance()
self.compute.run_instance(self.context, instance_id)
+ inst_ref = db.instance_get(self.context, instance_id)
self.assertRaises(exception.Error, self.compute.prep_resize,
- self.context, instance_id, 1)
+ self.context, inst_ref['uuid'], 1)
self.compute.terminate_instance(self.context, instance_id)
def test_migrate(self):
@@ -569,7 +617,6 @@ class ComputeTestCase(test.TestCase):
self._setup_other_managers()
dbmock = self.mox.CreateMock(db)
volmock = self.mox.CreateMock(self.volume_manager)
- netmock = self.mox.CreateMock(self.network_manager)
drivermock = self.mox.CreateMock(self.compute_driver)
dbmock.instance_get(c, i_ref['id']).AndReturn(i_ref)
@@ -577,12 +624,11 @@ class ComputeTestCase(test.TestCase):
for i in range(len(i_ref['volumes'])):
vid = i_ref['volumes'][i]['id']
volmock.setup_compute_volume(c, vid).InAnyOrder('g1')
- netmock.setup_compute_network(c, i_ref['id'])
+ drivermock.plug_vifs(i_ref, [])
drivermock.ensure_filtering_rules_for_instance(i_ref)
self.compute.db = dbmock
self.compute.volume_manager = volmock
- self.compute.network_manager = netmock
self.compute.driver = drivermock
self.mox.ReplayAll()
@@ -597,18 +643,16 @@ class ComputeTestCase(test.TestCase):
self._setup_other_managers()
dbmock = self.mox.CreateMock(db)
- netmock = self.mox.CreateMock(self.network_manager)
drivermock = self.mox.CreateMock(self.compute_driver)
dbmock.instance_get(c, i_ref['id']).AndReturn(i_ref)
dbmock.instance_get_fixed_addresses(c, i_ref['id']).AndReturn('dummy')
self.mox.StubOutWithMock(compute_manager.LOG, 'info')
compute_manager.LOG.info(_("%s has no volume."), i_ref['hostname'])
- netmock.setup_compute_network(c, i_ref['id'])
+ drivermock.plug_vifs(i_ref, [])
drivermock.ensure_filtering_rules_for_instance(i_ref)
self.compute.db = dbmock
- self.compute.network_manager = netmock
self.compute.driver = drivermock
self.mox.ReplayAll()
@@ -629,18 +673,20 @@ class ComputeTestCase(test.TestCase):
dbmock = self.mox.CreateMock(db)
netmock = self.mox.CreateMock(self.network_manager)
volmock = self.mox.CreateMock(self.volume_manager)
+ drivermock = self.mox.CreateMock(self.compute_driver)
dbmock.instance_get(c, i_ref['id']).AndReturn(i_ref)
dbmock.instance_get_fixed_addresses(c, i_ref['id']).AndReturn('dummy')
for i in range(len(i_ref['volumes'])):
volmock.setup_compute_volume(c, i_ref['volumes'][i]['id'])
for i in range(FLAGS.live_migration_retry_count):
- netmock.setup_compute_network(c, i_ref['id']).\
+ drivermock.plug_vifs(i_ref, []).\
AndRaise(exception.ProcessExecutionError())
self.compute.db = dbmock
self.compute.network_manager = netmock
self.compute.volume_manager = volmock
+ self.compute.driver = drivermock
self.mox.ReplayAll()
self.assertRaises(exception.ProcessExecutionError,
@@ -775,7 +821,7 @@ class ComputeTestCase(test.TestCase):
for v in i_ref['volumes']:
self.compute.volume_manager.remove_compute_volume(c, v['id'])
self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance')
- self.compute.driver.unfilter_instance(i_ref)
+ self.compute.driver.unfilter_instance(i_ref, [])
# executing
self.mox.ReplayAll()
@@ -795,7 +841,6 @@ class ComputeTestCase(test.TestCase):
def test_run_kill_vm(self):
"""Detect when a vm is terminated behind the scenes"""
- self.stubs = stubout.StubOutForTesting()
self.stubs.Set(compute_manager.ComputeManager,
'_report_driver_status', nop_report_driver_status)
diff --git a/nova/tests/test_console.py b/nova/tests/test_console.py
index 1806cc1ea..cf7f592cf 100644
--- a/nova/tests/test_console.py
+++ b/nova/tests/test_console.py
@@ -26,10 +26,9 @@ from nova import exception
from nova import flags
from nova import test
from nova import utils
-from nova.auth import manager
-from nova.console import manager as console_manager
FLAGS = flags.FLAGS
+flags.DECLARE('console_driver', 'nova.console.manager')
class ConsoleTestCase(test.TestCase):
@@ -39,17 +38,11 @@ class ConsoleTestCase(test.TestCase):
self.flags(console_driver='nova.console.fake.FakeConsoleProxy',
stub_compute=True)
self.console = utils.import_object(FLAGS.console_manager)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake')
- self.project = self.manager.create_project('fake', 'fake', 'fake')
- self.context = context.get_admin_context()
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
self.host = 'test_compute_host'
- def tearDown(self):
- self.manager.delete_user(self.user)
- self.manager.delete_project(self.project)
- super(ConsoleTestCase, self).tearDown()
-
def _create_instance(self):
"""Create a test instance"""
inst = {}
@@ -58,8 +51,8 @@ class ConsoleTestCase(test.TestCase):
inst['image_id'] = 1
inst['reservation_id'] = 'r-fakeres'
inst['launch_time'] = '10'
- inst['user_id'] = self.user.id
- inst['project_id'] = self.project.id
+ inst['user_id'] = self.user_id
+ inst['project_id'] = self.project_id
inst['instance_type_id'] = 1
inst['ami_launch_index'] = 0
return db.instance_create(self.context, inst)['id']
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
new file mode 100644
index 000000000..0c07cbb7c
--- /dev/null
+++ b/nova/tests/test_db_api.py
@@ -0,0 +1,78 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the DB API"""
+
+from nova import test
+from nova import context
+from nova import db
+from nova import flags
+
+FLAGS = flags.FLAGS
+
+
+def _setup_networking(instance_id, ip='1.2.3.4', flo_addr='1.2.1.2'):
+ ctxt = context.get_admin_context()
+ network_ref = db.project_get_networks(ctxt,
+ 'fake',
+ associate=True)[0]
+ vif = {'address': '56:12:12:12:12:12',
+ 'network_id': network_ref['id'],
+ 'instance_id': instance_id}
+ vif_ref = db.virtual_interface_create(ctxt, vif)
+
+ fixed_ip = {'address': ip,
+ 'network_id': network_ref['id'],
+ 'virtual_interface_id': vif_ref['id'],
+ 'allocated': True,
+ 'instance_id': instance_id}
+ db.fixed_ip_create(ctxt, fixed_ip)
+ fix_ref = db.fixed_ip_get_by_address(ctxt, ip)
+ db.floating_ip_create(ctxt, {'address': flo_addr,
+ 'fixed_ip_id': fix_ref['id']})
+
+
+class DbApiTestCase(test.TestCase):
+ def setUp(self):
+ super(DbApiTestCase, self).setUp()
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
+
+ def test_instance_get_project_vpn(self):
+ values = {'instance_type_id': FLAGS.default_instance_type,
+ 'image_ref': FLAGS.vpn_image_id,
+ 'project_id': self.project_id,
+ }
+ instance = db.instance_create(self.context, values)
+ result = db.instance_get_project_vpn(self.context.elevated(),
+ self.project_id)
+ self.assertEqual(instance['id'], result['id'])
+
+ def test_instance_get_project_vpn_joins(self):
+ values = {'instance_type_id': FLAGS.default_instance_type,
+ 'image_ref': FLAGS.vpn_image_id,
+ 'project_id': self.project_id,
+ }
+ instance = db.instance_create(self.context, values)
+ _setup_networking(instance['id'])
+ result = db.instance_get_project_vpn(self.context.elevated(),
+ self.project_id)
+ self.assertEqual(instance['id'], result['id'])
+ self.assertEqual(result['fixed_ips'][0]['floating_ips'][0].address,
+ '1.2.1.2')
diff --git a/nova/tests/test_host_filter.py b/nova/tests/test_host_filter.py
index 438f3e522..3a1389a49 100644
--- a/nova/tests/test_host_filter.py
+++ b/nova/tests/test_host_filter.py
@@ -19,12 +19,9 @@ Tests For Scheduler Host Filters.
import json
from nova import exception
-from nova import flags
from nova import test
from nova.scheduler import host_filter
-FLAGS = flags.FLAGS
-
class FakeZoneManager:
pass
@@ -57,9 +54,9 @@ class HostFilterTestCase(test.TestCase):
'host_name-label': 'xs-%s' % multiplier}
def setUp(self):
- self.old_flag = FLAGS.default_host_filter
- FLAGS.default_host_filter = \
- 'nova.scheduler.host_filter.AllHostsFilter'
+ super(HostFilterTestCase, self).setUp()
+ default_host_filter = 'nova.scheduler.host_filter.AllHostsFilter'
+ self.flags(default_host_filter=default_host_filter)
self.instance_type = dict(name='tiny',
memory_mb=50,
vcpus=10,
@@ -76,9 +73,6 @@ class HostFilterTestCase(test.TestCase):
states['host%02d' % (x + 1)] = {'compute': self._host_caps(x)}
self.zone_manager.service_states = states
- def tearDown(self):
- FLAGS.default_host_filter = self.old_flag
-
def test_choose_filter(self):
# Test default filter ...
hf = host_filter.choose_host_filter()
diff --git a/nova/tests/test_image.py b/nova/tests/test_image.py
new file mode 100644
index 000000000..9680d6f2b
--- /dev/null
+++ b/nova/tests/test_image.py
@@ -0,0 +1,134 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC
+# Author: Soren Hansen
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import datetime
+
+from nova import context
+from nova import exception
+from nova import test
+import nova.image
+
+
+class _ImageTestCase(test.TestCase):
+ def setUp(self):
+ super(_ImageTestCase, self).setUp()
+ self.context = context.get_admin_context()
+
+ def test_index(self):
+ res = self.image_service.index(self.context)
+ for image in res:
+ self.assertEquals(set(image.keys()), set(['id', 'name']))
+
+ def test_detail(self):
+ res = self.image_service.detail(self.context)
+ for image in res:
+ keys = set(image.keys())
+ self.assertEquals(keys, set(['id', 'name', 'created_at',
+ 'updated_at', 'deleted_at', 'deleted',
+ 'status', 'is_public', 'properties']))
+ self.assertTrue(isinstance(image['created_at'], datetime.datetime))
+ self.assertTrue(isinstance(image['updated_at'], datetime.datetime))
+
+ if not (isinstance(image['deleted_at'], datetime.datetime) or
+ image['deleted_at'] is None):
+ self.fail('image\'s "deleted_at" attribute was neither a '
+ 'datetime object nor None')
+
+ def check_is_bool(image, key):
+ val = image.get('deleted')
+ if not isinstance(val, bool):
+ self.fail('image\'s "%s" attribute wasn\'t '
+ 'a bool: %r' % (key, val))
+
+ check_is_bool(image, 'deleted')
+ check_is_bool(image, 'is_public')
+
+ def test_index_and_detail_have_same_results(self):
+ index = self.image_service.index(self.context)
+ detail = self.image_service.detail(self.context)
+ index_set = set([(i['id'], i['name']) for i in index])
+ detail_set = set([(i['id'], i['name']) for i in detail])
+ self.assertEqual(index_set, detail_set)
+
+ def test_show_raises_imagenotfound_for_invalid_id(self):
+ self.assertRaises(exception.ImageNotFound,
+ self.image_service.show,
+ self.context,
+ 'this image does not exist')
+
+ def test_show_by_name(self):
+ self.assertRaises(exception.ImageNotFound,
+ self.image_service.show_by_name,
+ self.context,
+ 'this image does not exist')
+
+ def test_create_adds_id(self):
+ index = self.image_service.index(self.context)
+ image_count = len(index)
+
+ self.image_service.create(self.context, {})
+
+ index = self.image_service.index(self.context)
+ self.assertEquals(len(index), image_count + 1)
+
+ self.assertTrue(index[0]['id'])
+
+ def test_create_keeps_id(self):
+ self.image_service.create(self.context, {'id': '34'})
+ self.image_service.show(self.context, '34')
+
+ def test_create_rejects_duplicate_ids(self):
+ self.image_service.create(self.context, {'id': '34'})
+ self.assertRaises(exception.Duplicate,
+ self.image_service.create,
+ self.context,
+ {'id': '34'})
+
+ # Make sure there's still one left
+ self.image_service.show(self.context, '34')
+
+ def test_update(self):
+ self.image_service.create(self.context,
+ {'id': '34', 'foo': 'bar'})
+
+ self.image_service.update(self.context, '34',
+ {'id': '34', 'foo': 'baz'})
+
+ img = self.image_service.show(self.context, '34')
+ self.assertEquals(img['foo'], 'baz')
+
+ def test_delete(self):
+ self.image_service.create(self.context, {'id': '34', 'foo': 'bar'})
+ self.image_service.delete(self.context, '34')
+ self.assertRaises(exception.NotFound,
+ self.image_service.show,
+ self.context,
+ '34')
+
+ def test_delete_all(self):
+ self.image_service.create(self.context, {'id': '32', 'foo': 'bar'})
+ self.image_service.create(self.context, {'id': '33', 'foo': 'bar'})
+ self.image_service.create(self.context, {'id': '34', 'foo': 'bar'})
+ self.image_service.delete_all()
+ index = self.image_service.index(self.context)
+ self.assertEquals(len(index), 0)
+
+
+class FakeImageTestCase(_ImageTestCase):
+ def setUp(self):
+ super(FakeImageTestCase, self).setUp()
+ self.image_service = nova.image.fake.FakeImageService()
diff --git a/nova/tests/test_instance_types_extra_specs.py b/nova/tests/test_instance_types_extra_specs.py
index c26cf82ff..393ed1e36 100644
--- a/nova/tests/test_instance_types_extra_specs.py
+++ b/nova/tests/test_instance_types_extra_specs.py
@@ -105,8 +105,8 @@ class InstanceTypeExtraSpecsTestCase(test.TestCase):
self.instance_type_id)
self.assertEquals(expected_specs, actual_specs)
- def test_instance_type_get_by_id_with_extra_specs(self):
- instance_type = db.api.instance_type_get_by_id(
+ def test_instance_type_get_with_extra_specs(self):
+ instance_type = db.api.instance_type_get(
context.get_admin_context(),
self.instance_type_id)
self.assertEquals(instance_type['extra_specs'],
@@ -115,7 +115,7 @@ class InstanceTypeExtraSpecsTestCase(test.TestCase):
xpu_arch="fermi",
xpus="2",
xpu_model="Tesla 2050"))
- instance_type = db.api.instance_type_get_by_id(
+ instance_type = db.api.instance_type_get(
context.get_admin_context(),
5)
self.assertEquals(instance_type['extra_specs'], {})
@@ -136,7 +136,7 @@ class InstanceTypeExtraSpecsTestCase(test.TestCase):
"m1.small")
self.assertEquals(instance_type['extra_specs'], {})
- def test_instance_type_get_by_id_with_extra_specs(self):
+ def test_instance_type_get_with_extra_specs(self):
instance_type = db.api.instance_type_get_by_flavor_id(
context.get_admin_context(),
105)
diff --git a/nova/tests/test_ipv6.py b/nova/tests/test_ipv6.py
index 11dc2ec98..d123df6f1 100644
--- a/nova/tests/test_ipv6.py
+++ b/nova/tests/test_ipv6.py
@@ -16,15 +16,12 @@
"""Test suite for IPv6."""
-from nova import flags
from nova import ipv6
from nova import log as logging
from nova import test
LOG = logging.getLogger('nova.tests.test_ipv6')
-FLAGS = flags.FLAGS
-
import sys
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index f99e1713d..f8b866985 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -32,14 +32,12 @@ from nova import flags
from nova import test
from nova import utils
from nova.api.ec2 import cloud
-from nova.auth import manager
from nova.compute import power_state
from nova.virt.libvirt import connection
from nova.virt.libvirt import firewall
libvirt = None
FLAGS = flags.FLAGS
-flags.DECLARE('instances_path', 'nova.compute.manager')
def _concurrency(wait, done, target):
@@ -54,10 +52,15 @@ def _create_network_info(count=1, ipv6=None):
fake_ip = '0.0.0.0/0'
fake_ip_2 = '0.0.0.1/0'
fake_ip_3 = '0.0.0.1/0'
+ fake_vlan = 100
+ fake_bridge_interface = 'eth0'
network = {'bridge': fake,
'cidr': fake_ip,
- 'cidr_v6': fake_ip}
+ 'cidr_v6': fake_ip,
+ 'vlan': fake_vlan,
+ 'bridge_interface': fake_bridge_interface}
mapping = {'mac': fake,
+ 'dhcp_server': fake,
'gateway': fake,
'gateway6': fake,
'ips': [{'ip': fake_ip}, {'ip': fake_ip}]}
@@ -83,12 +86,13 @@ def _setup_networking(instance_id, ip='1.2.3.4'):
'virtual_interface_id': vif_ref['id']}
db.fixed_ip_create(ctxt, fixed_ip)
db.fixed_ip_update(ctxt, ip, {'allocated': True,
- 'instance_id': instance_id})
+ 'instance_id': instance_id})
class CacheConcurrencyTestCase(test.TestCase):
def setUp(self):
super(CacheConcurrencyTestCase, self).setUp()
+ self.flags(instances_path='nova.compute.manager')
def fake_exists(fname):
basedir = os.path.join(FLAGS.instances_path, '_base')
@@ -149,36 +153,15 @@ class LibvirtConnTestCase(test.TestCase):
super(LibvirtConnTestCase, self).setUp()
connection._late_load_cheetah()
self.flags(fake_call=True)
- self.manager = manager.AuthManager()
-
- try:
- pjs = self.manager.get_projects()
- pjs = [p for p in pjs if p.name == 'fake']
- if 0 != len(pjs):
- self.manager.delete_project(pjs[0])
-
- users = self.manager.get_users()
- users = [u for u in users if u.name == 'fake']
- if 0 != len(users):
- self.manager.delete_user(users[0])
- except Exception, e:
- pass
-
- users = self.manager.get_users()
- self.user = self.manager.create_user('fake', 'fake', 'fake',
- admin=True)
- self.project = self.manager.create_project('fake', 'fake', 'fake')
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
self.network = utils.import_object(FLAGS.network_manager)
self.context = context.get_admin_context()
- FLAGS.instances_path = ''
+ self.flags(instances_path='')
self.call_libvirt_dependant_setup = False
+ self.test_ip = '10.11.12.13'
- def tearDown(self):
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
- super(LibvirtConnTestCase, self).tearDown()
-
- test_ip = '10.11.12.13'
test_instance = {'memory_kb': '1024000',
'basepath': '/some/path',
'bridge_name': 'br100',
@@ -218,9 +201,29 @@ class LibvirtConnTestCase(test.TestCase):
def setattr(self, key, val):
self.__setattr__(key, val)
+ # A fake VIF driver
+ class FakeVIFDriver(object):
+
+ def __init__(self, **kwargs):
+ pass
+
+ def setattr(self, key, val):
+ self.__setattr__(key, val)
+
+ def plug(self, instance, network, mapping):
+ return {
+ 'id': 'fake',
+ 'bridge_name': 'fake',
+ 'mac_address': 'fake',
+ 'ip_address': 'fake',
+ 'dhcp_server': 'fake',
+ 'extra_params': 'fake',
+ }
+
# Creating mocks
fake = FakeLibvirtConnection()
fakeip = FakeIptablesFirewallDriver
+ fakevif = FakeVIFDriver()
# Customizing above fake if necessary
for key, val in kwargs.items():
fake.__setattr__(key, val)
@@ -228,6 +231,8 @@ class LibvirtConnTestCase(test.TestCase):
# Inevitable mocks for connection.LibvirtConnection
self.mox.StubOutWithMock(connection.utils, 'import_class')
connection.utils.import_class(mox.IgnoreArg()).AndReturn(fakeip)
+ self.mox.StubOutWithMock(connection.utils, 'import_object')
+ connection.utils.import_object(mox.IgnoreArg()).AndReturn(fakevif)
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
connection.LibvirtConnection._conn = fake
@@ -263,7 +268,6 @@ class LibvirtConnTestCase(test.TestCase):
return db.service_create(context.get_admin_context(), service_ref)
- @test.skip_test("Please review this test to ensure intent")
def test_preparing_xml_info(self):
conn = connection.LibvirtConnection(True)
instance_ref = db.instance_create(self.context, self.test_instance)
@@ -279,43 +283,23 @@ class LibvirtConnTestCase(test.TestCase):
_create_network_info(2))
self.assertTrue(len(result['nics']) == 2)
- def test_get_nic_for_xml_v4(self):
- conn = connection.LibvirtConnection(True)
- network, mapping = _create_network_info()[0]
- self.flags(use_ipv6=False)
- params = conn._get_nic_for_xml(network, mapping)['extra_params']
- self.assertTrue(params.find('PROJNETV6') == -1)
- self.assertTrue(params.find('PROJMASKV6') == -1)
-
- def test_get_nic_for_xml_v6(self):
- conn = connection.LibvirtConnection(True)
- network, mapping = _create_network_info()[0]
- self.flags(use_ipv6=True)
- params = conn._get_nic_for_xml(network, mapping)['extra_params']
- self.assertTrue(params.find('PROJNETV6') > -1)
- self.assertTrue(params.find('PROJMASKV6') > -1)
-
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_xml_and_uri_no_ramdisk_no_kernel(self):
instance_data = dict(self.test_instance)
self._check_xml_and_uri(instance_data,
expect_kernel=False, expect_ramdisk=False)
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_xml_and_uri_no_ramdisk(self):
instance_data = dict(self.test_instance)
instance_data['kernel_id'] = 'aki-deadbeef'
self._check_xml_and_uri(instance_data,
expect_kernel=True, expect_ramdisk=False)
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_xml_and_uri_no_kernel(self):
instance_data = dict(self.test_instance)
instance_data['ramdisk_id'] = 'ari-deadbeef'
self._check_xml_and_uri(instance_data,
expect_kernel=False, expect_ramdisk=False)
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_xml_and_uri(self):
instance_data = dict(self.test_instance)
instance_data['ramdisk_id'] = 'ari-deadbeef'
@@ -323,7 +307,6 @@ class LibvirtConnTestCase(test.TestCase):
self._check_xml_and_uri(instance_data,
expect_kernel=True, expect_ramdisk=True)
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_xml_and_uri_rescue(self):
instance_data = dict(self.test_instance)
instance_data['ramdisk_id'] = 'ari-deadbeef'
@@ -331,7 +314,6 @@ class LibvirtConnTestCase(test.TestCase):
self._check_xml_and_uri(instance_data, expect_kernel=True,
expect_ramdisk=True, rescue=True)
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_lxc_container_and_uri(self):
instance_data = dict(self.test_instance)
self._check_xml_and_container(instance_data)
@@ -340,7 +322,7 @@ class LibvirtConnTestCase(test.TestCase):
if not self.lazy_load_library_exists():
return
- FLAGS.image_service = 'nova.image.fake.FakeImageService'
+ self.flags(image_service='nova.image.fake.FakeImageService')
# Start test
image_service = utils.import_object(FLAGS.image_service)
@@ -364,7 +346,7 @@ class LibvirtConnTestCase(test.TestCase):
self.mox.ReplayAll()
conn = connection.LibvirtConnection(False)
- conn.snapshot(instance_ref, recv_meta['id'])
+ conn.snapshot(self.context, instance_ref, recv_meta['id'])
snapshot = image_service.show(context, recv_meta['id'])
self.assertEquals(snapshot['properties']['image_state'], 'available')
@@ -375,7 +357,7 @@ class LibvirtConnTestCase(test.TestCase):
if not self.lazy_load_library_exists():
return
- FLAGS.image_service = 'nova.image.fake.FakeImageService'
+ self.flags(image_service='nova.image.fake.FakeImageService')
# Start test
image_service = utils.import_object(FLAGS.image_service)
@@ -404,13 +386,22 @@ class LibvirtConnTestCase(test.TestCase):
self.mox.ReplayAll()
conn = connection.LibvirtConnection(False)
- conn.snapshot(instance_ref, recv_meta['id'])
+ conn.snapshot(self.context, instance_ref, recv_meta['id'])
snapshot = image_service.show(context, recv_meta['id'])
self.assertEquals(snapshot['properties']['image_state'], 'available')
self.assertEquals(snapshot['status'], 'active')
self.assertEquals(snapshot['name'], snapshot_name)
+ def test_attach_invalid_device(self):
+ self.create_fake_libvirt_mock()
+ connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
+ self.mox.ReplayAll()
+ conn = connection.LibvirtConnection(False)
+ self.assertRaises(exception.InvalidDevicePath,
+ conn.attach_volume,
+ "fake", "bad/device/path", "/dev/fake")
+
def test_multi_nic(self):
instance_data = dict(self.test_instance)
network_info = _create_network_info(2)
@@ -428,27 +419,10 @@ class LibvirtConnTestCase(test.TestCase):
self.assertEquals(parameters[1].get('value'), 'fake')
def _check_xml_and_container(self, instance):
- user_context = context.RequestContext(project=self.project,
- user=self.user)
+ user_context = context.RequestContext(self.user_id,
+ self.project_id)
instance_ref = db.instance_create(user_context, instance)
- # Re-get the instance so it's bound to an actual session
- instance_ref = db.instance_get(user_context, instance_ref['id'])
- network_ref = db.project_get_networks(context.get_admin_context(),
- self.project.id)[0]
-
- vif = {'address': '56:12:12:12:12:12',
- 'network_id': network_ref['id'],
- 'instance_id': instance_ref['id']}
- vif_ref = db.virtual_interface_create(self.context, vif)
- fixed_ip = {'address': self.test_ip,
- 'network_id': network_ref['id'],
- 'virtual_interface_id': vif_ref['id']}
-
- ctxt = context.get_admin_context()
- fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip)
- db.fixed_ip_update(ctxt, self.test_ip,
- {'allocated': True,
- 'instance_id': instance_ref['id']})
+ _setup_networking(instance_ref['id'], self.test_ip)
self.flags(libvirt_type='lxc')
conn = connection.LibvirtConnection(True)
@@ -474,13 +448,12 @@ class LibvirtConnTestCase(test.TestCase):
def _check_xml_and_uri(self, instance, expect_ramdisk, expect_kernel,
rescue=False):
- user_context = context.RequestContext(project=self.project,
- user=self.user)
+ user_context = context.RequestContext(self.user_id, self.project_id)
instance_ref = db.instance_create(user_context, instance)
network_ref = db.project_get_networks(context.get_admin_context(),
- self.project.id)[0]
+ self.project_id)[0]
- _setup_networking(instance_ref['id'], ip=self.test_ip)
+ _setup_networking(instance_ref['id'], self.test_ip)
type_uri_map = {'qemu': ('qemu:///system',
[(lambda t: t.find('.').get('type'), 'qemu'),
@@ -548,7 +521,7 @@ class LibvirtConnTestCase(test.TestCase):
'disk.local')]
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
- FLAGS.libvirt_type = libvirt_type
+ self.flags(libvirt_type=libvirt_type)
conn = connection.LibvirtConnection(True)
uri = conn.get_uri()
@@ -573,9 +546,9 @@ class LibvirtConnTestCase(test.TestCase):
# checking against that later on. This way we make sure the
# implementation doesn't fiddle around with the FLAGS.
testuri = 'something completely different'
- FLAGS.libvirt_uri = testuri
+ self.flags(libvirt_uri=testuri)
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
- FLAGS.libvirt_type = libvirt_type
+ self.flags(libvirt_type=libvirt_type)
conn = connection.LibvirtConnection(True)
uri = conn.get_uri()
self.assertEquals(uri, testuri)
@@ -583,8 +556,7 @@ class LibvirtConnTestCase(test.TestCase):
def test_update_available_resource_works_correctly(self):
"""Confirm compute_node table is updated successfully."""
- org_path = FLAGS.instances_path = ''
- FLAGS.instances_path = '.'
+ self.flags(instances_path='.')
# Prepare mocks
def getVersion():
@@ -631,12 +603,10 @@ class LibvirtConnTestCase(test.TestCase):
self.assertTrue(compute_node['hypervisor_version'] > 0)
db.service_destroy(self.context, service_ref['id'])
- FLAGS.instances_path = org_path
def test_update_resource_info_no_compute_record_found(self):
"""Raise exception if no recorde found on services table."""
- org_path = FLAGS.instances_path = ''
- FLAGS.instances_path = '.'
+ self.flags(instances_path='.')
self.create_fake_libvirt_mock()
self.mox.ReplayAll()
@@ -645,8 +615,6 @@ class LibvirtConnTestCase(test.TestCase):
conn.update_available_resource,
self.context, 'dummy')
- FLAGS.instances_path = org_path
-
def test_ensure_filtering_rules_for_instance_timeout(self):
"""ensure_filtering_fules_for_instance() finishes with timeout."""
# Skip if non-libvirt environment
@@ -721,6 +689,9 @@ class LibvirtConnTestCase(test.TestCase):
return vdmock
self.create_fake_libvirt_mock(lookupByName=fake_lookup)
+ self.mox.StubOutWithMock(self.compute, "recover_live_migration")
+ self.compute.recover_live_migration(self.context, instance_ref,
+ dest='dest')
# Start test
self.mox.ReplayAll()
@@ -739,7 +710,6 @@ class LibvirtConnTestCase(test.TestCase):
db.volume_destroy(self.context, volume_ref['id'])
db.instance_destroy(self.context, instance_ref['id'])
- @test.skip_test("test needs rewrite: instance no longer has mac_address")
def test_spawn_with_network_info(self):
# Skip if non-libvirt environment
if not self.lazy_load_library_exists():
@@ -758,20 +728,10 @@ class LibvirtConnTestCase(test.TestCase):
conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
- network = db.project_get_networks(context.get_admin_context(),
- self.project.id)[0]
- ip_dict = {'ip': self.test_ip,
- 'netmask': network['netmask'],
- 'enabled': '1'}
- mapping = {'label': network['label'],
- 'gateway': network['gateway'],
- 'mac': instance['mac_address'],
- 'dns': [network['dns']],
- 'ips': [ip_dict]}
- network_info = [(network, mapping)]
+ network_info = _create_network_info()
try:
- conn.spawn(instance, network_info)
+ conn.spawn(self.context, instance, network_info)
except Exception, e:
count = (0 <= str(e.message).find('Unexpected method call'))
@@ -814,11 +774,9 @@ class IptablesFirewallTestCase(test.TestCase):
def setUp(self):
super(IptablesFirewallTestCase, self).setUp()
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake',
- admin=True)
- self.project = self.manager.create_project('fake', 'fake', 'fake')
- self.context = context.RequestContext('fake', 'fake')
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
self.network = utils.import_object(FLAGS.network_manager)
class FakeLibvirtConnection(object):
@@ -826,6 +784,7 @@ class IptablesFirewallTestCase(test.TestCase):
"""setup_basic_rules in nwfilter calls this."""
pass
self.fake_libvirt_connection = FakeLibvirtConnection()
+ self.test_ip = '10.11.12.13'
self.fw = firewall.IptablesFirewallDriver(
get_connection=lambda: self.fake_libvirt_connection)
@@ -843,11 +802,6 @@ class IptablesFirewallTestCase(test.TestCase):
connection.libxml2 = __import__('libxml2')
return True
- def tearDown(self):
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
- super(IptablesFirewallTestCase, self).tearDown()
-
in_nat_rules = [
'# Generated by iptables-save v1.4.10 on Sat Feb 19 00:03:19 2011',
'*nat',
@@ -891,27 +845,11 @@ class IptablesFirewallTestCase(test.TestCase):
'project_id': 'fake',
'instance_type_id': 1})
- @test.skip_test("skipping libvirt tests depends on get_network_info shim")
def test_static_filters(self):
instance_ref = self._create_instance_ref()
- ip = '10.11.12.13'
-
- network_ref = db.project_get_networks(self.context,
- 'fake',
- associate=True)[0]
- vif = {'address': '56:12:12:12:12:12',
- 'network_id': network_ref['id'],
- 'instance_id': instance_ref['id']}
- vif_ref = db.virtual_interface_create(self.context, vif)
-
- fixed_ip = {'address': ip,
- 'network_id': network_ref['id'],
- 'virtual_interface_id': vif_ref['id']}
- admin_ctxt = context.get_admin_context()
- db.fixed_ip_create(admin_ctxt, fixed_ip)
- db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
- 'instance_id': instance_ref['id']})
+ _setup_networking(instance_ref['id'], self.test_ip)
+ admin_ctxt = context.get_admin_context()
secgroup = db.security_group_create(admin_ctxt,
{'user_id': 'fake',
'project_id': 'fake',
@@ -1043,7 +981,6 @@ class IptablesFirewallTestCase(test.TestCase):
self.assertEquals(ipv6_network_rules,
ipv6_rules_per_network * networks_count)
- @test.skip_test("skipping libvirt tests")
def test_do_refresh_security_group_rules(self):
instance_ref = self._create_instance_ref()
self.mox.StubOutWithMock(self.fw,
@@ -1054,7 +991,6 @@ class IptablesFirewallTestCase(test.TestCase):
self.mox.ReplayAll()
self.fw.do_refresh_security_group_rules("fake")
- @test.skip_test("skip libvirt test project_get_network no longer exists")
def test_unfilter_instance_undefines_nwfilter(self):
# Skip if non-libvirt environment
if not self.lazy_load_library_exists():
@@ -1068,38 +1004,24 @@ class IptablesFirewallTestCase(test.TestCase):
self.fw.nwfilter._conn.nwfilterLookupByName =\
fakefilter.nwfilterLookupByName
instance_ref = self._create_instance_ref()
- inst_id = instance_ref['id']
- instance = db.instance_get(self.context, inst_id)
- ip = '10.11.12.13'
- network_ref = db.project_get_network(self.context, 'fake')
- fixed_ip = {'address': ip, 'network_id': network_ref['id']}
- db.fixed_ip_create(admin_ctxt, fixed_ip)
- db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
- 'instance_id': inst_id})
- self.fw.setup_basic_filtering(instance)
- self.fw.prepare_instance_filter(instance)
- self.fw.apply_instance_filter(instance)
+ _setup_networking(instance_ref['id'], self.test_ip)
+ self.fw.setup_basic_filtering(instance_ref)
+ self.fw.prepare_instance_filter(instance_ref)
+ self.fw.apply_instance_filter(instance_ref)
original_filter_count = len(fakefilter.filters)
- self.fw.unfilter_instance(instance)
+ self.fw.unfilter_instance(instance_ref)
# should undefine just the instance filter
self.assertEqual(original_filter_count - len(fakefilter.filters), 1)
db.instance_destroy(admin_ctxt, instance_ref['id'])
- @test.skip_test("skip libvirt test project_get_network no longer exists")
def test_provider_firewall_rules(self):
# setup basic instance data
instance_ref = self._create_instance_ref()
nw_info = _create_network_info(1)
- ip = '10.11.12.13'
- network_ref = db.project_get_network(self.context, 'fake')
- admin_ctxt = context.get_admin_context()
- fixed_ip = {'address': ip, 'network_id': network_ref['id']}
- db.fixed_ip_create(admin_ctxt, fixed_ip)
- db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
- 'instance_id': instance_ref['id']})
+ _setup_networking(instance_ref['id'], self.test_ip)
# FRAGILE: peeks at how the firewall names chains
chain_name = 'inst-%s' % instance_ref['id']
@@ -1111,6 +1033,7 @@ class IptablesFirewallTestCase(test.TestCase):
if rule.chain == 'provider']
self.assertEqual(0, len(rules))
+ admin_ctxt = context.get_admin_context()
# add a rule and send the update message, check for 1 rule
provider_fw0 = db.provider_fw_rule_create(admin_ctxt,
{'protocol': 'tcp',
@@ -1161,22 +1084,16 @@ class NWFilterTestCase(test.TestCase):
class Mock(object):
pass
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake',
- admin=True)
- self.project = self.manager.create_project('fake', 'fake', 'fake')
- self.context = context.RequestContext(self.user, self.project)
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
self.fake_libvirt_connection = Mock()
+ self.test_ip = '10.11.12.13'
self.fw = firewall.NWFilterFirewall(
lambda: self.fake_libvirt_connection)
- def tearDown(self):
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
- super(NWFilterTestCase, self).tearDown()
-
def test_cidr_rule_nwfilter_xml(self):
cloud_controller = cloud.CloudController()
cloud_controller.create_security_group(self.context,
@@ -1255,7 +1172,6 @@ class NWFilterTestCase(test.TestCase):
inst.update(params)
return db.instance_type_create(context, inst)['id']
- @test.skip_test('Skipping this test')
def test_creates_base_rule_first(self):
# These come pre-defined by libvirt
self.defined_filters = ['no-mac-spoofing',
@@ -1287,21 +1203,11 @@ class NWFilterTestCase(test.TestCase):
instance_ref = self._create_instance()
inst_id = instance_ref['id']
- ip = '10.11.12.13'
-
- #network_ref = db.project_get_networks(self.context, 'fake')[0]
- #fixed_ip = {'address': ip, 'network_id': network_ref['id']}
-
- #admin_ctxt = context.get_admin_context()
- #db.fixed_ip_create(admin_ctxt, fixed_ip)
- #db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
- # 'instance_id': inst_id})
-
- self._setup_networking(instance_ref['id'], ip=ip)
+ _setup_networking(instance_ref['id'], self.test_ip)
def _ensure_all_called():
instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'],
- '00A0C914C829')
+ '561212121212')
secgroup_filter = 'nova-secgroup-%s' % self.security_group['id']
for required in [secgroup_filter, 'allow-dhcp-server',
'no-arp-spoofing', 'no-ip-spoofing',
@@ -1322,7 +1228,7 @@ class NWFilterTestCase(test.TestCase):
self.fw.apply_instance_filter(instance)
_ensure_all_called()
self.teardown_security_group()
- db.instance_destroy(admin_ctxt, instance_ref['id'])
+ db.instance_destroy(context.get_admin_context(), instance_ref['id'])
def test_create_network_filters(self):
instance_ref = self._create_instance()
@@ -1332,7 +1238,6 @@ class NWFilterTestCase(test.TestCase):
"fake")
self.assertEquals(len(result), 3)
- @test.skip_test("skip libvirt test project_get_network no longer exists")
def test_unfilter_instance_undefines_nwfilters(self):
admin_ctxt = context.get_admin_context()
@@ -1350,12 +1255,7 @@ class NWFilterTestCase(test.TestCase):
instance = db.instance_get(self.context, inst_id)
- ip = '10.11.12.13'
- network_ref = db.project_get_network(self.context, 'fake')
- fixed_ip = {'address': ip, 'network_id': network_ref['id']}
- db.fixed_ip_create(admin_ctxt, fixed_ip)
- db.fixed_ip_update(admin_ctxt, ip, {'allocated': True,
- 'instance_id': inst_id})
+ _setup_networking(instance_ref['id'], self.test_ip)
self.fw.setup_basic_filtering(instance)
self.fw.prepare_instance_filter(instance)
self.fw.apply_instance_filter(instance)
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
index b09021e13..2ca8b64f4 100644
--- a/nova/tests/test_network.py
+++ b/nova/tests/test_network.py
@@ -17,7 +17,6 @@
from nova import db
from nova import exception
-from nova import flags
from nova import log as logging
from nova import test
from nova.network import manager as network_manager
@@ -26,7 +25,6 @@ from nova.network import manager as network_manager
import mox
-FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
@@ -45,6 +43,7 @@ class FakeModel(dict):
networks = [{'id': 0,
'label': 'test0',
'injected': False,
+ 'multi_host': False,
'cidr': '192.168.0.0/24',
'cidr_v6': '2001:db8::/64',
'gateway_v6': '2001:db8::1',
@@ -54,7 +53,8 @@ networks = [{'id': 0,
'bridge_interface': 'fake_fa0',
'gateway': '192.168.0.1',
'broadcast': '192.168.0.255',
- 'dns': '192.168.0.1',
+ 'dns1': '192.168.0.1',
+ 'dns2': '192.168.0.2',
'vlan': None,
'host': None,
'project_id': 'fake_project',
@@ -62,6 +62,7 @@ networks = [{'id': 0,
{'id': 1,
'label': 'test1',
'injected': False,
+ 'multi_host': False,
'cidr': '192.168.1.0/24',
'cidr_v6': '2001:db9::/64',
'gateway_v6': '2001:db9::1',
@@ -71,7 +72,8 @@ networks = [{'id': 0,
'bridge_interface': 'fake_fa1',
'gateway': '192.168.1.1',
'broadcast': '192.168.1.255',
- 'dns': '192.168.0.1',
+ 'dns1': '192.168.0.1',
+ 'dns2': '192.168.0.2',
'vlan': None,
'host': None,
'project_id': 'fake_project',
@@ -122,34 +124,20 @@ class FlatNetworkTestCase(test.TestCase):
self.network = network_manager.FlatManager(host=HOST)
self.network.db = db
- def test_set_network_hosts(self):
- self.mox.StubOutWithMock(db, 'network_get_all')
- self.mox.StubOutWithMock(db, 'network_set_host')
- self.mox.StubOutWithMock(db, 'network_update')
-
- db.network_get_all(mox.IgnoreArg()).AndReturn([networks[0]])
- db.network_set_host(mox.IgnoreArg(),
- networks[0]['id'],
- mox.IgnoreArg()).AndReturn(HOST)
- db.network_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg())
- self.mox.ReplayAll()
-
- self.network.set_network_hosts(None)
-
def test_get_instance_nw_info(self):
self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance')
self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance')
- self.mox.StubOutWithMock(db, 'instance_type_get_by_id')
+ self.mox.StubOutWithMock(db, 'instance_type_get')
db.fixed_ip_get_by_instance(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(fixed_ips)
db.virtual_interface_get_by_instance(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(vifs)
- db.instance_type_get_by_id(mox.IgnoreArg(),
+ db.instance_type_get(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(flavor)
self.mox.ReplayAll()
- nw_info = self.network.get_instance_nw_info(None, 0, 0)
+ nw_info = self.network.get_instance_nw_info(None, 0, 0, None)
self.assertTrue(nw_info)
@@ -159,11 +147,15 @@ class FlatNetworkTestCase(test.TestCase):
'cidr': '192.168.%s.0/24' % i,
'cidr_v6': '2001:db%s::/64' % i8,
'id': i,
- 'injected': 'DONTCARE'}
+ 'multi_host': False,
+ 'injected': 'DONTCARE',
+ 'bridge_interface': 'fake_fa%s' % i,
+ 'vlan': None}
self.assertDictMatch(nw[0], check)
check = {'broadcast': '192.168.%s.255' % i,
+ 'dhcp_server': '192.168.%s.1' % i,
'dns': 'DONTCARE',
'gateway': '192.168.%s.1' % i,
'gateway6': '2001:db%s::1' % i8,
@@ -171,7 +163,9 @@ class FlatNetworkTestCase(test.TestCase):
'ips': 'DONTCARE',
'label': 'test%s' % i,
'mac': 'DE:AD:BE:EF:00:0%s' % i,
- 'rxtx_cap': 'DONTCARE'}
+ 'rxtx_cap': 'DONTCARE',
+ 'should_create_vlan': False,
+ 'should_create_bridge': False}
self.assertDictMatch(nw[1], check)
check = [{'enabled': 'DONTCARE',
diff --git a/nova/tests/test_nova_manage.py b/nova/tests/test_nova_manage.py
new file mode 100644
index 000000000..9c6563f14
--- /dev/null
+++ b/nova/tests/test_nova_manage.py
@@ -0,0 +1,82 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC
+# Copyright 2011 Ilya Alekseyev
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+import sys
+
+TOPDIR = os.path.normpath(os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ os.pardir,
+ os.pardir))
+NOVA_MANAGE_PATH = os.path.join(TOPDIR, 'bin', 'nova-manage')
+
+sys.dont_write_bytecode = True
+import imp
+nova_manage = imp.load_source('nova_manage.py', NOVA_MANAGE_PATH)
+sys.dont_write_bytecode = False
+
+import netaddr
+from nova import context
+from nova import db
+from nova import flags
+from nova import test
+
+FLAGS = flags.FLAGS
+
+
+class FixedIpCommandsTestCase(test.TestCase):
+ def setUp(self):
+ super(FixedIpCommandsTestCase, self).setUp()
+ cidr = '10.0.0.0/24'
+ net = netaddr.IPNetwork(cidr)
+ net_info = {'bridge': 'fakebr',
+ 'bridge_interface': 'fakeeth',
+ 'dns': FLAGS.flat_network_dns,
+ 'cidr': cidr,
+ 'netmask': str(net.netmask),
+ 'gateway': str(net[1]),
+ 'broadcast': str(net.broadcast),
+ 'dhcp_start': str(net[2])}
+ self.network = db.network_create_safe(context.get_admin_context(),
+ net_info)
+ num_ips = len(net)
+ for index in range(num_ips):
+ address = str(net[index])
+ reserved = (index == 1 or index == 2)
+ db.fixed_ip_create(context.get_admin_context(),
+ {'network_id': self.network['id'],
+ 'address': address,
+ 'reserved': reserved})
+ self.commands = nova_manage.FixedIpCommands()
+
+ def tearDown(self):
+ db.network_delete_safe(context.get_admin_context(), self.network['id'])
+ super(FixedIpCommandsTestCase, self).tearDown()
+
+ def test_reserve(self):
+ self.commands.reserve('10.0.0.100')
+ address = db.fixed_ip_get_by_address(context.get_admin_context(),
+ '10.0.0.100')
+ self.assertEqual(address['reserved'], True)
+
+ def test_unreserve(self):
+ db.fixed_ip_update(context.get_admin_context(), '10.0.0.100',
+ {'reserved': True})
+ self.commands.unreserve('10.0.0.100')
+ address = db.fixed_ip_get_by_address(context.get_admin_context(),
+ '10.0.0.100')
+ self.assertEqual(address['reserved'], False)
diff --git a/nova/tests/test_objectstore.py b/nova/tests/test_objectstore.py
index 39b4e18d7..0b2dce20e 100644
--- a/nova/tests/test_objectstore.py
+++ b/nova/tests/test_objectstore.py
@@ -21,8 +21,6 @@ Unittets for S3 objectstore clone.
"""
import boto
-import glob
-import hashlib
import os
import shutil
import tempfile
@@ -30,12 +28,9 @@ import tempfile
from boto import exception as boto_exception
from boto.s3 import connection as s3
-from nova import context
-from nova import exception
from nova import flags
from nova import wsgi
from nova import test
-from nova.auth import manager
from nova.objectstore import s3server
@@ -57,15 +52,9 @@ class S3APITestCase(test.TestCase):
def setUp(self):
"""Setup users, projects, and start a test server."""
super(S3APITestCase, self).setUp()
- self.flags(auth_driver='nova.auth.ldapdriver.FakeLdapDriver',
- buckets_path=os.path.join(OSS_TEMPDIR, 'buckets'),
+ self.flags(buckets_path=os.path.join(OSS_TEMPDIR, 'buckets'),
s3_host='127.0.0.1')
- self.auth_manager = manager.AuthManager()
- self.admin_user = self.auth_manager.create_user('admin', admin=True)
- self.admin_project = self.auth_manager.create_project('admin',
- self.admin_user)
-
shutil.rmtree(FLAGS.buckets_path)
os.mkdir(FLAGS.buckets_path)
@@ -80,8 +69,8 @@ class S3APITestCase(test.TestCase):
boto.config.add_section('Boto')
boto.config.set('Boto', 'num_retries', '0')
- conn = s3.S3Connection(aws_access_key_id=self.admin_user.access,
- aws_secret_access_key=self.admin_user.secret,
+ conn = s3.S3Connection(aws_access_key_id='fake',
+ aws_secret_access_key='fake',
host=FLAGS.s3_host,
port=FLAGS.s3_port,
is_secure=False,
@@ -104,11 +93,11 @@ class S3APITestCase(test.TestCase):
self.assertEquals(buckets[0].name, name, "Wrong name")
return True
- def test_000_list_buckets(self):
+ def test_list_buckets(self):
"""Make sure we are starting with no buckets."""
self._ensure_no_buckets(self.conn.get_all_buckets())
- def test_001_create_and_delete_bucket(self):
+ def test_create_and_delete_bucket(self):
"""Test bucket creation and deletion."""
bucket_name = 'testbucket'
@@ -117,7 +106,7 @@ class S3APITestCase(test.TestCase):
self.conn.delete_bucket(bucket_name)
self._ensure_no_buckets(self.conn.get_all_buckets())
- def test_002_create_bucket_and_key_and_delete_key_again(self):
+ def test_create_bucket_and_key_and_delete_key_again(self):
"""Test key operations on buckets."""
bucket_name = 'testbucket'
key_name = 'somekey'
@@ -146,8 +135,6 @@ class S3APITestCase(test.TestCase):
bucket_name)
def tearDown(self):
- """Tear down auth and test server."""
- self.auth_manager.delete_user('admin')
- self.auth_manager.delete_project('admin')
+ """Tear down test server."""
self.server.stop()
super(S3APITestCase, self).tearDown()
diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py
index 69d2deafe..f4b481ebe 100644
--- a/nova/tests/test_quota.py
+++ b/nova/tests/test_quota.py
@@ -20,12 +20,9 @@ from nova import compute
from nova import context
from nova import db
from nova import flags
-from nova import network
from nova import quota
from nova import test
-from nova import utils
from nova import volume
-from nova.auth import manager
from nova.compute import instance_types
@@ -48,25 +45,20 @@ class QuotaTestCase(test.TestCase):
quota_gigabytes=20,
quota_floating_ips=1)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('admin', 'admin', 'admin', True)
- self.project = self.manager.create_project('admin', 'admin', 'admin')
self.network = self.network = self.start_service('network')
- self.context = context.RequestContext(project=self.project,
- user=self.user)
-
- def tearDown(self):
- manager.AuthManager().delete_project(self.project)
- manager.AuthManager().delete_user(self.user)
- super(QuotaTestCase, self).tearDown()
+ self.user_id = 'admin'
+ self.project_id = 'admin'
+ self.context = context.RequestContext(self.user_id,
+ self.project_id,
+ True)
def _create_instance(self, cores=2):
"""Create a test instance"""
inst = {}
inst['image_id'] = 1
inst['reservation_id'] = 'r-fakeres'
- inst['user_id'] = self.user.id
- inst['project_id'] = self.project.id
+ inst['user_id'] = self.user_id
+ inst['project_id'] = self.project_id
inst['instance_type_id'] = '3' # m1.large
inst['vcpus'] = cores
return db.instance_create(self.context, inst)['id']
@@ -74,8 +66,8 @@ class QuotaTestCase(test.TestCase):
def _create_volume(self, size=10):
"""Create a test volume"""
vol = {}
- vol['user_id'] = self.user.id
- vol['project_id'] = self.project.id
+ vol['user_id'] = self.user_id
+ vol['project_id'] = self.project_id
vol['size'] = size
return db.volume_create(self.context, vol)['id']
@@ -95,15 +87,15 @@ class QuotaTestCase(test.TestCase):
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 2)
- db.quota_create(self.context, self.project.id, 'instances', 10)
+ db.quota_create(self.context, self.project_id, 'instances', 10)
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 4)
- db.quota_create(self.context, self.project.id, 'cores', 100)
+ db.quota_create(self.context, self.project_id, 'cores', 100)
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 10)
- db.quota_create(self.context, self.project.id, 'ram', 3 * 2048)
+ db.quota_create(self.context, self.project_id, 'ram', 3 * 2048)
num_instances = quota.allowed_instances(self.context, 100,
self._get_instance_type('m1.small'))
self.assertEqual(num_instances, 3)
@@ -113,23 +105,21 @@ class QuotaTestCase(test.TestCase):
num_metadata_items = quota.allowed_metadata_items(self.context,
too_many_items)
self.assertEqual(num_metadata_items, FLAGS.quota_metadata_items)
- db.quota_create(self.context, self.project.id, 'metadata_items', 5)
+ db.quota_create(self.context, self.project_id, 'metadata_items', 5)
num_metadata_items = quota.allowed_metadata_items(self.context,
too_many_items)
self.assertEqual(num_metadata_items, 5)
# Cleanup
- db.quota_destroy_all_by_project(self.context, self.project.id)
+ db.quota_destroy_all_by_project(self.context, self.project_id)
def test_unlimited_instances(self):
- FLAGS.quota_instances = 2
- FLAGS.quota_ram = -1
- FLAGS.quota_cores = -1
+ self.flags(quota_instances=2, quota_ram=-1, quota_cores=-1)
instance_type = self._get_instance_type('m1.small')
num_instances = quota.allowed_instances(self.context, 100,
instance_type)
self.assertEqual(num_instances, 2)
- db.quota_create(self.context, self.project.id, 'instances', None)
+ db.quota_create(self.context, self.project_id, 'instances', None)
num_instances = quota.allowed_instances(self.context, 100,
instance_type)
self.assertEqual(num_instances, 100)
@@ -138,14 +128,12 @@ class QuotaTestCase(test.TestCase):
self.assertEqual(num_instances, 101)
def test_unlimited_ram(self):
- FLAGS.quota_instances = -1
- FLAGS.quota_ram = 2 * 2048
- FLAGS.quota_cores = -1
+ self.flags(quota_instances=-1, quota_ram=2 * 2048, quota_cores=-1)
instance_type = self._get_instance_type('m1.small')
num_instances = quota.allowed_instances(self.context, 100,
instance_type)
self.assertEqual(num_instances, 2)
- db.quota_create(self.context, self.project.id, 'ram', None)
+ db.quota_create(self.context, self.project_id, 'ram', None)
num_instances = quota.allowed_instances(self.context, 100,
instance_type)
self.assertEqual(num_instances, 100)
@@ -154,14 +142,12 @@ class QuotaTestCase(test.TestCase):
self.assertEqual(num_instances, 101)
def test_unlimited_cores(self):
- FLAGS.quota_instances = -1
- FLAGS.quota_ram = -1
- FLAGS.quota_cores = 2
+ self.flags(quota_instances=-1, quota_ram=-1, quota_cores=2)
instance_type = self._get_instance_type('m1.small')
num_instances = quota.allowed_instances(self.context, 100,
instance_type)
self.assertEqual(num_instances, 2)
- db.quota_create(self.context, self.project.id, 'cores', None)
+ db.quota_create(self.context, self.project_id, 'cores', None)
num_instances = quota.allowed_instances(self.context, 100,
instance_type)
self.assertEqual(num_instances, 100)
@@ -170,42 +156,40 @@ class QuotaTestCase(test.TestCase):
self.assertEqual(num_instances, 101)
def test_unlimited_volumes(self):
- FLAGS.quota_volumes = 10
- FLAGS.quota_gigabytes = -1
+ self.flags(quota_volumes=10, quota_gigabytes=-1)
volumes = quota.allowed_volumes(self.context, 100, 1)
self.assertEqual(volumes, 10)
- db.quota_create(self.context, self.project.id, 'volumes', None)
+ db.quota_create(self.context, self.project_id, 'volumes', None)
volumes = quota.allowed_volumes(self.context, 100, 1)
self.assertEqual(volumes, 100)
volumes = quota.allowed_volumes(self.context, 101, 1)
self.assertEqual(volumes, 101)
def test_unlimited_gigabytes(self):
- FLAGS.quota_volumes = -1
- FLAGS.quota_gigabytes = 10
+ self.flags(quota_volumes=-1, quota_gigabytes=10)
volumes = quota.allowed_volumes(self.context, 100, 1)
self.assertEqual(volumes, 10)
- db.quota_create(self.context, self.project.id, 'gigabytes', None)
+ db.quota_create(self.context, self.project_id, 'gigabytes', None)
volumes = quota.allowed_volumes(self.context, 100, 1)
self.assertEqual(volumes, 100)
volumes = quota.allowed_volumes(self.context, 101, 1)
self.assertEqual(volumes, 101)
def test_unlimited_floating_ips(self):
- FLAGS.quota_floating_ips = 10
+ self.flags(quota_floating_ips=10)
floating_ips = quota.allowed_floating_ips(self.context, 100)
self.assertEqual(floating_ips, 10)
- db.quota_create(self.context, self.project.id, 'floating_ips', None)
+ db.quota_create(self.context, self.project_id, 'floating_ips', None)
floating_ips = quota.allowed_floating_ips(self.context, 100)
self.assertEqual(floating_ips, 100)
floating_ips = quota.allowed_floating_ips(self.context, 101)
self.assertEqual(floating_ips, 101)
def test_unlimited_metadata_items(self):
- FLAGS.quota_metadata_items = 10
+ self.flags(quota_metadata_items=10)
items = quota.allowed_metadata_items(self.context, 100)
self.assertEqual(items, 10)
- db.quota_create(self.context, self.project.id, 'metadata_items', None)
+ db.quota_create(self.context, self.project_id, 'metadata_items', None)
items = quota.allowed_metadata_items(self.context, 100)
self.assertEqual(items, 100)
items = quota.allowed_metadata_items(self.context, 101)
@@ -269,16 +253,15 @@ class QuotaTestCase(test.TestCase):
for volume_id in volume_ids:
db.volume_destroy(self.context, volume_id)
- @test.skip_test
def test_too_many_addresses(self):
address = '192.168.0.100'
db.floating_ip_create(context.get_admin_context(),
- {'address': address, 'host': FLAGS.host,
- 'project_id': self.project.id})
+ {'address': address,
+ 'project_id': self.project_id})
self.assertRaises(quota.QuotaError,
self.network.allocate_floating_ip,
self.context,
- self.project.id)
+ self.project_id)
db.floating_ip_destroy(context.get_admin_context(), address)
def test_too_many_metadata_items(self):
@@ -295,49 +278,49 @@ class QuotaTestCase(test.TestCase):
metadata=metadata)
def test_default_allowed_injected_files(self):
- FLAGS.quota_max_injected_files = 55
+ self.flags(quota_max_injected_files=55)
self.assertEqual(quota.allowed_injected_files(self.context, 100), 55)
def test_overridden_allowed_injected_files(self):
- FLAGS.quota_max_injected_files = 5
- db.quota_create(self.context, self.project.id, 'injected_files', 77)
+ self.flags(quota_max_injected_files=5)
+ db.quota_create(self.context, self.project_id, 'injected_files', 77)
self.assertEqual(quota.allowed_injected_files(self.context, 100), 77)
def test_unlimited_default_allowed_injected_files(self):
- FLAGS.quota_max_injected_files = -1
+ self.flags(quota_max_injected_files=-1)
self.assertEqual(quota.allowed_injected_files(self.context, 100), 100)
def test_unlimited_db_allowed_injected_files(self):
- FLAGS.quota_max_injected_files = 5
- db.quota_create(self.context, self.project.id, 'injected_files', None)
+ self.flags(quota_max_injected_files=5)
+ db.quota_create(self.context, self.project_id, 'injected_files', None)
self.assertEqual(quota.allowed_injected_files(self.context, 100), 100)
def test_default_allowed_injected_file_content_bytes(self):
- FLAGS.quota_max_injected_file_content_bytes = 12345
+ self.flags(quota_max_injected_file_content_bytes=12345)
limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
self.assertEqual(limit, 12345)
def test_overridden_allowed_injected_file_content_bytes(self):
- FLAGS.quota_max_injected_file_content_bytes = 12345
- db.quota_create(self.context, self.project.id,
+ self.flags(quota_max_injected_file_content_bytes=12345)
+ db.quota_create(self.context, self.project_id,
'injected_file_content_bytes', 5678)
limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
self.assertEqual(limit, 5678)
def test_unlimited_default_allowed_injected_file_content_bytes(self):
- FLAGS.quota_max_injected_file_content_bytes = -1
+ self.flags(quota_max_injected_file_content_bytes=-1)
limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
self.assertEqual(limit, 23456)
def test_unlimited_db_allowed_injected_file_content_bytes(self):
- FLAGS.quota_max_injected_file_content_bytes = 12345
- db.quota_create(self.context, self.project.id,
+ self.flags(quota_max_injected_file_content_bytes=12345)
+ db.quota_create(self.context, self.project_id,
'injected_file_content_bytes', None)
limit = quota.allowed_injected_file_content_bytes(self.context, 23456)
self.assertEqual(limit, 23456)
def _create_with_injected_files(self, files):
- FLAGS.image_service = 'nova.image.fake.FakeImageService'
+ self.flags(image_service='nova.image.fake.FakeImageService')
api = compute.API(image_service=self.StubImageService())
inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, min_count=1, max_count=1,
@@ -345,7 +328,7 @@ class QuotaTestCase(test.TestCase):
injected_files=files)
def test_no_injected_files(self):
- FLAGS.image_service = 'nova.image.fake.FakeImageService'
+ self.flags(image_service='nova.image.fake.FakeImageService')
api = compute.API(image_service=self.StubImageService())
inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, instance_type=inst_type, image_href='3')
diff --git a/nova/tests/test_rpc.py b/nova/tests/test_rpc.py
index ffd748efe..ba9c0a859 100644
--- a/nova/tests/test_rpc.py
+++ b/nova/tests/test_rpc.py
@@ -20,24 +20,23 @@ Unit Tests for remote procedure calls using queue
"""
from nova import context
-from nova import flags
from nova import log as logging
from nova import rpc
from nova import test
-FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.rpc')
class RpcTestCase(test.TestCase):
def setUp(self):
super(RpcTestCase, self).setUp()
- self.conn = rpc.Connection.instance(True)
+ self.conn = rpc.create_connection(True)
self.receiver = TestReceiver()
- self.consumer = rpc.TopicAdapterConsumer(connection=self.conn,
- topic='test',
- proxy=self.receiver)
+ self.consumer = rpc.create_consumer(self.conn,
+ 'test',
+ self.receiver,
+ False)
self.consumer.attach_to_eventlet()
self.context = context.get_admin_context()
@@ -129,6 +128,8 @@ class RpcTestCase(test.TestCase):
"""Calls echo in the passed queue"""
LOG.debug(_("Nested received %(queue)s, %(value)s")
% locals())
+ # TODO: so, it will replay the context and use the same REQID?
+ # that's bizarre.
ret = rpc.call(context,
queue,
{"method": "echo",
@@ -137,10 +138,11 @@ class RpcTestCase(test.TestCase):
return value
nested = Nested()
- conn = rpc.Connection.instance(True)
- consumer = rpc.TopicAdapterConsumer(connection=conn,
- topic='nested',
- proxy=nested)
+ conn = rpc.create_connection(True)
+ consumer = rpc.create_consumer(conn,
+ 'nested',
+ nested,
+ False)
consumer.attach_to_eventlet()
value = 42
result = rpc.call(self.context,
@@ -149,47 +151,6 @@ class RpcTestCase(test.TestCase):
"value": value}})
self.assertEqual(value, result)
- def test_connectionpool_single(self):
- """Test that ConnectionPool recycles a single connection."""
- conn1 = rpc.ConnectionPool.get()
- rpc.ConnectionPool.put(conn1)
- conn2 = rpc.ConnectionPool.get()
- rpc.ConnectionPool.put(conn2)
- self.assertEqual(conn1, conn2)
-
- def test_connectionpool_double(self):
- """Test that ConnectionPool returns and reuses separate connections.
-
- When called consecutively we should get separate connections and upon
- returning them those connections should be reused for future calls
- before generating a new connection.
-
- """
- conn1 = rpc.ConnectionPool.get()
- conn2 = rpc.ConnectionPool.get()
-
- self.assertNotEqual(conn1, conn2)
- rpc.ConnectionPool.put(conn1)
- rpc.ConnectionPool.put(conn2)
-
- conn3 = rpc.ConnectionPool.get()
- conn4 = rpc.ConnectionPool.get()
- self.assertEqual(conn1, conn3)
- self.assertEqual(conn2, conn4)
-
- def test_connectionpool_limit(self):
- """Test connection pool limit and connection uniqueness."""
- max_size = FLAGS.rpc_conn_pool_size
- conns = []
-
- for i in xrange(max_size):
- conns.append(rpc.ConnectionPool.get())
-
- self.assertFalse(rpc.ConnectionPool.free_items)
- self.assertEqual(rpc.ConnectionPool.current_size,
- rpc.ConnectionPool.max_size)
- self.assertEqual(len(set(conns)), max_size)
-
class TestReceiver(object):
"""Simple Proxy class so the consumer has methods to call.
diff --git a/nova/tests/test_rpc_amqp.py b/nova/tests/test_rpc_amqp.py
new file mode 100644
index 000000000..2215a908b
--- /dev/null
+++ b/nova/tests/test_rpc_amqp.py
@@ -0,0 +1,88 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2010 Openstack, LLC.
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Tests For RPC AMQP.
+"""
+
+from nova import context
+from nova import log as logging
+from nova import rpc
+from nova.rpc import amqp
+from nova import test
+
+
+LOG = logging.getLogger('nova.tests.rpc')
+
+
+class RpcAMQPTestCase(test.TestCase):
+ def setUp(self):
+ super(RpcAMQPTestCase, self).setUp()
+ self.conn = rpc.create_connection(True)
+ self.receiver = TestReceiver()
+ self.consumer = rpc.create_consumer(self.conn,
+ 'test',
+ self.receiver,
+ False)
+ self.consumer.attach_to_eventlet()
+ self.context = context.get_admin_context()
+
+ def test_connectionpool_single(self):
+ """Test that ConnectionPool recycles a single connection."""
+ conn1 = amqp.ConnectionPool.get()
+ amqp.ConnectionPool.put(conn1)
+ conn2 = amqp.ConnectionPool.get()
+ amqp.ConnectionPool.put(conn2)
+ self.assertEqual(conn1, conn2)
+
+
+class TestReceiver(object):
+ """Simple Proxy class so the consumer has methods to call.
+
+ Uses static methods because we aren't actually storing any state.
+
+ """
+
+ @staticmethod
+ def echo(context, value):
+ """Simply returns whatever value is sent in."""
+ LOG.debug(_("Received %s"), value)
+ return value
+
+ @staticmethod
+ def context(context, value):
+ """Returns dictionary version of context."""
+ LOG.debug(_("Received %s"), context)
+ return context.to_dict()
+
+ @staticmethod
+ def echo_three_times(context, value):
+ context.reply(value)
+ context.reply(value + 1)
+ context.reply(value + 2)
+
+ @staticmethod
+ def echo_three_times_yield(context, value):
+ yield value
+ yield value + 1
+ yield value + 2
+
+ @staticmethod
+ def fail(context, value):
+ """Raises an exception with the value sent in."""
+ raise Exception(value)
diff --git a/nova/tests/test_service.py b/nova/tests/test_service.py
index f45f76b73..8f92406ff 100644
--- a/nova/tests/test_service.py
+++ b/nova/tests/test_service.py
@@ -33,7 +33,6 @@ from nova import manager
from nova import wsgi
from nova.compute import manager as compute_manager
-FLAGS = flags.FLAGS
flags.DEFINE_string("fake_manager", "nova.tests.test_service.FakeManager",
"Manager for testing")
@@ -109,103 +108,8 @@ class ServiceTestCase(test.TestCase):
# the looping calls are created in StartService.
app = service.Service.create(host=host, binary=binary, topic=topic)
- self.mox.StubOutWithMock(service.rpc.Connection, 'instance')
- service.rpc.Connection.instance(new=mox.IgnoreArg())
-
- self.mox.StubOutWithMock(rpc,
- 'TopicAdapterConsumer',
- use_mock_anything=True)
- self.mox.StubOutWithMock(rpc,
- 'FanoutAdapterConsumer',
- use_mock_anything=True)
-
- self.mox.StubOutWithMock(rpc,
- 'ConsumerSet',
- use_mock_anything=True)
-
- rpc.TopicAdapterConsumer(connection=mox.IgnoreArg(),
- topic=topic,
- proxy=mox.IsA(service.Service)).AndReturn(
- rpc.TopicAdapterConsumer)
-
- rpc.TopicAdapterConsumer(connection=mox.IgnoreArg(),
- topic='%s.%s' % (topic, host),
- proxy=mox.IsA(service.Service)).AndReturn(
- rpc.TopicAdapterConsumer)
-
- rpc.FanoutAdapterConsumer(connection=mox.IgnoreArg(),
- topic=topic,
- proxy=mox.IsA(service.Service)).AndReturn(
- rpc.FanoutAdapterConsumer)
-
- def wait_func(self, limit=None):
- return None
-
- mock_cset = self.mox.CreateMock(rpc.ConsumerSet,
- {'wait': wait_func})
- rpc.ConsumerSet(connection=mox.IgnoreArg(),
- consumer_list=mox.IsA(list)).AndReturn(mock_cset)
- wait_func(mox.IgnoreArg())
-
- service_create = {'host': host,
- 'binary': binary,
- 'topic': topic,
- 'report_count': 0,
- 'availability_zone': 'nova'}
- service_ref = {'host': host,
- 'binary': binary,
- 'report_count': 0,
- 'id': 1}
-
- service.db.service_get_by_args(mox.IgnoreArg(),
- host,
- binary).AndRaise(exception.NotFound())
- service.db.service_create(mox.IgnoreArg(),
- service_create).AndReturn(service_ref)
- self.mox.ReplayAll()
-
- app.start()
- app.stop()
self.assert_(app)
- # We're testing sort of weird behavior in how report_state decides
- # whether it is disconnected, it looks for a variable on itself called
- # 'model_disconnected' and report_state doesn't really do much so this
- # these are mostly just for coverage
- def test_report_state_no_service(self):
- host = 'foo'
- binary = 'bar'
- topic = 'test'
- service_create = {'host': host,
- 'binary': binary,
- 'topic': topic,
- 'report_count': 0,
- 'availability_zone': 'nova'}
- service_ref = {'host': host,
- 'binary': binary,
- 'topic': topic,
- 'report_count': 0,
- 'availability_zone': 'nova',
- 'id': 1}
-
- service.db.service_get_by_args(mox.IgnoreArg(),
- host,
- binary).AndRaise(exception.NotFound())
- service.db.service_create(mox.IgnoreArg(),
- service_create).AndReturn(service_ref)
- service.db.service_get(mox.IgnoreArg(),
- service_ref['id']).AndReturn(service_ref)
- service.db.service_update(mox.IgnoreArg(), service_ref['id'],
- mox.ContainsKeyValue('report_count', 1))
-
- self.mox.ReplayAll()
- serv = service.Service(host,
- binary,
- topic,
- 'nova.tests.test_service.FakeManager')
- serv.start()
- serv.report_state()
-
def test_report_state_newly_disconnected(self):
host = 'foo'
binary = 'bar'
@@ -276,81 +180,6 @@ class ServiceTestCase(test.TestCase):
self.assert_(not serv.model_disconnected)
- def test_compute_can_update_available_resource(self):
- """Confirm compute updates their record of compute-service table."""
- host = 'foo'
- binary = 'nova-compute'
- topic = 'compute'
-
- # Any mocks are not working without UnsetStubs() here.
- self.mox.UnsetStubs()
- ctxt = context.get_admin_context()
- service_ref = db.service_create(ctxt, {'host': host,
- 'binary': binary,
- 'topic': topic})
- serv = service.Service(host,
- binary,
- topic,
- 'nova.compute.manager.ComputeManager')
-
- # This testcase want to test calling update_available_resource.
- # No need to call periodic call, then below variable must be set 0.
- serv.report_interval = 0
- serv.periodic_interval = 0
-
- # Creating mocks
- self.mox.StubOutWithMock(service.rpc.Connection, 'instance')
- service.rpc.Connection.instance(new=mox.IgnoreArg())
-
- self.mox.StubOutWithMock(rpc,
- 'TopicAdapterConsumer',
- use_mock_anything=True)
- self.mox.StubOutWithMock(rpc,
- 'FanoutAdapterConsumer',
- use_mock_anything=True)
-
- self.mox.StubOutWithMock(rpc,
- 'ConsumerSet',
- use_mock_anything=True)
-
- rpc.TopicAdapterConsumer(connection=mox.IgnoreArg(),
- topic=topic,
- proxy=mox.IsA(service.Service)).AndReturn(
- rpc.TopicAdapterConsumer)
-
- rpc.TopicAdapterConsumer(connection=mox.IgnoreArg(),
- topic='%s.%s' % (topic, host),
- proxy=mox.IsA(service.Service)).AndReturn(
- rpc.TopicAdapterConsumer)
-
- rpc.FanoutAdapterConsumer(connection=mox.IgnoreArg(),
- topic=topic,
- proxy=mox.IsA(service.Service)).AndReturn(
- rpc.FanoutAdapterConsumer)
-
- def wait_func(self, limit=None):
- return None
-
- mock_cset = self.mox.CreateMock(rpc.ConsumerSet,
- {'wait': wait_func})
- rpc.ConsumerSet(connection=mox.IgnoreArg(),
- consumer_list=mox.IsA(list)).AndReturn(mock_cset)
- wait_func(mox.IgnoreArg())
-
- self.mox.StubOutWithMock(serv.manager.driver,
- 'update_available_resource')
- serv.manager.driver.update_available_resource(mox.IgnoreArg(), host)
-
- # Just doing start()-stop(), not confirm new db record is created,
- # because update_available_resource() works only in
- # libvirt environment. This testcase confirms
- # update_available_resource() is called. Otherwise, mox complains.
- self.mox.ReplayAll()
- serv.start()
- serv.stop()
-
- db.service_destroy(ctxt, service_ref['id'])
-
class TestWSGIService(test.TestCase):
diff --git a/nova/tests/test_skip_examples.py b/nova/tests/test_skip_examples.py
new file mode 100644
index 000000000..8ca203442
--- /dev/null
+++ b/nova/tests/test_skip_examples.py
@@ -0,0 +1,47 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova import test
+
+
+class ExampleSkipTestCase(test.TestCase):
+ test_counter = 0
+
+ @test.skip_test("Example usage of @test.skip_test()")
+ def test_skip_test_example(self):
+ self.fail("skip_test failed to work properly.")
+
+ @test.skip_if(True, "Example usage of @test.skip_if()")
+ def test_skip_if_example(self):
+ self.fail("skip_if failed to work properly.")
+
+ @test.skip_unless(False, "Example usage of @test.skip_unless()")
+ def test_skip_unless_example(self):
+ self.fail("skip_unless failed to work properly.")
+
+ @test.skip_if(False, "This test case should never be skipped.")
+ def test_001_increase_test_counter(self):
+ ExampleSkipTestCase.test_counter += 1
+
+ @test.skip_unless(True, "This test case should never be skipped.")
+ def test_002_increase_test_counter(self):
+ ExampleSkipTestCase.test_counter += 1
+
+ def test_003_verify_test_counter(self):
+ self.assertEquals(ExampleSkipTestCase.test_counter, 2,
+ "Tests were not skipped appropriately")
diff --git a/nova/tests/test_test.py b/nova/tests/test_test.py
index 35c838065..64f11fa45 100644
--- a/nova/tests/test_test.py
+++ b/nova/tests/test_test.py
@@ -33,8 +33,13 @@ class IsolationTestCase(test.TestCase):
self.start_service('compute')
def test_rpc_consumer_isolation(self):
- connection = rpc.Connection.instance(new=True)
- consumer = rpc.TopicAdapterConsumer(connection, topic='compute')
- consumer.register_callback(
- lambda x, y: self.fail('I should never be called'))
+ class NeverCalled(object):
+
+ def __getattribute__(*args):
+ assert False, "I should never get called."
+
+ connection = rpc.create_connection(new=True)
+ proxy = NeverCalled()
+ consumer = rpc.create_consumer(connection, 'compute',
+ proxy, fanout=False)
consumer.attach_to_eventlet()
diff --git a/nova/tests/test_twistd.py b/nova/tests/test_twistd.py
deleted file mode 100644
index ff8627c3b..000000000
--- a/nova/tests/test_twistd.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import StringIO
-import sys
-
-from nova import twistd
-from nova import exception
-from nova import flags
-from nova import test
-
-
-FLAGS = flags.FLAGS
-
-
-class TwistdTestCase(test.TestCase):
- def setUp(self):
- super(TwistdTestCase, self).setUp()
- self.Options = twistd.WrapTwistedOptions(twistd.TwistdServerOptions)
- sys.stdout = StringIO.StringIO()
-
- def tearDown(self):
- super(TwistdTestCase, self).tearDown()
- sys.stdout = sys.__stdout__
-
- def test_basic(self):
- options = self.Options()
- argv = options.parseOptions()
-
- def test_logfile(self):
- options = self.Options()
- argv = options.parseOptions(['--logfile=foo'])
- self.assertEqual(FLAGS.logfile, 'foo')
-
- def test_help(self):
- options = self.Options()
- self.assertRaises(SystemExit, options.parseOptions, ['--help'])
- self.assert_('pidfile' in sys.stdout.getvalue())
diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index 0c359e981..ec5098a37 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import datetime
import os
import tempfile
@@ -306,3 +307,80 @@ class IsUUIDLikeTestCase(test.TestCase):
def test_non_uuid_string_passed(self):
val = 'foo-fooo'
self.assertUUIDLike(val, False)
+
+
+class ToPrimitiveTestCase(test.TestCase):
+ def test_list(self):
+ self.assertEquals(utils.to_primitive([1, 2, 3]), [1, 2, 3])
+
+ def test_empty_list(self):
+ self.assertEquals(utils.to_primitive([]), [])
+
+ def test_tuple(self):
+ self.assertEquals(utils.to_primitive((1, 2, 3)), [1, 2, 3])
+
+ def test_dict(self):
+ self.assertEquals(utils.to_primitive(dict(a=1, b=2, c=3)),
+ dict(a=1, b=2, c=3))
+
+ def test_empty_dict(self):
+ self.assertEquals(utils.to_primitive({}), {})
+
+ def test_datetime(self):
+ x = datetime.datetime(1, 2, 3, 4, 5, 6, 7)
+ self.assertEquals(utils.to_primitive(x), "0001-02-03 04:05:06.000007")
+
+ def test_iter(self):
+ class IterClass(object):
+ def __init__(self):
+ self.data = [1, 2, 3, 4, 5]
+ self.index = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.index == len(self.data):
+ raise StopIteration
+ self.index = self.index + 1
+ return self.data[self.index - 1]
+
+ x = IterClass()
+ self.assertEquals(utils.to_primitive(x), [1, 2, 3, 4, 5])
+
+ def test_iteritems(self):
+ class IterItemsClass(object):
+ def __init__(self):
+ self.data = dict(a=1, b=2, c=3).items()
+ self.index = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.index == len(self.data):
+ raise StopIteration
+ self.index = self.index + 1
+ return self.data[self.index - 1]
+
+ x = IterItemsClass()
+ ordered = utils.to_primitive(x)
+ ordered.sort()
+ self.assertEquals(ordered, [['a', 1], ['b', 2], ['c', 3]])
+
+ def test_instance(self):
+ class MysteryClass(object):
+ a = 10
+
+ def __init__(self):
+ self.b = 1
+
+ x = MysteryClass()
+ self.assertEquals(utils.to_primitive(x, convert_instances=True),
+ dict(b=1))
+
+ self.assertEquals(utils.to_primitive(x), x)
+
+ def test_typeerror(self):
+ x = bytearray # Class, not instance
+ self.assertEquals(utils.to_primitive(x), u"<type 'bytearray'>")
diff --git a/nova/tests/test_vmwareapi.py b/nova/tests/test_vmwareapi.py
index cbf7801cf..06daf46e8 100644
--- a/nova/tests/test_vmwareapi.py
+++ b/nova/tests/test_vmwareapi.py
@@ -19,14 +19,11 @@
Test suite for VMWareAPI.
"""
-import stubout
-
from nova import context
from nova import db
from nova import flags
from nova import test
from nova import utils
-from nova.auth import manager
from nova.compute import power_state
from nova.tests.glance import stubs as glance_stubs
from nova.tests.vmwareapi import db_fakes
@@ -41,51 +38,64 @@ FLAGS = flags.FLAGS
class VMWareAPIVMTestCase(test.TestCase):
"""Unit tests for Vmware API connection calls."""
- # NOTE(jkoelker): This is leaking stubs into the db module.
- # Commenting out until updated for multi-nic.
- #def setUp(self):
- # super(VMWareAPIVMTestCase, self).setUp()
- # self.flags(vmwareapi_host_ip='test_url',
- # vmwareapi_host_username='test_username',
- # vmwareapi_host_password='test_pass')
- # self.manager = manager.AuthManager()
- # self.user = self.manager.create_user('fake', 'fake', 'fake',
- # admin=True)
- # self.project = self.manager.create_project('fake', 'fake', 'fake')
- # self.network = utils.import_object(FLAGS.network_manager)
- # self.stubs = stubout.StubOutForTesting()
- # vmwareapi_fake.reset()
- # db_fakes.stub_out_db_instance_api(self.stubs)
- # stubs.set_stubs(self.stubs)
- # glance_stubs.stubout_glance_client(self.stubs,
- # glance_stubs.FakeGlance)
- # self.conn = vmwareapi_conn.get_connection(False)
-
- #def tearDown(self):
- # super(VMWareAPIVMTestCase, self).tearDown()
- # vmwareapi_fake.cleanup()
- # self.manager.delete_project(self.project)
- # self.manager.delete_user(self.user)
- # self.stubs.UnsetAll()
+ def setUp(self):
+ super(VMWareAPIVMTestCase, self).setUp()
+ self.context = context.RequestContext('fake', 'fake', False)
+ self.flags(vmwareapi_host_ip='test_url',
+ vmwareapi_host_username='test_username',
+ vmwareapi_host_password='test_pass')
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
+ self.network = utils.import_object(FLAGS.network_manager)
+ vmwareapi_fake.reset()
+ db_fakes.stub_out_db_instance_api(self.stubs)
+ stubs.set_stubs(self.stubs)
+ glance_stubs.stubout_glance_client(self.stubs)
+ self.conn = vmwareapi_conn.get_connection(False)
+ # NOTE(vish): none of the network plugging code is actually
+ # being tested
+ self.network_info = [({'bridge': 'fa0',
+ 'id': 0,
+ 'vlan': None,
+ 'bridge_interface': None,
+ 'injected': True},
+ {'broadcast': '192.168.0.255',
+ 'dns': ['192.168.0.1'],
+ 'gateway': '192.168.0.1',
+ 'gateway6': 'dead:beef::1',
+ 'ip6s': [{'enabled': '1',
+ 'ip': 'dead:beef::dcad:beff:feef:0',
+ 'netmask': '64'}],
+ 'ips': [{'enabled': '1',
+ 'ip': '192.168.0.100',
+ 'netmask': '255.255.255.0'}],
+ 'label': 'fake',
+ 'mac': 'DE:AD:BE:EF:00:00',
+ 'rxtx_cap': 3})]
+
+ def tearDown(self):
+ super(VMWareAPIVMTestCase, self).tearDown()
+ vmwareapi_fake.cleanup()
def _create_instance_in_the_db(self):
values = {'name': 1,
'id': 1,
- 'project_id': self.project.id,
- 'user_id': self.user.id,
- 'image_id': "1",
+ 'project_id': self.project_id,
+ 'user_id': self.user_id,
+ 'image_ref': "1",
'kernel_id': "1",
'ramdisk_id': "1",
+ 'mac_address': "de:ad:be:ef:be:ef",
'instance_type': 'm1.large',
- 'mac_address': 'aa:bb:cc:dd:ee:ff',
}
- self.instance = db.instance_create(values)
+ self.instance = db.instance_create(None, values)
def _create_vm(self):
"""Create and spawn the VM."""
self._create_instance_in_the_db()
self.type_data = db.instance_type_get_by_name(None, 'm1.large')
- self.conn.spawn(self.instance)
+ self.conn.spawn(self.context, self.instance, self.network_info)
self._check_vm_record()
def _check_vm_record(self):
@@ -129,53 +139,45 @@ class VMWareAPIVMTestCase(test.TestCase):
self.assertEquals(info["mem"], mem_kib)
self.assertEquals(info["num_cpu"], self.type_data['vcpus'])
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_list_instances(self):
instances = self.conn.list_instances()
self.assertEquals(len(instances), 0)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_list_instances_1(self):
self._create_vm()
instances = self.conn.list_instances()
self.assertEquals(len(instances), 1)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_spawn(self):
self._create_vm()
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_snapshot(self):
self._create_vm()
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- self.conn.snapshot(self.instance, "Test-Snapshot")
+ self.conn.snapshot(self.context, self.instance, "Test-Snapshot")
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_snapshot_non_existent(self):
self._create_instance_in_the_db()
- self.assertRaises(Exception, self.conn.snapshot, self.instance,
- "Test-Snapshot")
+ self.assertRaises(Exception, self.conn.snapshot, self.context,
+ self.instance, "Test-Snapshot")
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_reboot(self):
self._create_vm()
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- self.conn.reboot(self.instance)
+ self.conn.reboot(self.instance, self.network_info)
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_reboot_non_existent(self):
self._create_instance_in_the_db()
self.assertRaises(Exception, self.conn.reboot, self.instance)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_reboot_not_poweredon(self):
self._create_vm()
info = self.conn.get_info(1)
@@ -185,7 +187,6 @@ class VMWareAPIVMTestCase(test.TestCase):
self._check_vm_info(info, power_state.PAUSED)
self.assertRaises(Exception, self.conn.reboot, self.instance)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_suspend(self):
self._create_vm()
info = self.conn.get_info(1)
@@ -194,13 +195,11 @@ class VMWareAPIVMTestCase(test.TestCase):
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.PAUSED)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_suspend_non_existent(self):
self._create_instance_in_the_db()
self.assertRaises(Exception, self.conn.suspend, self.instance,
self.dummy_callback_handler)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_resume(self):
self._create_vm()
info = self.conn.get_info(1)
@@ -212,13 +211,11 @@ class VMWareAPIVMTestCase(test.TestCase):
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_resume_non_existent(self):
self._create_instance_in_the_db()
self.assertRaises(Exception, self.conn.resume, self.instance,
self.dummy_callback_handler)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_resume_not_suspended(self):
self._create_vm()
info = self.conn.get_info(1)
@@ -226,49 +223,41 @@ class VMWareAPIVMTestCase(test.TestCase):
self.assertRaises(Exception, self.conn.resume, self.instance,
self.dummy_callback_handler)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_get_info(self):
self._create_vm()
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_destroy(self):
self._create_vm()
info = self.conn.get_info(1)
self._check_vm_info(info, power_state.RUNNING)
instances = self.conn.list_instances()
self.assertEquals(len(instances), 1)
- self.conn.destroy(self.instance)
+ self.conn.destroy(self.instance, self.network_info)
instances = self.conn.list_instances()
self.assertEquals(len(instances), 0)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_destroy_non_existent(self):
self._create_instance_in_the_db()
- self.assertEquals(self.conn.destroy(self.instance), None)
+ self.assertEquals(self.conn.destroy(self.instance, self.network_info),
+ None)
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_pause(self):
pass
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_unpause(self):
pass
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_diagnostics(self):
pass
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_get_console_output(self):
pass
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def test_get_ajax_console(self):
pass
- @test.skip_test("DB stubbing not removed, needs updating for multi-nic")
def dummy_callback_handler(self, ret):
"""
Dummy callback function to be passed to suspend, resume, etc., calls.
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 4cb7447d3..dfc1eeb0a 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -30,7 +30,6 @@ from nova import flags
from nova import log as logging
from nova import test
from nova import utils
-from nova.auth import manager
from nova.compute import instance_types
from nova.compute import power_state
from nova import exception
@@ -69,15 +68,17 @@ class XenAPIVolumeTestCase(test.TestCase):
def setUp(self):
super(XenAPIVolumeTestCase, self).setUp()
self.stubs = stubout.StubOutForTesting()
- self.context = context.RequestContext('fake', 'fake', False)
- FLAGS.target_host = '127.0.0.1'
- FLAGS.xenapi_connection_url = 'test_url'
- FLAGS.xenapi_connection_password = 'test_pass'
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
+ self.flags(target_host='127.0.0.1',
+ xenapi_connection_url='test_url',
+ xenapi_connection_password='test_pass')
db_fakes.stub_out_db_instance_api(self.stubs)
stubs.stub_out_get_target(self.stubs)
xenapi_fake.reset()
self.values = {'id': 1,
- 'project_id': 'fake',
+ 'project_id': self.user_id,
'user_id': 'fake',
'image_ref': 1,
'kernel_id': 2,
@@ -169,14 +170,14 @@ def reset_network(*args):
pass
+def _find_rescue_vbd_ref(*args):
+ pass
+
+
class XenAPIVMTestCase(test.TestCase):
"""Unit tests for VM operations."""
def setUp(self):
super(XenAPIVMTestCase, self).setUp()
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake',
- admin=True)
- self.project = self.manager.create_project('fake', 'fake', 'fake')
self.network = utils.import_object(FLAGS.network_manager)
self.stubs = stubout.StubOutForTesting()
self.flags(xenapi_connection_url='test_url',
@@ -192,10 +193,14 @@ class XenAPIVMTestCase(test.TestCase):
stubs.stubout_stream_disk(self.stubs)
stubs.stubout_is_vdi_pv(self.stubs)
self.stubs.Set(vmops.VMOps, 'reset_network', reset_network)
+ self.stubs.Set(vmops.VMOps, '_find_rescue_vbd_ref',
+ _find_rescue_vbd_ref)
stubs.stub_out_vm_methods(self.stubs)
glance_stubs.stubout_glance_client(self.stubs)
fake_utils.stub_out_utils_execute(self.stubs)
- self.context = context.RequestContext('fake', 'fake', False)
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
self.conn = xenapi_conn.get_connection(False)
def test_parallel_builds(self):
@@ -227,10 +232,10 @@ class XenAPIVMTestCase(test.TestCase):
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
instance = db.instance_create(self.context, values)
- self.conn.spawn(instance, network_info)
+ self.conn.spawn(self.context, instance, network_info)
- gt1 = eventlet.spawn(_do_build, 1, self.project.id, self.user.id)
- gt2 = eventlet.spawn(_do_build, 2, self.project.id, self.user.id)
+ gt1 = eventlet.spawn(_do_build, 1, self.project_id, self.user_id)
+ gt2 = eventlet.spawn(_do_build, 2, self.project_id, self.user_id)
gt1.wait()
gt2.wait()
@@ -257,14 +262,15 @@ class XenAPIVMTestCase(test.TestCase):
instance = self._create_instance()
name = "MySnapshot"
- self.assertRaises(exception.Error, self.conn.snapshot, instance, name)
+ self.assertRaises(exception.Error, self.conn.snapshot,
+ self.context, instance, name)
def test_instance_snapshot(self):
stubs.stubout_instance_snapshot(self.stubs)
instance = self._create_instance()
name = "MySnapshot"
- template_vm_ref = self.conn.snapshot(instance, name)
+ template_vm_ref = self.conn.snapshot(self.context, instance, name)
def ensure_vm_was_torn_down():
vm_labels = []
@@ -396,18 +402,22 @@ class XenAPIVMTestCase(test.TestCase):
def _test_spawn(self, image_ref, kernel_id, ramdisk_id,
instance_type_id="3", os_type="linux",
architecture="x86-64", instance_id=1,
- check_injection=False):
+ check_injection=False,
+ create_record=True, empty_dns=False):
stubs.stubout_loopingcall_start(self.stubs)
- values = {'id': instance_id,
- 'project_id': self.project.id,
- 'user_id': self.user.id,
- 'image_ref': image_ref,
- 'kernel_id': kernel_id,
- 'ramdisk_id': ramdisk_id,
- 'instance_type_id': instance_type_id,
- 'os_type': os_type,
- 'architecture': architecture}
- instance = db.instance_create(self.context, values)
+ if create_record:
+ values = {'id': instance_id,
+ 'project_id': self.project_id,
+ 'user_id': self.user_id,
+ 'image_ref': image_ref,
+ 'kernel_id': kernel_id,
+ 'ramdisk_id': ramdisk_id,
+ 'instance_type_id': instance_type_id,
+ 'os_type': os_type,
+ 'architecture': architecture}
+ instance = db.instance_create(self.context, values)
+ else:
+ instance = db.instance_get(self.context, instance_id)
network_info = [({'bridge': 'fa0', 'id': 0, 'injected': True},
{'broadcast': '192.168.0.255',
'dns': ['192.168.0.1'],
@@ -422,14 +432,23 @@ class XenAPIVMTestCase(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
- self.conn.spawn(instance, network_info)
+ if empty_dns:
+ network_info[0][1]['dns'] = []
+
+ self.conn.spawn(self.context, instance, network_info)
self.create_vm_record(self.conn, os_type, instance_id)
self.check_vm_record(self.conn, check_injection)
self.assertTrue(instance.os_type)
self.assertTrue(instance.architecture)
+ def test_spawn_empty_dns(self):
+ """"Test spawning with an empty dns list"""
+ self._test_spawn(glance_stubs.FakeGlance.IMAGE_VHD, None, None,
+ os_type="linux", architecture="x86-64",
+ empty_dns=True)
+ self.check_vm_params_for_linux()
+
def test_spawn_not_enough_memory(self):
- FLAGS.xenapi_image_service = 'glance'
self.assertRaises(Exception,
self._test_spawn,
1, 2, 3, "4") # m1.xlarge
@@ -441,7 +460,6 @@ class XenAPIVMTestCase(test.TestCase):
"""
vdi_recs_start = self._list_vdis()
- FLAGS.xenapi_image_service = 'glance'
stubs.stubout_fetch_image_glance_disk(self.stubs)
self.assertRaises(xenapi_fake.Failure,
self._test_spawn, 1, 2, 3)
@@ -456,7 +474,6 @@ class XenAPIVMTestCase(test.TestCase):
"""
vdi_recs_start = self._list_vdis()
- FLAGS.xenapi_image_service = 'glance'
stubs.stubout_create_vm(self.stubs)
self.assertRaises(xenapi_fake.Failure,
self._test_spawn, 1, 2, 3)
@@ -464,22 +481,12 @@ class XenAPIVMTestCase(test.TestCase):
vdi_recs_end = self._list_vdis()
self._check_vdis(vdi_recs_start, vdi_recs_end)
- def test_spawn_raw_objectstore(self):
- FLAGS.xenapi_image_service = 'objectstore'
- self._test_spawn(1, None, None)
-
- def test_spawn_objectstore(self):
- FLAGS.xenapi_image_service = 'objectstore'
- self._test_spawn(1, 2, 3)
-
@stub_vm_utils_with_vdi_attached_here
def test_spawn_raw_glance(self):
- FLAGS.xenapi_image_service = 'glance'
self._test_spawn(glance_stubs.FakeGlance.IMAGE_RAW, None, None)
self.check_vm_params_for_linux()
def test_spawn_vhd_glance_linux(self):
- FLAGS.xenapi_image_service = 'glance'
self._test_spawn(glance_stubs.FakeGlance.IMAGE_VHD, None, None,
os_type="linux", architecture="x86-64")
self.check_vm_params_for_linux()
@@ -508,20 +515,17 @@ class XenAPIVMTestCase(test.TestCase):
self.assertEqual(len(self.vm['VBDs']), 1)
def test_spawn_vhd_glance_windows(self):
- FLAGS.xenapi_image_service = 'glance'
self._test_spawn(glance_stubs.FakeGlance.IMAGE_VHD, None, None,
os_type="windows", architecture="i386")
self.check_vm_params_for_windows()
def test_spawn_glance(self):
- FLAGS.xenapi_image_service = 'glance'
self._test_spawn(glance_stubs.FakeGlance.IMAGE_MACHINE,
glance_stubs.FakeGlance.IMAGE_KERNEL,
glance_stubs.FakeGlance.IMAGE_RAMDISK)
self.check_vm_params_for_linux_with_external_kernel()
def test_spawn_netinject_file(self):
- FLAGS.xenapi_image_service = 'glance'
db_fakes.stub_out_db_instance_api(self.stubs, injected=True)
self._tee_executed = False
@@ -547,7 +551,6 @@ class XenAPIVMTestCase(test.TestCase):
# Capture the sudo tee .../etc/network/interfaces command
(r'(sudo\s+)?tee.*interfaces', _tee_handler),
])
- FLAGS.xenapi_image_service = 'glance'
self._test_spawn(glance_stubs.FakeGlance.IMAGE_MACHINE,
glance_stubs.FakeGlance.IMAGE_KERNEL,
glance_stubs.FakeGlance.IMAGE_RAMDISK,
@@ -555,7 +558,6 @@ class XenAPIVMTestCase(test.TestCase):
self.assertTrue(self._tee_executed)
def test_spawn_netinject_xenstore(self):
- FLAGS.xenapi_image_service = 'glance'
db_fakes.stub_out_db_instance_api(self.stubs, injected=True)
self._tee_executed = False
@@ -599,41 +601,38 @@ class XenAPIVMTestCase(test.TestCase):
# guest agent is detected
self.assertFalse(self._tee_executed)
- @test.skip_test("Never gets an address, not sure why")
def test_spawn_vlanmanager(self):
- self.flags(xenapi_image_service='glance',
+ self.flags(image_service='nova.image.glance.GlanceImageService',
network_manager='nova.network.manager.VlanManager',
- network_driver='nova.network.xenapi_net',
vlan_interface='fake0')
def dummy(*args, **kwargs):
pass
- self.stubs.Set(VMOps, 'create_vifs', dummy)
+ self.stubs.Set(vmops.VMOps, 'create_vifs', dummy)
# Reset network table
xenapi_fake.reset_table('network')
# Instance id = 2 will use vlan network (see db/fakes.py)
ctxt = self.context.elevated()
- instance_ref = self._create_instance(2)
- network_bk = self.network
- # Ensure we use xenapi_net driver
- self.network = utils.import_object(FLAGS.network_manager)
+ instance = self._create_instance(2, False)
networks = self.network.db.network_get_all(ctxt)
for network in networks:
- self.network.set_network_host(ctxt, network['id'])
-
- self.network.allocate_for_instance(ctxt, instance_id=instance_ref.id,
- instance_type_id=1, project_id=self.project.id)
- self.network.setup_compute_network(ctxt, instance_ref.id)
+ self.network.set_network_host(ctxt, network)
+
+ self.network.allocate_for_instance(ctxt,
+ instance_id=2,
+ host=FLAGS.host,
+ vpn=None,
+ instance_type_id=1,
+ project_id=self.project_id)
self._test_spawn(glance_stubs.FakeGlance.IMAGE_MACHINE,
glance_stubs.FakeGlance.IMAGE_KERNEL,
glance_stubs.FakeGlance.IMAGE_RAMDISK,
- instance_id=instance_ref.id,
+ instance_id=2,
create_record=False)
# TODO(salvatore-orlando): a complete test here would require
# a check for making sure the bridge for the VM's VIF is
# consistent with bridge specified in nova db
- self.network = network_bk
def test_spawn_with_network_qos(self):
self._create_instance()
@@ -644,10 +643,10 @@ class XenAPIVMTestCase(test.TestCase):
str(3 * 1024))
def test_rescue(self):
- self.flags(xenapi_inject_image=False)
+ self.flags(flat_injected=False)
instance = self._create_instance()
conn = xenapi_conn.get_connection(False)
- conn.rescue(instance, None)
+ conn.rescue(self.context, instance, None, [])
def test_unrescue(self):
instance = self._create_instance()
@@ -655,21 +654,13 @@ class XenAPIVMTestCase(test.TestCase):
# Ensure that it will not unrescue a non-rescued instance.
self.assertRaises(Exception, conn.unrescue, instance, None)
- def tearDown(self):
- super(XenAPIVMTestCase, self).tearDown()
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
- self.vm_info = None
- self.vm = None
- self.stubs.UnsetAll()
-
- def _create_instance(self, instance_id=1):
+ def _create_instance(self, instance_id=1, spawn=True):
"""Creates and spawns a test instance."""
stubs.stubout_loopingcall_start(self.stubs)
values = {
'id': instance_id,
- 'project_id': self.project.id,
- 'user_id': self.user.id,
+ 'project_id': self.project_id,
+ 'user_id': self.user_id,
'image_ref': 1,
'kernel_id': 2,
'ramdisk_id': 3,
@@ -691,7 +682,8 @@ class XenAPIVMTestCase(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
- self.conn.spawn(instance, network_info)
+ if spawn:
+ self.conn.spawn(self.context, instance, network_info)
return instance
@@ -743,21 +735,19 @@ class XenAPIMigrateInstance(test.TestCase):
def setUp(self):
super(XenAPIMigrateInstance, self).setUp()
self.stubs = stubout.StubOutForTesting()
- FLAGS.target_host = '127.0.0.1'
- FLAGS.xenapi_connection_url = 'test_url'
- FLAGS.xenapi_connection_password = 'test_pass'
+ self.flags(target_host='127.0.0.1',
+ xenapi_connection_url='test_url',
+ xenapi_connection_password='test_pass')
db_fakes.stub_out_db_instance_api(self.stubs)
stubs.stub_out_get_target(self.stubs)
xenapi_fake.reset()
xenapi_fake.create_network('fake', FLAGS.flat_network_bridge)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('fake', 'fake', 'fake',
- admin=True)
- self.project = self.manager.create_project('fake', 'fake', 'fake')
- self.context = context.RequestContext('fake', 'fake', False)
+ self.user_id = 'fake'
+ self.project_id = 'fake'
+ self.context = context.RequestContext(self.user_id, self.project_id)
self.values = {'id': 1,
- 'project_id': self.project.id,
- 'user_id': self.user.id,
+ 'project_id': self.project_id,
+ 'user_id': self.user_id,
'image_ref': 1,
'kernel_id': None,
'ramdisk_id': None,
@@ -771,20 +761,107 @@ class XenAPIMigrateInstance(test.TestCase):
stubs.stubout_get_this_vm_uuid(self.stubs)
glance_stubs.stubout_glance_client(self.stubs)
- def tearDown(self):
- super(XenAPIMigrateInstance, self).tearDown()
- self.manager.delete_project(self.project)
- self.manager.delete_user(self.user)
- self.stubs.UnsetAll()
-
def test_migrate_disk_and_power_off(self):
instance = db.instance_create(self.context, self.values)
stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests)
conn = xenapi_conn.get_connection(False)
conn.migrate_disk_and_power_off(instance, '127.0.0.1')
- def test_finish_resize(self):
+ def test_revert_migrate(self):
+ instance = db.instance_create(self.context, self.values)
+ self.called = False
+ self.fake_vm_start_called = False
+ self.fake_revert_migration_called = False
+
+ def fake_vm_start(*args, **kwargs):
+ self.fake_vm_start_called = True
+
+ def fake_vdi_resize(*args, **kwargs):
+ self.called = True
+
+ def fake_revert_migration(*args, **kwargs):
+ self.fake_revert_migration_called = True
+
+ self.stubs.Set(stubs.FakeSessionForMigrationTests,
+ "VDI_resize_online", fake_vdi_resize)
+ self.stubs.Set(vmops.VMOps, '_start', fake_vm_start)
+ self.stubs.Set(vmops.VMOps, 'revert_migration', fake_revert_migration)
+
+ stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests)
+ stubs.stubout_loopingcall_start(self.stubs)
+ conn = xenapi_conn.get_connection(False)
+ network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
+ {'broadcast': '192.168.0.255',
+ 'dns': ['192.168.0.1'],
+ 'gateway': '192.168.0.1',
+ 'gateway6': 'dead:beef::1',
+ 'ip6s': [{'enabled': '1',
+ 'ip': 'dead:beef::dcad:beff:feef:0',
+ 'netmask': '64'}],
+ 'ips': [{'enabled': '1',
+ 'ip': '192.168.0.100',
+ 'netmask': '255.255.255.0'}],
+ 'label': 'fake',
+ 'mac': 'DE:AD:BE:EF:00:00',
+ 'rxtx_cap': 3})]
+ conn.finish_migration(self.context, instance,
+ dict(base_copy='hurr', cow='durr'),
+ network_info, resize_instance=True)
+ self.assertEqual(self.called, True)
+ self.assertEqual(self.fake_vm_start_called, True)
+
+ conn.revert_migration(instance)
+ self.assertEqual(self.fake_revert_migration_called, True)
+
+ def test_finish_migrate(self):
+ instance = db.instance_create(self.context, self.values)
+ self.called = False
+ self.fake_vm_start_called = False
+
+ def fake_vm_start(*args, **kwargs):
+ self.fake_vm_start_called = True
+
+ def fake_vdi_resize(*args, **kwargs):
+ self.called = True
+
+ self.stubs.Set(stubs.FakeSessionForMigrationTests,
+ "VDI_resize_online", fake_vdi_resize)
+ self.stubs.Set(vmops.VMOps, '_start', fake_vm_start)
+
+ stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests)
+ stubs.stubout_loopingcall_start(self.stubs)
+ conn = xenapi_conn.get_connection(False)
+ network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
+ {'broadcast': '192.168.0.255',
+ 'dns': ['192.168.0.1'],
+ 'gateway': '192.168.0.1',
+ 'gateway6': 'dead:beef::1',
+ 'ip6s': [{'enabled': '1',
+ 'ip': 'dead:beef::dcad:beff:feef:0',
+ 'netmask': '64'}],
+ 'ips': [{'enabled': '1',
+ 'ip': '192.168.0.100',
+ 'netmask': '255.255.255.0'}],
+ 'label': 'fake',
+ 'mac': 'DE:AD:BE:EF:00:00',
+ 'rxtx_cap': 3})]
+ conn.finish_migration(self.context, instance,
+ dict(base_copy='hurr', cow='durr'),
+ network_info, resize_instance=True)
+ self.assertEqual(self.called, True)
+ self.assertEqual(self.fake_vm_start_called, True)
+
+ def test_finish_migrate_no_local_storage(self):
+ tiny_type_id = \
+ instance_types.get_instance_type_by_name('m1.tiny')['id']
+ self.values.update({'instance_type_id': tiny_type_id, 'local_gb': 0})
instance = db.instance_create(self.context, self.values)
+
+ def fake_vdi_resize(*args, **kwargs):
+ raise Exception("This shouldn't be called")
+
+ self.stubs.Set(stubs.FakeSessionForMigrationTests,
+ "VDI_resize_online", fake_vdi_resize)
stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests)
stubs.stubout_loopingcall_start(self.stubs)
conn = xenapi_conn.get_connection(False)
@@ -802,8 +879,56 @@ class XenAPIMigrateInstance(test.TestCase):
'label': 'fake',
'mac': 'DE:AD:BE:EF:00:00',
'rxtx_cap': 3})]
- conn.finish_resize(instance, dict(base_copy='hurr', cow='durr'),
- network_info)
+ conn.finish_migration(self.context, instance,
+ dict(base_copy='hurr', cow='durr'),
+ network_info, resize_instance=True)
+
+ def test_finish_migrate_no_resize_vdi(self):
+ instance = db.instance_create(self.context, self.values)
+
+ def fake_vdi_resize(*args, **kwargs):
+ raise Exception("This shouldn't be called")
+
+ self.stubs.Set(stubs.FakeSessionForMigrationTests,
+ "VDI_resize_online", fake_vdi_resize)
+ stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests)
+ stubs.stubout_loopingcall_start(self.stubs)
+ conn = xenapi_conn.get_connection(False)
+ network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False},
+ {'broadcast': '192.168.0.255',
+ 'dns': ['192.168.0.1'],
+ 'gateway': '192.168.0.1',
+ 'gateway6': 'dead:beef::1',
+ 'ip6s': [{'enabled': '1',
+ 'ip': 'dead:beef::dcad:beff:feef:0',
+ 'netmask': '64'}],
+ 'ips': [{'enabled': '1',
+ 'ip': '192.168.0.100',
+ 'netmask': '255.255.255.0'}],
+ 'label': 'fake',
+ 'mac': 'DE:AD:BE:EF:00:00',
+ 'rxtx_cap': 3})]
+
+ # Resize instance would be determined by the compute call
+ conn.finish_migration(self.context, instance,
+ dict(base_copy='hurr', cow='durr'),
+ network_info, resize_instance=False)
+
+
+class XenAPIImageTypeTestCase(test.TestCase):
+ """Test ImageType class."""
+
+ def test_to_string(self):
+ """Can convert from type id to type string."""
+ self.assertEquals(
+ vm_utils.ImageType.to_string(vm_utils.ImageType.KERNEL),
+ vm_utils.ImageType.KERNEL_STR)
+
+ def test_from_string(self):
+ """Can convert from string to type id."""
+ self.assertEquals(
+ vm_utils.ImageType.from_string(vm_utils.ImageType.KERNEL_STR),
+ vm_utils.ImageType.KERNEL)
class XenAPIDetermineDiskImageTestCase(test.TestCase):
@@ -827,7 +952,6 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
def test_instance_disk(self):
"""If a kernel is specified, the image type is DISK (aka machine)."""
- FLAGS.xenapi_image_service = 'objectstore'
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_MACHINE
self.fake_instance.kernel_id = glance_stubs.FakeGlance.IMAGE_KERNEL
self.assert_disk_type(vm_utils.ImageType.DISK)
@@ -837,7 +961,6 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
If the kernel isn't specified, and we're not using Glance, then
DISK_RAW is assumed.
"""
- FLAGS.xenapi_image_service = 'objectstore'
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_RAW
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_RAW)
@@ -847,7 +970,6 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
If we're using Glance, then defer to the image_type field, which in
this case will be 'raw'.
"""
- FLAGS.xenapi_image_service = 'glance'
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_RAW
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_RAW)
@@ -857,7 +979,6 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
If we're using Glance, then defer to the image_type field, which in
this case will be 'vhd'.
"""
- FLAGS.xenapi_image_service = 'glance'
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_VHD
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_VHD)
diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py
index d4eb87daf..afd672c7a 100644
--- a/nova/tests/vmwareapi/db_fakes.py
+++ b/nova/tests/vmwareapi/db_fakes.py
@@ -70,8 +70,8 @@ def stub_out_db_instance_api(stubs):
'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
'instance_type': values['instance_type'],
'memory_mb': type_data['memory_mb'],
- 'mac_address': values['mac_address'],
'vcpus': type_data['vcpus'],
+ 'mac_addresses': [{'address': values['mac_address']}],
'local_gb': type_data['local_gb'],
}
return FakeModel(base_options)
@@ -83,6 +83,8 @@ def stub_out_db_instance_api(stubs):
'bridge': 'vmnet0',
'netmask': '255.255.255.0',
'gateway': '10.10.10.1',
+ 'broadcast': '10.10.10.255',
+ 'dns1': 'fake',
'vlan': 100}
return FakeModel(fields)
@@ -90,7 +92,7 @@ def stub_out_db_instance_api(stubs):
"""Stubs out the db.instance_action_create method."""
pass
- def fake_instance_get_fixed_address(context, instance_id):
+ def fake_instance_get_fixed_addresses(context, instance_id):
"""Stubs out the db.instance_get_fixed_address method."""
return '10.10.10.10'
@@ -103,7 +105,7 @@ def stub_out_db_instance_api(stubs):
stubs.Set(db, 'instance_create', fake_instance_create)
stubs.Set(db, 'network_get_by_instance', fake_network_get_by_instance)
stubs.Set(db, 'instance_action_create', fake_instance_action_create)
- stubs.Set(db, 'instance_get_fixed_address',
- fake_instance_get_fixed_address)
+ stubs.Set(db, 'instance_get_fixed_addresses',
+ fake_instance_get_fixed_addresses)
stubs.Set(db, 'instance_type_get_all', fake_instance_type_get_all)
stubs.Set(db, 'instance_type_get_by_name', fake_instance_type_get_by_name)
diff --git a/nova/tests/vmwareapi/stubs.py b/nova/tests/vmwareapi/stubs.py
index a648efb16..0ed5e9b68 100644
--- a/nova/tests/vmwareapi/stubs.py
+++ b/nova/tests/vmwareapi/stubs.py
@@ -22,6 +22,8 @@ Stubouts for the test suite
from nova.virt import vmwareapi_conn
from nova.virt.vmwareapi import fake
from nova.virt.vmwareapi import vmware_images
+from nova.virt.vmwareapi import vmops
+from nova.virt.vmwareapi import network_utils
def fake_get_vim_object(arg):
@@ -36,11 +38,16 @@ def fake_is_vim_object(arg, module):
def set_stubs(stubs):
"""Set the stubs."""
+ stubs.Set(vmops.VMWareVMOps, 'plug_vifs', fake.fake_plug_vifs)
+ stubs.Set(network_utils, 'get_network_with_the_name',
+ fake.fake_get_network)
stubs.Set(vmware_images, 'fetch_image', fake.fake_fetch_image)
stubs.Set(vmware_images, 'get_vmdk_size_and_properties',
fake.fake_get_vmdk_size_and_properties)
stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image)
stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",
fake_get_vim_object)
+ stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object",
+ fake_get_vim_object)
stubs.Set(vmwareapi_conn.VMWareAPISession, "_is_vim_object",
fake_is_vim_object)
diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py
index 66c79d465..0d0f84e32 100644
--- a/nova/tests/xenapi/stubs.py
+++ b/nova/tests/xenapi/stubs.py
@@ -28,8 +28,8 @@ from nova import utils
def stubout_instance_snapshot(stubs):
@classmethod
- def fake_fetch_image(cls, session, instance_id, image, user, project,
- type):
+ def fake_fetch_image(cls, context, session, instance_id, image, user,
+ project, type):
from nova.virt.xenapi.fake import create_vdi
name_label = "instance-%s" % instance_id
#TODO: create fake SR record
@@ -227,7 +227,7 @@ def stub_out_vm_methods(stubs):
def fake_release_bootlock(self, vm):
pass
- def fake_spawn_rescue(self, inst):
+ def fake_spawn_rescue(self, context, inst, network_info):
inst._rescue = False
stubs.Set(vmops.VMOps, "_shutdown", fake_shutdown)
diff --git a/nova/twistd.py b/nova/twistd.py
deleted file mode 100644
index 15cf67825..000000000
--- a/nova/twistd.py
+++ /dev/null
@@ -1,267 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-Twisted daemon helpers, specifically to parse out gFlags from twisted flags,
-manage pid files and support syslogging.
-"""
-
-import gflags
-import os
-import signal
-import sys
-import time
-from twisted.scripts import twistd
-from twisted.python import log
-from twisted.python import reflect
-from twisted.python import runtime
-from twisted.python import usage
-
-from nova import flags
-from nova import log as logging
-
-
-if runtime.platformType == "win32":
- from twisted.scripts._twistw import ServerOptions
-else:
- from twisted.scripts._twistd_unix import ServerOptions
-
-
-FLAGS = flags.FLAGS
-
-
-class TwistdServerOptions(ServerOptions):
- def parseArgs(self, *args):
- return
-
-
-class FlagParser(object):
- # this is a required attribute for gflags
- syntactic_help = ''
-
- def __init__(self, parser):
- self.parser = parser
-
- def Parse(self, s):
- return self.parser(s)
-
-
-def WrapTwistedOptions(wrapped):
- class TwistedOptionsToFlags(wrapped):
- subCommands = None
-
- def __init__(self):
- # NOTE(termie): _data exists because Twisted stuff expects
- # to be able to set arbitrary things that are
- # not actual flags
- self._data = {}
- self._flagHandlers = {}
- self._paramHandlers = {}
-
- # Absorb the twistd flags into our FLAGS
- self._absorbFlags()
- self._absorbParameters()
- self._absorbHandlers()
-
- wrapped.__init__(self)
-
- def _absorbFlags(self):
- twistd_flags = []
- reflect.accumulateClassList(self.__class__, 'optFlags',
- twistd_flags)
- for flag in twistd_flags:
- key = flag[0].replace('-', '_')
- if hasattr(FLAGS, key):
- continue
- flags.DEFINE_boolean(key, None, str(flag[-1]))
-
- def _absorbParameters(self):
- twistd_params = []
- reflect.accumulateClassList(self.__class__, 'optParameters',
- twistd_params)
- for param in twistd_params:
- key = param[0].replace('-', '_')
- if hasattr(FLAGS, key):
- continue
- if len(param) > 4:
- flags.DEFINE(FlagParser(param[4]),
- key, param[2], str(param[3]),
- serializer=gflags.ArgumentSerializer())
- else:
- flags.DEFINE_string(key, param[2], str(param[3]))
-
- def _absorbHandlers(self):
- twistd_handlers = {}
- reflect.addMethodNamesToDict(self.__class__, twistd_handlers,
- "opt_")
-
- # NOTE(termie): Much of the following is derived/copied from
- # twisted.python.usage with the express purpose of
- # providing compatibility
- for name in twistd_handlers.keys():
- method = getattr(self, 'opt_' + name)
-
- takesArg = not usage.flagFunction(method, name)
- doc = getattr(method, '__doc__', None)
- if not doc:
- doc = 'undocumented'
-
- if not takesArg:
- if name not in FLAGS:
- flags.DEFINE_boolean(name, None, doc)
- self._flagHandlers[name] = method
- else:
- if name not in FLAGS:
- flags.DEFINE_string(name, None, doc)
- self._paramHandlers[name] = method
-
- def _doHandlers(self):
- for flag, handler in self._flagHandlers.iteritems():
- if self[flag]:
- handler()
- for param, handler in self._paramHandlers.iteritems():
- if self[param] is not None:
- handler(self[param])
-
- def __str__(self):
- return str(FLAGS)
-
- def parseOptions(self, options=None):
- if options is None:
- options = sys.argv
- else:
- options.insert(0, '')
-
- args = FLAGS(options)
- logging.setup()
- argv = args[1:]
- # ignore subcommands
-
- try:
- self.parseArgs(*argv)
- except TypeError:
- raise usage.UsageError(_("Wrong number of arguments."))
-
- self.postOptions()
- return args
-
- def parseArgs(self, *args):
- # TODO(termie): figure out a decent way of dealing with args
- #return
- wrapped.parseArgs(self, *args)
-
- def postOptions(self):
- self._doHandlers()
-
- wrapped.postOptions(self)
-
- def __getitem__(self, key):
- key = key.replace('-', '_')
- try:
- return getattr(FLAGS, key)
- except (AttributeError, KeyError):
- return self._data[key]
-
- def __setitem__(self, key, value):
- key = key.replace('-', '_')
- try:
- return setattr(FLAGS, key, value)
- except (AttributeError, KeyError):
- self._data[key] = value
-
- def get(self, key, default):
- key = key.replace('-', '_')
- try:
- return getattr(FLAGS, key)
- except (AttributeError, KeyError):
- self._data.get(key, default)
-
- return TwistedOptionsToFlags
-
-
-def stop(pidfile):
- """
- Stop the daemon
- """
- # Get the pid from the pidfile
- try:
- pf = file(pidfile, 'r')
- pid = int(pf.read().strip())
- pf.close()
- except IOError:
- pid = None
-
- if not pid:
- message = _("pidfile %s does not exist. Daemon not running?\n")
- sys.stderr.write(message % pidfile)
- # Not an error in a restart
- return
-
- # Try killing the daemon process
- try:
- while 1:
- os.kill(pid, signal.SIGKILL)
- time.sleep(0.1)
- except OSError, err:
- err = str(err)
- if err.find(_("No such process")) > 0:
- if os.path.exists(pidfile):
- os.remove(pidfile)
- else:
- print str(err)
- sys.exit(1)
-
-
-def serve(filename):
- logging.debug(_("Serving %s") % filename)
- name = os.path.basename(filename)
- OptionsClass = WrapTwistedOptions(TwistdServerOptions)
- options = OptionsClass()
- argv = options.parseOptions()
- FLAGS.python = filename
- FLAGS.no_save = True
- if not FLAGS.pidfile:
- FLAGS.pidfile = '%s.pid' % name
- elif FLAGS.pidfile.endswith('twistd.pid'):
- FLAGS.pidfile = FLAGS.pidfile.replace('twistd.pid', '%s.pid' % name)
- if not FLAGS.prefix:
- FLAGS.prefix = name
- elif FLAGS.prefix.endswith('twisted'):
- FLAGS.prefix = FLAGS.prefix.replace('twisted', name)
-
- action = 'start'
- if len(argv) > 1:
- action = argv.pop()
-
- if action == 'stop':
- stop(FLAGS.pidfile)
- sys.exit()
- elif action == 'restart':
- stop(FLAGS.pidfile)
- elif action == 'start':
- pass
- else:
- print 'usage: %s [options] [start|stop|restart]' % argv[0]
- sys.exit(1)
-
- logging.debug(_("Full set of FLAGS:"))
- for flag in FLAGS:
- logging.debug("%s : %s" % (flag, FLAGS.get(flag, None)))
-
- logging.audit(_("Starting %s"), name)
- twistd.runApp(options)
diff --git a/nova/utils.py b/nova/utils.py
index 8784a227d..1e2dbebb1 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -19,7 +19,6 @@
"""Utilities and helper functions."""
-import base64
import datetime
import functools
import inspect
@@ -30,7 +29,6 @@ import os
import random
import re
import socket
-import string
import struct
import sys
import time
@@ -50,7 +48,8 @@ from nova import version
LOG = logging.getLogger("nova.utils")
-TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
+ISO_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
+PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
FLAGS = flags.FLAGS
@@ -127,6 +126,22 @@ def fetchfile(url, target):
def execute(*cmd, **kwargs):
+ """
+ Helper method to execute command with optional retry.
+
+ :cmd Passed to subprocess.Popen.
+ :process_input Send to opened process.
+ :addl_env Added to the processes env.
+ :check_exit_code Defaults to 0. Raise exception.ProcessExecutionError
+ unless program exits with this code.
+ :delay_on_retry True | False. Defaults to True. If set to True, wait a
+ short amount of time before retrying.
+ :attempts How many times to retry cmd.
+
+ :raises exception.Error on receiving unknown arguments
+ :raises exception.ProcessExecutionError
+ """
+
process_input = kwargs.pop('process_input', None)
addl_env = kwargs.pop('addl_env', None)
check_exit_code = kwargs.pop('check_exit_code', 0)
@@ -361,16 +376,26 @@ def clear_time_override():
utcnow.override_time = None
-def isotime(at=None):
- """Returns iso formatted utcnow."""
+def strtime(at=None, fmt=PERFECT_TIME_FORMAT):
+ """Returns formatted utcnow."""
if not at:
at = utcnow()
- return at.strftime(TIME_FORMAT)
+ return at.strftime(fmt)
+
+
+def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT):
+ """Turn a formatted time back into a datetime."""
+ return datetime.datetime.strptime(timestr, fmt)
+
+
+def isotime(at=None):
+ """Returns iso formatted utcnow."""
+ return strtime(at, ISO_TIME_FORMAT)
def parse_isotime(timestr):
"""Turn an iso formatted time back into a datetime."""
- return datetime.datetime.strptime(timestr, TIME_FORMAT)
+ return parse_strtime(timestr, ISO_TIME_FORMAT)
def parse_mailmap(mailmap='.mailmap'):
@@ -504,25 +529,61 @@ def utf8(value):
return value
-def to_primitive(value):
- if type(value) is type([]) or type(value) is type((None,)):
- o = []
- for v in value:
- o.append(to_primitive(v))
- return o
- elif type(value) is type({}):
- o = {}
- for k, v in value.iteritems():
- o[k] = to_primitive(v)
- return o
- elif isinstance(value, datetime.datetime):
- return str(value)
- elif hasattr(value, 'iteritems'):
- return to_primitive(dict(value.iteritems()))
- elif hasattr(value, '__iter__'):
- return to_primitive(list(value))
- else:
- return value
+def to_primitive(value, convert_instances=False, level=0):
+ """Convert a complex object into primitives.
+
+ Handy for JSON serialization. We can optionally handle instances,
+ but since this is a recursive function, we could have cyclical
+ data structures.
+
+ To handle cyclical data structures we could track the actual objects
+ visited in a set, but not all objects are hashable. Instead we just
+ track the depth of the object inspections and don't go too deep.
+
+ Therefore, convert_instances=True is lossy ... be aware.
+
+ """
+ if inspect.isclass(value):
+ return unicode(value)
+
+ if level > 3:
+ return []
+
+ # The try block may not be necessary after the class check above,
+ # but just in case ...
+ try:
+ if type(value) is type([]) or type(value) is type((None,)):
+ o = []
+ for v in value:
+ o.append(to_primitive(v, convert_instances=convert_instances,
+ level=level))
+ return o
+ elif type(value) is type({}):
+ o = {}
+ for k, v in value.iteritems():
+ o[k] = to_primitive(v, convert_instances=convert_instances,
+ level=level)
+ return o
+ elif isinstance(value, datetime.datetime):
+ return str(value)
+ elif hasattr(value, 'iteritems'):
+ return to_primitive(dict(value.iteritems()),
+ convert_instances=convert_instances,
+ level=level)
+ elif hasattr(value, '__iter__'):
+ return to_primitive(list(value), level)
+ elif convert_instances and hasattr(value, '__dict__'):
+ # Likely an instance of something. Watch for cycles.
+ # Ignore class member vars.
+ return to_primitive(value.__dict__,
+ convert_instances=convert_instances,
+ level=level + 1)
+ else:
+ return value
+ except TypeError, e:
+ # Class objects are tricky since they may define something like
+ # __iter__ defined but it isn't callable as list().
+ return unicode(value)
def dumps(value):
@@ -745,7 +806,7 @@ def parse_server_string(server_str):
(address, port) = server_str.split(':')
return (address, port)
- except:
+ except Exception:
LOG.debug(_('Invalid server_string: %s' % server_str))
return ('', '')
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 178279d31..4f3cfefad 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -40,6 +40,7 @@ class ComputeDriver(object):
def init_host(self, host):
"""Adopt existing VM's running here"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def get_info(self, instance_name):
@@ -52,20 +53,24 @@ class ComputeDriver(object):
:num_cpu: (int) the number of virtual CPUs for the domain
:cpu_time: (int) the CPU time used in nanoseconds
"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def list_instances(self):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def list_instances_detail(self):
"""Return a list of InstanceInfo for all registered VMs"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def spawn(self, instance, network_info=None, block_device_mapping=None):
+ def spawn(self, context, instance, network_info,
+ block_device_mapping=None):
"""Launch a VM for the specified instance"""
raise NotImplementedError()
- def destroy(self, instance, cleanup=True):
+ def destroy(self, instance, network_info, cleanup=True):
"""Destroy (shutdown and delete) the specified instance.
The given parameter is an instance of nova.compute.service.Instance,
@@ -79,29 +84,36 @@ class ComputeDriver(object):
warning in that case.
"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""Reboot specified VM"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def snapshot_instance(self, context, instance_id, image_id):
raise NotImplementedError()
def get_console_pool_info(self, console_type):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def get_console_output(self, instance):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def get_ajax_console(self, instance):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def get_diagnostics(self, instance):
"""Return data about VM diagnostics"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def get_host_ip_addr(self):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def attach_volume(self, context, instance_id, volume_id, mountpoint):
@@ -116,42 +128,50 @@ class ComputeDriver(object):
def migrate_disk_and_power_off(self, instance, dest):
"""Transfers the VHD of a running instance to another host, then shuts
off the instance copies over the COW disk"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def snapshot(self, instance, image_id):
+ def snapshot(self, context, instance, image_id):
"""Create snapshot from a running VM instance."""
raise NotImplementedError()
- def finish_resize(self, instance, disk_info):
+ def finish_migration(self, context, instance, disk_info, network_info,
+ resize_instance):
"""Completes a resize, turning on the migrated instance"""
raise NotImplementedError()
- def revert_resize(self, instance):
+ def revert_migration(self, instance):
"""Reverts a resize, powering back on the instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def pause(self, instance, callback):
"""Pause VM instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def unpause(self, instance, callback):
"""Unpause paused VM instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def suspend(self, instance, callback):
"""suspend the specified instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def resume(self, instance, callback):
"""resume the specified instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def rescue(self, instance, callback):
+ def rescue(self, context, instance, callback, network_info):
"""Rescue the specified instance"""
raise NotImplementedError()
- def unrescue(self, instance, callback):
+ def unrescue(self, instance, callback, network_info):
"""Unrescue the specified instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def update_available_resource(self, ctxt, host):
@@ -164,6 +184,7 @@ class ComputeDriver(object):
:param host: hostname that compute manager is currently running
"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def live_migration(self, ctxt, instance_ref, dest,
@@ -183,20 +204,25 @@ class ComputeDriver(object):
expected nova.compute.manager.recover_live_migration.
"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def refresh_security_group_rules(self, security_group_id):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def refresh_security_group_members(self, security_group_id):
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def refresh_provider_fw_rules(self, security_group_id):
"""See: nova/virt/fake.py for docs."""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def reset_network(self, instance):
"""reset networking for specified instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
pass
def ensure_filtering_rules_for_instance(self, instance_ref):
@@ -222,10 +248,12 @@ class ComputeDriver(object):
:params instance_ref: nova.db.sqlalchemy.models.Instance object
"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def unfilter_instance(self, instance):
+ def unfilter_instance(self, instance, network_info):
"""Stop filtering instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def set_admin_password(self, context, instance_id, new_pass=None):
@@ -236,20 +264,30 @@ class ComputeDriver(object):
"""Create a file on the VM instance. The file path and contents
should be base64-encoded.
"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def agent_update(self, instance, url, md5hash):
"""Update agent on the VM instance."""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def inject_network_info(self, instance, nw_info):
"""inject network info for specified instance"""
+ # TODO(Vek): Need to pass context in for access to auth_token
pass
def poll_rescued_instances(self, timeout):
"""Poll for rescued instances"""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
def set_host_enabled(self, host, enabled):
"""Sets the specified host's ability to accept new instances."""
+ # TODO(Vek): Need to pass context in for access to auth_token
+ raise NotImplementedError()
+
+ def plug_vifs(self, instance, network_info):
+ """Plugs in VIFs to networks."""
+ # TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index ea0a59f21..80abcc644 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -129,7 +129,8 @@ class FakeConnection(driver.ComputeDriver):
info_list.append(self._map_to_instance_info(instance))
return info_list
- def spawn(self, instance, network_info, block_device_mapping=None):
+ def spawn(self, context, instance, network_info,
+ block_device_mapping=None):
"""
Create a new instance/VM/domain on the virtualization platform.
@@ -153,7 +154,7 @@ class FakeConnection(driver.ComputeDriver):
fake_instance = FakeInstance(name, state)
self.instances[name] = fake_instance
- def snapshot(self, instance, name):
+ def snapshot(self, context, instance, name):
"""
Snapshots the specified instance.
@@ -167,7 +168,7 @@ class FakeConnection(driver.ComputeDriver):
"""
pass
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""
Reboot the specified instance.
@@ -240,13 +241,13 @@ class FakeConnection(driver.ComputeDriver):
"""
pass
- def rescue(self, instance):
+ def rescue(self, context, instance, callback, network_info):
"""
Rescue the specified instance.
"""
pass
- def unrescue(self, instance):
+ def unrescue(self, instance, callback, network_info):
"""
Unrescue the specified instance.
"""
@@ -293,7 +294,7 @@ class FakeConnection(driver.ComputeDriver):
"""
pass
- def destroy(self, instance):
+ def destroy(self, instance, network_info):
key = instance.name
if key in self.instances:
del self.instances[key]
@@ -340,8 +341,7 @@ class FakeConnection(driver.ComputeDriver):
only useful for giving back to this layer as a parameter to
disk_stats). These IDs only need to be unique for a given instance.
- Note that this function takes an instance ID, not a
- compute.service.Instance, so that it can be called by compute.monitor.
+ Note that this function takes an instance ID.
"""
return ['A_DISK']
@@ -353,8 +353,7 @@ class FakeConnection(driver.ComputeDriver):
interface_stats). These IDs only need to be unique for a given
instance.
- Note that this function takes an instance ID, not a
- compute.service.Instance, so that it can be called by compute.monitor.
+ Note that this function takes an instance ID.
"""
return ['A_VIF']
@@ -374,8 +373,7 @@ class FakeConnection(driver.ComputeDriver):
having to do the aggregation. On those platforms, this method is
unused.
- Note that this function takes an instance ID, not a
- compute.service.Instance, so that it can be called by compute.monitor.
+ Note that this function takes an instance ID.
"""
return [0L, 0L, 0L, 0L, None]
@@ -395,8 +393,7 @@ class FakeConnection(driver.ComputeDriver):
having to do the aggregation. On those platforms, this method is
unused.
- Note that this function takes an instance ID, not a
- compute.service.Instance, so that it can be called by compute.monitor.
+ Note that this function takes an instance ID.
"""
return [0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L]
@@ -499,7 +496,7 @@ class FakeConnection(driver.ComputeDriver):
"""This method is supported only by libvirt."""
return
- def unfilter_instance(self, instance_ref):
+ def unfilter_instance(self, instance_ref, network_info=None):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 5c1dc772d..3428a7fc1 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -66,7 +66,6 @@ import time
from nova import exception
from nova import flags
from nova import log as logging
-from nova.auth import manager
from nova.compute import power_state
from nova.virt import driver
from nova.virt import images
@@ -139,19 +138,19 @@ class HyperVConnection(driver.ComputeDriver):
return instance_infos
- def spawn(self, instance, network_info=None, block_device_mapping=None):
+ def spawn(self, context, instance, network_info,
+ block_device_mapping=None):
""" Create a new VM and start it."""
vm = self._lookup(instance.name)
if vm is not None:
raise exception.InstanceExists(name=instance.name)
- user = manager.AuthManager().get_user(instance['user_id'])
- project = manager.AuthManager().get_project(instance['project_id'])
#Fetch the file, assume it is a VHD file.
base_vhd_filename = os.path.join(FLAGS.instances_path,
instance.name)
vhdfile = "%s.vhd" % (base_vhd_filename)
- images.fetch(instance['image_ref'], vhdfile, user, project)
+ images.fetch(instance['image_ref'], vhdfile,
+ instance['user_id'], instance['project_id'])
try:
self._create_vm(instance)
@@ -368,14 +367,14 @@ class HyperVConnection(driver.ComputeDriver):
wmi_obj.Properties_.Item(prop).Value
return newinst
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""Reboot the specified instance."""
vm = self._lookup(instance.name)
if vm is None:
raise exception.InstanceNotFound(instance_id=instance.id)
self._set_vm_state(instance.name, 'Reboot')
- def destroy(self, instance):
+ def destroy(self, instance, network_info):
"""Destroy the VM. Also destroy the associated VHD disk files"""
LOG.debug(_("Got request to destroy vm %s"), instance.name)
vm = self._lookup(instance.name)
diff --git a/nova/virt/images.py b/nova/virt/images.py
index 40bf6107c..54c691a40 100644
--- a/nova/virt/images.py
+++ b/nova/virt/images.py
@@ -21,7 +21,6 @@
Handling of VM disk images.
"""
-from nova import context
from nova import flags
from nova.image import glance as glance_image_service
import nova.image
@@ -33,13 +32,12 @@ FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.virt.images')
-def fetch(image_href, path, _user, _project):
+def fetch(context, image_href, path, _user_id, _project_id):
# TODO(vish): Improve context handling and add owner and auth data
# when it is added to glance. Right now there is no
# auth checking in glance, so we assume that access was
# checked before we got here.
(image_service, image_id) = nova.image.get_image_service(image_href)
with open(path, "wb") as image_file:
- elevated = context.get_admin_context()
- metadata = image_service.get(elevated, image_id, image_file)
+ metadata = image_service.get(context, image_id, image_file)
return metadata
diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template
index e1a683da8..a75636390 100644
--- a/nova/virt/libvirt.xml.template
+++ b/nova/virt/libvirt.xml.template
@@ -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
@@ -92,6 +96,22 @@
#end if
#for $nic in $nics
+ #if $vif_type == 'ethernet'
+ <interface type='ethernet'>
+ <target dev='${nic.name}' />
+ <mac address='${nic.mac_address}' />
+ <script path='${nic.script}' />
+ </interface>
+ #else if $vif_type == '802.1Qbh'
+ <interface type='direct'>
+ <mac address='${nic.mac_address}'/>
+ <source dev='${nic.device_name}' mode='private'/>
+ <virtualport type='802.1Qbh'>
+ <parameters profileid='${nic.profile_name}'/>
+ </virtualport>
+ <model type='virtio'/>
+ </interface>
+ #else
<interface type='bridge'>
<source bridge='${nic.bridge_name}'/>
<mac address='${nic.mac_address}'/>
@@ -107,6 +127,8 @@
#end if
</filterref>
</interface>
+ #end if
+
#end for
<!-- The order is significant here. File must be defined first -->
<serial type="file">
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 977bb7dfe..d4160b280 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -54,7 +54,7 @@ from xml.etree import ElementTree
from eventlet import greenthread
from eventlet import tpool
-from nova import context
+from nova import context as nova_context
from nova import db
from nova import exception
from nova import flags
@@ -121,8 +121,11 @@ flags.DEFINE_integer('live_migration_bandwidth', 0,
'Define live migration behavior')
flags.DEFINE_string('qemu_img', 'qemu-img',
'binary to use for qemu-img commands')
-flags.DEFINE_bool('start_guests_on_host_boot', False,
- 'Whether to restart guests when the host reboots')
+flags.DEFINE_string('libvirt_vif_type', 'bridge',
+ 'Type of VIF to create.')
+flags.DEFINE_string('libvirt_vif_driver',
+ 'nova.virt.libvirt.vif.LibvirtBridgeDriver',
+ 'The libvirt VIF driver to configure the VIFs.')
def get_connection(read_only):
@@ -165,29 +168,11 @@ class LibvirtConnection(driver.ComputeDriver):
fw_class = utils.import_class(FLAGS.firewall_driver)
self.firewall_driver = fw_class(get_connection=self._get_connection)
+ self.vif_driver = utils.import_object(FLAGS.libvirt_vif_driver)
def init_host(self, host):
- # Adopt existing VM's running here
- ctxt = context.get_admin_context()
- for instance in db.instance_get_all_by_host(ctxt, host):
- try:
- LOG.debug(_('Checking state of %s'), instance['name'])
- state = self.get_info(instance['name'])['state']
- except exception.NotFound:
- state = power_state.SHUTOFF
-
- LOG.debug(_('Current state of %(name)s was %(state)s.'),
- {'name': instance['name'], 'state': state})
- db.instance_set_state(ctxt, instance['id'], state)
-
- # NOTE(justinsb): We no longer delete SHUTOFF instances,
- # the user may want to power them back on
-
- if state != power_state.RUNNING:
- continue
- self.firewall_driver.setup_basic_filtering(instance)
- self.firewall_driver.prepare_instance_filter(instance)
- self.firewall_driver.apply_instance_filter(instance)
+ # NOTE(nsokolov): moved instance restarting to ComputeManager
+ pass
def _get_connection(self):
if not self._wrapped_conn or not self._test_connection():
@@ -256,7 +241,12 @@ class LibvirtConnection(driver.ComputeDriver):
infos.append(info)
return infos
- def destroy(self, instance, cleanup=True):
+ def plug_vifs(self, instance, network_info):
+ """Plugin VIFs into networks."""
+ for (network, mapping) in network_info:
+ self.vif_driver.plug(instance, network, mapping)
+
+ def destroy(self, instance, network_info, cleanup=True):
instance_name = instance['name']
try:
@@ -300,6 +290,9 @@ class LibvirtConnection(driver.ComputeDriver):
locals())
raise
+ for (network, mapping) in network_info:
+ self.vif_driver.unplug(instance, network, mapping)
+
def _wait_for_destroy():
"""Called at an interval until the VM is gone."""
instance_name = instance['name']
@@ -314,7 +307,8 @@ class LibvirtConnection(driver.ComputeDriver):
timer = utils.LoopingCall(_wait_for_destroy)
timer.start(interval=0.5, now=True)
- self.firewall_driver.unfilter_instance(instance)
+ self.firewall_driver.unfilter_instance(instance,
+ network_info=network_info)
if cleanup:
self._cleanup(instance)
@@ -335,31 +329,27 @@ 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(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)
- else:
- raise exception.InvalidDevicePath(path=device_path)
-
+ </disk>""" % (protocol, name, mount_device)
virt_dom.attachDevice(xml)
def _get_disk_xml(self, xml, device):
"""Returns the xml for the disk mounted at device"""
try:
doc = libxml2.parseDoc(xml)
- except:
+ except Exception:
return None
ctx = doc.xpathNewContext()
try:
@@ -385,7 +375,7 @@ class LibvirtConnection(driver.ComputeDriver):
virt_dom.detachDevice(xml)
@exception.wrap_exception()
- def snapshot(self, instance, image_href):
+ def snapshot(self, context, instance, image_href):
"""Create snapshot from a running VM instance.
This command only works with qemu 0.14+, the qemu_img flag is
@@ -394,18 +384,15 @@ class LibvirtConnection(driver.ComputeDriver):
"""
virt_dom = self._lookup_by_name(instance['name'])
- elevated = context.get_admin_context()
(image_service, image_id) = nova.image.get_image_service(
instance['image_ref'])
- base = image_service.show(elevated, image_id)
+ base = image_service.show(context, image_id)
(snapshot_image_service, snapshot_image_id) = \
nova.image.get_image_service(image_href)
- snapshot = snapshot_image_service.show(elevated, snapshot_image_id)
+ snapshot = snapshot_image_service.show(context, snapshot_image_id)
- metadata = {'disk_format': base['disk_format'],
- 'container_format': base['container_format'],
- 'is_public': False,
+ metadata = {'is_public': False,
'status': 'active',
'name': snapshot['name'],
'properties': {
@@ -420,6 +407,12 @@ class LibvirtConnection(driver.ComputeDriver):
arch = base['properties']['architecture']
metadata['properties']['architecture'] = arch
+ if 'disk_format' in base:
+ metadata['disk_format'] = base['disk_format']
+
+ if 'container_format' in base:
+ metadata['container_format'] = base['container_format']
+
# Make the snapshot
snapshot_name = uuid.uuid4().hex
snapshot_xml = """
@@ -452,7 +445,7 @@ class LibvirtConnection(driver.ComputeDriver):
# Upload that image to the image service
with open(out_path) as image_file:
- image_service.update(elevated,
+ image_service.update(context,
image_href,
metadata,
image_file)
@@ -461,7 +454,7 @@ class LibvirtConnection(driver.ComputeDriver):
shutil.rmtree(temp_dir)
@exception.wrap_exception()
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""Reboot a virtual machine, given an instance reference.
This method actually destroys and re-creates the domain to ensure the
@@ -476,7 +469,8 @@ class LibvirtConnection(driver.ComputeDriver):
# NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is
# better because we cannot ensure flushing dirty buffers
# in the guest OS. But, in case of KVM, shutdown() does not work...
- self.destroy(instance, False)
+ self.destroy(instance, network_info, cleanup=False)
+ self.plug_vifs(instance, network_info)
self.firewall_driver.setup_basic_filtering(instance)
self.firewall_driver.prepare_instance_filter(instance)
self._create_new_domain(xml)
@@ -526,7 +520,7 @@ class LibvirtConnection(driver.ComputeDriver):
dom.create()
@exception.wrap_exception()
- def rescue(self, instance):
+ def rescue(self, context, instance, callback, network_info):
"""Loads a VM using rescue images.
A rescue is normally performed when something goes wrong with the
@@ -535,13 +529,13 @@ class LibvirtConnection(driver.ComputeDriver):
data recovery.
"""
- self.destroy(instance, False)
+ self.destroy(instance, network_info, cleanup=False)
xml = self.to_xml(instance, rescue=True)
rescue_images = {'image_id': FLAGS.rescue_image_id,
'kernel_id': FLAGS.rescue_kernel_id,
'ramdisk_id': FLAGS.rescue_ramdisk_id}
- self._create_image(instance, xml, '.rescue', rescue_images)
+ self._create_image(context, instance, xml, '.rescue', rescue_images)
self._create_new_domain(xml)
def _wait_for_rescue():
@@ -564,14 +558,14 @@ class LibvirtConnection(driver.ComputeDriver):
return timer.start(interval=0.5, now=True)
@exception.wrap_exception()
- def unrescue(self, instance):
+ def unrescue(self, instance, network_info):
"""Reboot the VM which is being rescued back into primary images.
Because reboot destroys and re-creates instances, unresue should
simply call reboot.
"""
- self.reboot(instance)
+ self.reboot(instance, network_info)
@exception.wrap_exception()
def poll_rescued_instances(self, timeout):
@@ -580,23 +574,19 @@ class LibvirtConnection(driver.ComputeDriver):
# NOTE(ilyaalekseyev): Implementation like in multinics
# for xenapi(tr3buchet)
@exception.wrap_exception()
- def spawn(self, instance, network_info=None, block_device_mapping=None):
+ def spawn(self, context, instance, network_info,
+ block_device_mapping=None):
xml = self.to_xml(instance, False, network_info=network_info,
block_device_mapping=block_device_mapping)
block_device_mapping = block_device_mapping or []
self.firewall_driver.setup_basic_filtering(instance, network_info)
self.firewall_driver.prepare_instance_filter(instance, network_info)
- self._create_image(instance, xml, network_info=network_info,
+ self._create_image(context, instance, xml, network_info=network_info,
block_device_mapping=block_device_mapping)
domain = self._create_new_domain(xml)
LOG.debug(_("instance %s: is running"), instance['name'])
self.firewall_driver.apply_instance_filter(instance)
- if FLAGS.start_guests_on_host_boot:
- LOG.debug(_("instance %s: setting autostart ON") %
- instance['name'])
- domain.setAutostart(1)
-
def _wait_for_boot():
"""Called at an interval until the VM is running."""
instance_name = instance['name']
@@ -757,9 +747,10 @@ class LibvirtConnection(driver.ComputeDriver):
else:
utils.execute('cp', base, target)
- def _fetch_image(self, target, image_id, user, project, size=None):
+ def _fetch_image(self, context, target, image_id, user_id, project_id,
+ size=None):
"""Grab image and optionally attempt to resize it"""
- images.fetch(image_id, target, user, project)
+ images.fetch(context, image_id, target, user_id, project_id)
if size:
disk.extend(target, size)
@@ -768,8 +759,9 @@ class LibvirtConnection(driver.ComputeDriver):
utils.execute('truncate', target, '-s', "%dG" % local_gb)
# TODO(vish): should we format disk by default?
- def _create_image(self, inst, libvirt_xml, suffix='', disk_images=None,
- network_info=None, block_device_mapping=None):
+ def _create_image(self, context, inst, libvirt_xml, suffix='',
+ disk_images=None, network_info=None,
+ block_device_mapping=None):
block_device_mapping = block_device_mapping or []
if not suffix:
@@ -797,9 +789,6 @@ class LibvirtConnection(driver.ComputeDriver):
os.close(os.open(basepath('console.log', ''),
os.O_CREAT | os.O_WRONLY, 0660))
- user = manager.AuthManager().get_user(inst['user_id'])
- project = manager.AuthManager().get_project(inst['project_id'])
-
if not disk_images:
disk_images = {'image_id': inst['image_ref'],
'kernel_id': inst['kernel_id'],
@@ -808,19 +797,21 @@ class LibvirtConnection(driver.ComputeDriver):
if disk_images['kernel_id']:
fname = '%08x' % int(disk_images['kernel_id'])
self._cache_image(fn=self._fetch_image,
+ context=context,
target=basepath('kernel'),
fname=fname,
image_id=disk_images['kernel_id'],
- user=user,
- project=project)
+ user_id=inst['user_id'],
+ project_id=inst['project_id'])
if disk_images['ramdisk_id']:
fname = '%08x' % int(disk_images['ramdisk_id'])
self._cache_image(fn=self._fetch_image,
+ context=context,
target=basepath('ramdisk'),
fname=fname,
image_id=disk_images['ramdisk_id'],
- user=user,
- project=project)
+ user_id=inst['user_id'],
+ project_id=inst['project_id'])
root_fname = hashlib.sha1(disk_images['image_id']).hexdigest()
size = FLAGS.minimum_root_size
@@ -834,12 +825,13 @@ class LibvirtConnection(driver.ComputeDriver):
if not self._volume_in_mapping(self.root_mount_device,
block_device_mapping):
self._cache_image(fn=self._fetch_image,
+ context=context,
target=basepath('disk'),
fname=root_fname,
cow=FLAGS.use_cow_images,
image_id=disk_images['image_id'],
- user=user,
- project=project,
+ user_id=inst['user_id'],
+ project_id=inst['project_id'],
size=size)
if inst_type['local_gb'] and not self._volume_in_mapping(
@@ -870,7 +862,7 @@ class LibvirtConnection(driver.ComputeDriver):
ifc_template = open(FLAGS.injected_network_template).read()
ifc_num = -1
have_injected_networks = False
- admin_context = context.get_admin_context()
+ admin_context = nova_context.get_admin_context()
for (network_ref, mapping) in network_info:
ifc_num += 1
@@ -881,17 +873,20 @@ class LibvirtConnection(driver.ComputeDriver):
address = mapping['ips'][0]['ip']
netmask = mapping['ips'][0]['netmask']
address_v6 = None
+ gateway_v6 = None
+ netmask_v6 = None
if FLAGS.use_ipv6:
address_v6 = mapping['ip6s'][0]['ip']
netmask_v6 = mapping['ip6s'][0]['netmask']
+ gateway_v6 = mapping['gateway6']
net_info = {'name': 'eth%d' % ifc_num,
'address': address,
'netmask': netmask,
'gateway': mapping['gateway'],
'broadcast': mapping['broadcast'],
- 'dns': mapping['dns'],
+ 'dns': ' '.join(mapping['dns']),
'address_v6': address_v6,
- 'gateway6': mapping['gateway6'],
+ 'gateway6': gateway_v6,
'netmask_v6': netmask_v6}
nets.append(net_info)
@@ -926,40 +921,6 @@ class LibvirtConnection(driver.ComputeDriver):
if FLAGS.libvirt_type == 'uml':
utils.execute('sudo', 'chown', 'root', basepath('disk'))
- def _get_nic_for_xml(self, network, mapping):
- # Assume that the gateway also acts as the dhcp server.
- dhcp_server = mapping['gateway']
- gateway6 = mapping.get('gateway6')
- mac_id = mapping['mac'].replace(':', '')
-
- if FLAGS.allow_project_net_traffic:
- template = "<parameter name=\"%s\"value=\"%s\" />\n"
- net, mask = netutils.get_net_and_mask(network['cidr'])
- values = [("PROJNET", net), ("PROJMASK", mask)]
- if FLAGS.use_ipv6:
- net_v6, prefixlen_v6 = netutils.get_net_and_prefixlen(
- network['cidr_v6'])
- values.extend([("PROJNETV6", net_v6),
- ("PROJMASKV6", prefixlen_v6)])
-
- extra_params = "".join([template % value for value in values])
- else:
- extra_params = "\n"
-
- result = {
- 'id': mac_id,
- 'bridge_name': network['bridge'],
- 'mac_address': mapping['mac'],
- 'ip_address': mapping['ips'][0]['ip'],
- 'dhcp_server': dhcp_server,
- 'extra_params': extra_params,
- }
-
- if gateway6:
- result['gateway6'] = gateway6 + "/128"
-
- return result
-
root_mount_device = 'vda' # FIXME for now. it's hard coded.
local_mount_device = 'vdb' # FIXME for now. it's hard coded.
@@ -971,6 +932,15 @@ class LibvirtConnection(driver.ComputeDriver):
return True
return False
+ 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 []
@@ -981,7 +951,7 @@ class LibvirtConnection(driver.ComputeDriver):
nics = []
for (network, mapping) in network_info:
- nics.append(self._get_nic_for_xml(network, mapping))
+ nics.append(self.vif_driver.plug(instance, network, mapping))
# FIXME(vish): stick this in db
inst_type_id = instance['instance_type_id']
inst_type = instance_types.get_instance_type(inst_type_id)
@@ -993,6 +963,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,
@@ -1010,14 +983,14 @@ class LibvirtConnection(driver.ComputeDriver):
'rescue': rescue,
'local': local_gb,
'driver_type': driver_type,
+ 'vif_type': FLAGS.libvirt_vif_type,
'nics': nics,
'ebs_root': ebs_root,
'volumes': block_device_mapping}
- if FLAGS.vnc_enabled:
- if FLAGS.libvirt_type != 'lxc' or FLAGS.libvirt_type != 'uml':
- xml_info['vncserver_host'] = FLAGS.vncserver_host
- xml_info['vnc_keymap'] = FLAGS.vnc_keymap
+ if FLAGS.vnc_enabled and FLAGS.libvirt_type not in ('lxc', 'uml'):
+ xml_info['vncserver_host'] = FLAGS.vncserver_host
+ xml_info['vnc_keymap'] = FLAGS.vnc_keymap
if not rescue:
if instance['kernel_id']:
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
@@ -1097,8 +1070,7 @@ class LibvirtConnection(driver.ComputeDriver):
def get_disks(self, instance_name):
"""
- Note that this function takes an instance name, not an Instance, so
- that it can be called by monitor.
+ Note that this function takes an instance name.
Returns a list of all block devices for this domain.
"""
@@ -1109,7 +1081,7 @@ class LibvirtConnection(driver.ComputeDriver):
try:
doc = libxml2.parseDoc(xml)
- except:
+ except Exception:
return []
ctx = doc.xpathNewContext()
@@ -1139,8 +1111,7 @@ class LibvirtConnection(driver.ComputeDriver):
def get_interfaces(self, instance_name):
"""
- Note that this function takes an instance name, not an Instance, so
- that it can be called by monitor.
+ Note that this function takes an instance name.
Returns a list of all network interfaces for this instance.
"""
@@ -1151,7 +1122,7 @@ class LibvirtConnection(driver.ComputeDriver):
try:
doc = libxml2.parseDoc(xml)
- except:
+ except Exception:
return []
ctx = doc.xpathNewContext()
@@ -1355,16 +1326,14 @@ class LibvirtConnection(driver.ComputeDriver):
def block_stats(self, instance_name, disk):
"""
- Note that this function takes an instance name, not an Instance, so
- that it can be called by monitor.
+ Note that this function takes an instance name.
"""
domain = self._lookup_by_name(instance_name)
return domain.blockStats(disk)
def interface_stats(self, instance_name, interface):
"""
- Note that this function takes an instance name, not an Instance, so
- that it can be called by monitor.
+ Note that this function takes an instance name.
"""
domain = self._lookup_by_name(instance_name)
return domain.interfaceStats(interface)
@@ -1580,9 +1549,10 @@ class LibvirtConnection(driver.ComputeDriver):
timer.f = wait_for_live_migration
timer.start(interval=0.5, now=True)
- def unfilter_instance(self, instance_ref):
+ def unfilter_instance(self, instance_ref, network_info):
"""See comments of same method in firewall_driver."""
- self.firewall_driver.unfilter_instance(instance_ref)
+ self.firewall_driver.unfilter_instance(instance_ref,
+ network_info=network_info)
def update_host_status(self):
"""See xenapi_conn.py implementation."""
diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py
index 379197398..9ce57b6c9 100644
--- a/nova/virt/libvirt/firewall.py
+++ b/nova/virt/libvirt/firewall.py
@@ -46,7 +46,7 @@ class FirewallDriver(object):
At this point, the instance isn't running yet."""
raise NotImplementedError()
- def unfilter_instance(self, instance):
+ def unfilter_instance(self, instance, network_info=None):
"""Stop filtering instance"""
raise NotImplementedError()
@@ -300,9 +300,10 @@ class NWFilterFirewall(FirewallDriver):
# execute in a native thread and block current greenthread until done
tpool.execute(self._conn.nwfilterDefineXML, xml)
- def unfilter_instance(self, instance):
+ def unfilter_instance(self, instance, network_info=None):
"""Clear out the nwfilter rules."""
- network_info = netutils.get_network_info(instance)
+ if not network_info:
+ network_info = netutils.get_network_info(instance)
instance_name = instance.name
for (network, mapping) in network_info:
nic_id = mapping['mac'].replace(':', '')
@@ -542,11 +543,11 @@ class IptablesFirewallDriver(FirewallDriver):
"""No-op. Everything is done in prepare_instance_filter"""
pass
- def unfilter_instance(self, instance):
+ def unfilter_instance(self, instance, network_info=None):
if self.instances.pop(instance['id'], None):
self.remove_filters_for_instance(instance)
self.iptables.apply()
- self.nwfilter.unfilter_instance(instance)
+ self.nwfilter.unfilter_instance(instance, network_info)
else:
LOG.info(_('Attempted to unfilter instance %s which is not '
'filtered'), instance['id'])
diff --git a/nova/virt/libvirt/netutils.py b/nova/virt/libvirt/netutils.py
index e5aaf7cec..a8e88fc07 100644
--- a/nova/virt/libvirt/netutils.py
+++ b/nova/virt/libvirt/netutils.py
@@ -25,6 +25,7 @@ import netaddr
from nova import context
from nova import db
+from nova import exception
from nova import flags
from nova import ipv6
from nova import utils
@@ -55,11 +56,13 @@ def get_network_info(instance):
# we should cache network_info
admin_context = context.get_admin_context()
- fixed_ips = db.fixed_ip_get_by_instance(admin_context, instance['id'])
+ try:
+ fixed_ips = db.fixed_ip_get_by_instance(admin_context, instance['id'])
+ except exception.FixedIpNotFoundForInstance:
+ fixed_ips = []
+
vifs = db.virtual_interface_get_by_instance(admin_context, instance['id'])
- networks = db.network_get_all_by_instance(admin_context,
- instance['id'])
- flavor = db.instance_type_get_by_id(admin_context,
+ flavor = db.instance_type_get(admin_context,
instance['instance_type_id'])
network_info = []
@@ -89,11 +92,17 @@ def get_network_info(instance):
'label': network['label'],
'gateway': network['gateway'],
'broadcast': network['broadcast'],
+ 'dhcp_server': network['gateway'],
'mac': vif['address'],
'rxtx_cap': flavor['rxtx_cap'],
- 'dns': [network['dns']],
+ 'dns': [],
'ips': [ip_dict(ip) for ip in network_ips]}
+ if network['dns1']:
+ mapping['dns'].append(network['dns1'])
+ if network['dns2']:
+ mapping['dns'].append(network['dns2'])
+
if FLAGS.use_ipv6:
mapping['ip6s'] = [ip6_dict()]
mapping['gateway6'] = network['gateway_v6']
diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py
new file mode 100644
index 000000000..711b05bae
--- /dev/null
+++ b/nova/virt/libvirt/vif.py
@@ -0,0 +1,135 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (C) 2011 Midokura KK
+# Copyright (C) 2011 Nicira, Inc
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""VIF drivers for libvirt."""
+
+from nova import flags
+from nova import log as logging
+from nova.network import linux_net
+from nova.virt.libvirt import netutils
+from nova import utils
+from nova.virt.vif import VIFDriver
+from nova import exception
+
+LOG = logging.getLogger('nova.virt.libvirt.vif')
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_string('libvirt_ovs_bridge', 'br-int',
+ 'Name of Integration Bridge used by Open vSwitch')
+
+
+class LibvirtBridgeDriver(VIFDriver):
+ """VIF driver for Linux bridge."""
+
+ def _get_configurations(self, network, mapping):
+ """Get a dictionary of VIF configurations for bridge type."""
+ # Assume that the gateway also acts as the dhcp server.
+ gateway6 = mapping.get('gateway6')
+ mac_id = mapping['mac'].replace(':', '')
+
+ if FLAGS.allow_project_net_traffic:
+ template = "<parameter name=\"%s\"value=\"%s\" />\n"
+ net, mask = netutils.get_net_and_mask(network['cidr'])
+ values = [("PROJNET", net), ("PROJMASK", mask)]
+ if FLAGS.use_ipv6:
+ net_v6, prefixlen_v6 = netutils.get_net_and_prefixlen(
+ network['cidr_v6'])
+ values.extend([("PROJNETV6", net_v6),
+ ("PROJMASKV6", prefixlen_v6)])
+
+ extra_params = "".join([template % value for value in values])
+ else:
+ extra_params = "\n"
+
+ result = {
+ 'id': mac_id,
+ 'bridge_name': network['bridge'],
+ 'mac_address': mapping['mac'],
+ 'ip_address': mapping['ips'][0]['ip'],
+ 'dhcp_server': mapping['dhcp_server'],
+ 'extra_params': extra_params,
+ }
+
+ if gateway6:
+ result['gateway6'] = gateway6 + "/128"
+
+ return result
+
+ def plug(self, instance, network, mapping):
+ """Ensure that the bridge exists, and add VIF to it."""
+ if (not network.get('multi_host') and
+ mapping.get('should_create_bridge')):
+ if mapping.get('should_create_vlan'):
+ LOG.debug(_('Ensuring vlan %(vlan)s and bridge %(bridge)s'),
+ {'vlan': network['vlan'],
+ 'bridge': network['bridge']})
+ linux_net.ensure_vlan_bridge(network['vlan'],
+ network['bridge'],
+ network['bridge_interface'])
+ else:
+ LOG.debug(_("Ensuring bridge %s"), network['bridge'])
+ linux_net.ensure_bridge(network['bridge'],
+ network['bridge_interface'])
+
+ return self._get_configurations(network, mapping)
+
+ def unplug(self, instance, network, mapping):
+ """No manual unplugging required."""
+ pass
+
+
+class LibvirtOpenVswitchDriver(VIFDriver):
+ """VIF driver for Open vSwitch."""
+
+ def plug(self, instance, network, mapping):
+ vif_id = str(instance['id']) + "-" + str(network['id'])
+ dev = "tap-%s" % vif_id
+ iface_id = "nova-" + vif_id
+ if not linux_net._device_exists(dev):
+ utils.execute('sudo', 'ip', 'tuntap', 'add', dev, 'mode', 'tap')
+ utils.execute('sudo', 'ip', 'link', 'set', dev, 'up')
+ utils.execute('sudo', 'ovs-vsctl', '--', '--may-exist', 'add-port',
+ FLAGS.libvirt_ovs_bridge, dev,
+ '--', 'set', 'Interface', dev,
+ "external-ids:iface-id=%s" % iface_id,
+ '--', 'set', 'Interface', dev,
+ "external-ids:iface-status=active",
+ '--', 'set', 'Interface', dev,
+ "external-ids:attached-mac=%s" % mapping['mac'])
+
+ result = {
+ 'script': '',
+ 'name': dev,
+ 'mac_address': mapping['mac']}
+ return result
+
+ def unplug(self, instance, network, mapping):
+ """Unplug the VIF from the network by deleting the port from
+ the bridge."""
+ vif_id = str(instance['id']) + "-" + str(network['id'])
+ dev = "tap-%s" % vif_id
+ try:
+ utils.execute('sudo', 'ovs-vsctl', 'del-port',
+ network['bridge'], dev)
+ utils.execute('sudo', 'ip', 'link', 'delete', dev)
+ except exception.ProcessExecutionError:
+ LOG.warning(_("Failed while unplugging vif of instance '%s'"),
+ instance['name'])
+ raise
diff --git a/nova/virt/vif.py b/nova/virt/vif.py
new file mode 100644
index 000000000..b78689957
--- /dev/null
+++ b/nova/virt/vif.py
@@ -0,0 +1,30 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (C) 2011 Midokura KK
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""VIF module common to all virt layers."""
+
+
+class VIFDriver(object):
+ """Abstract class that defines generic interfaces for all VIF drivers."""
+
+ def plug(self, instance, network, mapping):
+ """Plug VIF into network."""
+ raise NotImplementedError()
+
+ def unplug(self, instance, network, mapping):
+ """Unplug VIF from network."""
+ raise NotImplementedError()
diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py
index 7370684bd..4c62d18bb 100644
--- a/nova/virt/vmwareapi/fake.py
+++ b/nova/virt/vmwareapi/fake.py
@@ -402,6 +402,16 @@ def _remove_file(file_path):
lst_files.remove(file)
+def fake_plug_vifs(*args, **kwargs):
+ """Fakes plugging vifs."""
+ pass
+
+
+def fake_get_network(*args, **kwargs):
+ """Fake get network."""
+ return [{'type': 'fake'}]
+
+
def fake_fetch_image(image, instance, **kwargs):
"""Fakes fetch image call. Just adds a reference to the db for the file."""
ds_name = kwargs.get("datastore_name")
diff --git a/nova/virt/vmwareapi/network_utils.py b/nova/virt/vmwareapi/network_utils.py
index e77842535..ec3b93fe7 100644
--- a/nova/virt/vmwareapi/network_utils.py
+++ b/nova/virt/vmwareapi/network_utils.py
@@ -45,10 +45,31 @@ 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 = {}
+ LOG.warn(vm_networks)
+ 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):
diff --git a/nova/virt/vmwareapi/vif.py b/nova/virt/vmwareapi/vif.py
new file mode 100644
index 000000000..b3e43b209
--- /dev/null
+++ b/nova/virt/vmwareapi/vif.py
@@ -0,0 +1,95 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Citrix Systems, Inc.
+# Copyright 2011 OpenStack LLC.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""VIF drivers for VMWare."""
+
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import utils
+from nova.virt.vif import VIFDriver
+from nova.virt.vmwareapi_conn import VMWareAPISession
+from nova.virt.vmwareapi import network_utils
+
+
+LOG = logging.getLogger("nova.virt.vmwareapi.vif")
+
+FLAGS = flags.FLAGS
+
+
+class VMWareVlanBridgeDriver(VIFDriver):
+ """VIF Driver to setup bridge/VLAN networking using VMWare API."""
+
+ def plug(self, instance, network, mapping):
+ """Create a vlan and bridge unless they already exist."""
+ vlan_num = network['vlan']
+ bridge = network['bridge']
+ bridge_interface = network['bridge_interface']
+
+ # Open vmwareapi session
+ host_ip = FLAGS.vmwareapi_host_ip
+ host_username = FLAGS.vmwareapi_host_username
+ host_password = FLAGS.vmwareapi_host_password
+ if not host_ip or host_username is None or host_password is None:
+ raise Exception(_('Must specify vmwareapi_host_ip, '
+ 'vmwareapi_host_username '
+ 'and vmwareapi_host_password to use '
+ 'connection_type=vmwareapi'))
+ session = VMWareAPISession(host_ip, host_username, host_password,
+ FLAGS.vmwareapi_api_retry_count)
+ vlan_interface = bridge_interface
+ # Check if the vlan_interface physical network adapter exists on the
+ # host.
+ if not network_utils.check_if_vlan_interface_exists(session,
+ vlan_interface):
+ raise exception.NetworkAdapterNotFound(adapter=vlan_interface)
+
+ # Get the vSwitch associated with the Physical Adapter
+ vswitch_associated = network_utils.get_vswitch_for_vlan_interface(
+ session, vlan_interface)
+ if vswitch_associated is None:
+ raise exception.SwicthNotFoundForNetworkAdapter(
+ adapter=vlan_interface)
+ # Check whether bridge already exists and retrieve the the ref of the
+ # network whose name_label is "bridge"
+ network_ref = network_utils.get_network_with_the_name(session, bridge)
+ if network_ref is None:
+ # Create a port group on the vSwitch associated with the
+ # vlan_interface corresponding physical network adapter on the ESX
+ # host.
+ network_utils.create_port_group(session, bridge,
+ vswitch_associated, vlan_num)
+ else:
+ # Get the vlan id and vswitch corresponding to the port group
+ pg_vlanid, pg_vswitch = \
+ network_utils.get_vlanid_and_vswitch_for_portgroup(session,
+ bridge)
+
+ # Check if the vswitch associated is proper
+ if pg_vswitch != vswitch_associated:
+ raise exception.InvalidVLANPortGroup(
+ bridge=bridge, expected=vswitch_associated,
+ actual=pg_vswitch)
+
+ # Check if the vlan id is proper for the port group
+ if pg_vlanid != vlan_num:
+ raise exception.InvalidVLANTag(bridge=bridge, tag=vlan_num,
+ pgroup=pg_vlanid)
+
+ def unplug(self, instance, network, mapping):
+ pass
diff --git a/nova/virt/vmwareapi/vm_util.py b/nova/virt/vmwareapi/vm_util.py
index 1638149f1..82b5f7214 100644
--- a/nova/virt/vmwareapi/vm_util.py
+++ b/nova/virt/vmwareapi/vm_util.py
@@ -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,25 @@ 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 and
+ 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 +295,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')
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py
index 94d9e6226..07a6ba6ab 100644
--- a/nova/virt/vmwareapi/vmops.py
+++ b/nova/virt/vmwareapi/vmops.py
@@ -26,11 +26,12 @@ import urllib
import urllib2
import uuid
-from nova import context
+from nova import context as nova_context
from nova import db
from nova import exception
from nova import flags
from nova import log as logging
+from nova import utils
from nova.compute import power_state
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
@@ -38,6 +39,10 @@ from nova.virt.vmwareapi import vmware_images
from nova.virt.vmwareapi import network_utils
FLAGS = flags.FLAGS
+flags.DEFINE_string('vmware_vif_driver',
+ 'nova.virt.vmwareapi.vif.VMWareVlanBridgeDriver',
+ 'The VMWare VIF driver to configure the VIFs.')
+
LOG = logging.getLogger("nova.virt.vmwareapi.vmops")
VMWARE_POWER_STATES = {
@@ -52,6 +57,7 @@ class VMWareVMOps(object):
def __init__(self, session):
"""Initializer."""
self._session = session
+ self._vif_driver = utils.import_object(FLAGS.vmware_vif_driver)
def _wait_with_callback(self, instance_id, task, callback):
"""Waits for the task to finish and does a callback after."""
@@ -83,7 +89,7 @@ class VMWareVMOps(object):
LOG.debug(_("Got total of %s instances") % str(len(lst_vm_names)))
return lst_vm_names
- def spawn(self, instance):
+ def spawn(self, context, instance, network_info):
"""
Creates a VM instance.
@@ -105,7 +111,7 @@ class VMWareVMOps(object):
client_factory = self._session._get_vim().client.factory
service_content = self._session._get_vim().get_service_content()
- network = db.network_get_by_instance(context.get_admin_context(),
+ network = db.network_get_by_instance(nova_context.get_admin_context(),
instance['id'])
net_name = network['bridge']
@@ -116,8 +122,10 @@ class VMWareVMOps(object):
net_name)
if network_ref is None:
raise exception.NetworkNotFoundForBridge(bridge=net_name)
+ return network_ref
- _check_if_network_bridge_exists()
+ self.plug_vifs(instance, network_info)
+ network_obj = _check_if_network_bridge_exists()
def _get_datastore_ref():
"""Get the datastore list and choose the first local storage."""
@@ -175,8 +183,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."""
@@ -319,7 +329,7 @@ class VMWareVMOps(object):
LOG.debug(_("Powered on the VM instance %s") % instance.name)
_power_on_vm()
- def snapshot(self, instance, snapshot_name):
+ def snapshot(self, context, instance, snapshot_name):
"""
Create snapshot from a running VM instance.
Steps followed are:
@@ -472,11 +482,14 @@ class VMWareVMOps(object):
_clean_temp_data()
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""Reboot a VM instance."""
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None:
raise exception.InstanceNotFound(instance_id=instance.id)
+
+ self.plug_vifs(instance, network_info)
+
lst_properties = ["summary.guest.toolsStatus", "runtime.powerState",
"summary.guest.toolsRunningStatus"]
props = self._session._call_method(vim_util, "get_object_properties",
@@ -514,7 +527,7 @@ class VMWareVMOps(object):
self._session._wait_for_task(instance.id, reset_task)
LOG.debug(_("Did hard reboot of VM %s") % instance.name)
- def destroy(self, instance):
+ def destroy(self, instance, network_info):
"""
Destroy a VM instance. Steps followed are:
1. Power off the VM, if it is in poweredOn state.
@@ -560,6 +573,8 @@ class VMWareVMOps(object):
LOG.warn(_("In vmwareapi:vmops:destroy, got this exception"
" while un-registering the VM: %s") % str(excep))
+ self._unplug_vifs(instance, network_info)
+
# Delete the folder holding the VM related content on
# the datastore.
try:
@@ -706,11 +721,11 @@ class VMWareVMOps(object):
Set the machine id of the VM for guest tools to pick up and change
the IP.
"""
- admin_context = context.get_admin_context()
+ admin_context = nova_context.get_admin_context()
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None:
raise exception.InstanceNotFound(instance_id=instance.id)
- network = db.network_get_by_instance(context.get_admin_context(),
+ network = db.network_get_by_instance(nova_context.get_admin_context(),
instance['id'])
mac_address = None
if instance['mac_addresses']:
@@ -718,20 +733,25 @@ class VMWareVMOps(object):
net_mask = network["netmask"]
gateway = network["gateway"]
+ broadcast = network["broadcast"]
+ # TODO(vish): add support for dns2
+ dns = network["dns1"]
+
addresses = db.instance_get_fixed_addresses(admin_context,
instance['id'])
ip_addr = addresses[0] if addresses else None
- machine_id_chanfge_spec = \
+ machine_id_change_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,
'ip_addr': ip_addr}))
reconfig_task = self._session._call_method(self._session._get_vim(),
"ReconfigVM_Task", vm_ref,
- spec=machine_id_chanfge_spec)
+ spec=machine_id_change_spec)
self._session._wait_for_task(instance.id, reconfig_task)
LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "
"with ip - %(ip_addr)s") %
@@ -784,3 +804,13 @@ class VMWareVMOps(object):
if vm.propSet[0].val == vm_name:
return vm.obj
return None
+
+ def plug_vifs(self, instance, network_info):
+ """Plug VIFs into networks."""
+ for (network, mapping) in network_info:
+ self._vif_driver.plug(instance, network, mapping)
+
+ def _unplug_vifs(self, instance, network_info):
+ """Unplug VIFs from networks."""
+ for (network, mapping) in network_info:
+ self._vif_driver.unplug(instance, network, mapping)
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py
index d80e14931..3d209fa99 100644
--- a/nova/virt/vmwareapi_conn.py
+++ b/nova/virt/vmwareapi_conn.py
@@ -124,21 +124,22 @@ class VMWareESXConnection(driver.ComputeDriver):
"""List VM instances."""
return self._vmops.list_instances()
- def spawn(self, instance, network_info=None, block_device_mapping=None):
+ def spawn(self, context, instance, network_info,
+ block_device_mapping=None):
"""Create VM instance."""
- self._vmops.spawn(instance)
+ self._vmops.spawn(context, instance, network_info)
- def snapshot(self, instance, name):
+ def snapshot(self, context, instance, name):
"""Create snapshot from a running VM instance."""
- self._vmops.snapshot(instance, name)
+ self._vmops.snapshot(context, instance, name)
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""Reboot VM instance."""
- self._vmops.reboot(instance)
+ self._vmops.reboot(instance, network_info)
- def destroy(self, instance):
+ def destroy(self, instance, network_info):
"""Destroy VM instance."""
- self._vmops.destroy(instance)
+ self._vmops.destroy(instance, network_info)
def pause(self, instance, callback):
"""Pause VM instance."""
@@ -194,6 +195,10 @@ class VMWareESXConnection(driver.ComputeDriver):
"""Sets the specified host's ability to accept new instances."""
pass
+ def plug_vifs(self, instance, network_info):
+ """Plugs in VIFs to networks."""
+ self._vmops.plug_vifs(instance, network_info)
+
class VMWareAPISession(object):
"""
diff --git a/nova/virt/xenapi/vif.py b/nova/virt/xenapi/vif.py
new file mode 100644
index 000000000..527602243
--- /dev/null
+++ b/nova/virt/xenapi/vif.py
@@ -0,0 +1,140 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Citrix Systems, Inc.
+# Copyright 2011 OpenStack LLC.
+# Copyright (C) 2011 Nicira, Inc
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""VIF drivers for XenAPI."""
+
+from nova import flags
+from nova import log as logging
+from nova.virt.vif import VIFDriver
+from nova.virt.xenapi.network_utils import NetworkHelper
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('xenapi_ovs_integration_bridge', 'xapi1',
+ 'Name of Integration Bridge used by Open vSwitch')
+
+LOG = logging.getLogger("nova.virt.xenapi.vif")
+
+
+class XenAPIBridgeDriver(VIFDriver):
+ """VIF Driver for XenAPI that uses XenAPI to create Networks."""
+
+ def plug(self, xenapi_session, vm_ref, instance, device, network,
+ network_mapping):
+ if network_mapping.get('should_create_vlan'):
+ network_ref = self.ensure_vlan_bridge(xenapi_session, network)
+ else:
+ network_ref = NetworkHelper.find_network_with_bridge(
+ xenapi_session, network['bridge'])
+ rxtx_cap = network_mapping.pop('rxtx_cap')
+ vif_rec = {}
+ vif_rec['device'] = str(device)
+ vif_rec['network'] = network_ref
+ vif_rec['VM'] = vm_ref
+ vif_rec['MAC'] = network_mapping['mac']
+ vif_rec['MTU'] = '1500'
+ vif_rec['other_config'] = {}
+ vif_rec['qos_algorithm_type'] = "ratelimit" if rxtx_cap else ''
+ vif_rec['qos_algorithm_params'] = \
+ {"kbps": str(rxtx_cap * 1024)} if rxtx_cap else {}
+ return vif_rec
+
+ def ensure_vlan_bridge(self, xenapi_session, network):
+ """Ensure that a VLAN bridge exists"""
+
+ vlan_num = network['vlan']
+ bridge = network['bridge']
+ bridge_interface = network['bridge_interface']
+ # Check whether bridge already exists
+ # Retrieve network whose name_label is "bridge"
+ network_ref = NetworkHelper.find_network_with_name_label(
+ xenapi_session, bridge)
+ if network_ref is None:
+ # If bridge does not exists
+ # 1 - create network
+ description = 'network for nova bridge %s' % bridge
+ network_rec = {'name_label': bridge,
+ 'name_description': description,
+ 'other_config': {}}
+ network_ref = xenapi_session.call_xenapi('network.create',
+ network_rec)
+ # 2 - find PIF for VLAN NOTE(salvatore-orlando): using double
+ # quotes inside single quotes as xapi filter only support
+ # tokens in double quotes
+ expr = 'field "device" = "%s" and \
+ field "VLAN" = "-1"' % bridge_interface
+ pifs = xenapi_session.call_xenapi('PIF.get_all_records_where',
+ expr)
+ pif_ref = None
+ # Multiple PIF are ok: we are dealing with a pool
+ if len(pifs) == 0:
+ raise Exception(_('Found no PIF for device %s') % \
+ bridge_interface)
+ for pif_ref in pifs.keys():
+ xenapi_session.call_xenapi('VLAN.create',
+ pif_ref,
+ str(vlan_num),
+ network_ref)
+ else:
+ # Check VLAN tag is appropriate
+ network_rec = xenapi_session.call_xenapi('network.get_record',
+ network_ref)
+ # Retrieve PIFs from network
+ for pif_ref in network_rec['PIFs']:
+ # Retrieve VLAN from PIF
+ pif_rec = xenapi_session.call_xenapi('PIF.get_record',
+ pif_ref)
+ pif_vlan = int(pif_rec['VLAN'])
+ # Raise an exception if VLAN != vlan_num
+ if pif_vlan != vlan_num:
+ raise Exception(_(
+ "PIF %(pif_rec['uuid'])s for network "
+ "%(bridge)s has VLAN id %(pif_vlan)d. "
+ "Expected %(vlan_num)d") % locals())
+
+ return network_ref
+
+ def unplug(self, instance, network, mapping):
+ pass
+
+
+class XenAPIOpenVswitchDriver(VIFDriver):
+ """VIF driver for Open vSwitch with XenAPI."""
+
+ def plug(self, xenapi_session, vm_ref, instance, device, network,
+ network_mapping):
+ # with OVS model, always plug into an OVS integration bridge
+ # that is already created
+ network_ref = NetworkHelper.find_network_with_bridge(xenapi_session,
+ FLAGS.xenapi_ovs_integration_bridge)
+ vif_rec = {}
+ vif_rec['device'] = str(device)
+ vif_rec['network'] = network_ref
+ vif_rec['VM'] = vm_ref
+ vif_rec['MAC'] = network_mapping['mac']
+ vif_rec['MTU'] = '1500'
+ vif_id = "nova-" + str(instance['id']) + "-" + str(network['id'])
+ vif_rec['qos_algorithm_type'] = ""
+ vif_rec['qos_algorithm_params'] = {}
+ # OVS on the hypervisor monitors this key and uses it to
+ # set the iface-id attribute
+ vif_rec['other_config'] = {"nicira-iface-id": vif_id}
+ return vif_rec
+
+ def unplug(self, instance, network, mapping):
+ pass
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 71107aff4..6d2340ccd 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -37,7 +37,6 @@ import nova.image
from nova.image import glance as glance_image_service
from nova import log as logging
from nova import utils
-from nova.auth.manager import AuthManager
from nova.compute import instance_types
from nova.compute import power_state
from nova.virt import disk
@@ -85,38 +84,22 @@ class ImageType:
DISK = 2
DISK_RAW = 3
DISK_VHD = 4
+ _ids = (KERNEL, RAMDISK, DISK, DISK_RAW, DISK_VHD)
KERNEL_STR = "kernel"
RAMDISK_STR = "ramdisk"
DISK_STR = "os"
DISK_RAW_STR = "os_raw"
DISK_VHD_STR = "vhd"
+ _strs = (KERNEL_STR, RAMDISK_STR, DISK_STR, DISK_RAW_STR, DISK_VHD_STR)
@classmethod
def to_string(cls, image_type):
- if image_type == ImageType.KERNEL:
- return ImageType.KERNEL_STR
- elif image_type == ImageType.RAMDISK:
- return ImageType.RAMDISK_STR
- elif image_type == ImageType.DISK:
- return ImageType.DISK_STR
- elif image_type == ImageType.DISK_RAW:
- return ImageType.DISK_RAW_STR
- elif image_type == ImageType.DISK_VHD:
- return ImageType.VHD_STR
+ return dict(zip(ImageType._ids, ImageType._strs)).get(image_type)
@classmethod
def from_string(cls, image_type_str):
- if image_type_str == ImageType.KERNEL_STR:
- return ImageType.KERNEL
- elif image_type == ImageType.RAMDISK_STR:
- return ImageType.RAMDISK
- elif image_type == ImageType.DISK_STR:
- return ImageType.DISK
- elif image_type == ImageType.DISK_RAW_STR:
- return ImageType.DISK_RAW
- elif image_type == ImageType.DISK_VHD_STR:
- return ImageType.VHD
+ return dict(zip(ImageType._strs, ImageType._ids)).get(image_type_str)
class VMHelper(HelperBase):
@@ -283,28 +266,6 @@ class VMHelper(HelperBase):
raise StorageError(_('Unable to destroy VDI %s') % vdi_ref)
@classmethod
- def create_vif(cls, session, vm_ref, network_ref, mac_address,
- dev, rxtx_cap=0):
- """Create a VIF record. Returns a Deferred that gives the new
- VIF reference."""
- vif_rec = {}
- vif_rec['device'] = str(dev)
- vif_rec['network'] = network_ref
- vif_rec['VM'] = vm_ref
- vif_rec['MAC'] = mac_address
- vif_rec['MTU'] = '1500'
- vif_rec['other_config'] = {}
- vif_rec['qos_algorithm_type'] = "ratelimit" if rxtx_cap else ''
- vif_rec['qos_algorithm_params'] = \
- {"kbps": str(rxtx_cap * 1024)} if rxtx_cap else {}
- LOG.debug(_('Creating VIF for VM %(vm_ref)s,'
- ' network %(network_ref)s.') % locals())
- vif_ref = session.call_xenapi('VIF.create', vif_rec)
- LOG.debug(_('Created VIF %(vif_ref)s for VM %(vm_ref)s,'
- ' network %(network_ref)s.') % locals())
- return vif_ref
-
- @classmethod
def create_vdi(cls, session, sr_ref, name_label, virtual_size, read_only):
"""Create a VDI record and returns its reference."""
vdi_ref = session.get_xenapi().VDI.create(
@@ -381,7 +342,7 @@ class VMHelper(HelperBase):
return os.path.join(FLAGS.xenapi_sr_base_path, sr_uuid)
@classmethod
- def upload_image(cls, session, instance, vdi_uuids, image_id):
+ def upload_image(cls, context, session, instance, vdi_uuids, image_id):
""" Requests that the Glance plugin bundle the specified VDIs and
push them into Glance using the specified human-friendly name.
"""
@@ -399,37 +360,30 @@ class VMHelper(HelperBase):
'glance_host': glance_host,
'glance_port': glance_port,
'sr_path': cls.get_sr_path(session),
- 'os_type': os_type}
+ 'os_type': os_type,
+ 'auth_token': getattr(context, 'auth_token', None)}
kwargs = {'params': pickle.dumps(params)}
task = session.async_call_plugin('glance', 'upload_vhd', kwargs)
session.wait_for_task(task, instance.id)
@classmethod
- def fetch_image(cls, session, instance_id, image, user, project,
- image_type):
- """
- image_type is interpreted as an ImageType instance
- Related flags:
- xenapi_image_service = ['glance', 'objectstore']
- glance_address = 'address for glance services'
- glance_port = 'port for glance services'
+ def fetch_image(cls, context, session, instance_id, image, user_id,
+ project_id, image_type):
+ """Fetch image from glance based on image type.
- Returns: A single filename if image_type is KERNEL_RAMDISK
+ Returns: A single filename if image_type is KERNEL or RAMDISK
A list of dictionaries that describe VDIs, otherwise
"""
- access = AuthManager().get_access_key(user, project)
-
- if FLAGS.xenapi_image_service == 'glance':
- return cls._fetch_image_glance(session, instance_id, image,
- access, image_type)
+ if image_type == ImageType.DISK_VHD:
+ return cls._fetch_image_glance_vhd(context,
+ session, instance_id, image, image_type)
else:
- return cls._fetch_image_objectstore(session, instance_id, image,
- access, user.secret,
- image_type)
+ return cls._fetch_image_glance_disk(context,
+ session, instance_id, image, image_type)
@classmethod
- def _fetch_image_glance_vhd(cls, session, instance_id, image, access,
+ def _fetch_image_glance_vhd(cls, context, session, instance_id, image,
image_type):
"""Tell glance to download an image and put the VHDs into the SR
@@ -451,7 +405,8 @@ class VMHelper(HelperBase):
'glance_host': glance_host,
'glance_port': glance_port,
'uuid_stack': uuid_stack,
- 'sr_path': cls.get_sr_path(session)}
+ 'sr_path': cls.get_sr_path(session),
+ 'auth_token': getattr(context, 'auth_token', None)}
kwargs = {'params': pickle.dumps(params)}
task = session.async_call_plugin('glance', 'download_vhd', kwargs)
@@ -477,7 +432,7 @@ class VMHelper(HelperBase):
return vdis
@classmethod
- def _fetch_image_glance_disk(cls, session, instance_id, image, access,
+ def _fetch_image_glance_disk(cls, context, session, instance_id, image,
image_type):
"""Fetch the image from Glance
@@ -497,6 +452,7 @@ class VMHelper(HelperBase):
sr_ref = safe_find_sr(session)
glance_client, image_id = nova.image.get_glance_client(image)
+ glance_client.set_auth_token(getattr(context, 'auth_token', None))
meta, image_file = glance_client.get_image(image_id)
virtual_size = int(meta['size'])
vdi_size = virtual_size
@@ -600,136 +556,38 @@ class VMHelper(HelperBase):
else:
return ImageType.DISK_RAW
- # FIXME(sirp): can we unify the ImageService and xenapi_image_service
- # abstractions?
- if FLAGS.xenapi_image_service == 'glance':
- image_type = determine_from_glance()
- else:
- image_type = determine_from_instance()
+ image_type = determine_from_glance()
log_disk_format(image_type)
return image_type
@classmethod
- def _fetch_image_glance(cls, session, instance_id, image, access,
- image_type):
- """Fetch image from glance based on image type.
-
- Returns: A single filename if image_type is KERNEL or RAMDISK
- A list of dictionaries that describe VDIs, otherwise
- """
- if image_type == ImageType.DISK_VHD:
- return cls._fetch_image_glance_vhd(
- session, instance_id, image, access, image_type)
- else:
- return cls._fetch_image_glance_disk(
- session, instance_id, image, access, image_type)
-
- @classmethod
- def _fetch_image_objectstore(cls, session, instance_id, image, access,
- secret, image_type):
- """Fetch an image from objectstore.
-
- Returns: A single filename if image_type is KERNEL or RAMDISK
- A list of dictionaries that describe VDIs, otherwise
- """
- url = "http://%s:%s/_images/%s/image" % (FLAGS.s3_host, FLAGS.s3_port,
- image)
- LOG.debug(_("Asking xapi to fetch %(url)s as %(access)s") % locals())
- if image_type in (ImageType.KERNEL, ImageType.RAMDISK):
- fn = 'get_kernel'
- else:
- fn = 'get_vdi'
- args = {}
- args['src_url'] = url
- args['username'] = access
- args['password'] = secret
- args['add_partition'] = 'false'
- args['raw'] = 'false'
- if not image_type in (ImageType.KERNEL, ImageType.RAMDISK):
- args['add_partition'] = 'true'
- if image_type == ImageType.DISK_RAW:
- args['raw'] = 'true'
- task = session.async_call_plugin('objectstore', fn, args)
- vdi_uuid = None
- filename = None
- if image_type in (ImageType.KERNEL, ImageType.RAMDISK):
- filename = session.wait_for_task(task, instance_id)
- else:
- vdi_uuid = session.wait_for_task(task, instance_id)
- return [dict(vdi_type=ImageType.to_string(image_type),
- vdi_uuid=vdi_uuid,
- file=filename)]
-
- @classmethod
def determine_is_pv(cls, session, instance_id, vdi_ref, disk_image_type,
os_type):
"""
Determine whether the VM will use a paravirtualized kernel or if it
will use hardware virtualization.
- 1. Objectstore (any image type):
- We use plugin to figure out whether the VDI uses PV
-
- 2. Glance (VHD): then we use `os_type`, raise if not set
-
- 3. Glance (DISK_RAW): use Pygrub to figure out if pv kernel is
- available
-
- 4. Glance (DISK): pv is assumed
- """
- if FLAGS.xenapi_image_service == 'glance':
- # 2, 3, 4: Glance
- return cls._determine_is_pv_glance(
- session, vdi_ref, disk_image_type, os_type)
- else:
- # 1. Objecstore
- return cls._determine_is_pv_objectstore(session, instance_id,
- vdi_ref)
-
- @classmethod
- def _determine_is_pv_objectstore(cls, session, instance_id, vdi_ref):
- LOG.debug(_("Looking up vdi %s for PV kernel"), vdi_ref)
- fn = "is_vdi_pv"
- args = {}
- args['vdi-ref'] = vdi_ref
- task = session.async_call_plugin('objectstore', fn, args)
- pv_str = session.wait_for_task(task, instance_id)
- pv = None
- if pv_str.lower() == 'true':
- pv = True
- elif pv_str.lower() == 'false':
- pv = False
- LOG.debug(_("PV Kernel in VDI:%s"), pv)
- return pv
+ 1. Glance (VHD): then we use `os_type`, raise if not set
- @classmethod
- def _determine_is_pv_glance(cls, session, vdi_ref, disk_image_type,
- os_type):
- """
- For a Glance image, determine if we need paravirtualization.
-
- The relevant scenarios are:
- 2. Glance (VHD): then we use `os_type`, raise if not set
-
- 3. Glance (DISK_RAW): use Pygrub to figure out if pv kernel is
+ 2. Glance (DISK_RAW): use Pygrub to figure out if pv kernel is
available
- 4. Glance (DISK): pv is assumed
+ 3. Glance (DISK): pv is assumed
"""
LOG.debug(_("Looking up vdi %s for PV kernel"), vdi_ref)
if disk_image_type == ImageType.DISK_VHD:
- # 2. VHD
+ # 1. VHD
if os_type == 'windows':
is_pv = False
else:
is_pv = True
elif disk_image_type == ImageType.DISK_RAW:
- # 3. RAW
+ # 2. RAW
is_pv = with_vdi_attached_here(session, vdi_ref, True, _is_vdi_pv)
elif disk_image_type == ImageType.DISK:
- # 4. Disk
+ # 3. Disk
is_pv = True
else:
raise exception.Error(_("Unknown image format %(disk_image_type)s")
@@ -1237,6 +1095,8 @@ def _prepare_injectables(inst, networks_info):
ip_v6 = info['ip6s'][0]
if len(info['dns']) > 0:
dns = info['dns'][0]
+ else:
+ dns = ''
interface_info = {'name': 'eth%d' % ifc_num,
'address': ip_v4 and ip_v4['ip'] or '',
'netmask': ip_v4 and ip_v4['netmask'] or '',
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index c332c27b0..a78413370 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -30,7 +30,7 @@ import sys
import time
import uuid
-from nova import context
+from nova import context as nova_context
from nova import db
from nova import exception
from nova import flags
@@ -38,7 +38,6 @@ from nova import ipv6
from nova import log as logging
from nova import utils
-from nova.auth.manager import AuthManager
from nova.compute import power_state
from nova.virt import driver
from nova.virt.xenapi.network_utils import NetworkHelper
@@ -52,6 +51,9 @@ FLAGS = flags.FLAGS
flags.DEFINE_integer('windows_version_timeout', 300,
'number of seconds to wait for windows agent to be '
'fully operational')
+flags.DEFINE_string('xenapi_vif_driver',
+ 'nova.virt.xenapi.vif.XenAPIBridgeDriver',
+ 'The XenAPI VIF driver using XenServer Network APIs.')
def cmp_version(a, b):
@@ -78,6 +80,7 @@ class VMOps(object):
self._session = session
self.poll_rescue_last_ran = None
VMHelper.XenAPI = self.XenAPI
+ self.vif_driver = utils.import_object(FLAGS.xenapi_vif_driver)
def list_instances(self):
"""List VM instances."""
@@ -106,18 +109,20 @@ class VMOps(object):
instance_infos.append(instance_info)
return instance_infos
- def revert_resize(self, instance):
+ def revert_migration(self, instance):
vm_ref = VMHelper.lookup(self._session, instance.name)
self._start(instance, vm_ref)
- def finish_resize(self, instance, disk_info, network_info):
+ def finish_migration(self, context, instance, disk_info, network_info,
+ resize_instance):
vdi_uuid = self.link_disks(instance, disk_info['base_copy'],
disk_info['cow'])
- vm_ref = self._create_vm(instance,
+ vm_ref = self._create_vm(context, instance,
[dict(vdi_type='os', vdi_uuid=vdi_uuid)],
network_info)
- self.resize_instance(instance, vdi_uuid)
- self._spawn(instance, vm_ref)
+ if resize_instance:
+ self.resize_instance(instance, vdi_uuid)
+ self._start(instance, vm_ref=vm_ref)
def _start(self, instance, vm_ref=None):
"""Power on a VM instance"""
@@ -129,20 +134,19 @@ class VMOps(object):
LOG.debug(_("Starting instance %s"), instance.name)
self._session.call_xenapi('VM.start', vm_ref, False, False)
- def _create_disks(self, instance):
- user = AuthManager().get_user(instance.user_id)
- project = AuthManager().get_project(instance.project_id)
+ def _create_disks(self, context, instance):
disk_image_type = VMHelper.determine_disk_image_type(instance)
- vdis = VMHelper.fetch_image(self._session,
- instance.id, instance.image_ref, user, project,
+ vdis = VMHelper.fetch_image(context, self._session,
+ instance.id, instance.image_ref,
+ instance.user_id, instance.project_id,
disk_image_type)
return vdis
- def spawn(self, instance, network_info):
+ def spawn(self, context, instance, network_info):
vdis = None
try:
- vdis = self._create_disks(instance)
- vm_ref = self._create_vm(instance, vdis, network_info)
+ vdis = self._create_disks(context, instance)
+ vm_ref = self._create_vm(context, instance, vdis, network_info)
self._spawn(instance, vm_ref)
except (self.XenAPI.Failure, OSError, IOError) as spawn_error:
LOG.exception(_("instance %s: Failed to spawn"),
@@ -152,11 +156,11 @@ class VMOps(object):
self._handle_spawn_error(vdis, spawn_error)
raise spawn_error
- def spawn_rescue(self, instance):
+ def spawn_rescue(self, context, instance, network_info):
"""Spawn a rescue instance."""
- self.spawn(instance)
+ self.spawn(context, instance, network_info)
- def _create_vm(self, instance, vdis, network_info):
+ def _create_vm(self, context, instance, vdis, network_info):
"""Create VM instance."""
instance_name = instance.name
vm_ref = VMHelper.lookup(self._session, instance_name)
@@ -167,26 +171,23 @@ class VMOps(object):
if not VMHelper.ensure_free_mem(self._session, instance):
LOG.exception(_('instance %(instance_name)s: not enough free '
'memory') % locals())
- db.instance_set_state(context.get_admin_context(),
+ db.instance_set_state(nova_context.get_admin_context(),
instance['id'],
power_state.SHUTDOWN)
return
- user = AuthManager().get_user(instance.user_id)
- project = AuthManager().get_project(instance.project_id)
-
disk_image_type = VMHelper.determine_disk_image_type(instance)
kernel = None
ramdisk = None
try:
if instance.kernel_id:
- kernel = VMHelper.fetch_image(self._session, instance.id,
- instance.kernel_id, user, project,
- ImageType.KERNEL)[0]
+ kernel = VMHelper.fetch_image(context, self._session,
+ instance.id, instance.kernel_id, instance.user_id,
+ instance.project_id, ImageType.KERNEL)[0]
if instance.ramdisk_id:
- ramdisk = VMHelper.fetch_image(self._session, instance.id,
- instance.ramdisk_id, user, project,
- ImageType.RAMDISK)[0]
+ ramdisk = VMHelper.fetch_image(context, self._session,
+ instance.id, instance.kernel_id, instance.user_id,
+ instance.project_id, ImageType.RAMDISK)[0]
# Create the VM ref and attach the first disk
first_vdi_ref = self._session.call_xenapi('VDI.get_by_uuid',
vdis[0]['vdi_uuid'])
@@ -205,7 +206,7 @@ class VMOps(object):
if instance.vm_mode != vm_mode:
# Update database with normalized (or determined) value
- db.instance_update(context.get_admin_context(),
+ db.instance_update(nova_context.get_admin_context(),
instance['id'], {'vm_mode': vm_mode})
vm_ref = VMHelper.create_vm(self._session, instance,
kernel and kernel.get('file', None) or None,
@@ -251,11 +252,11 @@ class VMOps(object):
userdevice += 1
# Alter the image before VM start for, e.g. network injection
- if FLAGS.xenapi_inject_image:
+ if FLAGS.flat_injected:
VMHelper.preconfigure_instance(self._session, instance,
first_vdi_ref, network_info)
- self.create_vifs(vm_ref, network_info)
+ self.create_vifs(vm_ref, instance, network_info)
self.inject_network_info(instance, network_info, vm_ref)
return vm_ref
@@ -267,7 +268,7 @@ class VMOps(object):
LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.')
% locals())
- ctx = context.get_admin_context()
+ ctx = nova_context.get_admin_context()
agent_build = db.agent_build_get_by_triple(ctx, 'xen',
instance.os_type, instance.architecture)
if agent_build:
@@ -340,6 +341,7 @@ class VMOps(object):
_check_agent_version()
_inject_files()
_set_admin_password()
+ self.reset_network(instance, vm_ref)
return True
except Exception, exc:
LOG.warn(exc)
@@ -349,9 +351,6 @@ class VMOps(object):
timer.f = _wait_for_boot
- # call to reset network to configure network from xenstore
- self.reset_network(instance, vm_ref)
-
return timer.start(interval=0.5, now=True)
def _handle_spawn_error(self, vdis, spawn_error):
@@ -413,7 +412,7 @@ class VMOps(object):
# if instance_or_vm is an int/long it must be instance id
elif isinstance(instance_or_vm, (int, long)):
- ctx = context.get_admin_context()
+ ctx = nova_context.get_admin_context()
instance_obj = db.instance_get(ctx, instance_or_vm)
instance_name = instance_obj.name
else:
@@ -438,9 +437,10 @@ class VMOps(object):
vm,
"start")
- def snapshot(self, instance, image_id):
+ def snapshot(self, context, instance, image_id):
"""Create snapshot from a running VM instance.
+ :param context: request context
:param instance: instance to be snapshotted
:param image_id: id of image to upload to
@@ -465,7 +465,7 @@ class VMOps(object):
try:
template_vm_ref, template_vdi_uuids = self._get_snapshot(instance)
# call plugin to ship snapshot off to glance
- VMHelper.upload_image(
+ VMHelper.upload_image(context,
self._session, instance, template_vdi_uuids, image_id)
finally:
if template_vm_ref:
@@ -566,18 +566,22 @@ class VMOps(object):
return new_cow_uuid
def resize_instance(self, instance, vdi_uuid):
- """Resize a running instance by changing it's RAM and disk size."""
+ """Resize a running instance by changing its RAM and disk size."""
#TODO(mdietz): this will need to be adjusted for swap later
#The new disk size must be in bytes
- new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- instance_name = instance.name
- instance_local_gb = instance.local_gb
- LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance %(instance_name)s."
- " Expanding to %(instance_local_gb)d GB") % locals())
- vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
- self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
- LOG.debug(_("Resize instance %s complete") % (instance.name))
+ new_disk_size = instance.local_gb * 1024 * 1024 * 1024
+ if new_disk_size > 0:
+ instance_name = instance.name
+ instance_local_gb = instance.local_gb
+ LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance"
+ "%(instance_name)s. Expanding to %(instance_local_gb)d"
+ " GB") % locals())
+ vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
+ # for an instance with no local storage
+ self._session.call_xenapi('VDI.resize_online', vdi_ref,
+ str(new_disk_size))
+ LOG.debug(_("Resize instance %s complete") % (instance.name))
def reboot(self, instance):
"""Reboot VM instance."""
@@ -682,7 +686,7 @@ class VMOps(object):
# Successful return code from password is '0'
if resp_dict['returncode'] != '0':
raise RuntimeError(resp_dict['message'])
- db.instance_update(context.get_admin_context(),
+ db.instance_update(nova_context.get_admin_context(),
instance['id'],
dict(admin_pass=new_pass))
return resp_dict['message']
@@ -739,6 +743,17 @@ class VMOps(object):
except self.XenAPI.Failure, exc:
LOG.exception(exc)
+ def _find_rescue_vbd_ref(self, vm_ref, rescue_vm_ref):
+ """Find and return the rescue VM's vbd_ref.
+
+ We use the second VBD here because swap is first with the root file
+ system coming in second."""
+ vbd_ref = self._session.get_xenapi().VM.get_VBDs(vm_ref)[1]
+ vdi_ref = self._session.get_xenapi().VBD.get_record(vbd_ref)["VDI"]
+
+ return VMHelper.create_vbd(self._session, rescue_vm_ref, vdi_ref, 1,
+ False)
+
def _shutdown_rescue(self, rescue_vm_ref):
"""Shutdown a rescue instance."""
self._session.call_xenapi("Async.VM.hard_shutdown", rescue_vm_ref)
@@ -839,7 +854,7 @@ class VMOps(object):
self._session.call_xenapi("Async.VM.destroy", rescue_vm_ref)
- def destroy(self, instance):
+ def destroy(self, instance, network_info):
"""Destroy VM instance.
This is the method exposed by xenapi_conn.destroy(). The rest of the
@@ -849,9 +864,9 @@ class VMOps(object):
instance_id = instance.id
LOG.info(_("Destroying VM for Instance %(instance_id)s") % locals())
vm_ref = VMHelper.lookup(self._session, instance.name)
- return self._destroy(instance, vm_ref, shutdown=True)
+ return self._destroy(instance, vm_ref, network_info, shutdown=True)
- def _destroy(self, instance, vm_ref, shutdown=True,
+ def _destroy(self, instance, vm_ref, network_info=None, shutdown=True,
destroy_kernel_ramdisk=True):
"""Destroys VM instance by performing:
@@ -873,6 +888,10 @@ class VMOps(object):
self._destroy_kernel_ramdisk(instance, vm_ref)
self._destroy_vm(instance, vm_ref)
+ if network_info:
+ for (network, mapping) in network_info:
+ self.vif_driver.unplug(instance, network, mapping)
+
def _wait_with_callback(self, instance_id, task, callback):
ret = None
try:
@@ -906,7 +925,7 @@ class VMOps(object):
True)
self._wait_with_callback(instance.id, task, callback)
- def rescue(self, instance, callback):
+ def rescue(self, context, instance, _callback, network_info):
"""Rescue the specified instance.
- shutdown the instance VM.
@@ -924,17 +943,13 @@ class VMOps(object):
self._shutdown(instance, vm_ref)
self._acquire_bootlock(vm_ref)
instance._rescue = True
- self.spawn_rescue(instance)
+ self.spawn_rescue(context, instance, network_info)
rescue_vm_ref = VMHelper.lookup(self._session, instance.name)
-
- vbd_ref = self._session.get_xenapi().VM.get_VBDs(vm_ref)[0]
- vdi_ref = self._session.get_xenapi().VBD.get_record(vbd_ref)["VDI"]
- rescue_vbd_ref = VMHelper.create_vbd(self._session, rescue_vm_ref,
- vdi_ref, 1, False)
+ rescue_vbd_ref = self._find_rescue_vbd_ref(vm_ref, rescue_vm_ref)
self._session.call_xenapi("Async.VBD.plug", rescue_vbd_ref)
- def unrescue(self, instance, callback):
+ def unrescue(self, instance, _callback):
"""Unrescue the specified instance.
- unplug the instance VM's disk from the rescue VM.
@@ -1068,7 +1083,7 @@ class VMOps(object):
# catch KeyError for domid if instance isn't running
pass
- def create_vifs(self, vm_ref, network_info):
+ def create_vifs(self, vm_ref, instance, network_info):
"""Creates vifs for an instance."""
logging.debug(_("creating vif(s) for vm: |%s|"), vm_ref)
@@ -1077,14 +1092,19 @@ class VMOps(object):
self._session.get_xenapi().VM.get_record(vm_ref)
for device, (network, info) in enumerate(network_info):
- mac_address = info['mac']
- bridge = network['bridge']
- rxtx_cap = info.pop('rxtx_cap')
- network_ref = \
- NetworkHelper.find_network_with_bridge(self._session,
- bridge)
- VMHelper.create_vif(self._session, vm_ref, network_ref,
- mac_address, device, rxtx_cap)
+ vif_rec = self.vif_driver.plug(self._session,
+ vm_ref, instance, device, network, info)
+ network_ref = vif_rec['network']
+ LOG.debug(_('Creating VIF for VM %(vm_ref)s,' \
+ ' network %(network_ref)s.') % locals())
+ vif_ref = self._session.call_xenapi('VIF.create', vif_rec)
+ LOG.debug(_('Created VIF %(vif_ref)s for VM %(vm_ref)s,'
+ ' network %(network_ref)s.') % locals())
+
+ def plug_vifs(self, instance, network_info):
+ """Set up VIF networking on the host."""
+ for (network, mapping) in network_info:
+ self.vif_driver.plug(self._session, instance, network, mapping)
def reset_network(self, instance, vm_ref=None):
"""Creates uuid arg to pass to make_agent_call and calls it."""
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index ec8c44c1c..49ae2623e 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -101,9 +101,6 @@ flags.DEFINE_float('xenapi_task_poll_interval',
'The interval used for polling of remote tasks '
'(Async.VM.start, etc). Used only if '
'connection_type=xenapi.')
-flags.DEFINE_string('xenapi_image_service',
- 'glance',
- 'Where to get VM images: glance or objectstore.')
flags.DEFINE_float('xenapi_vhd_coalesce_poll_interval',
5.0,
'The interval used for polling of coalescing vhds.'
@@ -112,22 +109,15 @@ flags.DEFINE_integer('xenapi_vhd_coalesce_max_attempts',
5,
'Max number of times to poll for VHD to coalesce.'
' Used only if connection_type=xenapi.')
-flags.DEFINE_bool('xenapi_inject_image',
- True,
- 'Specifies whether an attempt to inject network/key'
- ' data into the disk image should be made.'
- ' Used only if connection_type=xenapi.')
flags.DEFINE_string('xenapi_agent_path',
'usr/sbin/xe-update-networking',
'Specifies the path in which the xenapi guest agent'
' should be located. If the agent is present,'
' network configuration is not injected into the image'
' Used only if connection_type=xenapi.'
- ' and xenapi_inject_image=True')
-
+ ' and flat_injected=True')
flags.DEFINE_string('xenapi_sr_base_path', '/var/run/sr-mount',
'Base path to the storage repository')
-
flags.DEFINE_string('target_host',
None,
'iSCSI Target Host')
@@ -194,23 +184,26 @@ class XenAPIConnection(driver.ComputeDriver):
def list_instances_detail(self):
return self._vmops.list_instances_detail()
- def spawn(self, instance, network_info, block_device_mapping=None):
+ def spawn(self, context, instance, network_info,
+ block_device_mapping=None):
"""Create VM instance"""
- self._vmops.spawn(instance, network_info)
+ self._vmops.spawn(context, instance, network_info)
- def revert_resize(self, instance):
+ def revert_migration(self, instance):
"""Reverts a resize, powering back on the instance"""
- self._vmops.revert_resize(instance)
+ self._vmops.revert_migration(instance)
- def finish_resize(self, instance, disk_info, network_info):
+ def finish_migration(self, context, instance, disk_info, network_info,
+ resize_instance=False):
"""Completes a resize, turning on the migrated instance"""
- self._vmops.finish_resize(instance, disk_info, network_info)
+ self._vmops.finish_migration(context, instance, disk_info,
+ network_info, resize_instance)
- def snapshot(self, instance, image_id):
+ def snapshot(self, context, instance, image_id):
""" Create snapshot from a running VM instance """
- self._vmops.snapshot(instance, image_id)
+ self._vmops.snapshot(context, instance, image_id)
- def reboot(self, instance):
+ def reboot(self, instance, network_info):
"""Reboot VM instance"""
self._vmops.reboot(instance)
@@ -224,9 +217,9 @@ class XenAPIConnection(driver.ComputeDriver):
"""
self._vmops.inject_file(instance, b64_path, b64_contents)
- def destroy(self, instance):
+ def destroy(self, instance, network_info):
"""Destroy VM instance"""
- self._vmops.destroy(instance)
+ self._vmops.destroy(instance, network_info)
def pause(self, instance, callback):
"""Pause VM instance"""
@@ -249,13 +242,13 @@ class XenAPIConnection(driver.ComputeDriver):
"""resume the specified instance"""
self._vmops.resume(instance, callback)
- def rescue(self, instance, callback):
+ def rescue(self, context, instance, _callback, network_info):
"""Rescue the specified instance"""
- self._vmops.rescue(instance, callback)
+ self._vmops.rescue(context, instance, _callback, network_info)
- def unrescue(self, instance, callback):
+ def unrescue(self, instance, _callback, network_info):
"""Unrescue the specified instance"""
- self._vmops.unrescue(instance, callback)
+ self._vmops.unrescue(instance, _callback)
def poll_rescued_instances(self, timeout):
"""Poll for rescued instances"""
@@ -269,6 +262,9 @@ class XenAPIConnection(driver.ComputeDriver):
"""inject network info for specified instance"""
self._vmops.inject_network_info(instance, network_info)
+ def plug_vifs(self, instance_ref, network_info):
+ self._vmops.plug_vifs(instance_ref, network_info)
+
def get_info(self, instance_id):
"""Return data about VM instance"""
return self._vmops.get_info(instance_id)
@@ -322,7 +318,7 @@ class XenAPIConnection(driver.ComputeDriver):
"""This method is supported only by libvirt."""
return
- def unfilter_instance(self, instance_ref):
+ def unfilter_instance(self, instance_ref, network_info):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
@@ -398,11 +394,10 @@ class XenAPISession(object):
try:
name = self._session.xenapi.task.get_name_label(task)
status = self._session.xenapi.task.get_status(task)
+ # Ensure action is never > 255
+ action = dict(action=name[:255], error=None)
if id:
- action = dict(
- instance_id=int(id),
- action=name[0:255], # Ensure action is never > 255
- error=None)
+ action["instance_id"] = int(id)
if status == "pending":
return
elif status == "success":
@@ -445,7 +440,7 @@ class XenAPISession(object):
params = None
try:
params = eval(exc.details[3])
- except:
+ except Exception:
raise exc
raise self.XenAPI.Failure(params)
else:
diff --git a/nova/vnc/proxy.py b/nova/vnc/proxy.py
index c4603803b..2e3e38ca9 100644
--- a/nova/vnc/proxy.py
+++ b/nova/vnc/proxy.py
@@ -60,7 +60,7 @@ class WebsocketVNCProxy(object):
break
d = base64.b64encode(d)
dest.send(d)
- except:
+ except Exception:
source.close()
dest.close()
@@ -72,7 +72,7 @@ class WebsocketVNCProxy(object):
break
d = base64.b64decode(d)
dest.sendall(d)
- except:
+ except Exception:
source.close()
dest.close()
diff --git a/nova/volume/api.py b/nova/volume/api.py
index cfc274c77..52b3a9fed 100644
--- a/nova/volume/api.py
+++ b/nova/volume/api.py
@@ -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)
diff --git a/nova/wsgi.py b/nova/wsgi.py
index eae3afcb4..c8ddb97d7 100644
--- a/nova/wsgi.py
+++ b/nova/wsgi.py
@@ -274,6 +274,18 @@ class Middleware(Application):
return self.process_response(response)
+class InjectContext(Middleware):
+ """Add a 'nova.context' to WSGI environ."""
+ def __init__(self, context, *args, **kwargs):
+ self.context = context
+ super(InjectContext, self).__init__(*args, **kwargs)
+
+ @webob.dec.wsgify(RequestClass=Request)
+ def __call__(self, req):
+ req.environ['nova.context'] = self.context
+ return self.application
+
+
class Debug(Middleware):
"""Helper class for debugging a WSGI application.
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
index 288ccc78a..d609a88ab 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
@@ -72,7 +72,9 @@ def key_init(self, arg_dict):
info to be passed, such as passwords. Returns the shared
secret key value.
"""
- pub = int(arg_dict["pub"])
+ # WARNING: Some older Windows agents will crash if the public key isn't
+ # a string
+ pub = arg_dict["pub"]
arg_dict["value"] = json.dumps({"name": "keyinit", "value": pub})
request_id = arg_dict["id"]
arg_dict["path"] = "data/host/%s" % request_id
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
index fbe080b22..a06312890 100644..100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
@@ -67,12 +67,17 @@ def _copy_kernel_vdi(dest, copy_args):
def _download_tarball(sr_path, staging_path, image_id, glance_host,
- glance_port):
+ glance_port, auth_token):
"""Download the tarball image from Glance and extract it into the staging
area.
"""
+ # Build request headers
+ headers = {}
+ if auth_token:
+ headers['x-auth-token'] = auth_token
+
conn = httplib.HTTPConnection(glance_host, glance_port)
- conn.request('GET', '/v1/images/%s' % image_id)
+ conn.request('GET', '/v1/images/%s' % image_id, headers=headers)
resp = conn.getresponse()
if resp.status == httplib.NOT_FOUND:
raise Exception("Image '%s' not found in Glance" % image_id)
@@ -236,12 +241,29 @@ def _prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids):
os.link(source, link_name)
-def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type):
+def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
+ auth_token):
"""
Create a tarball of the image and then stream that into Glance
using chunked-transfer-encoded HTTP.
"""
conn = httplib.HTTPConnection(glance_host, glance_port)
+
+ # NOTE(dprince): We need to resend any existing Glance meta/property
+ # headers so they are preserved in Glance. We obtain them here with a
+ # HEAD request.
+ conn.request('HEAD', '/v1/images/%s' % image_id)
+ resp = conn.getresponse()
+ if resp.status != httplib.OK:
+ raise Exception("Unexpected response from Glance %i" % resp.status)
+ headers = {}
+ for header, value in resp.getheaders():
+ if header.lower().startswith("x-image-meta-property-"):
+ headers[header.lower()] = value
+
+ # Toss body so connection state-machine is ready for next request/response
+ resp.read()
+
# NOTE(sirp): httplib under python2.4 won't accept a file-like object
# to request
conn.putrequest('PUT', '/v1/images/%s' % image_id)
@@ -254,7 +276,7 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type):
# 2. We're currently uploading a vanilla tarball. In order to be OVF/OVA
# compliant, we'll need to embed a minimal OVF manifest as the first
# file.
- headers = {
+ ovf_headers = {
'content-type': 'application/octet-stream',
'transfer-encoding': 'chunked',
'x-image-meta-is-public': 'True',
@@ -263,6 +285,12 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type):
'x-image-meta-container-format': 'ovf',
'x-image-meta-property-os-type': os_type}
+ # If we have an auth_token, set an x-auth-token header
+ if auth_token:
+ ovf_headers['x-auth-token'] = auth_token
+
+ headers.update(ovf_headers)
+
for header, value in headers.iteritems():
conn.putheader(header, value)
conn.endheaders()
@@ -364,11 +392,12 @@ def download_vhd(session, args):
glance_port = params["glance_port"]
uuid_stack = params["uuid_stack"]
sr_path = params["sr_path"]
+ auth_token = params["auth_token"]
staging_path = _make_staging_area(sr_path)
try:
_download_tarball(sr_path, staging_path, image_id, glance_host,
- glance_port)
+ glance_port, auth_token)
# Right now, it's easier to return a single string via XenAPI,
# so we'll json encode the list of VHDs.
return json.dumps(_import_vhds(sr_path, staging_path, uuid_stack))
@@ -386,12 +415,13 @@ def upload_vhd(session, args):
glance_port = params["glance_port"]
sr_path = params["sr_path"]
os_type = params["os_type"]
+ auth_token = params["auth_token"]
staging_path = _make_staging_area(sr_path)
try:
_prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids)
_upload_tarball(staging_path, image_id, glance_host, glance_port,
- os_type)
+ os_type, auth_token)
finally:
_cleanup_staging_area(staging_path)
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
index ac1c50ad9..ac1c50ad9 100644..100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore b/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore
index d0313b4ed..d0313b4ed 100644..100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py
index f51f5fce4..f51f5fce4 100755..100644
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
index 292bbce12..292bbce12 100644..100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
diff --git a/po/ast.po b/po/ast.po
index be9910a2c..449cddb07 100644
--- a/po/ast.po
+++ b/po/ast.po
@@ -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
@@ -125,33 +125,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr ""
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr ""
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr ""
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr ""
-
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
#: ../nova/api/ec2/__init__.py:317
@@ -1778,34 +1751,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2263,10 +2208,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/cs.po b/po/cs.po
index 7c69e2f79..2dc763838 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -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
@@ -125,33 +125,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr ""
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr ""
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr ""
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr ""
-
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
#: ../nova/api/ec2/__init__.py:317
@@ -1778,34 +1751,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2265,10 +2210,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/da.po b/po/da.po
index d24d89fd9..570629119 100644
--- a/po/da.po
+++ b/po/da.po
@@ -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
@@ -125,33 +125,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr ""
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr ""
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr ""
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr ""
-
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
#: ../nova/api/ec2/__init__.py:317
@@ -1778,34 +1751,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2263,10 +2208,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/de.po b/po/de.po
index 8b4a00d72..772ae236c 100644
--- a/po/de.po
+++ b/po/de.po
@@ -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"
@@ -130,33 +131,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr ""
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr "PID-Datei %s existiert nicht. Läuft der Daemon nicht?\n"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr ""
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr "Alle vorhandenen FLAGS:"
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "%s wird gestartet"
-
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
#: ../nova/api/ec2/__init__.py:317
@@ -183,12 +157,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 +174,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 +189,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 +205,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 +273,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 +289,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 +352,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 +362,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 +559,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 +612,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
@@ -1783,34 +1758,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2268,10 +2215,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
@@ -2562,7 +2505,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 +2515,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 +2639,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 +2667,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 +2683,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 +2700,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 +2786,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
diff --git a/po/en_AU.po b/po/en_AU.po
new file mode 100644
index 000000000..3fa62c006
--- /dev/null
+++ b/po/en_AU.po
@@ -0,0 +1,2789 @@
+# English (Australia) translation for nova
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the nova package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+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-06-30 10:30+0000\n"
+"Last-Translator: Benny <Benjamin.Donald.Wilson.K@gmail.com>\n"
+"Language-Team: English (Australia) <en_AU@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-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 "No hosts found"
+
+#: ../nova/exception.py:33
+msgid "Unexpected error while running command."
+msgstr ""
+
+#: ../nova/exception.py:36
+#, python-format
+msgid ""
+"%(description)s\n"
+"Command: %(cmd)s\n"
+"Exit code: %(exit_code)s\n"
+"Stdout: %(stdout)r\n"
+"Stderr: %(stderr)r"
+msgstr ""
+
+#: ../nova/exception.py:107
+msgid "DB exception wrapped"
+msgstr ""
+
+#. exc_type, exc_value, exc_traceback = sys.exc_info()
+#: ../nova/exception.py:120
+msgid "Uncaught exception"
+msgstr ""
+
+#: ../nova/volume/api.py:45
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
+msgstr ""
+
+#: ../nova/volume/api.py:47
+#, python-format
+msgid "Volume quota exceeded. You cannot create a volume of size %sG"
+msgstr ""
+
+#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
+msgid "Volume status must be available"
+msgstr ""
+
+#: ../nova/volume/api.py:98
+msgid "Volume is already attached"
+msgstr ""
+
+#: ../nova/volume/api.py:104
+msgid "Volume is already detached"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:72
+msgid "Failed to read private ip"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:79
+msgid "Failed to read public ip(s)"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:152
+#, python-format
+msgid "%(param)s property not found for image %(_image_id)s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:168
+msgid "No keypairs defined"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:238
+#, python-format
+msgid "Compute.api::lock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:253
+#, python-format
+msgid "Compute.api::unlock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:267
+#, python-format
+msgid "Compute.api::get_lock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:281
+#, python-format
+msgid "Compute.api::reset_network %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:292
+#, python-format
+msgid "Compute.api::pause %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:303
+#, python-format
+msgid "Compute.api::unpause %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:314
+#, python-format
+msgid "compute.api::suspend %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:325
+#, python-format
+msgid "compute.api::resume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
+#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
+#: ../nova/api/ec2/__init__.py:317
+#, python-format
+msgid "Instance %s not found"
+msgstr ""
+
+#. NOTE: No Resource Pool concept so far
+#: ../nova/virt/xenapi/volumeops.py:51
+#, python-format
+msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:69
+#, python-format
+msgid "Unable to create VDI on SR %(sr_ref)s for instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:80
+#, python-format
+msgid "Unable to use SR %(sr_ref)s for instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:91
+#, python-format
+msgid "Unable to attach volume to instance %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:93
+#, python-format
+msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
+msgstr ""
+
+#. Detach VBD from VM
+#: ../nova/virt/xenapi/volumeops.py:104
+#, python-format
+msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:112
+#, python-format
+msgid "Unable to locate volume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:120
+#, python-format
+msgid "Unable to detach volume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:127
+#, python-format
+msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/compute/instance_types.py:41
+#, python-format
+msgid "Unknown instance type: %s"
+msgstr ""
+
+#: ../nova/crypto.py:46
+msgid "Filename of root CA"
+msgstr ""
+
+#: ../nova/crypto.py:49
+msgid "Filename of private key"
+msgstr ""
+
+#: ../nova/crypto.py:51
+msgid "Filename of root Certificate Revokation List"
+msgstr ""
+
+#: ../nova/crypto.py:53
+msgid "Where we keep our keys"
+msgstr ""
+
+#: ../nova/crypto.py:55
+msgid "Where we keep our root CA"
+msgstr ""
+
+#: ../nova/crypto.py:57
+msgid "Should we use a CA for each project?"
+msgstr ""
+
+#: ../nova/crypto.py:61
+#, python-format
+msgid "Subject for certificate for users, %s for project, user, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:66
+#, python-format
+msgid "Subject for certificate for projects, %s for project, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:71
+#, python-format
+msgid "Subject for certificate for vpns, %s for project, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:258
+#, python-format
+msgid "Flags path: %s"
+msgstr ""
+
+#: ../nova/scheduler/manager.py:69
+#, python-format
+msgid "Casting to %(topic)s %(host)s for %(method)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:78
+#, python-format
+msgid "check_instance_lock: decorating: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:80
+#, python-format
+msgid ""
+"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:84
+#, python-format
+msgid "check_instance_lock: locked: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:86
+#, python-format
+msgid "check_instance_lock: admin: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:91
+#, python-format
+msgid "check_instance_lock: executing: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:95
+#, python-format
+msgid "check_instance_lock: not executing |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:179
+msgid "Instance has already been created"
+msgstr ""
+
+#: ../nova/compute/manager.py:180
+#, python-format
+msgid "instance %s: starting..."
+msgstr ""
+
+#. pylint: disable=W0702
+#: ../nova/compute/manager.py:219
+#, python-format
+msgid "instance %s: Failed to spawn"
+msgstr ""
+
+#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
+#, python-format
+msgid "Terminating instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:255
+#, python-format
+msgid "Deallocating address %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:268
+#, python-format
+msgid "trying to destroy already destroyed instance: %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:282
+#, python-format
+msgid "Rebooting instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:287
+#, python-format
+msgid ""
+"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:311
+#, python-format
+msgid "instance %s: snapshotting"
+msgstr ""
+
+#: ../nova/compute/manager.py:316
+#, python-format
+msgid ""
+"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:332
+#, python-format
+msgid ""
+"trying to reset the password on a non-running instance: %(instance_id)s "
+"(state: %(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:335
+#, python-format
+msgid "instance %s: setting admin password"
+msgstr ""
+
+#: ../nova/compute/manager.py:353
+#, python-format
+msgid ""
+"trying to inject a file into a non-running instance: %(instance_id)s (state: "
+"%(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:362
+#, python-format
+msgid "instance %(nm)s: injecting file to %(plain_path)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:372
+#, python-format
+msgid "instance %s: rescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:387
+#, python-format
+msgid "instance %s: unrescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:406
+#, python-format
+msgid "instance %s: pausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:423
+#, python-format
+msgid "instance %s: unpausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:440
+#, python-format
+msgid "instance %s: retrieving diagnostics"
+msgstr ""
+
+#: ../nova/compute/manager.py:453
+#, python-format
+msgid "instance %s: suspending"
+msgstr ""
+
+#: ../nova/compute/manager.py:472
+#, python-format
+msgid "instance %s: resuming"
+msgstr ""
+
+#: ../nova/compute/manager.py:491
+#, python-format
+msgid "instance %s: locking"
+msgstr ""
+
+#: ../nova/compute/manager.py:503
+#, python-format
+msgid "instance %s: unlocking"
+msgstr ""
+
+#: ../nova/compute/manager.py:513
+#, python-format
+msgid "instance %s: getting locked state"
+msgstr ""
+
+#: ../nova/compute/manager.py:526
+#, python-format
+msgid "instance %s: reset network"
+msgstr ""
+
+#: ../nova/compute/manager.py:535 ../nova/api/ec2/cloud.py:515
+#, python-format
+msgid "Get console output for instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:543
+#, python-format
+msgid "instance %s: getting ajax console"
+msgstr ""
+
+#: ../nova/compute/manager.py:553
+#, python-format
+msgid ""
+"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
+msgstr ""
+
+#. pylint: disable=W0702
+#. NOTE(vish): The inline callback eats the exception info so we
+#. log the traceback here and reraise the same
+#. ecxception below.
+#: ../nova/compute/manager.py:569
+#, python-format
+msgid "instance %(instance_id)s: attach failed %(mountpoint)s, removing"
+msgstr ""
+
+#: ../nova/compute/manager.py:585
+#, python-format
+msgid ""
+"Detach volume %(volume_id)s from mountpoint %(mp)s on instance "
+"%(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:588
+#, python-format
+msgid "Detaching volume from unknown instance %s"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:53
+#, python-format
+msgid "Host %s is not alive"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:65
+msgid "All hosts have too many cores"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:87
+#, python-format
+msgid "Host %s not available"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:99
+msgid "All hosts have too many gigabytes"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:119
+msgid "All hosts have too many networks"
+msgstr ""
+
+#: ../nova/volume/manager.py:85
+#, python-format
+msgid "Re-exporting %s volumes"
+msgstr ""
+
+#: ../nova/volume/manager.py:90
+#, python-format
+msgid "volume %s: skipping export"
+msgstr ""
+
+#: ../nova/volume/manager.py:96
+#, python-format
+msgid "volume %s: creating"
+msgstr ""
+
+#: ../nova/volume/manager.py:108
+#, python-format
+msgid "volume %(vol_name)s: creating lv of size %(vol_size)sG"
+msgstr ""
+
+#: ../nova/volume/manager.py:112
+#, python-format
+msgid "volume %s: creating export"
+msgstr ""
+
+#: ../nova/volume/manager.py:123
+#, python-format
+msgid "volume %s: created successfully"
+msgstr ""
+
+#: ../nova/volume/manager.py:131
+msgid "Volume is still attached"
+msgstr ""
+
+#: ../nova/volume/manager.py:133
+msgid "Volume is not local to this node"
+msgstr ""
+
+#: ../nova/volume/manager.py:136
+#, python-format
+msgid "volume %s: removing export"
+msgstr ""
+
+#: ../nova/volume/manager.py:138
+#, python-format
+msgid "volume %s: deleting"
+msgstr ""
+
+#: ../nova/volume/manager.py:147
+#, python-format
+msgid "volume %s: deleted successfully"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:74
+#, python-format
+msgid "%(text)s: _db_content => %(content)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:304 ../nova/virt/xenapi/fake.py:404
+#: ../nova/virt/xenapi/fake.py:422 ../nova/virt/xenapi/fake.py:478
+msgid "Raising NotImplemented"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:306
+#, python-format
+msgid "xenapi.fake does not have an implementation for %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:341
+#, python-format
+msgid "Calling %(localname)s %(impl)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:346
+#, python-format
+msgid "Calling getter %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:406
+#, python-format
+msgid ""
+"xenapi.fake does not have an implementation for %s or it has been called "
+"with the wrong number of arguments"
+msgstr ""
+
+#: ../nova/tests/test_cloud.py:256
+msgid "Can't test instances without a real virtual env."
+msgstr ""
+
+#: ../nova/tests/test_cloud.py:268
+#, python-format
+msgid "Need to watch instance %s until it's running..."
+msgstr ""
+
+#: ../nova/virt/connection.py:73
+msgid "Failed to open connection to the hypervisor"
+msgstr ""
+
+#: ../nova/network/linux_net.py:187
+#, python-format
+msgid "Starting VLAN inteface %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:208
+#, python-format
+msgid "Starting Bridge interface for %s"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:314
+#, python-format
+msgid "Hupping dnsmasq threw %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:316
+#, python-format
+msgid "Pid %d is stale, relaunching dnsmasq"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:358
+#, python-format
+msgid "killing radvd threw %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:360
+#, python-format
+msgid "Pid %d is stale, relaunching radvd"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:449
+#, python-format
+msgid "Killing dnsmasq threw %s"
+msgstr ""
+
+#: ../nova/utils.py:58
+#, python-format
+msgid "Inner Exception: %s"
+msgstr ""
+
+#: ../nova/utils.py:59
+#, python-format
+msgid "Class %s cannot be found"
+msgstr ""
+
+#: ../nova/utils.py:118
+#, python-format
+msgid "Fetching %s"
+msgstr ""
+
+#: ../nova/utils.py:130
+#, python-format
+msgid "Running cmd (subprocess): %s"
+msgstr ""
+
+#: ../nova/utils.py:143 ../nova/utils.py:183
+#, python-format
+msgid "Result was %s"
+msgstr ""
+
+#: ../nova/utils.py:159
+#, python-format
+msgid "Running cmd (SSH): %s"
+msgstr ""
+
+#: ../nova/utils.py:217
+#, python-format
+msgid "debug in callback: %s"
+msgstr ""
+
+#: ../nova/utils.py:222
+#, python-format
+msgid "Running %s"
+msgstr ""
+
+#: ../nova/utils.py:262
+#, python-format
+msgid "Link Local address is not found.:%s"
+msgstr ""
+
+#: ../nova/utils.py:265
+#, python-format
+msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
+msgstr ""
+
+#: ../nova/utils.py:363
+#, python-format
+msgid "Invalid backend: %s"
+msgstr ""
+
+#: ../nova/utils.py:374
+#, python-format
+msgid "backend %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:49
+#, python-format
+msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:54
+#, python-format
+msgid "Publishing to route %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:84
+#, python-format
+msgid "Declaring queue %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:90
+#, python-format
+msgid "Declaring exchange %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:96
+#, python-format
+msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:121
+#, python-format
+msgid "Getting from %(queue)s: %(message)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
+#, python-format
+msgid "Created VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:138
+#, python-format
+msgid "Created VM %(instance_name)s as %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:168
+#, python-format
+msgid "Creating VBD for VM %(vm_ref)s, VDI %(vdi_ref)s ... "
+msgstr ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:187
+#, python-format
+msgid "VBD not found in instance %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:197
+#, python-format
+msgid "Unable to unplug VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:209
+#, python-format
+msgid "Unable to destroy VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:224
+#, python-format
+msgid "Creating VIF for VM %(vm_ref)s, network %(network_ref)s."
+msgstr ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:246
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(sr_ref)s."
+msgstr ""
+
+#. 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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:272
+#, python-format
+msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:286
+#, python-format
+msgid "Asking xapi to upload %(vdi_uuids)s as ID %(image_id)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:327
+#, python-format
+msgid "Size for image %(image)s:%(virtual_size)d"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:332
+#, python-format
+msgid "Glance image %s"
+msgstr ""
+
+#. 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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:352
+#, python-format
+msgid "Kernel/Ramdisk VDI %s destroyed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:361
+#, python-format
+msgid "Asking xapi to fetch %(url)s as %(access)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
+#, python-format
+msgid "Looking up vdi %s for PV kernel"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:397
+#, python-format
+msgid "PV Kernel in VDI:%s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:405
+#, python-format
+msgid "Running pygrub against %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:411
+#, python-format
+msgid "Found Xen kernel %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:413
+msgid "No Xen kernel found. Booting HVM."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
+#, python-format
+msgid "duplicate name found: %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:442
+#, python-format
+msgid "VDI %s is still available"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:463
+#, python-format
+msgid "(VM_UTILS) xenserver vm state -> |%s|"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:465
+#, python-format
+msgid "(VM_UTILS) xenapi power_state -> |%s|"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:525
+#, python-format
+msgid "VHD %(vdi_uuid)s has parent %(parent_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:542
+#, python-format
+msgid "Re-scanning SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:567
+#, python-format
+msgid ""
+"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:574
+#, python-format
+msgid ""
+"Parent %(parent_uuid)s doesn't match original parent "
+"%(original_parent_uuid)s, waiting for coalesce..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:590
+#, python-format
+msgid "No VDIs found for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:594
+#, python-format
+msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
+msgstr ""
+
+#: ../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 ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:657
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
+#, python-format
+msgid "Plugging VBD %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:659
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:194
+#, python-format
+msgid "Plugging VBD %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:661
+#, python-format
+msgid "VBD %(vbd)s plugged as %(orig_dev)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:664
+#, python-format
+msgid "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:668
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:197
+#, python-format
+msgid "Destroying VBD for VDI %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:671
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:200
+#, python-format
+msgid "Destroying VBD for VDI %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:683
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:211
+msgid "VBD.unplug successful first time."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:688
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:216
+msgid "VBD.unplug rejected: retrying..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:692
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:220
+msgid "VBD.unplug successful eventually."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:695
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:223
+#, python-format
+msgid "Ignoring XenAPI.Failure in VBD.unplug: %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:704
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:66
+#, python-format
+msgid "Ignoring XenAPI.Failure %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:735
+#, python-format
+msgid ""
+"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:747
+#, python-format
+msgid "Writing partition table %s done."
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:89
+#, python-format
+msgid "Nested received %(queue)s, %(value)s"
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:95
+#, python-format
+msgid "Nested return %s"
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:120 ../nova/tests/test_rpc.py:126
+#, python-format
+msgid "Received %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:44
+msgid "Use of empty request context is deprecated"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:133
+#, python-format
+msgid "No service for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:251
+#, python-format
+msgid "No service for %(host)s, %(binary)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:592
+msgid "No fixed ips defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:608
+#, python-format
+msgid "No floating ip for address %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:629
+#, python-format
+msgid "No address for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:961
+#, python-format
+msgid "no keypair for user %(user_id)s, name %(name)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1076 ../nova/db/sqlalchemy/api.py:1156
+#, python-format
+msgid "No network for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1086
+msgid "No networks defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1115
+#, python-format
+msgid "No network for bridge %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1129 ../nova/db/sqlalchemy/api.py:1142
+#, python-format
+msgid "No network for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1277
+#, python-format
+msgid "Token %s does not exist"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1302
+#, python-format
+msgid "No quota for project_id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1455 ../nova/db/sqlalchemy/api.py:1501
+#: ../nova/api/ec2/__init__.py:323
+#, python-format
+msgid "Volume %s not found"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1514
+#, python-format
+msgid "No export device found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1527
+#, python-format
+msgid "No target id found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1572
+#, python-format
+msgid "No security group with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1589
+#, python-format
+msgid "No security group named %(group_name)s for project: %(project_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1682
+#, python-format
+msgid "No secuity group rule with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1756
+#, python-format
+msgid "No user for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1772
+#, python-format
+msgid "No user for access key %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1834
+#, python-format
+msgid "No project with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1979
+#, python-format
+msgid "No console pool with id %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1996
+#, python-format
+msgid ""
+"No console pool of type %(console_type)s for compute host %(compute_host)s "
+"on proxy host %(host)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2035
+#, python-format
+msgid "No console for instance %(instance_id)s in pool %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2057
+#, python-format
+msgid "on instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2058
+#, python-format
+msgid "No console with id %(console_id)s %(idesc)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2078 ../nova/db/sqlalchemy/api.py:2097
+#, python-format
+msgid "No zone with id %(zone_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:160
+#, python-format
+msgid "Checking state of %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:165
+#, python-format
+msgid "Current state of %(name)s was %(state)s."
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:183
+#, python-format
+msgid "Connecting to libvirt: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:196
+msgid "Connection to libvirt broke"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:258
+#, python-format
+msgid "instance %(instance_name)s: deleting instance files %(target)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:283
+#, python-format
+msgid "Invalid device path %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:313
+#, python-format
+msgid "No disk at %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:320
+msgid "Instance snapshotting is not supported for libvirtat this time"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:336
+#, python-format
+msgid "instance %s: rebooted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:339
+#, python-format
+msgid "_wait_for_reboot failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:382
+#, python-format
+msgid "instance %s: rescued"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:385
+#, python-format
+msgid "_wait_for_rescue failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:411
+#, python-format
+msgid "instance %s: is running"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:422
+#, python-format
+msgid "instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:425 ../nova/virt/xenapi/vmops.py:186
+#, python-format
+msgid "instance %s: failed to boot"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:436
+#, python-format
+msgid "virsh said: %r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:440
+msgid "cool, it's a device"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:448
+#, python-format
+msgid "data: %(data)r, fpath: %(fpath)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:456
+#, python-format
+msgid "Contents of file %(fpath)s: %(contents)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:489
+msgid "Unable to find an open port"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:563
+#, python-format
+msgid "instance %s: Creating image"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:646
+#, python-format
+msgid "instance %(inst_name)s: injecting key into image %(img_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:649
+#, python-format
+msgid "instance %(inst_name)s: injecting net into image %(img_id)s"
+msgstr ""
+
+#. This could be a windows image, or a vmdk format disk
+#: ../nova/virt/libvirt_conn.py:657
+#, python-format
+msgid ""
+"instance %(inst_name)s: ignoring error injecting data into image %(img_id)s "
+"(%(e)s)"
+msgstr ""
+
+#. TODO(termie): cache?
+#: ../nova/virt/libvirt_conn.py:665
+#, python-format
+msgid "instance %s: starting toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:732
+#, python-format
+msgid "instance %s: finished toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:751
+msgid "diagnostics are not supported for libvirt"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:1225
+#, python-format
+msgid "Attempted to unfilter instance %s which is not filtered"
+msgstr ""
+
+#: ../nova/api/ec2/metadatarequesthandler.py:76
+#, python-format
+msgid "Failed to get metadata for ip: %s"
+msgstr ""
+
+#: ../nova/auth/fakeldap.py:33
+msgid "Attempted to instantiate singleton"
+msgstr ""
+
+#: ../nova/network/api.py:39
+#, python-format
+msgid "Quota exceeeded for %s, tried to allocate address"
+msgstr ""
+
+#: ../nova/network/api.py:42
+msgid "Address quota exceeded. You cannot allocate any more addresses"
+msgstr ""
+
+#: ../nova/tests/test_volume.py:162
+#, python-format
+msgid "Target %s allocated"
+msgstr ""
+
+#: ../nova/virt/images.py:70
+#, python-format
+msgid "Finished retreving %(url)s -- placed in %(path)s"
+msgstr ""
+
+#: ../nova/scheduler/driver.py:66
+msgid "Must implement a fallback schedule"
+msgstr ""
+
+#: ../nova/console/manager.py:70
+msgid "Adding console"
+msgstr ""
+
+#: ../nova/console/manager.py:90
+#, python-format
+msgid "Tried to remove non-existant console %(console_id)s."
+msgstr ""
+
+#: ../nova/api/direct.py:149
+msgid "not available"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:62
+#, python-format
+msgid "The key_pair %s already exists"
+msgstr ""
+
+#. TODO(vish): Do this with M2Crypto instead
+#: ../nova/api/ec2/cloud.py:118
+#, python-format
+msgid "Generating root CA: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:303
+#, python-format
+msgid "Create key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:311
+#, python-format
+msgid "Delete key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:386
+#, python-format
+msgid "%s is not a valid ipProtocol"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:390
+msgid "Invalid port range"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:421
+#, python-format
+msgid "Revoke security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:430 ../nova/api/ec2/cloud.py:459
+msgid "Not enough parameters to build a valid rule."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:443
+msgid "No rule for the specified parameters."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:450
+#, python-format
+msgid "Authorize security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:464
+#, python-format
+msgid "This rule already exists in group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:492
+#, python-format
+msgid "Create Security Group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:495
+#, python-format
+msgid "group %s already exists"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:507
+#, python-format
+msgid "Delete security group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:584
+#, python-format
+msgid "Create volume of %s GB"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:612
+#, python-format
+msgid "Attach volume %(volume_id)s to instance %(instance_id)s at %(device)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:629
+#, python-format
+msgid "Detach volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:761
+msgid "Allocate address"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:766
+#, python-format
+msgid "Release address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:771
+#, python-format
+msgid "Associate address %(public_ip)s to instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:780
+#, python-format
+msgid "Disassociate address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:807
+msgid "Going to start terminating instances"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:815
+#, python-format
+msgid "Reboot instance %r"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:867
+#, python-format
+msgid "De-registering image %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:875
+#, python-format
+msgid "Registered image %(image_location)s with id %(image_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:882 ../nova/api/ec2/cloud.py:900
+#, python-format
+msgid "attribute not supported: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:890
+#, python-format
+msgid "invalid id: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:903
+msgid "user or group not specified"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:905
+msgid "only group \"all\" is supported"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:907
+msgid "operation_type must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:908
+#, python-format
+msgid "Updating image %s publicity"
+msgstr ""
+
+#: ../bin/nova-api.py:52
+#, python-format
+msgid "Using paste.deploy config at: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:57
+#, python-format
+msgid "No paste configuration for app: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:59
+#, python-format
+msgid ""
+"App Config: %(api)s\n"
+"%(config)r"
+msgstr ""
+
+#: ../bin/nova-api.py:64
+#, python-format
+msgid "Running %s API"
+msgstr ""
+
+#: ../bin/nova-api.py:69
+#, python-format
+msgid "No known API applications configured in %s."
+msgstr ""
+
+#: ../bin/nova-api.py:83
+#, python-format
+msgid "Starting nova-api node (version %s)"
+msgstr ""
+
+#: ../bin/nova-api.py:89
+#, python-format
+msgid "No paste configuration found for: %s"
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:84
+#, python-format
+msgid "Argument %(key)s value %(value)s is too short."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:89
+#, python-format
+msgid "Argument %(key)s value %(value)s contains invalid characters."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:94
+#, python-format
+msgid "Argument %(key)s value %(value)s starts with a hyphen."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:102
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:130
+#, python-format
+msgid "Argument %s is required."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:117
+#, python-format
+msgid ""
+"Argument %(key)s may not take value %(value)s. Valid values are ['true', "
+"'false']."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:163
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) on %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:67
+#, python-format
+msgid "Attempted to create non-unique name %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:73
+#, python-format
+msgid "instance %(name)s: not enough free memory"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:148
+#, python-format
+msgid "Starting VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:151
+#, python-format
+msgid "Spawning VM %(instance_name)s created %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:162
+#, python-format
+msgid "Invalid value for onset_files: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:167
+#, python-format
+msgid "Injecting file path: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:180
+#, python-format
+msgid "Instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:232
+#, python-format
+msgid "Instance not present %s"
+msgstr ""
+
+#. TODO(sirp): Add quiesce and VSS locking support when Windows support
+#. is added
+#: ../nova/virt/xenapi/vmops.py:261
+#, python-format
+msgid "Starting snapshot for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:269
+#, python-format
+msgid "Unable to Snapshot %(vm_ref)s: %(exc)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:280
+#, python-format
+msgid "Finished snapshot and upload for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:356
+#, python-format
+msgid "VM %(vm)s already halted, skipping shutdown..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:389
+msgid "Removing kernel/ramdisk files"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:399
+msgid "kernel/ramdisk files removed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:561
+#, python-format
+msgid ""
+"TIMEOUT: The call to %(method)s timed out. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:564
+#, python-format
+msgid ""
+"NOT IMPLEMENTED: The call to %(method)s is not supported by the agent. VM "
+"id=%(instance_id)s; args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:569
+#, python-format
+msgid ""
+"The call to %(method)s returned an error: %(e)s. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:760
+#, python-format
+msgid "OpenSSL error: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:148
+#, python-format
+msgid "Running instances: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:154
+#, python-format
+msgid "After terminating instances: %s"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:45
+msgid "Template for script to run on cloudpipe instance boot"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:48
+msgid "Network to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:51
+msgid "Netmask to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:97
+#, python-format
+msgid "Launching VPN for %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/migration.py:35
+msgid "python-migrate is not installed. Exiting."
+msgstr ""
+
+#: ../nova/image/s3.py:99
+#, python-format
+msgid "Image %s could not be found"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:121
+msgid "Too many failed authentications."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:131
+#, python-format
+msgid ""
+"Access key %(access_key)s has had %(failures)d failed authentications and "
+"will be locked out for %(lock_mins)d minutes."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:169 ../nova/objectstore/handler.py:140
+#, python-format
+msgid "Authentication Failure: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:182
+#, python-format
+msgid "Authenticated Request For %(uname)s:%(pname)s)"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:207
+#, python-format
+msgid "action: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:209
+#, python-format
+msgid "arg: %(key)s\t\tval: %(value)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:281
+#, python-format
+msgid ""
+"Unauthorized request for controller=%(controller)s and action=%(action)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:314
+#, python-format
+msgid "InstanceNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:320
+#, python-format
+msgid "VolumeNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:326
+#, python-format
+msgid "NotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:329
+#, python-format
+msgid "ApiError raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:338
+#, python-format
+msgid "Unexpected error raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:343
+msgid "An unknown error has occurred. Please try your request again."
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:84
+#, python-format
+msgid "User %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:106 ../nova/auth/ldapdriver.py:232
+#, python-format
+msgid "Project can't be created because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:122 ../nova/auth/ldapdriver.py:243
+#, python-format
+msgid "Project can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:135 ../nova/auth/ldapdriver.py:229
+#, python-format
+msgid "Project can't be created because project %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:157 ../nova/auth/ldapdriver.py:268
+#, python-format
+msgid "Project can't be modified because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:245
+#, python-format
+msgid "User \"%s\" not found"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:248
+#, python-format
+msgid "Project \"%s\" not found"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:129
+msgid ""
+"Must specify xenapi_connection_url, xenapi_connection_username (optionally), "
+"and xenapi_connection_password to use connection_type=xenapi"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:311
+#, python-format
+msgid "Task [%(name)s] %(task)s status: success %(result)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:317
+#, python-format
+msgid "Task [%(name)s] %(task)s status: %(status)s %(error_info)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:331 ../nova/virt/xenapi_conn.py:344
+#, python-format
+msgid "Got exception: %s"
+msgstr ""
+
+#: ../nova/volume/san.py:67
+#, python-format
+msgid "Could not find iSCSI export for volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/apirequest.py:100
+#, python-format
+msgid ""
+"Unsupported API request: controller = %(controller)s, action = %(action)s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:55
+#, python-format
+msgid "Caught error: %s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:76
+msgid "Including admin operations in API."
+msgstr ""
+
+#: ../nova/console/xvp.py:99
+msgid "Rebuilding xvp conf"
+msgstr ""
+
+#: ../nova/console/xvp.py:116
+#, python-format
+msgid "Re-wrote %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:121
+msgid "Stopping xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:134
+msgid "Starting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:141
+#, python-format
+msgid "Error starting xvp: %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:144
+msgid "Restarting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:146
+msgid "xvp not running..."
+msgstr ""
+
+#: ../bin/nova-manage.py:272
+msgid ""
+"The above error may show that the database has not been created.\n"
+"Please create a database using nova-manage sync db before running this "
+"command."
+msgstr ""
+
+#: ../bin/nova-manage.py:426
+msgid ""
+"No more networks available. If this is a new installation, you need\n"
+"to call something like this:\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
+msgstr ""
+
+#: ../bin/nova-manage.py:431
+msgid ""
+"The above error may show that the certificate db has not been created.\n"
+"Please create a database by running a nova-api server on this host."
+msgstr ""
+
+#: ../bin/nova-manage.py:447 ../bin/nova-manage.py:536
+msgid "network"
+msgstr ""
+
+#: ../bin/nova-manage.py:448
+msgid "IP address"
+msgstr ""
+
+#: ../bin/nova-manage.py:449
+msgid "MAC address"
+msgstr ""
+
+#: ../bin/nova-manage.py:450
+msgid "hostname"
+msgstr ""
+
+#: ../bin/nova-manage.py:451
+msgid "host"
+msgstr ""
+
+#: ../bin/nova-manage.py:537
+msgid "netmask"
+msgstr ""
+
+#: ../bin/nova-manage.py:538
+msgid "start address"
+msgstr ""
+
+#: ../nova/virt/disk.py:69
+#, python-format
+msgid "Failed to load partition: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:91
+#, python-format
+msgid "Failed to mount filesystem: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:124
+#, python-format
+msgid "nbd device %s did not show up"
+msgstr ""
+
+#: ../nova/virt/disk.py:128
+#, python-format
+msgid "Could not attach image to loopback: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:151
+msgid "No free nbd devices"
+msgstr ""
+
+#: ../doc/ext/nova_todo.py:46
+#, python-format
+msgid "%(filename)s, line %(line_info)d"
+msgstr ""
+
+#. FIXME(chiradeep): implement this
+#: ../nova/virt/hyperv.py:118
+msgid "In init host"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:131
+#, python-format
+msgid "Attempt to create duplicate vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:148
+#, python-format
+msgid "Starting VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:150
+#, python-format
+msgid "Started VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:152
+#, python-format
+msgid "spawn vm failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:169
+#, python-format
+msgid "Failed to create VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:188
+#, python-format
+msgid "Set memory for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:198
+#, python-format
+msgid "Set vcpus for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:202
+#, python-format
+msgid "Creating disk for %(vm_name)s by attaching disk file %(vhdfile)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:227
+#, python-format
+msgid "Failed to add diskdrive to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:230
+#, python-format
+msgid "New disk drive path is %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:247
+#, python-format
+msgid "Failed to add vhd file to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:249
+#, python-format
+msgid "Created disk for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:253
+#, python-format
+msgid "Creating nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:272
+msgid "Failed creating a port on the external vswitch"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:273
+#, python-format
+msgid "Failed creating port for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:276
+#, python-format
+msgid "Created switch port %(vm_name)s on switch %(ext_path)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:286
+#, python-format
+msgid "Failed to add nic to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:288
+#, python-format
+msgid "Created nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:321
+#, python-format
+msgid "WMI job failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:325
+#, python-format
+msgid "WMI job succeeded: %(desc)s, Elapsed=%(elap)s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:361
+#, python-format
+msgid "Got request to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:386
+#, python-format
+msgid "Failed to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:393
+#, python-format
+msgid "Del: disk %(vhdfile)s vm %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:415
+#, python-format
+msgid ""
+"Got Info for vm %(instance_id)s: state=%(state)s, mem=%(memusage)s, "
+"num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:451
+#, python-format
+msgid "Successfully changed vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:454
+#, python-format
+msgid "Failed to change vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/compute/api.py:71
+#, python-format
+msgid "Instance %d was not found in get_network_topic"
+msgstr ""
+
+#: ../nova/compute/api.py:77
+#, python-format
+msgid "Instance %d has no host"
+msgstr ""
+
+#: ../nova/compute/api.py:97
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to run %(min_count)s instances"
+msgstr ""
+
+#: ../nova/compute/api.py:99
+#, python-format
+msgid ""
+"Instance quota exceeded. You can only run %s more instances of this type."
+msgstr ""
+
+#: ../nova/compute/api.py:112
+msgid "Creating a raw instance"
+msgstr ""
+
+#: ../nova/compute/api.py:160
+#, python-format
+msgid "Going to run %s instances..."
+msgstr ""
+
+#: ../nova/compute/api.py:187
+#, python-format
+msgid "Casting to scheduler for %(pid)s/%(uid)s's instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/api.py:292
+#, python-format
+msgid "Going to try to terminate %s"
+msgstr ""
+
+#: ../nova/compute/api.py:296
+#, python-format
+msgid "Instance %d was not found during terminate"
+msgstr ""
+
+#: ../nova/compute/api.py:301
+#, python-format
+msgid "Instance %d is already being terminated"
+msgstr ""
+
+#: ../nova/compute/api.py:481
+#, python-format
+msgid "Invalid device specified: %s. Example device: /dev/vdb"
+msgstr ""
+
+#: ../nova/compute/api.py:496
+msgid "Volume isn't attached to anything!"
+msgstr ""
+
+#: ../nova/rpc.py:98
+#, python-format
+msgid ""
+"AMQP server on %(fl_host)s:%(fl_port)d is unreachable. Trying again in "
+"%(fl_intv)d seconds."
+msgstr ""
+
+#: ../nova/rpc.py:103
+#, python-format
+msgid "Unable to connect to AMQP server after %d tries. Shutting down."
+msgstr ""
+
+#: ../nova/rpc.py:122
+msgid "Reconnected to queue"
+msgstr ""
+
+#: ../nova/rpc.py:129
+msgid "Failed to fetch message from queue"
+msgstr ""
+
+#: ../nova/rpc.py:159
+#, python-format
+msgid "Initing the Adapter Consumer for %s"
+msgstr ""
+
+#: ../nova/rpc.py:178
+#, python-format
+msgid "received %s"
+msgstr ""
+
+#. NOTE(vish): we may not want to ack here, but that means that bad
+#. messages stay in the queue indefinitely, so for now
+#. we just log the message and send an error string
+#. back to the caller
+#: ../nova/rpc.py:191
+#, python-format
+msgid "no method for message: %s"
+msgstr ""
+
+#: ../nova/rpc.py:192
+#, python-format
+msgid "No method for message: %s"
+msgstr ""
+
+#: ../nova/rpc.py:253
+#, python-format
+msgid "Returning exception %s to caller"
+msgstr ""
+
+#: ../nova/rpc.py:294
+#, python-format
+msgid "unpacked context: %s"
+msgstr ""
+
+#: ../nova/rpc.py:313
+msgid "Making asynchronous call..."
+msgstr ""
+
+#: ../nova/rpc.py:316
+#, python-format
+msgid "MSG_ID is %s"
+msgstr ""
+
+#: ../nova/rpc.py:354
+msgid "Making asynchronous cast..."
+msgstr ""
+
+#: ../nova/rpc.py:364
+#, python-format
+msgid "response %s"
+msgstr ""
+
+#: ../nova/rpc.py:373
+#, python-format
+msgid "topic is %s"
+msgstr ""
+
+#: ../nova/rpc.py:374
+#, python-format
+msgid "message %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:78
+#, python-format
+msgid "Recovering from a failed execute. Try number %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:87
+#, python-format
+msgid "volume group %s doesn't exist"
+msgstr ""
+
+#: ../nova/volume/driver.py:220
+#, python-format
+msgid "FAKE AOE: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:233
+msgid "Skipping ensure_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:279 ../nova/volume/driver.py:288
+msgid "Skipping remove_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:347
+#, python-format
+msgid "FAKE ISCSI: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:359
+#, python-format
+msgid "rbd has no pool %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:414
+#, python-format
+msgid "Sheepdog is not working: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:416
+msgid "Sheepdog is not working"
+msgstr ""
+
+#: ../nova/wsgi.py:68
+#, python-format
+msgid "Starting %(arg0)s on %(host)s:%(port)s"
+msgstr ""
+
+#: ../nova/wsgi.py:147
+msgid "You must implement __call__"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:58
+msgid "leasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:73
+msgid "Adopted old lease or got a change of mac/hostname"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:80
+msgid "releasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:123
+#, python-format
+msgid ""
+"Called %(action)s for mac %(mac)s with ip %(ip)s and hostname %(hostname)s "
+"on interface %(interface)s"
+msgstr ""
+
+#: ../nova/virt/fake.py:239
+#, python-format
+msgid "Instance %s Not Found"
+msgstr ""
+
+#: ../nova/network/manager.py:153
+#, python-format
+msgid "Dissassociated %s stale fixed ip(s)"
+msgstr ""
+
+#: ../nova/network/manager.py:157
+msgid "setting network host"
+msgstr ""
+
+#: ../nova/network/manager.py:212
+#, python-format
+msgid "Leasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:216
+#, python-format
+msgid "IP %s leased that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:220
+#, python-format
+msgid "IP %(address)s leased to bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:228
+#, python-format
+msgid "IP %s leased that was already deallocated"
+msgstr ""
+
+#: ../nova/network/manager.py:233
+#, python-format
+msgid "Releasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:237
+#, python-format
+msgid "IP %s released that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:241
+#, python-format
+msgid "IP %(address)s released from bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:244
+#, python-format
+msgid "IP %s released that was not leased"
+msgstr ""
+
+#: ../nova/network/manager.py:519
+msgid ""
+"The sum between the number of networks and the vlan start cannot be greater "
+"than 4094"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:57
+#, python-format
+msgid "Introducing %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:74
+#, python-format
+msgid "Introduced %(label)s as %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:78
+msgid "Unable to create Storage Repository"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:90
+#, python-format
+msgid "Unable to find SR from VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:96
+#, python-format
+msgid "Forgetting SR %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:101
+#, python-format
+msgid "Ignoring exception %(exc)s when getting PBDs for %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:107
+#, python-format
+msgid "Ignoring exception %(exc)s when unplugging PBD %(pbd)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:111
+#, python-format
+msgid "Forgetting SR %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:113
+#, python-format
+msgid "Ignoring exception %(exc)s when forgetting SR %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:123
+#, python-format
+msgid "Unable to introduce VDI on SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:128
+#, python-format
+msgid "Unable to get record of VDI %s on"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:146
+#, python-format
+msgid "Unable to introduce VDI for SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:175
+#, python-format
+msgid "Unable to obtain target information %(device_path)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:197
+#, python-format
+msgid "Mountpoint cannot be translated: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:262
+#, python-format
+msgid "Failed to decrypt private key: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:269
+#, python-format
+msgid "Failed to decrypt initialization vector: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:277
+#, python-format
+msgid "Failed to decrypt image file %(image_file)s: %(err)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:106
+#, python-format
+msgid "Unknown S3 value type %r"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:137
+msgid "Authenticated request"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:182
+msgid "List of buckets requested"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:209
+#, python-format
+msgid "List keys for bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:217
+#, python-format
+msgid "Unauthorized attempt to access bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:235
+#, python-format
+msgid "Creating bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:245
+#, python-format
+msgid "Deleting bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:249
+#, python-format
+msgid "Unauthorized attempt to delete bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:273
+#, python-format
+msgid "Getting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:276
+#, python-format
+msgid "Unauthorized attempt to get object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:296
+#, python-format
+msgid "Putting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:299
+#, python-format
+msgid "Unauthorized attempt to upload object %(nm)s to bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:318
+#, python-format
+msgid "Deleting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:322
+#, python-format
+msgid "Unauthorized attempt to delete object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:396
+#, python-format
+msgid "Not authorized to upload image: invalid directory %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:404
+#, python-format
+msgid "Not authorized to upload image: unauthorized bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:409
+#, python-format
+msgid "Starting image upload: %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:423
+#, python-format
+msgid "Not authorized to update attributes of image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:431
+#, python-format
+msgid "Toggling publicity flag of image %(image_id)s %(newstatus)r"
+msgstr ""
+
+#. other attributes imply update
+#: ../nova/objectstore/handler.py:436
+#, python-format
+msgid "Updating user fields on image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:450
+#, python-format
+msgid "Unauthorized attempt to delete image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:455
+#, python-format
+msgid "Deleted image: %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:259
+#, python-format
+msgid "Looking up user: %r"
+msgstr ""
+
+#: ../nova/auth/manager.py:263
+#, python-format
+msgid "Failed authorization for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:264
+#, python-format
+msgid "No user found for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:270
+#, python-format
+msgid "Using project name = user name (%s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:277
+#, python-format
+msgid "failed authorization: no project named %(pjid)s (user=%(uname)s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:279
+#, python-format
+msgid "No project called %s could be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:287
+#, python-format
+msgid ""
+"Failed authorization: user %(uname)s not admin and not member of project "
+"%(pjname)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:289
+#, python-format
+msgid "User %(uid)s is not a member of project %(pjid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:298 ../nova/auth/manager.py:309
+#, python-format
+msgid "Invalid signature for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:299 ../nova/auth/manager.py:310
+msgid "Signature does not match"
+msgstr ""
+
+#: ../nova/auth/manager.py:380
+msgid "Must specify project"
+msgstr ""
+
+#: ../nova/auth/manager.py:414
+#, python-format
+msgid "The %s role can not be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:416
+#, python-format
+msgid "The %s role is global only"
+msgstr ""
+
+#: ../nova/auth/manager.py:420
+#, python-format
+msgid "Adding role %(role)s to user %(uid)s in project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:423
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:448
+#, python-format
+msgid "Removing role %(role)s from user %(uid)s on project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:451
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:515
+#, python-format
+msgid "Created project %(name)s with manager %(manager_user)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:533
+#, python-format
+msgid "modifying project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:545
+#, python-format
+msgid "Adding user %(uid)s to project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:566
+#, python-format
+msgid "Remove user %(uid)s from project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:592
+#, python-format
+msgid "Deleting project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:650
+#, python-format
+msgid "Created user %(rvname)s (admin: %(rvadmin)r)"
+msgstr ""
+
+#: ../nova/auth/manager.py:659
+#, python-format
+msgid "Deleting user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:669
+#, python-format
+msgid "Access Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:671
+#, python-format
+msgid "Secret Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:673
+#, python-format
+msgid "Admin status set to %(admin)r for user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:722
+#, python-format
+msgid "No vpn data for project %s"
+msgstr ""
+
+#: ../nova/service.py:161
+#, python-format
+msgid "Starting %(topic)s node (version %(vcs_string)s)"
+msgstr ""
+
+#: ../nova/service.py:174
+msgid "Service killed that has no database entry"
+msgstr ""
+
+#: ../nova/service.py:195
+msgid "The service database object disappeared, Recreating it."
+msgstr ""
+
+#: ../nova/service.py:207
+msgid "Recovered model server connection!"
+msgstr ""
+
+#: ../nova/service.py:213
+msgid "model server went away"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:174
+#, python-format
+msgid "LDAP user %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:205
+#, python-format
+msgid "LDAP object for %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:348
+#, python-format
+msgid "User %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:472
+#, python-format
+msgid "Group can't be created because group %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:478
+#, python-format
+msgid "Group can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:495
+#, python-format
+msgid "User %s can't be searched in group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:507
+#, python-format
+msgid "User %s can't be added to the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
+#, python-format
+msgid "The group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:513
+#, python-format
+msgid "User %(uid)s is already a member of the group %(group_dn)s"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:524
+#, python-format
+msgid ""
+"User %s can't be removed from the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:528
+#, python-format
+msgid "User %s is not a member of the group"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:542
+#, python-format
+msgid ""
+"Attempted to remove the last member of a group. Deleting the group at %s "
+"instead."
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:549
+#, python-format
+msgid "User %s can't be removed from all because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:564
+#, python-format
+msgid "Group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:40
+#, python-format
+msgid "Found non-unique network for bridge %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:43
+#, python-format
+msgid "Found no network for bridge %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:97
+#, python-format
+msgid "Creating new user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:105
+#, python-format
+msgid "Deleting user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:127
+#, python-format
+msgid "Adding role %(role)s to user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:131
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:137
+#, python-format
+msgid "Removing role %(role)s from user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:141
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:146 ../nova/api/ec2/admin.py:223
+msgid "operation must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:159
+#, python-format
+msgid "Getting x509 for user: %(name)s on project: %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:177
+#, python-format
+msgid "Create project %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:190
+#, python-format
+msgid "Modify project: %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:200
+#, python-format
+msgid "Delete project: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:214
+#, python-format
+msgid "Adding user %(user)s to project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:218
+#, python-format
+msgid "Removing user %(user)s from project %(project)s"
+msgstr ""
diff --git a/po/en_GB.po b/po/en_GB.po
new file mode 100644
index 000000000..b204c93a1
--- /dev/null
+++ b/po/en_GB.po
@@ -0,0 +1,2814 @@
+# English (United Kingdom) translation for nova
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the nova package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+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-06-19 18:14+0000\n"
+"Last-Translator: Dave Walker <davewalker@ubuntu.com>\n"
+"Language-Team: English (United Kingdom) <en_GB@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-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 "No hosts found"
+
+#: ../nova/exception.py:33
+msgid "Unexpected error while running command."
+msgstr "Unexpected error while running command."
+
+#: ../nova/exception.py:36
+#, python-format
+msgid ""
+"%(description)s\n"
+"Command: %(cmd)s\n"
+"Exit code: %(exit_code)s\n"
+"Stdout: %(stdout)r\n"
+"Stderr: %(stderr)r"
+msgstr ""
+"%(description)s\n"
+"Command: %(cmd)s\n"
+"Exit code: %(exit_code)s\n"
+"Stdout: %(stdout)r\n"
+"Stderr: %(stderr)r"
+
+#: ../nova/exception.py:107
+msgid "DB exception wrapped"
+msgstr "DB exception wrapped"
+
+#. exc_type, exc_value, exc_traceback = sys.exc_info()
+#: ../nova/exception.py:120
+msgid "Uncaught exception"
+msgstr "Uncaught exception"
+
+#: ../nova/volume/api.py:45
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
+msgstr "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
+
+#: ../nova/volume/api.py:47
+#, python-format
+msgid "Volume quota exceeded. You cannot create a volume of size %sG"
+msgstr "Volume quota exceeded. You cannot create a volume of size %sG"
+
+#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
+msgid "Volume status must be available"
+msgstr "Volume status must be available"
+
+#: ../nova/volume/api.py:98
+msgid "Volume is already attached"
+msgstr "Volume is already attached"
+
+#: ../nova/volume/api.py:104
+msgid "Volume is already detached"
+msgstr "Volume is already detached"
+
+#: ../nova/api/openstack/servers.py:72
+msgid "Failed to read private ip"
+msgstr "Failed to read private ip"
+
+#: ../nova/api/openstack/servers.py:79
+msgid "Failed to read public ip(s)"
+msgstr "Failed to read public ip(s)"
+
+#: ../nova/api/openstack/servers.py:152
+#, python-format
+msgid "%(param)s property not found for image %(_image_id)s"
+msgstr "%(param)s property not found for image %(_image_id)s"
+
+#: ../nova/api/openstack/servers.py:168
+msgid "No keypairs defined"
+msgstr "No keypairs defined"
+
+#: ../nova/api/openstack/servers.py:238
+#, python-format
+msgid "Compute.api::lock %s"
+msgstr "Compute.api::lock %s"
+
+#: ../nova/api/openstack/servers.py:253
+#, python-format
+msgid "Compute.api::unlock %s"
+msgstr "Compute.api::unlock %s"
+
+#: ../nova/api/openstack/servers.py:267
+#, python-format
+msgid "Compute.api::get_lock %s"
+msgstr "Compute.api::get_lock %s"
+
+#: ../nova/api/openstack/servers.py:281
+#, python-format
+msgid "Compute.api::reset_network %s"
+msgstr "Compute.api::reset_network %s"
+
+#: ../nova/api/openstack/servers.py:292
+#, python-format
+msgid "Compute.api::pause %s"
+msgstr "Compute.api::pause %s"
+
+#: ../nova/api/openstack/servers.py:303
+#, python-format
+msgid "Compute.api::unpause %s"
+msgstr "Compute.api::unpause %s"
+
+#: ../nova/api/openstack/servers.py:314
+#, python-format
+msgid "compute.api::suspend %s"
+msgstr "compute.api::suspend %s"
+
+#: ../nova/api/openstack/servers.py:325
+#, python-format
+msgid "compute.api::resume %s"
+msgstr "compute.api::resume %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
+#: ../nova/api/ec2/__init__.py:317
+#, python-format
+msgid "Instance %s not found"
+msgstr "Instance %s not found"
+
+#. NOTE: No Resource Pool concept so far
+#: ../nova/virt/xenapi/volumeops.py:51
+#, python-format
+msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
+msgstr "Attach_volume: %(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 "Unable to create VDI on SR %(sr_ref)s for instance %(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 "Unable to use SR %(sr_ref)s for instance %(instance_name)s"
+
+#: ../nova/virt/xenapi/volumeops.py:91
+#, python-format
+msgid "Unable to attach volume to instance %s"
+msgstr "Unable to attach volume to instance %s"
+
+#: ../nova/virt/xenapi/volumeops.py:93
+#, python-format
+msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
+msgstr "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
+
+#. Detach VBD from VM
+#: ../nova/virt/xenapi/volumeops.py:104
+#, python-format
+msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
+msgstr "Detach_volume: %(instance_name)s, %(mountpoint)s"
+
+#: ../nova/virt/xenapi/volumeops.py:112
+#, python-format
+msgid "Unable to locate volume %s"
+msgstr "Unable to locate volume %s"
+
+#: ../nova/virt/xenapi/volumeops.py:120
+#, python-format
+msgid "Unable to detach volume %s"
+msgstr "Unable to detach volume %s"
+
+#: ../nova/virt/xenapi/volumeops.py:127
+#, python-format
+msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
+msgstr "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
+
+#: ../nova/compute/instance_types.py:41
+#, python-format
+msgid "Unknown instance type: %s"
+msgstr "Unknown instance type: %s"
+
+#: ../nova/crypto.py:46
+msgid "Filename of root CA"
+msgstr "Filename of root CA"
+
+#: ../nova/crypto.py:49
+msgid "Filename of private key"
+msgstr "Filename of private key"
+
+#: ../nova/crypto.py:51
+msgid "Filename of root Certificate Revokation List"
+msgstr "Filename of root Certificate Revocation List"
+
+#: ../nova/crypto.py:53
+msgid "Where we keep our keys"
+msgstr "Where we keep our keys"
+
+#: ../nova/crypto.py:55
+msgid "Where we keep our root CA"
+msgstr "Where we keep our root CA"
+
+#: ../nova/crypto.py:57
+msgid "Should we use a CA for each project?"
+msgstr "Should we use a CA for each project?"
+
+#: ../nova/crypto.py:61
+#, python-format
+msgid "Subject for certificate for users, %s for project, user, timestamp"
+msgstr "Subject for certificate for users, %s for project, user, timestamp"
+
+#: ../nova/crypto.py:66
+#, python-format
+msgid "Subject for certificate for projects, %s for project, timestamp"
+msgstr "Subject for certificate for projects, %s for project, timestamp"
+
+#: ../nova/crypto.py:71
+#, python-format
+msgid "Subject for certificate for vpns, %s for project, timestamp"
+msgstr "Subject for certificate for vpns, %s for project, timestamp"
+
+#: ../nova/crypto.py:258
+#, python-format
+msgid "Flags path: %s"
+msgstr "Flags path: %s"
+
+#: ../nova/scheduler/manager.py:69
+#, python-format
+msgid "Casting to %(topic)s %(host)s for %(method)s"
+msgstr "Casting to %(topic)s %(host)s for %(method)s"
+
+#: ../nova/compute/manager.py:78
+#, python-format
+msgid "check_instance_lock: decorating: |%s|"
+msgstr "check_instance_lock: decorating: |%s|"
+
+#: ../nova/compute/manager.py:80
+#, python-format
+msgid ""
+"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
+msgstr ""
+"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
+
+#: ../nova/compute/manager.py:84
+#, python-format
+msgid "check_instance_lock: locked: |%s|"
+msgstr "check_instance_lock: locked: |%s|"
+
+#: ../nova/compute/manager.py:86
+#, python-format
+msgid "check_instance_lock: admin: |%s|"
+msgstr "check_instance_lock: admin: |%s|"
+
+#: ../nova/compute/manager.py:91
+#, python-format
+msgid "check_instance_lock: executing: |%s|"
+msgstr "check_instance_lock: executing: |%s|"
+
+#: ../nova/compute/manager.py:95
+#, python-format
+msgid "check_instance_lock: not executing |%s|"
+msgstr "check_instance_lock: not executing |%s|"
+
+#: ../nova/compute/manager.py:179
+msgid "Instance has already been created"
+msgstr "Instance has already been created"
+
+#: ../nova/compute/manager.py:180
+#, python-format
+msgid "instance %s: starting..."
+msgstr "instance %s: starting..."
+
+#. pylint: disable=W0702
+#: ../nova/compute/manager.py:219
+#, python-format
+msgid "instance %s: Failed to spawn"
+msgstr "instance %s: Failed to spawn"
+
+#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
+#, python-format
+msgid "Terminating instance %s"
+msgstr "Terminating instance %s"
+
+#: ../nova/compute/manager.py:255
+#, python-format
+msgid "Deallocating address %s"
+msgstr "Deallocating address %s"
+
+#: ../nova/compute/manager.py:268
+#, python-format
+msgid "trying to destroy already destroyed instance: %s"
+msgstr "trying to destroy already destroyed instance: %s"
+
+#: ../nova/compute/manager.py:282
+#, python-format
+msgid "Rebooting instance %s"
+msgstr "Rebooting instance %s"
+
+#: ../nova/compute/manager.py:287
+#, python-format
+msgid ""
+"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+
+#: ../nova/compute/manager.py:311
+#, python-format
+msgid "instance %s: snapshotting"
+msgstr "instance %s: snapshotting"
+
+#: ../nova/compute/manager.py:316
+#, python-format
+msgid ""
+"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+
+#: ../nova/compute/manager.py:332
+#, python-format
+msgid ""
+"trying to reset the password on a non-running instance: %(instance_id)s "
+"(state: %(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+"trying to reset the password on a non-running instance: %(instance_id)s "
+"(state: %(instance_state)s expected: %(expected_state)s)"
+
+#: ../nova/compute/manager.py:335
+#, python-format
+msgid "instance %s: setting admin password"
+msgstr "instance %s: setting admin password"
+
+#: ../nova/compute/manager.py:353
+#, python-format
+msgid ""
+"trying to inject a file into a non-running instance: %(instance_id)s (state: "
+"%(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+"trying to inject a file into a non-running instance: %(instance_id)s (state: "
+"%(instance_state)s expected: %(expected_state)s)"
+
+#: ../nova/compute/manager.py:362
+#, python-format
+msgid "instance %(nm)s: injecting file to %(plain_path)s"
+msgstr "instance %(nm)s: injecting file to %(plain_path)s"
+
+#: ../nova/compute/manager.py:372
+#, python-format
+msgid "instance %s: rescuing"
+msgstr "instance %s: rescuing"
+
+#: ../nova/compute/manager.py:387
+#, python-format
+msgid "instance %s: unrescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:406
+#, python-format
+msgid "instance %s: pausing"
+msgstr "instance %s: pausing"
+
+#: ../nova/compute/manager.py:423
+#, python-format
+msgid "instance %s: unpausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:440
+#, python-format
+msgid "instance %s: retrieving diagnostics"
+msgstr "instance %s: retrieving diagnostics"
+
+#: ../nova/compute/manager.py:453
+#, python-format
+msgid "instance %s: suspending"
+msgstr "instance %s: suspending"
+
+#: ../nova/compute/manager.py:472
+#, python-format
+msgid "instance %s: resuming"
+msgstr "instance %s: resuming"
+
+#: ../nova/compute/manager.py:491
+#, python-format
+msgid "instance %s: locking"
+msgstr "instance %s: locking"
+
+#: ../nova/compute/manager.py:503
+#, python-format
+msgid "instance %s: unlocking"
+msgstr "instance %s: unlocking"
+
+#: ../nova/compute/manager.py:513
+#, python-format
+msgid "instance %s: getting locked state"
+msgstr "instance %s: getting locked state"
+
+#: ../nova/compute/manager.py:526
+#, python-format
+msgid "instance %s: reset network"
+msgstr "instance %s: reset network"
+
+#: ../nova/compute/manager.py:535 ../nova/api/ec2/cloud.py:515
+#, python-format
+msgid "Get console output for instance %s"
+msgstr "Get console output for instance %s"
+
+#: ../nova/compute/manager.py:543
+#, python-format
+msgid "instance %s: getting ajax console"
+msgstr "instance %s: getting ajax console"
+
+#: ../nova/compute/manager.py:553
+#, python-format
+msgid ""
+"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
+msgstr ""
+"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
+
+#. pylint: disable=W0702
+#. NOTE(vish): The inline callback eats the exception info so we
+#. log the traceback here and reraise the same
+#. ecxception below.
+#: ../nova/compute/manager.py:569
+#, python-format
+msgid "instance %(instance_id)s: attach failed %(mountpoint)s, removing"
+msgstr "instance %(instance_id)s: attach failed %(mountpoint)s, removing"
+
+#: ../nova/compute/manager.py:585
+#, python-format
+msgid ""
+"Detach volume %(volume_id)s from mountpoint %(mp)s on instance "
+"%(instance_id)s"
+msgstr ""
+"Detach volume %(volume_id)s from mountpoint %(mp)s on instance "
+"%(instance_id)s"
+
+#: ../nova/compute/manager.py:588
+#, python-format
+msgid "Detaching volume from unknown instance %s"
+msgstr "Detaching volume from unknown instance %s"
+
+#: ../nova/scheduler/simple.py:53
+#, python-format
+msgid "Host %s is not alive"
+msgstr "Host %s is not alive"
+
+#: ../nova/scheduler/simple.py:65
+msgid "All hosts have too many cores"
+msgstr "All hosts have too many cores"
+
+#: ../nova/scheduler/simple.py:87
+#, python-format
+msgid "Host %s not available"
+msgstr "Host %s not available"
+
+#: ../nova/scheduler/simple.py:99
+msgid "All hosts have too many gigabytes"
+msgstr "All hosts have too many gigabytes"
+
+#: ../nova/scheduler/simple.py:119
+msgid "All hosts have too many networks"
+msgstr "All hosts have too many networks"
+
+#: ../nova/volume/manager.py:85
+#, python-format
+msgid "Re-exporting %s volumes"
+msgstr "Re-exporting %s volumes"
+
+#: ../nova/volume/manager.py:90
+#, python-format
+msgid "volume %s: skipping export"
+msgstr "volume %s: skipping export"
+
+#: ../nova/volume/manager.py:96
+#, python-format
+msgid "volume %s: creating"
+msgstr "volume %s: creating"
+
+#: ../nova/volume/manager.py:108
+#, python-format
+msgid "volume %(vol_name)s: creating lv of size %(vol_size)sG"
+msgstr "volume %(vol_name)s: creating lv of size %(vol_size)sG"
+
+#: ../nova/volume/manager.py:112
+#, python-format
+msgid "volume %s: creating export"
+msgstr "volume %s: creating export"
+
+#: ../nova/volume/manager.py:123
+#, python-format
+msgid "volume %s: created successfully"
+msgstr "volume %s: created successfully"
+
+#: ../nova/volume/manager.py:131
+msgid "Volume is still attached"
+msgstr "Volume is still attached"
+
+#: ../nova/volume/manager.py:133
+msgid "Volume is not local to this node"
+msgstr "Volume is not local to this node"
+
+#: ../nova/volume/manager.py:136
+#, python-format
+msgid "volume %s: removing export"
+msgstr "volume %s: removing export"
+
+#: ../nova/volume/manager.py:138
+#, python-format
+msgid "volume %s: deleting"
+msgstr "volume %s: deleting"
+
+#: ../nova/volume/manager.py:147
+#, python-format
+msgid "volume %s: deleted successfully"
+msgstr "volume %s: deleted successfully"
+
+#: ../nova/virt/xenapi/fake.py:74
+#, python-format
+msgid "%(text)s: _db_content => %(content)s"
+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
+msgid "Raising NotImplemented"
+msgstr "Raising NotImplemented"
+
+#: ../nova/virt/xenapi/fake.py:306
+#, python-format
+msgid "xenapi.fake does not have an implementation for %s"
+msgstr "xenapi.fake does not have an implementation for %s"
+
+#: ../nova/virt/xenapi/fake.py:341
+#, python-format
+msgid "Calling %(localname)s %(impl)s"
+msgstr "Calling %(localname)s %(impl)s"
+
+#: ../nova/virt/xenapi/fake.py:346
+#, python-format
+msgid "Calling getter %s"
+msgstr "Calling getter %s"
+
+#: ../nova/virt/xenapi/fake.py:406
+#, python-format
+msgid ""
+"xenapi.fake does not have an implementation for %s or it has been called "
+"with the wrong number of arguments"
+msgstr ""
+"xenapi.fake does not have an implementation for %s or it has been called "
+"with the wrong number of arguments"
+
+#: ../nova/tests/test_cloud.py:256
+msgid "Can't test instances without a real virtual env."
+msgstr "Can't test instances without a real virtual env."
+
+#: ../nova/tests/test_cloud.py:268
+#, python-format
+msgid "Need to watch instance %s until it's running..."
+msgstr "Need to watch instance %s until it's running..."
+
+#: ../nova/virt/connection.py:73
+msgid "Failed to open connection to the hypervisor"
+msgstr "Failed to open connection to the hypervisor"
+
+#: ../nova/network/linux_net.py:187
+#, python-format
+msgid "Starting VLAN inteface %s"
+msgstr "Starting VLAN inteface %s"
+
+#: ../nova/network/linux_net.py:208
+#, python-format
+msgid "Starting Bridge interface for %s"
+msgstr "Starting Bridge interface for %s"
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:314
+#, python-format
+msgid "Hupping dnsmasq threw %s"
+msgstr "Hupping dnsmasq threw %s"
+
+#: ../nova/network/linux_net.py:316
+#, python-format
+msgid "Pid %d is stale, relaunching dnsmasq"
+msgstr "Pid %d is stale, relaunching dnsmasq"
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:358
+#, python-format
+msgid "killing radvd threw %s"
+msgstr "killing radvd threw %s"
+
+#: ../nova/network/linux_net.py:360
+#, python-format
+msgid "Pid %d is stale, relaunching radvd"
+msgstr "Pid %d is stale, relaunching radvd"
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:449
+#, python-format
+msgid "Killing dnsmasq threw %s"
+msgstr "Killing dnsmasq threw %s"
+
+#: ../nova/utils.py:58
+#, python-format
+msgid "Inner Exception: %s"
+msgstr "Inner Exception: %s"
+
+#: ../nova/utils.py:59
+#, python-format
+msgid "Class %s cannot be found"
+msgstr "Class %s cannot be found"
+
+#: ../nova/utils.py:118
+#, python-format
+msgid "Fetching %s"
+msgstr "Fetching %s"
+
+#: ../nova/utils.py:130
+#, python-format
+msgid "Running cmd (subprocess): %s"
+msgstr "Running cmd (subprocess): %s"
+
+#: ../nova/utils.py:143 ../nova/utils.py:183
+#, python-format
+msgid "Result was %s"
+msgstr "Result was %s"
+
+#: ../nova/utils.py:159
+#, python-format
+msgid "Running cmd (SSH): %s"
+msgstr "Running cmd (SSH): %s"
+
+#: ../nova/utils.py:217
+#, python-format
+msgid "debug in callback: %s"
+msgstr "debug in callback: %s"
+
+#: ../nova/utils.py:222
+#, python-format
+msgid "Running %s"
+msgstr "Running %s"
+
+#: ../nova/utils.py:262
+#, python-format
+msgid "Link Local address is not found.:%s"
+msgstr "Link Local address is not found.:%s"
+
+#: ../nova/utils.py:265
+#, python-format
+msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
+msgstr "Couldn't get Link Local IP of %(interface)s :%(ex)s"
+
+#: ../nova/utils.py:363
+#, python-format
+msgid "Invalid backend: %s"
+msgstr "Invalid backend: %s"
+
+#: ../nova/utils.py:374
+#, python-format
+msgid "backend %s"
+msgstr "backend %s"
+
+#: ../nova/fakerabbit.py:49
+#, python-format
+msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
+msgstr "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
+
+#: ../nova/fakerabbit.py:54
+#, python-format
+msgid "Publishing to route %s"
+msgstr "Publishing to route %s"
+
+#: ../nova/fakerabbit.py:84
+#, python-format
+msgid "Declaring queue %s"
+msgstr "Declaring queue %s"
+
+#: ../nova/fakerabbit.py:90
+#, python-format
+msgid "Declaring exchange %s"
+msgstr "Declaring exchange %s"
+
+#: ../nova/fakerabbit.py:96
+#, python-format
+msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
+msgstr "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
+
+#: ../nova/fakerabbit.py:121
+#, python-format
+msgid "Getting from %(queue)s: %(message)s"
+msgstr "Getting from %(queue)s: %(message)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
+#, python-format
+msgid "Created VM %s..."
+msgstr "Created VM %s..."
+
+#: ../nova/virt/xenapi/vm_utils.py:138
+#, python-format
+msgid "Created VM %(instance_name)s as %(vm_ref)s."
+msgstr "Created VM %(instance_name)s as %(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 "Creating VBD for 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 "Created VBD %(vbd_ref)s for VM %(vm_ref)s, VDI %(vdi_ref)s."
+
+#: ../nova/virt/xenapi/vm_utils.py:187
+#, python-format
+msgid "VBD not found in instance %s"
+msgstr "VBD not found in instance %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:197
+#, python-format
+msgid "Unable to unplug VBD %s"
+msgstr "Unable to unplug VBD %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:209
+#, python-format
+msgid "Unable to destroy VBD %s"
+msgstr "Unable to destroy VBD %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:224
+#, python-format
+msgid "Creating VIF for VM %(vm_ref)s, network %(network_ref)s."
+msgstr "Creating VIF for VM %(vm_ref)s, network %(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 "Created VIF %(vif_ref)s for VM %(vm_ref)s, network %(network_ref)s."
+
+#: ../nova/virt/xenapi/vm_utils.py:246
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(sr_ref)s."
+msgstr ""
+"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(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 "Snapshotting VM %(vm_ref)s with label '%(label)s'..."
+
+#: ../nova/virt/xenapi/vm_utils.py:272
+#, python-format
+msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
+msgstr "Created snapshot %(template_vm_ref)s from 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 "Asking xapi to upload %(vdi_uuids)s as ID %(image_id)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:327
+#, python-format
+msgid "Size for image %(image)s:%(virtual_size)d"
+msgstr "Size for image %(image)s:%(virtual_size)d"
+
+#: ../nova/virt/xenapi/vm_utils.py:332
+#, python-format
+msgid "Glance image %s"
+msgstr "Glance image %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 "Copying VDI %s to /boot/guest on dom0"
+
+#: ../nova/virt/xenapi/vm_utils.py:352
+#, python-format
+msgid "Kernel/Ramdisk VDI %s destroyed"
+msgstr "Kernel/Ramdisk VDI %s destroyed"
+
+#: ../nova/virt/xenapi/vm_utils.py:361
+#, python-format
+msgid "Asking xapi to fetch %(url)s as %(access)s"
+msgstr "Asking xapi to fetch %(url)s as %(access)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
+#, python-format
+msgid "Looking up vdi %s for PV kernel"
+msgstr "Looking up vdi %s for PV kernel"
+
+#: ../nova/virt/xenapi/vm_utils.py:397
+#, python-format
+msgid "PV Kernel in VDI:%s"
+msgstr "PV Kernel in VDI:%s"
+
+#: ../nova/virt/xenapi/vm_utils.py:405
+#, python-format
+msgid "Running pygrub against %s"
+msgstr "Running pygrub against %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:411
+#, python-format
+msgid "Found Xen kernel %s"
+msgstr "Found Xen kernel %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:413
+msgid "No Xen kernel found. Booting HVM."
+msgstr "No Xen kernel found. Booting HVM."
+
+#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
+#, python-format
+msgid "duplicate name found: %s"
+msgstr "duplicate name found: %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:442
+#, python-format
+msgid "VDI %s is still available"
+msgstr "VDI %s is still available"
+
+#: ../nova/virt/xenapi/vm_utils.py:463
+#, python-format
+msgid "(VM_UTILS) xenserver vm state -> |%s|"
+msgstr "(VM_UTILS) xenserver vm state -> |%s|"
+
+#: ../nova/virt/xenapi/vm_utils.py:465
+#, python-format
+msgid "(VM_UTILS) xenapi power_state -> |%s|"
+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 "VHD %(vdi_uuid)s has parent %(parent_ref)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:542
+#, python-format
+msgid "Re-scanning SR %s"
+msgstr "Re-scanning SR %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:567
+#, python-format
+msgid ""
+"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
+msgstr ""
+"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
+
+#: ../nova/virt/xenapi/vm_utils.py:574
+#, python-format
+msgid ""
+"Parent %(parent_uuid)s doesn't match original parent "
+"%(original_parent_uuid)s, waiting for coalesce..."
+msgstr ""
+"Parent %(parent_uuid)s doesn't match original parent "
+"%(original_parent_uuid)s, waiting for coalesce..."
+
+#: ../nova/virt/xenapi/vm_utils.py:590
+#, python-format
+msgid "No VDIs found for VM %s"
+msgstr "No VDIs found for VM %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:594
+#, python-format
+msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
+msgstr "Unexpected number of VDIs (%(num_vdis)s) found for 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 "Creating VBD for 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 "Creating VBD for VDI %s done."
+
+#: ../nova/virt/xenapi/vm_utils.py:657
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
+#, python-format
+msgid "Plugging VBD %s ... "
+msgstr "Plugging VBD %s ... "
+
+#: ../nova/virt/xenapi/vm_utils.py:659
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:194
+#, python-format
+msgid "Plugging VBD %s done."
+msgstr "Plugging VBD %s done."
+
+#: ../nova/virt/xenapi/vm_utils.py:661
+#, python-format
+msgid "VBD %(vbd)s plugged as %(orig_dev)s"
+msgstr "VBD %(vbd)s plugged as %(orig_dev)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:664
+#, python-format
+msgid "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
+msgstr "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:668
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:197
+#, python-format
+msgid "Destroying VBD for VDI %s ... "
+msgstr "Destroying VBD for VDI %s ... "
+
+#: ../nova/virt/xenapi/vm_utils.py:671
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:200
+#, python-format
+msgid "Destroying VBD for VDI %s done."
+msgstr "Destroying VBD for VDI %s done."
+
+#: ../nova/virt/xenapi/vm_utils.py:683
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:211
+msgid "VBD.unplug successful first time."
+msgstr "VBD.unplug successful first time."
+
+#: ../nova/virt/xenapi/vm_utils.py:688
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:216
+msgid "VBD.unplug rejected: retrying..."
+msgstr "VBD.unplug rejected: retrying..."
+
+#: ../nova/virt/xenapi/vm_utils.py:692
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:220
+msgid "VBD.unplug successful eventually."
+msgstr "VBD.unplug successful eventually."
+
+#: ../nova/virt/xenapi/vm_utils.py:695
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:223
+#, python-format
+msgid "Ignoring XenAPI.Failure in VBD.unplug: %s"
+msgstr "Ignoring XenAPI.Failure in VBD.unplug: %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:704
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:66
+#, python-format
+msgid "Ignoring XenAPI.Failure %s"
+msgstr "Ignoring XenAPI.Failure %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:735
+#, python-format
+msgid ""
+"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
+msgstr ""
+"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
+
+#: ../nova/virt/xenapi/vm_utils.py:747
+#, python-format
+msgid "Writing partition table %s done."
+msgstr "Writing partition table %s done."
+
+#: ../nova/tests/test_rpc.py:89
+#, python-format
+msgid "Nested received %(queue)s, %(value)s"
+msgstr "Nested received %(queue)s, %(value)s"
+
+#: ../nova/tests/test_rpc.py:95
+#, python-format
+msgid "Nested return %s"
+msgstr "Nested return %s"
+
+#: ../nova/tests/test_rpc.py:120 ../nova/tests/test_rpc.py:126
+#, python-format
+msgid "Received %s"
+msgstr "Received %s"
+
+#: ../nova/db/sqlalchemy/api.py:44
+msgid "Use of empty request context is deprecated"
+msgstr "Use of empty request context is deprecated"
+
+#: ../nova/db/sqlalchemy/api.py:133
+#, python-format
+msgid "No service for id %s"
+msgstr "No service for id %s"
+
+#: ../nova/db/sqlalchemy/api.py:251
+#, python-format
+msgid "No service for %(host)s, %(binary)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:592
+msgid "No fixed ips defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:608
+#, python-format
+msgid "No floating ip for address %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:629
+#, python-format
+msgid "No address for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:961
+#, python-format
+msgid "no keypair for user %(user_id)s, name %(name)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1076 ../nova/db/sqlalchemy/api.py:1156
+#, python-format
+msgid "No network for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1086
+msgid "No networks defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1115
+#, python-format
+msgid "No network for bridge %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1129 ../nova/db/sqlalchemy/api.py:1142
+#, python-format
+msgid "No network for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1277
+#, python-format
+msgid "Token %s does not exist"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1302
+#, python-format
+msgid "No quota for project_id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1455 ../nova/db/sqlalchemy/api.py:1501
+#: ../nova/api/ec2/__init__.py:323
+#, python-format
+msgid "Volume %s not found"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1514
+#, python-format
+msgid "No export device found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1527
+#, python-format
+msgid "No target id found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1572
+#, python-format
+msgid "No security group with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1589
+#, python-format
+msgid "No security group named %(group_name)s for project: %(project_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1682
+#, python-format
+msgid "No secuity group rule with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1756
+#, python-format
+msgid "No user for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1772
+#, python-format
+msgid "No user for access key %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1834
+#, python-format
+msgid "No project with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1979
+#, python-format
+msgid "No console pool with id %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1996
+#, python-format
+msgid ""
+"No console pool of type %(console_type)s for compute host %(compute_host)s "
+"on proxy host %(host)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2035
+#, python-format
+msgid "No console for instance %(instance_id)s in pool %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2057
+#, python-format
+msgid "on instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2058
+#, python-format
+msgid "No console with id %(console_id)s %(idesc)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2078 ../nova/db/sqlalchemy/api.py:2097
+#, python-format
+msgid "No zone with id %(zone_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:160
+#, python-format
+msgid "Checking state of %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:165
+#, python-format
+msgid "Current state of %(name)s was %(state)s."
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:183
+#, python-format
+msgid "Connecting to libvirt: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:196
+msgid "Connection to libvirt broke"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:258
+#, python-format
+msgid "instance %(instance_name)s: deleting instance files %(target)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:283
+#, python-format
+msgid "Invalid device path %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:313
+#, python-format
+msgid "No disk at %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:320
+msgid "Instance snapshotting is not supported for libvirtat this time"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:336
+#, python-format
+msgid "instance %s: rebooted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:339
+#, python-format
+msgid "_wait_for_reboot failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:382
+#, python-format
+msgid "instance %s: rescued"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:385
+#, python-format
+msgid "_wait_for_rescue failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:411
+#, python-format
+msgid "instance %s: is running"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:422
+#, python-format
+msgid "instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:425 ../nova/virt/xenapi/vmops.py:186
+#, python-format
+msgid "instance %s: failed to boot"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:436
+#, python-format
+msgid "virsh said: %r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:440
+msgid "cool, it's a device"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:448
+#, python-format
+msgid "data: %(data)r, fpath: %(fpath)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:456
+#, python-format
+msgid "Contents of file %(fpath)s: %(contents)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:489
+msgid "Unable to find an open port"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:563
+#, python-format
+msgid "instance %s: Creating image"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:646
+#, python-format
+msgid "instance %(inst_name)s: injecting key into image %(img_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:649
+#, python-format
+msgid "instance %(inst_name)s: injecting net into image %(img_id)s"
+msgstr ""
+
+#. This could be a windows image, or a vmdk format disk
+#: ../nova/virt/libvirt_conn.py:657
+#, python-format
+msgid ""
+"instance %(inst_name)s: ignoring error injecting data into image %(img_id)s "
+"(%(e)s)"
+msgstr ""
+
+#. TODO(termie): cache?
+#: ../nova/virt/libvirt_conn.py:665
+#, python-format
+msgid "instance %s: starting toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:732
+#, python-format
+msgid "instance %s: finished toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:751
+msgid "diagnostics are not supported for libvirt"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:1225
+#, python-format
+msgid "Attempted to unfilter instance %s which is not filtered"
+msgstr ""
+
+#: ../nova/api/ec2/metadatarequesthandler.py:76
+#, python-format
+msgid "Failed to get metadata for ip: %s"
+msgstr ""
+
+#: ../nova/auth/fakeldap.py:33
+msgid "Attempted to instantiate singleton"
+msgstr ""
+
+#: ../nova/network/api.py:39
+#, python-format
+msgid "Quota exceeeded for %s, tried to allocate address"
+msgstr ""
+
+#: ../nova/network/api.py:42
+msgid "Address quota exceeded. You cannot allocate any more addresses"
+msgstr ""
+
+#: ../nova/tests/test_volume.py:162
+#, python-format
+msgid "Target %s allocated"
+msgstr ""
+
+#: ../nova/virt/images.py:70
+#, python-format
+msgid "Finished retreving %(url)s -- placed in %(path)s"
+msgstr ""
+
+#: ../nova/scheduler/driver.py:66
+msgid "Must implement a fallback schedule"
+msgstr ""
+
+#: ../nova/console/manager.py:70
+msgid "Adding console"
+msgstr ""
+
+#: ../nova/console/manager.py:90
+#, python-format
+msgid "Tried to remove non-existant console %(console_id)s."
+msgstr ""
+
+#: ../nova/api/direct.py:149
+msgid "not available"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:62
+#, python-format
+msgid "The key_pair %s already exists"
+msgstr ""
+
+#. TODO(vish): Do this with M2Crypto instead
+#: ../nova/api/ec2/cloud.py:118
+#, python-format
+msgid "Generating root CA: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:303
+#, python-format
+msgid "Create key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:311
+#, python-format
+msgid "Delete key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:386
+#, python-format
+msgid "%s is not a valid ipProtocol"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:390
+msgid "Invalid port range"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:421
+#, python-format
+msgid "Revoke security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:430 ../nova/api/ec2/cloud.py:459
+msgid "Not enough parameters to build a valid rule."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:443
+msgid "No rule for the specified parameters."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:450
+#, python-format
+msgid "Authorize security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:464
+#, python-format
+msgid "This rule already exists in group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:492
+#, python-format
+msgid "Create Security Group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:495
+#, python-format
+msgid "group %s already exists"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:507
+#, python-format
+msgid "Delete security group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:584
+#, python-format
+msgid "Create volume of %s GB"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:612
+#, python-format
+msgid "Attach volume %(volume_id)s to instance %(instance_id)s at %(device)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:629
+#, python-format
+msgid "Detach volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:761
+msgid "Allocate address"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:766
+#, python-format
+msgid "Release address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:771
+#, python-format
+msgid "Associate address %(public_ip)s to instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:780
+#, python-format
+msgid "Disassociate address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:807
+msgid "Going to start terminating instances"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:815
+#, python-format
+msgid "Reboot instance %r"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:867
+#, python-format
+msgid "De-registering image %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:875
+#, python-format
+msgid "Registered image %(image_location)s with id %(image_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:882 ../nova/api/ec2/cloud.py:900
+#, python-format
+msgid "attribute not supported: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:890
+#, python-format
+msgid "invalid id: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:903
+msgid "user or group not specified"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:905
+msgid "only group \"all\" is supported"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:907
+msgid "operation_type must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:908
+#, python-format
+msgid "Updating image %s publicity"
+msgstr ""
+
+#: ../bin/nova-api.py:52
+#, python-format
+msgid "Using paste.deploy config at: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:57
+#, python-format
+msgid "No paste configuration for app: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:59
+#, python-format
+msgid ""
+"App Config: %(api)s\n"
+"%(config)r"
+msgstr ""
+
+#: ../bin/nova-api.py:64
+#, python-format
+msgid "Running %s API"
+msgstr ""
+
+#: ../bin/nova-api.py:69
+#, python-format
+msgid "No known API applications configured in %s."
+msgstr ""
+
+#: ../bin/nova-api.py:83
+#, python-format
+msgid "Starting nova-api node (version %s)"
+msgstr ""
+
+#: ../bin/nova-api.py:89
+#, python-format
+msgid "No paste configuration found for: %s"
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:84
+#, python-format
+msgid "Argument %(key)s value %(value)s is too short."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:89
+#, python-format
+msgid "Argument %(key)s value %(value)s contains invalid characters."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:94
+#, python-format
+msgid "Argument %(key)s value %(value)s starts with a hyphen."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:102
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:130
+#, python-format
+msgid "Argument %s is required."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:117
+#, python-format
+msgid ""
+"Argument %(key)s may not take value %(value)s. Valid values are ['true', "
+"'false']."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:163
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) on %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:67
+#, python-format
+msgid "Attempted to create non-unique name %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:73
+#, python-format
+msgid "instance %(name)s: not enough free memory"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:148
+#, python-format
+msgid "Starting VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:151
+#, python-format
+msgid "Spawning VM %(instance_name)s created %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:162
+#, python-format
+msgid "Invalid value for onset_files: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:167
+#, python-format
+msgid "Injecting file path: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:180
+#, python-format
+msgid "Instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:232
+#, python-format
+msgid "Instance not present %s"
+msgstr ""
+
+#. TODO(sirp): Add quiesce and VSS locking support when Windows support
+#. is added
+#: ../nova/virt/xenapi/vmops.py:261
+#, python-format
+msgid "Starting snapshot for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:269
+#, python-format
+msgid "Unable to Snapshot %(vm_ref)s: %(exc)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:280
+#, python-format
+msgid "Finished snapshot and upload for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:356
+#, python-format
+msgid "VM %(vm)s already halted, skipping shutdown..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:389
+msgid "Removing kernel/ramdisk files"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:399
+msgid "kernel/ramdisk files removed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:561
+#, python-format
+msgid ""
+"TIMEOUT: The call to %(method)s timed out. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:564
+#, python-format
+msgid ""
+"NOT IMPLEMENTED: The call to %(method)s is not supported by the agent. VM "
+"id=%(instance_id)s; args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:569
+#, python-format
+msgid ""
+"The call to %(method)s returned an error: %(e)s. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:760
+#, python-format
+msgid "OpenSSL error: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:148
+#, python-format
+msgid "Running instances: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:154
+#, python-format
+msgid "After terminating instances: %s"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:45
+msgid "Template for script to run on cloudpipe instance boot"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:48
+msgid "Network to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:51
+msgid "Netmask to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:97
+#, python-format
+msgid "Launching VPN for %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/migration.py:35
+msgid "python-migrate is not installed. Exiting."
+msgstr ""
+
+#: ../nova/image/s3.py:99
+#, python-format
+msgid "Image %s could not be found"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:121
+msgid "Too many failed authentications."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:131
+#, python-format
+msgid ""
+"Access key %(access_key)s has had %(failures)d failed authentications and "
+"will be locked out for %(lock_mins)d minutes."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:169 ../nova/objectstore/handler.py:140
+#, python-format
+msgid "Authentication Failure: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:182
+#, python-format
+msgid "Authenticated Request For %(uname)s:%(pname)s)"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:207
+#, python-format
+msgid "action: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:209
+#, python-format
+msgid "arg: %(key)s\t\tval: %(value)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:281
+#, python-format
+msgid ""
+"Unauthorized request for controller=%(controller)s and action=%(action)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:314
+#, python-format
+msgid "InstanceNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:320
+#, python-format
+msgid "VolumeNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:326
+#, python-format
+msgid "NotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:329
+#, python-format
+msgid "ApiError raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:338
+#, python-format
+msgid "Unexpected error raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:343
+msgid "An unknown error has occurred. Please try your request again."
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:84
+#, python-format
+msgid "User %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:106 ../nova/auth/ldapdriver.py:232
+#, python-format
+msgid "Project can't be created because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:122 ../nova/auth/ldapdriver.py:243
+#, python-format
+msgid "Project can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:135 ../nova/auth/ldapdriver.py:229
+#, python-format
+msgid "Project can't be created because project %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:157 ../nova/auth/ldapdriver.py:268
+#, python-format
+msgid "Project can't be modified because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:245
+#, python-format
+msgid "User \"%s\" not found"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:248
+#, python-format
+msgid "Project \"%s\" not found"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:129
+msgid ""
+"Must specify xenapi_connection_url, xenapi_connection_username (optionally), "
+"and xenapi_connection_password to use connection_type=xenapi"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:311
+#, python-format
+msgid "Task [%(name)s] %(task)s status: success %(result)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:317
+#, python-format
+msgid "Task [%(name)s] %(task)s status: %(status)s %(error_info)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:331 ../nova/virt/xenapi_conn.py:344
+#, python-format
+msgid "Got exception: %s"
+msgstr ""
+
+#: ../nova/volume/san.py:67
+#, python-format
+msgid "Could not find iSCSI export for volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/apirequest.py:100
+#, python-format
+msgid ""
+"Unsupported API request: controller = %(controller)s, action = %(action)s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:55
+#, python-format
+msgid "Caught error: %s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:76
+msgid "Including admin operations in API."
+msgstr ""
+
+#: ../nova/console/xvp.py:99
+msgid "Rebuilding xvp conf"
+msgstr ""
+
+#: ../nova/console/xvp.py:116
+#, python-format
+msgid "Re-wrote %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:121
+msgid "Stopping xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:134
+msgid "Starting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:141
+#, python-format
+msgid "Error starting xvp: %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:144
+msgid "Restarting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:146
+msgid "xvp not running..."
+msgstr ""
+
+#: ../bin/nova-manage.py:272
+msgid ""
+"The above error may show that the database has not been created.\n"
+"Please create a database using nova-manage sync db before running this "
+"command."
+msgstr ""
+
+#: ../bin/nova-manage.py:426
+msgid ""
+"No more networks available. If this is a new installation, you need\n"
+"to call something like this:\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
+msgstr ""
+
+#: ../bin/nova-manage.py:431
+msgid ""
+"The above error may show that the certificate db has not been created.\n"
+"Please create a database by running a nova-api server on this host."
+msgstr ""
+
+#: ../bin/nova-manage.py:447 ../bin/nova-manage.py:536
+msgid "network"
+msgstr ""
+
+#: ../bin/nova-manage.py:448
+msgid "IP address"
+msgstr ""
+
+#: ../bin/nova-manage.py:449
+msgid "MAC address"
+msgstr ""
+
+#: ../bin/nova-manage.py:450
+msgid "hostname"
+msgstr ""
+
+#: ../bin/nova-manage.py:451
+msgid "host"
+msgstr ""
+
+#: ../bin/nova-manage.py:537
+msgid "netmask"
+msgstr ""
+
+#: ../bin/nova-manage.py:538
+msgid "start address"
+msgstr ""
+
+#: ../nova/virt/disk.py:69
+#, python-format
+msgid "Failed to load partition: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:91
+#, python-format
+msgid "Failed to mount filesystem: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:124
+#, python-format
+msgid "nbd device %s did not show up"
+msgstr ""
+
+#: ../nova/virt/disk.py:128
+#, python-format
+msgid "Could not attach image to loopback: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:151
+msgid "No free nbd devices"
+msgstr ""
+
+#: ../doc/ext/nova_todo.py:46
+#, python-format
+msgid "%(filename)s, line %(line_info)d"
+msgstr ""
+
+#. FIXME(chiradeep): implement this
+#: ../nova/virt/hyperv.py:118
+msgid "In init host"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:131
+#, python-format
+msgid "Attempt to create duplicate vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:148
+#, python-format
+msgid "Starting VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:150
+#, python-format
+msgid "Started VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:152
+#, python-format
+msgid "spawn vm failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:169
+#, python-format
+msgid "Failed to create VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:188
+#, python-format
+msgid "Set memory for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:198
+#, python-format
+msgid "Set vcpus for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:202
+#, python-format
+msgid "Creating disk for %(vm_name)s by attaching disk file %(vhdfile)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:227
+#, python-format
+msgid "Failed to add diskdrive to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:230
+#, python-format
+msgid "New disk drive path is %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:247
+#, python-format
+msgid "Failed to add vhd file to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:249
+#, python-format
+msgid "Created disk for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:253
+#, python-format
+msgid "Creating nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:272
+msgid "Failed creating a port on the external vswitch"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:273
+#, python-format
+msgid "Failed creating port for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:276
+#, python-format
+msgid "Created switch port %(vm_name)s on switch %(ext_path)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:286
+#, python-format
+msgid "Failed to add nic to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:288
+#, python-format
+msgid "Created nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:321
+#, python-format
+msgid "WMI job failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:325
+#, python-format
+msgid "WMI job succeeded: %(desc)s, Elapsed=%(elap)s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:361
+#, python-format
+msgid "Got request to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:386
+#, python-format
+msgid "Failed to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:393
+#, python-format
+msgid "Del: disk %(vhdfile)s vm %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:415
+#, python-format
+msgid ""
+"Got Info for vm %(instance_id)s: state=%(state)s, mem=%(memusage)s, "
+"num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:451
+#, python-format
+msgid "Successfully changed vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:454
+#, python-format
+msgid "Failed to change vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/compute/api.py:71
+#, python-format
+msgid "Instance %d was not found in get_network_topic"
+msgstr ""
+
+#: ../nova/compute/api.py:77
+#, python-format
+msgid "Instance %d has no host"
+msgstr ""
+
+#: ../nova/compute/api.py:97
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to run %(min_count)s instances"
+msgstr ""
+
+#: ../nova/compute/api.py:99
+#, python-format
+msgid ""
+"Instance quota exceeded. You can only run %s more instances of this type."
+msgstr ""
+
+#: ../nova/compute/api.py:112
+msgid "Creating a raw instance"
+msgstr ""
+
+#: ../nova/compute/api.py:160
+#, python-format
+msgid "Going to run %s instances..."
+msgstr ""
+
+#: ../nova/compute/api.py:187
+#, python-format
+msgid "Casting to scheduler for %(pid)s/%(uid)s's instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/api.py:292
+#, python-format
+msgid "Going to try to terminate %s"
+msgstr ""
+
+#: ../nova/compute/api.py:296
+#, python-format
+msgid "Instance %d was not found during terminate"
+msgstr ""
+
+#: ../nova/compute/api.py:301
+#, python-format
+msgid "Instance %d is already being terminated"
+msgstr ""
+
+#: ../nova/compute/api.py:481
+#, python-format
+msgid "Invalid device specified: %s. Example device: /dev/vdb"
+msgstr ""
+
+#: ../nova/compute/api.py:496
+msgid "Volume isn't attached to anything!"
+msgstr ""
+
+#: ../nova/rpc.py:98
+#, python-format
+msgid ""
+"AMQP server on %(fl_host)s:%(fl_port)d is unreachable. Trying again in "
+"%(fl_intv)d seconds."
+msgstr ""
+
+#: ../nova/rpc.py:103
+#, python-format
+msgid "Unable to connect to AMQP server after %d tries. Shutting down."
+msgstr ""
+
+#: ../nova/rpc.py:122
+msgid "Reconnected to queue"
+msgstr ""
+
+#: ../nova/rpc.py:129
+msgid "Failed to fetch message from queue"
+msgstr ""
+
+#: ../nova/rpc.py:159
+#, python-format
+msgid "Initing the Adapter Consumer for %s"
+msgstr ""
+
+#: ../nova/rpc.py:178
+#, python-format
+msgid "received %s"
+msgstr ""
+
+#. NOTE(vish): we may not want to ack here, but that means that bad
+#. messages stay in the queue indefinitely, so for now
+#. we just log the message and send an error string
+#. back to the caller
+#: ../nova/rpc.py:191
+#, python-format
+msgid "no method for message: %s"
+msgstr ""
+
+#: ../nova/rpc.py:192
+#, python-format
+msgid "No method for message: %s"
+msgstr ""
+
+#: ../nova/rpc.py:253
+#, python-format
+msgid "Returning exception %s to caller"
+msgstr ""
+
+#: ../nova/rpc.py:294
+#, python-format
+msgid "unpacked context: %s"
+msgstr ""
+
+#: ../nova/rpc.py:313
+msgid "Making asynchronous call..."
+msgstr ""
+
+#: ../nova/rpc.py:316
+#, python-format
+msgid "MSG_ID is %s"
+msgstr ""
+
+#: ../nova/rpc.py:354
+msgid "Making asynchronous cast..."
+msgstr ""
+
+#: ../nova/rpc.py:364
+#, python-format
+msgid "response %s"
+msgstr ""
+
+#: ../nova/rpc.py:373
+#, python-format
+msgid "topic is %s"
+msgstr ""
+
+#: ../nova/rpc.py:374
+#, python-format
+msgid "message %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:78
+#, python-format
+msgid "Recovering from a failed execute. Try number %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:87
+#, python-format
+msgid "volume group %s doesn't exist"
+msgstr ""
+
+#: ../nova/volume/driver.py:220
+#, python-format
+msgid "FAKE AOE: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:233
+msgid "Skipping ensure_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:279 ../nova/volume/driver.py:288
+msgid "Skipping remove_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:347
+#, python-format
+msgid "FAKE ISCSI: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:359
+#, python-format
+msgid "rbd has no pool %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:414
+#, python-format
+msgid "Sheepdog is not working: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:416
+msgid "Sheepdog is not working"
+msgstr ""
+
+#: ../nova/wsgi.py:68
+#, python-format
+msgid "Starting %(arg0)s on %(host)s:%(port)s"
+msgstr ""
+
+#: ../nova/wsgi.py:147
+msgid "You must implement __call__"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:58
+msgid "leasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:73
+msgid "Adopted old lease or got a change of mac/hostname"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:80
+msgid "releasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:123
+#, python-format
+msgid ""
+"Called %(action)s for mac %(mac)s with ip %(ip)s and hostname %(hostname)s "
+"on interface %(interface)s"
+msgstr ""
+
+#: ../nova/virt/fake.py:239
+#, python-format
+msgid "Instance %s Not Found"
+msgstr ""
+
+#: ../nova/network/manager.py:153
+#, python-format
+msgid "Dissassociated %s stale fixed ip(s)"
+msgstr ""
+
+#: ../nova/network/manager.py:157
+msgid "setting network host"
+msgstr ""
+
+#: ../nova/network/manager.py:212
+#, python-format
+msgid "Leasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:216
+#, python-format
+msgid "IP %s leased that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:220
+#, python-format
+msgid "IP %(address)s leased to bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:228
+#, python-format
+msgid "IP %s leased that was already deallocated"
+msgstr ""
+
+#: ../nova/network/manager.py:233
+#, python-format
+msgid "Releasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:237
+#, python-format
+msgid "IP %s released that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:241
+#, python-format
+msgid "IP %(address)s released from bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:244
+#, python-format
+msgid "IP %s released that was not leased"
+msgstr ""
+
+#: ../nova/network/manager.py:519
+msgid ""
+"The sum between the number of networks and the vlan start cannot be greater "
+"than 4094"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:57
+#, python-format
+msgid "Introducing %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:74
+#, python-format
+msgid "Introduced %(label)s as %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:78
+msgid "Unable to create Storage Repository"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:90
+#, python-format
+msgid "Unable to find SR from VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:96
+#, python-format
+msgid "Forgetting SR %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:101
+#, python-format
+msgid "Ignoring exception %(exc)s when getting PBDs for %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:107
+#, python-format
+msgid "Ignoring exception %(exc)s when unplugging PBD %(pbd)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:111
+#, python-format
+msgid "Forgetting SR %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:113
+#, python-format
+msgid "Ignoring exception %(exc)s when forgetting SR %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:123
+#, python-format
+msgid "Unable to introduce VDI on SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:128
+#, python-format
+msgid "Unable to get record of VDI %s on"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:146
+#, python-format
+msgid "Unable to introduce VDI for SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:175
+#, python-format
+msgid "Unable to obtain target information %(device_path)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:197
+#, python-format
+msgid "Mountpoint cannot be translated: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:262
+#, python-format
+msgid "Failed to decrypt private key: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:269
+#, python-format
+msgid "Failed to decrypt initialization vector: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:277
+#, python-format
+msgid "Failed to decrypt image file %(image_file)s: %(err)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:106
+#, python-format
+msgid "Unknown S3 value type %r"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:137
+msgid "Authenticated request"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:182
+msgid "List of buckets requested"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:209
+#, python-format
+msgid "List keys for bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:217
+#, python-format
+msgid "Unauthorized attempt to access bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:235
+#, python-format
+msgid "Creating bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:245
+#, python-format
+msgid "Deleting bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:249
+#, python-format
+msgid "Unauthorized attempt to delete bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:273
+#, python-format
+msgid "Getting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:276
+#, python-format
+msgid "Unauthorized attempt to get object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:296
+#, python-format
+msgid "Putting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:299
+#, python-format
+msgid "Unauthorized attempt to upload object %(nm)s to bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:318
+#, python-format
+msgid "Deleting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:322
+#, python-format
+msgid "Unauthorized attempt to delete object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:396
+#, python-format
+msgid "Not authorized to upload image: invalid directory %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:404
+#, python-format
+msgid "Not authorized to upload image: unauthorized bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:409
+#, python-format
+msgid "Starting image upload: %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:423
+#, python-format
+msgid "Not authorized to update attributes of image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:431
+#, python-format
+msgid "Toggling publicity flag of image %(image_id)s %(newstatus)r"
+msgstr ""
+
+#. other attributes imply update
+#: ../nova/objectstore/handler.py:436
+#, python-format
+msgid "Updating user fields on image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:450
+#, python-format
+msgid "Unauthorized attempt to delete image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:455
+#, python-format
+msgid "Deleted image: %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:259
+#, python-format
+msgid "Looking up user: %r"
+msgstr ""
+
+#: ../nova/auth/manager.py:263
+#, python-format
+msgid "Failed authorization for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:264
+#, python-format
+msgid "No user found for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:270
+#, python-format
+msgid "Using project name = user name (%s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:277
+#, python-format
+msgid "failed authorization: no project named %(pjid)s (user=%(uname)s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:279
+#, python-format
+msgid "No project called %s could be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:287
+#, python-format
+msgid ""
+"Failed authorization: user %(uname)s not admin and not member of project "
+"%(pjname)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:289
+#, python-format
+msgid "User %(uid)s is not a member of project %(pjid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:298 ../nova/auth/manager.py:309
+#, python-format
+msgid "Invalid signature for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:299 ../nova/auth/manager.py:310
+msgid "Signature does not match"
+msgstr ""
+
+#: ../nova/auth/manager.py:380
+msgid "Must specify project"
+msgstr ""
+
+#: ../nova/auth/manager.py:414
+#, python-format
+msgid "The %s role can not be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:416
+#, python-format
+msgid "The %s role is global only"
+msgstr ""
+
+#: ../nova/auth/manager.py:420
+#, python-format
+msgid "Adding role %(role)s to user %(uid)s in project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:423
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:448
+#, python-format
+msgid "Removing role %(role)s from user %(uid)s on project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:451
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:515
+#, python-format
+msgid "Created project %(name)s with manager %(manager_user)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:533
+#, python-format
+msgid "modifying project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:545
+#, python-format
+msgid "Adding user %(uid)s to project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:566
+#, python-format
+msgid "Remove user %(uid)s from project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:592
+#, python-format
+msgid "Deleting project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:650
+#, python-format
+msgid "Created user %(rvname)s (admin: %(rvadmin)r)"
+msgstr ""
+
+#: ../nova/auth/manager.py:659
+#, python-format
+msgid "Deleting user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:669
+#, python-format
+msgid "Access Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:671
+#, python-format
+msgid "Secret Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:673
+#, python-format
+msgid "Admin status set to %(admin)r for user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:722
+#, python-format
+msgid "No vpn data for project %s"
+msgstr ""
+
+#: ../nova/service.py:161
+#, python-format
+msgid "Starting %(topic)s node (version %(vcs_string)s)"
+msgstr ""
+
+#: ../nova/service.py:174
+msgid "Service killed that has no database entry"
+msgstr ""
+
+#: ../nova/service.py:195
+msgid "The service database object disappeared, Recreating it."
+msgstr ""
+
+#: ../nova/service.py:207
+msgid "Recovered model server connection!"
+msgstr ""
+
+#: ../nova/service.py:213
+msgid "model server went away"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:174
+#, python-format
+msgid "LDAP user %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:205
+#, python-format
+msgid "LDAP object for %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:348
+#, python-format
+msgid "User %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:472
+#, python-format
+msgid "Group can't be created because group %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:478
+#, python-format
+msgid "Group can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:495
+#, python-format
+msgid "User %s can't be searched in group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:507
+#, python-format
+msgid "User %s can't be added to the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
+#, python-format
+msgid "The group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:513
+#, python-format
+msgid "User %(uid)s is already a member of the group %(group_dn)s"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:524
+#, python-format
+msgid ""
+"User %s can't be removed from the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:528
+#, python-format
+msgid "User %s is not a member of the group"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:542
+#, python-format
+msgid ""
+"Attempted to remove the last member of a group. Deleting the group at %s "
+"instead."
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:549
+#, python-format
+msgid "User %s can't be removed from all because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:564
+#, python-format
+msgid "Group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:40
+#, python-format
+msgid "Found non-unique network for bridge %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:43
+#, python-format
+msgid "Found no network for bridge %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:97
+#, python-format
+msgid "Creating new user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:105
+#, python-format
+msgid "Deleting user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:127
+#, python-format
+msgid "Adding role %(role)s to user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:131
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:137
+#, python-format
+msgid "Removing role %(role)s from user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:141
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:146 ../nova/api/ec2/admin.py:223
+msgid "operation must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:159
+#, python-format
+msgid "Getting x509 for user: %(name)s on project: %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:177
+#, python-format
+msgid "Create project %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:190
+#, python-format
+msgid "Modify project: %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:200
+#, python-format
+msgid "Delete project: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:214
+#, python-format
+msgid "Adding user %(user)s to project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:218
+#, python-format
+msgid "Removing user %(user)s from project %(project)s"
+msgstr ""
diff --git a/po/es.po b/po/es.po
index a54260db8..f97434041 100644
--- a/po/es.po
+++ b/po/es.po
@@ -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
@@ -125,33 +130,6 @@ msgstr "compute.api::suspend %s"
msgid "compute.api::resume %s"
msgstr "compute.api::resume %s"
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr "Numero de argumentos incorrectos"
-
-#: ../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"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr "No se encontró proceso"
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr "Sirviendo %s"
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr "Conjunto completo de opciones:"
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "Comenzando %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
#: ../nova/api/ec2/__init__.py:317
@@ -163,17 +141,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 +164,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 +187,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 +243,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 +260,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 +323,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 +337,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 +346,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 +360,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 +386,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 +396,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 +494,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 +504,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 +542,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 +557,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 +611,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 +652,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 +667,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 +687,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 +707,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 +722,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 +752,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 +765,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 +820,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 +859,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 +888,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
@@ -1796,34 +1792,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr "Obtenida excepción %s"
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr "actualizando %s..."
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr "error inesperado durante la actualización"
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr "excepción inexperada al obtener la conexión"
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr "Encontrada interfaz: %s"
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2286,10 +2254,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
@@ -2850,12 +2814,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 +2829,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 ""
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 000000000..83e4e7af0
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,2931 @@
+# French translation for nova
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the nova package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+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-05-27 16:50+0000\n"
+"Last-Translator: Capashen <Unknown>\n"
+"Language-Team: French <fr@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-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 "Pas d'hôte trouvé"
+
+#: ../nova/exception.py:33
+msgid "Unexpected error while running command."
+msgstr "Erreur imprévue lors de l'éxecution de la commande"
+
+#: ../nova/exception.py:36
+#, python-format
+msgid ""
+"%(description)s\n"
+"Command: %(cmd)s\n"
+"Exit code: %(exit_code)s\n"
+"Stdout: %(stdout)r\n"
+"Stderr: %(stderr)r"
+msgstr ""
+"%(description)s\n"
+"Commande : %(cmd)s\n"
+"Valeur retournée : %(exit_code)s\n"
+"Sortie standard : %(stdout)r\n"
+"Sortie d'erreur : %(stderr)r"
+
+#: ../nova/exception.py:107
+msgid "DB exception wrapped"
+msgstr "Remontée d'exception de la base de données"
+
+#. exc_type, exc_value, exc_traceback = sys.exc_info()
+#: ../nova/exception.py:120
+msgid "Uncaught exception"
+msgstr "Exception non prévue"
+
+#: ../nova/volume/api.py:45
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
+msgstr ""
+"Quota dépassé pour %(pid)s lors d'une tentative de création d'un volume de "
+"%(size)sG"
+
+#: ../nova/volume/api.py:47
+#, python-format
+msgid "Volume quota exceeded. You cannot create a volume of size %sG"
+msgstr "Quota de volume dépassé. Vous ne pouvez pas créer un volume de %sG"
+
+#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
+msgid "Volume status must be available"
+msgstr "Le status du volume doit être disponible"
+
+#: ../nova/volume/api.py:98
+msgid "Volume is already attached"
+msgstr "Volume déjà attaché"
+
+#: ../nova/volume/api.py:104
+msgid "Volume is already detached"
+msgstr "Volume déjà déttaché"
+
+#: ../nova/api/openstack/servers.py:72
+msgid "Failed to read private ip"
+msgstr "Echec lors de la lecture de l'ip privée"
+
+#: ../nova/api/openstack/servers.py:79
+msgid "Failed to read public ip(s)"
+msgstr "Echec lors de la lecture de l'ip(s) privée(s)"
+
+#: ../nova/api/openstack/servers.py:152
+#, python-format
+msgid "%(param)s property not found for image %(_image_id)s"
+msgstr ""
+"La propriété %(param)s n'a pas été trouvée pour l'image %(_image_id)s"
+
+#: ../nova/api/openstack/servers.py:168
+msgid "No keypairs defined"
+msgstr "Pas de paire de clés définie"
+
+#: ../nova/api/openstack/servers.py:238
+#, python-format
+msgid "Compute.api::lock %s"
+msgstr "Compute.api::lock %s"
+
+#: ../nova/api/openstack/servers.py:253
+#, python-format
+msgid "Compute.api::unlock %s"
+msgstr "Compute.api::unlock %s"
+
+#: ../nova/api/openstack/servers.py:267
+#, python-format
+msgid "Compute.api::get_lock %s"
+msgstr "Compute.api::get_lock %s"
+
+#: ../nova/api/openstack/servers.py:281
+#, python-format
+msgid "Compute.api::reset_network %s"
+msgstr "Compute.api::reset_network %s"
+
+#: ../nova/api/openstack/servers.py:292
+#, python-format
+msgid "Compute.api::pause %s"
+msgstr "Compute.api::pause %s"
+
+#: ../nova/api/openstack/servers.py:303
+#, python-format
+msgid "Compute.api::unpause %s"
+msgstr "Compute.api::unpause %s"
+
+#: ../nova/api/openstack/servers.py:314
+#, python-format
+msgid "compute.api::suspend %s"
+msgstr "compute.api::suspend %s"
+
+#: ../nova/api/openstack/servers.py:325
+#, python-format
+msgid "compute.api::resume %s"
+msgstr "compute.api::resume %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
+#: ../nova/api/ec2/__init__.py:317
+#, python-format
+msgid "Instance %s not found"
+msgstr "Instance %s non trouvée"
+
+#. NOTE: No Resource Pool concept so far
+#: ../nova/virt/xenapi/volumeops.py:51
+#, python-format
+msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
+msgstr "Attach_volume: %(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 ""
+"Impossible de créer VDI sur SR %(sr_ref)s pour l'instance %(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 ""
+"Impossible d'utiliser SR %(sr_ref)s pour l'instance %(instance_name)s"
+
+#: ../nova/virt/xenapi/volumeops.py:91
+#, python-format
+msgid "Unable to attach volume to instance %s"
+msgstr "Impossible d'attacher le volume à l'instance %s"
+
+#: ../nova/virt/xenapi/volumeops.py:93
+#, python-format
+msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
+msgstr ""
+"Le point de montage %(mountpoint)s a été attaché à l'instance "
+"%(instance_name)s"
+
+#. Detach VBD from VM
+#: ../nova/virt/xenapi/volumeops.py:104
+#, python-format
+msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
+msgstr "Detach_volume: %(instance_name)s, %(mountpoint)s"
+
+#: ../nova/virt/xenapi/volumeops.py:112
+#, python-format
+msgid "Unable to locate volume %s"
+msgstr "Impossible de trouver le volume %s"
+
+#: ../nova/virt/xenapi/volumeops.py:120
+#, python-format
+msgid "Unable to detach volume %s"
+msgstr "Impossible de détacher le volume %s"
+
+#: ../nova/virt/xenapi/volumeops.py:127
+#, python-format
+msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
+msgstr ""
+"Le point de montage %(mountpoint)s à été détaché de l'instance "
+"%(instance_name)s"
+
+#: ../nova/compute/instance_types.py:41
+#, python-format
+msgid "Unknown instance type: %s"
+msgstr "Type d'instance inconnu: %s"
+
+#: ../nova/crypto.py:46
+msgid "Filename of root CA"
+msgstr "Nom du fichier contenant la racine de l'autorité de certification"
+
+#: ../nova/crypto.py:49
+msgid "Filename of private key"
+msgstr "Nom de fichier de la clé privée"
+
+#: ../nova/crypto.py:51
+msgid "Filename of root Certificate Revokation List"
+msgstr "Nom de fichier de la racine de liste de révocation (CRL)"
+
+#: ../nova/crypto.py:53
+msgid "Where we keep our keys"
+msgstr "Emplacement de sauvegarde des clefs"
+
+#: ../nova/crypto.py:55
+msgid "Where we keep our root CA"
+msgstr "Emplacement de sauvegarde des racines d'autorité de certification"
+
+#: ../nova/crypto.py:57
+msgid "Should we use a CA for each project?"
+msgstr "Doit-on utiliser une autorité de certification pour chaque projet ?"
+
+#: ../nova/crypto.py:61
+#, python-format
+msgid "Subject for certificate for users, %s for project, user, timestamp"
+msgstr ""
+"Sujet pour les certificats utilisateurs, %s pour le projet, utilisateur, "
+"timestamp"
+
+#: ../nova/crypto.py:66
+#, python-format
+msgid "Subject for certificate for projects, %s for project, timestamp"
+msgstr "Sujet de certificat pour projets, %s pour le projet, timestamp"
+
+#: ../nova/crypto.py:71
+#, python-format
+msgid "Subject for certificate for vpns, %s for project, timestamp"
+msgstr "Suject de certificat pour les vpns, %s pour le projet, timestamp"
+
+#: ../nova/crypto.py:258
+#, python-format
+msgid "Flags path: %s"
+msgstr "Chemin des propriétés: %s"
+
+#: ../nova/scheduler/manager.py:69
+#, python-format
+msgid "Casting to %(topic)s %(host)s for %(method)s"
+msgstr "Typage de %(topic)s %(host)s pour %(method)s"
+
+#: ../nova/compute/manager.py:78
+#, python-format
+msgid "check_instance_lock: decorating: |%s|"
+msgstr "check_instance_lock: décoration : |%s|"
+
+#: ../nova/compute/manager.py:80
+#, python-format
+msgid ""
+"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
+msgstr ""
+"check_instance_lock: arguments : |%(self)s| |%(context)s| |%(instance_id)s|"
+
+#: ../nova/compute/manager.py:84
+#, python-format
+msgid "check_instance_lock: locked: |%s|"
+msgstr "check_instance_lock: vérouillé : |%s|"
+
+#: ../nova/compute/manager.py:86
+#, python-format
+msgid "check_instance_lock: admin: |%s|"
+msgstr "check_instance_lock: admin : |%s|"
+
+#: ../nova/compute/manager.py:91
+#, python-format
+msgid "check_instance_lock: executing: |%s|"
+msgstr "check_instance_lock: exécution : |%s|"
+
+#: ../nova/compute/manager.py:95
+#, python-format
+msgid "check_instance_lock: not executing |%s|"
+msgstr "check_instance_lock: ne s'éxécute pas |%s|"
+
+#: ../nova/compute/manager.py:179
+msgid "Instance has already been created"
+msgstr "L'instance a déjà été crée"
+
+#: ../nova/compute/manager.py:180
+#, python-format
+msgid "instance %s: starting..."
+msgstr "L'instance %s: est en train d'être démarée..."
+
+#. pylint: disable=W0702
+#: ../nova/compute/manager.py:219
+#, python-format
+msgid "instance %s: Failed to spawn"
+msgstr "instance %s: n'a pas pu être crée"
+
+#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
+#, python-format
+msgid "Terminating instance %s"
+msgstr "Arrêt de l'instance %s"
+
+#: ../nova/compute/manager.py:255
+#, python-format
+msgid "Deallocating address %s"
+msgstr "Dé-allocation de l'adresss %s"
+
+#: ../nova/compute/manager.py:268
+#, python-format
+msgid "trying to destroy already destroyed instance: %s"
+msgstr "Tentative de destruction d'une instance déjà détruite: %s"
+
+#: ../nova/compute/manager.py:282
+#, python-format
+msgid "Rebooting instance %s"
+msgstr "Redémarrage de l'instance %s"
+
+#: ../nova/compute/manager.py:287
+#, python-format
+msgid ""
+"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+"Tentative de redémarrage d'une instance non démarrée: %(instance_id)s "
+"(state: %(state)s s'attendait à : %(running)s)"
+
+#: ../nova/compute/manager.py:311
+#, python-format
+msgid "instance %s: snapshotting"
+msgstr "instance %s: création d'un instantané (snapshot)"
+
+#: ../nova/compute/manager.py:316
+#, python-format
+msgid ""
+"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+"Tentative de création d'un instantané (snapshot) pour une instance non "
+"démarrée: %(instance_id)s (state: %(state)s sattendait à : %(running)s)"
+
+#: ../nova/compute/manager.py:332
+#, python-format
+msgid ""
+"trying to reset the password on a non-running instance: %(instance_id)s "
+"(state: %(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+"Tentative de ré-initialisation du mot de passe pour une instance non "
+"démarrée: %(instance_id)s (state: %(instance_state)s expected: "
+"%(expected_state)s)"
+
+#: ../nova/compute/manager.py:335
+#, python-format
+msgid "instance %s: setting admin password"
+msgstr "instance %s: configuration du mot de passe admin"
+
+#: ../nova/compute/manager.py:353
+#, python-format
+msgid ""
+"trying to inject a file into a non-running instance: %(instance_id)s (state: "
+"%(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+"Tentative d'injection d'un fichier pour une instance non "
+"démarrée:%(instance_id)s (state: %(instance_state)s s'attendait à : "
+"%(expected_state)s)"
+
+#: ../nova/compute/manager.py:362
+#, python-format
+msgid "instance %(nm)s: injecting file to %(plain_path)s"
+msgstr "instance %(nm)s: injection de fichier vers %(plain_path)s"
+
+#: ../nova/compute/manager.py:372
+#, python-format
+msgid "instance %s: rescuing"
+msgstr "instance %s: récupération"
+
+#: ../nova/compute/manager.py:387
+#, python-format
+msgid "instance %s: unrescuing"
+msgstr "instance %s: dé-récupération"
+
+#: ../nova/compute/manager.py:406
+#, python-format
+msgid "instance %s: pausing"
+msgstr "instance %s: mise en pause"
+
+#: ../nova/compute/manager.py:423
+#, python-format
+msgid "instance %s: unpausing"
+msgstr "instance %s: reprise après pause"
+
+#: ../nova/compute/manager.py:440
+#, python-format
+msgid "instance %s: retrieving diagnostics"
+msgstr "instance %s: récupération des diagnostiques"
+
+#: ../nova/compute/manager.py:453
+#, python-format
+msgid "instance %s: suspending"
+msgstr "instance %s: suspension"
+
+#: ../nova/compute/manager.py:472
+#, python-format
+msgid "instance %s: resuming"
+msgstr "instance %s: reprise après suspension"
+
+#: ../nova/compute/manager.py:491
+#, python-format
+msgid "instance %s: locking"
+msgstr "instance %s: vérrouillage"
+
+#: ../nova/compute/manager.py:503
+#, python-format
+msgid "instance %s: unlocking"
+msgstr "instance %s: déverrouillage"
+
+#: ../nova/compute/manager.py:513
+#, python-format
+msgid "instance %s: getting locked state"
+msgstr "instance %s: récupération de l'état de vérouillage"
+
+#: ../nova/compute/manager.py:526
+#, python-format
+msgid "instance %s: reset network"
+msgstr "instance %s: redémarrage du réseau"
+
+#: ../nova/compute/manager.py:535 ../nova/api/ec2/cloud.py:515
+#, python-format
+msgid "Get console output for instance %s"
+msgstr "Récupération de la sortie de la console de l'instance %s"
+
+#: ../nova/compute/manager.py:543
+#, python-format
+msgid "instance %s: getting ajax console"
+msgstr "instance %s: préparation d'une console ajax"
+
+#: ../nova/compute/manager.py:553
+#, python-format
+msgid ""
+"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
+msgstr ""
+"instance %(instance_id)s: montage du volume %(volume_id)s à %(mountpoint)s"
+
+#. pylint: disable=W0702
+#. NOTE(vish): The inline callback eats the exception info so we
+#. log the traceback here and reraise the same
+#. ecxception below.
+#: ../nova/compute/manager.py:569
+#, python-format
+msgid "instance %(instance_id)s: attach failed %(mountpoint)s, removing"
+msgstr ""
+"instance %(instance_id)s: Échec de montage %(mountpoint)s, supression"
+
+#: ../nova/compute/manager.py:585
+#, python-format
+msgid ""
+"Detach volume %(volume_id)s from mountpoint %(mp)s on instance "
+"%(instance_id)s"
+msgstr ""
+"Démontage du volume %(volume_id)s du point de montage %(mp)s sur l'instance "
+"%(instance_id)s"
+
+#: ../nova/compute/manager.py:588
+#, python-format
+msgid "Detaching volume from unknown instance %s"
+msgstr "Démontage de volume d'une instance inconnue %s"
+
+#: ../nova/scheduler/simple.py:53
+#, python-format
+msgid "Host %s is not alive"
+msgstr "Host %s n'est pas en fonction"
+
+#: ../nova/scheduler/simple.py:65
+msgid "All hosts have too many cores"
+msgstr "Tous les hôtes ont trop de coeurs"
+
+#: ../nova/scheduler/simple.py:87
+#, python-format
+msgid "Host %s not available"
+msgstr "Hôte %s non disponible"
+
+#: ../nova/scheduler/simple.py:99
+msgid "All hosts have too many gigabytes"
+msgstr "Tous les hôtes ont trop de mémoire"
+
+#: ../nova/scheduler/simple.py:119
+msgid "All hosts have too many networks"
+msgstr "Tous les hôtes ont trop de réseaux"
+
+#: ../nova/volume/manager.py:85
+#, python-format
+msgid "Re-exporting %s volumes"
+msgstr "Ré-exportation de %s volumes"
+
+#: ../nova/volume/manager.py:90
+#, python-format
+msgid "volume %s: skipping export"
+msgstr "volume %s : exportation évitée"
+
+#: ../nova/volume/manager.py:96
+#, python-format
+msgid "volume %s: creating"
+msgstr "volume %s: création"
+
+#: ../nova/volume/manager.py:108
+#, python-format
+msgid "volume %(vol_name)s: creating lv of size %(vol_size)sG"
+msgstr "volume %(vol_name)s: cŕeation d'un volume logique de %(vol_size)sG"
+
+#: ../nova/volume/manager.py:112
+#, python-format
+msgid "volume %s: creating export"
+msgstr "volume %s: exportation en cours"
+
+#: ../nova/volume/manager.py:123
+#, python-format
+msgid "volume %s: created successfully"
+msgstr "volume %s: crée avec succès"
+
+#: ../nova/volume/manager.py:131
+msgid "Volume is still attached"
+msgstr "Le volume est encore attaché"
+
+#: ../nova/volume/manager.py:133
+msgid "Volume is not local to this node"
+msgstr "Le volume n'est pas local à ce noeud"
+
+#: ../nova/volume/manager.py:136
+#, python-format
+msgid "volume %s: removing export"
+msgstr "volume %s: suppression de l'exportation"
+
+#: ../nova/volume/manager.py:138
+#, python-format
+msgid "volume %s: deleting"
+msgstr "volume %s: suppression"
+
+#: ../nova/volume/manager.py:147
+#, python-format
+msgid "volume %s: deleted successfully"
+msgstr "volume %s: supprimé avec succès"
+
+#: ../nova/virt/xenapi/fake.py:74
+#, python-format
+msgid "%(text)s: _db_content => %(content)s"
+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
+msgid "Raising NotImplemented"
+msgstr "Fonction non implémentée"
+
+#: ../nova/virt/xenapi/fake.py:306
+#, python-format
+msgid "xenapi.fake does not have an implementation for %s"
+msgstr "xenapi.fake n'a pas d'implémentation pour %s"
+
+#: ../nova/virt/xenapi/fake.py:341
+#, python-format
+msgid "Calling %(localname)s %(impl)s"
+msgstr "Appel %(localname)s %(impl)s"
+
+#: ../nova/virt/xenapi/fake.py:346
+#, python-format
+msgid "Calling getter %s"
+msgstr "Appel du getter %s"
+
+#: ../nova/virt/xenapi/fake.py:406
+#, python-format
+msgid ""
+"xenapi.fake does not have an implementation for %s or it has been called "
+"with the wrong number of arguments"
+msgstr ""
+"xenapi.fake n'a pas d'implementation pour %s ou il a été appelé avec le "
+"mauvais nombre d'arguments"
+
+#: ../nova/tests/test_cloud.py:256
+msgid "Can't test instances without a real virtual env."
+msgstr "Ne peut pas tester les instances sans un env virtuel."
+
+#: ../nova/tests/test_cloud.py:268
+#, python-format
+msgid "Need to watch instance %s until it's running..."
+msgstr "Besoin de surveiller l'instance %s jusqu'à son démarrage..."
+
+#: ../nova/virt/connection.py:73
+msgid "Failed to open connection to the hypervisor"
+msgstr "Échec lors de l'ouverture d'une connexion à l'hyperviseur"
+
+#: ../nova/network/linux_net.py:187
+#, python-format
+msgid "Starting VLAN inteface %s"
+msgstr "Démarrage de l'interface VLAN %s"
+
+#: ../nova/network/linux_net.py:208
+#, python-format
+msgid "Starting Bridge interface for %s"
+msgstr "Démarrage de l'interface de Bridge %s"
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:314
+#, python-format
+msgid "Hupping dnsmasq threw %s"
+msgstr "Hupping dnsmasq à renvoyé %s"
+
+#: ../nova/network/linux_net.py:316
+#, python-format
+msgid "Pid %d is stale, relaunching dnsmasq"
+msgstr "Pid %d est dépassé, re-démarrage de dnsmasq"
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:358
+#, python-format
+msgid "killing radvd threw %s"
+msgstr "La destruction de radvd à renvoyé %s"
+
+#: ../nova/network/linux_net.py:360
+#, python-format
+msgid "Pid %d is stale, relaunching radvd"
+msgstr "Pid %d est dépassé, re-démarrage radvd"
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:449
+#, python-format
+msgid "Killing dnsmasq threw %s"
+msgstr "La destruction de dnsmasq à renvoyé %s"
+
+#: ../nova/utils.py:58
+#, python-format
+msgid "Inner Exception: %s"
+msgstr "Exception interne : %s"
+
+#: ../nova/utils.py:59
+#, python-format
+msgid "Class %s cannot be found"
+msgstr "La classe %s n'a pas pu être trouvée"
+
+#: ../nova/utils.py:118
+#, python-format
+msgid "Fetching %s"
+msgstr "Récupèration de %s"
+
+#: ../nova/utils.py:130
+#, python-format
+msgid "Running cmd (subprocess): %s"
+msgstr "Execution de la commande (sous-processus) : %s"
+
+#: ../nova/utils.py:143 ../nova/utils.py:183
+#, python-format
+msgid "Result was %s"
+msgstr "Le résultat était %s"
+
+#: ../nova/utils.py:159
+#, python-format
+msgid "Running cmd (SSH): %s"
+msgstr "Execution de la cmd (SSH): %s"
+
+#: ../nova/utils.py:217
+#, python-format
+msgid "debug in callback: %s"
+msgstr "Debug dans le rappel : %s"
+
+#: ../nova/utils.py:222
+#, python-format
+msgid "Running %s"
+msgstr "Exécution de %s"
+
+#: ../nova/utils.py:262
+#, python-format
+msgid "Link Local address is not found.:%s"
+msgstr "L'adresse du lien local n'a pas été trouvé :%s"
+
+#: ../nova/utils.py:265
+#, python-format
+msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
+msgstr "Impossible de trouver l'IP du lien local de %(interface)s :%(ex)s"
+
+#: ../nova/utils.py:363
+#, python-format
+msgid "Invalid backend: %s"
+msgstr "Backend invalide : %s"
+
+#: ../nova/utils.py:374
+#, python-format
+msgid "backend %s"
+msgstr "backend %s"
+
+#: ../nova/fakerabbit.py:49
+#, python-format
+msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
+msgstr "(%(nm)s) publication (key: %(routing_key)s) %(message)s"
+
+#: ../nova/fakerabbit.py:54
+#, python-format
+msgid "Publishing to route %s"
+msgstr "Publication vers la route %s"
+
+#: ../nova/fakerabbit.py:84
+#, python-format
+msgid "Declaring queue %s"
+msgstr "Déclaration de la queue %s"
+
+#: ../nova/fakerabbit.py:90
+#, python-format
+msgid "Declaring exchange %s"
+msgstr "Déclaration de l'échange %s"
+
+#: ../nova/fakerabbit.py:96
+#, python-format
+msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
+msgstr ""
+"Rattachement de %(queue)s vers %(exchange)s avec la clef %(routing_key)s"
+
+#: ../nova/fakerabbit.py:121
+#, python-format
+msgid "Getting from %(queue)s: %(message)s"
+msgstr "Récupération depuis %(queue)s: %(message)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
+#, python-format
+msgid "Created VM %s..."
+msgstr "VM %s crée..."
+
+#: ../nova/virt/xenapi/vm_utils.py:138
+#, python-format
+msgid "Created VM %(instance_name)s as %(vm_ref)s."
+msgstr "VM %(instance_name)s crée en tant que %(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 "Création de VBD pour 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 "VBD créé %(vbd_ref)s pour VM %(vm_ref)s, VDI %(vdi_ref)s."
+
+#: ../nova/virt/xenapi/vm_utils.py:187
+#, python-format
+msgid "VBD not found in instance %s"
+msgstr "VBD non trouvé dans l'instance %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:197
+#, python-format
+msgid "Unable to unplug VBD %s"
+msgstr "Impossible de deconnecter le VBD %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:209
+#, python-format
+msgid "Unable to destroy VBD %s"
+msgstr "Impossible de supprimer le VBD %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:224
+#, python-format
+msgid "Creating VIF for VM %(vm_ref)s, network %(network_ref)s."
+msgstr "Création du VIF pour la VM %(vm_ref)s, réseau %(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 "VIF créé %(vif_ref)s pour la VM %(vm_ref)s, network %(network_ref)s."
+
+#: ../nova/virt/xenapi/vm_utils.py:246
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(sr_ref)s."
+msgstr ""
+"VDI créé %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(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 ""
+"Création de l'instantané (snapshot) pour la VM %(vm_ref)s avec le label "
+"'%(label)s'..."
+
+#: ../nova/virt/xenapi/vm_utils.py:272
+#, python-format
+msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
+msgstr ""
+"Instantané (snapshot) créé %(template_vm_ref)s pour 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 ""
+"Demande de chargement à xapi de %(vdi_uuids)s en tant qu'ID %(image_id)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:327
+#, python-format
+msgid "Size for image %(image)s:%(virtual_size)d"
+msgstr "Taille de l'image %(image)s:%(virtual_size)d"
+
+#: ../nova/virt/xenapi/vm_utils.py:332
+#, python-format
+msgid "Glance image %s"
+msgstr "Image 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 "Copie de VDI %s vers /boot/guest sur dom0"
+
+#: ../nova/virt/xenapi/vm_utils.py:352
+#, python-format
+msgid "Kernel/Ramdisk VDI %s destroyed"
+msgstr "Noyau/Ramdisk VDI %s détruit"
+
+#: ../nova/virt/xenapi/vm_utils.py:361
+#, python-format
+msgid "Asking xapi to fetch %(url)s as %(access)s"
+msgstr "Demande de récupération à xapi de %(url)s as %(access)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
+#, python-format
+msgid "Looking up vdi %s for PV kernel"
+msgstr "Recherche du VDI %s pour le PV kernel"
+
+#: ../nova/virt/xenapi/vm_utils.py:397
+#, python-format
+msgid "PV Kernel in VDI:%s"
+msgstr "PV Kernel sur VDI :%s"
+
+#: ../nova/virt/xenapi/vm_utils.py:405
+#, python-format
+msgid "Running pygrub against %s"
+msgstr "Exécution de pygrub sur %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:411
+#, python-format
+msgid "Found Xen kernel %s"
+msgstr "Kernel Xen %s trouvé"
+
+#: ../nova/virt/xenapi/vm_utils.py:413
+msgid "No Xen kernel found. Booting HVM."
+msgstr "Pas de kernel Xen trouvé. Démarrage en HVM."
+
+#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
+#, python-format
+msgid "duplicate name found: %s"
+msgstr "Doublon de nom trouvé : %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:442
+#, python-format
+msgid "VDI %s is still available"
+msgstr "Le VDI %s est toujours disponible"
+
+#: ../nova/virt/xenapi/vm_utils.py:463
+#, python-format
+msgid "(VM_UTILS) xenserver vm state -> |%s|"
+msgstr "(VM_UTILS) état xenserver vm -> |%s|"
+
+#: ../nova/virt/xenapi/vm_utils.py:465
+#, python-format
+msgid "(VM_UTILS) xenapi power_state -> |%s|"
+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 "VHD %(vdi_uuid)s à pour parent %(parent_ref)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:542
+#, python-format
+msgid "Re-scanning SR %s"
+msgstr "Re-parcours de SR %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:567
+#, python-format
+msgid ""
+"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
+msgstr ""
+"VHD tentatives de coalesence dépassé (%(counter)d > %(max_attempts)d), "
+"abandon..."
+
+#: ../nova/virt/xenapi/vm_utils.py:574
+#, python-format
+msgid ""
+"Parent %(parent_uuid)s doesn't match original parent "
+"%(original_parent_uuid)s, waiting for coalesce..."
+msgstr ""
+"L'UUID parent %(parent_uuid)s ne correspond pas au parent originel "
+"%(original_parent_uuid)s, attente de coalesence..."
+
+#: ../nova/virt/xenapi/vm_utils.py:590
+#, python-format
+msgid "No VDIs found for VM %s"
+msgstr "Pas de VDIs trouvé pour la VM %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:594
+#, python-format
+msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
+msgstr ""
+"Nombre de VDIs non attendu (%(num_vdis)s) trouvés pour la 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 "Création de VBD pour la 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 "La création de VBD pour la VDI %s est terminée."
+
+#: ../nova/virt/xenapi/vm_utils.py:657
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
+#, python-format
+msgid "Plugging VBD %s ... "
+msgstr "Connexion de VBD %s ... "
+
+#: ../nova/virt/xenapi/vm_utils.py:659
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:194
+#, python-format
+msgid "Plugging VBD %s done."
+msgstr "Connexion de VBD %s terminée."
+
+#: ../nova/virt/xenapi/vm_utils.py:661
+#, python-format
+msgid "VBD %(vbd)s plugged as %(orig_dev)s"
+msgstr "VBD %(vbd)s connecté en tant que %(orig_dev)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:664
+#, python-format
+msgid "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
+msgstr "VBD %(vbd)s connecté au mauvais device, re-connexion vers %(dev)s"
+
+#: ../nova/virt/xenapi/vm_utils.py:668
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:197
+#, python-format
+msgid "Destroying VBD for VDI %s ... "
+msgstr "Destruction de VBD pour la VDI %s ... "
+
+#: ../nova/virt/xenapi/vm_utils.py:671
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:200
+#, python-format
+msgid "Destroying VBD for VDI %s done."
+msgstr "Destruction de VBD pour la VDI %s terminée."
+
+#: ../nova/virt/xenapi/vm_utils.py:683
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:211
+msgid "VBD.unplug successful first time."
+msgstr "VBD.unplug terminé dés la première tentative."
+
+#: ../nova/virt/xenapi/vm_utils.py:688
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:216
+msgid "VBD.unplug rejected: retrying..."
+msgstr "VBD.unplug refusé : nouvel essai..."
+
+#: ../nova/virt/xenapi/vm_utils.py:692
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:220
+msgid "VBD.unplug successful eventually."
+msgstr "VBD.unplug à enfin été achevée."
+
+#: ../nova/virt/xenapi/vm_utils.py:695
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:223
+#, python-format
+msgid "Ignoring XenAPI.Failure in VBD.unplug: %s"
+msgstr "XenAPI.Failure ignorée dans VBD.unplug: %s"
+
+#: ../nova/virt/xenapi/vm_utils.py:704
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:66
+#, python-format
+msgid "Ignoring XenAPI.Failure %s"
+msgstr "XenAPI.Failure %s ignorée"
+
+#: ../nova/virt/xenapi/vm_utils.py:735
+#, python-format
+msgid ""
+"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
+msgstr ""
+"Ecriture de la table de partitionnement %(primary_first)d %(primary_last)d "
+"vers %(dest)s..."
+
+#: ../nova/virt/xenapi/vm_utils.py:747
+#, python-format
+msgid "Writing partition table %s done."
+msgstr "Ecriture de la table de partitionnement %s terminée."
+
+#: ../nova/tests/test_rpc.py:89
+#, python-format
+msgid "Nested received %(queue)s, %(value)s"
+msgstr "Reception par Nested %(queue)s, %(value)s"
+
+#: ../nova/tests/test_rpc.py:95
+#, python-format
+msgid "Nested return %s"
+msgstr "Nested renvoi %s"
+
+#: ../nova/tests/test_rpc.py:120 ../nova/tests/test_rpc.py:126
+#, python-format
+msgid "Received %s"
+msgstr "%s Reçu"
+
+#: ../nova/db/sqlalchemy/api.py:44
+msgid "Use of empty request context is deprecated"
+msgstr "L'utilisation d'une requête de contexte vide est dévalué"
+
+#: ../nova/db/sqlalchemy/api.py:133
+#, python-format
+msgid "No service for id %s"
+msgstr "Pas de service pour l'id %s"
+
+#: ../nova/db/sqlalchemy/api.py:251
+#, python-format
+msgid "No service for %(host)s, %(binary)s"
+msgstr "Pas de service pour %(host)s, %(binary)s"
+
+#: ../nova/db/sqlalchemy/api.py:592
+msgid "No fixed ips defined"
+msgstr "Aucune IP fixe définie"
+
+#: ../nova/db/sqlalchemy/api.py:608
+#, python-format
+msgid "No floating ip for address %s"
+msgstr "Pas d'IP flottante pour l'addresse %s"
+
+#: ../nova/db/sqlalchemy/api.py:629
+#, python-format
+msgid "No address for instance %s"
+msgstr "Pas d'adresse pour l'instance %s"
+
+#: ../nova/db/sqlalchemy/api.py:961
+#, python-format
+msgid "no keypair for user %(user_id)s, name %(name)s"
+msgstr "Pas de bi-clef pour l'utilisation %(user_id)s, nommé %(name)s"
+
+#: ../nova/db/sqlalchemy/api.py:1076 ../nova/db/sqlalchemy/api.py:1156
+#, python-format
+msgid "No network for id %s"
+msgstr "Pas de réseau pourl'id %s"
+
+#: ../nova/db/sqlalchemy/api.py:1086
+msgid "No networks defined"
+msgstr "Pas de réseau défini"
+
+#: ../nova/db/sqlalchemy/api.py:1115
+#, python-format
+msgid "No network for bridge %s"
+msgstr "Pas de réseau pour le bridge %s"
+
+#: ../nova/db/sqlalchemy/api.py:1129 ../nova/db/sqlalchemy/api.py:1142
+#, python-format
+msgid "No network for instance %s"
+msgstr "Pas de réseau pour l'instance %s"
+
+#: ../nova/db/sqlalchemy/api.py:1277
+#, python-format
+msgid "Token %s does not exist"
+msgstr "Le jeton %s n'existe pas"
+
+#: ../nova/db/sqlalchemy/api.py:1302
+#, python-format
+msgid "No quota for project_id %s"
+msgstr "Pas de quota pour l'ID projet %s"
+
+#: ../nova/db/sqlalchemy/api.py:1455 ../nova/db/sqlalchemy/api.py:1501
+#: ../nova/api/ec2/__init__.py:323
+#, python-format
+msgid "Volume %s not found"
+msgstr "Volume %s non trouvé"
+
+#: ../nova/db/sqlalchemy/api.py:1514
+#, python-format
+msgid "No export device found for volume %s"
+msgstr "Pas de device d'exportation pour le volume %s"
+
+#: ../nova/db/sqlalchemy/api.py:1527
+#, python-format
+msgid "No target id found for volume %s"
+msgstr "Pas d'id de destination trouvée pour le volume %s"
+
+#: ../nova/db/sqlalchemy/api.py:1572
+#, python-format
+msgid "No security group with id %s"
+msgstr "Aucun groupe de sécurité avec l'id %s"
+
+#: ../nova/db/sqlalchemy/api.py:1589
+#, python-format
+msgid "No security group named %(group_name)s for project: %(project_id)s"
+msgstr ""
+"Aucun groupe de sécurité nommé %(group_name)s pour le projet : %(project_id)s"
+
+#: ../nova/db/sqlalchemy/api.py:1682
+#, python-format
+msgid "No secuity group rule with id %s"
+msgstr "Pas de groupe de sécurité ayant pour ID %s"
+
+#: ../nova/db/sqlalchemy/api.py:1756
+#, python-format
+msgid "No user for id %s"
+msgstr "Pas d'utilisateur ayant pour ID %s"
+
+#: ../nova/db/sqlalchemy/api.py:1772
+#, python-format
+msgid "No user for access key %s"
+msgstr "Pas d'utilisateur avec la clef d'accès %s"
+
+#: ../nova/db/sqlalchemy/api.py:1834
+#, python-format
+msgid "No project with id %s"
+msgstr "Pas de projet ayant pour ID %s"
+
+#: ../nova/db/sqlalchemy/api.py:1979
+#, python-format
+msgid "No console pool with id %(pool_id)s"
+msgstr "Pas de groupe de console ayant pour ID %(pool_id)s"
+
+#: ../nova/db/sqlalchemy/api.py:1996
+#, python-format
+msgid ""
+"No console pool of type %(console_type)s for compute host %(compute_host)s "
+"on proxy host %(host)s"
+msgstr ""
+"Pas de groupe de console de type %(console_type)s pour l'hote de calcul "
+"%(compute_host)s sur le proxy %(host)s"
+
+#: ../nova/db/sqlalchemy/api.py:2035
+#, python-format
+msgid "No console for instance %(instance_id)s in pool %(pool_id)s"
+msgstr ""
+"Pas de console pour l'intance %(instance_id)s dans le groupe %(pool_id)s"
+
+#: ../nova/db/sqlalchemy/api.py:2057
+#, python-format
+msgid "on instance %s"
+msgstr "sur l'intance %s"
+
+#: ../nova/db/sqlalchemy/api.py:2058
+#, python-format
+msgid "No console with id %(console_id)s %(idesc)s"
+msgstr "Pas de console ayant pour ID %(console_id)s %(idesc)s"
+
+#: ../nova/db/sqlalchemy/api.py:2078 ../nova/db/sqlalchemy/api.py:2097
+#, python-format
+msgid "No zone with id %(zone_id)s"
+msgstr "Pas de zone ayant pour ID %(zone_id)s"
+
+#: ../nova/virt/libvirt_conn.py:160
+#, python-format
+msgid "Checking state of %s"
+msgstr "Vérification de l'état de %s"
+
+#: ../nova/virt/libvirt_conn.py:165
+#, python-format
+msgid "Current state of %(name)s was %(state)s."
+msgstr "L'état de %(name)s est %(state)s."
+
+#: ../nova/virt/libvirt_conn.py:183
+#, python-format
+msgid "Connecting to libvirt: %s"
+msgstr "Connexion à libvirt: %s"
+
+#: ../nova/virt/libvirt_conn.py:196
+msgid "Connection to libvirt broke"
+msgstr "Connexion à libvirt interrompue"
+
+#: ../nova/virt/libvirt_conn.py:258
+#, python-format
+msgid "instance %(instance_name)s: deleting instance files %(target)s"
+msgstr ""
+"instance %(instance_name)s: suppression des fichiers d'instance %(target)s"
+
+#: ../nova/virt/libvirt_conn.py:283
+#, python-format
+msgid "Invalid device path %s"
+msgstr "Chemin de device invalide %s"
+
+#: ../nova/virt/libvirt_conn.py:313
+#, python-format
+msgid "No disk at %s"
+msgstr "Pas de disque sur %s"
+
+#: ../nova/virt/libvirt_conn.py:320
+msgid "Instance snapshotting is not supported for libvirtat this time"
+msgstr ""
+"Les instantanés (snapshot) d'instance ne sont pas disponible avec libvirt "
+"pour le moment"
+
+#: ../nova/virt/libvirt_conn.py:336
+#, python-format
+msgid "instance %s: rebooted"
+msgstr "instance %s: re-démarrée"
+
+#: ../nova/virt/libvirt_conn.py:339
+#, python-format
+msgid "_wait_for_reboot failed: %s"
+msgstr "_wait_for_reboot échouée : %s"
+
+#: ../nova/virt/libvirt_conn.py:382
+#, python-format
+msgid "instance %s: rescued"
+msgstr "instance %s: récupérée"
+
+#: ../nova/virt/libvirt_conn.py:385
+#, python-format
+msgid "_wait_for_rescue failed: %s"
+msgstr "_wait_for_rescue échouée : %s"
+
+#: ../nova/virt/libvirt_conn.py:411
+#, python-format
+msgid "instance %s: is running"
+msgstr "instance %s: est active"
+
+#: ../nova/virt/libvirt_conn.py:422
+#, python-format
+msgid "instance %s: booted"
+msgstr "instance %s: a démarrée"
+
+#: ../nova/virt/libvirt_conn.py:425 ../nova/virt/xenapi/vmops.py:186
+#, python-format
+msgid "instance %s: failed to boot"
+msgstr "instance %s: n'a pas réussie à démarrer"
+
+#: ../nova/virt/libvirt_conn.py:436
+#, python-format
+msgid "virsh said: %r"
+msgstr "virsh a retourné : %r"
+
+#: ../nova/virt/libvirt_conn.py:440
+msgid "cool, it's a device"
+msgstr "super, c'est un device"
+
+#: ../nova/virt/libvirt_conn.py:448
+#, python-format
+msgid "data: %(data)r, fpath: %(fpath)r"
+msgstr "data: %(data)r, fpath: %(fpath)r"
+
+#: ../nova/virt/libvirt_conn.py:456
+#, python-format
+msgid "Contents of file %(fpath)s: %(contents)r"
+msgstr "Contenu du fichier %(fpath)s: %(contents)r"
+
+#: ../nova/virt/libvirt_conn.py:489
+msgid "Unable to find an open port"
+msgstr "Impossible de trouver un port ouvert"
+
+#: ../nova/virt/libvirt_conn.py:563
+#, python-format
+msgid "instance %s: Creating image"
+msgstr "instance %s : Création de l'image"
+
+#: ../nova/virt/libvirt_conn.py:646
+#, python-format
+msgid "instance %(inst_name)s: injecting key into image %(img_id)s"
+msgstr "instance %(inst_name)s : injection de clef dans l'image %(img_id)s"
+
+#: ../nova/virt/libvirt_conn.py:649
+#, python-format
+msgid "instance %(inst_name)s: injecting net into image %(img_id)s"
+msgstr "instance %(inst_name)s : injection de réseau dans l'image %(img_id)s"
+
+#. This could be a windows image, or a vmdk format disk
+#: ../nova/virt/libvirt_conn.py:657
+#, python-format
+msgid ""
+"instance %(inst_name)s: ignoring error injecting data into image %(img_id)s "
+"(%(e)s)"
+msgstr ""
+"instance %(inst_name)s : l'erreur d'injection de donné dans l'image "
+"%(img_id)s (%(e)s) a été ignorée"
+
+#. TODO(termie): cache?
+#: ../nova/virt/libvirt_conn.py:665
+#, python-format
+msgid "instance %s: starting toXML method"
+msgstr "instance %s: démarrage de la méthode toXML"
+
+#: ../nova/virt/libvirt_conn.py:732
+#, python-format
+msgid "instance %s: finished toXML method"
+msgstr "instance %s: fin d'éxécution de la méthode toXML"
+
+#: ../nova/virt/libvirt_conn.py:751
+msgid "diagnostics are not supported for libvirt"
+msgstr "Les diagnostiques ne sont pas disponibles pour libvirt"
+
+#: ../nova/virt/libvirt_conn.py:1225
+#, python-format
+msgid "Attempted to unfilter instance %s which is not filtered"
+msgstr ""
+"Tentative de suppression de filtre pour l'intance %s qui n'est pas filtrée"
+
+#: ../nova/api/ec2/metadatarequesthandler.py:76
+#, python-format
+msgid "Failed to get metadata for ip: %s"
+msgstr "Impossible de récupérer les méta-donnérs pour l'IP : %s"
+
+#: ../nova/auth/fakeldap.py:33
+msgid "Attempted to instantiate singleton"
+msgstr "Tentative d'instanciation d'un singleton"
+
+#: ../nova/network/api.py:39
+#, python-format
+msgid "Quota exceeeded for %s, tried to allocate address"
+msgstr "Quota dépassé pour %s lors de la tentative d'allocation d'adresse"
+
+#: ../nova/network/api.py:42
+msgid "Address quota exceeded. You cannot allocate any more addresses"
+msgstr "Quota d'adresse dépassé. Vous ne pouvez pas allouer d'autre adresse"
+
+#: ../nova/tests/test_volume.py:162
+#, python-format
+msgid "Target %s allocated"
+msgstr "Destination %s allouée"
+
+#: ../nova/virt/images.py:70
+#, python-format
+msgid "Finished retreving %(url)s -- placed in %(path)s"
+msgstr "Fin de récupération de %(url)s -- placé dans %(path)s"
+
+#: ../nova/scheduler/driver.py:66
+msgid "Must implement a fallback schedule"
+msgstr "Doit mettre en oeuvre un calendrier de retrait"
+
+#: ../nova/console/manager.py:70
+msgid "Adding console"
+msgstr "Ajout de console"
+
+#: ../nova/console/manager.py:90
+#, python-format
+msgid "Tried to remove non-existant console %(console_id)s."
+msgstr "Tentative de suppression d'une console non existante %(console_id)s."
+
+#: ../nova/api/direct.py:149
+msgid "not available"
+msgstr "non disponible"
+
+#: ../nova/api/ec2/cloud.py:62
+#, python-format
+msgid "The key_pair %s already exists"
+msgstr "Le bi-clef %s existe déjà"
+
+#. TODO(vish): Do this with M2Crypto instead
+#: ../nova/api/ec2/cloud.py:118
+#, python-format
+msgid "Generating root CA: %s"
+msgstr "Génération de la racine d'autorité de certification : %s"
+
+#: ../nova/api/ec2/cloud.py:303
+#, python-format
+msgid "Create key pair %s"
+msgstr "Création du bi-clef %s"
+
+#: ../nova/api/ec2/cloud.py:311
+#, python-format
+msgid "Delete key pair %s"
+msgstr "Suppression du bi-clef %s"
+
+#: ../nova/api/ec2/cloud.py:386
+#, python-format
+msgid "%s is not a valid ipProtocol"
+msgstr "%s n'est pas un protocol ip valide"
+
+#: ../nova/api/ec2/cloud.py:390
+msgid "Invalid port range"
+msgstr "Interval de port invalide"
+
+#: ../nova/api/ec2/cloud.py:421
+#, python-format
+msgid "Revoke security group ingress %s"
+msgstr "Révocation de groupe de sécurité %s"
+
+#: ../nova/api/ec2/cloud.py:430 ../nova/api/ec2/cloud.py:459
+msgid "Not enough parameters to build a valid rule."
+msgstr "Pas assez de parametres pour contruire un règle valide."
+
+#: ../nova/api/ec2/cloud.py:443
+msgid "No rule for the specified parameters."
+msgstr "Pas de règle pour les paramètres spécifiés."
+
+#: ../nova/api/ec2/cloud.py:450
+#, python-format
+msgid "Authorize security group ingress %s"
+msgstr "Authorisation du groupe de sécurité %s"
+
+#: ../nova/api/ec2/cloud.py:464
+#, python-format
+msgid "This rule already exists in group %s"
+msgstr "Cette règle existe déjà dans le groupe %s"
+
+#: ../nova/api/ec2/cloud.py:492
+#, python-format
+msgid "Create Security Group %s"
+msgstr "Création du groupe de sécurité %s"
+
+#: ../nova/api/ec2/cloud.py:495
+#, python-format
+msgid "group %s already exists"
+msgstr "le groupe %s existe déjà"
+
+#: ../nova/api/ec2/cloud.py:507
+#, python-format
+msgid "Delete security group %s"
+msgstr "Suppression du groupe de sécurité %s"
+
+#: ../nova/api/ec2/cloud.py:584
+#, python-format
+msgid "Create volume of %s GB"
+msgstr "Création d'un volume de %s Go"
+
+#: ../nova/api/ec2/cloud.py:612
+#, python-format
+msgid "Attach volume %(volume_id)s to instance %(instance_id)s at %(device)s"
+msgstr ""
+"Montage du volume %(volume_id)s sur l'instance %(instance_id)s en tant que "
+"%(device)s"
+
+#: ../nova/api/ec2/cloud.py:629
+#, python-format
+msgid "Detach volume %s"
+msgstr "Dé-montage du volume %s"
+
+#: ../nova/api/ec2/cloud.py:761
+msgid "Allocate address"
+msgstr "Allocation d'adresse"
+
+#: ../nova/api/ec2/cloud.py:766
+#, python-format
+msgid "Release address %s"
+msgstr "Désallocation de l'adresse %s"
+
+#: ../nova/api/ec2/cloud.py:771
+#, python-format
+msgid "Associate address %(public_ip)s to instance %(instance_id)s"
+msgstr ""
+"Association de l'adresse %(public_ip)s avec l'instance %(instance_id)s"
+
+#: ../nova/api/ec2/cloud.py:780
+#, python-format
+msgid "Disassociate address %s"
+msgstr "Désassociation de l'adresse %s"
+
+#: ../nova/api/ec2/cloud.py:807
+msgid "Going to start terminating instances"
+msgstr "Début de la destruction d'instance"
+
+#: ../nova/api/ec2/cloud.py:815
+#, python-format
+msgid "Reboot instance %r"
+msgstr "Re-démarrage de l'instance %r"
+
+#: ../nova/api/ec2/cloud.py:867
+#, python-format
+msgid "De-registering image %s"
+msgstr "Dé-enregitrement de l'image %s"
+
+#: ../nova/api/ec2/cloud.py:875
+#, python-format
+msgid "Registered image %(image_location)s with id %(image_id)s"
+msgstr "Image %(image_location)s enregistré avec l'id %(image_id)s"
+
+#: ../nova/api/ec2/cloud.py:882 ../nova/api/ec2/cloud.py:900
+#, python-format
+msgid "attribute not supported: %s"
+msgstr "attribut non reconnu : %s"
+
+#: ../nova/api/ec2/cloud.py:890
+#, python-format
+msgid "invalid id: %s"
+msgstr "ID invalide : %s"
+
+#: ../nova/api/ec2/cloud.py:903
+msgid "user or group not specified"
+msgstr "Utilisateur ou groupe non spécifié"
+
+#: ../nova/api/ec2/cloud.py:905
+msgid "only group \"all\" is supported"
+msgstr "Seul le group \"tous\" est supporté"
+
+#: ../nova/api/ec2/cloud.py:907
+msgid "operation_type must be add or remove"
+msgstr ""
+"le type d'opération (operation_type) doit être ajout (add) ou suppression "
+"(remove)"
+
+#: ../nova/api/ec2/cloud.py:908
+#, python-format
+msgid "Updating image %s publicity"
+msgstr "Mis à jour de la publication de l'image %s"
+
+#: ../bin/nova-api.py:52
+#, python-format
+msgid "Using paste.deploy config at: %s"
+msgstr "Utilisation de la configuration paste.deploy sur : %s"
+
+#: ../bin/nova-api.py:57
+#, python-format
+msgid "No paste configuration for app: %s"
+msgstr "Pas de configuration collé pour l'application : %s"
+
+#: ../bin/nova-api.py:59
+#, python-format
+msgid ""
+"App Config: %(api)s\n"
+"%(config)r"
+msgstr ""
+"App Config: %(api)s\n"
+"%(config)r"
+
+#: ../bin/nova-api.py:64
+#, python-format
+msgid "Running %s API"
+msgstr "API %s en cours d'éxécution"
+
+#: ../bin/nova-api.py:69
+#, python-format
+msgid "No known API applications configured in %s."
+msgstr "Pas d'API d'applications connue configurée pour %s."
+
+#: ../bin/nova-api.py:83
+#, python-format
+msgid "Starting nova-api node (version %s)"
+msgstr "Démarrage du noeud nova-api (version %s)"
+
+#: ../bin/nova-api.py:89
+#, python-format
+msgid "No paste configuration found for: %s"
+msgstr "Pas de configuration collée trouvée : %s"
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:84
+#, python-format
+msgid "Argument %(key)s value %(value)s is too short."
+msgstr "La valeur %(value)s pour l'argument %(key)s est trop courte."
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:89
+#, python-format
+msgid "Argument %(key)s value %(value)s contains invalid characters."
+msgstr ""
+"La valeur %(value)s pour l'argument %(key)s contient des caractères "
+"interdits."
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:94
+#, python-format
+msgid "Argument %(key)s value %(value)s starts with a hyphen."
+msgstr ""
+"La valeur %(value)s pour l'argument %(key)s débute par un trait d'union."
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:102
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:130
+#, python-format
+msgid "Argument %s is required."
+msgstr "L'argument %s est requis."
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:117
+#, python-format
+msgid ""
+"Argument %(key)s may not take value %(value)s. Valid values are ['true', "
+"'false']."
+msgstr ""
+"La valeur %(value)s pour l'argument %(key)s n'est pas valide. Les valeurs "
+"autorisées sont ['true', 'false']."
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:163
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) on %(sr_ref)s."
+msgstr ""
+"La VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) a été créée sur "
+"%(sr_ref)s."
+
+#: ../nova/virt/xenapi/vmops.py:67
+#, python-format
+msgid "Attempted to create non-unique name %s"
+msgstr "Tentative de création d'un nom non unique %s"
+
+#: ../nova/virt/xenapi/vmops.py:73
+#, python-format
+msgid "instance %(name)s: not enough free memory"
+msgstr "instance %(name)s: pas assez de mémoire"
+
+#: ../nova/virt/xenapi/vmops.py:148
+#, python-format
+msgid "Starting VM %s..."
+msgstr "Démarrage de la VM %s..."
+
+#: ../nova/virt/xenapi/vmops.py:151
+#, python-format
+msgid "Spawning VM %(instance_name)s created %(vm_ref)s."
+msgstr "La VM %(instance_name)s a créé %(vm_ref)s."
+
+#: ../nova/virt/xenapi/vmops.py:162
+#, python-format
+msgid "Invalid value for onset_files: '%s'"
+msgstr "Valeur interdite pour onset_files : '%s'"
+
+#: ../nova/virt/xenapi/vmops.py:167
+#, python-format
+msgid "Injecting file path: '%s'"
+msgstr "Injection du chemin d'accès : '%s'"
+
+#: ../nova/virt/xenapi/vmops.py:180
+#, python-format
+msgid "Instance %s: booted"
+msgstr "Instance %s : démarée"
+
+#: ../nova/virt/xenapi/vmops.py:232
+#, python-format
+msgid "Instance not present %s"
+msgstr "Instance non présente %s"
+
+#. TODO(sirp): Add quiesce and VSS locking support when Windows support
+#. is added
+#: ../nova/virt/xenapi/vmops.py:261
+#, python-format
+msgid "Starting snapshot for VM %s"
+msgstr "Début de création d'instantané (snapshot) pour la VM %s"
+
+#: ../nova/virt/xenapi/vmops.py:269
+#, python-format
+msgid "Unable to Snapshot %(vm_ref)s: %(exc)s"
+msgstr "Impossible de faire un instantané de %(vm_ref)s: %(exc)s"
+
+#: ../nova/virt/xenapi/vmops.py:280
+#, python-format
+msgid "Finished snapshot and upload for VM %s"
+msgstr "Fin de l'instantané et du chargement de VM %s"
+
+#: ../nova/virt/xenapi/vmops.py:356
+#, python-format
+msgid "VM %(vm)s already halted, skipping shutdown..."
+msgstr "La VM %(vm)s est déjà arrété, exctinction évitée."
+
+#: ../nova/virt/xenapi/vmops.py:389
+msgid "Removing kernel/ramdisk files"
+msgstr "Suppression des fichiers noyau/ramdisk"
+
+#: ../nova/virt/xenapi/vmops.py:399
+msgid "kernel/ramdisk files removed"
+msgstr "Fichiers noyau/ramdisk supprimés"
+
+#: ../nova/virt/xenapi/vmops.py:561
+#, python-format
+msgid ""
+"TIMEOUT: The call to %(method)s timed out. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+"DELAI DEPASSE : L'appel de %(method)s à depasser de délai de réponse "
+"maximal. VM id=%(instance_id)s; args=%(strargs)s"
+
+#: ../nova/virt/xenapi/vmops.py:564
+#, python-format
+msgid ""
+"NOT IMPLEMENTED: The call to %(method)s is not supported by the agent. VM "
+"id=%(instance_id)s; args=%(strargs)s"
+msgstr ""
+"NON IMPLEMENTE : l'appel de %(method)s n'est pas pris en compte par l'agent. "
+"VM id=%(instance_id)s; args=%(strargs)s"
+
+#: ../nova/virt/xenapi/vmops.py:569
+#, python-format
+msgid ""
+"The call to %(method)s returned an error: %(e)s. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+"L'appel de %(method)s à renvoyé l'erreur : %(e)s. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+
+#: ../nova/virt/xenapi/vmops.py:760
+#, python-format
+msgid "OpenSSL error: %s"
+msgstr "Erreur OpenSSL : %s"
+
+#: ../nova/tests/test_compute.py:148
+#, python-format
+msgid "Running instances: %s"
+msgstr "Instance actives : %s"
+
+#: ../nova/tests/test_compute.py:154
+#, python-format
+msgid "After terminating instances: %s"
+msgstr "Après l'arrêt d'instances : %s"
+
+#: ../nova/cloudpipe/pipelib.py:45
+msgid "Template for script to run on cloudpipe instance boot"
+msgstr "Patron du script à exécuter au boot d'instance cloudpipe"
+
+#: ../nova/cloudpipe/pipelib.py:48
+msgid "Network to push into openvpn config"
+msgstr "Réseau à passer à la configuration d'openvpn"
+
+#: ../nova/cloudpipe/pipelib.py:51
+msgid "Netmask to push into openvpn config"
+msgstr "Masque réseau à passer à la configuration d'openvpn"
+
+#: ../nova/cloudpipe/pipelib.py:97
+#, python-format
+msgid "Launching VPN for %s"
+msgstr "Démarrage du VPN pour %s"
+
+#: ../nova/db/sqlalchemy/migration.py:35
+msgid "python-migrate is not installed. Exiting."
+msgstr "python-migrate n'est pas installé. Fin d'éxécution."
+
+#: ../nova/image/s3.py:99
+#, python-format
+msgid "Image %s could not be found"
+msgstr "L'image %s n'a pas été trouvée"
+
+#: ../nova/api/ec2/__init__.py:121
+msgid "Too many failed authentications."
+msgstr "Trop d'erreur d'authentification"
+
+#: ../nova/api/ec2/__init__.py:131
+#, python-format
+msgid ""
+"Access key %(access_key)s has had %(failures)d failed authentications and "
+"will be locked out for %(lock_mins)d minutes."
+msgstr ""
+"La clef d'accès %(access_key)s a rencontrée %(failures)d echecs "
+"d'authentification et sera par conséquent vérouillée pour %(lock_mins)d "
+"minutes."
+
+#: ../nova/api/ec2/__init__.py:169 ../nova/objectstore/handler.py:140
+#, python-format
+msgid "Authentication Failure: %s"
+msgstr "Echec d'authentification : %s"
+
+#: ../nova/api/ec2/__init__.py:182
+#, python-format
+msgid "Authenticated Request For %(uname)s:%(pname)s)"
+msgstr "Requête authentifiée pour : %(uname)s:%(pname)s)"
+
+#: ../nova/api/ec2/__init__.py:207
+#, python-format
+msgid "action: %s"
+msgstr "action: %s"
+
+#: ../nova/api/ec2/__init__.py:209
+#, python-format
+msgid "arg: %(key)s\t\tval: %(value)s"
+msgstr "arg: %(key)s\t\tval: %(value)s"
+
+#: ../nova/api/ec2/__init__.py:281
+#, python-format
+msgid ""
+"Unauthorized request for controller=%(controller)s and action=%(action)s"
+msgstr ""
+"Requête non authorisé pour le controlleur=%(controller)s et "
+"l'action=%(action)s"
+
+#: ../nova/api/ec2/__init__.py:314
+#, python-format
+msgid "InstanceNotFound raised: %s"
+msgstr "\"Instance non trouvée\" remontée : %s"
+
+#: ../nova/api/ec2/__init__.py:320
+#, python-format
+msgid "VolumeNotFound raised: %s"
+msgstr "\"Volume non trouvé\" remonté : %s"
+
+#: ../nova/api/ec2/__init__.py:326
+#, python-format
+msgid "NotFound raised: %s"
+msgstr "\"Non trouvé\" remonté : %s"
+
+#: ../nova/api/ec2/__init__.py:329
+#, python-format
+msgid "ApiError raised: %s"
+msgstr "\"Erreur API\" remontée : %s"
+
+#: ../nova/api/ec2/__init__.py:338
+#, python-format
+msgid "Unexpected error raised: %s"
+msgstr "\"Erreur inopinée\" remontée : %s"
+
+#: ../nova/api/ec2/__init__.py:343
+msgid "An unknown error has occurred. Please try your request again."
+msgstr ""
+"Une erreur inopinée à eu lieu. Merci d'essayer votre requête à nouveau."
+
+#: ../nova/auth/dbdriver.py:84
+#, python-format
+msgid "User %s already exists"
+msgstr "L'utilisateur %s existe déjà"
+
+#: ../nova/auth/dbdriver.py:106 ../nova/auth/ldapdriver.py:232
+#, python-format
+msgid "Project can't be created because manager %s doesn't exist"
+msgstr "Le projet ne peut pas être créé car le manager %s n'existe pas"
+
+#: ../nova/auth/dbdriver.py:122 ../nova/auth/ldapdriver.py:243
+#, python-format
+msgid "Project can't be created because user %s doesn't exist"
+msgstr "Le projet ne peut pas être créé car l'utiisateur %s n'existe pas"
+
+#: ../nova/auth/dbdriver.py:135 ../nova/auth/ldapdriver.py:229
+#, python-format
+msgid "Project can't be created because project %s already exists"
+msgstr "Le projet ne peut pas être créé car projet %s existe déjà"
+
+#: ../nova/auth/dbdriver.py:157 ../nova/auth/ldapdriver.py:268
+#, python-format
+msgid "Project can't be modified because manager %s doesn't exist"
+msgstr "Le projet ne peut pas être modifié car le manager %s n'existe pas"
+
+#: ../nova/auth/dbdriver.py:245
+#, python-format
+msgid "User \"%s\" not found"
+msgstr "Utilisateur \"%s\" non trouvé"
+
+#: ../nova/auth/dbdriver.py:248
+#, python-format
+msgid "Project \"%s\" not found"
+msgstr "Projet %s non trouvé"
+
+#: ../nova/virt/xenapi_conn.py:129
+msgid ""
+"Must specify xenapi_connection_url, xenapi_connection_username (optionally), "
+"and xenapi_connection_password to use connection_type=xenapi"
+msgstr ""
+"Doit spécifier xenapi_connection_url, xenapi_connection_username (optionel), "
+"et xenapi_connection_password pour utiliser connection_type=xenapi"
+
+#: ../nova/virt/xenapi_conn.py:311
+#, python-format
+msgid "Task [%(name)s] %(task)s status: success %(result)s"
+msgstr "Tâche [%(name)s] %(task)s état : succès %(result)s"
+
+#: ../nova/virt/xenapi_conn.py:317
+#, python-format
+msgid "Task [%(name)s] %(task)s status: %(status)s %(error_info)s"
+msgstr "Tâche [%(name)s] %(task)s état : %(status)s %(error_info)s"
+
+#: ../nova/virt/xenapi_conn.py:331 ../nova/virt/xenapi_conn.py:344
+#, python-format
+msgid "Got exception: %s"
+msgstr "Reçu exception : %s"
+
+#: ../nova/volume/san.py:67
+#, python-format
+msgid "Could not find iSCSI export for volume %s"
+msgstr "Imposible de trouver une exportation iSCSI pour le volume %s"
+
+#: ../nova/api/ec2/apirequest.py:100
+#, python-format
+msgid ""
+"Unsupported API request: controller = %(controller)s, action = %(action)s"
+msgstr ""
+"Requête API non supportée : controleur = %(controller)s, action = %(action)s"
+
+#: ../nova/api/openstack/__init__.py:55
+#, python-format
+msgid "Caught error: %s"
+msgstr "Erreur interceptée : %s"
+
+#: ../nova/api/openstack/__init__.py:76
+msgid "Including admin operations in API."
+msgstr "Inclusion des opérations d'admin dans l'API."
+
+#: ../nova/console/xvp.py:99
+msgid "Rebuilding xvp conf"
+msgstr "Reconstruction de la configuration xvp"
+
+#: ../nova/console/xvp.py:116
+#, python-format
+msgid "Re-wrote %s"
+msgstr "Ré-écriture de %s"
+
+#: ../nova/console/xvp.py:121
+msgid "Stopping xvp"
+msgstr "Arrêt xvp"
+
+#: ../nova/console/xvp.py:134
+msgid "Starting xvp"
+msgstr "Démarrage xvp"
+
+#: ../nova/console/xvp.py:141
+#, python-format
+msgid "Error starting xvp: %s"
+msgstr "Erreur au démarrage xvp : %s"
+
+#: ../nova/console/xvp.py:144
+msgid "Restarting xvp"
+msgstr "Re-démarrage xvp"
+
+#: ../nova/console/xvp.py:146
+msgid "xvp not running..."
+msgstr "xvp non actif..."
+
+#: ../bin/nova-manage.py:272
+msgid ""
+"The above error may show that the database has not been created.\n"
+"Please create a database using nova-manage sync db before running this "
+"command."
+msgstr ""
+"L'erreur çi dessus peut indiquer que la base de données n'a pas été créée.\n"
+"Veuillez créer une base de données en utilisant nova-manage sync db avant "
+"d'utiliser cette commande."
+
+#: ../bin/nova-manage.py:426
+msgid ""
+"No more networks available. If this is a new installation, you need\n"
+"to call something like this:\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
+msgstr ""
+"Plus de réseaux disponibles. Si vous venez d'installer nova, vous devez "
+"exécuter une commande telle que :\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
+
+#: ../bin/nova-manage.py:431
+msgid ""
+"The above error may show that the certificate db has not been created.\n"
+"Please create a database by running a nova-api server on this host."
+msgstr ""
+"L'erreur çi dessus peut indiquer que la base de données de certificats n'a "
+"pas été créée.\n"
+"Veuillez créer une base de données en exécutant nova-api server sur cet hôte."
+
+#: ../bin/nova-manage.py:447 ../bin/nova-manage.py:536
+msgid "network"
+msgstr "réseau"
+
+#: ../bin/nova-manage.py:448
+msgid "IP address"
+msgstr "adresse IP"
+
+#: ../bin/nova-manage.py:449
+msgid "MAC address"
+msgstr "adresse MAC"
+
+#: ../bin/nova-manage.py:450
+msgid "hostname"
+msgstr "nom du serveur"
+
+#: ../bin/nova-manage.py:451
+msgid "host"
+msgstr "hôte"
+
+#: ../bin/nova-manage.py:537
+msgid "netmask"
+msgstr "masque de réseau"
+
+#: ../bin/nova-manage.py:538
+msgid "start address"
+msgstr "adresse de départ"
+
+#: ../nova/virt/disk.py:69
+#, python-format
+msgid "Failed to load partition: %s"
+msgstr "Impossible de charger la partition: %s"
+
+#: ../nova/virt/disk.py:91
+#, python-format
+msgid "Failed to mount filesystem: %s"
+msgstr "Impossible de monter le système de fichier : %s"
+
+#: ../nova/virt/disk.py:124
+#, python-format
+msgid "nbd device %s did not show up"
+msgstr "Device nbd %s n'est pas apparu"
+
+#: ../nova/virt/disk.py:128
+#, python-format
+msgid "Could not attach image to loopback: %s"
+msgstr "Impossible de lier l'image au loopback : %s"
+
+#: ../nova/virt/disk.py:151
+msgid "No free nbd devices"
+msgstr "Pas de device nbd libre"
+
+#: ../doc/ext/nova_todo.py:46
+#, python-format
+msgid "%(filename)s, line %(line_info)d"
+msgstr "%(filename)s, ligne %(line_info)d"
+
+#. FIXME(chiradeep): implement this
+#: ../nova/virt/hyperv.py:118
+msgid "In init host"
+msgstr "Dans init host"
+
+#: ../nova/virt/hyperv.py:131
+#, python-format
+msgid "Attempt to create duplicate vm %s"
+msgstr "Tentative de création de vm en doublon %s"
+
+#: ../nova/virt/hyperv.py:148
+#, python-format
+msgid "Starting VM %s "
+msgstr "Démarrage VM %s "
+
+#: ../nova/virt/hyperv.py:150
+#, python-format
+msgid "Started VM %s "
+msgstr "VM %s démarrée "
+
+#: ../nova/virt/hyperv.py:152
+#, python-format
+msgid "spawn vm failed: %s"
+msgstr "Erreur à l'activation VM : %s"
+
+#: ../nova/virt/hyperv.py:169
+#, python-format
+msgid "Failed to create VM %s"
+msgstr "Erreur de création VM %s"
+
+#: ../nova/virt/hyperv.py:188
+#, python-format
+msgid "Set memory for vm %s..."
+msgstr "Réglage de la mémoire sur VM %s..."
+
+#: ../nova/virt/hyperv.py:198
+#, python-format
+msgid "Set vcpus for vm %s..."
+msgstr "Réglage vcpus sur vm %s..."
+
+#: ../nova/virt/hyperv.py:202
+#, python-format
+msgid "Creating disk for %(vm_name)s by attaching disk file %(vhdfile)s"
+msgstr ""
+"Création du disque pour %(vm_name)s par liaison avec le fichier disque "
+"%(vhdfile)s"
+
+#: ../nova/virt/hyperv.py:227
+#, python-format
+msgid "Failed to add diskdrive to VM %s"
+msgstr "Impossible d'ajouter le disque à la VM %s"
+
+#: ../nova/virt/hyperv.py:230
+#, python-format
+msgid "New disk drive path is %s"
+msgstr "Nouveau chemin d'accès pour le disque : %s"
+
+#: ../nova/virt/hyperv.py:247
+#, python-format
+msgid "Failed to add vhd file to VM %s"
+msgstr "Impossible d'ajouter le fichier vhd à la VM %s"
+
+#: ../nova/virt/hyperv.py:249
+#, python-format
+msgid "Created disk for %s"
+msgstr "Disque créé pour %s"
+
+#: ../nova/virt/hyperv.py:253
+#, python-format
+msgid "Creating nic for %s "
+msgstr "Création de l'interface réseau pour %s "
+
+#: ../nova/virt/hyperv.py:272
+msgid "Failed creating a port on the external vswitch"
+msgstr "Erreur de création de port sur le vswitch externe"
+
+#: ../nova/virt/hyperv.py:273
+#, python-format
+msgid "Failed creating port for %s"
+msgstr "Erreur de création de port pour %s"
+
+#: ../nova/virt/hyperv.py:276
+#, python-format
+msgid "Created switch port %(vm_name)s on switch %(ext_path)s"
+msgstr "Le port switch %(vm_name)s a été créé sur le switch %(ext_path)s"
+
+#: ../nova/virt/hyperv.py:286
+#, python-format
+msgid "Failed to add nic to VM %s"
+msgstr "Impossible d'ajouter une interface réseau à la VM %s"
+
+#: ../nova/virt/hyperv.py:288
+#, python-format
+msgid "Created nic for %s "
+msgstr "Interface réseau créée pour %s "
+
+#: ../nova/virt/hyperv.py:321
+#, python-format
+msgid "WMI job failed: %s"
+msgstr "Tâche WMI echouée : %s"
+
+#: ../nova/virt/hyperv.py:325
+#, python-format
+msgid "WMI job succeeded: %(desc)s, Elapsed=%(elap)s "
+msgstr "Tâche WMI réussie : %(desc)s, Elapsed=%(elap)s "
+
+#: ../nova/virt/hyperv.py:361
+#, python-format
+msgid "Got request to destroy vm %s"
+msgstr "Requête de suppression de la VM %s reçue"
+
+#: ../nova/virt/hyperv.py:386
+#, python-format
+msgid "Failed to destroy vm %s"
+msgstr "Impossible de supprimer la VM %s"
+
+#: ../nova/virt/hyperv.py:393
+#, python-format
+msgid "Del: disk %(vhdfile)s vm %(instance_name)s"
+msgstr "Suppression: disque %(vhdfile)s vm %(instance_name)s"
+
+#: ../nova/virt/hyperv.py:415
+#, python-format
+msgid ""
+"Got Info for vm %(instance_id)s: state=%(state)s, mem=%(memusage)s, "
+"num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
+msgstr ""
+"Informations reçues pour la VM %(instance_id)s: état=%(state)s, "
+"mem=%(memusage)s, num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
+
+#: ../nova/virt/hyperv.py:451
+#, python-format
+msgid "Successfully changed vm state of %(vm_name)s to %(req_state)s"
+msgstr "Changement d'état de la VM %(vm_name)s en %(req_state)s réussi"
+
+#: ../nova/virt/hyperv.py:454
+#, python-format
+msgid "Failed to change vm state of %(vm_name)s to %(req_state)s"
+msgstr "Impossible de changer l'état de la vm %(vm_name)s en %(req_state)s"
+
+#: ../nova/compute/api.py:71
+#, python-format
+msgid "Instance %d was not found in get_network_topic"
+msgstr "Instance %d non trouvée dans get_network_topic"
+
+#: ../nova/compute/api.py:77
+#, python-format
+msgid "Instance %d has no host"
+msgstr "Instance %d n'a pas d'hôte"
+
+#: ../nova/compute/api.py:97
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to run %(min_count)s instances"
+msgstr ""
+"Quota dépassé pour %(pid)s, lors de la tentative d'exécution de "
+"%(min_count)s instances"
+
+#: ../nova/compute/api.py:99
+#, python-format
+msgid ""
+"Instance quota exceeded. You can only run %s more instances of this type."
+msgstr ""
+"Quota d'instances dépassé. Vous ne pouvez éxécuter que %s instances de ce "
+"type de plus."
+
+#: ../nova/compute/api.py:112
+msgid "Creating a raw instance"
+msgstr "Création d'une instance raw"
+
+#: ../nova/compute/api.py:160
+#, python-format
+msgid "Going to run %s instances..."
+msgstr "Démarrage de %s instances..."
+
+#: ../nova/compute/api.py:187
+#, python-format
+msgid "Casting to scheduler for %(pid)s/%(uid)s's instance %(instance_id)s"
+msgstr "Envoi au scheduler de %(pid)s/%(uid)s's instance %(instance_id)s"
+
+#: ../nova/compute/api.py:292
+#, python-format
+msgid "Going to try to terminate %s"
+msgstr "Va essayer d'arrêter %s"
+
+#: ../nova/compute/api.py:296
+#, python-format
+msgid "Instance %d was not found during terminate"
+msgstr "L'instance %d n'a pas été trouvée durant l'arrêt"
+
+#: ../nova/compute/api.py:301
+#, python-format
+msgid "Instance %d is already being terminated"
+msgstr "L'instance %d est déjà en cours d'arrêt"
+
+#: ../nova/compute/api.py:481
+#, python-format
+msgid "Invalid device specified: %s. Example device: /dev/vdb"
+msgstr "Device spécifié invalide : %s. Exemple de device: /dev/vdb"
+
+#: ../nova/compute/api.py:496
+msgid "Volume isn't attached to anything!"
+msgstr "Le volume n'est pas attaché à quoi que ce soit!"
+
+#: ../nova/rpc.py:98
+#, python-format
+msgid ""
+"AMQP server on %(fl_host)s:%(fl_port)d is unreachable. Trying again in "
+"%(fl_intv)d seconds."
+msgstr ""
+"Le serveur AMQP sur %(fl_host)s:%(fl_port)d n'est pas joignable. Nouvel "
+"essai dans %(fl_intv)d secondes."
+
+#: ../nova/rpc.py:103
+#, python-format
+msgid "Unable to connect to AMQP server after %d tries. Shutting down."
+msgstr ""
+"Impossible de se connecter au serveur AMQP après %d essais. Extinction."
+
+#: ../nova/rpc.py:122
+msgid "Reconnected to queue"
+msgstr "Reconnection à la queue"
+
+#: ../nova/rpc.py:129
+msgid "Failed to fetch message from queue"
+msgstr "Impossible de récuperrer les message de la queue"
+
+#: ../nova/rpc.py:159
+#, python-format
+msgid "Initing the Adapter Consumer for %s"
+msgstr "Initialisation du Consomateur d'Adapteur pour %s"
+
+#: ../nova/rpc.py:178
+#, python-format
+msgid "received %s"
+msgstr "%s reçu"
+
+#. NOTE(vish): we may not want to ack here, but that means that bad
+#. messages stay in the queue indefinitely, so for now
+#. we just log the message and send an error string
+#. back to the caller
+#: ../nova/rpc.py:191
+#, python-format
+msgid "no method for message: %s"
+msgstr "Pas de méthode pour le message : %s"
+
+#: ../nova/rpc.py:192
+#, python-format
+msgid "No method for message: %s"
+msgstr "Pas de méthode pour le message : %s"
+
+#: ../nova/rpc.py:253
+#, python-format
+msgid "Returning exception %s to caller"
+msgstr "Renvoi de l'exception %s à l'appelant"
+
+#: ../nova/rpc.py:294
+#, python-format
+msgid "unpacked context: %s"
+msgstr "Contexte décompacté : %s"
+
+#: ../nova/rpc.py:313
+msgid "Making asynchronous call..."
+msgstr "En cours d'appel assynchrone..."
+
+#: ../nova/rpc.py:316
+#, python-format
+msgid "MSG_ID is %s"
+msgstr "MSG_ID est %s"
+
+#: ../nova/rpc.py:354
+msgid "Making asynchronous cast..."
+msgstr "En cours de diffusion assynchrone"
+
+#: ../nova/rpc.py:364
+#, python-format
+msgid "response %s"
+msgstr "réponse %s"
+
+#: ../nova/rpc.py:373
+#, python-format
+msgid "topic is %s"
+msgstr "le sujet est %s"
+
+#: ../nova/rpc.py:374
+#, python-format
+msgid "message %s"
+msgstr "message %s"
+
+#: ../nova/volume/driver.py:78
+#, python-format
+msgid "Recovering from a failed execute. Try number %s"
+msgstr "Récupération après une exécution erronée. Tentative numéro %s"
+
+#: ../nova/volume/driver.py:87
+#, python-format
+msgid "volume group %s doesn't exist"
+msgstr "Le groupe de volume %s n'existe pas"
+
+#: ../nova/volume/driver.py:220
+#, python-format
+msgid "FAKE AOE: %s"
+msgstr "FAUX AOE: %s"
+
+#: ../nova/volume/driver.py:233
+msgid "Skipping ensure_export. No iscsi_target "
+msgstr "ensure_export sauté. Pas d'iscsi_target "
+
+#: ../nova/volume/driver.py:279 ../nova/volume/driver.py:288
+msgid "Skipping remove_export. No iscsi_target "
+msgstr "remove_export sauté. Pas d'iscsi_target "
+
+#: ../nova/volume/driver.py:347
+#, python-format
+msgid "FAKE ISCSI: %s"
+msgstr "FAUX ISCSI: %s"
+
+#: ../nova/volume/driver.py:359
+#, python-format
+msgid "rbd has no pool %s"
+msgstr "rbd n'as pas de file %s"
+
+#: ../nova/volume/driver.py:414
+#, python-format
+msgid "Sheepdog is not working: %s"
+msgstr "Sheepdog n'est pas actif : %s"
+
+#: ../nova/volume/driver.py:416
+msgid "Sheepdog is not working"
+msgstr "Sheepdog n'est pas actif"
+
+#: ../nova/wsgi.py:68
+#, python-format
+msgid "Starting %(arg0)s on %(host)s:%(port)s"
+msgstr "Démarrage %(arg0)s sur %(host)s:%(port)s"
+
+#: ../nova/wsgi.py:147
+msgid "You must implement __call__"
+msgstr "Vous devez implémenter __call__"
+
+#: ../bin/nova-dhcpbridge.py:58
+msgid "leasing ip"
+msgstr "Allocation IP"
+
+#: ../bin/nova-dhcpbridge.py:73
+msgid "Adopted old lease or got a change of mac/hostname"
+msgstr "Allocation périmée accepté ou changement de nom/adresse MAC d'hôte"
+
+#: ../bin/nova-dhcpbridge.py:80
+msgid "releasing ip"
+msgstr "Libération IP"
+
+#: ../bin/nova-dhcpbridge.py:123
+#, python-format
+msgid ""
+"Called %(action)s for mac %(mac)s with ip %(ip)s and hostname %(hostname)s "
+"on interface %(interface)s"
+msgstr ""
+"%(action)s appelée pour MAC %(mac)s avec IP %(ip)s nom d'hôte %(hostname)s "
+"sur l'interface %(interface)s"
+
+#: ../nova/virt/fake.py:239
+#, python-format
+msgid "Instance %s Not Found"
+msgstr "Instance %s Non trouvée"
+
+#: ../nova/network/manager.py:153
+#, python-format
+msgid "Dissassociated %s stale fixed ip(s)"
+msgstr "Désassociation de %s ip(s) fixes périmées"
+
+#: ../nova/network/manager.py:157
+msgid "setting network host"
+msgstr "réglage de l'hôte réseau"
+
+#: ../nova/network/manager.py:212
+#, python-format
+msgid "Leasing IP %s"
+msgstr "Allocation IP %s"
+
+#: ../nova/network/manager.py:216
+#, python-format
+msgid "IP %s leased that isn't associated"
+msgstr "IP %s allouée qui n'est pas associée"
+
+#: ../nova/network/manager.py:220
+#, python-format
+msgid "IP %(address)s leased to bad mac %(inst_addr)s vs %(mac)s"
+msgstr "IP %(address)s allouée à une mauvaise MAC %(inst_addr)s pour %(mac)s"
+
+#: ../nova/network/manager.py:228
+#, python-format
+msgid "IP %s leased that was already deallocated"
+msgstr "IP %s alloué qui était déjà désallouée"
+
+#: ../nova/network/manager.py:233
+#, python-format
+msgid "Releasing IP %s"
+msgstr "Libération IP %s"
+
+#: ../nova/network/manager.py:237
+#, python-format
+msgid "IP %s released that isn't associated"
+msgstr "IP %s libérée qui n'était pas associée"
+
+#: ../nova/network/manager.py:241
+#, python-format
+msgid "IP %(address)s released from bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+"IP %(address)s libérée par une mauvaise MAC %(inst_addr)s pour %(mac)s"
+
+#: ../nova/network/manager.py:244
+#, python-format
+msgid "IP %s released that was not leased"
+msgstr "IP %s libérée qui n'était pas allouée"
+
+#: ../nova/network/manager.py:519
+msgid ""
+"The sum between the number of networks and the vlan start cannot be greater "
+"than 4094"
+msgstr ""
+"La somme du nombre de réseau et le début de vlan ne peut excéder 4094"
+
+#: ../nova/virt/xenapi/volume_utils.py:57
+#, python-format
+msgid "Introducing %s..."
+msgstr "Introduction de %s"
+
+#: ../nova/virt/xenapi/volume_utils.py:74
+#, python-format
+msgid "Introduced %(label)s as %(sr_ref)s."
+msgstr "%(label)s introduit comme %(sr_ref)s."
+
+#: ../nova/virt/xenapi/volume_utils.py:78
+msgid "Unable to create Storage Repository"
+msgstr "Impossible de créer le dépot de stockage"
+
+#: ../nova/virt/xenapi/volume_utils.py:90
+#, python-format
+msgid "Unable to find SR from VBD %s"
+msgstr "Impossible de trouver SR du VDB %s"
+
+#: ../nova/virt/xenapi/volume_utils.py:96
+#, python-format
+msgid "Forgetting SR %s ... "
+msgstr "Démémorisation du SR %s "
+
+#: ../nova/virt/xenapi/volume_utils.py:101
+#, python-format
+msgid "Ignoring exception %(exc)s when getting PBDs for %(sr_ref)s"
+msgstr ""
+"Exception %(exc)s ignorée pendant l'obtention de PBDs pour %(sr_ref)s"
+
+#: ../nova/virt/xenapi/volume_utils.py:107
+#, python-format
+msgid "Ignoring exception %(exc)s when unplugging PBD %(pbd)s"
+msgstr "Exception %(exc)s ignorée pendant la deconnexion du PBD %(pbd)s"
+
+#: ../nova/virt/xenapi/volume_utils.py:111
+#, python-format
+msgid "Forgetting SR %s done."
+msgstr "Démémorisation du SR %s terminée"
+
+#: ../nova/virt/xenapi/volume_utils.py:113
+#, python-format
+msgid "Ignoring exception %(exc)s when forgetting SR %(sr_ref)s"
+msgstr "Exception %(exc)s ignorée pendant la démémorisation du SR %(sr_ref)s"
+
+#: ../nova/virt/xenapi/volume_utils.py:123
+#, python-format
+msgid "Unable to introduce VDI on SR %s"
+msgstr "Impossible d'introduire VDI sur SR %s"
+
+#: ../nova/virt/xenapi/volume_utils.py:128
+#, python-format
+msgid "Unable to get record of VDI %s on"
+msgstr "Impossible de récuppérer l'enregistrement du VDI %s sur"
+
+#: ../nova/virt/xenapi/volume_utils.py:146
+#, python-format
+msgid "Unable to introduce VDI for SR %s"
+msgstr "Impossible d'introduire le VDI pour SR %s"
+
+#: ../nova/virt/xenapi/volume_utils.py:175
+#, python-format
+msgid "Unable to obtain target information %(device_path)s, %(mountpoint)s"
+msgstr ""
+"Impossible de récuppérer les informations de destination %(device_path)s, "
+"%(mountpoint)s"
+
+#: ../nova/virt/xenapi/volume_utils.py:197
+#, python-format
+msgid "Mountpoint cannot be translated: %s"
+msgstr "Le point de montage ne peut pas être traduit : %s"
+
+#: ../nova/objectstore/image.py:262
+#, python-format
+msgid "Failed to decrypt private key: %s"
+msgstr "Impossible de déchiffrer la clef privée : %s"
+
+#: ../nova/objectstore/image.py:269
+#, python-format
+msgid "Failed to decrypt initialization vector: %s"
+msgstr "Impossible de déchiffrer le vecteur d'initialisation : %s"
+
+#: ../nova/objectstore/image.py:277
+#, python-format
+msgid "Failed to decrypt image file %(image_file)s: %(err)s"
+msgstr "Impossible de déchiffrer le fichier image %(image_file)s: %(err)s"
+
+#: ../nova/objectstore/handler.py:106
+#, python-format
+msgid "Unknown S3 value type %r"
+msgstr "Type de valeur S3 inconnu %r"
+
+#: ../nova/objectstore/handler.py:137
+msgid "Authenticated request"
+msgstr "Requête authentifiée"
+
+#: ../nova/objectstore/handler.py:182
+msgid "List of buckets requested"
+msgstr "Listes de conteneurs (buckets) demandée"
+
+#: ../nova/objectstore/handler.py:209
+#, python-format
+msgid "List keys for bucket %s"
+msgstr "List des clefs pour le conteneur (bucket) %s"
+
+#: ../nova/objectstore/handler.py:217
+#, python-format
+msgid "Unauthorized attempt to access bucket %s"
+msgstr "Demande d'accès au conteneur %s non autorisé"
+
+#: ../nova/objectstore/handler.py:235
+#, python-format
+msgid "Creating bucket %s"
+msgstr "Création du conteneur %s"
+
+#: ../nova/objectstore/handler.py:245
+#, python-format
+msgid "Deleting bucket %s"
+msgstr "Suppression du conteneur %s"
+
+#: ../nova/objectstore/handler.py:249
+#, python-format
+msgid "Unauthorized attempt to delete bucket %s"
+msgstr "Tentative de suppression du conteneur %s non autorisée"
+
+#: ../nova/objectstore/handler.py:273
+#, python-format
+msgid "Getting object: %(bname)s / %(nm)s"
+msgstr "Récupération de l'objet : %(bname)s / %(nm)s"
+
+#: ../nova/objectstore/handler.py:276
+#, python-format
+msgid "Unauthorized attempt to get object %(nm)s from bucket %(bname)s"
+msgstr ""
+"Tentative d'accès à l'objet %(nm)s non autorisée pour le conteneur %(bname)s"
+
+#: ../nova/objectstore/handler.py:296
+#, python-format
+msgid "Putting object: %(bname)s / %(nm)s"
+msgstr "Injection d'objet : %(bname)s / %(nm)s"
+
+#: ../nova/objectstore/handler.py:299
+#, python-format
+msgid "Unauthorized attempt to upload object %(nm)s to bucket %(bname)s"
+msgstr ""
+"Tentative de chargement de l'objet %(nm)s vers le conteneur %(bname)s non "
+"autorisée"
+
+#: ../nova/objectstore/handler.py:318
+#, python-format
+msgid "Deleting object: %(bname)s / %(nm)s"
+msgstr "Suppression de l'objet : %(bname)s / %(nm)s"
+
+#: ../nova/objectstore/handler.py:322
+#, python-format
+msgid "Unauthorized attempt to delete object %(nm)s from bucket %(bname)s"
+msgstr ""
+"Tentative de suppression de l'objet %(nm)s non autorisé pour le conteneur "
+"%(bname)s"
+
+#: ../nova/objectstore/handler.py:396
+#, python-format
+msgid "Not authorized to upload image: invalid directory %s"
+msgstr "Chargement d'image non autorisé : répertoire invalide %s"
+
+#: ../nova/objectstore/handler.py:404
+#, python-format
+msgid "Not authorized to upload image: unauthorized bucket %s"
+msgstr "Chargement d'image non autorisé : conteneur non autorisé %s"
+
+#: ../nova/objectstore/handler.py:409
+#, python-format
+msgid "Starting image upload: %s"
+msgstr "Début de chargement d'image: %s"
+
+#: ../nova/objectstore/handler.py:423
+#, python-format
+msgid "Not authorized to update attributes of image %s"
+msgstr "Tentative de mise a jour d'attributs non autorisée pour l'image %s"
+
+#: ../nova/objectstore/handler.py:431
+#, python-format
+msgid "Toggling publicity flag of image %(image_id)s %(newstatus)r"
+msgstr ""
+"Basculement de l'attribut public de l'image %(image_id)s %(newstatus)r"
+
+#. other attributes imply update
+#: ../nova/objectstore/handler.py:436
+#, python-format
+msgid "Updating user fields on image %s"
+msgstr "Mise à jour des champs utilisateurs sur l'image %s"
+
+#: ../nova/objectstore/handler.py:450
+#, python-format
+msgid "Unauthorized attempt to delete image %s"
+msgstr "Tentative de suppression de l'image %s non autorisée"
+
+#: ../nova/objectstore/handler.py:455
+#, python-format
+msgid "Deleted image: %s"
+msgstr "Image supprimée : %s"
+
+#: ../nova/auth/manager.py:259
+#, python-format
+msgid "Looking up user: %r"
+msgstr "Recherche de l'utilisateur : %r"
+
+#: ../nova/auth/manager.py:263
+#, python-format
+msgid "Failed authorization for access key %s"
+msgstr "Autorisation refusée pour la clef d'accès %s"
+
+#: ../nova/auth/manager.py:264
+#, python-format
+msgid "No user found for access key %s"
+msgstr "Pas d'utilisateur trouvé pour la clef d'accès %s"
+
+#: ../nova/auth/manager.py:270
+#, python-format
+msgid "Using project name = user name (%s)"
+msgstr "Nom de projet utilisé = nom d'utilisateur (%s)"
+
+#: ../nova/auth/manager.py:277
+#, python-format
+msgid "failed authorization: no project named %(pjid)s (user=%(uname)s)"
+msgstr ""
+"Autorisation refusée : pas de projet nommé %(pjid)s (utilisateur=%(uname)s)"
+
+#: ../nova/auth/manager.py:279
+#, python-format
+msgid "No project called %s could be found"
+msgstr "Aucun projet nommé %s trouvé"
+
+#: ../nova/auth/manager.py:287
+#, python-format
+msgid ""
+"Failed authorization: user %(uname)s not admin and not member of project "
+"%(pjname)s"
+msgstr ""
+"Autorisation refusée : utilisateur %(uname)s n'est ni admin ni membre du "
+"projet %(pjname)s"
+
+#: ../nova/auth/manager.py:289
+#, python-format
+msgid "User %(uid)s is not a member of project %(pjid)s"
+msgstr "L'utilisateur %(uid)s n'est pas membre du projet %(pjid)s"
+
+#: ../nova/auth/manager.py:298 ../nova/auth/manager.py:309
+#, python-format
+msgid "Invalid signature for user %s"
+msgstr "Signature non valide pour l'utilisateur %s"
+
+#: ../nova/auth/manager.py:299 ../nova/auth/manager.py:310
+msgid "Signature does not match"
+msgstr "La signature ne correspond pas"
+
+#: ../nova/auth/manager.py:380
+msgid "Must specify project"
+msgstr "Le projet doit être spécifié"
+
+#: ../nova/auth/manager.py:414
+#, python-format
+msgid "The %s role can not be found"
+msgstr "Le rôle %s n'a pas été trouvé"
+
+#: ../nova/auth/manager.py:416
+#, python-format
+msgid "The %s role is global only"
+msgstr "Le rôle %s est obligatoirement global"
+
+#: ../nova/auth/manager.py:420
+#, python-format
+msgid "Adding role %(role)s to user %(uid)s in project %(pid)s"
+msgstr ""
+"Ajout du rôle %(role)s à l'utilisateur %(uid)s pour le projet %(pid)s"
+
+#: ../nova/auth/manager.py:423
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(uid)s"
+msgstr "Ajout du rôle global %(role)s pour l'utilisateur %(uid)s"
+
+#: ../nova/auth/manager.py:448
+#, python-format
+msgid "Removing role %(role)s from user %(uid)s on project %(pid)s"
+msgstr ""
+"Suppression du rôle %(role)s pour l'utilisateur %(uid)s dans le projet "
+"%(pid)s"
+
+#: ../nova/auth/manager.py:451
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(uid)s"
+msgstr "Suppression du role global %(role)s pour l'utilisateur %(uid)s"
+
+#: ../nova/auth/manager.py:515
+#, python-format
+msgid "Created project %(name)s with manager %(manager_user)s"
+msgstr "Création du projet %(name)s ayant pour manager %(manager_user)s"
+
+#: ../nova/auth/manager.py:533
+#, python-format
+msgid "modifying project %s"
+msgstr "modification du projet %s"
+
+#: ../nova/auth/manager.py:545
+#, python-format
+msgid "Adding user %(uid)s to project %(pid)s"
+msgstr "Ajout de l'utilisateur %(uid)s au projet %(pid)s"
+
+#: ../nova/auth/manager.py:566
+#, python-format
+msgid "Remove user %(uid)s from project %(pid)s"
+msgstr "Suppression de l'utilisateur %(uid)s du projet %(pid)s"
+
+#: ../nova/auth/manager.py:592
+#, python-format
+msgid "Deleting project %s"
+msgstr "Suppression du projet %s"
+
+#: ../nova/auth/manager.py:650
+#, python-format
+msgid "Created user %(rvname)s (admin: %(rvadmin)r)"
+msgstr "Utilisateur créé %(rvname)s (admin: %(rvadmin)r)"
+
+#: ../nova/auth/manager.py:659
+#, python-format
+msgid "Deleting user %s"
+msgstr "Suppression de l'utilisateur %s"
+
+#: ../nova/auth/manager.py:669
+#, python-format
+msgid "Access Key change for user %s"
+msgstr "Clef d'accès changée pour l'utilisateur %s"
+
+#: ../nova/auth/manager.py:671
+#, python-format
+msgid "Secret Key change for user %s"
+msgstr "Clef secrète changée pour l'utilisateur %s"
+
+#: ../nova/auth/manager.py:673
+#, python-format
+msgid "Admin status set to %(admin)r for user %(uid)s"
+msgstr "Statut admin changé en %(admin)r pour l'utilisateur %(uid)s"
+
+#: ../nova/auth/manager.py:722
+#, python-format
+msgid "No vpn data for project %s"
+msgstr "Pas de données VPN pour le projet %s"
+
+#: ../nova/service.py:161
+#, python-format
+msgid "Starting %(topic)s node (version %(vcs_string)s)"
+msgstr "Démarrage du noeud %(topic)s (version %(vcs_string)s)"
+
+#: ../nova/service.py:174
+msgid "Service killed that has no database entry"
+msgstr "Service détruit sans entrée dans la base de données"
+
+#: ../nova/service.py:195
+msgid "The service database object disappeared, Recreating it."
+msgstr ""
+"L'objet du service de base de données à disparru, re-création en cours."
+
+#: ../nova/service.py:207
+msgid "Recovered model server connection!"
+msgstr "Récupération du modelle de connexion serveur terminée!"
+
+#: ../nova/service.py:213
+msgid "model server went away"
+msgstr "Le modèle de serveur à disparu"
+
+#: ../nova/auth/ldapdriver.py:174
+#, python-format
+msgid "LDAP user %s already exists"
+msgstr "L'utilisateur LDAP %s existe déjà"
+
+#: ../nova/auth/ldapdriver.py:205
+#, python-format
+msgid "LDAP object for %s doesn't exist"
+msgstr "L'objet LDAP pour %s n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:348
+#, python-format
+msgid "User %s doesn't exist"
+msgstr "L'utilisateur %s n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:472
+#, python-format
+msgid "Group can't be created because group %s already exists"
+msgstr "Un groupe nommé %s existe déjà"
+
+#: ../nova/auth/ldapdriver.py:478
+#, python-format
+msgid "Group can't be created because user %s doesn't exist"
+msgstr "Le groupe n'a pu être créé car l'utilisateur %s n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:495
+#, python-format
+msgid "User %s can't be searched in group because the user doesn't exist"
+msgstr ""
+"L'utilisateur %s ne peut pas être trouvé dans le groupe car cet utilisateur "
+"n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:507
+#, python-format
+msgid "User %s can't be added to the group because the user doesn't exist"
+msgstr ""
+"L'utilisateur %s ne peut être ajouté au groupe car cet utilisateur n'existe "
+"pas"
+
+#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
+#, python-format
+msgid "The group at dn %s doesn't exist"
+msgstr "Le group ayant pour dn %s n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:513
+#, python-format
+msgid "User %(uid)s is already a member of the group %(group_dn)s"
+msgstr "L'utilisateur %(uid)s est déjà membre du groupe %(group_dn)s"
+
+#: ../nova/auth/ldapdriver.py:524
+#, python-format
+msgid ""
+"User %s can't be removed from the group because the user doesn't exist"
+msgstr ""
+"L'utilisateur %s ne peut être supprimé du groupe car cet utilisateur "
+"n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:528
+#, python-format
+msgid "User %s is not a member of the group"
+msgstr "L'utilisateur %s n'est pas membre du groupe"
+
+#: ../nova/auth/ldapdriver.py:542
+#, python-format
+msgid ""
+"Attempted to remove the last member of a group. Deleting the group at %s "
+"instead."
+msgstr ""
+"Tentative de suppression du dernier membre d'un groupe. Essayez plutôt de "
+"supprimer le group sur %s."
+
+#: ../nova/auth/ldapdriver.py:549
+#, python-format
+msgid "User %s can't be removed from all because the user doesn't exist"
+msgstr ""
+"L'utilisateur %s ne peut être supprimé partout car l'utilisateur n'existe pas"
+
+#: ../nova/auth/ldapdriver.py:564
+#, python-format
+msgid "Group at dn %s doesn't exist"
+msgstr "Le groupe ayant pour dn %s n'existe pas"
+
+#: ../nova/virt/xenapi/network_utils.py:40
+#, python-format
+msgid "Found non-unique network for bridge %s"
+msgstr "Réseau non unique trouvé pour le bridge %s"
+
+#: ../nova/virt/xenapi/network_utils.py:43
+#, python-format
+msgid "Found no network for bridge %s"
+msgstr "Aucun réseau trouvé pour le bridge %s"
+
+#: ../nova/api/ec2/admin.py:97
+#, python-format
+msgid "Creating new user: %s"
+msgstr "Création d'un nouvel utilisateur : %s"
+
+#: ../nova/api/ec2/admin.py:105
+#, python-format
+msgid "Deleting user: %s"
+msgstr "Suppression de l'utilisateur : %s"
+
+#: ../nova/api/ec2/admin.py:127
+#, python-format
+msgid "Adding role %(role)s to user %(user)s for project %(project)s"
+msgstr ""
+"Ajout du rôle %(role)s à l'utilisateur %(user)s pour le projet %(project)s"
+
+#: ../nova/api/ec2/admin.py:131
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(user)s"
+msgstr "Ajout du rôle global %(role)s à l'utilisateur %(user)s"
+
+#: ../nova/api/ec2/admin.py:137
+#, python-format
+msgid "Removing role %(role)s from user %(user)s for project %(project)s"
+msgstr ""
+"Suppresion du rôle %(role)s de l'utilisateur %(user)s pour le projet "
+"%(project)s"
+
+#: ../nova/api/ec2/admin.py:141
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(user)s"
+msgstr "Suppression du rôle global %(role)s pour l'utilisateur %(user)s"
+
+#: ../nova/api/ec2/admin.py:146 ../nova/api/ec2/admin.py:223
+msgid "operation must be add or remove"
+msgstr "L'opération doit être ajout ou suppression"
+
+#: ../nova/api/ec2/admin.py:159
+#, python-format
+msgid "Getting x509 for user: %(name)s on project: %(project)s"
+msgstr ""
+"Récupération de x509 pour l'utilisateur : %(name)s sur le projet : "
+"%(project)s"
+
+#: ../nova/api/ec2/admin.py:177
+#, python-format
+msgid "Create project %(name)s managed by %(manager_user)s"
+msgstr "Création du projet %(name)s géré par %(manager_user)s"
+
+#: ../nova/api/ec2/admin.py:190
+#, python-format
+msgid "Modify project: %(name)s managed by %(manager_user)s"
+msgstr "Modification du projet: %(name)s géré par %(manager_user)s"
+
+#: ../nova/api/ec2/admin.py:200
+#, python-format
+msgid "Delete project: %s"
+msgstr "Supprimer le projet : %s"
+
+#: ../nova/api/ec2/admin.py:214
+#, python-format
+msgid "Adding user %(user)s to project %(project)s"
+msgstr "Ajout de l'utilisateur %(user)s au projet %(project)s"
+
+#: ../nova/api/ec2/admin.py:218
+#, python-format
+msgid "Removing user %(user)s from project %(project)s"
+msgstr "Suppression de l'utilisateur %(user)s du projet %(project)s"
diff --git a/po/it.po b/po/it.po
index 1beb116a3..6bfcf1274 100644
--- a/po/it.po
+++ b/po/it.po
@@ -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
@@ -134,34 +134,6 @@ msgstr "compute.api::suspend %s"
msgid "compute.api::resume %s"
msgstr "compute.api::resume %s"
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr "Numero errato di argomenti"
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-"Il pidfile %s non esiste. Assicurarsi che il demone é in esecuzione.\n"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr "Nessun processo trovato"
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr "Servire %s"
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr "Insieme di FLAGS:"
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "Avvio di %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
#: ../nova/api/ec2/__init__.py:317
@@ -1791,34 +1763,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2278,10 +2222,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/ja.po b/po/ja.po
index 87065d778..a7906ede8 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -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-29 07:27+0000\n"
-"Last-Translator: Koji Iida <Unknown>\n"
+"PO-Revision-Date: 2011-05-10 10:26+0000\n"
+"Last-Translator: Akira YOSHIYAMA <Unknown>\n"
"Language-Team: \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-30 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
#: ../nova/scheduler/simple.py:122
msgid "No hosts found"
-msgstr "é©åˆ‡ãªãƒ›ã‚¹ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
+msgstr "ホストãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
#: ../nova/exception.py:33
msgid "Unexpected error while running command."
@@ -36,10 +36,15 @@ 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"
-msgstr ""
+msgstr "DB 例外ãŒãƒ©ãƒƒãƒ—(wrapped)ã•れã¾ã—ãŸ"
#. exc_type, exc_value, exc_traceback = sys.exc_info()
#: ../nova/exception.py:120
@@ -49,32 +54,32 @@ msgstr "キャッãƒã•れãªã‹ã£ãŸä¾‹å¤–"
#: ../nova/volume/api.py:45
#, python-format
msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
-msgstr "サイズ %(size)sG ã®ãƒœãƒªãƒ¥ãƒ¼ãƒ ã®ä½œæˆã‚’行ãŠã†ã¨ã—ã¾ã—ãŸãŒã€%(pid)sã®ã‚¯ã‚ªãƒ¼ã‚¿ã‚’è¶…ãˆã¦ã„ã¾ã™ã€‚"
+msgstr "サイズ %(size)s GB ã®ãƒœãƒªãƒ¥ãƒ¼ãƒ ä½œæˆã‚’行ãŠã†ã¨ã—ã¾ã—ãŸãŒã€%(pid)s ã®ã‚µã‚¤ã‚ºåˆ¶é™ã‚’è¶…ãˆã¦ã„ã¾ã™ã€‚"
#: ../nova/volume/api.py:47
#, python-format
msgid "Volume quota exceeded. You cannot create a volume of size %sG"
-msgstr "ボリュームã®ã‚¯ã‚ªãƒ¼ã‚¿ã‚’è¶…ãˆã¦ã„ã¾ã™ã€‚%sã®å¤§ãã•ã®ãƒœãƒªãƒ¥ãƒ¼ãƒ ã¯ä½œæˆã§ãã¾ã›ã‚“。"
+msgstr "ボリュームã®ã‚µã‚¤ã‚ºåˆ¶é™ã‚’è¶…ãˆã¦ã„ã¾ã™ã€‚サイズ %s GB ã®ãƒœãƒªãƒ¥ãƒ¼ãƒ ã¯ä½œæˆã§ãã¾ã›ã‚“。"
#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
msgid "Volume status must be available"
-msgstr "ボリュームã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹(status)㌠available ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。"
+msgstr "ボリュームã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹(status)㯠available ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。"
#: ../nova/volume/api.py:98
msgid "Volume is already attached"
-msgstr "ãƒœãƒªãƒ¥ãƒ¼ãƒ ã¯æ—¢ã«ã‚¢ã‚¿ãƒƒãƒã•れã¦ã„ã¾ã™(attached)。"
+msgstr "ãƒœãƒªãƒ¥ãƒ¼ãƒ ã¯æ—¢ã«æŽ¥ç¶š(attached)ã•れã¦ã„ã¾ã™ã€‚"
#: ../nova/volume/api.py:104
msgid "Volume is already detached"
-msgstr "ãƒœãƒªãƒ¥ãƒ¼ãƒ ã¯æ—¢ã«ãƒ‡ã‚¿ãƒƒãƒã•れã¦ã„ã¾ã™(detached)。"
+msgstr "ãƒœãƒªãƒ¥ãƒ¼ãƒ ã¯æ—¢ã«åˆ‡æ–­(detached)ã•れã¦ã„ã¾ã™ã€‚"
#: ../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 +88,7 @@ msgstr "イメージ %(_image_id)s ã«å¯¾ã™ã‚‹ãƒ—ロパティ %(param)s ãŒè¦‹ã
#: ../nova/api/openstack/servers.py:168
msgid "No keypairs defined"
-msgstr "キーペアãŒå®šç¾©ã•れã¦ã„ã¾ã›ã‚“。"
+msgstr "キーペアãŒå®šç¾©ã•れã¦ã„ã¾ã›ã‚“"
#: ../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
@@ -125,33 +130,6 @@ msgstr "例外: compute.api::suspend %s"
msgid "compute.api::resume %s"
msgstr "例外: compute.api::resume %s"
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr "å¼•æ•°ã®æ•°ãŒç•°ãªã‚Šã¾ã™ã€‚"
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr "pidfile %s ãŒå­˜åœ¨ã—ã¾ã›ã‚“。デーモンã¯å®Ÿè¡Œä¸­ã§ã™ã‹ï¼Ÿ\n"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr "ãã®ã‚ˆã†ãªãƒ—ロセスã¯ã‚りã¾ã›ã‚“"
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr "%s サービスã®é–‹å§‹"
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr "FLAGSã®ä¸€è¦§:"
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "%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
#: ../nova/api/ec2/__init__.py:317
@@ -163,33 +141,33 @@ msgstr "インスタンス %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
#: ../nova/virt/xenapi/volumeops.py:51
#, python-format
msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
-msgstr ""
+msgstr "ボリューム接続: %(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 ""
+msgstr "インスタンス %(instance_name)s 用ã®SR %(sr_ref)s ã«ãŠã‘ã‚‹ VDI を作æˆã§ãã¾ã›ã‚“"
#: ../nova/virt/xenapi/volumeops.py:80
#, python-format
msgid "Unable to use SR %(sr_ref)s for instance %(instance_name)s"
-msgstr ""
+msgstr "インスタンス %(instance_name)s 用ã®SR %(sr_ref)s ãŒä½¿ç”¨ã§ãã¾ã›ã‚“"
#: ../nova/virt/xenapi/volumeops.py:91
#, python-format
msgid "Unable to attach volume to instance %s"
-msgstr "インスタンス %s ã«ãƒœãƒªãƒ¥ãƒ¼ãƒ ã‚’アタッãƒã§ãã¾ã›ã‚“。"
+msgstr "インスタンス %s ã«ãƒœãƒªãƒ¥ãƒ¼ãƒ ã‚’接続(attach)ã§ãã¾ã›ã‚“。"
#: ../nova/virt/xenapi/volumeops.py:93
#, python-format
msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
-msgstr "インスタンス %(instance_name)s ã«ãƒžã‚¦ãƒ³ãƒˆãƒã‚¤ãƒ³ãƒˆ %(mountpoint)s をアタッãƒã—ã¾ã—ãŸã€‚"
+msgstr "インスタンス %(instance_name)s ã«ãƒžã‚¦ãƒ³ãƒˆãƒã‚¤ãƒ³ãƒˆ %(mountpoint)s を接続(attach)ã—ã¾ã—ãŸ"
#. Detach VBD from VM
#: ../nova/virt/xenapi/volumeops.py:104
#, python-format
msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
-msgstr ""
+msgstr "ボリューム切断: %(instance_name)s, %(mountpoint)s"
#: ../nova/virt/xenapi/volumeops.py:112
#, python-format
@@ -199,17 +177,17 @@ msgstr "ボリューム %s ã®å­˜åœ¨ãŒç¢ºèªã§ãã¾ã›ã‚“。"
#: ../nova/virt/xenapi/volumeops.py:120
#, python-format
msgid "Unable to detach volume %s"
-msgstr "ボリューム %s ã®ãƒ‡ã‚¿ãƒƒãƒãŒã§ãã¾ã›ã‚“。"
+msgstr "ボリューム %s を切断(detach)ã§ãã¾ã›ã‚“"
#: ../nova/virt/xenapi/volumeops.py:127
#, python-format
msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
-msgstr "インスタンス %(instance_name)s ã‹ã‚‰ãƒžã‚¦ãƒ³ãƒˆãƒã‚¤ãƒ³ãƒˆ %(mountpoint)s をデタッãƒã—ã¾ã—ãŸã€‚"
+msgstr "インスタンス %(instance_name)s ã‹ã‚‰ãƒžã‚¦ãƒ³ãƒˆãƒã‚¤ãƒ³ãƒˆ %(mountpoint)s を切断(detach)ã—ã¾ã—ãŸ"
#: ../nova/compute/instance_types.py:41
#, python-format
msgid "Unknown instance type: %s"
-msgstr "%s ã¯æœªçŸ¥ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚¿ã‚¤ãƒ—ã§ã™ã€‚"
+msgstr "未知ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚¿ã‚¤ãƒ—: %s"
#: ../nova/crypto.py:46
msgid "Filename of root CA"
@@ -258,7 +236,7 @@ msgstr "Flags ã®ãƒ‘ス: %s"
#: ../nova/scheduler/manager.py:69
#, python-format
msgid "Casting to %(topic)s %(host)s for %(method)s"
-msgstr ""
+msgstr "%(method)s 用㫠%(topic)s %(host)s を割り当ã¦ä¸­"
#: ../nova/compute/manager.py:78
#, python-format
@@ -269,7 +247,7 @@ msgstr "check_instance_lock: decorating: |%s|"
#, python-format
msgid ""
"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
-msgstr ""
+msgstr "check_instance_lock: 引数: |%(self)s| |%(context)s| |%(instance_id)s|"
#: ../nova/compute/manager.py:84
#, python-format
@@ -298,23 +276,23 @@ msgstr "ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã¯æ—¢ã«ç”Ÿæˆã•れã¦ã„ã¾ã™ã€‚"
#: ../nova/compute/manager.py:180
#, python-format
msgid "instance %s: starting..."
-msgstr "インスタンス %s ã‚’é–‹å§‹ã—ã¾ã™ã€‚"
+msgstr "インスタンス %s: 起動中…"
#. pylint: disable=W0702
#: ../nova/compute/manager.py:219
#, python-format
msgid "instance %s: Failed to spawn"
-msgstr "インスタンス %s ã®èµ·å‹•ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
+msgstr "インスタンス %s: èµ·å‹•ã«å¤±æ•—ã—ã¾ã—ãŸ"
#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
#, python-format
msgid "Terminating instance %s"
-msgstr "Terminating instance: インスタンス %s を終了ã—ã¾ã™ã€‚"
+msgstr "インスタンス %s ã‚’åœæ­¢ä¸­"
#: ../nova/compute/manager.py:255
#, python-format
msgid "Deallocating address %s"
-msgstr "アドレス %s ã®å‰²å½“を解除(deallocate)ã—ã¾ã™ã€‚"
+msgstr "アドレス %s ã®å‰²å½“を解除中(deallocating)"
#: ../nova/compute/manager.py:268
#, python-format
@@ -338,7 +316,7 @@ msgstr ""
#: ../nova/compute/manager.py:311
#, python-format
msgid "instance %s: snapshotting"
-msgstr "snapshotting: インスタンス %s ã®ã‚¹ãƒŠãƒƒãƒ—ショットをå–å¾—ã—ã¾ã™ã€‚"
+msgstr "snapshotting: インスタンス %s ã®ã‚¹ãƒŠãƒƒãƒ—ショットをå–得中"
#: ../nova/compute/manager.py:316
#, python-format
@@ -361,7 +339,7 @@ msgstr ""
#: ../nova/compute/manager.py:335
#, python-format
msgid "instance %s: setting admin password"
-msgstr "インスタンス %s: admin password をセットã—ã¾ã™"
+msgstr "インスタンス %s: 管ç†è€…用パスワードをセット中"
#: ../nova/compute/manager.py:353
#, python-format
@@ -375,7 +353,7 @@ msgstr ""
#: ../nova/compute/manager.py:362
#, python-format
msgid "instance %(nm)s: injecting file to %(plain_path)s"
-msgstr "インスタンス %(nm)s: ファイルを %(plain_path)s ã«ã‚¤ãƒ³ã‚¸ã‚§ã‚¯ãƒˆã—ã¾ã™"
+msgstr "インスタンス %(nm)s: ファイルを %(plain_path)s ã«åŸ‹ã‚è¾¼ã¿ä¸­"
#: ../nova/compute/manager.py:372
#, python-format
@@ -447,7 +425,7 @@ msgstr "インスタンス %s: ajax consoleを接続ã—ã¾ã™"
msgid ""
"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
msgstr ""
-"インスタンス %(instance_id)s: ボリューム %(volume_id)s ã‚’ %(mountpoint)s ã«ã‚¢ã‚¿ãƒƒãƒã—ã¾ã™"
+"インスタンス %(instance_id)s: ボリューム %(volume_id)s ã‚’ %(mountpoint)s ã«æŽ¥ç¶šä¸­(attaching)"
#. pylint: disable=W0702
#. NOTE(vish): The inline callback eats the exception info so we
@@ -549,7 +527,7 @@ msgstr "ボリューム %s ã®å‰Šé™¤ã«æˆåŠŸã—ã¾ã—ãŸã€‚"
#: ../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
@@ -616,12 +594,12 @@ msgstr "Pid %d ã¯ç„¡åйã§ã™ã€‚dnsmasqã‚’å†å®Ÿè¡Œã—ã¾ã™ã€‚"
#: ../nova/network/linux_net.py:358
#, python-format
msgid "killing radvd threw %s"
-msgstr ""
+msgstr "radvd åœæ­¢ãŒ %s 例外を発行ã—ã¾ã—ãŸ"
#: ../nova/network/linux_net.py:360
#, python-format
msgid "Pid %d is stale, relaunching radvd"
-msgstr ""
+msgstr "Pid %d ãŒã‚¹ãƒˆãƒ¼ãƒ«ã—ã¦ã„ã‚‹ã®ã§ radvd ã‚’å†å®Ÿè¡Œã—ã¦ã„ã¾ã™â€¦"
#. pylint: disable=W0703
#: ../nova/network/linux_net.py:449
@@ -677,7 +655,7 @@ msgstr "リンクローカルアドレスãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
#: ../nova/utils.py:265
#, python-format
msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
-msgstr ""
+msgstr "%(interface)s ã®ãƒ­ãƒ¼ã‚«ãƒ«IPアドレスã®ãƒªãƒ³ã‚¯ãŒå–å¾—ã§ãã¾ã›ã‚“:%(ex)s"
#: ../nova/utils.py:363
#, python-format
@@ -692,7 +670,7 @@ msgstr "ãƒãƒƒã‚¯ã‚¨ãƒ³ãƒ‰ã¯ %s ã§ã™ã€‚"
#: ../nova/fakerabbit.py:49
#, python-format
msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
-msgstr ""
+msgstr "(%(nm)s) 公開 (キー: %(routing_key)s) %(message)s"
#: ../nova/fakerabbit.py:54
#, python-format
@@ -712,12 +690,12 @@ msgstr "exchange %s ã®å®£è¨€"
#: ../nova/fakerabbit.py:96
#, python-format
msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
-msgstr ""
+msgstr "キー %(routing_key)s 付ãã§ %(exchange)s ã« %(queue)s ã‚’ãƒã‚¤ãƒ³ãƒ‰ã—ã¦ã„ã¾ã™"
#: ../nova/fakerabbit.py:121
#, python-format
msgid "Getting from %(queue)s: %(message)s"
-msgstr ""
+msgstr "%(queue)s ã‹ã‚‰å–å¾—ã—ã¦ã„ã¾ã™: %(message)s"
#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
#, python-format
@@ -727,17 +705,17 @@ msgstr "VM %s を作æˆã—ã¾ã™ã€‚"
#: ../nova/virt/xenapi/vm_utils.py:138
#, python-format
msgid "Created VM %(instance_name)s as %(vm_ref)s."
-msgstr ""
+msgstr "%(vm_ref)s ã¨ã—㦠VM %(instance_name)s を作æˆã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vm_utils.py:168
#, python-format
msgid "Creating VBD for VM %(vm_ref)s, VDI %(vdi_ref)s ... "
-msgstr ""
+msgstr "VM %(vm_ref)s, VDI %(vdi_ref)s 用 VBD を作æˆã—ã¦ã„ã¾ã™â€¦ "
#: ../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 "VM %(vm_ref)s, VDI %(vdi_ref)s 用仮想ブロックデãƒã‚¤ã‚¹(VBD) %(vbd_ref)s を作æˆã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:187
#, python-format
@@ -757,12 +735,12 @@ msgstr "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 "VM %(vm_ref)s, network %(network_ref)s 用仮想インターフェース(VIF)を作æˆã—ã¦ã„ã¾ã™ã€‚"
#: ../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 "VM %(vm_ref)s, network %(network_ref)s 用 VIF %(vif_ref)s を作æˆã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:246
#, python-format
@@ -770,50 +748,52 @@ msgid ""
"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
"%(sr_ref)s."
msgstr ""
+"%(sr_ref)s 上㫠VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, "
+"%(read_only)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 "ラベル '%(label)s' 付ã VM %(vm_ref)s ã®ã‚¹ãƒŠãƒƒãƒ—ショットを作æˆã—ã¦ã„ã¾ã™â€¦"
#: ../nova/virt/xenapi/vm_utils.py:272
#, python-format
msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
-msgstr ""
+msgstr "VM %(vm_ref)s ã‹ã‚‰ã‚¹ãƒŠãƒƒãƒ—ショット %(template_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 "ID %(image_id)s ã¨ã—㦠%(vdi_uuids)s ã®ã‚¢ãƒƒãƒ—ロードã®ç‚ºã« xapi ã‚’å•ã„åˆã‚ã›ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vm_utils.py:327
#, python-format
msgid "Size for image %(image)s:%(virtual_size)d"
-msgstr ""
+msgstr "イメージ %(image)s ã®ã‚µã‚¤ã‚º:%(virtual_size)d"
#: ../nova/virt/xenapi/vm_utils.py:332
#, python-format
msgid "Glance image %s"
-msgstr ""
+msgstr "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 "ドメイン0 上㮠/boot/guest 㫠VDI %s をコピー中"
#: ../nova/virt/xenapi/vm_utils.py:352
#, python-format
msgid "Kernel/Ramdisk VDI %s destroyed"
-msgstr ""
+msgstr "カーãƒãƒ«/RAMディスク VDI %s ãŒå‰Šé™¤ã•れã¾ã—ãŸ"
#: ../nova/virt/xenapi/vm_utils.py:361
#, python-format
msgid "Asking xapi to fetch %(url)s as %(access)s"
-msgstr ""
+msgstr "%(access)s ã¨ã—㦠%(url)s å–å¾—ã®ç‚ºã« xapi ã‚’å•ã„åˆã‚ã›ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
#, python-format
@@ -823,12 +803,12 @@ msgstr "PV kernelã®vdi %s ã‚’å–å¾—ã—ã¾ã™ã€‚"
#: ../nova/virt/xenapi/vm_utils.py:397
#, python-format
msgid "PV Kernel in VDI:%s"
-msgstr ""
+msgstr "VDI 中㮠PV カーãƒãƒ«:%s"
#: ../nova/virt/xenapi/vm_utils.py:405
#, python-format
msgid "Running pygrub against %s"
-msgstr ""
+msgstr "%s ã«å¯¾ã—㦠pygrub を実行ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vm_utils.py:411
#, python-format
@@ -838,6 +818,8 @@ msgstr "Xen Kernel %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:413
msgid "No Xen kernel found. Booting HVM."
msgstr ""
+"No Xen kernel found. Booting HVM.\r\n"
+"Xen 用カーãƒãƒ«ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。完全仮想化モード(HVM)ã§èµ·å‹•ã—ã¦ã„ã¾ã™ã€‚"
#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
#, python-format
@@ -862,7 +844,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 ã®è¦ªã¯ %(parent_ref)s ã§ã™"
#: ../nova/virt/xenapi/vm_utils.py:542
#, python-format
@@ -873,14 +855,14 @@ msgstr "SR %s ã‚’å†ã‚¹ã‚­ãƒ£ãƒ³ã—ã¾ã™ã€‚"
#, python-format
msgid ""
"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
-msgstr ""
+msgstr "VHD 作æˆãŒåˆ¶é™ã‚’è¶Šãˆã¾ã—ãŸ(%(counter)d > %(max_attempts)d)ã®ã§ã€ä¸­æ­¢ã—ã¦ã„ã¾ã™â€¦"
#: ../nova/virt/xenapi/vm_utils.py:574
#, python-format
msgid ""
"Parent %(parent_uuid)s doesn't match original parent "
"%(original_parent_uuid)s, waiting for coalesce..."
-msgstr ""
+msgstr "親 %(parent_uuid)s ãŒå…ƒã€…ã®è¦ª %(original_parent_uuid)s ã¨ä¸€è‡´ã—ã¾ã›ã‚“。作æˆã‚’待機ã—ã¦ã„ã¾ã™â€¦"
#: ../nova/virt/xenapi/vm_utils.py:590
#, python-format
@@ -890,96 +872,96 @@ msgstr "VM %s ã«VDIãŒå­˜åœ¨ã—ã¾ã›ã‚“。"
#: ../nova/virt/xenapi/vm_utils.py:594
#, python-format
msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
-msgstr ""
+msgstr "VM %(vm_ref)s 用ã«äºˆæœŸã—ãªã„æ•°ã® VDI (%(num_vdis)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 "VDI %s 用㫠VBD を作æˆã—ã¦ã„ã¾ã™â€¦ "
#: ../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 "VDI %s 用 VBD ã®ä½œæˆãŒå®Œäº†ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:657
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
#, python-format
msgid "Plugging VBD %s ... "
-msgstr ""
+msgstr "VBD %s を接続ã—ã¦ã„ã¾ã™â€¦ "
#: ../nova/virt/xenapi/vm_utils.py:659
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:194
#, python-format
msgid "Plugging VBD %s done."
-msgstr ""
+msgstr "仮想ブロックデãƒã‚¤ã‚¹(VBD) %s ã®æŽ¥ç¶šãŒå®Œäº†ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:661
#, python-format
msgid "VBD %(vbd)s plugged as %(orig_dev)s"
-msgstr ""
+msgstr "%(orig_dev)s ã¨ã—ã¦ä»®æƒ³ãƒ–ロックデãƒã‚¤ã‚¹(VBD) %(vbd)s を接続ã—ã¾ã—ãŸ"
#: ../nova/virt/xenapi/vm_utils.py:664
#, python-format
msgid "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
-msgstr ""
+msgstr "仮想ブロックデãƒã‚¤ã‚¹(VBD) %(vbd)s ã¯ä¸æ­£ãªãƒ‡ãƒã‚¤ã‚¹ã«æŽ¥ç¶šã•れã¾ã—ãŸã®ã§ã€%(dev)s ã«å†ãƒžãƒƒãƒ”ングã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vm_utils.py:668
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:197
#, python-format
msgid "Destroying VBD for VDI %s ... "
-msgstr ""
+msgstr "VDI %s 用ã®ä»®æƒ³ãƒ–ロックデãƒã‚¤ã‚¹(VBD)を削除ã—ã¦ã„ã¾ã™â€¦ "
#: ../nova/virt/xenapi/vm_utils.py:671
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:200
#, python-format
msgid "Destroying VBD for VDI %s done."
-msgstr ""
+msgstr "VDI %s 用ã®ä»®æƒ³ãƒ–ロックデãƒã‚¤ã‚¹(VBD)ã®å‰Šé™¤ãŒå®Œäº†ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:683
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:211
msgid "VBD.unplug successful first time."
-msgstr ""
+msgstr "VBD.unplug ã¯ï¼‘å›žç›®ã§æˆåŠŸã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:688
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:216
msgid "VBD.unplug rejected: retrying..."
-msgstr ""
+msgstr "VBD.unplug ãŒæ‹’å¦ã•れã¾ã—ãŸ: å†è©¦è¡Œã—ã¦ã„ã¾ã™â€¦"
#: ../nova/virt/xenapi/vm_utils.py:692
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:220
msgid "VBD.unplug successful eventually."
-msgstr ""
+msgstr "VBD.unplug ã¯æœ€çµ‚çš„ã«æˆåŠŸã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vm_utils.py:695
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:223
#, python-format
msgid "Ignoring XenAPI.Failure in VBD.unplug: %s"
-msgstr ""
+msgstr "VBD.unplug 中㮠XenAPI.Failure を無視ã—ã¦ã„ã¾ã™: %s"
#: ../nova/virt/xenapi/vm_utils.py:704
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:66
#, python-format
msgid "Ignoring XenAPI.Failure %s"
-msgstr ""
+msgstr "XenAPI.Failure %s を無視ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vm_utils.py:735
#, python-format
msgid ""
"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
-msgstr ""
+msgstr "%(dest)s ã«ãƒ‘ーティションテーブル %(primary_first)d %(primary_last)d を書ã込んã§ã„ã¾ã™â€¦"
#: ../nova/virt/xenapi/vm_utils.py:747
#, python-format
msgid "Writing partition table %s done."
-msgstr ""
+msgstr "パーティションテーブル %s ã®æ›¸ãè¾¼ã¿ãŒå®Œäº†ã—ã¾ã—ãŸã€‚"
#: ../nova/tests/test_rpc.py:89
#, python-format
msgid "Nested received %(queue)s, %(value)s"
-msgstr ""
+msgstr "Nested received %(queue)s, %(value)s"
#: ../nova/tests/test_rpc.py:95
#, python-format
@@ -1003,7 +985,7 @@ msgstr "id %s ã®serviceãŒå­˜åœ¨ã—ã¾ã›ã‚“。"
#: ../nova/db/sqlalchemy/api.py:251
#, python-format
msgid "No service for %(host)s, %(binary)s"
-msgstr ""
+msgstr "%(host)s, %(binary)s 用ã®ã‚µãƒ¼ãƒ“スãŒã‚りã¾ã›ã‚“"
#: ../nova/db/sqlalchemy/api.py:592
msgid "No fixed ips defined"
@@ -1110,6 +1092,8 @@ msgid ""
"No console pool of type %(console_type)s for compute host %(compute_host)s "
"on proxy host %(host)s"
msgstr ""
+"コンピュータホスト %(compute_host)s 用 %(console_type)s 型コンソールプールãŒãƒ—ロキシホスト %(host)s "
+"上ã«ã‚りã¾ã›ã‚“"
#: ../nova/db/sqlalchemy/api.py:2035
#, python-format
@@ -1119,27 +1103,27 @@ msgstr "プール %(pool_id)s ã« %(instance_id)s ã®ã‚³ãƒ³ã‚½ãƒ¼ãƒ«ãŒã‚りã¾
#: ../nova/db/sqlalchemy/api.py:2057
#, python-format
msgid "on instance %s"
-msgstr ""
+msgstr "インスタンス %s 上"
#: ../nova/db/sqlalchemy/api.py:2058
#, python-format
msgid "No console with id %(console_id)s %(idesc)s"
-msgstr ""
+msgstr "ID %(console_id)s %(idesc)s ã‚’æŒã¤ã‚³ãƒ³ã‚½ãƒ¼ãƒ«ãŒã‚りã¾ã›ã‚“"
#: ../nova/db/sqlalchemy/api.py:2078 ../nova/db/sqlalchemy/api.py:2097
#, python-format
msgid "No zone with id %(zone_id)s"
-msgstr ""
+msgstr "ID %(zone_id)s ã‚’æŒã¤ã‚¾ãƒ¼ãƒ³ãŒã‚りã¾ã›ã‚“"
#: ../nova/virt/libvirt_conn.py:160
#, python-format
msgid "Checking state of %s"
-msgstr ""
+msgstr "%s ã®çŠ¶æ…‹ã‚’ç¢ºèªã—ã¦ã„ã¾ã™"
#: ../nova/virt/libvirt_conn.py:165
#, python-format
msgid "Current state of %(name)s was %(state)s."
-msgstr ""
+msgstr "%(name)s ã®ç¾åœ¨ã®çŠ¶æ…‹ã¯ %(state)s ã§ã™"
#: ../nova/virt/libvirt_conn.py:183
#, python-format
@@ -1153,12 +1137,12 @@ msgstr "libvirtã¸ã®æŽ¥ç¶šãŒåˆ‡ã‚Œã¦ã„ã¾ã™ã€‚"
#: ../nova/virt/libvirt_conn.py:258
#, python-format
msgid "instance %(instance_name)s: deleting instance files %(target)s"
-msgstr ""
+msgstr "インスタンス %(instance_name)s: インスタンスファイル群 %(target)s を削除ã—ã¦ã„ã¾ã™"
#: ../nova/virt/libvirt_conn.py:283
#, python-format
msgid "Invalid device path %s"
-msgstr ""
+msgstr "%s ã¯ä¸æ­£ãªãƒ‡ãƒã‚¤ã‚¹ãƒ‘スã§ã™"
#: ../nova/virt/libvirt_conn.py:313
#, python-format
@@ -1216,16 +1200,16 @@ msgstr "デãƒã‚¤ã‚¹ã§ã™ã€‚"
#: ../nova/virt/libvirt_conn.py:448
#, python-format
msgid "data: %(data)r, fpath: %(fpath)r"
-msgstr ""
+msgstr "データ: %(data)r, ファイルパス: %(fpath)r"
#: ../nova/virt/libvirt_conn.py:456
#, python-format
msgid "Contents of file %(fpath)s: %(contents)r"
-msgstr ""
+msgstr "ファイル %(fpath)s ã®å†…容: %(contents)r"
#: ../nova/virt/libvirt_conn.py:489
msgid "Unable to find an open port"
-msgstr ""
+msgstr "é–‹ã„ãŸãƒãƒ¼ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
#: ../nova/virt/libvirt_conn.py:563
#, python-format
@@ -1235,12 +1219,12 @@ msgstr "インスタンス %s ã®ã‚¤ãƒ¡ãƒ¼ã‚¸ã‚’生æˆã—ã¾ã™ã€‚"
#: ../nova/virt/libvirt_conn.py:646
#, python-format
msgid "instance %(inst_name)s: injecting key into image %(img_id)s"
-msgstr ""
+msgstr "インスタンス %(inst_name)s: イメージ %(img_id)s ã«éµæƒ…報を埋ã‚込んã§ã„ã¾ã™"
#: ../nova/virt/libvirt_conn.py:649
#, python-format
msgid "instance %(inst_name)s: injecting net into image %(img_id)s"
-msgstr ""
+msgstr "インスタンス %(inst_name)s: イメージ %(img_id)s ã«ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æƒ…報を埋ã‚込んã§ã„ã¾ã™"
#. This could be a windows image, or a vmdk format disk
#: ../nova/virt/libvirt_conn.py:657
@@ -1248,7 +1232,7 @@ msgstr ""
msgid ""
"instance %(inst_name)s: ignoring error injecting data into image %(img_id)s "
"(%(e)s)"
-msgstr ""
+msgstr "インスタンス %(inst_name)s: イメージ %(img_id)s ã¸ã®ãƒ‡ãƒ¼ã‚¿åŸ‹ã‚è¾¼ã¿ã®ã‚¨ãƒ©ãƒ¼ã‚’無視ã—ã¦ã„ã¾ã™ (%(e)s)"
#. TODO(termie): cache?
#: ../nova/virt/libvirt_conn.py:665
@@ -1263,12 +1247,12 @@ msgstr "インスタンス %s: toXML メソッドを完了。"
#: ../nova/virt/libvirt_conn.py:751
msgid "diagnostics are not supported for libvirt"
-msgstr ""
+msgstr "libvirt ã§ã¯è¨ºæ–­(diagnostics)ãŒã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“"
#: ../nova/virt/libvirt_conn.py:1225
#, python-format
msgid "Attempted to unfilter instance %s which is not filtered"
-msgstr ""
+msgstr "フィルタã•れã¦ã„ãªã„インスタンス %s ã®ãƒ•ィルタ解除を試行ã—ã¾ã—ãŸ"
#: ../nova/api/ec2/metadatarequesthandler.py:76
#, python-format
@@ -1296,7 +1280,7 @@ msgstr "ターゲット %s をアロケートã—ã¾ã—ãŸã€‚"
#: ../nova/virt/images.py:70
#, python-format
msgid "Finished retreving %(url)s -- placed in %(path)s"
-msgstr ""
+msgstr "%(url)s ã®å–得を完了ã—ã¾ã—㟠-- %(path)s ã«é…ç½®ã•れã¾ã—ãŸ"
#: ../nova/scheduler/driver.py:66
msgid "Must implement a fallback schedule"
@@ -1304,21 +1288,21 @@ msgstr "予備ã®(fallback)スケジューラを実装ã™ã‚‹å¿…è¦ãŒã‚りã¾ã
#: ../nova/console/manager.py:70
msgid "Adding console"
-msgstr ""
+msgstr "コンソールを追加ã—ã¦ã„ã¾ã™"
#: ../nova/console/manager.py:90
#, python-format
msgid "Tried to remove non-existant console %(console_id)s."
-msgstr ""
+msgstr "存在ã—ãªã„コンソール %(console_id)s を削除ã—よã†ã¨ã—ã¾ã—ãŸ"
#: ../nova/api/direct.py:149
msgid "not available"
-msgstr ""
+msgstr "利用ã§ãã¾ã›ã‚“"
#: ../nova/api/ec2/cloud.py:62
#, python-format
msgid "The key_pair %s already exists"
-msgstr ""
+msgstr "キーペア %s ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
#. TODO(vish): Do this with M2Crypto instead
#: ../nova/api/ec2/cloud.py:118
@@ -1352,7 +1336,7 @@ msgstr "Revoke security group ingress: ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚°ãƒ«ãƒ¼ãƒ—è¨±å¯ %s ã
#: ../nova/api/ec2/cloud.py:430 ../nova/api/ec2/cloud.py:459
msgid "Not enough parameters to build a valid rule."
-msgstr ""
+msgstr "有効ãªãƒ«ãƒ¼ãƒ«ã‚’作æˆã™ã‚‹ç‚ºã®å分ãªãƒ‘ラメータãŒã‚りã¾ã›ã‚“"
#: ../nova/api/ec2/cloud.py:443
msgid "No rule for the specified parameters."
@@ -1391,7 +1375,7 @@ msgstr "Create volume: %s GBã®ãƒœãƒªãƒ¥ãƒ¼ãƒ ã‚’作æˆã—ã¾ã™ã€‚"
#: ../nova/api/ec2/cloud.py:612
#, python-format
msgid "Attach volume %(volume_id)s to instance %(instance_id)s at %(device)s"
-msgstr ""
+msgstr "ボリューム %(volume_id)s をインスタンス %(instance_id)s ã®ãƒ‡ãƒã‚¤ã‚¹ %(device)s ã«æŽ¥ç¶š"
#: ../nova/api/ec2/cloud.py:629
#, python-format
@@ -1410,7 +1394,7 @@ msgstr "Release address: アドレス %s を開放ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/cloud.py:771
#, python-format
msgid "Associate address %(public_ip)s to instance %(instance_id)s"
-msgstr ""
+msgstr "インスタンス %(instance_id)s ã«ã‚¢ãƒ‰ãƒ¬ã‚¹ %(public_ip)s を割り当ã¦"
#: ../nova/api/ec2/cloud.py:780
#, python-format
@@ -1434,7 +1418,7 @@ msgstr "De-registering image: イメージ %s を登録解除ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/cloud.py:875
#, python-format
msgid "Registered image %(image_location)s with id %(image_id)s"
-msgstr ""
+msgstr "イメージ %(image_location)s ㌠ID %(image_id)s ã§ç™»éŒ²ã•れã¾ã—ãŸ"
#: ../nova/api/ec2/cloud.py:882 ../nova/api/ec2/cloud.py:900
#, python-format
@@ -1466,12 +1450,12 @@ msgstr "イメージ %s ã®å…¬é–‹è¨­å®šã‚’æ›´æ–°ã—ã¾ã™ã€‚"
#: ../bin/nova-api.py:52
#, python-format
msgid "Using paste.deploy config at: %s"
-msgstr ""
+msgstr "%s ã«ã‚ã‚‹ paste.deploy 設定を使用ã—ã¦ã„ã¾ã™"
#: ../bin/nova-api.py:57
#, python-format
msgid "No paste configuration for app: %s"
-msgstr ""
+msgstr "アプリケーション用 paste 設定ãŒã‚りã¾ã›ã‚“: %s"
#: ../bin/nova-api.py:59
#, python-format
@@ -1479,60 +1463,63 @@ msgid ""
"App Config: %(api)s\n"
"%(config)r"
msgstr ""
+"アプリケーション設定 %(api)s\n"
+"%(config)r"
#: ../bin/nova-api.py:64
#, python-format
msgid "Running %s API"
-msgstr ""
+msgstr "%s API を実行ã—ã¦ã„ã¾ã™"
#: ../bin/nova-api.py:69
#, python-format
msgid "No known API applications configured in %s."
-msgstr ""
+msgstr "%s ä¸­ã«æ—¢çŸ¥ã® API アプリケーション設定ãŒã‚りã¾ã›ã‚“。"
#: ../bin/nova-api.py:83
#, python-format
msgid "Starting nova-api node (version %s)"
-msgstr ""
+msgstr "nova-api ノードを起動ã—ã¦ã„ã¾ã™ (ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %s)"
#: ../bin/nova-api.py:89
#, python-format
msgid "No paste configuration found for: %s"
-msgstr ""
+msgstr "%s 用㮠paste 設定ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:84
#, python-format
msgid "Argument %(key)s value %(value)s is too short."
-msgstr ""
+msgstr "引数 %(key)s ã®å€¤ %(value)s ãŒçŸ­ã™ãŽã¾ã™ã€‚"
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:89
#, python-format
msgid "Argument %(key)s value %(value)s contains invalid characters."
-msgstr ""
+msgstr "引数 %(key)s ã®å€¤ %(value)s ãŒä¸æ­£ãªæ–‡å­—ã‚’å«ã‚“ã§ã„ã¾ã™ã€‚"
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:94
#, python-format
msgid "Argument %(key)s value %(value)s starts with a hyphen."
-msgstr ""
+msgstr "引数 %(key)s ã®å€¤ %(value)s ãŒãƒã‚¤ãƒ•ン(-)ã‹ã‚‰å§‹ã¾ã£ã¦ã„ã¾ã™ã€‚"
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:102
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:130
#, python-format
msgid "Argument %s is required."
-msgstr ""
+msgstr "引数 %s ãŒå¿…è¦ã§ã™ã€‚"
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:117
#, python-format
msgid ""
"Argument %(key)s may not take value %(value)s. Valid values are ['true', "
"'false']."
-msgstr ""
+msgstr "引数 %(key)s ã¯å€¤ %(value)s ãŒè¨±å¯ã•れã¦ã„ã¾ã›ã‚“。有効ãªå€¤ã¯ ['true', 'false'] ã§ã™ã€‚"
#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:163
#, python-format
msgid ""
"Created VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) on %(sr_ref)s."
msgstr ""
+"%(sr_ref)s 上㫠VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) を作æˆã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vmops.py:67
#, python-format
@@ -1542,7 +1529,7 @@ msgstr "ユニークã§ã¯ãªã„name %s を作æˆã—よã†ã¨ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/xenapi/vmops.py:73
#, python-format
msgid "instance %(name)s: not enough free memory"
-msgstr ""
+msgstr "インスタンス %(name)s: å分ãªç©ºãメモリãŒã‚りã¾ã›ã‚“"
#: ../nova/virt/xenapi/vmops.py:148
#, python-format
@@ -1552,17 +1539,17 @@ msgstr "VM %s ã‚’é–‹å§‹ã—ã¾ã™â€¦"
#: ../nova/virt/xenapi/vmops.py:151
#, python-format
msgid "Spawning VM %(instance_name)s created %(vm_ref)s."
-msgstr ""
+msgstr "%(vm_ref)s ã‹ã‚‰ä½œæˆã•れ㟠VM %(instance_name)s ã®å®Ÿè¡ŒãŒç¹°ã‚Šã‹ãˆã•れã¦ã„ã¾ã™ã€‚"
#: ../nova/virt/xenapi/vmops.py:162
#, python-format
msgid "Invalid value for onset_files: '%s'"
-msgstr ""
+msgstr "onset_files 用ã®ä¸æ­£ãªå€¤: '%s'"
#: ../nova/virt/xenapi/vmops.py:167
#, python-format
msgid "Injecting file path: '%s'"
-msgstr ""
+msgstr "ファイルパス '%s' を埋ã‚込んã§ã„ã¾ã™"
#: ../nova/virt/xenapi/vmops.py:180
#, python-format
@@ -1584,7 +1571,7 @@ msgstr "VM %s ã«å¯¾ã™ã‚‹ã‚¹ãƒŠãƒƒãƒ—ショットを開始ã—ã¾ã™ã€‚"
#: ../nova/virt/xenapi/vmops.py:269
#, python-format
msgid "Unable to Snapshot %(vm_ref)s: %(exc)s"
-msgstr ""
+msgstr "%(vm_ref)s ã®ã‚¹ãƒŠãƒƒãƒ—ショットãŒä½œæˆå‡ºæ¥ã¾ã›ã‚“: %(exc)s"
#: ../nova/virt/xenapi/vmops.py:280
#, python-format
@@ -1594,15 +1581,15 @@ msgstr "VM %s ã®ã‚¹ãƒŠãƒƒãƒ—ショットã¨ã‚¢ãƒƒãƒ—ロードãŒå®Œäº†ã—ã¾ã—
#: ../nova/virt/xenapi/vmops.py:356
#, python-format
msgid "VM %(vm)s already halted, skipping shutdown..."
-msgstr ""
+msgstr "VM %(vm)s ã¯æ—¢ã«åœæ­¢ã—ã¦ã„ã¾ã™ã®ã§ã€ã‚·ãƒ£ãƒƒãƒˆãƒ€ã‚¦ãƒ³ã‚’çœç•¥ã—ã¾ã™â€¦"
#: ../nova/virt/xenapi/vmops.py:389
msgid "Removing kernel/ramdisk files"
-msgstr ""
+msgstr "カーãƒãƒ«/RAMディスクファイルを削除ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/vmops.py:399
msgid "kernel/ramdisk files removed"
-msgstr ""
+msgstr "カーãƒãƒ«/RAMディスクファイルãŒå‰Šé™¤ã•れã¾ã—ãŸ"
#: ../nova/virt/xenapi/vmops.py:561
#, python-format
@@ -1610,6 +1597,7 @@ msgid ""
"TIMEOUT: The call to %(method)s timed out. VM id=%(instance_id)s; "
"args=%(strargs)s"
msgstr ""
+"タイムアウト: %(method)s ã®å‘¼ã³å‡ºã—ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸã€‚VM id=%(instance_id)s; 引数=%(strargs)s"
#: ../nova/virt/xenapi/vmops.py:564
#, python-format
@@ -1617,6 +1605,7 @@ msgid ""
"NOT IMPLEMENTED: The call to %(method)s is not supported by the agent. VM "
"id=%(instance_id)s; args=%(strargs)s"
msgstr ""
+"未実装: %(method)s ã®å‘¼ã³å‡ºã—ã¯ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã«å®Ÿè£…ã•れã¦ã„ã¾ã›ã‚“。VM id=%(instance_id)s; 引数=%(strargs)s"
#: ../nova/virt/xenapi/vmops.py:569
#, python-format
@@ -1624,11 +1613,12 @@ msgid ""
"The call to %(method)s returned an error: %(e)s. VM id=%(instance_id)s; "
"args=%(strargs)s"
msgstr ""
+"%(method)s 呼ã³å‡ºã—ãŒã‚¨ãƒ©ãƒ¼ã‚’è¿”ã—ã¾ã—ãŸ: %(e)s. VM id=%(instance_id)s; 引数=%(strargs)s"
#: ../nova/virt/xenapi/vmops.py:760
#, python-format
msgid "OpenSSL error: %s"
-msgstr ""
+msgstr "OpenSSL エラー: %s"
#: ../nova/tests/test_compute.py:148
#, python-format
@@ -1659,7 +1649,7 @@ msgstr "%s 用ã®VPNã‚’èµ·å‹•ã—ã¾ã™ã€‚"
#: ../nova/db/sqlalchemy/migration.py:35
msgid "python-migrate is not installed. Exiting."
-msgstr ""
+msgstr "python-migrate ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ã„ã¾ã›ã‚“。終了ã—ã¾ã™ã€‚"
#: ../nova/image/s3.py:99
#, python-format
@@ -1676,6 +1666,7 @@ msgid ""
"Access key %(access_key)s has had %(failures)d failed authentications and "
"will be locked out for %(lock_mins)d minutes."
msgstr ""
+"アクセスキー %(access_key)s 㯠%(failures)d 回èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã®ã§ã€%(lock_mins)d 分間ロックã—ã¾ã™ã€‚"
#: ../nova/api/ec2/__init__.py:169 ../nova/objectstore/handler.py:140
#, python-format
@@ -1685,7 +1676,7 @@ msgstr "%s ã®èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: ../nova/api/ec2/__init__.py:182
#, python-format
msgid "Authenticated Request For %(uname)s:%(pname)s)"
-msgstr ""
+msgstr "%(uname)s 用ã®èªè¨¼ãƒªã‚¯ã‚¨ã‚¹ãƒˆ:%(pname)s)"
#: ../nova/api/ec2/__init__.py:207
#, python-format
@@ -1695,23 +1686,23 @@ msgstr "アクション(action): %s"
#: ../nova/api/ec2/__init__.py:209
#, python-format
msgid "arg: %(key)s\t\tval: %(value)s"
-msgstr ""
+msgstr "引数: %(key)s\t\t値: %(value)s"
#: ../nova/api/ec2/__init__.py:281
#, python-format
msgid ""
"Unauthorized request for controller=%(controller)s and action=%(action)s"
-msgstr ""
+msgstr "コントローラ=%(controller)s ã¨ã‚¢ã‚¯ã‚·ãƒ§ãƒ³=%(action)s 用ã®è¨±å¯ã•れã¦ã„ãªã„リクエスト"
#: ../nova/api/ec2/__init__.py:314
#, python-format
msgid "InstanceNotFound raised: %s"
-msgstr ""
+msgstr "InstanceNotFound ãŒç™ºè¡Œã•れã¾ã—ãŸ: %s"
#: ../nova/api/ec2/__init__.py:320
#, python-format
msgid "VolumeNotFound raised: %s"
-msgstr ""
+msgstr "VolumeNotFound ãŒç™ºè¡Œã•れã¾ã—ãŸ: %s"
#: ../nova/api/ec2/__init__.py:326
#, python-format
@@ -1778,56 +1769,28 @@ msgstr ""
#: ../nova/virt/xenapi_conn.py:311
#, python-format
msgid "Task [%(name)s] %(task)s status: success %(result)s"
-msgstr ""
+msgstr "タスク [%(name)s] %(task)s 状態: æˆåŠŸ %(result)s"
#: ../nova/virt/xenapi_conn.py:317
#, python-format
msgid "Task [%(name)s] %(task)s status: %(status)s %(error_info)s"
-msgstr ""
+msgstr "タスク [%(name)s] %(task)s 状態: %(status)s %(error_info)s"
#: ../nova/virt/xenapi_conn.py:331 ../nova/virt/xenapi_conn.py:344
#, python-format
msgid "Got exception: %s"
msgstr "例外 %s ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr "%s ã®æƒ…å ±ã®æ›´æ–°â€¦"
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr "æ›´æ–°ã®æœ€ä¸­ã«äºˆæœŸã—ãªã„エラーãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr "接続ã«éš›ã—予期ã—ãªã„エラーãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr "インスタンス %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚"
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
-msgstr ""
+msgstr "ボリューム %s 用㮠iSCSI エクスãƒãƒ¼ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
#: ../nova/api/ec2/apirequest.py:100
#, python-format
msgid ""
"Unsupported API request: controller = %(controller)s, action = %(action)s"
-msgstr ""
+msgstr "未サãƒãƒ¼ãƒˆã® API リクエスト: コントローラ = %(controller)s, アクション = %(action)s"
#: ../nova/api/openstack/__init__.py:55
#, python-format
@@ -1840,33 +1803,33 @@ msgstr "管ç†ç”¨ã‚ªãƒšãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ï¼ˆadmin operation)ã‚’APIã«ç™»éŒ²ã—ã¾ã
#: ../nova/console/xvp.py:99
msgid "Rebuilding xvp conf"
-msgstr ""
+msgstr "xvp è¨­å®šã‚’å†æ§‹ç¯‰ã—ã¦ã„ã¾ã™"
#: ../nova/console/xvp.py:116
#, python-format
msgid "Re-wrote %s"
-msgstr ""
+msgstr "%s ã‚’å†åº¦æ›¸ãè¾¼ã¿ã¾ã—ãŸ"
#: ../nova/console/xvp.py:121
msgid "Stopping xvp"
-msgstr ""
+msgstr "xvp ã‚’åœæ­¢ã—ã¦ã„ã¾ã™"
#: ../nova/console/xvp.py:134
msgid "Starting xvp"
-msgstr ""
+msgstr "xvp ã‚’é–‹å§‹ã—ã¦ã„ã¾ã™"
#: ../nova/console/xvp.py:141
#, python-format
msgid "Error starting xvp: %s"
-msgstr ""
+msgstr "xvp ã®é–‹å§‹ä¸­ã«ã‚¨ãƒ©ãƒ¼: %s"
#: ../nova/console/xvp.py:144
msgid "Restarting xvp"
-msgstr ""
+msgstr "xvp ã‚’å†èµ·å‹•ã—ã¦ã„ã¾ã™"
#: ../nova/console/xvp.py:146
msgid "xvp not running..."
-msgstr ""
+msgstr "xvp ãŒå®Ÿè¡Œã•れã¦ã„ã¾ã›ã‚“…"
#: ../bin/nova-manage.py:272
msgid ""
@@ -1874,6 +1837,8 @@ msgid ""
"Please create a database using nova-manage sync db before running this "
"command."
msgstr ""
+"上記ã®ã‚¨ãƒ©ãƒ¼ã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒä½œæˆã•れã¦ã„ãªã„為ã«è¡¨ç¤ºã•れãŸã®ã‹ã‚‚知れã¾ã›ã‚“。\n"
+"ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’実行ã™ã‚‹å‰ã«ã€nova-manage db sync を使用ã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’作æˆã—ã¦ä¸‹ã•ã„。"
#: ../bin/nova-manage.py:426
msgid ""
@@ -1883,40 +1848,47 @@ msgid ""
" nova-manage network create 10.0.0.0/8 10 64\n"
"\n"
msgstr ""
+"ã“れ以上利用å¯èƒ½ãªãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒã‚りã¾ã›ã‚“。ã“ã‚ŒãŒæ–°è¦ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã§ã‚れã°ã€\n"
+"下記ã®ã‚ˆã†ãªã‚³ãƒžãƒ³ãƒ‰ã‚’実行ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™:\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
#: ../bin/nova-manage.py:431
msgid ""
"The above error may show that the certificate db has not been created.\n"
"Please create a database by running a nova-api server on this host."
msgstr ""
+"上記ã®ã‚¨ãƒ©ãƒ¼ã¯èªè¨¼ DB ãŒä½œæˆã•れã¦ã„ãªã„為ã«è¡¨ç¤ºã•れるã®ã‹ã‚‚知れã¾ã›ã‚“。\n"
+"ã“ã®ãƒ›ã‚¹ãƒˆä¸Šã§ nova-api を実行ã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’作æˆã—ã¦ä¸‹ã•ã„。"
#: ../bin/nova-manage.py:447 ../bin/nova-manage.py:536
msgid "network"
-msgstr ""
+msgstr "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯"
#: ../bin/nova-manage.py:448
msgid "IP address"
-msgstr ""
+msgstr "IPアドレス"
#: ../bin/nova-manage.py:449
msgid "MAC address"
-msgstr ""
+msgstr "MAC アドレス"
#: ../bin/nova-manage.py:450
msgid "hostname"
-msgstr ""
+msgstr "ホストå"
#: ../bin/nova-manage.py:451
msgid "host"
-msgstr ""
+msgstr "ホスト"
#: ../bin/nova-manage.py:537
msgid "netmask"
-msgstr ""
+msgstr "ãƒãƒƒãƒˆãƒžã‚¹ã‚¯"
#: ../bin/nova-manage.py:538
msgid "start address"
-msgstr ""
+msgstr "開始アドレス"
#: ../nova/virt/disk.py:69
#, python-format
@@ -1931,7 +1903,7 @@ msgstr "ファイルシステム %s ã®ãƒžã‚¦ãƒ³ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/disk.py:124
#, python-format
msgid "nbd device %s did not show up"
-msgstr ""
+msgstr "nbd デãƒã‚¤ã‚¹ %s ãŒå‡ºç¾ã—ã¾ã›ã‚“"
#: ../nova/virt/disk.py:128
#, python-format
@@ -1940,12 +1912,12 @@ msgstr "イメージをループãƒãƒƒã‚¯ %s ã«ã‚¢ã‚¿ãƒƒãƒã§ãã¾ã›ã‚“。"
#: ../nova/virt/disk.py:151
msgid "No free nbd devices"
-msgstr ""
+msgstr "空ãã® nbd デãƒã‚¤ã‚¹ãŒã‚りã¾ã›ã‚“"
#: ../doc/ext/nova_todo.py:46
#, python-format
msgid "%(filename)s, line %(line_info)d"
-msgstr ""
+msgstr "%(filename)s, %(line_info)d 行目"
#. FIXME(chiradeep): implement this
#: ../nova/virt/hyperv.py:118
@@ -1990,7 +1962,7 @@ msgstr "vm %s ã®vcpus を設定ã—ã¾ã™ã€‚"
#: ../nova/virt/hyperv.py:202
#, python-format
msgid "Creating disk for %(vm_name)s by attaching disk file %(vhdfile)s"
-msgstr ""
+msgstr "ディスクファイル %(vhdfile)s 接続ã«ã‚ˆã‚Šã€%(vm_name)s 用ディスクを作æˆã—ã¦ã„ã¾ã™"
#: ../nova/virt/hyperv.py:227
#, python-format
@@ -2029,7 +2001,7 @@ msgstr "ãƒãƒ¼ãƒˆ %s ã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/hyperv.py:276
#, python-format
msgid "Created switch port %(vm_name)s on switch %(ext_path)s"
-msgstr ""
+msgstr "スイッム%(ext_path)s 上ã®ã‚¹ã‚¤ãƒƒãƒãƒãƒ¼ãƒˆ %(vm_name)s ãŒä½œæˆã•れã¾ã—ãŸ"
#: ../nova/virt/hyperv.py:286
#, python-format
@@ -2049,7 +2021,7 @@ msgstr "WMIジョブã«å¤±æ•—ã—ã¾ã—ãŸ: %s"
#: ../nova/virt/hyperv.py:325
#, python-format
msgid "WMI job succeeded: %(desc)s, Elapsed=%(elap)s "
-msgstr ""
+msgstr "WMI ジョブæˆåŠŸ: %(desc)s, çµŒéŽæ™‚é–“=%(elap)s "
#: ../nova/virt/hyperv.py:361
#, python-format
@@ -2064,7 +2036,7 @@ msgstr "vm %s ã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: ../nova/virt/hyperv.py:393
#, python-format
msgid "Del: disk %(vhdfile)s vm %(instance_name)s"
-msgstr ""
+msgstr "削除: ディスク %(vhdfile)s VM %(instance_name)s"
#: ../nova/virt/hyperv.py:415
#, python-format
@@ -2072,16 +2044,20 @@ msgid ""
"Got Info for vm %(instance_id)s: state=%(state)s, mem=%(memusage)s, "
"num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
msgstr ""
+"VM %(instance_id)s 用情報å–å¾—: 状態=%(state)s, メモリ=%(memusage)s, CPUæ•°=%(numprocs)s, "
+"CPU時間=%(uptime)s"
#: ../nova/virt/hyperv.py:451
#, python-format
msgid "Successfully changed vm state of %(vm_name)s to %(req_state)s"
-msgstr ""
+msgstr "VM ã®çŠ¶æ…‹ãŒ %(vm_name)s ã‹ã‚‰ %(req_state)s ã«ç„¡äº‹å¤‰æ›´ã•れã¾ã—ãŸ"
#: ../nova/virt/hyperv.py:454
#, python-format
msgid "Failed to change vm state of %(vm_name)s to %(req_state)s"
msgstr ""
+"Failed to change vm state of \r\n"
+"%(vm_name)s ã‹ã‚‰ %(req_state)s ã¸ã®VM ã®çŠ¶æ…‹å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸ"
#: ../nova/compute/api.py:71
#, python-format
@@ -2096,7 +2072,7 @@ msgstr "インスタンス %d ã«ãƒ›ã‚¹ãƒˆãŒç™»éŒ²ã•れã¦ã„ã¾ã›ã‚“。"
#: ../nova/compute/api.py:97
#, python-format
msgid "Quota exceeeded for %(pid)s, tried to run %(min_count)s instances"
-msgstr ""
+msgstr "%(pid)s 用ã®åˆ¶é™(Quota)è¶…éŽã€%(min_count)s 個ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’実行ã—よã†ã¨ã—ã¾ã—ãŸ"
#: ../nova/compute/api.py:99
#, python-format
@@ -2117,11 +2093,14 @@ msgstr "%s 個ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®èµ·å‹•ã‚’å§‹ã‚ã¾ã™â€¦"
#, python-format
msgid "Casting to scheduler for %(pid)s/%(uid)s's instance %(instance_id)s"
msgstr ""
+"Casting to scheduler for \r\n"
+"\r\n"
+"%(pid)s/%(uid)s ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ %(instance_id)s 用ã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ©ã‚’割り当ã¦"
#: ../nova/compute/api.py:292
#, python-format
msgid "Going to try to terminate %s"
-msgstr ""
+msgstr "%s ã‚’åœæ­¢ã—よã†ã¨ã—ã¦ã„ã¾ã™"
#: ../nova/compute/api.py:296
#, python-format
@@ -2148,6 +2127,8 @@ msgid ""
"AMQP server on %(fl_host)s:%(fl_port)d is unreachable. Trying again in "
"%(fl_intv)d seconds."
msgstr ""
+"%(fl_host)s 上㮠AMQP サーãƒ:%(fl_port)d ãŒåˆ°é”ä¸èƒ½(unreachable)ã§ã™ã€‚%(fl_intv)d "
+"秒後ã«å†è©¦è¡Œã—ã¾ã™ã€‚"
#: ../nova/rpc.py:103
#, python-format
@@ -2207,7 +2188,7 @@ msgstr "MSG_ID㯠%s ã§ã™ã€‚"
#: ../nova/rpc.py:354
msgid "Making asynchronous cast..."
-msgstr ""
+msgstr "éžåŒæœŸã®å‰²ã‚Šå½“ã¦ã‚’作æˆã—ã¦ã„ã¾ã™â€¦"
#: ../nova/rpc.py:364
#, python-format
@@ -2241,11 +2222,11 @@ msgstr "å½ã®AOE: %s"
#: ../nova/volume/driver.py:233
msgid "Skipping ensure_export. No iscsi_target "
-msgstr ""
+msgstr "ensure_export ã‚’çœç•¥ã—ã¦ã„ã¾ã™ã€‚iscsi_target ãŒã‚りã¾ã›ã‚“。 "
#: ../nova/volume/driver.py:279 ../nova/volume/driver.py:288
msgid "Skipping remove_export. No iscsi_target "
-msgstr ""
+msgstr "remove_export ã‚’çœç•¥ã—ã¦ã„ã¾ã™ã€‚iscsi_target ãŒã‚りã¾ã›ã‚“ "
#: ../nova/volume/driver.py:347
#, python-format
@@ -2255,41 +2236,37 @@ msgstr "å½ã®ISCSI: %s"
#: ../nova/volume/driver.py:359
#, python-format
msgid "rbd has no pool %s"
-msgstr ""
+msgstr "rbd ã«ãƒ—ール %s ãŒã‚りã¾ã›ã‚“。"
#: ../nova/volume/driver.py:414
#, python-format
msgid "Sheepdog is not working: %s"
-msgstr ""
+msgstr "Sheepdog ãŒå‹•作ã—ã¦ã„ã¾ã›ã‚“: %s"
#: ../nova/volume/driver.py:416
msgid "Sheepdog is not working"
-msgstr ""
+msgstr "Sheepdog ãŒæ©Ÿèƒ½ã—ã¦ã„ã¾ã›ã‚“"
#: ../nova/wsgi.py:68
#, python-format
msgid "Starting %(arg0)s on %(host)s:%(port)s"
-msgstr ""
+msgstr "%(host)s:%(port)s 上㧠%(arg0)s ã‚’é–‹å§‹ã—ã¦ã„ã¾ã™"
#: ../nova/wsgi.py:147
msgid "You must implement __call__"
-msgstr ""
-
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
+msgstr "__call__ を実装ã—ãªã‘れã°ãªã‚Šã¾ã›ã‚“"
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
-msgstr ""
+msgstr "IP アドレスをリースã—ã¾ã—ãŸ"
#: ../bin/nova-dhcpbridge.py:73
msgid "Adopted old lease or got a change of mac/hostname"
-msgstr ""
+msgstr "以å‰ã®ãƒªãƒ¼ã‚¹ã‚’採用ã—ãŸã‹ã€MAC/ホストåã®å¤‰æ›´ã‚’å–å¾—ã—ã¾ã—ãŸ"
#: ../bin/nova-dhcpbridge.py:80
msgid "releasing ip"
-msgstr ""
+msgstr "IP アドレスを開放ã—ã¦ã„ã¾ã™"
#: ../bin/nova-dhcpbridge.py:123
#, python-format
@@ -2297,6 +2274,8 @@ msgid ""
"Called %(action)s for mac %(mac)s with ip %(ip)s and hostname %(hostname)s "
"on interface %(interface)s"
msgstr ""
+"インターフェース %(interface)s 上㫠IP アドレス %(ip)sã€ãƒ›ã‚¹ãƒˆå %(hostname)s ã‚’æŒã£ãŸ MAC アドレス "
+"%(mac)s 用㮠%(action)s を呼ã³å‡ºã—ã¾ã—ãŸ"
#: ../nova/virt/fake.py:239
#, python-format
@@ -2325,7 +2304,7 @@ msgstr "IP %s ãŒãƒªãƒ¼ã‚¹ã•れã¾ã—ãŸãŒé–¢é€£ä»˜ã‘られã¦ã„ã¾ã›ã‚“。
#: ../nova/network/manager.py:220
#, python-format
msgid "IP %(address)s leased to bad mac %(inst_addr)s vs %(mac)s"
-msgstr ""
+msgstr "IP アドレス %(address)s ãŒä¸æ­£ãª MAC アドレス %(inst_addr)s 対 %(mac)s ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã—ãŸ"
#: ../nova/network/manager.py:228
#, python-format
@@ -2335,7 +2314,7 @@ msgstr "æ—¢ã«å‰²å½“解除ã—ã¦ã„ã‚‹IP %s ãŒãƒªãƒ¼ã‚¹ã•れã¾ã—ãŸã€‚"
#: ../nova/network/manager.py:233
#, python-format
msgid "Releasing IP %s"
-msgstr ""
+msgstr "IP アドレス %s を開放ã—ã¦ã„ã¾ã™"
#: ../nova/network/manager.py:237
#, python-format
@@ -2345,7 +2324,7 @@ msgstr "割り当ã¦ã¦ã„ãªã„IP %s ãŒé–‹æ”¾ã•れã¾ã—ãŸã€‚"
#: ../nova/network/manager.py:241
#, python-format
msgid "IP %(address)s released from bad mac %(inst_addr)s vs %(mac)s"
-msgstr ""
+msgstr "䏿­£ãª MAC アドレス %(inst_addr)s 対 %(mac)s ã‹ã‚‰ IP アドレス %(address)s ãŒé–‹æ”¾ã•れã¾ã—ãŸ"
#: ../nova/network/manager.py:244
#, python-format
@@ -2356,7 +2335,7 @@ msgstr "リースã—ã¦ã„ãªã„IP %s ãŒé–‹æ”¾ã•れã¾ã—ãŸã€‚"
msgid ""
"The sum between the number of networks and the vlan start cannot be greater "
"than 4094"
-msgstr ""
+msgstr "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®æ•°ã¨VLANã®é–‹å§‹ç•ªå·ã®å’Œã¯ 4094 より大ããã§ãã¾ã›ã‚“。"
#: ../nova/virt/xenapi/volume_utils.py:57
#, python-format
@@ -2366,7 +2345,7 @@ msgstr "%s ã‚’ introduce ã—ã¾ã™â€¦"
#: ../nova/virt/xenapi/volume_utils.py:74
#, python-format
msgid "Introduced %(label)s as %(sr_ref)s."
-msgstr ""
+msgstr "%(sr_ref)s ã¨ã—㦠%(label)s ã‚’å°Žå…¥ã—ã¾ã—ãŸ"
#: ../nova/virt/xenapi/volume_utils.py:78
msgid "Unable to create Storage Repository"
@@ -2385,12 +2364,12 @@ msgstr "SR %s ã‚’forgetã—ã¾ã™ã€‚ "
#: ../nova/virt/xenapi/volume_utils.py:101
#, python-format
msgid "Ignoring exception %(exc)s when getting PBDs for %(sr_ref)s"
-msgstr ""
+msgstr "%(sr_ref)s 用ã®ç‰©ç†ãƒ–ロックデãƒã‚¤ã‚¹(PBD)å–得時ã«ä¾‹å¤– %(exc)s を無視ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/volume_utils.py:107
#, python-format
msgid "Ignoring exception %(exc)s when unplugging PBD %(pbd)s"
-msgstr ""
+msgstr "物ç†ãƒ–ロックデãƒã‚¤ã‚¹(PBD) %(pbd)s ã®å–ã‚Šå¤–ã—æ™‚ã«ä¾‹å¤– %(exc)s を無視ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/volume_utils.py:111
#, python-format
@@ -2400,7 +2379,7 @@ msgstr "SR %s ã®forgetãŒå®Œäº†ã€‚"
#: ../nova/virt/xenapi/volume_utils.py:113
#, python-format
msgid "Ignoring exception %(exc)s when forgetting SR %(sr_ref)s"
-msgstr ""
+msgstr "SR %(sr_ref)s ã®ç™»éŒ²å‰Šé™¤æ™‚ã«ä¾‹å¤– %(exc)s を無視ã—ã¦ã„ã¾ã™"
#: ../nova/virt/xenapi/volume_utils.py:123
#, python-format
@@ -2420,7 +2399,7 @@ msgstr "SR %s ã®VDIã‚’introduceã§ãã¾ã›ã‚“。"
#: ../nova/virt/xenapi/volume_utils.py:175
#, python-format
msgid "Unable to obtain target information %(device_path)s, %(mountpoint)s"
-msgstr ""
+msgstr "ターゲット情報 %(device_path)s, %(mountpoint)s ã‚’å–å¾—ã§ãã¾ã›ã‚“"
#: ../nova/virt/xenapi/volume_utils.py:197
#, python-format
@@ -2430,17 +2409,17 @@ msgstr "マウントãƒã‚¤ãƒ³ãƒˆã‚’変æ›ã§ãã¾ã›ã‚“。 %s"
#: ../nova/objectstore/image.py:262
#, python-format
msgid "Failed to decrypt private key: %s"
-msgstr ""
+msgstr "プライベートキーã®å¾©å·ã«å¤±æ•—ã—ã¾ã—ãŸ: %s"
#: ../nova/objectstore/image.py:269
#, python-format
msgid "Failed to decrypt initialization vector: %s"
-msgstr ""
+msgstr "åˆæœŸåŒ–ベクタã®å¾©å·ã«å¤±æ•—ã—ã¾ã—ãŸ: %s"
#: ../nova/objectstore/image.py:277
#, python-format
msgid "Failed to decrypt image file %(image_file)s: %(err)s"
-msgstr ""
+msgstr "イメージファイル %(image_file)s ã®å¾©å·ã«å¤±æ•—ã—ã¾ã—ãŸ: %(err)s"
#: ../nova/objectstore/handler.py:106
#, python-format
@@ -2483,32 +2462,32 @@ msgstr "Unauthorized attempt to delete bucket: ãƒã‚±ãƒƒãƒˆ %s ã«å¯¾ã™ã‚‹å‰Šé™
#: ../nova/objectstore/handler.py:273
#, python-format
msgid "Getting object: %(bname)s / %(nm)s"
-msgstr ""
+msgstr "オブジェクトをå–å¾—ã—ã¦ã„ã¾ã™: %(bname)s / %(nm)s"
#: ../nova/objectstore/handler.py:276
#, python-format
msgid "Unauthorized attempt to get object %(nm)s from bucket %(bname)s"
-msgstr ""
+msgstr "ãƒã‚±ãƒƒãƒˆ %(bname)s ã‹ã‚‰ã®ã‚ªãƒ–ジェクト %(nm)s å–å¾—ã¯è¨±å¯ã•れã¦ã„ã¾ã›ã‚“"
#: ../nova/objectstore/handler.py:296
#, python-format
msgid "Putting object: %(bname)s / %(nm)s"
-msgstr ""
+msgstr "オブジェクトをアップロードã—ã¦ã„ã¾ã™: %(bname)s / %(nm)s"
#: ../nova/objectstore/handler.py:299
#, python-format
msgid "Unauthorized attempt to upload object %(nm)s to bucket %(bname)s"
-msgstr ""
+msgstr "ãƒã‚±ãƒƒãƒˆ %(bname)s ã¸ã®ã‚ªãƒ–ジェクト %(nm)s ã®ã‚¢ãƒƒãƒ—ロードã¯è¨±å¯ã•れã¦ã„ã¾ã›ã‚“"
#: ../nova/objectstore/handler.py:318
#, python-format
msgid "Deleting object: %(bname)s / %(nm)s"
-msgstr ""
+msgstr "オブジェクトを削除ã—ã¦ã„ã¾ã™: %(bname)s / %(nm)s"
#: ../nova/objectstore/handler.py:322
#, python-format
msgid "Unauthorized attempt to delete object %(nm)s from bucket %(bname)s"
-msgstr ""
+msgstr "ãƒã‚±ãƒƒãƒˆ %(bname)s 上ã®ã‚ªãƒ–ジェクト %(nm)s ã®å‰Šé™¤ã¯è¨±å¯ã•れã¦ã„ã¾ã›ã‚“"
#: ../nova/objectstore/handler.py:396
#, python-format
@@ -2535,7 +2514,7 @@ msgstr "Not authorized to update attributes: イメージ %s ã®ã‚¢ãƒˆãƒªãƒ“ュã
#: ../nova/objectstore/handler.py:431
#, python-format
msgid "Toggling publicity flag of image %(image_id)s %(newstatus)r"
-msgstr ""
+msgstr "イメージ %(image_id)s %(newstatus)r ã®å…¬é–‹ãƒ•ラグを切り替ãˆã¦ã„ã¾ã™"
#. other attributes imply update
#: ../nova/objectstore/handler.py:436
@@ -2576,7 +2555,7 @@ msgstr "ユーザå (%s) をプロジェクトåã¨ã—ã¦ä½¿ç”¨ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:277
#, python-format
msgid "failed authorization: no project named %(pjid)s (user=%(uname)s)"
-msgstr ""
+msgstr "許å¯ã•れã¾ã›ã‚“: %(pjid)s ã¨ã„ã†åç§°ã®ãƒ—ロジェクトã¯ã‚りã¾ã›ã‚“ (ユーザ=%(uname)s)"
#: ../nova/auth/manager.py:279
#, python-format
@@ -2588,12 +2567,12 @@ msgstr "プロジェクト %s ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
msgid ""
"Failed authorization: user %(uname)s not admin and not member of project "
"%(pjname)s"
-msgstr ""
+msgstr "許å¯ã•れã¾ã›ã‚“: ユーザ %(uname)s ã¯ç®¡ç†è€…ã§ã‚‚プロジェクト %(pjname)s ã®ãƒ¡ãƒ³ãƒã§ã‚‚ã‚りã¾ã›ã‚“。"
#: ../nova/auth/manager.py:289
#, python-format
msgid "User %(uid)s is not a member of project %(pjid)s"
-msgstr ""
+msgstr "ユーザ %(uid)s ã¯ãƒ—ロジェクト %(pjid)s ã®ãƒ¡ãƒ³ãƒã§ã¯ã‚りã¾ã›ã‚“。"
#: ../nova/auth/manager.py:298 ../nova/auth/manager.py:309
#, python-format
@@ -2621,27 +2600,27 @@ msgstr "ロール %s ã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«ã§ã®ã¿ä½¿ç”¨å¯èƒ½ã§ã™ã€‚"
#: ../nova/auth/manager.py:420
#, python-format
msgid "Adding role %(role)s to user %(uid)s in project %(pid)s"
-msgstr ""
+msgstr "プロジェクト %(pid)s ã®ãƒ¦ãƒ¼ã‚¶ %(uid)s ã«ãƒ­ãƒ¼ãƒ« %(role)s を付与ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:423
#, python-format
msgid "Adding sitewide role %(role)s to user %(uid)s"
-msgstr ""
+msgstr "サイト共通ã®ãƒ­ãƒ¼ãƒ« %(role)s をユーザ %(uid)s ã«ä»˜ä¸Žã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:448
#, python-format
msgid "Removing role %(role)s from user %(uid)s on project %(pid)s"
-msgstr ""
+msgstr "プロジェクト %(pid)s ã®ãƒ¦ãƒ¼ã‚¶ %(uid)s ã‹ã‚‰ãƒ­ãƒ¼ãƒ« %(role)s を削除ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:451
#, python-format
msgid "Removing sitewide role %(role)s from user %(uid)s"
-msgstr ""
+msgstr "ユーザ %(uid)s ã‹ã‚‰ã‚µã‚¤ãƒˆå…±é€šã®ãƒ­ãƒ¼ãƒ« %(role)s を削除ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:515
#, python-format
msgid "Created project %(name)s with manager %(manager_user)s"
-msgstr ""
+msgstr "プロジェクト %(name)s を管ç†è€… %(manager_user)s ã§ä½œæˆã—ã¾ã—ãŸã€‚"
#: ../nova/auth/manager.py:533
#, python-format
@@ -2651,12 +2630,12 @@ msgstr "modifying project: プロジェクト %s ã‚’æ›´æ–°ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:545
#, python-format
msgid "Adding user %(uid)s to project %(pid)s"
-msgstr ""
+msgstr "ユーザ %(uid)s をプロジェクト %(pid)s ã«è¿½åŠ ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:566
#, python-format
msgid "Remove user %(uid)s from project %(pid)s"
-msgstr ""
+msgstr "ユーザ %(uid)s をプロジェクト %(pid)s ã‹ã‚‰å‰Šé™¤ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:592
#, python-format
@@ -2666,7 +2645,7 @@ msgstr "Deleting project: プロジェクト %s を削除ã—ã¾ã™ã€‚"
#: ../nova/auth/manager.py:650
#, python-format
msgid "Created user %(rvname)s (admin: %(rvadmin)r)"
-msgstr ""
+msgstr "ユーザ %(rvname)s を作æˆã—ã¾ã—ãŸã€‚(管ç†è€…: %(rvadmin)r)"
#: ../nova/auth/manager.py:659
#, python-format
@@ -2686,7 +2665,7 @@ msgstr "Secret Key change: ユーザ %s ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆã‚­ãƒ¼ã‚’æ›´æ–°ã—ã
#: ../nova/auth/manager.py:673
#, python-format
msgid "Admin status set to %(admin)r for user %(uid)s"
-msgstr ""
+msgstr "ユーザ %(uid)s ã«å¯¾ã—ã¦ç®¡ç†è€…状態㌠%(admin)r ã«è¨­å®šã•れã¾ã—ãŸã€‚"
#: ../nova/auth/manager.py:722
#, python-format
@@ -2696,7 +2675,7 @@ msgstr "プロジェクト %s ã«é–¢ã™ã‚‹vpnデータãŒã‚りã¾ã›ã‚“。"
#: ../nova/service.py:161
#, python-format
msgid "Starting %(topic)s node (version %(vcs_string)s)"
-msgstr ""
+msgstr "%(topic)s ノードを開始ã—ã¦ã„ã¾ã™ (ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %(vcs_string)s)"
#: ../nova/service.py:174
msgid "Service killed that has no database entry"
@@ -2717,7 +2696,7 @@ msgstr "モデルサーãƒãŒæ¶ˆæ»…ã—ã¾ã—ãŸã€‚"
#: ../nova/auth/ldapdriver.py:174
#, python-format
msgid "LDAP user %s already exists"
-msgstr ""
+msgstr "LDAPユーザ %s ã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™ã€‚"
#: ../nova/auth/ldapdriver.py:205
#, python-format
@@ -2727,48 +2706,48 @@ msgstr "LDAPオブジェクト %s ãŒå­˜åœ¨ã—ã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:348
#, python-format
msgid "User %s doesn't exist"
-msgstr ""
+msgstr "ユーザ %s ã¯å­˜åœ¨ã—ã¾ã›ã‚“"
#: ../nova/auth/ldapdriver.py:472
#, python-format
msgid "Group can't be created because group %s already exists"
-msgstr ""
+msgstr "グループ %s ã¯æ—¢ã«å­˜åœ¨ã™ã‚‹ãŸã‚ã€ä½œæˆã§ãã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:478
#, python-format
msgid "Group can't be created because user %s doesn't exist"
-msgstr ""
+msgstr "ユーザ %s ã¯å­˜åœ¨ã—ãªã„ãŸã‚ã€ã‚°ãƒ«ãƒ¼ãƒ—ã®ä½œæˆã¯ã§ãã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:495
#, python-format
msgid "User %s can't be searched in group because the user doesn't exist"
-msgstr ""
+msgstr "ユーザ %s ã¯å­˜åœ¨ã—ãªã„ãŸã‚ã€ã‚°ãƒ«ãƒ¼ãƒ—å†…ã§æ¤œç´¢ã§ãã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:507
#, python-format
msgid "User %s can't be added to the group because the user doesn't exist"
-msgstr ""
+msgstr "ユーザ %s ã¯å­˜åœ¨ã—ãªã„ãŸã‚ã€å½“該グループã«è¿½åŠ ã§ãã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
#, python-format
msgid "The group at dn %s doesn't exist"
-msgstr ""
+msgstr "識別å(DN) %s ã®ã‚°ãƒ«ãƒ¼ãƒ—ã¯å­˜åœ¨ã—ã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:513
#, python-format
msgid "User %(uid)s is already a member of the group %(group_dn)s"
-msgstr ""
+msgstr "ユーザ %(uid)s ã¯ã™ã§ã«ã‚°ãƒ«ãƒ¼ãƒ— %(group_dn)s ã®ãƒ¡ãƒ³ãƒã§ã™ã€‚"
#: ../nova/auth/ldapdriver.py:524
#, python-format
msgid ""
"User %s can't be removed from the group because the user doesn't exist"
-msgstr ""
+msgstr "ユーザ %s ã¯å­˜åœ¨ã—ãªã„ãŸã‚ã€å½“該グループã‹ã‚‰å‰Šé™¤ã§ãã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:528
#, python-format
msgid "User %s is not a member of the group"
-msgstr ""
+msgstr "ユーザ %s ã¯å½“該グループã®ãƒ¡ãƒ³ãƒã§ã¯ã‚りã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:542
#, python-format
@@ -2780,7 +2759,7 @@ msgstr "ã‚°ãƒ«ãƒ¼ãƒ—ã®æœ€å¾Œã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’削除ã—よã†ã¨ã—ã¾ã—ãŸã€‚
#: ../nova/auth/ldapdriver.py:549
#, python-format
msgid "User %s can't be removed from all because the user doesn't exist"
-msgstr ""
+msgstr "ユーザ %s ã¯å­˜åœ¨ã—ãªã„ãŸã‚ã€å…¨ãƒ­ãƒ¼ãƒ«ã‹ã‚‰ã®å‰Šé™¤ã¯ã§ãã¾ã›ã‚“。"
#: ../nova/auth/ldapdriver.py:564
#, python-format
@@ -2810,22 +2789,22 @@ msgstr "Deleting user: ユーザ %s を削除ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:127
#, python-format
msgid "Adding role %(role)s to user %(user)s for project %(project)s"
-msgstr ""
+msgstr "プロジェクト %(project)s ã®ãƒ¦ãƒ¼ã‚¶ %(user)s ã«ãƒ­ãƒ¼ãƒ« %(role)s を付与ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:131
#, python-format
msgid "Adding sitewide role %(role)s to user %(user)s"
-msgstr ""
+msgstr "ユーザ %(user)s ã«ã‚µã‚¤ãƒˆå…±é€šãªãƒ­ãƒ¼ãƒ« %(role)s を追加中"
#: ../nova/api/ec2/admin.py:137
#, python-format
msgid "Removing role %(role)s from user %(user)s for project %(project)s"
-msgstr ""
+msgstr "プロジェクト %(project)s ã®ãƒ¦ãƒ¼ã‚¶ %(user)s ã‹ã‚‰ãƒ­ãƒ¼ãƒ« %(role)s を削除ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:141
#, python-format
msgid "Removing sitewide role %(role)s from user %(user)s"
-msgstr ""
+msgstr "ユーザ %(user)s ã‹ã‚‰ã‚µã‚¤ãƒˆå…±é€šãªãƒ­ãƒ¼ãƒ« %(role)s を削除中"
#: ../nova/api/ec2/admin.py:146 ../nova/api/ec2/admin.py:223
msgid "operation must be add or remove"
@@ -2834,17 +2813,17 @@ msgstr "operation 㯠add ã¾ãŸã¯ remove ã®ä½•れã‹ã§ã‚ã‚‹å¿…è¦ãŒã‚りã
#: ../nova/api/ec2/admin.py:159
#, python-format
msgid "Getting x509 for user: %(name)s on project: %(project)s"
-msgstr ""
+msgstr "プロジェクト %(project)s ã®ãƒ¦ãƒ¼ã‚¶ %(name)s ã® x509 証明書をå–å¾—ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:177
#, python-format
msgid "Create project %(name)s managed by %(manager_user)s"
-msgstr ""
+msgstr "管ç†è€… %(manager_user)s ã«ã‚ˆã£ã¦ç®¡ç†ã•れるプロジェクト %(name)s を作æˆã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:190
#, python-format
msgid "Modify project: %(name)s managed by %(manager_user)s"
-msgstr ""
+msgstr "管ç†è€… %(manager_user)s ã«ã‚ˆã£ã¦ç®¡ç†ã•れるプロジェクト %(name)s を変更ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:200
#, python-format
@@ -2854,12 +2833,12 @@ msgstr "Delete project: プロジェクト %s を削除ã—ã¾ã—ãŸã€‚"
#: ../nova/api/ec2/admin.py:214
#, python-format
msgid "Adding user %(user)s to project %(project)s"
-msgstr ""
+msgstr "ユーザ %(user)s をプロジェクト %(project)s ã«è¿½åŠ ã—ã¾ã™ã€‚"
#: ../nova/api/ec2/admin.py:218
#, python-format
msgid "Removing user %(user)s from project %(project)s"
-msgstr ""
+msgstr "ユーザ %(user)s をプロジェクト %(project)s ã‹ã‚‰å‰Šé™¤ã—ã¾ã™ã€‚"
#, python-format
#~ msgid ""
diff --git a/po/nova.pot b/po/nova.pot
index 58140302d..e180ed750 100644
--- a/po/nova.pot
+++ b/po/nova.pot
@@ -125,33 +125,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr ""
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr ""
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr ""
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr ""
-
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
#: ../nova/api/ec2/__init__.py:317
@@ -1778,34 +1751,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2263,10 +2208,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/pt_BR.po b/po/pt_BR.po
index 887c32597..b3aefce44 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -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
@@ -126,34 +126,6 @@ msgstr "compute.api::suspend %s"
msgid "compute.api::resume %s"
msgstr "compute.api::resume %s"
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr "Número errado de argumentos."
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-"Arquivo do id do processo (pidfile) %s não existe. O Daemon está parado?\n"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr "Processo inexistente"
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr "Servindo %s"
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr "Conjunto completo de FLAGS:"
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %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
#: ../nova/api/ec2/__init__.py:317
@@ -1804,34 +1776,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2290,10 +2234,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/ru.po b/po/ru.po
index bbfcfb19f..1bf672fc3 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -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
@@ -125,33 +125,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr "Ðеверное чиÑло аргументов."
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr "pidfile %s не обнаружен. Демон не запущен?\n"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr ""
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr ""
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "ЗапуÑкаетÑÑ %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
#: ../nova/api/ec2/__init__.py:317
@@ -1779,34 +1752,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr "обновление %s..."
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr "Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° во Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ"
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2264,10 +2209,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/tl.po b/po/tl.po
new file mode 100644
index 000000000..1ae59330b
--- /dev/null
+++ b/po/tl.po
@@ -0,0 +1,2796 @@
+# Tagalog translation for nova
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the nova package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+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-02-17 03:24+0000\n"
+"Last-Translator: John Michael Baterna <Unknown>\n"
+"Language-Team: Tagalog <tl@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-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 ""
+
+#: ../nova/exception.py:33
+msgid "Unexpected error while running command."
+msgstr "Merong hindi-inaasahang pagkakamali habang tumatakbo ang command."
+
+#: ../nova/exception.py:36
+#, python-format
+msgid ""
+"%(description)s\n"
+"Command: %(cmd)s\n"
+"Exit code: %(exit_code)s\n"
+"Stdout: %(stdout)r\n"
+"Stderr: %(stderr)r"
+msgstr ""
+
+#: ../nova/exception.py:107
+msgid "DB exception wrapped"
+msgstr ""
+
+#. exc_type, exc_value, exc_traceback = sys.exc_info()
+#: ../nova/exception.py:120
+msgid "Uncaught exception"
+msgstr ""
+
+#: ../nova/volume/api.py:45
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
+msgstr ""
+
+#: ../nova/volume/api.py:47
+#, python-format
+msgid "Volume quota exceeded. You cannot create a volume of size %sG"
+msgstr ""
+
+#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
+msgid "Volume status must be available"
+msgstr ""
+
+#: ../nova/volume/api.py:98
+msgid "Volume is already attached"
+msgstr ""
+
+#: ../nova/volume/api.py:104
+msgid "Volume is already detached"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:72
+msgid "Failed to read private ip"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:79
+msgid "Failed to read public ip(s)"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:152
+#, python-format
+msgid "%(param)s property not found for image %(_image_id)s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:168
+msgid "No keypairs defined"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:238
+#, python-format
+msgid "Compute.api::lock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:253
+#, python-format
+msgid "Compute.api::unlock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:267
+#, python-format
+msgid "Compute.api::get_lock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:281
+#, python-format
+msgid "Compute.api::reset_network %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:292
+#, python-format
+msgid "Compute.api::pause %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:303
+#, python-format
+msgid "Compute.api::unpause %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:314
+#, python-format
+msgid "compute.api::suspend %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:325
+#, python-format
+msgid "compute.api::resume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
+#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
+#: ../nova/api/ec2/__init__.py:317
+#, python-format
+msgid "Instance %s not found"
+msgstr ""
+
+#. NOTE: No Resource Pool concept so far
+#: ../nova/virt/xenapi/volumeops.py:51
+#, python-format
+msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:69
+#, python-format
+msgid "Unable to create VDI on SR %(sr_ref)s for instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:80
+#, python-format
+msgid "Unable to use SR %(sr_ref)s for instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:91
+#, python-format
+msgid "Unable to attach volume to instance %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:93
+#, python-format
+msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
+msgstr ""
+
+#. Detach VBD from VM
+#: ../nova/virt/xenapi/volumeops.py:104
+#, python-format
+msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:112
+#, python-format
+msgid "Unable to locate volume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:120
+#, python-format
+msgid "Unable to detach volume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:127
+#, python-format
+msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/compute/instance_types.py:41
+#, python-format
+msgid "Unknown instance type: %s"
+msgstr ""
+
+#: ../nova/crypto.py:46
+msgid "Filename of root CA"
+msgstr ""
+
+#: ../nova/crypto.py:49
+msgid "Filename of private key"
+msgstr ""
+
+#: ../nova/crypto.py:51
+msgid "Filename of root Certificate Revokation List"
+msgstr ""
+
+#: ../nova/crypto.py:53
+msgid "Where we keep our keys"
+msgstr ""
+
+#: ../nova/crypto.py:55
+msgid "Where we keep our root CA"
+msgstr ""
+
+#: ../nova/crypto.py:57
+msgid "Should we use a CA for each project?"
+msgstr "Kailangan bang gumamit ng CA bawat proyekto?"
+
+#: ../nova/crypto.py:61
+#, python-format
+msgid "Subject for certificate for users, %s for project, user, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:66
+#, python-format
+msgid "Subject for certificate for projects, %s for project, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:71
+#, python-format
+msgid "Subject for certificate for vpns, %s for project, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:258
+#, python-format
+msgid "Flags path: %s"
+msgstr ""
+
+#: ../nova/scheduler/manager.py:69
+#, python-format
+msgid "Casting to %(topic)s %(host)s for %(method)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:78
+#, python-format
+msgid "check_instance_lock: decorating: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:80
+#, python-format
+msgid ""
+"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:84
+#, python-format
+msgid "check_instance_lock: locked: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:86
+#, python-format
+msgid "check_instance_lock: admin: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:91
+#, python-format
+msgid "check_instance_lock: executing: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:95
+#, python-format
+msgid "check_instance_lock: not executing |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:179
+msgid "Instance has already been created"
+msgstr ""
+
+#: ../nova/compute/manager.py:180
+#, python-format
+msgid "instance %s: starting..."
+msgstr ""
+
+#. pylint: disable=W0702
+#: ../nova/compute/manager.py:219
+#, python-format
+msgid "instance %s: Failed to spawn"
+msgstr ""
+
+#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
+#, python-format
+msgid "Terminating instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:255
+#, python-format
+msgid "Deallocating address %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:268
+#, python-format
+msgid "trying to destroy already destroyed instance: %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:282
+#, python-format
+msgid "Rebooting instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:287
+#, python-format
+msgid ""
+"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:311
+#, python-format
+msgid "instance %s: snapshotting"
+msgstr ""
+
+#: ../nova/compute/manager.py:316
+#, python-format
+msgid ""
+"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:332
+#, python-format
+msgid ""
+"trying to reset the password on a non-running instance: %(instance_id)s "
+"(state: %(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:335
+#, python-format
+msgid "instance %s: setting admin password"
+msgstr ""
+
+#: ../nova/compute/manager.py:353
+#, python-format
+msgid ""
+"trying to inject a file into a non-running instance: %(instance_id)s (state: "
+"%(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:362
+#, python-format
+msgid "instance %(nm)s: injecting file to %(plain_path)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:372
+#, python-format
+msgid "instance %s: rescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:387
+#, python-format
+msgid "instance %s: unrescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:406
+#, python-format
+msgid "instance %s: pausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:423
+#, python-format
+msgid "instance %s: unpausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:440
+#, python-format
+msgid "instance %s: retrieving diagnostics"
+msgstr ""
+
+#: ../nova/compute/manager.py:453
+#, python-format
+msgid "instance %s: suspending"
+msgstr ""
+
+#: ../nova/compute/manager.py:472
+#, python-format
+msgid "instance %s: resuming"
+msgstr ""
+
+#: ../nova/compute/manager.py:491
+#, python-format
+msgid "instance %s: locking"
+msgstr ""
+
+#: ../nova/compute/manager.py:503
+#, python-format
+msgid "instance %s: unlocking"
+msgstr ""
+
+#: ../nova/compute/manager.py:513
+#, python-format
+msgid "instance %s: getting locked state"
+msgstr ""
+
+#: ../nova/compute/manager.py:526
+#, python-format
+msgid "instance %s: reset network"
+msgstr ""
+
+#: ../nova/compute/manager.py:535 ../nova/api/ec2/cloud.py:515
+#, python-format
+msgid "Get console output for instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:543
+#, python-format
+msgid "instance %s: getting ajax console"
+msgstr ""
+
+#: ../nova/compute/manager.py:553
+#, python-format
+msgid ""
+"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
+msgstr ""
+
+#. pylint: disable=W0702
+#. NOTE(vish): The inline callback eats the exception info so we
+#. log the traceback here and reraise the same
+#. ecxception below.
+#: ../nova/compute/manager.py:569
+#, python-format
+msgid "instance %(instance_id)s: attach failed %(mountpoint)s, removing"
+msgstr ""
+
+#: ../nova/compute/manager.py:585
+#, python-format
+msgid ""
+"Detach volume %(volume_id)s from mountpoint %(mp)s on instance "
+"%(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:588
+#, python-format
+msgid "Detaching volume from unknown instance %s"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:53
+#, python-format
+msgid "Host %s is not alive"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:65
+msgid "All hosts have too many cores"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:87
+#, python-format
+msgid "Host %s not available"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:99
+msgid "All hosts have too many gigabytes"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:119
+msgid "All hosts have too many networks"
+msgstr ""
+
+#: ../nova/volume/manager.py:85
+#, python-format
+msgid "Re-exporting %s volumes"
+msgstr ""
+
+#: ../nova/volume/manager.py:90
+#, python-format
+msgid "volume %s: skipping export"
+msgstr ""
+
+#: ../nova/volume/manager.py:96
+#, python-format
+msgid "volume %s: creating"
+msgstr ""
+
+#: ../nova/volume/manager.py:108
+#, python-format
+msgid "volume %(vol_name)s: creating lv of size %(vol_size)sG"
+msgstr ""
+
+#: ../nova/volume/manager.py:112
+#, python-format
+msgid "volume %s: creating export"
+msgstr ""
+
+#: ../nova/volume/manager.py:123
+#, python-format
+msgid "volume %s: created successfully"
+msgstr ""
+
+#: ../nova/volume/manager.py:131
+msgid "Volume is still attached"
+msgstr ""
+
+#: ../nova/volume/manager.py:133
+msgid "Volume is not local to this node"
+msgstr ""
+
+#: ../nova/volume/manager.py:136
+#, python-format
+msgid "volume %s: removing export"
+msgstr ""
+
+#: ../nova/volume/manager.py:138
+#, python-format
+msgid "volume %s: deleting"
+msgstr ""
+
+#: ../nova/volume/manager.py:147
+#, python-format
+msgid "volume %s: deleted successfully"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:74
+#, python-format
+msgid "%(text)s: _db_content => %(content)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:304 ../nova/virt/xenapi/fake.py:404
+#: ../nova/virt/xenapi/fake.py:422 ../nova/virt/xenapi/fake.py:478
+msgid "Raising NotImplemented"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:306
+#, python-format
+msgid "xenapi.fake does not have an implementation for %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:341
+#, python-format
+msgid "Calling %(localname)s %(impl)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:346
+#, python-format
+msgid "Calling getter %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:406
+#, python-format
+msgid ""
+"xenapi.fake does not have an implementation for %s or it has been called "
+"with the wrong number of arguments"
+msgstr ""
+
+#: ../nova/tests/test_cloud.py:256
+msgid "Can't test instances without a real virtual env."
+msgstr ""
+
+#: ../nova/tests/test_cloud.py:268
+#, python-format
+msgid "Need to watch instance %s until it's running..."
+msgstr ""
+
+#: ../nova/virt/connection.py:73
+msgid "Failed to open connection to the hypervisor"
+msgstr ""
+
+#: ../nova/network/linux_net.py:187
+#, python-format
+msgid "Starting VLAN inteface %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:208
+#, python-format
+msgid "Starting Bridge interface for %s"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:314
+#, python-format
+msgid "Hupping dnsmasq threw %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:316
+#, python-format
+msgid "Pid %d is stale, relaunching dnsmasq"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:358
+#, python-format
+msgid "killing radvd threw %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:360
+#, python-format
+msgid "Pid %d is stale, relaunching radvd"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:449
+#, python-format
+msgid "Killing dnsmasq threw %s"
+msgstr ""
+
+#: ../nova/utils.py:58
+#, python-format
+msgid "Inner Exception: %s"
+msgstr ""
+
+#: ../nova/utils.py:59
+#, python-format
+msgid "Class %s cannot be found"
+msgstr ""
+
+#: ../nova/utils.py:118
+#, python-format
+msgid "Fetching %s"
+msgstr ""
+
+#: ../nova/utils.py:130
+#, python-format
+msgid "Running cmd (subprocess): %s"
+msgstr ""
+
+#: ../nova/utils.py:143 ../nova/utils.py:183
+#, python-format
+msgid "Result was %s"
+msgstr ""
+
+#: ../nova/utils.py:159
+#, python-format
+msgid "Running cmd (SSH): %s"
+msgstr ""
+
+#: ../nova/utils.py:217
+#, python-format
+msgid "debug in callback: %s"
+msgstr ""
+
+#: ../nova/utils.py:222
+#, python-format
+msgid "Running %s"
+msgstr ""
+
+#: ../nova/utils.py:262
+#, python-format
+msgid "Link Local address is not found.:%s"
+msgstr ""
+
+#: ../nova/utils.py:265
+#, python-format
+msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
+msgstr ""
+
+#: ../nova/utils.py:363
+#, python-format
+msgid "Invalid backend: %s"
+msgstr ""
+
+#: ../nova/utils.py:374
+#, python-format
+msgid "backend %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:49
+#, python-format
+msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:54
+#, python-format
+msgid "Publishing to route %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:84
+#, python-format
+msgid "Declaring queue %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:90
+#, python-format
+msgid "Declaring exchange %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:96
+#, python-format
+msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:121
+#, python-format
+msgid "Getting from %(queue)s: %(message)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
+#, python-format
+msgid "Created VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:138
+#, python-format
+msgid "Created VM %(instance_name)s as %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:168
+#, python-format
+msgid "Creating VBD for VM %(vm_ref)s, VDI %(vdi_ref)s ... "
+msgstr ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:187
+#, python-format
+msgid "VBD not found in instance %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:197
+#, python-format
+msgid "Unable to unplug VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:209
+#, python-format
+msgid "Unable to destroy VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:224
+#, python-format
+msgid "Creating VIF for VM %(vm_ref)s, network %(network_ref)s."
+msgstr ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:246
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(sr_ref)s."
+msgstr ""
+
+#. 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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:272
+#, python-format
+msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:286
+#, python-format
+msgid "Asking xapi to upload %(vdi_uuids)s as ID %(image_id)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:327
+#, python-format
+msgid "Size for image %(image)s:%(virtual_size)d"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:332
+#, python-format
+msgid "Glance image %s"
+msgstr ""
+
+#. 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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:352
+#, python-format
+msgid "Kernel/Ramdisk VDI %s destroyed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:361
+#, python-format
+msgid "Asking xapi to fetch %(url)s as %(access)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
+#, python-format
+msgid "Looking up vdi %s for PV kernel"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:397
+#, python-format
+msgid "PV Kernel in VDI:%s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:405
+#, python-format
+msgid "Running pygrub against %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:411
+#, python-format
+msgid "Found Xen kernel %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:413
+msgid "No Xen kernel found. Booting HVM."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
+#, python-format
+msgid "duplicate name found: %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:442
+#, python-format
+msgid "VDI %s is still available"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:463
+#, python-format
+msgid "(VM_UTILS) xenserver vm state -> |%s|"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:465
+#, python-format
+msgid "(VM_UTILS) xenapi power_state -> |%s|"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:525
+#, python-format
+msgid "VHD %(vdi_uuid)s has parent %(parent_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:542
+#, python-format
+msgid "Re-scanning SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:567
+#, python-format
+msgid ""
+"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:574
+#, python-format
+msgid ""
+"Parent %(parent_uuid)s doesn't match original parent "
+"%(original_parent_uuid)s, waiting for coalesce..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:590
+#, python-format
+msgid "No VDIs found for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:594
+#, python-format
+msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
+msgstr ""
+
+#: ../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 ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:657
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
+#, python-format
+msgid "Plugging VBD %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:659
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:194
+#, python-format
+msgid "Plugging VBD %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:661
+#, python-format
+msgid "VBD %(vbd)s plugged as %(orig_dev)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:664
+#, python-format
+msgid "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:668
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:197
+#, python-format
+msgid "Destroying VBD for VDI %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:671
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:200
+#, python-format
+msgid "Destroying VBD for VDI %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:683
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:211
+msgid "VBD.unplug successful first time."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:688
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:216
+msgid "VBD.unplug rejected: retrying..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:692
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:220
+msgid "VBD.unplug successful eventually."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:695
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:223
+#, python-format
+msgid "Ignoring XenAPI.Failure in VBD.unplug: %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:704
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:66
+#, python-format
+msgid "Ignoring XenAPI.Failure %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:735
+#, python-format
+msgid ""
+"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:747
+#, python-format
+msgid "Writing partition table %s done."
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:89
+#, python-format
+msgid "Nested received %(queue)s, %(value)s"
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:95
+#, python-format
+msgid "Nested return %s"
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:120 ../nova/tests/test_rpc.py:126
+#, python-format
+msgid "Received %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:44
+msgid "Use of empty request context is deprecated"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:133
+#, python-format
+msgid "No service for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:251
+#, python-format
+msgid "No service for %(host)s, %(binary)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:592
+msgid "No fixed ips defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:608
+#, python-format
+msgid "No floating ip for address %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:629
+#, python-format
+msgid "No address for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:961
+#, python-format
+msgid "no keypair for user %(user_id)s, name %(name)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1076 ../nova/db/sqlalchemy/api.py:1156
+#, python-format
+msgid "No network for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1086
+msgid "No networks defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1115
+#, python-format
+msgid "No network for bridge %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1129 ../nova/db/sqlalchemy/api.py:1142
+#, python-format
+msgid "No network for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1277
+#, python-format
+msgid "Token %s does not exist"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1302
+#, python-format
+msgid "No quota for project_id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1455 ../nova/db/sqlalchemy/api.py:1501
+#: ../nova/api/ec2/__init__.py:323
+#, python-format
+msgid "Volume %s not found"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1514
+#, python-format
+msgid "No export device found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1527
+#, python-format
+msgid "No target id found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1572
+#, python-format
+msgid "No security group with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1589
+#, python-format
+msgid "No security group named %(group_name)s for project: %(project_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1682
+#, python-format
+msgid "No secuity group rule with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1756
+#, python-format
+msgid "No user for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1772
+#, python-format
+msgid "No user for access key %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1834
+#, python-format
+msgid "No project with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1979
+#, python-format
+msgid "No console pool with id %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1996
+#, python-format
+msgid ""
+"No console pool of type %(console_type)s for compute host %(compute_host)s "
+"on proxy host %(host)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2035
+#, python-format
+msgid "No console for instance %(instance_id)s in pool %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2057
+#, python-format
+msgid "on instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2058
+#, python-format
+msgid "No console with id %(console_id)s %(idesc)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2078 ../nova/db/sqlalchemy/api.py:2097
+#, python-format
+msgid "No zone with id %(zone_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:160
+#, python-format
+msgid "Checking state of %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:165
+#, python-format
+msgid "Current state of %(name)s was %(state)s."
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:183
+#, python-format
+msgid "Connecting to libvirt: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:196
+msgid "Connection to libvirt broke"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:258
+#, python-format
+msgid "instance %(instance_name)s: deleting instance files %(target)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:283
+#, python-format
+msgid "Invalid device path %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:313
+#, python-format
+msgid "No disk at %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:320
+msgid "Instance snapshotting is not supported for libvirtat this time"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:336
+#, python-format
+msgid "instance %s: rebooted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:339
+#, python-format
+msgid "_wait_for_reboot failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:382
+#, python-format
+msgid "instance %s: rescued"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:385
+#, python-format
+msgid "_wait_for_rescue failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:411
+#, python-format
+msgid "instance %s: is running"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:422
+#, python-format
+msgid "instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:425 ../nova/virt/xenapi/vmops.py:186
+#, python-format
+msgid "instance %s: failed to boot"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:436
+#, python-format
+msgid "virsh said: %r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:440
+msgid "cool, it's a device"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:448
+#, python-format
+msgid "data: %(data)r, fpath: %(fpath)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:456
+#, python-format
+msgid "Contents of file %(fpath)s: %(contents)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:489
+msgid "Unable to find an open port"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:563
+#, python-format
+msgid "instance %s: Creating image"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:646
+#, python-format
+msgid "instance %(inst_name)s: injecting key into image %(img_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:649
+#, python-format
+msgid "instance %(inst_name)s: injecting net into image %(img_id)s"
+msgstr ""
+
+#. This could be a windows image, or a vmdk format disk
+#: ../nova/virt/libvirt_conn.py:657
+#, python-format
+msgid ""
+"instance %(inst_name)s: ignoring error injecting data into image %(img_id)s "
+"(%(e)s)"
+msgstr ""
+
+#. TODO(termie): cache?
+#: ../nova/virt/libvirt_conn.py:665
+#, python-format
+msgid "instance %s: starting toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:732
+#, python-format
+msgid "instance %s: finished toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:751
+msgid "diagnostics are not supported for libvirt"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:1225
+#, python-format
+msgid "Attempted to unfilter instance %s which is not filtered"
+msgstr ""
+
+#: ../nova/api/ec2/metadatarequesthandler.py:76
+#, python-format
+msgid "Failed to get metadata for ip: %s"
+msgstr ""
+
+#: ../nova/auth/fakeldap.py:33
+msgid "Attempted to instantiate singleton"
+msgstr ""
+
+#: ../nova/network/api.py:39
+#, python-format
+msgid "Quota exceeeded for %s, tried to allocate address"
+msgstr ""
+
+#: ../nova/network/api.py:42
+msgid "Address quota exceeded. You cannot allocate any more addresses"
+msgstr ""
+
+#: ../nova/tests/test_volume.py:162
+#, python-format
+msgid "Target %s allocated"
+msgstr ""
+
+#: ../nova/virt/images.py:70
+#, python-format
+msgid "Finished retreving %(url)s -- placed in %(path)s"
+msgstr ""
+
+#: ../nova/scheduler/driver.py:66
+msgid "Must implement a fallback schedule"
+msgstr ""
+
+#: ../nova/console/manager.py:70
+msgid "Adding console"
+msgstr ""
+
+#: ../nova/console/manager.py:90
+#, python-format
+msgid "Tried to remove non-existant console %(console_id)s."
+msgstr ""
+
+#: ../nova/api/direct.py:149
+msgid "not available"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:62
+#, python-format
+msgid "The key_pair %s already exists"
+msgstr ""
+
+#. TODO(vish): Do this with M2Crypto instead
+#: ../nova/api/ec2/cloud.py:118
+#, python-format
+msgid "Generating root CA: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:303
+#, python-format
+msgid "Create key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:311
+#, python-format
+msgid "Delete key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:386
+#, python-format
+msgid "%s is not a valid ipProtocol"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:390
+msgid "Invalid port range"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:421
+#, python-format
+msgid "Revoke security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:430 ../nova/api/ec2/cloud.py:459
+msgid "Not enough parameters to build a valid rule."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:443
+msgid "No rule for the specified parameters."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:450
+#, python-format
+msgid "Authorize security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:464
+#, python-format
+msgid "This rule already exists in group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:492
+#, python-format
+msgid "Create Security Group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:495
+#, python-format
+msgid "group %s already exists"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:507
+#, python-format
+msgid "Delete security group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:584
+#, python-format
+msgid "Create volume of %s GB"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:612
+#, python-format
+msgid "Attach volume %(volume_id)s to instance %(instance_id)s at %(device)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:629
+#, python-format
+msgid "Detach volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:761
+msgid "Allocate address"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:766
+#, python-format
+msgid "Release address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:771
+#, python-format
+msgid "Associate address %(public_ip)s to instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:780
+#, python-format
+msgid "Disassociate address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:807
+msgid "Going to start terminating instances"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:815
+#, python-format
+msgid "Reboot instance %r"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:867
+#, python-format
+msgid "De-registering image %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:875
+#, python-format
+msgid "Registered image %(image_location)s with id %(image_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:882 ../nova/api/ec2/cloud.py:900
+#, python-format
+msgid "attribute not supported: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:890
+#, python-format
+msgid "invalid id: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:903
+msgid "user or group not specified"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:905
+msgid "only group \"all\" is supported"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:907
+msgid "operation_type must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:908
+#, python-format
+msgid "Updating image %s publicity"
+msgstr ""
+
+#: ../bin/nova-api.py:52
+#, python-format
+msgid "Using paste.deploy config at: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:57
+#, python-format
+msgid "No paste configuration for app: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:59
+#, python-format
+msgid ""
+"App Config: %(api)s\n"
+"%(config)r"
+msgstr ""
+
+#: ../bin/nova-api.py:64
+#, python-format
+msgid "Running %s API"
+msgstr ""
+
+#: ../bin/nova-api.py:69
+#, python-format
+msgid "No known API applications configured in %s."
+msgstr ""
+
+#: ../bin/nova-api.py:83
+#, python-format
+msgid "Starting nova-api node (version %s)"
+msgstr ""
+
+#: ../bin/nova-api.py:89
+#, python-format
+msgid "No paste configuration found for: %s"
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:84
+#, python-format
+msgid "Argument %(key)s value %(value)s is too short."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:89
+#, python-format
+msgid "Argument %(key)s value %(value)s contains invalid characters."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:94
+#, python-format
+msgid "Argument %(key)s value %(value)s starts with a hyphen."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:102
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:130
+#, python-format
+msgid "Argument %s is required."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:117
+#, python-format
+msgid ""
+"Argument %(key)s may not take value %(value)s. Valid values are ['true', "
+"'false']."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:163
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) on %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:67
+#, python-format
+msgid "Attempted to create non-unique name %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:73
+#, python-format
+msgid "instance %(name)s: not enough free memory"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:148
+#, python-format
+msgid "Starting VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:151
+#, python-format
+msgid "Spawning VM %(instance_name)s created %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:162
+#, python-format
+msgid "Invalid value for onset_files: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:167
+#, python-format
+msgid "Injecting file path: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:180
+#, python-format
+msgid "Instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:232
+#, python-format
+msgid "Instance not present %s"
+msgstr ""
+
+#. TODO(sirp): Add quiesce and VSS locking support when Windows support
+#. is added
+#: ../nova/virt/xenapi/vmops.py:261
+#, python-format
+msgid "Starting snapshot for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:269
+#, python-format
+msgid "Unable to Snapshot %(vm_ref)s: %(exc)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:280
+#, python-format
+msgid "Finished snapshot and upload for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:356
+#, python-format
+msgid "VM %(vm)s already halted, skipping shutdown..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:389
+msgid "Removing kernel/ramdisk files"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:399
+msgid "kernel/ramdisk files removed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:561
+#, python-format
+msgid ""
+"TIMEOUT: The call to %(method)s timed out. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:564
+#, python-format
+msgid ""
+"NOT IMPLEMENTED: The call to %(method)s is not supported by the agent. VM "
+"id=%(instance_id)s; args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:569
+#, python-format
+msgid ""
+"The call to %(method)s returned an error: %(e)s. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:760
+#, python-format
+msgid "OpenSSL error: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:148
+#, python-format
+msgid "Running instances: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:154
+#, python-format
+msgid "After terminating instances: %s"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:45
+msgid "Template for script to run on cloudpipe instance boot"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:48
+msgid "Network to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:51
+msgid "Netmask to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:97
+#, python-format
+msgid "Launching VPN for %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/migration.py:35
+msgid "python-migrate is not installed. Exiting."
+msgstr ""
+
+#: ../nova/image/s3.py:99
+#, python-format
+msgid "Image %s could not be found"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:121
+msgid "Too many failed authentications."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:131
+#, python-format
+msgid ""
+"Access key %(access_key)s has had %(failures)d failed authentications and "
+"will be locked out for %(lock_mins)d minutes."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:169 ../nova/objectstore/handler.py:140
+#, python-format
+msgid "Authentication Failure: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:182
+#, python-format
+msgid "Authenticated Request For %(uname)s:%(pname)s)"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:207
+#, python-format
+msgid "action: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:209
+#, python-format
+msgid "arg: %(key)s\t\tval: %(value)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:281
+#, python-format
+msgid ""
+"Unauthorized request for controller=%(controller)s and action=%(action)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:314
+#, python-format
+msgid "InstanceNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:320
+#, python-format
+msgid "VolumeNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:326
+#, python-format
+msgid "NotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:329
+#, python-format
+msgid "ApiError raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:338
+#, python-format
+msgid "Unexpected error raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:343
+msgid "An unknown error has occurred. Please try your request again."
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:84
+#, python-format
+msgid "User %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:106 ../nova/auth/ldapdriver.py:232
+#, python-format
+msgid "Project can't be created because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:122 ../nova/auth/ldapdriver.py:243
+#, python-format
+msgid "Project can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:135 ../nova/auth/ldapdriver.py:229
+#, python-format
+msgid "Project can't be created because project %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:157 ../nova/auth/ldapdriver.py:268
+#, python-format
+msgid "Project can't be modified because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:245
+#, python-format
+msgid "User \"%s\" not found"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:248
+#, python-format
+msgid "Project \"%s\" not found"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:129
+msgid ""
+"Must specify xenapi_connection_url, xenapi_connection_username (optionally), "
+"and xenapi_connection_password to use connection_type=xenapi"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:311
+#, python-format
+msgid "Task [%(name)s] %(task)s status: success %(result)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:317
+#, python-format
+msgid "Task [%(name)s] %(task)s status: %(status)s %(error_info)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:331 ../nova/virt/xenapi_conn.py:344
+#, python-format
+msgid "Got exception: %s"
+msgstr ""
+
+#: ../nova/volume/san.py:67
+#, python-format
+msgid "Could not find iSCSI export for volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/apirequest.py:100
+#, python-format
+msgid ""
+"Unsupported API request: controller = %(controller)s, action = %(action)s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:55
+#, python-format
+msgid "Caught error: %s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:76
+msgid "Including admin operations in API."
+msgstr ""
+
+#: ../nova/console/xvp.py:99
+msgid "Rebuilding xvp conf"
+msgstr ""
+
+#: ../nova/console/xvp.py:116
+#, python-format
+msgid "Re-wrote %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:121
+msgid "Stopping xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:134
+msgid "Starting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:141
+#, python-format
+msgid "Error starting xvp: %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:144
+msgid "Restarting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:146
+msgid "xvp not running..."
+msgstr ""
+
+#: ../bin/nova-manage.py:272
+msgid ""
+"The above error may show that the database has not been created.\n"
+"Please create a database using nova-manage sync db before running this "
+"command."
+msgstr ""
+
+#: ../bin/nova-manage.py:426
+msgid ""
+"No more networks available. If this is a new installation, you need\n"
+"to call something like this:\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
+msgstr ""
+
+#: ../bin/nova-manage.py:431
+msgid ""
+"The above error may show that the certificate db has not been created.\n"
+"Please create a database by running a nova-api server on this host."
+msgstr ""
+
+#: ../bin/nova-manage.py:447 ../bin/nova-manage.py:536
+msgid "network"
+msgstr ""
+
+#: ../bin/nova-manage.py:448
+msgid "IP address"
+msgstr ""
+
+#: ../bin/nova-manage.py:449
+msgid "MAC address"
+msgstr ""
+
+#: ../bin/nova-manage.py:450
+msgid "hostname"
+msgstr ""
+
+#: ../bin/nova-manage.py:451
+msgid "host"
+msgstr ""
+
+#: ../bin/nova-manage.py:537
+msgid "netmask"
+msgstr ""
+
+#: ../bin/nova-manage.py:538
+msgid "start address"
+msgstr ""
+
+#: ../nova/virt/disk.py:69
+#, python-format
+msgid "Failed to load partition: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:91
+#, python-format
+msgid "Failed to mount filesystem: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:124
+#, python-format
+msgid "nbd device %s did not show up"
+msgstr ""
+
+#: ../nova/virt/disk.py:128
+#, python-format
+msgid "Could not attach image to loopback: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:151
+msgid "No free nbd devices"
+msgstr ""
+
+#: ../doc/ext/nova_todo.py:46
+#, python-format
+msgid "%(filename)s, line %(line_info)d"
+msgstr ""
+
+#. FIXME(chiradeep): implement this
+#: ../nova/virt/hyperv.py:118
+msgid "In init host"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:131
+#, python-format
+msgid "Attempt to create duplicate vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:148
+#, python-format
+msgid "Starting VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:150
+#, python-format
+msgid "Started VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:152
+#, python-format
+msgid "spawn vm failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:169
+#, python-format
+msgid "Failed to create VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:188
+#, python-format
+msgid "Set memory for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:198
+#, python-format
+msgid "Set vcpus for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:202
+#, python-format
+msgid "Creating disk for %(vm_name)s by attaching disk file %(vhdfile)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:227
+#, python-format
+msgid "Failed to add diskdrive to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:230
+#, python-format
+msgid "New disk drive path is %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:247
+#, python-format
+msgid "Failed to add vhd file to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:249
+#, python-format
+msgid "Created disk for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:253
+#, python-format
+msgid "Creating nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:272
+msgid "Failed creating a port on the external vswitch"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:273
+#, python-format
+msgid "Failed creating port for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:276
+#, python-format
+msgid "Created switch port %(vm_name)s on switch %(ext_path)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:286
+#, python-format
+msgid "Failed to add nic to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:288
+#, python-format
+msgid "Created nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:321
+#, python-format
+msgid "WMI job failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:325
+#, python-format
+msgid "WMI job succeeded: %(desc)s, Elapsed=%(elap)s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:361
+#, python-format
+msgid "Got request to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:386
+#, python-format
+msgid "Failed to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:393
+#, python-format
+msgid "Del: disk %(vhdfile)s vm %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:415
+#, python-format
+msgid ""
+"Got Info for vm %(instance_id)s: state=%(state)s, mem=%(memusage)s, "
+"num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:451
+#, python-format
+msgid "Successfully changed vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:454
+#, python-format
+msgid "Failed to change vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/compute/api.py:71
+#, python-format
+msgid "Instance %d was not found in get_network_topic"
+msgstr ""
+
+#: ../nova/compute/api.py:77
+#, python-format
+msgid "Instance %d has no host"
+msgstr ""
+
+#: ../nova/compute/api.py:97
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to run %(min_count)s instances"
+msgstr ""
+
+#: ../nova/compute/api.py:99
+#, python-format
+msgid ""
+"Instance quota exceeded. You can only run %s more instances of this type."
+msgstr ""
+
+#: ../nova/compute/api.py:112
+msgid "Creating a raw instance"
+msgstr ""
+
+#: ../nova/compute/api.py:160
+#, python-format
+msgid "Going to run %s instances..."
+msgstr ""
+
+#: ../nova/compute/api.py:187
+#, python-format
+msgid "Casting to scheduler for %(pid)s/%(uid)s's instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/api.py:292
+#, python-format
+msgid "Going to try to terminate %s"
+msgstr ""
+
+#: ../nova/compute/api.py:296
+#, python-format
+msgid "Instance %d was not found during terminate"
+msgstr ""
+
+#: ../nova/compute/api.py:301
+#, python-format
+msgid "Instance %d is already being terminated"
+msgstr ""
+
+#: ../nova/compute/api.py:481
+#, python-format
+msgid "Invalid device specified: %s. Example device: /dev/vdb"
+msgstr ""
+
+#: ../nova/compute/api.py:496
+msgid "Volume isn't attached to anything!"
+msgstr ""
+
+#: ../nova/rpc.py:98
+#, python-format
+msgid ""
+"AMQP server on %(fl_host)s:%(fl_port)d is unreachable. Trying again in "
+"%(fl_intv)d seconds."
+msgstr ""
+
+#: ../nova/rpc.py:103
+#, python-format
+msgid "Unable to connect to AMQP server after %d tries. Shutting down."
+msgstr ""
+"Hindi maka-konekta sa AMQP server pagkatapos ng %d ulit. Isasara na ang "
+"sistema."
+
+#: ../nova/rpc.py:122
+msgid "Reconnected to queue"
+msgstr "Muling kumonekta sa queue"
+
+#: ../nova/rpc.py:129
+msgid "Failed to fetch message from queue"
+msgstr "Hindi nai-abot ang mensahe buhat sa queue"
+
+#: ../nova/rpc.py:159
+#, python-format
+msgid "Initing the Adapter Consumer for %s"
+msgstr ""
+
+#: ../nova/rpc.py:178
+#, python-format
+msgid "received %s"
+msgstr "natanggap %s"
+
+#. NOTE(vish): we may not want to ack here, but that means that bad
+#. messages stay in the queue indefinitely, so for now
+#. we just log the message and send an error string
+#. back to the caller
+#: ../nova/rpc.py:191
+#, python-format
+msgid "no method for message: %s"
+msgstr "walang paraan para sa mensahe: %s"
+
+#: ../nova/rpc.py:192
+#, python-format
+msgid "No method for message: %s"
+msgstr "Walang paraan para sa mensahe: %s"
+
+#: ../nova/rpc.py:253
+#, python-format
+msgid "Returning exception %s to caller"
+msgstr ""
+
+#: ../nova/rpc.py:294
+#, python-format
+msgid "unpacked context: %s"
+msgstr ""
+
+#: ../nova/rpc.py:313
+msgid "Making asynchronous call..."
+msgstr ""
+
+#: ../nova/rpc.py:316
+#, python-format
+msgid "MSG_ID is %s"
+msgstr ""
+
+#: ../nova/rpc.py:354
+msgid "Making asynchronous cast..."
+msgstr ""
+
+#: ../nova/rpc.py:364
+#, python-format
+msgid "response %s"
+msgstr ""
+
+#: ../nova/rpc.py:373
+#, python-format
+msgid "topic is %s"
+msgstr ""
+
+#: ../nova/rpc.py:374
+#, python-format
+msgid "message %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:78
+#, python-format
+msgid "Recovering from a failed execute. Try number %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:87
+#, python-format
+msgid "volume group %s doesn't exist"
+msgstr ""
+
+#: ../nova/volume/driver.py:220
+#, python-format
+msgid "FAKE AOE: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:233
+msgid "Skipping ensure_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:279 ../nova/volume/driver.py:288
+msgid "Skipping remove_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:347
+#, python-format
+msgid "FAKE ISCSI: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:359
+#, python-format
+msgid "rbd has no pool %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:414
+#, python-format
+msgid "Sheepdog is not working: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:416
+msgid "Sheepdog is not working"
+msgstr ""
+
+#: ../nova/wsgi.py:68
+#, python-format
+msgid "Starting %(arg0)s on %(host)s:%(port)s"
+msgstr ""
+
+#: ../nova/wsgi.py:147
+msgid "You must implement __call__"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:58
+msgid "leasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:73
+msgid "Adopted old lease or got a change of mac/hostname"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:80
+msgid "releasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:123
+#, python-format
+msgid ""
+"Called %(action)s for mac %(mac)s with ip %(ip)s and hostname %(hostname)s "
+"on interface %(interface)s"
+msgstr ""
+
+#: ../nova/virt/fake.py:239
+#, python-format
+msgid "Instance %s Not Found"
+msgstr ""
+
+#: ../nova/network/manager.py:153
+#, python-format
+msgid "Dissassociated %s stale fixed ip(s)"
+msgstr ""
+
+#: ../nova/network/manager.py:157
+msgid "setting network host"
+msgstr ""
+
+#: ../nova/network/manager.py:212
+#, python-format
+msgid "Leasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:216
+#, python-format
+msgid "IP %s leased that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:220
+#, python-format
+msgid "IP %(address)s leased to bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:228
+#, python-format
+msgid "IP %s leased that was already deallocated"
+msgstr ""
+
+#: ../nova/network/manager.py:233
+#, python-format
+msgid "Releasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:237
+#, python-format
+msgid "IP %s released that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:241
+#, python-format
+msgid "IP %(address)s released from bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:244
+#, python-format
+msgid "IP %s released that was not leased"
+msgstr ""
+
+#: ../nova/network/manager.py:519
+msgid ""
+"The sum between the number of networks and the vlan start cannot be greater "
+"than 4094"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:57
+#, python-format
+msgid "Introducing %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:74
+#, python-format
+msgid "Introduced %(label)s as %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:78
+msgid "Unable to create Storage Repository"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:90
+#, python-format
+msgid "Unable to find SR from VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:96
+#, python-format
+msgid "Forgetting SR %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:101
+#, python-format
+msgid "Ignoring exception %(exc)s when getting PBDs for %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:107
+#, python-format
+msgid "Ignoring exception %(exc)s when unplugging PBD %(pbd)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:111
+#, python-format
+msgid "Forgetting SR %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:113
+#, python-format
+msgid "Ignoring exception %(exc)s when forgetting SR %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:123
+#, python-format
+msgid "Unable to introduce VDI on SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:128
+#, python-format
+msgid "Unable to get record of VDI %s on"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:146
+#, python-format
+msgid "Unable to introduce VDI for SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:175
+#, python-format
+msgid "Unable to obtain target information %(device_path)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:197
+#, python-format
+msgid "Mountpoint cannot be translated: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:262
+#, python-format
+msgid "Failed to decrypt private key: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:269
+#, python-format
+msgid "Failed to decrypt initialization vector: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:277
+#, python-format
+msgid "Failed to decrypt image file %(image_file)s: %(err)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:106
+#, python-format
+msgid "Unknown S3 value type %r"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:137
+msgid "Authenticated request"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:182
+msgid "List of buckets requested"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:209
+#, python-format
+msgid "List keys for bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:217
+#, python-format
+msgid "Unauthorized attempt to access bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:235
+#, python-format
+msgid "Creating bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:245
+#, python-format
+msgid "Deleting bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:249
+#, python-format
+msgid "Unauthorized attempt to delete bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:273
+#, python-format
+msgid "Getting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:276
+#, python-format
+msgid "Unauthorized attempt to get object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:296
+#, python-format
+msgid "Putting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:299
+#, python-format
+msgid "Unauthorized attempt to upload object %(nm)s to bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:318
+#, python-format
+msgid "Deleting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:322
+#, python-format
+msgid "Unauthorized attempt to delete object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:396
+#, python-format
+msgid "Not authorized to upload image: invalid directory %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:404
+#, python-format
+msgid "Not authorized to upload image: unauthorized bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:409
+#, python-format
+msgid "Starting image upload: %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:423
+#, python-format
+msgid "Not authorized to update attributes of image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:431
+#, python-format
+msgid "Toggling publicity flag of image %(image_id)s %(newstatus)r"
+msgstr ""
+
+#. other attributes imply update
+#: ../nova/objectstore/handler.py:436
+#, python-format
+msgid "Updating user fields on image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:450
+#, python-format
+msgid "Unauthorized attempt to delete image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:455
+#, python-format
+msgid "Deleted image: %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:259
+#, python-format
+msgid "Looking up user: %r"
+msgstr ""
+
+#: ../nova/auth/manager.py:263
+#, python-format
+msgid "Failed authorization for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:264
+#, python-format
+msgid "No user found for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:270
+#, python-format
+msgid "Using project name = user name (%s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:277
+#, python-format
+msgid "failed authorization: no project named %(pjid)s (user=%(uname)s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:279
+#, python-format
+msgid "No project called %s could be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:287
+#, python-format
+msgid ""
+"Failed authorization: user %(uname)s not admin and not member of project "
+"%(pjname)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:289
+#, python-format
+msgid "User %(uid)s is not a member of project %(pjid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:298 ../nova/auth/manager.py:309
+#, python-format
+msgid "Invalid signature for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:299 ../nova/auth/manager.py:310
+msgid "Signature does not match"
+msgstr ""
+
+#: ../nova/auth/manager.py:380
+msgid "Must specify project"
+msgstr ""
+
+#: ../nova/auth/manager.py:414
+#, python-format
+msgid "The %s role can not be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:416
+#, python-format
+msgid "The %s role is global only"
+msgstr ""
+
+#: ../nova/auth/manager.py:420
+#, python-format
+msgid "Adding role %(role)s to user %(uid)s in project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:423
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:448
+#, python-format
+msgid "Removing role %(role)s from user %(uid)s on project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:451
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:515
+#, python-format
+msgid "Created project %(name)s with manager %(manager_user)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:533
+#, python-format
+msgid "modifying project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:545
+#, python-format
+msgid "Adding user %(uid)s to project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:566
+#, python-format
+msgid "Remove user %(uid)s from project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:592
+#, python-format
+msgid "Deleting project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:650
+#, python-format
+msgid "Created user %(rvname)s (admin: %(rvadmin)r)"
+msgstr ""
+
+#: ../nova/auth/manager.py:659
+#, python-format
+msgid "Deleting user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:669
+#, python-format
+msgid "Access Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:671
+#, python-format
+msgid "Secret Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:673
+#, python-format
+msgid "Admin status set to %(admin)r for user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:722
+#, python-format
+msgid "No vpn data for project %s"
+msgstr ""
+
+#: ../nova/service.py:161
+#, python-format
+msgid "Starting %(topic)s node (version %(vcs_string)s)"
+msgstr ""
+
+#: ../nova/service.py:174
+msgid "Service killed that has no database entry"
+msgstr ""
+
+#: ../nova/service.py:195
+msgid "The service database object disappeared, Recreating it."
+msgstr ""
+
+#: ../nova/service.py:207
+msgid "Recovered model server connection!"
+msgstr ""
+
+#: ../nova/service.py:213
+msgid "model server went away"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:174
+#, python-format
+msgid "LDAP user %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:205
+#, python-format
+msgid "LDAP object for %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:348
+#, python-format
+msgid "User %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:472
+#, python-format
+msgid "Group can't be created because group %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:478
+#, python-format
+msgid "Group can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:495
+#, python-format
+msgid "User %s can't be searched in group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:507
+#, python-format
+msgid "User %s can't be added to the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
+#, python-format
+msgid "The group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:513
+#, python-format
+msgid "User %(uid)s is already a member of the group %(group_dn)s"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:524
+#, python-format
+msgid ""
+"User %s can't be removed from the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:528
+#, python-format
+msgid "User %s is not a member of the group"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:542
+#, python-format
+msgid ""
+"Attempted to remove the last member of a group. Deleting the group at %s "
+"instead."
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:549
+#, python-format
+msgid "User %s can't be removed from all because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:564
+#, python-format
+msgid "Group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:40
+#, python-format
+msgid "Found non-unique network for bridge %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:43
+#, python-format
+msgid "Found no network for bridge %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:97
+#, python-format
+msgid "Creating new user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:105
+#, python-format
+msgid "Deleting user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:127
+#, python-format
+msgid "Adding role %(role)s to user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:131
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:137
+#, python-format
+msgid "Removing role %(role)s from user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:141
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:146 ../nova/api/ec2/admin.py:223
+msgid "operation must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:159
+#, python-format
+msgid "Getting x509 for user: %(name)s on project: %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:177
+#, python-format
+msgid "Create project %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:190
+#, python-format
+msgid "Modify project: %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:200
+#, python-format
+msgid "Delete project: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:214
+#, python-format
+msgid "Adding user %(user)s to project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:218
+#, python-format
+msgid "Removing user %(user)s from project %(project)s"
+msgstr ""
+
+#, python-format
+#~ msgid "AMQP server on %s:%d is unreachable. Trying again in %d seconds."
+#~ msgstr ""
+#~ "Hindi makita o maabot ang AMQP server sa %s:%d. Muling subukan sa %d segundo."
diff --git a/po/uk.po b/po/uk.po
index d28860c9b..481851e1c 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -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
@@ -125,33 +125,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr ""
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr ""
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr ""
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr "ОбÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ %s"
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr ""
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "ЗапуÑкаєтьÑÑ %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
#: ../nova/api/ec2/__init__.py:317
@@ -1778,34 +1751,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2263,10 +2208,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 9690356f5..d0ddcd2f7 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -8,25 +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-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"
-
-#: ../nova/twistd.py:266
-#, python-format
-msgid "Starting %s"
-msgstr "å¯åЍ %s 中"
+"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."
@@ -41,6 +36,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"
@@ -130,28 +130,6 @@ msgstr ""
msgid "compute.api::resume %s"
msgstr ""
-#: ../nova/twistd.py:157
-msgid "Wrong number of arguments."
-msgstr "é”™è¯¯å‚æ•°ä¸ªæ•°ã€‚"
-
-#: ../nova/twistd.py:209
-#, python-format
-msgid "pidfile %s does not exist. Daemon not running?\n"
-msgstr "pidfile %s ä¸å­˜åœ¨ï¼Œå®ˆæŠ¤è¿›ç¨‹æ˜¯å¦è¿è¡Œï¼Ÿ\n"
-
-#: ../nova/twistd.py:221
-msgid "No such process"
-msgstr "没有该进程"
-
-#: ../nova/twistd.py:230 ../nova/service.py:224
-#, python-format
-msgid "Serving %s"
-msgstr "正在为 %s æœåŠ¡"
-
-#: ../nova/twistd.py:262 ../nova/service.py:225
-msgid "Full set of FLAGS:"
-msgstr "FLAGS全集:"
-
#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
#: ../nova/api/ec2/__init__.py:317
@@ -309,17 +287,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 +309,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 +329,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
@@ -1778,34 +1758,6 @@ msgstr ""
msgid "Got exception: %s"
msgstr ""
-#: ../nova/compute/monitor.py:259
-#, python-format
-msgid "updating %s..."
-msgstr ""
-
-#: ../nova/compute/monitor.py:289
-msgid "unexpected error during update"
-msgstr ""
-
-#: ../nova/compute/monitor.py:356
-#, python-format
-msgid "Cannot get blockstats for \"%(disk)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:379
-#, python-format
-msgid "Cannot get ifstats for \"%(interface)s\" on \"%(iid)s\""
-msgstr ""
-
-#: ../nova/compute/monitor.py:414
-msgid "unexpected exception getting connection"
-msgstr ""
-
-#: ../nova/compute/monitor.py:429
-#, python-format
-msgid "Found instance: %s"
-msgstr ""
-
#: ../nova/volume/san.py:67
#, python-format
msgid "Could not find iSCSI export for volume %s"
@@ -2263,10 +2215,6 @@ msgstr ""
msgid "You must implement __call__"
msgstr ""
-#: ../bin/nova-instancemonitor.py:55
-msgid "Starting instance monitor"
-msgstr ""
-
#: ../bin/nova-dhcpbridge.py:58
msgid "leasing ip"
msgstr ""
diff --git a/po/zh_TW.po b/po/zh_TW.po
new file mode 100644
index 000000000..896e69618
--- /dev/null
+++ b/po/zh_TW.po
@@ -0,0 +1,2789 @@
+# Chinese (Traditional) translation for nova
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the nova package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+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-25 07:14+0000\n"
+"Last-Translator: Hugo Kou <Unknown>\n"
+"Language-Team: Chinese (Traditional) <zh_TW@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-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 "找ä¸åˆ°ä¸»æ©Ÿ"
+
+#: ../nova/exception.py:33
+msgid "Unexpected error while running command."
+msgstr "éžé æœŸçš„執行錯誤"
+
+#: ../nova/exception.py:36
+#, python-format
+msgid ""
+"%(description)s\n"
+"Command: %(cmd)s\n"
+"Exit code: %(exit_code)s\n"
+"Stdout: %(stdout)r\n"
+"Stderr: %(stderr)r"
+msgstr ""
+
+#: ../nova/exception.py:107
+msgid "DB exception wrapped"
+msgstr ""
+
+#. exc_type, exc_value, exc_traceback = sys.exc_info()
+#: ../nova/exception.py:120
+msgid "Uncaught exception"
+msgstr ""
+
+#: ../nova/volume/api.py:45
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to create %(size)sG volume"
+msgstr ""
+
+#: ../nova/volume/api.py:47
+#, python-format
+msgid "Volume quota exceeded. You cannot create a volume of size %sG"
+msgstr "Volume è¶…éŽé™åˆ¶ã€‚無法創建 volume å¤§å° %sG"
+
+#: ../nova/volume/api.py:71 ../nova/volume/api.py:96
+msgid "Volume status must be available"
+msgstr "Volume 狀態需è¦å¯è¢«ä½¿ç”¨"
+
+#: ../nova/volume/api.py:98
+msgid "Volume is already attached"
+msgstr "Volume 已掛載"
+
+#: ../nova/volume/api.py:104
+msgid "Volume is already detached"
+msgstr "Volume 已經å¸è¼‰"
+
+#: ../nova/api/openstack/servers.py:72
+msgid "Failed to read private ip"
+msgstr "讀å–private ip 失敗"
+
+#: ../nova/api/openstack/servers.py:79
+msgid "Failed to read public ip(s)"
+msgstr "讀å–public ip 失敗"
+
+#: ../nova/api/openstack/servers.py:152
+#, python-format
+msgid "%(param)s property not found for image %(_image_id)s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:168
+msgid "No keypairs defined"
+msgstr "沒有定義的金鑰(keypair)é…å°"
+
+#: ../nova/api/openstack/servers.py:238
+#, python-format
+msgid "Compute.api::lock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:253
+#, python-format
+msgid "Compute.api::unlock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:267
+#, python-format
+msgid "Compute.api::get_lock %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:281
+#, python-format
+msgid "Compute.api::reset_network %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:292
+#, python-format
+msgid "Compute.api::pause %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:303
+#, python-format
+msgid "Compute.api::unpause %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:314
+#, python-format
+msgid "compute.api::suspend %s"
+msgstr ""
+
+#: ../nova/api/openstack/servers.py:325
+#, python-format
+msgid "compute.api::resume %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:48 ../nova/virt/xenapi/volumeops.py:101
+#: ../nova/db/sqlalchemy/api.py:731 ../nova/virt/libvirt_conn.py:741
+#: ../nova/api/ec2/__init__.py:317
+#, python-format
+msgid "Instance %s not found"
+msgstr "找ä¸åˆ°è™›æ“¬æ©Ÿå™¨ %s"
+
+#. NOTE: No Resource Pool concept so far
+#: ../nova/virt/xenapi/volumeops.py:51
+#, python-format
+msgid "Attach_volume: %(instance_name)s, %(device_path)s, %(mountpoint)s"
+msgstr "掛載_Volume: %(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 ""
+
+#: ../nova/virt/xenapi/volumeops.py:80
+#, python-format
+msgid "Unable to use SR %(sr_ref)s for instance %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volumeops.py:91
+#, python-format
+msgid "Unable to attach volume to instance %s"
+msgstr "無法掛載Volume 到虛擬機器 %s"
+
+#: ../nova/virt/xenapi/volumeops.py:93
+#, python-format
+msgid "Mountpoint %(mountpoint)s attached to instance %(instance_name)s"
+msgstr "掛載點 %(mountpoint)s 掛載到虛擬機器 %(instance_name)s"
+
+#. Detach VBD from VM
+#: ../nova/virt/xenapi/volumeops.py:104
+#, python-format
+msgid "Detach_volume: %(instance_name)s, %(mountpoint)s"
+msgstr "å¸è¼‰_Volume: %(instance_name)s, %(mountpoint)s"
+
+#: ../nova/virt/xenapi/volumeops.py:112
+#, python-format
+msgid "Unable to locate volume %s"
+msgstr "找ä¸åˆ°Volume %s"
+
+#: ../nova/virt/xenapi/volumeops.py:120
+#, python-format
+msgid "Unable to detach volume %s"
+msgstr "無法å¸è¼‰ Volume %s"
+
+#: ../nova/virt/xenapi/volumeops.py:127
+#, python-format
+msgid "Mountpoint %(mountpoint)s detached from instance %(instance_name)s"
+msgstr "掛載點 %(mountpoint)s 從虛擬機器 %(instance_name)s å¸è¼‰"
+
+#: ../nova/compute/instance_types.py:41
+#, python-format
+msgid "Unknown instance type: %s"
+msgstr "æœªçŸ¥çš„è™›æ“¬æ©Ÿå™¨è¦æ ¼: %s"
+
+#: ../nova/crypto.py:46
+msgid "Filename of root CA"
+msgstr ""
+
+#: ../nova/crypto.py:49
+msgid "Filename of private key"
+msgstr "Private key ç§é‘°æª”案å稱"
+
+#: ../nova/crypto.py:51
+msgid "Filename of root Certificate Revokation List"
+msgstr ""
+
+#: ../nova/crypto.py:53
+msgid "Where we keep our keys"
+msgstr ""
+
+#: ../nova/crypto.py:55
+msgid "Where we keep our root CA"
+msgstr ""
+
+#: ../nova/crypto.py:57
+msgid "Should we use a CA for each project?"
+msgstr ""
+
+#: ../nova/crypto.py:61
+#, python-format
+msgid "Subject for certificate for users, %s for project, user, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:66
+#, python-format
+msgid "Subject for certificate for projects, %s for project, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:71
+#, python-format
+msgid "Subject for certificate for vpns, %s for project, timestamp"
+msgstr ""
+
+#: ../nova/crypto.py:258
+#, python-format
+msgid "Flags path: %s"
+msgstr ""
+
+#: ../nova/scheduler/manager.py:69
+#, python-format
+msgid "Casting to %(topic)s %(host)s for %(method)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:78
+#, python-format
+msgid "check_instance_lock: decorating: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:80
+#, python-format
+msgid ""
+"check_instance_lock: arguments: |%(self)s| |%(context)s| |%(instance_id)s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:84
+#, python-format
+msgid "check_instance_lock: locked: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:86
+#, python-format
+msgid "check_instance_lock: admin: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:91
+#, python-format
+msgid "check_instance_lock: executing: |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:95
+#, python-format
+msgid "check_instance_lock: not executing |%s|"
+msgstr ""
+
+#: ../nova/compute/manager.py:179
+msgid "Instance has already been created"
+msgstr ""
+
+#: ../nova/compute/manager.py:180
+#, python-format
+msgid "instance %s: starting..."
+msgstr ""
+
+#. pylint: disable=W0702
+#: ../nova/compute/manager.py:219
+#, python-format
+msgid "instance %s: Failed to spawn"
+msgstr ""
+
+#: ../nova/compute/manager.py:233 ../nova/tests/test_cloud.py:286
+#, python-format
+msgid "Terminating instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:255
+#, python-format
+msgid "Deallocating address %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:268
+#, python-format
+msgid "trying to destroy already destroyed instance: %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:282
+#, python-format
+msgid "Rebooting instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:287
+#, python-format
+msgid ""
+"trying to reboot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:311
+#, python-format
+msgid "instance %s: snapshotting"
+msgstr ""
+
+#: ../nova/compute/manager.py:316
+#, python-format
+msgid ""
+"trying to snapshot a non-running instance: %(instance_id)s (state: %(state)s "
+"expected: %(running)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:332
+#, python-format
+msgid ""
+"trying to reset the password on a non-running instance: %(instance_id)s "
+"(state: %(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:335
+#, python-format
+msgid "instance %s: setting admin password"
+msgstr ""
+
+#: ../nova/compute/manager.py:353
+#, python-format
+msgid ""
+"trying to inject a file into a non-running instance: %(instance_id)s (state: "
+"%(instance_state)s expected: %(expected_state)s)"
+msgstr ""
+
+#: ../nova/compute/manager.py:362
+#, python-format
+msgid "instance %(nm)s: injecting file to %(plain_path)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:372
+#, python-format
+msgid "instance %s: rescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:387
+#, python-format
+msgid "instance %s: unrescuing"
+msgstr ""
+
+#: ../nova/compute/manager.py:406
+#, python-format
+msgid "instance %s: pausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:423
+#, python-format
+msgid "instance %s: unpausing"
+msgstr ""
+
+#: ../nova/compute/manager.py:440
+#, python-format
+msgid "instance %s: retrieving diagnostics"
+msgstr ""
+
+#: ../nova/compute/manager.py:453
+#, python-format
+msgid "instance %s: suspending"
+msgstr ""
+
+#: ../nova/compute/manager.py:472
+#, python-format
+msgid "instance %s: resuming"
+msgstr ""
+
+#: ../nova/compute/manager.py:491
+#, python-format
+msgid "instance %s: locking"
+msgstr ""
+
+#: ../nova/compute/manager.py:503
+#, python-format
+msgid "instance %s: unlocking"
+msgstr ""
+
+#: ../nova/compute/manager.py:513
+#, python-format
+msgid "instance %s: getting locked state"
+msgstr ""
+
+#: ../nova/compute/manager.py:526
+#, python-format
+msgid "instance %s: reset network"
+msgstr ""
+
+#: ../nova/compute/manager.py:535 ../nova/api/ec2/cloud.py:515
+#, python-format
+msgid "Get console output for instance %s"
+msgstr ""
+
+#: ../nova/compute/manager.py:543
+#, python-format
+msgid "instance %s: getting ajax console"
+msgstr ""
+
+#: ../nova/compute/manager.py:553
+#, python-format
+msgid ""
+"instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s"
+msgstr ""
+
+#. pylint: disable=W0702
+#. NOTE(vish): The inline callback eats the exception info so we
+#. log the traceback here and reraise the same
+#. ecxception below.
+#: ../nova/compute/manager.py:569
+#, python-format
+msgid "instance %(instance_id)s: attach failed %(mountpoint)s, removing"
+msgstr ""
+
+#: ../nova/compute/manager.py:585
+#, python-format
+msgid ""
+"Detach volume %(volume_id)s from mountpoint %(mp)s on instance "
+"%(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/manager.py:588
+#, python-format
+msgid "Detaching volume from unknown instance %s"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:53
+#, python-format
+msgid "Host %s is not alive"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:65
+msgid "All hosts have too many cores"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:87
+#, python-format
+msgid "Host %s not available"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:99
+msgid "All hosts have too many gigabytes"
+msgstr ""
+
+#: ../nova/scheduler/simple.py:119
+msgid "All hosts have too many networks"
+msgstr ""
+
+#: ../nova/volume/manager.py:85
+#, python-format
+msgid "Re-exporting %s volumes"
+msgstr ""
+
+#: ../nova/volume/manager.py:90
+#, python-format
+msgid "volume %s: skipping export"
+msgstr ""
+
+#: ../nova/volume/manager.py:96
+#, python-format
+msgid "volume %s: creating"
+msgstr ""
+
+#: ../nova/volume/manager.py:108
+#, python-format
+msgid "volume %(vol_name)s: creating lv of size %(vol_size)sG"
+msgstr ""
+
+#: ../nova/volume/manager.py:112
+#, python-format
+msgid "volume %s: creating export"
+msgstr ""
+
+#: ../nova/volume/manager.py:123
+#, python-format
+msgid "volume %s: created successfully"
+msgstr ""
+
+#: ../nova/volume/manager.py:131
+msgid "Volume is still attached"
+msgstr ""
+
+#: ../nova/volume/manager.py:133
+msgid "Volume is not local to this node"
+msgstr ""
+
+#: ../nova/volume/manager.py:136
+#, python-format
+msgid "volume %s: removing export"
+msgstr ""
+
+#: ../nova/volume/manager.py:138
+#, python-format
+msgid "volume %s: deleting"
+msgstr ""
+
+#: ../nova/volume/manager.py:147
+#, python-format
+msgid "volume %s: deleted successfully"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:74
+#, python-format
+msgid "%(text)s: _db_content => %(content)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:304 ../nova/virt/xenapi/fake.py:404
+#: ../nova/virt/xenapi/fake.py:422 ../nova/virt/xenapi/fake.py:478
+msgid "Raising NotImplemented"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:306
+#, python-format
+msgid "xenapi.fake does not have an implementation for %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:341
+#, python-format
+msgid "Calling %(localname)s %(impl)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:346
+#, python-format
+msgid "Calling getter %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/fake.py:406
+#, python-format
+msgid ""
+"xenapi.fake does not have an implementation for %s or it has been called "
+"with the wrong number of arguments"
+msgstr ""
+
+#: ../nova/tests/test_cloud.py:256
+msgid "Can't test instances without a real virtual env."
+msgstr ""
+
+#: ../nova/tests/test_cloud.py:268
+#, python-format
+msgid "Need to watch instance %s until it's running..."
+msgstr ""
+
+#: ../nova/virt/connection.py:73
+msgid "Failed to open connection to the hypervisor"
+msgstr ""
+
+#: ../nova/network/linux_net.py:187
+#, python-format
+msgid "Starting VLAN inteface %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:208
+#, python-format
+msgid "Starting Bridge interface for %s"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:314
+#, python-format
+msgid "Hupping dnsmasq threw %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:316
+#, python-format
+msgid "Pid %d is stale, relaunching dnsmasq"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:358
+#, python-format
+msgid "killing radvd threw %s"
+msgstr ""
+
+#: ../nova/network/linux_net.py:360
+#, python-format
+msgid "Pid %d is stale, relaunching radvd"
+msgstr ""
+
+#. pylint: disable=W0703
+#: ../nova/network/linux_net.py:449
+#, python-format
+msgid "Killing dnsmasq threw %s"
+msgstr ""
+
+#: ../nova/utils.py:58
+#, python-format
+msgid "Inner Exception: %s"
+msgstr ""
+
+#: ../nova/utils.py:59
+#, python-format
+msgid "Class %s cannot be found"
+msgstr ""
+
+#: ../nova/utils.py:118
+#, python-format
+msgid "Fetching %s"
+msgstr ""
+
+#: ../nova/utils.py:130
+#, python-format
+msgid "Running cmd (subprocess): %s"
+msgstr ""
+
+#: ../nova/utils.py:143 ../nova/utils.py:183
+#, python-format
+msgid "Result was %s"
+msgstr ""
+
+#: ../nova/utils.py:159
+#, python-format
+msgid "Running cmd (SSH): %s"
+msgstr ""
+
+#: ../nova/utils.py:217
+#, python-format
+msgid "debug in callback: %s"
+msgstr ""
+
+#: ../nova/utils.py:222
+#, python-format
+msgid "Running %s"
+msgstr ""
+
+#: ../nova/utils.py:262
+#, python-format
+msgid "Link Local address is not found.:%s"
+msgstr ""
+
+#: ../nova/utils.py:265
+#, python-format
+msgid "Couldn't get Link Local IP of %(interface)s :%(ex)s"
+msgstr ""
+
+#: ../nova/utils.py:363
+#, python-format
+msgid "Invalid backend: %s"
+msgstr ""
+
+#: ../nova/utils.py:374
+#, python-format
+msgid "backend %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:49
+#, python-format
+msgid "(%(nm)s) publish (key: %(routing_key)s) %(message)s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:54
+#, python-format
+msgid "Publishing to route %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:84
+#, python-format
+msgid "Declaring queue %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:90
+#, python-format
+msgid "Declaring exchange %s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:96
+#, python-format
+msgid "Binding %(queue)s to %(exchange)s with key %(routing_key)s"
+msgstr ""
+
+#: ../nova/fakerabbit.py:121
+#, python-format
+msgid "Getting from %(queue)s: %(message)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:135 ../nova/virt/hyperv.py:171
+#, python-format
+msgid "Created VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:138
+#, python-format
+msgid "Created VM %(instance_name)s as %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:168
+#, python-format
+msgid "Creating VBD for VM %(vm_ref)s, VDI %(vdi_ref)s ... "
+msgstr ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:187
+#, python-format
+msgid "VBD not found in instance %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:197
+#, python-format
+msgid "Unable to unplug VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:209
+#, python-format
+msgid "Unable to destroy VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:224
+#, python-format
+msgid "Creating VIF for VM %(vm_ref)s, network %(network_ref)s."
+msgstr ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:246
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(name_label)s, %(virtual_size)s, %(read_only)s) on "
+"%(sr_ref)s."
+msgstr ""
+
+#. 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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:272
+#, python-format
+msgid "Created snapshot %(template_vm_ref)s from VM %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:286
+#, python-format
+msgid "Asking xapi to upload %(vdi_uuids)s as ID %(image_id)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:327
+#, python-format
+msgid "Size for image %(image)s:%(virtual_size)d"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:332
+#, python-format
+msgid "Glance image %s"
+msgstr ""
+
+#. 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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:352
+#, python-format
+msgid "Kernel/Ramdisk VDI %s destroyed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:361
+#, python-format
+msgid "Asking xapi to fetch %(url)s as %(access)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:386 ../nova/virt/xenapi/vm_utils.py:402
+#, python-format
+msgid "Looking up vdi %s for PV kernel"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:397
+#, python-format
+msgid "PV Kernel in VDI:%s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:405
+#, python-format
+msgid "Running pygrub against %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:411
+#, python-format
+msgid "Found Xen kernel %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:413
+msgid "No Xen kernel found. Booting HVM."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:425 ../nova/virt/hyperv.py:431
+#, python-format
+msgid "duplicate name found: %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:442
+#, python-format
+msgid "VDI %s is still available"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:463
+#, python-format
+msgid "(VM_UTILS) xenserver vm state -> |%s|"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:465
+#, python-format
+msgid "(VM_UTILS) xenapi power_state -> |%s|"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:525
+#, python-format
+msgid "VHD %(vdi_uuid)s has parent %(parent_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:542
+#, python-format
+msgid "Re-scanning SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:567
+#, python-format
+msgid ""
+"VHD coalesce attempts exceeded (%(counter)d > %(max_attempts)d), giving up..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:574
+#, python-format
+msgid ""
+"Parent %(parent_uuid)s doesn't match original parent "
+"%(original_parent_uuid)s, waiting for coalesce..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:590
+#, python-format
+msgid "No VDIs found for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:594
+#, python-format
+msgid "Unexpected number of VDIs (%(num_vdis)s) found for VM %(vm_ref)s"
+msgstr ""
+
+#: ../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 ""
+
+#: ../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 ""
+
+#: ../nova/virt/xenapi/vm_utils.py:657
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:192
+#, python-format
+msgid "Plugging VBD %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:659
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:194
+#, python-format
+msgid "Plugging VBD %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:661
+#, python-format
+msgid "VBD %(vbd)s plugged as %(orig_dev)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:664
+#, python-format
+msgid "VBD %(vbd)s plugged into wrong dev, remapping to %(dev)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:668
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:197
+#, python-format
+msgid "Destroying VBD for VDI %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:671
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:200
+#, python-format
+msgid "Destroying VBD for VDI %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:683
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:211
+msgid "VBD.unplug successful first time."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:688
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:216
+msgid "VBD.unplug rejected: retrying..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:692
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:220
+msgid "VBD.unplug successful eventually."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:695
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:223
+#, python-format
+msgid "Ignoring XenAPI.Failure in VBD.unplug: %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:704
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:66
+#, python-format
+msgid "Ignoring XenAPI.Failure %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:735
+#, python-format
+msgid ""
+"Writing partition table %(primary_first)d %(primary_last)d to %(dest)s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vm_utils.py:747
+#, python-format
+msgid "Writing partition table %s done."
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:89
+#, python-format
+msgid "Nested received %(queue)s, %(value)s"
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:95
+#, python-format
+msgid "Nested return %s"
+msgstr ""
+
+#: ../nova/tests/test_rpc.py:120 ../nova/tests/test_rpc.py:126
+#, python-format
+msgid "Received %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:44
+msgid "Use of empty request context is deprecated"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:133
+#, python-format
+msgid "No service for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:251
+#, python-format
+msgid "No service for %(host)s, %(binary)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:592
+msgid "No fixed ips defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:608
+#, python-format
+msgid "No floating ip for address %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:629
+#, python-format
+msgid "No address for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:961
+#, python-format
+msgid "no keypair for user %(user_id)s, name %(name)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1076 ../nova/db/sqlalchemy/api.py:1156
+#, python-format
+msgid "No network for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1086
+msgid "No networks defined"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1115
+#, python-format
+msgid "No network for bridge %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1129 ../nova/db/sqlalchemy/api.py:1142
+#, python-format
+msgid "No network for instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1277
+#, python-format
+msgid "Token %s does not exist"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1302
+#, python-format
+msgid "No quota for project_id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1455 ../nova/db/sqlalchemy/api.py:1501
+#: ../nova/api/ec2/__init__.py:323
+#, python-format
+msgid "Volume %s not found"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1514
+#, python-format
+msgid "No export device found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1527
+#, python-format
+msgid "No target id found for volume %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1572
+#, python-format
+msgid "No security group with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1589
+#, python-format
+msgid "No security group named %(group_name)s for project: %(project_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1682
+#, python-format
+msgid "No secuity group rule with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1756
+#, python-format
+msgid "No user for id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1772
+#, python-format
+msgid "No user for access key %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1834
+#, python-format
+msgid "No project with id %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1979
+#, python-format
+msgid "No console pool with id %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:1996
+#, python-format
+msgid ""
+"No console pool of type %(console_type)s for compute host %(compute_host)s "
+"on proxy host %(host)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2035
+#, python-format
+msgid "No console for instance %(instance_id)s in pool %(pool_id)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2057
+#, python-format
+msgid "on instance %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2058
+#, python-format
+msgid "No console with id %(console_id)s %(idesc)s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/api.py:2078 ../nova/db/sqlalchemy/api.py:2097
+#, python-format
+msgid "No zone with id %(zone_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:160
+#, python-format
+msgid "Checking state of %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:165
+#, python-format
+msgid "Current state of %(name)s was %(state)s."
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:183
+#, python-format
+msgid "Connecting to libvirt: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:196
+msgid "Connection to libvirt broke"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:258
+#, python-format
+msgid "instance %(instance_name)s: deleting instance files %(target)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:283
+#, python-format
+msgid "Invalid device path %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:313
+#, python-format
+msgid "No disk at %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:320
+msgid "Instance snapshotting is not supported for libvirtat this time"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:336
+#, python-format
+msgid "instance %s: rebooted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:339
+#, python-format
+msgid "_wait_for_reboot failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:382
+#, python-format
+msgid "instance %s: rescued"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:385
+#, python-format
+msgid "_wait_for_rescue failed: %s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:411
+#, python-format
+msgid "instance %s: is running"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:422
+#, python-format
+msgid "instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:425 ../nova/virt/xenapi/vmops.py:186
+#, python-format
+msgid "instance %s: failed to boot"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:436
+#, python-format
+msgid "virsh said: %r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:440
+msgid "cool, it's a device"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:448
+#, python-format
+msgid "data: %(data)r, fpath: %(fpath)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:456
+#, python-format
+msgid "Contents of file %(fpath)s: %(contents)r"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:489
+msgid "Unable to find an open port"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:563
+#, python-format
+msgid "instance %s: Creating image"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:646
+#, python-format
+msgid "instance %(inst_name)s: injecting key into image %(img_id)s"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:649
+#, python-format
+msgid "instance %(inst_name)s: injecting net into image %(img_id)s"
+msgstr ""
+
+#. This could be a windows image, or a vmdk format disk
+#: ../nova/virt/libvirt_conn.py:657
+#, python-format
+msgid ""
+"instance %(inst_name)s: ignoring error injecting data into image %(img_id)s "
+"(%(e)s)"
+msgstr ""
+
+#. TODO(termie): cache?
+#: ../nova/virt/libvirt_conn.py:665
+#, python-format
+msgid "instance %s: starting toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:732
+#, python-format
+msgid "instance %s: finished toXML method"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:751
+msgid "diagnostics are not supported for libvirt"
+msgstr ""
+
+#: ../nova/virt/libvirt_conn.py:1225
+#, python-format
+msgid "Attempted to unfilter instance %s which is not filtered"
+msgstr ""
+
+#: ../nova/api/ec2/metadatarequesthandler.py:76
+#, python-format
+msgid "Failed to get metadata for ip: %s"
+msgstr ""
+
+#: ../nova/auth/fakeldap.py:33
+msgid "Attempted to instantiate singleton"
+msgstr ""
+
+#: ../nova/network/api.py:39
+#, python-format
+msgid "Quota exceeeded for %s, tried to allocate address"
+msgstr ""
+
+#: ../nova/network/api.py:42
+msgid "Address quota exceeded. You cannot allocate any more addresses"
+msgstr ""
+
+#: ../nova/tests/test_volume.py:162
+#, python-format
+msgid "Target %s allocated"
+msgstr ""
+
+#: ../nova/virt/images.py:70
+#, python-format
+msgid "Finished retreving %(url)s -- placed in %(path)s"
+msgstr ""
+
+#: ../nova/scheduler/driver.py:66
+msgid "Must implement a fallback schedule"
+msgstr ""
+
+#: ../nova/console/manager.py:70
+msgid "Adding console"
+msgstr ""
+
+#: ../nova/console/manager.py:90
+#, python-format
+msgid "Tried to remove non-existant console %(console_id)s."
+msgstr ""
+
+#: ../nova/api/direct.py:149
+msgid "not available"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:62
+#, python-format
+msgid "The key_pair %s already exists"
+msgstr ""
+
+#. TODO(vish): Do this with M2Crypto instead
+#: ../nova/api/ec2/cloud.py:118
+#, python-format
+msgid "Generating root CA: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:303
+#, python-format
+msgid "Create key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:311
+#, python-format
+msgid "Delete key pair %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:386
+#, python-format
+msgid "%s is not a valid ipProtocol"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:390
+msgid "Invalid port range"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:421
+#, python-format
+msgid "Revoke security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:430 ../nova/api/ec2/cloud.py:459
+msgid "Not enough parameters to build a valid rule."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:443
+msgid "No rule for the specified parameters."
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:450
+#, python-format
+msgid "Authorize security group ingress %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:464
+#, python-format
+msgid "This rule already exists in group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:492
+#, python-format
+msgid "Create Security Group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:495
+#, python-format
+msgid "group %s already exists"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:507
+#, python-format
+msgid "Delete security group %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:584
+#, python-format
+msgid "Create volume of %s GB"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:612
+#, python-format
+msgid "Attach volume %(volume_id)s to instance %(instance_id)s at %(device)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:629
+#, python-format
+msgid "Detach volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:761
+msgid "Allocate address"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:766
+#, python-format
+msgid "Release address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:771
+#, python-format
+msgid "Associate address %(public_ip)s to instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:780
+#, python-format
+msgid "Disassociate address %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:807
+msgid "Going to start terminating instances"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:815
+#, python-format
+msgid "Reboot instance %r"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:867
+#, python-format
+msgid "De-registering image %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:875
+#, python-format
+msgid "Registered image %(image_location)s with id %(image_id)s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:882 ../nova/api/ec2/cloud.py:900
+#, python-format
+msgid "attribute not supported: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:890
+#, python-format
+msgid "invalid id: %s"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:903
+msgid "user or group not specified"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:905
+msgid "only group \"all\" is supported"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:907
+msgid "operation_type must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/cloud.py:908
+#, python-format
+msgid "Updating image %s publicity"
+msgstr ""
+
+#: ../bin/nova-api.py:52
+#, python-format
+msgid "Using paste.deploy config at: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:57
+#, python-format
+msgid "No paste configuration for app: %s"
+msgstr ""
+
+#: ../bin/nova-api.py:59
+#, python-format
+msgid ""
+"App Config: %(api)s\n"
+"%(config)r"
+msgstr ""
+
+#: ../bin/nova-api.py:64
+#, python-format
+msgid "Running %s API"
+msgstr ""
+
+#: ../bin/nova-api.py:69
+#, python-format
+msgid "No known API applications configured in %s."
+msgstr ""
+
+#: ../bin/nova-api.py:83
+#, python-format
+msgid "Starting nova-api node (version %s)"
+msgstr ""
+
+#: ../bin/nova-api.py:89
+#, python-format
+msgid "No paste configuration found for: %s"
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:84
+#, python-format
+msgid "Argument %(key)s value %(value)s is too short."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:89
+#, python-format
+msgid "Argument %(key)s value %(value)s contains invalid characters."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:94
+#, python-format
+msgid "Argument %(key)s value %(value)s starts with a hyphen."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:102
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:130
+#, python-format
+msgid "Argument %s is required."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:117
+#, python-format
+msgid ""
+"Argument %(key)s may not take value %(value)s. Valid values are ['true', "
+"'false']."
+msgstr ""
+
+#: ../plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py:163
+#, python-format
+msgid ""
+"Created VDI %(vdi_ref)s (%(label)s, %(size)s, %(read_only)s) on %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:67
+#, python-format
+msgid "Attempted to create non-unique name %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:73
+#, python-format
+msgid "instance %(name)s: not enough free memory"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:148
+#, python-format
+msgid "Starting VM %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:151
+#, python-format
+msgid "Spawning VM %(instance_name)s created %(vm_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:162
+#, python-format
+msgid "Invalid value for onset_files: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:167
+#, python-format
+msgid "Injecting file path: '%s'"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:180
+#, python-format
+msgid "Instance %s: booted"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:232
+#, python-format
+msgid "Instance not present %s"
+msgstr ""
+
+#. TODO(sirp): Add quiesce and VSS locking support when Windows support
+#. is added
+#: ../nova/virt/xenapi/vmops.py:261
+#, python-format
+msgid "Starting snapshot for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:269
+#, python-format
+msgid "Unable to Snapshot %(vm_ref)s: %(exc)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:280
+#, python-format
+msgid "Finished snapshot and upload for VM %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:356
+#, python-format
+msgid "VM %(vm)s already halted, skipping shutdown..."
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:389
+msgid "Removing kernel/ramdisk files"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:399
+msgid "kernel/ramdisk files removed"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:561
+#, python-format
+msgid ""
+"TIMEOUT: The call to %(method)s timed out. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:564
+#, python-format
+msgid ""
+"NOT IMPLEMENTED: The call to %(method)s is not supported by the agent. VM "
+"id=%(instance_id)s; args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:569
+#, python-format
+msgid ""
+"The call to %(method)s returned an error: %(e)s. VM id=%(instance_id)s; "
+"args=%(strargs)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/vmops.py:760
+#, python-format
+msgid "OpenSSL error: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:148
+#, python-format
+msgid "Running instances: %s"
+msgstr ""
+
+#: ../nova/tests/test_compute.py:154
+#, python-format
+msgid "After terminating instances: %s"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:45
+msgid "Template for script to run on cloudpipe instance boot"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:48
+msgid "Network to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:51
+msgid "Netmask to push into openvpn config"
+msgstr ""
+
+#: ../nova/cloudpipe/pipelib.py:97
+#, python-format
+msgid "Launching VPN for %s"
+msgstr ""
+
+#: ../nova/db/sqlalchemy/migration.py:35
+msgid "python-migrate is not installed. Exiting."
+msgstr ""
+
+#: ../nova/image/s3.py:99
+#, python-format
+msgid "Image %s could not be found"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:121
+msgid "Too many failed authentications."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:131
+#, python-format
+msgid ""
+"Access key %(access_key)s has had %(failures)d failed authentications and "
+"will be locked out for %(lock_mins)d minutes."
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:169 ../nova/objectstore/handler.py:140
+#, python-format
+msgid "Authentication Failure: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:182
+#, python-format
+msgid "Authenticated Request For %(uname)s:%(pname)s)"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:207
+#, python-format
+msgid "action: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:209
+#, python-format
+msgid "arg: %(key)s\t\tval: %(value)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:281
+#, python-format
+msgid ""
+"Unauthorized request for controller=%(controller)s and action=%(action)s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:314
+#, python-format
+msgid "InstanceNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:320
+#, python-format
+msgid "VolumeNotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:326
+#, python-format
+msgid "NotFound raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:329
+#, python-format
+msgid "ApiError raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:338
+#, python-format
+msgid "Unexpected error raised: %s"
+msgstr ""
+
+#: ../nova/api/ec2/__init__.py:343
+msgid "An unknown error has occurred. Please try your request again."
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:84
+#, python-format
+msgid "User %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:106 ../nova/auth/ldapdriver.py:232
+#, python-format
+msgid "Project can't be created because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:122 ../nova/auth/ldapdriver.py:243
+#, python-format
+msgid "Project can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:135 ../nova/auth/ldapdriver.py:229
+#, python-format
+msgid "Project can't be created because project %s already exists"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:157 ../nova/auth/ldapdriver.py:268
+#, python-format
+msgid "Project can't be modified because manager %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:245
+#, python-format
+msgid "User \"%s\" not found"
+msgstr ""
+
+#: ../nova/auth/dbdriver.py:248
+#, python-format
+msgid "Project \"%s\" not found"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:129
+msgid ""
+"Must specify xenapi_connection_url, xenapi_connection_username (optionally), "
+"and xenapi_connection_password to use connection_type=xenapi"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:311
+#, python-format
+msgid "Task [%(name)s] %(task)s status: success %(result)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:317
+#, python-format
+msgid "Task [%(name)s] %(task)s status: %(status)s %(error_info)s"
+msgstr ""
+
+#: ../nova/virt/xenapi_conn.py:331 ../nova/virt/xenapi_conn.py:344
+#, python-format
+msgid "Got exception: %s"
+msgstr ""
+
+#: ../nova/volume/san.py:67
+#, python-format
+msgid "Could not find iSCSI export for volume %s"
+msgstr ""
+
+#: ../nova/api/ec2/apirequest.py:100
+#, python-format
+msgid ""
+"Unsupported API request: controller = %(controller)s, action = %(action)s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:55
+#, python-format
+msgid "Caught error: %s"
+msgstr ""
+
+#: ../nova/api/openstack/__init__.py:76
+msgid "Including admin operations in API."
+msgstr ""
+
+#: ../nova/console/xvp.py:99
+msgid "Rebuilding xvp conf"
+msgstr ""
+
+#: ../nova/console/xvp.py:116
+#, python-format
+msgid "Re-wrote %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:121
+msgid "Stopping xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:134
+msgid "Starting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:141
+#, python-format
+msgid "Error starting xvp: %s"
+msgstr ""
+
+#: ../nova/console/xvp.py:144
+msgid "Restarting xvp"
+msgstr ""
+
+#: ../nova/console/xvp.py:146
+msgid "xvp not running..."
+msgstr ""
+
+#: ../bin/nova-manage.py:272
+msgid ""
+"The above error may show that the database has not been created.\n"
+"Please create a database using nova-manage sync db before running this "
+"command."
+msgstr ""
+
+#: ../bin/nova-manage.py:426
+msgid ""
+"No more networks available. If this is a new installation, you need\n"
+"to call something like this:\n"
+"\n"
+" nova-manage network create 10.0.0.0/8 10 64\n"
+"\n"
+msgstr ""
+
+#: ../bin/nova-manage.py:431
+msgid ""
+"The above error may show that the certificate db has not been created.\n"
+"Please create a database by running a nova-api server on this host."
+msgstr ""
+
+#: ../bin/nova-manage.py:447 ../bin/nova-manage.py:536
+msgid "network"
+msgstr ""
+
+#: ../bin/nova-manage.py:448
+msgid "IP address"
+msgstr ""
+
+#: ../bin/nova-manage.py:449
+msgid "MAC address"
+msgstr ""
+
+#: ../bin/nova-manage.py:450
+msgid "hostname"
+msgstr ""
+
+#: ../bin/nova-manage.py:451
+msgid "host"
+msgstr ""
+
+#: ../bin/nova-manage.py:537
+msgid "netmask"
+msgstr ""
+
+#: ../bin/nova-manage.py:538
+msgid "start address"
+msgstr ""
+
+#: ../nova/virt/disk.py:69
+#, python-format
+msgid "Failed to load partition: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:91
+#, python-format
+msgid "Failed to mount filesystem: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:124
+#, python-format
+msgid "nbd device %s did not show up"
+msgstr ""
+
+#: ../nova/virt/disk.py:128
+#, python-format
+msgid "Could not attach image to loopback: %s"
+msgstr ""
+
+#: ../nova/virt/disk.py:151
+msgid "No free nbd devices"
+msgstr ""
+
+#: ../doc/ext/nova_todo.py:46
+#, python-format
+msgid "%(filename)s, line %(line_info)d"
+msgstr ""
+
+#. FIXME(chiradeep): implement this
+#: ../nova/virt/hyperv.py:118
+msgid "In init host"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:131
+#, python-format
+msgid "Attempt to create duplicate vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:148
+#, python-format
+msgid "Starting VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:150
+#, python-format
+msgid "Started VM %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:152
+#, python-format
+msgid "spawn vm failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:169
+#, python-format
+msgid "Failed to create VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:188
+#, python-format
+msgid "Set memory for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:198
+#, python-format
+msgid "Set vcpus for vm %s..."
+msgstr ""
+
+#: ../nova/virt/hyperv.py:202
+#, python-format
+msgid "Creating disk for %(vm_name)s by attaching disk file %(vhdfile)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:227
+#, python-format
+msgid "Failed to add diskdrive to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:230
+#, python-format
+msgid "New disk drive path is %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:247
+#, python-format
+msgid "Failed to add vhd file to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:249
+#, python-format
+msgid "Created disk for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:253
+#, python-format
+msgid "Creating nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:272
+msgid "Failed creating a port on the external vswitch"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:273
+#, python-format
+msgid "Failed creating port for %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:276
+#, python-format
+msgid "Created switch port %(vm_name)s on switch %(ext_path)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:286
+#, python-format
+msgid "Failed to add nic to VM %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:288
+#, python-format
+msgid "Created nic for %s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:321
+#, python-format
+msgid "WMI job failed: %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:325
+#, python-format
+msgid "WMI job succeeded: %(desc)s, Elapsed=%(elap)s "
+msgstr ""
+
+#: ../nova/virt/hyperv.py:361
+#, python-format
+msgid "Got request to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:386
+#, python-format
+msgid "Failed to destroy vm %s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:393
+#, python-format
+msgid "Del: disk %(vhdfile)s vm %(instance_name)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:415
+#, python-format
+msgid ""
+"Got Info for vm %(instance_id)s: state=%(state)s, mem=%(memusage)s, "
+"num_cpu=%(numprocs)s, cpu_time=%(uptime)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:451
+#, python-format
+msgid "Successfully changed vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/virt/hyperv.py:454
+#, python-format
+msgid "Failed to change vm state of %(vm_name)s to %(req_state)s"
+msgstr ""
+
+#: ../nova/compute/api.py:71
+#, python-format
+msgid "Instance %d was not found in get_network_topic"
+msgstr ""
+
+#: ../nova/compute/api.py:77
+#, python-format
+msgid "Instance %d has no host"
+msgstr ""
+
+#: ../nova/compute/api.py:97
+#, python-format
+msgid "Quota exceeeded for %(pid)s, tried to run %(min_count)s instances"
+msgstr ""
+
+#: ../nova/compute/api.py:99
+#, python-format
+msgid ""
+"Instance quota exceeded. You can only run %s more instances of this type."
+msgstr ""
+
+#: ../nova/compute/api.py:112
+msgid "Creating a raw instance"
+msgstr ""
+
+#: ../nova/compute/api.py:160
+#, python-format
+msgid "Going to run %s instances..."
+msgstr ""
+
+#: ../nova/compute/api.py:187
+#, python-format
+msgid "Casting to scheduler for %(pid)s/%(uid)s's instance %(instance_id)s"
+msgstr ""
+
+#: ../nova/compute/api.py:292
+#, python-format
+msgid "Going to try to terminate %s"
+msgstr ""
+
+#: ../nova/compute/api.py:296
+#, python-format
+msgid "Instance %d was not found during terminate"
+msgstr ""
+
+#: ../nova/compute/api.py:301
+#, python-format
+msgid "Instance %d is already being terminated"
+msgstr ""
+
+#: ../nova/compute/api.py:481
+#, python-format
+msgid "Invalid device specified: %s. Example device: /dev/vdb"
+msgstr ""
+
+#: ../nova/compute/api.py:496
+msgid "Volume isn't attached to anything!"
+msgstr ""
+
+#: ../nova/rpc.py:98
+#, python-format
+msgid ""
+"AMQP server on %(fl_host)s:%(fl_port)d is unreachable. Trying again in "
+"%(fl_intv)d seconds."
+msgstr ""
+
+#: ../nova/rpc.py:103
+#, python-format
+msgid "Unable to connect to AMQP server after %d tries. Shutting down."
+msgstr ""
+
+#: ../nova/rpc.py:122
+msgid "Reconnected to queue"
+msgstr ""
+
+#: ../nova/rpc.py:129
+msgid "Failed to fetch message from queue"
+msgstr ""
+
+#: ../nova/rpc.py:159
+#, python-format
+msgid "Initing the Adapter Consumer for %s"
+msgstr ""
+
+#: ../nova/rpc.py:178
+#, python-format
+msgid "received %s"
+msgstr ""
+
+#. NOTE(vish): we may not want to ack here, but that means that bad
+#. messages stay in the queue indefinitely, so for now
+#. we just log the message and send an error string
+#. back to the caller
+#: ../nova/rpc.py:191
+#, python-format
+msgid "no method for message: %s"
+msgstr ""
+
+#: ../nova/rpc.py:192
+#, python-format
+msgid "No method for message: %s"
+msgstr ""
+
+#: ../nova/rpc.py:253
+#, python-format
+msgid "Returning exception %s to caller"
+msgstr ""
+
+#: ../nova/rpc.py:294
+#, python-format
+msgid "unpacked context: %s"
+msgstr ""
+
+#: ../nova/rpc.py:313
+msgid "Making asynchronous call..."
+msgstr ""
+
+#: ../nova/rpc.py:316
+#, python-format
+msgid "MSG_ID is %s"
+msgstr ""
+
+#: ../nova/rpc.py:354
+msgid "Making asynchronous cast..."
+msgstr ""
+
+#: ../nova/rpc.py:364
+#, python-format
+msgid "response %s"
+msgstr ""
+
+#: ../nova/rpc.py:373
+#, python-format
+msgid "topic is %s"
+msgstr ""
+
+#: ../nova/rpc.py:374
+#, python-format
+msgid "message %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:78
+#, python-format
+msgid "Recovering from a failed execute. Try number %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:87
+#, python-format
+msgid "volume group %s doesn't exist"
+msgstr ""
+
+#: ../nova/volume/driver.py:220
+#, python-format
+msgid "FAKE AOE: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:233
+msgid "Skipping ensure_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:279 ../nova/volume/driver.py:288
+msgid "Skipping remove_export. No iscsi_target "
+msgstr ""
+
+#: ../nova/volume/driver.py:347
+#, python-format
+msgid "FAKE ISCSI: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:359
+#, python-format
+msgid "rbd has no pool %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:414
+#, python-format
+msgid "Sheepdog is not working: %s"
+msgstr ""
+
+#: ../nova/volume/driver.py:416
+msgid "Sheepdog is not working"
+msgstr ""
+
+#: ../nova/wsgi.py:68
+#, python-format
+msgid "Starting %(arg0)s on %(host)s:%(port)s"
+msgstr ""
+
+#: ../nova/wsgi.py:147
+msgid "You must implement __call__"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:58
+msgid "leasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:73
+msgid "Adopted old lease or got a change of mac/hostname"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:80
+msgid "releasing ip"
+msgstr ""
+
+#: ../bin/nova-dhcpbridge.py:123
+#, python-format
+msgid ""
+"Called %(action)s for mac %(mac)s with ip %(ip)s and hostname %(hostname)s "
+"on interface %(interface)s"
+msgstr ""
+
+#: ../nova/virt/fake.py:239
+#, python-format
+msgid "Instance %s Not Found"
+msgstr ""
+
+#: ../nova/network/manager.py:153
+#, python-format
+msgid "Dissassociated %s stale fixed ip(s)"
+msgstr ""
+
+#: ../nova/network/manager.py:157
+msgid "setting network host"
+msgstr ""
+
+#: ../nova/network/manager.py:212
+#, python-format
+msgid "Leasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:216
+#, python-format
+msgid "IP %s leased that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:220
+#, python-format
+msgid "IP %(address)s leased to bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:228
+#, python-format
+msgid "IP %s leased that was already deallocated"
+msgstr ""
+
+#: ../nova/network/manager.py:233
+#, python-format
+msgid "Releasing IP %s"
+msgstr ""
+
+#: ../nova/network/manager.py:237
+#, python-format
+msgid "IP %s released that isn't associated"
+msgstr ""
+
+#: ../nova/network/manager.py:241
+#, python-format
+msgid "IP %(address)s released from bad mac %(inst_addr)s vs %(mac)s"
+msgstr ""
+
+#: ../nova/network/manager.py:244
+#, python-format
+msgid "IP %s released that was not leased"
+msgstr ""
+
+#: ../nova/network/manager.py:519
+msgid ""
+"The sum between the number of networks and the vlan start cannot be greater "
+"than 4094"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:57
+#, python-format
+msgid "Introducing %s..."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:74
+#, python-format
+msgid "Introduced %(label)s as %(sr_ref)s."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:78
+msgid "Unable to create Storage Repository"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:90
+#, python-format
+msgid "Unable to find SR from VBD %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:96
+#, python-format
+msgid "Forgetting SR %s ... "
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:101
+#, python-format
+msgid "Ignoring exception %(exc)s when getting PBDs for %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:107
+#, python-format
+msgid "Ignoring exception %(exc)s when unplugging PBD %(pbd)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:111
+#, python-format
+msgid "Forgetting SR %s done."
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:113
+#, python-format
+msgid "Ignoring exception %(exc)s when forgetting SR %(sr_ref)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:123
+#, python-format
+msgid "Unable to introduce VDI on SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:128
+#, python-format
+msgid "Unable to get record of VDI %s on"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:146
+#, python-format
+msgid "Unable to introduce VDI for SR %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:175
+#, python-format
+msgid "Unable to obtain target information %(device_path)s, %(mountpoint)s"
+msgstr ""
+
+#: ../nova/virt/xenapi/volume_utils.py:197
+#, python-format
+msgid "Mountpoint cannot be translated: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:262
+#, python-format
+msgid "Failed to decrypt private key: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:269
+#, python-format
+msgid "Failed to decrypt initialization vector: %s"
+msgstr ""
+
+#: ../nova/objectstore/image.py:277
+#, python-format
+msgid "Failed to decrypt image file %(image_file)s: %(err)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:106
+#, python-format
+msgid "Unknown S3 value type %r"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:137
+msgid "Authenticated request"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:182
+msgid "List of buckets requested"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:209
+#, python-format
+msgid "List keys for bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:217
+#, python-format
+msgid "Unauthorized attempt to access bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:235
+#, python-format
+msgid "Creating bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:245
+#, python-format
+msgid "Deleting bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:249
+#, python-format
+msgid "Unauthorized attempt to delete bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:273
+#, python-format
+msgid "Getting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:276
+#, python-format
+msgid "Unauthorized attempt to get object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:296
+#, python-format
+msgid "Putting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:299
+#, python-format
+msgid "Unauthorized attempt to upload object %(nm)s to bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:318
+#, python-format
+msgid "Deleting object: %(bname)s / %(nm)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:322
+#, python-format
+msgid "Unauthorized attempt to delete object %(nm)s from bucket %(bname)s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:396
+#, python-format
+msgid "Not authorized to upload image: invalid directory %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:404
+#, python-format
+msgid "Not authorized to upload image: unauthorized bucket %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:409
+#, python-format
+msgid "Starting image upload: %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:423
+#, python-format
+msgid "Not authorized to update attributes of image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:431
+#, python-format
+msgid "Toggling publicity flag of image %(image_id)s %(newstatus)r"
+msgstr ""
+
+#. other attributes imply update
+#: ../nova/objectstore/handler.py:436
+#, python-format
+msgid "Updating user fields on image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:450
+#, python-format
+msgid "Unauthorized attempt to delete image %s"
+msgstr ""
+
+#: ../nova/objectstore/handler.py:455
+#, python-format
+msgid "Deleted image: %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:259
+#, python-format
+msgid "Looking up user: %r"
+msgstr ""
+
+#: ../nova/auth/manager.py:263
+#, python-format
+msgid "Failed authorization for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:264
+#, python-format
+msgid "No user found for access key %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:270
+#, python-format
+msgid "Using project name = user name (%s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:277
+#, python-format
+msgid "failed authorization: no project named %(pjid)s (user=%(uname)s)"
+msgstr ""
+
+#: ../nova/auth/manager.py:279
+#, python-format
+msgid "No project called %s could be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:287
+#, python-format
+msgid ""
+"Failed authorization: user %(uname)s not admin and not member of project "
+"%(pjname)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:289
+#, python-format
+msgid "User %(uid)s is not a member of project %(pjid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:298 ../nova/auth/manager.py:309
+#, python-format
+msgid "Invalid signature for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:299 ../nova/auth/manager.py:310
+msgid "Signature does not match"
+msgstr ""
+
+#: ../nova/auth/manager.py:380
+msgid "Must specify project"
+msgstr ""
+
+#: ../nova/auth/manager.py:414
+#, python-format
+msgid "The %s role can not be found"
+msgstr ""
+
+#: ../nova/auth/manager.py:416
+#, python-format
+msgid "The %s role is global only"
+msgstr ""
+
+#: ../nova/auth/manager.py:420
+#, python-format
+msgid "Adding role %(role)s to user %(uid)s in project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:423
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:448
+#, python-format
+msgid "Removing role %(role)s from user %(uid)s on project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:451
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:515
+#, python-format
+msgid "Created project %(name)s with manager %(manager_user)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:533
+#, python-format
+msgid "modifying project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:545
+#, python-format
+msgid "Adding user %(uid)s to project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:566
+#, python-format
+msgid "Remove user %(uid)s from project %(pid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:592
+#, python-format
+msgid "Deleting project %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:650
+#, python-format
+msgid "Created user %(rvname)s (admin: %(rvadmin)r)"
+msgstr ""
+
+#: ../nova/auth/manager.py:659
+#, python-format
+msgid "Deleting user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:669
+#, python-format
+msgid "Access Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:671
+#, python-format
+msgid "Secret Key change for user %s"
+msgstr ""
+
+#: ../nova/auth/manager.py:673
+#, python-format
+msgid "Admin status set to %(admin)r for user %(uid)s"
+msgstr ""
+
+#: ../nova/auth/manager.py:722
+#, python-format
+msgid "No vpn data for project %s"
+msgstr ""
+
+#: ../nova/service.py:161
+#, python-format
+msgid "Starting %(topic)s node (version %(vcs_string)s)"
+msgstr ""
+
+#: ../nova/service.py:174
+msgid "Service killed that has no database entry"
+msgstr ""
+
+#: ../nova/service.py:195
+msgid "The service database object disappeared, Recreating it."
+msgstr ""
+
+#: ../nova/service.py:207
+msgid "Recovered model server connection!"
+msgstr ""
+
+#: ../nova/service.py:213
+msgid "model server went away"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:174
+#, python-format
+msgid "LDAP user %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:205
+#, python-format
+msgid "LDAP object for %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:348
+#, python-format
+msgid "User %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:472
+#, python-format
+msgid "Group can't be created because group %s already exists"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:478
+#, python-format
+msgid "Group can't be created because user %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:495
+#, python-format
+msgid "User %s can't be searched in group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:507
+#, python-format
+msgid "User %s can't be added to the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:510 ../nova/auth/ldapdriver.py:521
+#, python-format
+msgid "The group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:513
+#, python-format
+msgid "User %(uid)s is already a member of the group %(group_dn)s"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:524
+#, python-format
+msgid ""
+"User %s can't be removed from the group because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:528
+#, python-format
+msgid "User %s is not a member of the group"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:542
+#, python-format
+msgid ""
+"Attempted to remove the last member of a group. Deleting the group at %s "
+"instead."
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:549
+#, python-format
+msgid "User %s can't be removed from all because the user doesn't exist"
+msgstr ""
+
+#: ../nova/auth/ldapdriver.py:564
+#, python-format
+msgid "Group at dn %s doesn't exist"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:40
+#, python-format
+msgid "Found non-unique network for bridge %s"
+msgstr ""
+
+#: ../nova/virt/xenapi/network_utils.py:43
+#, python-format
+msgid "Found no network for bridge %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:97
+#, python-format
+msgid "Creating new user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:105
+#, python-format
+msgid "Deleting user: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:127
+#, python-format
+msgid "Adding role %(role)s to user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:131
+#, python-format
+msgid "Adding sitewide role %(role)s to user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:137
+#, python-format
+msgid "Removing role %(role)s from user %(user)s for project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:141
+#, python-format
+msgid "Removing sitewide role %(role)s from user %(user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:146 ../nova/api/ec2/admin.py:223
+msgid "operation must be add or remove"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:159
+#, python-format
+msgid "Getting x509 for user: %(name)s on project: %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:177
+#, python-format
+msgid "Create project %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:190
+#, python-format
+msgid "Modify project: %(name)s managed by %(manager_user)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:200
+#, python-format
+msgid "Delete project: %s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:214
+#, python-format
+msgid "Adding user %(user)s to project %(project)s"
+msgstr ""
+
+#: ../nova/api/ec2/admin.py:218
+#, python-format
+msgid "Removing user %(user)s from project %(project)s"
+msgstr ""
diff --git a/run_tests.sh b/run_tests.sh
index b8078e150..8f2b51757 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -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
diff --git a/setup.py b/setup.py
index c165f40d7..8121e250b 100644
--- a/setup.py
+++ b/setup.py
@@ -124,7 +124,6 @@ setup(name='nova',
'bin/nova-dhcpbridge',
'bin/nova-direct-api',
'bin/nova-import-canonical-imagestore',
- 'bin/nova-instancemonitor',
'bin/nova-logspool',
'bin/nova-manage',
'bin/nova-network',
diff --git a/smoketests/test_netadmin.py b/smoketests/test_netadmin.py
index 60086f065..de69c98a2 100644
--- a/smoketests/test_netadmin.py
+++ b/smoketests/test_netadmin.py
@@ -115,7 +115,8 @@ class SecurityGroupTests(base.UserSmokeTestCase):
if not instance_id:
return False
if instance_id != self.data['instance'].id:
- raise Exception("Wrong instance id")
+ raise Exception("Wrong instance id. Expected: %s, Got: %s" %
+ (self.data['instance'].id, instance_id))
return True
def test_001_can_create_security_group(self):
diff --git a/smoketests/test_sysadmin.py b/smoketests/test_sysadmin.py
index 268d9865b..454f6f1d5 100644
--- a/smoketests/test_sysadmin.py
+++ b/smoketests/test_sysadmin.py
@@ -103,27 +103,48 @@ class ImageTests(base.UserSmokeTestCase):
'launchPermission')
self.assert_(attrs.name, 'launch_permission')
- def test_009_can_modify_image_launch_permission(self):
+ def test_009_can_add_image_launch_permission(self):
+ image = self.conn.get_image(self.data['image_id'])
+ self.assertEqual(image.id, self.data['image_id'])
+ self.assertEqual(image.is_public, False)
self.conn.modify_image_attribute(image_id=self.data['image_id'],
operation='add',
attribute='launchPermission',
groups='all')
image = self.conn.get_image(self.data['image_id'])
self.assertEqual(image.id, self.data['image_id'])
+ self.assertEqual(image.is_public, True)
def test_010_can_see_launch_permission(self):
attrs = self.conn.get_image_attribute(self.data['image_id'],
'launchPermission')
- self.assert_(attrs.name, 'launch_permission')
- self.assert_(attrs.attrs['groups'][0], 'all')
+ self.assertEqual(attrs.name, 'launch_permission')
+ self.assertEqual(attrs.attrs['groups'][0], 'all')
+
+ def test_011_can_remove_image_launch_permission(self):
+ image = self.conn.get_image(self.data['image_id'])
+ self.assertEqual(image.id, self.data['image_id'])
+ self.assertEqual(image.is_public, True)
+ self.conn.modify_image_attribute(image_id=self.data['image_id'],
+ operation='remove',
+ attribute='launchPermission',
+ groups='all')
+ image = self.conn.get_image(self.data['image_id'])
+ self.assertEqual(image.id, self.data['image_id'])
+ self.assertEqual(image.is_public, False)
+
+ def test_012_private_image_shows_in_list(self):
+ images = self.conn.get_all_images()
+ image_ids = [image.id for image in images]
+ self.assertTrue(self.data['image_id'] in image_ids)
- def test_011_user_can_deregister_kernel(self):
+ def test_013_user_can_deregister_kernel(self):
self.assertTrue(self.conn.deregister_image(self.data['kernel_id']))
- def test_012_can_deregister_image(self):
+ def test_014_can_deregister_image(self):
self.assertTrue(self.conn.deregister_image(self.data['image_id']))
- def test_013_can_delete_bundle(self):
+ def test_015_can_delete_bundle(self):
self.assertTrue(self.delete_bundle_bucket(TEST_BUCKET))
diff --git a/tools/esx/guest_tool.py b/tools/esx/guest_tool.py
index 13b0f8d33..97b5302ba 100644
--- a/tools/esx/guest_tool.py
+++ b/tools/esx/guest_tool.py
@@ -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"))
diff --git a/tools/eventlet-patch b/tools/eventlet-patch
deleted file mode 100644
index c87c5f279..000000000
--- a/tools/eventlet-patch
+++ /dev/null
@@ -1,24 +0,0 @@
-# HG changeset patch
-# User Soren Hansen <soren@linux2go.dk>
-# Date 1297678255 -3600
-# Node ID 4c846d555010bb5a91ab4da78dfe596451313742
-# Parent 5b7e9946c79f005c028eb63207cf5eb7bb21d1c3
-Don't attempt to wrap GreenPipes in GreenPipe
-
-If the os module is monkeypatched, Python's standard subprocess module
-will return greenio.GreenPipe instances for Popen objects' stdin, stdout,
-and stderr attributes. However, eventlet.green.subprocess tries to wrap
-these attributes in another greenio.GreenPipe, which GreenPipe refuses.
-
-diff -r 5b7e9946c79f -r 4c846d555010 eventlet/green/subprocess.py
---- a/eventlet/green/subprocess.py Sat Feb 05 13:05:05 2011 -0800
-+++ b/eventlet/green/subprocess.py Mon Feb 14 11:10:55 2011 +0100
-@@ -27,7 +27,7 @@
- # eventlet.processes.Process.run() method.
- for attr in "stdin", "stdout", "stderr":
- pipe = getattr(self, attr)
-- if pipe is not None:
-+ if pipe is not None and not type(pipe) == greenio.GreenPipe:
- wrapped_pipe = greenio.GreenPipe(pipe, pipe.mode, bufsize)
- setattr(self, attr, wrapped_pipe)
- __init__.__doc__ = subprocess_orig.Popen.__init__.__doc__
diff --git a/tools/install_venv.py b/tools/install_venv.py
index f4b6583ed..3c2f6979f 100644
--- a/tools/install_venv.py
+++ b/tools/install_venv.py
@@ -31,7 +31,6 @@ import sys
ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
VENV = os.path.join(ROOT, '.nova-venv')
PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
-TWISTED_NOVA = 'http://nova.openstack.org/Twisted-10.0.0Nova.tar.gz'
PY_VERSION = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
@@ -106,20 +105,12 @@ def install_dependencies(venv=VENV):
'greenlet'], redirect_output=False)
run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv, '-r',
PIP_REQUIRES], redirect_output=False)
- run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv,
- TWISTED_NOVA], redirect_output=False)
# Tell the virtual env how to "import nova"
pthfile = os.path.join(venv, "lib", PY_VERSION, "site-packages",
"nova.pth")
f = open(pthfile, 'w')
f.write("%s\n" % ROOT)
- # Patch eventlet (see FAQ # 1485)
- patchsrc = os.path.join(ROOT, 'tools', 'eventlet-patch')
- patchfile = os.path.join(venv, "lib", PY_VERSION, "site-packages",
- "eventlet", "green", "subprocess.py")
- patch_cmd = "patch %s %s" % (patchfile, patchsrc)
- os.system(patch_cmd)
def print_help():
diff --git a/tools/pip-requires b/tools/pip-requires
index dec93c351..23e707034 100644
--- a/tools/pip-requires
+++ b/tools/pip-requires
@@ -9,7 +9,7 @@ boto==1.9b
carrot==0.10.5
eventlet
lockfile==0.8
-python-novaclient==2.5.7
+python-novaclient==2.5.9
python-daemon==1.5.5
python-gflags==1.3
redis==2.0.0
@@ -20,13 +20,13 @@ mox==0.5.3
greenlet==0.3.1
nose
bzr
-Twisted>=10.1.0
PasteDeploy
paste
sqlalchemy-migrate
netaddr
sphinx
glance
+xattr>=0.6.0
nova-adminclient
suds==0.4
coverage