1213 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1213 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
						|
 | 
						|
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
 | 
						|
# 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.
 | 
						|
 | 
						|
# Interactive shell based on Django:
 | 
						|
#
 | 
						|
# Copyright (c) 2005, the Lawrence Journal-World
 | 
						|
# All rights reserved.
 | 
						|
#
 | 
						|
# Redistribution and use in source and binary forms, with or without
 | 
						|
# modification, are permitted provided that the following conditions are met:
 | 
						|
#
 | 
						|
#     1. Redistributions of source code must retain the above copyright notice,
 | 
						|
#        this list of conditions and the following disclaimer.
 | 
						|
#
 | 
						|
#     2. Redistributions in binary form must reproduce the above copyright
 | 
						|
#        notice, this list of conditions and the following disclaimer in the
 | 
						|
#        documentation and/or other materials provided with the distribution.
 | 
						|
#
 | 
						|
#     3. Neither the name of Django nor the names of its contributors may be
 | 
						|
#        used to endorse or promote products derived from this software without
 | 
						|
#        specific prior written permission.
 | 
						|
#
 | 
						|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
 | 
						|
"""
 | 
						|
  CLI interface for nova management.
 | 
						|
"""
 | 
						|
 | 
						|
import gettext
 | 
						|
import netaddr
 | 
						|
import os
 | 
						|
import sys
 | 
						|
 | 
						|
# 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.api.ec2 import ec2utils
 | 
						|
from nova import availability_zones
 | 
						|
from nova.compute import instance_types
 | 
						|
from nova.compute import rpcapi as compute_rpcapi
 | 
						|
from nova import config
 | 
						|
from nova import context
 | 
						|
from nova import db
 | 
						|
from nova.db import migration
 | 
						|
from nova import exception
 | 
						|
from nova.openstack.common import cfg
 | 
						|
from nova.openstack.common import cliutils
 | 
						|
from nova.openstack.common import importutils
 | 
						|
from nova.openstack.common import log as logging
 | 
						|
from nova.openstack.common import rpc
 | 
						|
from nova.openstack.common import timeutils
 | 
						|
from nova import quota
 | 
						|
from nova.scheduler import rpcapi as scheduler_rpcapi
 | 
						|
from nova import utils
 | 
						|
from nova import version
 | 
						|
 | 
						|
CONF = cfg.CONF
 | 
						|
CONF.import_opt('network_manager', 'nova.service')
 | 
						|
CONF.import_opt('service_down_time', 'nova.service')
 | 
						|
CONF.import_opt('flat_network_bridge', 'nova.network.manager')
 | 
						|
CONF.import_opt('num_networks', 'nova.network.manager')
 | 
						|
CONF.import_opt('multi_host', 'nova.network.manager')
 | 
						|
CONF.import_opt('network_size', 'nova.network.manager')
 | 
						|
CONF.import_opt('vlan_start', 'nova.network.manager')
 | 
						|
CONF.import_opt('vpn_start', 'nova.network.manager')
 | 
						|
CONF.import_opt('default_floating_pool', 'nova.network.manager')
 | 
						|
CONF.import_opt('public_interface', 'nova.network.linux_net')
 | 
						|
 | 
						|
QUOTAS = quota.QUOTAS
 | 
						|
 | 
						|
 | 
						|
# Decorators for actions
 | 
						|
def args(*args, **kwargs):
 | 
						|
    def _decorator(func):
 | 
						|
        func.__dict__.setdefault('args', []).insert(0, (args, kwargs))
 | 
						|
        return func
 | 
						|
    return _decorator
 | 
						|
 | 
						|
 | 
						|
def param2id(object_id):
 | 
						|
    """Helper function to convert various volume id types to internal id.
 | 
						|
    args: [object_id], e.g. 'vol-0000000a' or 'volume-0000000a' or '10'
 | 
						|
    """
 | 
						|
    if '-' in object_id:
 | 
						|
        return ec2utils.ec2_vol_id_to_uuid(object_id)
 | 
						|
    else:
 | 
						|
        return object_id
 | 
						|
 | 
						|
 | 
						|
class VpnCommands(object):
 | 
						|
    """Class for managing VPNs."""
 | 
						|
 | 
						|
    @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
 | 
						|
 | 
						|
        """
 | 
						|
        # TODO(tr3buchet): perhaps this shouldn't update all networks
 | 
						|
        # associated with a project in the future
 | 
						|
        admin_context = context.get_admin_context()
 | 
						|
        networks = db.project_get_networks(admin_context, project_id)
 | 
						|
        for network in networks:
 | 
						|
            db.network_update(admin_context,
 | 
						|
                              network['id'],
 | 
						|
                              {'vpn_public_address': ip,
 | 
						|
                               'vpn_public_port': int(port)})
 | 
						|
 | 
						|
 | 
						|
class ShellCommands(object):
 | 
						|
    def bpython(self):
 | 
						|
        """Runs a bpython shell.
 | 
						|
 | 
						|
        Falls back to Ipython/python shell if unavailable"""
 | 
						|
        self.run('bpython')
 | 
						|
 | 
						|
    def ipython(self):
 | 
						|
        """Runs an Ipython shell.
 | 
						|
 | 
						|
        Falls back to Python shell if unavailable"""
 | 
						|
        self.run('ipython')
 | 
						|
 | 
						|
    def python(self):
 | 
						|
        """Runs a python shell.
 | 
						|
 | 
						|
        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."""
 | 
						|
        if not shell:
 | 
						|
            shell = 'bpython'
 | 
						|
 | 
						|
        if shell == 'bpython':
 | 
						|
            try:
 | 
						|
                import bpython
 | 
						|
                bpython.embed()
 | 
						|
            except ImportError:
 | 
						|
                shell = 'ipython'
 | 
						|
        if shell == 'ipython':
 | 
						|
            try:
 | 
						|
                import IPython
 | 
						|
                # Explicitly pass an empty list as arguments, because
 | 
						|
                # otherwise IPython would use sys.argv from this script.
 | 
						|
                shell = IPython.Shell.IPShell(argv=[])
 | 
						|
                shell.mainloop()
 | 
						|
            except ImportError:
 | 
						|
                shell = 'python'
 | 
						|
 | 
						|
        if shell == 'python':
 | 
						|
            import code
 | 
						|
            try:
 | 
						|
                # Try activating rlcompleter, because it's handy.
 | 
						|
                import readline
 | 
						|
            except ImportError:
 | 
						|
                pass
 | 
						|
            else:
 | 
						|
                # We don't have to wrap the following import in a 'try',
 | 
						|
                # because we already know 'readline' was imported successfully.
 | 
						|
                import rlcompleter
 | 
						|
                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 specified path with flags set properly.
 | 
						|
        arguments: path"""
 | 
						|
        exec(compile(open(path).read(), path, 'exec'), locals(), globals())
 | 
						|
 | 
						|
 | 
						|
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 db sync' before running this command.")
 | 
						|
    exit(1)
 | 
						|
 | 
						|
 | 
						|
