summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorTrey Morris <trey.morris@rackspace.com>2011-03-28 12:13:20 -0500
committerTrey Morris <trey.morris@rackspace.com>2011-03-28 12:13:20 -0500
commit7eedf3f69ca1bbd1f44252fa01fb4f2676735eb2 (patch)
tree33c3983537da1d894caa6b390b5c488511df83c4 /bin
parent57890776d0d7e9172b1fa056076ce28ae4b34b7b (diff)
parented12a2cd2beef77d1c7e9d16771e766aa068530d (diff)
downloadnova-7eedf3f69ca1bbd1f44252fa01fb4f2676735eb2.tar.gz
nova-7eedf3f69ca1bbd1f44252fa01fb4f2676735eb2.tar.xz
nova-7eedf3f69ca1bbd1f44252fa01fb4f2676735eb2.zip
merge with trunk
Diffstat (limited to 'bin')
-rwxr-xr-xbin/nova-ajax-console-proxy16
-rwxr-xr-xbin/nova-api50
-rwxr-xr-xbin/nova-dhcpbridge2
-rwxr-xr-xbin/nova-direct-api37
-rwxr-xr-xbin/nova-instancemonitor2
-rwxr-xr-xbin/nova-manage408
-rwxr-xr-xbin/nova-objectstore15
-rwxr-xr-xbin/stack14
8 files changed, 471 insertions, 73 deletions
diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy
index 1e11c6d58..b4ba157e1 100755
--- a/bin/nova-ajax-console-proxy
+++ b/bin/nova-ajax-console-proxy
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
@@ -63,10 +63,16 @@ class AjaxConsoleProxy(object):
def __call__(self, env, start_response):
try:
- req_url = '%s://%s%s?%s' % (env['wsgi.url_scheme'],
- env['HTTP_HOST'],
- env['PATH_INFO'],
- env['QUERY_STRING'])
+ if 'QUERY_STRING' in env:
+ req_url = '%s://%s%s?%s' % (env['wsgi.url_scheme'],
+ env['HTTP_HOST'],
+ env['PATH_INFO'],
+ env['QUERY_STRING'])
+ else:
+ req_url = '%s://%s%s' % (env['wsgi.url_scheme'],
+ env['HTTP_HOST'],
+ env['PATH_INFO'])
+
if 'HTTP_REFERER' in env:
auth_url = env['HTTP_REFERER']
else:
diff --git a/bin/nova-api b/bin/nova-api
index cf140570a..a1088c23d 100755
--- a/bin/nova-api
+++ b/bin/nova-api
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
@@ -36,50 +36,18 @@ gettext.install('nova', unicode=1)
from nova import flags
from nova import log as logging
+from nova import service
+from nova import utils
from nova import version
from nova import wsgi
+
LOG = logging.getLogger('nova.api')
FLAGS = flags.FLAGS
-flags.DEFINE_string('ec2_listen', "0.0.0.0",
- 'IP address for EC2 API to listen')
-flags.DEFINE_integer('ec2_listen_port', 8773, 'port for ec2 api to listen')
-flags.DEFINE_string('osapi_listen', "0.0.0.0",
- 'IP address for OpenStack API to listen')
-flags.DEFINE_integer('osapi_listen_port', 8774, 'port for os api to listen')
-flags.DEFINE_flag(flags.HelpFlag())
-flags.DEFINE_flag(flags.HelpshortFlag())
-flags.DEFINE_flag(flags.HelpXMLFlag())
-
-API_ENDPOINTS = ['ec2', 'osapi']
-
-
-def run_app(paste_config_file):
- LOG.debug(_("Using paste.deploy config at: %s"), paste_config_file)
- apps = []
- for api in API_ENDPOINTS:
- config = wsgi.load_paste_configuration(paste_config_file, api)
- if config is None:
- LOG.debug(_("No paste configuration for app: %s"), api)
- continue
- LOG.debug(_("App Config: %(api)s\n%(config)r") % locals())
- LOG.info(_("Running %s API"), api)
- app = wsgi.load_paste_app(paste_config_file, api)
- apps.append((app, getattr(FLAGS, "%s_listen_port" % api),
- getattr(FLAGS, "%s_listen" % api)))
- if len(apps) == 0:
- LOG.error(_("No known API applications configured in %s."),
- paste_config_file)
- return
-
- server = wsgi.Server()
- for app in apps:
- server.start(*app)
- server.wait()
-
if __name__ == '__main__':
+ utils.default_flagfile()
FLAGS(sys.argv)
logging.setup()
LOG.audit(_("Starting nova-api node (version %s)"),
@@ -88,8 +56,6 @@ if __name__ == '__main__':
for flag in FLAGS:
flag_get = FLAGS.get(flag, None)
LOG.debug("%(flag)s : %(flag_get)s" % locals())
- conf = wsgi.paste_config_file('nova-api.conf')
- if conf:
- run_app(conf)
- else:
- LOG.error(_("No paste configuration found for: %s"), 'nova-api.conf')
+
+ service = service.serve_wsgi(service.ApiService)
+ service.wait()
diff --git a/bin/nova-dhcpbridge b/bin/nova-dhcpbridge
index 3dd9de367..7ef51feba 100755
--- a/bin/nova-dhcpbridge
+++ b/bin/nova-dhcpbridge
@@ -94,7 +94,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_hosts(ctxt, network_ref['id'])
+ return linux_net.get_dhcp_leases(ctxt, network_ref['id'])
def main():
diff --git a/bin/nova-direct-api b/bin/nova-direct-api
index bf29d9a5e..83ec72722 100755
--- a/bin/nova-direct-api
+++ b/bin/nova-direct-api
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
@@ -34,12 +34,14 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
gettext.install('nova', unicode=1)
+from nova import compute
from nova import flags
from nova import log as logging
+from nova import network
from nova import utils
+from nova import volume
from nova import wsgi
from nova.api import direct
-from nova.compute import api as compute_api
FLAGS = flags.FLAGS
@@ -50,13 +52,42 @@ flags.DEFINE_flag(flags.HelpshortFlag())
flags.DEFINE_flag(flags.HelpXMLFlag())
+# An example of an API that only exposes read-only methods.
+# In this case we're just limiting which methods are exposed.
+class ReadOnlyCompute(direct.Limited):
+ """Read-only Compute API."""
+
+ _allowed = ['get', 'get_all', 'get_console_output']
+
+
+# An example of an API that provides a backwards compatibility layer.
+# In this case we're overwriting the implementation to ensure
+# compatibility with an older version. In reality we would want the
+# "description=None" to be part of the actual API so that code
+# like this isn't even necessary, but this example shows what one can
+# do if that isn't the situation.
+class VolumeVersionOne(direct.Limited):
+ _allowed = ['create', 'delete', 'update', 'get']
+
+ def create(self, context, size, name):
+ self.proxy.create(context, size, name, description=None)
+
+
if __name__ == '__main__':
utils.default_flagfile()
FLAGS(sys.argv)
logging.setup()
- direct.register_service('compute', compute_api.API())
+ direct.register_service('compute', compute.API())
+ direct.register_service('volume', volume.API())
+ direct.register_service('network', network.API())
direct.register_service('reflect', direct.Reflection())
+
+ # Here is how we could expose the code in the examples above.
+ #direct.register_service('compute-readonly',
+ # ReadOnlyCompute(compute.API()))
+ #direct.register_service('volume-v1', VolumeVersionOne(volume.API()))
+
router = direct.Router()
with_json = direct.JsonParamsMiddleware(router)
with_req = direct.PostParamsMiddleware(with_json)
diff --git a/bin/nova-instancemonitor b/bin/nova-instancemonitor
index 24cc9fd23..b9d4e49d7 100755
--- a/bin/nova-instancemonitor
+++ b/bin/nova-instancemonitor
@@ -50,7 +50,7 @@ if __name__ == '__main__':
if __name__ == '__builtin__':
LOG.warn(_('Starting instance monitor'))
- # pylint: disable-msg=C0103
+ # pylint: disable=C0103
monitor = monitor.InstanceMonitor()
# This is the parent service that twistd will be looking for when it
diff --git a/bin/nova-manage b/bin/nova-manage
index dd0f00c85..b63c7eb2a 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -55,6 +55,8 @@
import datetime
import gettext
+import glob
+import json
import os
import re
import sys
@@ -81,9 +83,10 @@ from nova import log as logging
from nova import quota
from nova import rpc
from nova import utils
-from nova.api.ec2.cloud import ec2_id_to_id
+from nova.api.ec2 import ec2utils
from nova.auth import manager
from nova.cloudpipe import pipelib
+from nova.compute import instance_types
from nova.db import migration
FLAGS = flags.FLAGS
@@ -93,6 +96,8 @@ flags.DECLARE('network_size', 'nova.network.manager')
flags.DECLARE('vlan_start', 'nova.network.manager')
flags.DECLARE('vpn_start', 'nova.network.manager')
flags.DECLARE('fixed_range_v6', 'nova.network.manager')
+flags.DECLARE('images_path', 'nova.image.local')
+flags.DECLARE('libvirt_type', 'nova.virt.libvirt_conn')
flags.DEFINE_flag(flags.HelpFlag())
flags.DEFINE_flag(flags.HelpshortFlag())
flags.DEFINE_flag(flags.HelpXMLFlag())
@@ -103,7 +108,7 @@ def param2id(object_id):
args: [object_id], e.g. 'vol-0000000a' or 'volume-0000000a' or '10'
"""
if '-' in object_id:
- return ec2_id_to_id(object_id)
+ return ec2utils.ec2_id_to_id(object_id)
else:
return int(object_id)
@@ -272,7 +277,7 @@ def _db_error(caught_exception):
print caught_exception
print _("The above error may show that the database has not "
"been created.\nPlease create a database using "
- "nova-manage sync db before running this command.")
+ "'nova-manage db sync' before running this command.")
exit(1)
@@ -433,6 +438,8 @@ class ProjectCommands(object):
"been created.\nPlease create a database by running a "
"nova-api server on this host.")
+AccountCommands = ProjectCommands
+
class FixedIpCommands(object):
"""Class for managing fixed ip."""
@@ -440,10 +447,15 @@ class FixedIpCommands(object):
def list(self, host=None):
"""Lists all fixed ips (optionally by host) arguments: [host]"""
ctxt = context.get_admin_context()
- if host == None:
- fixed_ips = db.fixed_ip_get_all(ctxt)
- else:
- fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host)
+
+ try:
+ if host == None:
+ fixed_ips = db.fixed_ip_get_all(ctxt)
+ else:
+ fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host)
+ except exception.NotFound as ex:
+ print "error: %s" % ex
+ sys.exit(2)
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (_('network'),
_('IP address'),
@@ -460,9 +472,9 @@ class FixedIpCommands(object):
host = instance['host']
mac_address = instance['mac_address']
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (
- fixed_ip['network']['cidr'],
- fixed_ip['address'],
- mac_address, hostname, host)
+ fixed_ip['network']['cidr'],
+ fixed_ip['address'],
+ mac_address, hostname, host)
class FloatingIpCommands(object):
@@ -508,11 +520,12 @@ class NetworkCommands(object):
vpn_start=None, fixed_range_v6=None, label='public',
flat_network_bridge=None):
"""Creates fixed ips for host by range
- arguments: [fixed_range=FLAG], [num_networks=FLAG],
+ arguments: fixed_range=FLAG, [num_networks=FLAG],
[network_size=FLAG], [vlan_start=FLAG],
[vpn_start=FLAG], [fixed_range_v6=FLAG]"""
if not fixed_range:
- fixed_range = FLAGS.fixed_range
+ raise TypeError(_('Fixed range in the form of 10.0.0.0/8 is '
+ 'required to create networks.'))
if not num_networks:
num_networks = FLAGS.num_networks
if not network_size:
@@ -548,6 +561,51 @@ class NetworkCommands(object):
network.dhcp_start,
network.dns)
+ def delete(self, fixed_range):
+ """Deletes a network"""
+ network = db.network_get_by_cidr(context.get_admin_context(), \
+ fixed_range)
+ if network.project_id is not None:
+ raise ValueError(_('Network must be disassociated from project %s'
+ ' before delete' % network.project_id))
+ db.network_delete_safe(context.get_admin_context(), network.id)
+
+
+class VmCommands(object):
+ """Class for mangaging VM instances."""
+
+ 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.
+
+ """
+
+ ctxt = context.get_admin_context()
+ instance_id = ec2utils.ec2_id_to_id(ec2_id)
+
+ if (FLAGS.connection_type != 'libvirt' or
+ (FLAGS.connection_type == 'libvirt' and
+ FLAGS.libvirt_type not in ['kvm', 'qemu'])):
+ msg = _('Only KVM and QEmu are supported for now. Sorry!')
+ raise exception.Error(msg)
+
+ if (FLAGS.volume_driver != 'nova.volume.driver.AOEDriver' and \
+ FLAGS.volume_driver != 'nova.volume.driver.ISCSIDriver'):
+ msg = _("Support only AOEDriver and ISCSIDriver. Sorry!")
+ raise exception.Error(msg)
+
+ rpc.call(ctxt,
+ FLAGS.scheduler_topic,
+ {"method": "live_migration",
+ "args": {"instance_id": instance_id,
+ "dest": dest,
+ "topic": FLAGS.compute_topic}})
+
+ print _('Migration of %s initiated.'
+ 'Check its progress using euca-describe-instances.') % ec2_id
+
class ServiceCommands(object):
"""Enable and disable running services"""
@@ -593,6 +651,59 @@ class ServiceCommands(object):
return
db.service_update(ctxt, svc['id'], {'disabled': True})
+ def describe_resource(self, host):
+ """Describes cpu/memory/hdd info for host.
+
+ :param host: hostname.
+
+ """
+
+ result = rpc.call(context.get_admin_context(),
+ FLAGS.scheduler_topic,
+ {"method": "show_host_resources",
+ "args": {"host": host}})
+
+ if type(result) != dict:
+ print _('An unexpected error has occurred.')
+ print _('[Result]'), result
+ else:
+ cpu = result['resource']['vcpus']
+ mem = result['resource']['memory_mb']
+ hdd = result['resource']['local_gb']
+ cpu_u = result['resource']['vcpus_used']
+ mem_u = result['resource']['memory_mb_used']
+ hdd_u = result['resource']['local_gb_used']
+
+ print 'HOST\t\t\tPROJECT\t\tcpu\tmem(mb)\tdisk(gb)'
+ print '%s(total)\t\t\t%s\t%s\t%s' % (host, cpu, mem, hdd)
+ print '%s(used)\t\t\t%s\t%s\t%s' % (host, cpu_u, mem_u, hdd_u)
+ for p_id, val in result['usage'].items():
+ print '%s\t\t%s\t\t%s\t%s\t%s' % (host,
+ p_id,
+ val['vcpus'],
+ val['memory_mb'],
+ val['local_gb'])
+
+ def update_resource(self, host):
+ """Updates available vcpu/memory/disk info for host.
+
+ :param host: hostname.
+
+ """
+
+ ctxt = context.get_admin_context()
+ service_refs = db.service_get_all_by_host(ctxt, host)
+ if len(service_refs) <= 0:
+ raise exception.Invalid(_('%s does not exist.') % host)
+
+ service_refs = [s for s in service_refs if s['topic'] == 'compute']
+ if len(service_refs) <= 0:
+ raise exception.Invalid(_('%s is not compute node.') % host)
+
+ rpc.call(ctxt,
+ db.queue_get_for(ctxt, FLAGS.compute_topic, host),
+ {"method": "update_available_resource"})
+
class LogCommands(object):
def request(self, request_id, logfile='/var/log/nova.log'):
@@ -618,6 +729,49 @@ 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"""
@@ -665,8 +819,231 @@ class VolumeCommands(object):
"mountpoint": volume['mountpoint']}})
+class InstanceTypeCommands(object):
+ """Class for managing instance types / flavors."""
+
+ def _print_instance_types(self, n, val):
+ deleted = ('', ', inactive')[val["deleted"] == 1]
+ print ("%s: Memory: %sMB, VCPUS: %s, Storage: %sGB, FlavorID: %s, "
+ "Swap: %sGB, RXTX Quota: %sGB, RXTX Cap: %sMB%s") % (
+ n, val["memory_mb"], val["vcpus"], val["local_gb"],
+ val["flavorid"], val["swap"], val["rxtx_quota"],
+ val["rxtx_cap"], deleted)
+
+ 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]
+ """
+ try:
+ instance_types.create(name, memory, vcpus, local_gb,
+ flavorid, swap, rxtx_quota, rxtx_cap)
+ except exception.InvalidInputException:
+ print "Must supply valid parameters to create instance type"
+ print e
+ sys.exit(1)
+ except exception.DBError, e:
+ print "DB Error: %s" % e
+ sys.exit(2)
+ except:
+ print "Unknown error"
+ sys.exit(3)
+ else:
+ print "%s created" % name
+
+ def delete(self, name, purge=None):
+ """Marks instance types / flavors as deleted
+ arguments: name"""
+ try:
+ if purge == "--purge":
+ instance_types.purge(name)
+ verb = "purged"
+ else:
+ instance_types.destroy(name)
+ verb = "deleted"
+ except exception.ApiError:
+ print "Valid instance type name is required"
+ sys.exit(1)
+ except exception.DBError, e:
+ print "DB Error: %s" % e
+ sys.exit(2)
+ except:
+ sys.exit(3)
+ else:
+ print "%s %s" % (name, verb)
+
+ def list(self, name=None):
+ """Lists all active or specific instance types / flavors
+ arguments: [name]"""
+ try:
+ if name == None:
+ inst_types = instance_types.get_all_types()
+ elif name == "--all":
+ inst_types = instance_types.get_all_types(True)
+ else:
+ inst_types = instance_types.get_instance_type(name)
+ except exception.DBError, e:
+ _db_error(e)
+ if isinstance(inst_types.values()[0], dict):
+ for k, v in inst_types.iteritems():
+ self._print_instance_types(k, v)
+ else:
+ self._print_instance_types(name, inst_types)
+
+
+class ImageCommands(object):
+ """Methods for dealing with a cloud in an odd state"""
+
+ def __init__(self, *args, **kwargs):
+ self.image_service = utils.import_object(FLAGS.image_service)
+
+ def _register(self, image_type, disk_format, container_format,
+ path, owner, name=None, is_public='T',
+ architecture='x86_64', kernel_id=None, ramdisk_id=None):
+ meta = {'is_public': True,
+ 'name': name,
+ 'disk_format': disk_format,
+ 'container_format': container_format,
+ 'properties': {'image_state': 'available',
+ 'owner': owner,
+ 'type': image_type,
+ 'architecture': architecture,
+ 'image_location': 'local',
+ 'is_public': (is_public == 'T')}}
+ print image_type, meta
+ if kernel_id:
+ meta['properties']['kernel_id'] = int(kernel_id)
+ if ramdisk_id:
+ meta['properties']['ramdisk_id'] = int(ramdisk_id)
+ elevated = context.get_admin_context()
+ try:
+ with open(path) as ifile:
+ image = self.image_service.create(elevated, meta, ifile)
+ new = image['id']
+ print _("Image registered to %(new)s (%(new)08x).") % locals()
+ return new
+ except Exception as exc:
+ print _("Failed to register %(path)s: %(exc)s") % locals()
+
+ 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']"""
+ kernel_id = self.kernel_register(kernel, owner, None,
+ is_public, architecture)
+ ramdisk_id = self.ramdisk_register(ramdisk, owner, None,
+ is_public, architecture)
+ self.image_register(image, owner, name, is_public,
+ architecture, kernel_id, ramdisk_id)
+
+ def image_register(self, path, owner, name=None, is_public='T',
+ architecture='x86_64', kernel_id=None, ramdisk_id=None,
+ disk_format='ami', container_format='ami'):
+ """Uploads an image into the image_service
+ arguments: path owner [name] [is_public='T'] [architecture='x86_64']
+ [kernel_id=None] [ramdisk_id=None]
+ [disk_format='ami'] [container_format='ami']"""
+ return self._register('machine', disk_format, container_format, path,
+ owner, name, is_public, architecture,
+ kernel_id, ramdisk_id)
+
+ 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']
+ """
+ return self._register('kernel', 'aki', 'aki', path, owner, name,
+ is_public, 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']
+ """
+ return self._register('ramdisk', 'ari', 'ari', path, owner, name,
+ is_public, architecture)
+
+ def _lookup(self, old_image_id):
+ try:
+ internal_id = ec2utils.ec2_id_to_id(old_image_id)
+ image = self.image_service.show(context, internal_id)
+ except exception.NotFound:
+ image = self.image_service.show_by_name(context, old_image_id)
+ return image['id']
+
+ def _old_to_new(self, old):
+ mapping = {'machine': 'ami',
+ 'kernel': 'aki',
+ 'ramdisk': 'ari'}
+ container_format = mapping[old['type']]
+ disk_format = container_format
+ new = {'disk_format': disk_format,
+ 'container_format': container_format,
+ 'is_public': True,
+ 'name': old['imageId'],
+ 'properties': {'image_state': old['imageState'],
+ 'owner': old['imageOwnerId'],
+ 'architecture': old['architecture'],
+ 'type': old['type'],
+ 'image_location': old['imageLocation'],
+ 'is_public': old['isPublic']}}
+ if old.get('kernelId'):
+ new['properties']['kernel_id'] = self._lookup(old['kernelId'])
+ if old.get('ramdiskId'):
+ new['properties']['ramdisk_id'] = self._lookup(old['ramdiskId'])
+ return new
+
+ def _convert_images(self, images):
+ elevated = context.get_admin_context()
+ for image_path, image_metadata in images.iteritems():
+ meta = self._old_to_new(image_metadata)
+ old = meta['name']
+ try:
+ with open(image_path) as ifile:
+ image = self.image_service.create(elevated, meta, ifile)
+ new = image['id']
+ print _("Image %(old)s converted to " \
+ "%(new)s (%(new)08x).") % locals()
+ except Exception as exc:
+ print _("Failed to convert %(old)s: %(exc)s") % locals()
+
+ def convert(self, directory):
+ """Uploads old objectstore images in directory to new service
+ arguments: directory"""
+ machine_images = {}
+ other_images = {}
+ directory = os.path.abspath(directory)
+ # NOTE(vish): If we're importing from the images path dir, attempt
+ # to move the files out of the way before importing
+ # so we aren't writing to the same directory. This
+ # may fail if the dir was a mointpoint.
+ if (FLAGS.image_service == 'nova.image.local.LocalImageService'
+ and directory == os.path.abspath(FLAGS.images_path)):
+ new_dir = "%s_bak" % directory
+ os.move(directory, new_dir)
+ os.mkdir(directory)
+ directory = new_dir
+ for fn in glob.glob("%s/*/info.json" % directory):
+ try:
+ image_path = os.path.join(fn.rpartition('/')[0], 'image')
+ with open(fn) as metadata_file:
+ image_metadata = json.load(metadata_file)
+ if image_metadata['type'] == 'machine':
+ machine_images[image_path] = image_metadata
+ else:
+ other_images[image_path] = image_metadata
+ except Exception as exc:
+ print _("Failed to load %(fn)s.") % locals()
+ # NOTE(vish): do kernels and ramdisks first so images
+ self._convert_images(other_images)
+ self._convert_images(machine_images)
+
+
CATEGORIES = [
('user', UserCommands),
+ ('account', AccountCommands),
('project', ProjectCommands),
('role', RoleCommands),
('shell', ShellCommands),
@@ -674,10 +1051,15 @@ CATEGORIES = [
('fixed', FixedIpCommands),
('floating', FloatingIpCommands),
('network', NetworkCommands),
+ ('vm', VmCommands),
('service', ServiceCommands),
('log', LogCommands),
('db', DbCommands),
- ('volume', VolumeCommands)]
+ ('volume', VolumeCommands),
+ ('instance_type', InstanceTypeCommands),
+ ('image', ImageCommands),
+ ('flavor', InstanceTypeCommands),
+ ('instance', InstanceCommands)]
def lazy_match(name, key_value_tuples):
diff --git a/bin/nova-objectstore b/bin/nova-objectstore
index 9fbe228a2..6ef841b85 100755
--- a/bin/nova-objectstore
+++ b/bin/nova-objectstore
@@ -36,9 +36,10 @@ if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
gettext.install('nova', unicode=1)
from nova import flags
+from nova import log as logging
from nova import utils
-from nova import twistd
-from nova.objectstore import handler
+from nova import wsgi
+from nova.objectstore import s3server
FLAGS = flags.FLAGS
@@ -46,7 +47,9 @@ FLAGS = flags.FLAGS
if __name__ == '__main__':
utils.default_flagfile()
- twistd.serve(__file__)
-
-if __name__ == '__builtin__':
- application = handler.get_application() # pylint: disable-msg=C0103
+ FLAGS(sys.argv)
+ logging.setup()
+ router = s3server.S3Application(FLAGS.buckets_path)
+ server = wsgi.Server()
+ server.start(router, FLAGS.s3_port, host=FLAGS.s3_host)
+ server.wait()
diff --git a/bin/stack b/bin/stack
index 25caca06f..d84a82e27 100755
--- a/bin/stack
+++ b/bin/stack
@@ -59,11 +59,21 @@ USAGE = """usage: stack [options] <controller> <method> [arg1=value arg2=value]
def format_help(d):
"""Format help text, keys are labels and values are descriptions."""
+ MAX_INDENT = 30
indent = max([len(k) for k in d])
+ if indent > MAX_INDENT:
+ indent = MAX_INDENT - 6
+
out = []
for k, v in d.iteritems():
- t = textwrap.TextWrapper(initial_indent=' %s ' % k.ljust(indent),
- subsequent_indent=' ' * (indent + 6))
+ if (len(k) + 6) > MAX_INDENT:
+ out.extend([' %s' % k])
+ initial_indent = ' ' * (indent + 6)
+ else:
+ initial_indent = ' %s ' % k.ljust(indent)
+ subsequent_indent = ' ' * (indent + 6)
+ t = textwrap.TextWrapper(initial_indent=initial_indent,
+ subsequent_indent=subsequent_indent)
out.extend(t.wrap(v))
return out