summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Authors1
-rwxr-xr-xbin/nova-manage99
-rw-r--r--doc/source/devref/zone.rst127
-rw-r--r--doc/source/man/novamanage.rst10
-rw-r--r--nova/virt/xenapi/vm_utils.py17
5 files changed, 199 insertions, 55 deletions
diff --git a/Authors b/Authors
index 48b912184..2de4fb955 100644
--- a/Authors
+++ b/Authors
@@ -31,6 +31,7 @@ Jay Pipes <jaypipes@gmail.com>
Jesse Andrews <anotherjesse@gmail.com>
Joe Heck <heckj@mac.com>
Joel Moore <joelbm24@gmail.com>
+Johannes Erdfelt <johannes.erdfelt@rackspace.com>
John Dewey <john@dewey.ws>
John Tran <jtran@attinteractive.com>
Jonathan Bryce <jbryce@jbryce.com>
diff --git a/bin/nova-manage b/bin/nova-manage
index bac291c01..adc631318 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -570,6 +570,49 @@ class NetworkCommands(object):
class VmCommands(object):
"""Class for mangaging VM instances."""
+ def list(self, host=None):
+ """Show a list of all instances
+
+ :param host: show all instance on specified host.
+ :param instance: show specificed instance.
+ """
+ print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
+ " %-10s %-10s %-10s %-5s" % (
+ _('instance'),
+ _('node'),
+ _('type'),
+ _('state'),
+ _('launched'),
+ _('image'),
+ _('kernel'),
+ _('ramdisk'),
+ _('project'),
+ _('user'),
+ _('zone'),
+ _('index'))
+
+ if host == None:
+ instances = db.instance_get_all(context.get_admin_context())
+ else:
+ instances = db.instance_get_all_by_host(
+ context.get_admin_context(), host)
+
+ for instance in instances:
+ print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
+ " %-10s %-10s %-10s %-5d" % (
+ instance['hostname'],
+ instance['host'],
+ instance['instance_type'],
+ instance['state_description'],
+ instance['launched_at'],
+ instance['image_id'],
+ instance['kernel_id'],
+ instance['ramdisk_id'],
+ instance['project_id'],
+ instance['user_id'],
+ instance['availability_zone'],
+ instance['launch_index'])
+
def live_migration(self, ec2_id, dest):
"""Migrates a running instance to a new machine.
@@ -701,15 +744,6 @@ class ServiceCommands(object):
{"method": "update_available_resource"})
-class LogCommands(object):
- def request(self, request_id, logfile='/var/log/nova.log'):
- """Show all fields in the log for the given request. Assumes you
- haven't changed the log format too much.
- ARGS: request_id [logfile]"""
- lines = utils.execute("cat %s | grep '\[%s '" % (logfile, request_id))
- print re.sub('#012', "\n", "\n".join(lines))
-
-
class DbCommands(object):
"""Class for managing the database."""
@@ -725,49 +759,6 @@ class DbCommands(object):
print migration.db_version()
-class InstanceCommands(object):
- """Class for managing instances."""
-
- def list(self, host=None, instance=None):
- """Show a list of all instances"""
- print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
- " %-10s %-10s %-10s %-5s" % (
- _('instance'),
- _('node'),
- _('type'),
- _('state'),
- _('launched'),
- _('image'),
- _('kernel'),
- _('ramdisk'),
- _('project'),
- _('user'),
- _('zone'),
- _('index'))
-
- if host == None:
- instances = db.instance_get_all(context.get_admin_context())
- else:
- instances = db.instance_get_all_by_host(
- context.get_admin_context(), host)
-
- for instance in instances:
- print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
- " %-10s %-10s %-10s %-5d" % (
- instance['hostname'],
- instance['host'],
- instance['instance_type'],
- instance['state_description'],
- instance['launched_at'],
- instance['image_id'],
- instance['kernel_id'],
- instance['ramdisk_id'],
- instance['project_id'],
- instance['user_id'],
- instance['availability_zone'],
- instance['launch_index'])
-
-
class VolumeCommands(object):
"""Methods for dealing with a cloud in an odd state"""
@@ -1049,13 +1040,11 @@ CATEGORIES = [
('network', NetworkCommands),
('vm', VmCommands),
('service', ServiceCommands),
- ('log', LogCommands),
('db', DbCommands),
('volume', VolumeCommands),
('instance_type', InstanceTypeCommands),
('image', ImageCommands),
- ('flavor', InstanceTypeCommands),
- ('instance', InstanceCommands)]
+ ('flavor', InstanceTypeCommands)]
def lazy_match(name, key_value_tuples):
diff --git a/doc/source/devref/zone.rst b/doc/source/devref/zone.rst
new file mode 100644
index 000000000..3dd9d37d3
--- /dev/null
+++ b/doc/source/devref/zone.rst
@@ -0,0 +1,127 @@
+..
+ Copyright 2010-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.
+
+Zones
+=====
+
+A Nova deployment is called a Zone. At the very least a Zone requires an API node, a Scheduler node, a database and RabbitMQ. Pushed further a Zone may contain many API nodes, many Scheduler, Volume, Network and Compute nodes as well as a cluster of databases and RabbitMQ servers. A Zone allows you to partition your deployments into logical groups for load balancing and instance distribution.
+
+The idea behind Zones is, if a particular deployment is not capable of servicing a particular request, the request may be forwarded to (child) Zones for possible processing. Zones may be nested in a tree fashion.
+
+Zones only know about their immediate children, they do not know about their parent Zones and may in fact have more than one parent. Likewise, a Zone's children may themselves have child Zones.
+
+Zones share nothing. They communicate via the public OpenStack API only. No database, queue, user or project definition is shared between Zones.
+
+
+Capabilities
+------------
+Routing between Zones is based on the Capabilities of that Zone. Capabilities are nothing more than key/value pairs. Values are multi-value, with each value separated with a semicolon (`;`). When expressed as a string they take the form:
+
+::
+
+ key=value;value;value, key=value;value;value
+
+Zones have Capabilities which are general to the Zone and are set via `--zone-capabilities` flag. Zones also have dynamic per-service Capabilities. Services derived from `nova.manager.SchedulerDependentManager` (such as Compute, Volume and Network) can set these capabilities by calling the `update_service_capabilities()` method on their `Manager` base class. These capabilities will be periodically sent to the Scheduler service automatically. The rate at which these updates are sent is controlled by the `--periodic_interval` flag.
+
+Flow within a Zone
+------------------
+The brunt of the work within a Zone is done in the Scheduler Service. The Scheduler is responsible for:
+- collecting capability messages from the Compute, Volume and Network nodes,
+- polling the child Zones for their status and
+- providing data to the Distributed Scheduler for performing load balancing calculations
+
+Inter-service communication within a Zone is done with RabbitMQ. Each class of Service (Compute, Volume and Network) has both a named message exchange (particular to that host) and a general message exchange (particular to that class of service). Messages sent to these exchanges are picked off in round-robin fashion. Zones introduce a new fan-out exchange per service. Messages sent to the fan-out exchange are picked up by all services of a particular class. This fan-out exchange is used by the Scheduler services to receive capability messages from the Compute, Volume and Network nodes.
+
+These capability messages are received by the Scheduler services and stored in the `ZoneManager` object. The SchedulerManager object has a reference to the `ZoneManager` it can use for load balancing.
+
+The `ZoneManager` also polls the child Zones periodically to gather their capabilities to aid in decision making. This is done via the OpenStack API `/v1.0/zones/info` REST call. This also captures the name of each child Zone. The Zone name is set via the `--zone-name` flag (and defaults to "nova").
+
+Zone administrative functions
+-----------------------------
+Zone administrative operations are usually done using python-novaclient_
+
+.. _python-novaclient: https://github.com/rackspace/python-novaclient
+
+In order to use the Zone operations, be sure to enable administrator operations in OpenStack API by setting the `--allow_admin_api=true` flag.
+
+Finally you need to enable Zone Forwarding. This will be used by the Distributed Scheduler initiative currently underway. Set `--enable_zone_routing=true` to enable this feature.
+
+Find out about this Zone
+------------------------
+In any Zone you can find the Zone's name and capabilities with the ``nova zone-info`` command.
+
+::
+
+ alice@novadev:~$ nova zone-info
+ +-----------------+---------------+
+ | Property | Value |
+ +-----------------+---------------+
+ | compute_cpu | 0.7,0.7 |
+ | compute_disk | 123000,123000 |
+ | compute_network | 800,800 |
+ | hypervisor | xenserver |
+ | name | nova |
+ | network_cpu | 0.7,0.7 |
+ | network_disk | 123000,123000 |
+ | network_network | 800,800 |
+ | os | linux |
+ +-----------------+---------------+
+
+This equates to a GET operation on `.../zones/info`. If you have no child Zones defined you'll usually only get back the default `name`, `hypervisor` and `os` capabilities. Otherwise you'll get back a tuple of min, max values for each capabilities of all the hosts of all the services running in the child zone. These take the `<service>_<capability> = <min>,<max>` format.
+
+Adding a child Zone
+-------------------
+Any Zone can be a parent Zone. Children are associated to a Zone. The Zone where this command originates from is known as the Parent Zone. Routing is only ever conducted from a Zone to its children, never the other direction. From a parent zone you can add a child zone with the following command:
+
+::
+
+ nova zone-add <child zone api url> <username> <nova api key>
+
+You can get the `child zone api url`, `nova api key` and `username` from the `novarc` file in the child zone. For example:
+
+::
+
+ export NOVA_API_KEY="3bd1af06-6435-4e23-a827-413b2eb86934"
+ export NOVA_USERNAME="alice"
+ export NOVA_URL="http://192.168.2.120:8774/v1.0/"
+
+
+This equates to a POST operation to `.../zones/` to add a new zone. No connection attempt to the child zone is done when this command. It only puts an entry in the db at this point. After about 30 seconds the `ZoneManager` in the Scheduler services will attempt to talk to the child zone and get its information.
+
+Getting a list of child Zones
+-----------------------------
+
+::
+
+ nova zone-list
+
+ alice@novadev:~$ nova zone-list
+ +----+-------+-----------+--------------------------------------------+---------------------------------+
+ | ID | Name | Is Active | Capabilities | API URL |
+ +----+-------+-----------+--------------------------------------------+---------------------------------+
+ | 2 | zone1 | True | hypervisor=xenserver;kvm, os=linux;windows | http://192.168.2.108:8774/v1.0/ |
+ | 3 | zone2 | True | hypervisor=xenserver;kvm, os=linux;windows | http://192.168.2.115:8774/v1.0/ |
+ +----+-------+-----------+--------------------------------------------+---------------------------------+
+
+This equates to a GET operation to `.../zones`.
+
+Removing a child Zone
+---------------------
+::
+
+ nova zone-delete <N>
+
+This equates to a DELETE call to `.../zones/N`. The Zone with ID=N will be removed. This will only remove the zone entry from the current (parent) Zone, no child Zones are affected. Removing a Child Zone doesn't affect any other part of the hierarchy.
diff --git a/doc/source/man/novamanage.rst b/doc/source/man/novamanage.rst
index 1d8446f08..9c54f3608 100644
--- a/doc/source/man/novamanage.rst
+++ b/doc/source/man/novamanage.rst
@@ -240,6 +240,16 @@ Nova Images
Converts all images in directory from the old (Bexar) format to the new format.
+Nova VM
+~~~~~~~~~~~
+
+``nova-manage vm list [host]``
+ Show a list of all instances. Accepts optional hostname (to show only instances on specific host).
+
+``nova-manage live-migration <ec2_id> <destination host name>``
+ Live migrate instance from current host to destination host. Requires instance id (which comes from euca-describe-instance) and destination host name (which can be found from nova-manage service list).
+
+
FILES
========
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 46fc6baa4..d2045a557 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -49,6 +49,8 @@ LOG = logging.getLogger("nova.virt.xenapi.vm_utils")
FLAGS = flags.FLAGS
flags.DEFINE_string('default_os_type', 'linux', 'Default OS type')
+flags.DEFINE_integer('block_device_creation_timeout', 10,
+ 'time to wait for a block device to be created')
XENAPI_POWER_STATE = {
'Halted': power_state.SHUTDOWN,
@@ -896,6 +898,16 @@ def remap_vbd_dev(dev):
return remapped_dev
+def _wait_for_device(dev):
+ """Wait for device node to appear"""
+ for i in xrange(0, FLAGS.block_device_creation_timeout):
+ if os.path.exists('/dev/%s' % dev):
+ return
+ time.sleep(1)
+
+ raise StorageError(_('Timeout waiting for device %s to be created') % dev)
+
+
def with_vdi_attached_here(session, vdi_ref, read_only, f):
this_vm_ref = get_this_vm_ref(session)
vbd_rec = {}
@@ -924,6 +936,11 @@ def with_vdi_attached_here(session, vdi_ref, read_only, f):
if dev != orig_dev:
LOG.debug(_('VBD %(vbd_ref)s plugged into wrong dev, '
'remapping to %(dev)s') % locals())
+ if dev != 'autodetect':
+ # NOTE(johannes): Unit tests will end up with a device called
+ # 'autodetect' which obviously won't exist. It's not ideal,
+ # but the alternatives were much messier
+ _wait_for_device(dev)
return f(dev)
finally:
LOG.debug(_('Destroying VBD for VDI %s ... '), vdi_ref)