class ProjectCommands(object):
 | 
						|
    """Class for managing projects."""
 | 
						|
 | 
						|
    @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."""
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        project_quota = QUOTAS.get_project_quotas(ctxt, project_id)
 | 
						|
        if key and key in project_quota:
 | 
						|
            if value.lower() == 'unlimited':
 | 
						|
                value = -1
 | 
						|
            try:
 | 
						|
                db.quota_update(ctxt, project_id, key, value)
 | 
						|
            except exception.ProjectQuotaNotFound:
 | 
						|
                db.quota_create(ctxt, project_id, key, value)
 | 
						|
        else:
 | 
						|
            print _('%(key)s is not a valid quota key. Valid options are: '
 | 
						|
                    '%(options)s.') % {'key': key,
 | 
						|
                                       'options': ', '.join(project_quota)}
 | 
						|
            sys.exit(2)
 | 
						|
        project_quota = QUOTAS.get_project_quotas(ctxt, project_id)
 | 
						|
        for key, value in project_quota.iteritems():
 | 
						|
            if value['limit'] < 0 or value['limit'] is None:
 | 
						|
                value['limit'] = 'unlimited'
 | 
						|
            print '%s: %s' % (key, value['limit'])
 | 
						|
 | 
						|
    @args('--project', dest="project_id", metavar='<Project name>',
 | 
						|
            help='Project name')
 | 
						|
    def scrub(self, 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:
 | 
						|
            db.network_disassociate(admin_context, network['id'])
 | 
						|
        groups = db.security_group_get_by_project(admin_context, project_id)
 | 
						|
        for group in groups:
 | 
						|
            db.security_group_destroy(admin_context, group['id'])
 | 
						|
 | 
						|
 | 
						|
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)."""
 | 
						|
        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_instance_host(ctxt, host)
 | 
						|
        except exception.NotFound as ex:
 | 
						|
            print _("error: %s") % ex
 | 
						|
            sys.exit(2)
 | 
						|
 | 
						|
        instances = db.instance_get_all(context.get_admin_context())
 | 
						|
        instances_by_uuid = {}
 | 
						|
        for instance in instances:
 | 
						|
            instances_by_uuid[instance['uuid']] = instance
 | 
						|
 | 
						|
        print "%-18s\t%-15s\t%-15s\t%s" % (_('network'),
 | 
						|
                                              _('IP address'),
 | 
						|
                                              _('hostname'),
 | 
						|
                                              _('host'))
 | 
						|
 | 
						|
        all_networks = {}
 | 
						|
        try:
 | 
						|
            # use network_get_all to retrieve all existing networks
 | 
						|
            # this is to ensure that IPs associated with deleted networks
 | 
						|
            # will not throw exceptions.
 | 
						|
            for network in db.network_get_all(context.get_admin_context()):
 | 
						|
                all_networks[network.id] = network
 | 
						|
        except exception.NoNetworksFound:
 | 
						|
            # do not have any networks, so even if there are IPs, these
 | 
						|
            # IPs should have been deleted ones, so return.
 | 
						|
            print _('No fixed IP found.')
 | 
						|
            return
 | 
						|
 | 
						|
        has_ip = False
 | 
						|
        for fixed_ip in fixed_ips:
 | 
						|
            hostname = None
 | 
						|
            host = None
 | 
						|
            network = all_networks.get(fixed_ip['network_id'])
 | 
						|
            if network:
 | 
						|
                has_ip = True
 | 
						|
                if fixed_ip.get('instance_uuid'):
 | 
						|
                    instance = instances_by_uuid.get(fixed_ip['instance_uuid'])
 | 
						|
                    if instance:
 | 
						|
                        hostname = instance['hostname']
 | 
						|
                        host = instance['host']
 | 
						|
                    else:
 | 
						|
                        print _('WARNING: fixed ip %s allocated to missing'
 | 
						|
                                ' instance') % str(fixed_ip['address'])
 | 
						|
                print "%-18s\t%-15s\t%-15s\t%s" % (
 | 
						|
                        network['cidr'],
 | 
						|
                        fixed_ip['address'],
 | 
						|
                        hostname, host)
 | 
						|
 | 
						|
        if not has_ip:
 | 
						|
            print _('No fixed IP found.')
 | 
						|
 | 
						|
    @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)
 | 
						|
            if fixed_ip is None:
 | 
						|
                raise exception.NotFound('Could not find 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."""
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def address_to_hosts(addresses):
 | 
						|
        """
 | 
						|
        Iterate over hosts within an address range.
 | 
						|
 | 
						|
        If an explicit range specifier is missing, the parameter is
 | 
						|
        interpreted as a specific individual address.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            return [netaddr.IPAddress(addresses)]
 | 
						|
        except ValueError:
 | 
						|
            net = netaddr.IPNetwork(addresses)
 | 
						|
            if net.size < 4:
 | 
						|
                reason = _("/%s should be specified as single address(es) "
 | 
						|
                           "not in cidr format") % net.prefixlen
 | 
						|
                raise exception.InvalidInput(reason=reason)
 | 
						|
            else:
 | 
						|
                return net.iter_hosts()
 | 
						|
 | 
						|
    @args('--ip_range', dest="ip_range", metavar='<range>', help='IP range')
 | 
						|
    @args('--pool', dest="pool", metavar='<pool>', help='Optional pool')
 | 
						|
    @args('--interface', dest="interface", metavar='<interface>',
 | 
						|
          help='Optional interface')
 | 
						|
    def create(self, ip_range, pool=None, interface=None):
 | 
						|
        """Creates floating ips for zone by range."""
 | 
						|
        admin_context = context.get_admin_context()
 | 
						|
        if not pool:
 | 
						|
            pool = CONF.default_floating_pool
 | 
						|
        if not interface:
 | 
						|
            interface = CONF.public_interface
 | 
						|
 | 
						|
        ips = ({'address': str(address), 'pool': pool, 'interface': interface}
 | 
						|
               for address in self.address_to_hosts(ip_range))
 | 
						|
        try:
 | 
						|
            db.floating_ip_bulk_create(admin_context, ips)
 | 
						|
        except exception.FloatingIpExists as exc:
 | 
						|
            # NOTE(simplylizz): Maybe logging would be better here
 | 
						|
            # instead of printing, but logging isn't used here and I
 | 
						|
            # don't know why.
 | 
						|
            print('error: %s' % exc)
 | 
						|
            sys.exit(1)
 | 
						|
 | 
						|
    @args('--ip_range', dest="ip_range", metavar='<range>', help='IP range')
 | 
						|
    def delete(self, ip_range):
 | 
						|
        """Deletes floating ips by range."""
 | 
						|
        admin_context = context.get_admin_context()
 | 
						|
 | 
						|
        ips = ({'address': str(address)}
 | 
						|
               for address in self.address_to_hosts(ip_range))
 | 
						|
        db.floating_ip_bulk_destroy(admin_context, ips)
 | 
						|
 | 
						|
    @args('--host', dest="host", metavar='<host>', help='Host')
 | 
						|
    def list(self, host=None):
 | 
						|
        """Lists all floating ips (optionally by host)
 | 
						|
        Note: if host is given, only active floating IPs are returned"""
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        try:
 | 
						|
            if host is None:
 | 
						|
                floating_ips = db.floating_ip_get_all(ctxt)
 | 
						|
            else:
 | 
						|
                floating_ips = db.floating_ip_get_all_by_host(ctxt, host)
 | 
						|
        except exception.NoFloatingIpsDefined:
 | 
						|
            print _("No floating IP addresses have been defined.")
 | 
						|
            return
 | 
						|
        for floating_ip in floating_ips:
 | 
						|
            instance_uuid = None
 | 
						|
            if floating_ip['fixed_ip_id']:
 | 
						|
                fixed_ip = db.fixed_ip_get(ctxt, floating_ip['fixed_ip_id'])
 | 
						|
                instance_uuid = fixed_ip['instance_uuid']
 | 
						|
 | 
						|
            print "%s\t%s\t%s\t%s\t%s" % (floating_ip['project_id'],
 | 
						|
                                          floating_ip['address'],
 | 
						|
                                          instance_uuid,
 | 
						|
                                          floating_ip['pool'],
 | 
						|
                                          floating_ip['interface'])
 | 
						|
 | 
						|
 | 
						|
class NetworkCommands(object):
 | 
						|
    """Class for managing networks."""
 | 
						|
 | 
						|
    @args('--label', dest="label", metavar='<label>',
 | 
						|
            help='Label for network (ex: public)')
 | 
						|
    @args('--fixed_range_v4', dest="cidr", 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="cidr_v6",
 | 
						|
          help='IPv6 subnet (ex: fe80::/64')
 | 
						|
    @args('--gateway', dest="gateway", help='gateway')
 | 
						|
    @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')
 | 
						|
    @args('--uuid', dest="uuid", metavar="<network uuid>",
 | 
						|
      help='Network UUID')
 | 
						|
    @args('--fixed_cidr', dest="fixed_cidr", metavar='<x.x.x.x/yy>',
 | 
						|
            help='IPv4 subnet for fixed IPS (ex: 10.20.0.0/16)')
 | 
						|
    @args('--project_id', dest="project_id", metavar="<project id>",
 | 
						|
      help='Project id')
 | 
						|
    @args('--priority', dest="priority", metavar="<number>",
 | 
						|
      help='Network interface priority')
 | 
						|
    def create(self, label=None, cidr=None, num_networks=None,
 | 
						|
               network_size=None, multi_host=None, vlan_start=None,
 | 
						|
               vpn_start=None, cidr_v6=None, gateway=None,
 | 
						|
               gateway_v6=None, bridge=None, bridge_interface=None,
 | 
						|
               dns1=None, dns2=None, project_id=None, priority=None,
 | 
						|
               uuid=None, fixed_cidr=None):
 | 
						|
        """Creates fixed ips for host by range."""
 | 
						|
        kwargs = dict(((k, v) for k, v in locals().iteritems()
 | 
						|
                       if v and k != "self"))
 | 
						|
        if multi_host is not None:
 | 
						|
            kwargs['multi_host'] = multi_host == 'T'
 | 
						|
        net_manager = importutils.import_object(CONF.network_manager)
 | 
						|
        net_manager.create_networks(context.get_admin_context(), **kwargs)
 | 
						|
 | 
						|
    def list(self):
 | 
						|
        """List all created networks."""
 | 
						|
        _fmt = "%-5s\t%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s"
 | 
						|
        print _fmt % (_('id'),
 | 
						|
                          _('IPv4'),
 | 
						|
                          _('IPv6'),
 | 
						|
                          _('start address'),
 | 
						|
                          _('DNS1'),
 | 
						|
                          _('DNS2'),
 | 
						|
                          _('VlanID'),
 | 
						|
                          _('project'),
 | 
						|
                          _("uuid"))
 | 
						|
        try:
 | 
						|
            # Since network_get_all can throw exception.NoNetworksFound
 | 
						|
            # for this command to show a nice result, this exception
 | 
						|
            # should be caught and handled as such.
 | 
						|
            networks = db.network_get_all(context.get_admin_context())
 | 
						|
        except exception.NoNetworksFound:
 | 
						|
            print _('No networks found')
 | 
						|
        else:
 | 
						|
            for network in networks:
 | 
						|
                print _fmt % (network.id,
 | 
						|
                              network.cidr,
 | 
						|
                              network.cidr_v6,
 | 
						|
                              network.dhcp_start,
 | 
						|
                              network.dns1,
 | 
						|
                              network.dns2,
 | 
						|
                              network.vlan,
 | 
						|
                              network.project_id,
 | 
						|
                              network.uuid)
 | 
						|
 | 
						|
    @args('--fixed_range', dest="fixed_range", metavar='<x.x.x.x/yy>',
 | 
						|
            help='Network to delete')
 | 
						|
    @args('--uuid', dest='uuid', metavar='<uuid>',
 | 
						|
            help='UUID of network to delete')
 | 
						|
    def delete(self, fixed_range=None, uuid=None):
 | 
						|
        """Deletes a network."""
 | 
						|
 | 
						|
        if fixed_range is None and uuid is None:
 | 
						|
            raise Exception(_("Please specify either fixed_range or uuid"))
 | 
						|
 | 
						|
        net_manager = importutils.import_object(CONF.network_manager)
 | 
						|
        if "QuantumManager" in CONF.network_manager:
 | 
						|
            if uuid is None:
 | 
						|
                raise Exception(_("UUID is required to delete "
 | 
						|
                                  "Quantum Networks"))
 | 
						|
            if fixed_range:
 | 
						|
                raise Exception(_("Deleting by fixed_range is not supported "
 | 
						|
                                "with the QuantumManager"))
 | 
						|
        # delete the network
 | 
						|
        net_manager.delete_network(context.get_admin_context(),
 | 
						|
            fixed_range, uuid)
 | 
						|
 | 
						|
    @args('--fixed_range', dest="fixed_range", metavar='<x.x.x.x/yy>',
 | 
						|
            help='Network to modify')
 | 
						|
    @args('--project', dest="project", metavar='<project name>',
 | 
						|
            help='Project name to associate')
 | 
						|
    @args('--host', dest="host", metavar='<host>',
 | 
						|
            help='Host to associate')
 | 
						|
    @args('--disassociate-project', action="store_true", dest='dis_project',
 | 
						|
          default=False, help='Disassociate Network from Project')
 | 
						|
    @args('--disassociate-host', action="store_true", dest='dis_host',
 | 
						|
          default=False, help='Disassociate Host from Project')
 | 
						|
    def modify(self, fixed_range, project=None, host=None,
 | 
						|
               dis_project=None, dis_host=None):
 | 
						|
        """Associate/Disassociate Network with Project and/or Host
 | 
						|
        arguments: network project host
 | 
						|
        leave any field blank to ignore it
 | 
						|
        """
 | 
						|
        admin_context = context.get_admin_context()
 | 
						|
        network = db.network_get_by_cidr(admin_context, fixed_range)
 | 
						|
        net = {}
 | 
						|
        #User can choose the following actions each for project and host.
 | 
						|
        #1) Associate (set not None value given by project/host parameter)
 | 
						|
        #2) Disassociate (set None by disassociate parameter)
 | 
						|
        #3) Keep unchanged (project/host key is not added to 'net')
 | 
						|
        if project:
 | 
						|
            net['project_id'] = project
 | 
						|
        elif dis_project:
 | 
						|
            net['project_id'] = None
 | 
						|
        if host:
 | 
						|
            net['host'] = host
 | 
						|
        elif dis_host:
 | 
						|
            net['host'] = None
 | 
						|
        db.network_update(admin_context, network['id'], net)
 | 
						|
 | 
						|
 | 
						|
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."""
 | 
						|
 | 
						|
        print ("%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s"
 | 
						|
               "  %-10s %-10s %-10s %-5s" % (_('instance'),
 | 
						|
                                             _('node'),
 | 
						|
                                             _('type'),
 | 
						|
                                             _('state'),
 | 
						|
                                             _('launched'),
 | 
						|
                                             _('image'),
 | 
						|
                                             _('kernel'),
 | 
						|
                                             _('ramdisk'),
 | 
						|
                                             _('project'),
 | 
						|
                                             _('user'),
 | 
						|
                                             _('zone'),
 | 
						|
                                             _('index')))
 | 
						|
 | 
						|
        if host is 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 %-26s %-9s %-9s %-9s"
 | 
						|
                   " %-10s %-10s %-10s %-5d" % (instance['display_name'],
 | 
						|
                                                instance['host'],
 | 
						|
                                                instance['instance_type'].name,
 | 
						|
                                                instance['vm_state'],
 | 
						|
                                                instance['launched_at'],
 | 
						|
                                                instance['image_ref'],
 | 
						|
                                                instance['kernel_id'],
 | 
						|
                                                instance['ramdisk_id'],
 | 
						|
                                                instance['project_id'],
 | 
						|
                                                instance['user_id'],
 | 
						|
                                                instance['availability_zone'],
 | 
						|
                                                instance['launch_index']))
 | 
						|
 | 
						|
 | 
						|
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.
 | 
						|
        """
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        now = timeutils.utcnow()
 | 
						|
        services = db.service_get_all(ctxt)
 | 
						|
        services = availability_zones.set_availability_zones(ctxt, services)
 | 
						|
        if host:
 | 
						|
            services = [s for s in services if s['host'] == host]
 | 
						|
        if service:
 | 
						|
            services = [s for s in services if s['binary'] == service]
 | 
						|
        print_format = "%-16s %-36s %-16s %-10s %-5s %-10s"
 | 
						|
        print print_format % (
 | 
						|
                    _('Binary'),
 | 
						|
                    _('Host'),
 | 
						|
                    _('Zone'),
 | 
						|
                    _('Status'),
 | 
						|
                    _('State'),
 | 
						|
                    _('Updated_At'))
 | 
						|
        for svc in services:
 | 
						|
            delta = now - (svc['updated_at'] or svc['created_at'])
 | 
						|
            alive = abs(utils.total_seconds(delta)) <= CONF.service_down_time
 | 
						|
            art = (alive and ":-)") or "XXX"
 | 
						|
            active = 'enabled'
 | 
						|
            if svc['disabled']:
 | 
						|
                active = 'disabled'
 | 
						|
            print print_format % (svc['binary'], svc['host'],
 | 
						|
                                  svc['availability_zone'], 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."""
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        svc = db.service_get_by_args(ctxt, host, service)
 | 
						|
        if not svc:
 | 
						|
            print _("Unable to find service")
 | 
						|
            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."""
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        svc = db.service_get_by_args(ctxt, host, service)
 | 
						|
        if not svc:
 | 
						|
            print _("Unable to find service")
 | 
						|
            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.
 | 
						|
 | 
						|
        """
 | 
						|
        rpcapi = scheduler_rpcapi.SchedulerAPI()
 | 
						|
        result = rpcapi.show_host_resources(context.get_admin_context(),
 | 
						|
                                            host=host)
 | 
						|
 | 
						|
        if not isinstance(result, dict):
 | 
						|
            print _('An unexpected error has occurred.')
 | 
						|
            print _('[Result]'), result
 | 
						|
        else:
 | 
						|
            # Printing a total and used_now
 | 
						|
            # (NOTE)The host name width 16 characters
 | 
						|
            print '%(a)-25s%(b)16s%(c)8s%(d)8s%(e)8s' % {"a": _('HOST'),
 | 
						|
                                                         "b": _('PROJECT'),
 | 
						|
                                                         "c": _('cpu'),
 | 
						|
                                                         "d": _('mem(mb)'),
 | 
						|
                                                         "e": _('hdd')}
 | 
						|
            print ('%(a)-16s(total)%(b)26s%(c)8s%(d)8s' %
 | 
						|
                   {"a": host,
 | 
						|
                    "b": result['resource']['vcpus'],
 | 
						|
                    "c": result['resource']['memory_mb'],
 | 
						|
                    "d": result['resource']['local_gb']})
 | 
						|
 | 
						|
            print ('%(a)-16s(used_now)%(b)23s%(c)8s%(d)8s' %
 | 
						|
                   {"a": host,
 | 
						|
                    "b": result['resource']['vcpus_used'],
 | 
						|
                    "c": result['resource']['memory_mb_used'],
 | 
						|
                    "d": result['resource']['local_gb_used']})
 | 
						|
 | 
						|
            # Printing a used_max
 | 
						|
            cpu_sum = 0
 | 
						|
            mem_sum = 0
 | 
						|
            hdd_sum = 0
 | 
						|
            for p_id, val in result['usage'].items():
 | 
						|
                cpu_sum += val['vcpus']
 | 
						|
                mem_sum += val['memory_mb']
 | 
						|
                hdd_sum += val['root_gb']
 | 
						|
                hdd_sum += val['ephemeral_gb']
 | 
						|
            print '%(a)-16s(used_max)%(b)23s%(c)8s%(d)8s' % {"a": host,
 | 
						|
                                                             "b": cpu_sum,
 | 
						|
                                                             "c": mem_sum,
 | 
						|
                                                             "d": hdd_sum}
 | 
						|
 | 
						|
            for p_id, val in result['usage'].items():
 | 
						|
                print '%(a)-25s%(b)16s%(c)8s%(d)8s%(e)8s' % {
 | 
						|
                        "a": host,
 | 
						|
                        "b": p_id,
 | 
						|
                        "c": val['vcpus'],
 | 
						|
                        "d": val['memory_mb'],
 | 
						|
                        "e": val['root_gb'] + val['ephemeral_gb']}
 | 
						|
 | 
						|
 | 
						|
class HostCommands(object):
 | 
						|
    """List hosts."""
 | 
						|
 | 
						|
    def list(self, zone=None):
 | 
						|
        """Show a list of all physical hosts. Filter by zone.
 | 
						|
        args: [zone]"""
 | 
						|
        print "%-25s\t%-15s" % (_('host'),
 | 
						|
                                _('zone'))
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        services = db.service_get_all(ctxt)
 | 
						|
        services = availability_zones.set_availability_zones(ctxt, services)
 | 
						|
        if zone:
 | 
						|
            services = [s for s in services if s['availability_zone'] == zone]
 | 
						|
        hosts = []
 | 
						|
        for srv in services:
 | 
						|
            if not [h for h in hosts if h['host'] == srv['host']]:
 | 
						|
                hosts.append(srv)
 | 
						|
 | 
						|
        for h in hosts:
 | 
						|
            print "%-25s\t%-15s" % (h['host'], h['availability_zone'])
 | 
						|
 | 
						|
 | 
						|
class DbCommands(object):
 | 
						|
    """Class for managing the database."""
 | 
						|
 | 
						|
    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)
 | 
						|
 | 
						|
    def version(self):
 | 
						|
        """Print the current database version."""
 | 
						|
        print migration.db_version()
 | 
						|
 | 
						|
 | 
						|
class InstanceTypeCommands(object):
 | 
						|
    """Class for managing instance types / flavors."""
 | 
						|
 | 
						|
    def _print_instance_types(self, name, val):
 | 
						|
        is_public = ('private', 'public')[val["is_public"] == 1]
 | 
						|
        print ("%s: Memory: %sMB, VCPUS: %s, Root: %sGB, Ephemeral: %sGb, "
 | 
						|
            "FlavorID: %s, Swap: %sMB, RXTX Factor: %s, %s, ExtraSpecs %s") % (
 | 
						|
            name, val["memory_mb"], val["vcpus"], val["root_gb"],
 | 
						|
            val["ephemeral_gb"], val["flavorid"], val["swap"],
 | 
						|
            val["rxtx_factor"], is_public, val["extra_specs"])
 | 
						|
 | 
						|
    @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('--root_gb', dest='root_gb', metavar='<root_gb>',
 | 
						|
            help='Root disk size')
 | 
						|
    @args('--ephemeral_gb', dest='ephemeral_gb', metavar='<ephemeral_gb>',
 | 
						|
            help='Ephemeral disk size')
 | 
						|
    @args('--flavor', dest='flavorid', metavar='<flavor  id>',
 | 
						|
            help='Flavor ID')
 | 
						|
    @args('--swap', dest='swap', metavar='<swap>', help='Swap')
 | 
						|
    @args('--rxtx_factor', dest='rxtx_factor', metavar='<rxtx_factor>',
 | 
						|
            help='rxtx_factor')
 | 
						|
    @args('--is_public', dest="is_public", metavar='<is_public>',
 | 
						|
            help='Make flavor accessible to the public')
 | 
						|
    def create(self, name, memory, vcpus, root_gb, ephemeral_gb=0,
 | 
						|
               flavorid=None, swap=0, rxtx_factor=1.0, is_public=True):
 | 
						|
        """Creates instance types / flavors."""
 | 
						|
        try:
 | 
						|
            instance_types.create(name, memory, vcpus, root_gb,
 | 
						|
                                  ephemeral_gb, flavorid, swap, rxtx_factor,
 | 
						|
                                  is_public)
 | 
						|
        except exception.InvalidInput, e:
 | 
						|
            print _("Must supply valid parameters to create instance_type")
 | 
						|
            print e
 | 
						|
            sys.exit(1)
 | 
						|
        except exception.InstanceTypeExists:
 | 
						|
            print _("Instance Type exists.")
 | 
						|
            print _("Please ensure instance_type name and flavorid are "
 | 
						|
                    "unique.")
 | 
						|
            print _("Currently defined instance_type names and flavorids:")
 | 
						|
            print
 | 
						|
            self.list()
 | 
						|
            sys.exit(2)
 | 
						|
        except Exception:
 | 
						|
            print _("Unknown error")
 | 
						|
            sys.exit(3)
 | 
						|
        else:
 | 
						|
            print _("%s created") % name
 | 
						|
 | 
						|
    @args('--name', dest='name', metavar='<name>',
 | 
						|
            help='Name of instance type/flavor')
 | 
						|
    def delete(self, name):
 | 
						|
        """Marks instance types / flavors as deleted."""
 | 
						|
        try:
 | 
						|
            instance_types.destroy(name)
 | 
						|
        except exception.InstanceTypeNotFound:
 | 
						|
            print _("Valid instance type name is required")
 | 
						|
            sys.exit(1)
 | 
						|
        except exception.DBError, e:
 | 
						|
            print _("DB Error: %s") % e
 | 
						|
            sys.exit(2)
 | 
						|
        except Exception:
 | 
						|
            sys.exit(3)
 | 
						|
        else:
 | 
						|
            print _("%s deleted") % name
 | 
						|
 | 
						|
    @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."""
 | 
						|
        try:
 | 
						|
            if name is None:
 | 
						|
                inst_types = instance_types.get_all_types()
 | 
						|
            else:
 | 
						|
                inst_types = instance_types.get_instance_type_by_name(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)
 | 
						|
 | 
						|
    @args('--name', dest='name', metavar='<name>',
 | 
						|
           help='Name of instance type/flavor')
 | 
						|
    @args('--key', dest='key', metavar='<key>',
 | 
						|
           help='The key of the key/value pair')
 | 
						|
    @args('--value', dest='value', metavar='<value>',
 | 
						|
           help='The value of the key/value pair')
 | 
						|
    def set_key(self, name, key, value=None):
 | 
						|
        """Add key/value pair to specified instance type's extra_specs."""
 | 
						|
        try:
 | 
						|
            try:
 | 
						|
                inst_type = instance_types.get_instance_type_by_name(name)
 | 
						|
            except exception.InstanceTypeNotFoundByName, e:
 | 
						|
                print e
 | 
						|
                sys.exit(2)
 | 
						|
 | 
						|
            ctxt = context.get_admin_context()
 | 
						|
            ext_spec = {key: value}
 | 
						|
            db.instance_type_extra_specs_update_or_create(
 | 
						|
                            ctxt,
 | 
						|
                            inst_type["flavorid"],
 | 
						|
                            ext_spec)
 | 
						|
            print _("Key %(key)s set to %(value)s on instance"
 | 
						|
                    " type %(name)s") % locals()
 | 
						|
        except exception.DBError, e:
 | 
						|
            _db_error(e)
 | 
						|
 | 
						|
    @args('--name', dest='name', metavar='<name>',
 | 
						|
           help='Name of instance type/flavor')
 | 
						|
    @args('--key', dest='key', metavar='<key>',
 | 
						|
           help='The key to be deleted')
 | 
						|
    def unset_key(self, name, key):
 | 
						|
        """Delete the specified extra spec for instance type."""
 | 
						|
        try:
 | 
						|
            try:
 | 
						|
                inst_type = instance_types.get_instance_type_by_name(name)
 | 
						|
            except exception.InstanceTypeNotFoundByName, e:
 | 
						|
                print e
 | 
						|
                sys.exit(2)
 | 
						|
 | 
						|
            ctxt = context.get_admin_context()
 | 
						|
            db.instance_type_extra_specs_delete(
 | 
						|
                        ctxt,
 | 
						|
                        inst_type["flavorid"],
 | 
						|
                        key)
 | 
						|
 | 
						|
            print _("Key %(key)s on instance type %(name)s unset") % locals()
 | 
						|
        except exception.DBError, e:
 | 
						|
            _db_error(e)
 | 
						|
 | 
						|
 | 
						|
class AgentBuildCommands(object):
 | 
						|
    """Class for managing agent builds."""
 | 
						|
 | 
						|
    def create(self, 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,
 | 
						|
                                             'os': os,
 | 
						|
                                             'architecture': architecture,
 | 
						|
                                             'version': version,
 | 
						|
                                             'url': url,
 | 
						|
                                             'md5hash': md5hash})
 | 
						|
 | 
						|
    def delete(self, 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)
 | 
						|
        db.agent_build_destroy(ctxt, agent_build_ref['id'])
 | 
						|
 | 
						|
    def list(self, hypervisor=None):
 | 
						|
        """Lists all agent builds.
 | 
						|
        arguments: <none>"""
 | 
						|
        fmt = "%-10s  %-8s  %12s  %s"
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        by_hypervisor = {}
 | 
						|
        for agent_build in db.agent_build_get_all(ctxt):
 | 
						|
            buildlist = by_hypervisor.get(agent_build.hypervisor)
 | 
						|
            if not buildlist:
 | 
						|
                buildlist = by_hypervisor[agent_build.hypervisor] = []
 | 
						|
 | 
						|
            buildlist.append(agent_build)
 | 
						|
 | 
						|
        for key, buildlist in by_hypervisor.iteritems():
 | 
						|
            if hypervisor and key != hypervisor:
 | 
						|
                continue
 | 
						|
 | 
						|
            print _('Hypervisor: %s') % key
 | 
						|
            print fmt % ('-' * 10, '-' * 8, '-' * 12, '-' * 32)
 | 
						|
            for agent_build in buildlist:
 | 
						|
                print fmt % (agent_build.os, agent_build.architecture,
 | 
						|
                             agent_build.version, agent_build.md5hash)
 | 
						|
                print '    %s' % agent_build.url
 | 
						|
 | 
						|
            print
 | 
						|
 | 
						|
    def modify(self, 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)
 | 
						|
        db.agent_build_update(ctxt, agent_build_ref['id'],
 | 
						|
                              {'version': version,
 | 
						|
                               'url': url,
 | 
						|
                               'md5hash': md5hash})
 | 
						|
 | 
						|
 | 
						|
class GetLogCommands(object):
 | 
						|
    """Get logging information."""
 | 
						|
 | 
						|
    def errors(self):
 | 
						|
        """Get all of the errors from the log files."""
 | 
						|
        error_found = 0
 | 
						|
        if CONF.log_dir:
 | 
						|
            logs = [x for x in os.listdir(CONF.log_dir) if x.endswith('.log')]
 | 
						|
            for file in logs:
 | 
						|
                log_file = os.path.join(CONF.log_dir, file)
 | 
						|
                lines = [line.strip() for line in open(log_file, "r")]
 | 
						|
                lines.reverse()
 | 
						|
                print_name = 0
 | 
						|
                for index, line in enumerate(lines):
 | 
						|
                    if line.find(" ERROR ") > 0:
 | 
						|
                        error_found += 1
 | 
						|
                        if print_name == 0:
 | 
						|
                            print log_file + ":-"
 | 
						|
                            print_name = 1
 | 
						|
                        linenum = len(lines) - index
 | 
						|
                        print _('Line %(linenum)d : %(line)s') % locals()
 | 
						|
        if error_found == 0:
 | 
						|
            print _('No errors in logfiles!')
 | 
						|
 | 
						|
    def syslog(self, num_entries=10):
 | 
						|
        """Get <num_entries> of the nova syslog events."""
 | 
						|
        entries = int(num_entries)
 | 
						|
        count = 0
 | 
						|
        log_file = ''
 | 
						|
        if os.path.exists('/var/log/syslog'):
 | 
						|
            log_file = '/var/log/syslog'
 | 
						|
        elif os.path.exists('/var/log/messages'):
 | 
						|
            log_file = '/var/log/messages'
 | 
						|
        else:
 | 
						|
            print _('Unable to find system log file!')
 | 
						|
            sys.exit(1)
 | 
						|
        lines = [line.strip() for line in open(log_file, "r")]
 | 
						|
        lines.reverse()
 | 
						|
        print _('Last %s nova syslog entries:-') % (entries)
 | 
						|
        for line in lines:
 | 
						|
            if line.find("nova") > 0:
 | 
						|
                count += 1
 | 
						|
                print "%s" % (line)
 | 
						|
            if count == entries:
 | 
						|
                break
 | 
						|
 | 
						|
        if count == 0:
 | 
						|
            print _('No nova entries in syslog!')
 | 
						|
 | 
						|
 | 
						|
class CellCommands(object):
 | 
						|
    """Commands for managing cells."""
 | 
						|
 | 
						|
    @args('--name', dest='name', metavar='<name>',
 | 
						|
            help='Name for the new cell')
 | 
						|
    @args('--cell_type', dest='cell_type', metavar='<parent|child>',
 | 
						|
         help='Whether the cell is a parent or child')
 | 
						|
    @args('--username', dest='username', metavar='<username>',
 | 
						|
         help='Username for the message broker in this cell')
 | 
						|
    @args('--password', dest='password', metavar='<password>',
 | 
						|
         help='Password for the message broker in this cell')
 | 
						|
    @args('--hostname', dest='hostname', metavar='<hostname>',
 | 
						|
         help='Address of the message broker in this cell')
 | 
						|
    @args('--port', dest='port', metavar='<number>',
 | 
						|
         help='Port number of the message broker in this cell')
 | 
						|
    @args('--virtual_host', dest='virtual_host', metavar='<virtual_host>',
 | 
						|
         help='The virtual host of the message broker in this cell')
 | 
						|
    @args('--woffset', dest='woffset', metavar='<float>')
 | 
						|
    @args('--wscale', dest='wscale', metavar='<float>')
 | 
						|
    def create(self, name, cell_type='child', username=None, password=None,
 | 
						|
               hostname=None, port=None, virtual_host=None,
 | 
						|
               woffset=None, wscale=None):
 | 
						|
 | 
						|
        if cell_type not in ['parent', 'child']:
 | 
						|
            print "Error: cell type must be 'parent' or 'child'"
 | 
						|
            sys.exit(2)
 | 
						|
 | 
						|
        is_parent = cell_type == 'parent'
 | 
						|
        values = {'name': name,
 | 
						|
                  'is_parent': is_parent,
 | 
						|
                  'username': username,
 | 
						|
                  'password': password,
 | 
						|
                  'rpc_host': hostname,
 | 
						|
                  'rpc_port': int(port),
 | 
						|
                  'rpc_virtual_host': virtual_host,
 | 
						|
                  'weight_offset': float(woffset),
 | 
						|
                  'weight_scale': float(wscale)}
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        db.cell_create(ctxt, values)
 | 
						|
 | 
						|
    @args('--cell_name', dest='cell_name', metavar='<cell_name>',
 | 
						|
         help='Name of the cell to delete')
 | 
						|
    def delete(self, cell_name):
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        db.cell_delete(ctxt, cell_name)
 | 
						|
 | 
						|
    def list(self):
 | 
						|
        ctxt = context.get_admin_context()
 | 
						|
        cells = db.cell_get_all(ctxt)
 | 
						|
        fmt = "%3s  %-10s  %-6s  %-10s  %-15s  %-5s  %-10s"
 | 
						|
        print fmt % ('Id', 'Name', 'Type', 'Username', 'Hostname',
 | 
						|
                'Port', 'VHost')
 | 
						|
        print fmt % ('-' * 3, '-' * 10, '-' * 6, '-' * 10, '-' * 15,
 | 
						|
                '-' * 5, '-' * 10)
 | 
						|
        for cell in cells:
 | 
						|
            print fmt % (cell.id, cell.name,
 | 
						|
                    'parent' if cell.is_parent else 'child',
 | 
						|
                    cell.username, cell.rpc_host,
 | 
						|
                    cell.rpc_port, cell.rpc_virtual_host)
 | 
						|
        print fmt % ('-' * 3, '-' * 10, '-' * 6, '-' * 10, '-' * 15,
 | 
						|
                '-' * 5, '-' * 10)
 | 
						|
 | 
						|
 | 
						|
CATEGORIES = {
 | 
						|
    'account': AccountCommands,
 | 
						|
    'agent': AgentBuildCommands,
 | 
						|
    'cell': CellCommands,
 | 
						|
    'db': DbCommands,
 | 
						|
    'fixed': FixedIpCommands,
 | 
						|
    'flavor': InstanceTypeCommands,
 | 
						|
    'floating': FloatingIpCommands,
 | 
						|
    'host': HostCommands,
 | 
						|
    'instance_type': InstanceTypeCommands,
 | 
						|
    'logs': GetLogCommands,
 | 
						|
    'network': NetworkCommands,
 | 
						|
    'project': ProjectCommands,
 | 
						|
    'service': ServiceCommands,
 | 
						|
    'shell': ShellCommands,
 | 
						|
    'vm': VmCommands,
 | 
						|
    'vpn': VpnCommands,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
def methods_of(obj):
 | 
						|
    """Get all callable methods of an object that don't start with underscore
 | 
						|
    returns a list of tuples of the form (method_name, method)"""
 | 
						|
    result = []
 | 
						|
    for i in dir(obj):
 | 
						|
        if callable(getattr(obj, i)) and not i.startswith('_'):
 | 
						|
            result.append((i, getattr(obj, i)))
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def add_command_parsers(subparsers):
 | 
						|
    parser = subparsers.add_parser('version')
 | 
						|
 | 
						|
    parser = subparsers.add_parser('bash-completion')
 | 
						|
    parser.add_argument('query_category', nargs='?')
 | 
						|
 | 
						|
    for category in CATEGORIES:
 | 
						|
        command_object = CATEGORIES[category]()
 | 
						|
 | 
						|
        parser = subparsers.add_parser(category)
 | 
						|
        parser.set_defaults(command_object=command_object)
 | 
						|
 | 
						|
        category_subparsers = parser.add_subparsers(dest='action')
 | 
						|
 | 
						|
        for (action, action_fn) in methods_of(command_object):
 | 
						|
            parser = category_subparsers.add_parser(action)
 | 
						|
 | 
						|
            action_kwargs = []
 | 
						|
            for args, kwargs in getattr(action_fn, 'args', []):
 | 
						|
                action_kwargs.append(kwargs['dest'])
 | 
						|
                kwargs['dest'] = 'action_kwarg_' + kwargs['dest']
 | 
						|
                parser.add_argument(*args, **kwargs)
 | 
						|
 | 
						|
            parser.set_defaults(action_fn=action_fn)
 | 
						|
            parser.set_defaults(action_kwargs=action_kwargs)
 | 
						|
 | 
						|
            parser.add_argument('action_args', nargs='*')
 | 
						|
 | 
						|
 | 
						|
category_opt = cfg.SubCommandOpt('category',
 | 
						|
                                 title='Command categories',
 | 
						|
                                 help='Available categories',
 | 
						|
                                 handler=add_command_parsers)
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
    """Parse options and call the appropriate class/method."""
 | 
						|
    CONF.register_cli_opt(category_opt)
 | 
						|
    try:
 | 
						|
        config.parse_args(sys.argv)
 | 
						|
        logging.setup("nova")
 | 
						|
    except cfg.ConfigFilesNotFoundError:
 | 
						|
        cfgfile = CONF.config_file[-1] if CONF.config_file else None
 | 
						|
        if cfgfile and not os.access(cfgfile, os.R_OK):
 | 
						|
            st = os.stat(cfgfile)
 | 
						|
            print _("Could not read %s. Re-running with sudo") % cfgfile
 | 
						|
            try:
 | 
						|
                os.execvp('sudo', ['sudo', '-u', '#%s' % st.st_uid] + sys.argv)
 | 
						|
            except Exception:
 | 
						|
                print _('sudo failed, continuing as if nothing happened')
 | 
						|
 | 
						|
        print _('Please re-run nova-manage as root.')
 | 
						|
        sys.exit(2)
 | 
						|
 | 
						|
    if CONF.category.name == "version":
 | 
						|
        print version.version_string_with_package()
 | 
						|
        sys.exit(0)
 | 
						|
 | 
						|
    if CONF.category.name == "bash-completion":
 | 
						|
        if not CONF.category.query_category:
 | 
						|
            print " ".join(CATEGORIES.keys())
 | 
						|
        elif CONF.category.query_category in CATEGORIES:
 | 
						|
            fn = CATEGORIES[CONF.category.query_category]
 | 
						|
            command_object = fn()
 | 
						|
            actions = methods_of(command_object)
 | 
						|
            print " ".join([k for (k, v) in actions])
 | 
						|
        sys.exit(0)
 | 
						|
 | 
						|
    fn = CONF.category.action_fn
 | 
						|
    fn_args = [arg.decode('utf-8') for arg in CONF.category.action_args]
 | 
						|
    fn_kwargs = {}
 | 
						|
    for k in CONF.category.action_kwargs:
 | 
						|
        v = getattr(CONF.category, 'action_kwarg_' + k)
 | 
						|
        if v is None:
 | 
						|
            continue
 | 
						|
        if isinstance(v, basestring):
 | 
						|
            v = v.decode('utf-8')
 | 
						|
        fn_kwargs[k] = v
 | 
						|
 | 
						|
    # call the action with the remaining arguments
 | 
						|
    # check arguments
 | 
						|
    try:
 | 
						|
        cliutils.validate_args(fn, *fn_args, **fn_kwargs)
 | 
						|
    except cliutils.MissingArgs as e:
 | 
						|
        # NOTE(mikal): this isn't the most helpful error message ever. It is
 | 
						|
        # long, and tells you a lot of things you probably don't want to know
 | 
						|
        # if you just got a single arg wrong.
 | 
						|
        print fn.__doc__
 | 
						|
        CONF.print_help()
 | 
						|
        print e
 | 
						|
        sys.exit(1)
 | 
						|
    try:
 | 
						|
        fn(*fn_args, **fn_kwargs)
 | 
						|
        rpc.cleanup()
 | 
						|
        sys.exit(0)
 | 
						|
    except Exception:
 | 
						|
        print _("Command failed, please check log for more info")
 | 
						|
        raise
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main()
 |