# 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. # Copyright 2013 Red Hat, Inc. # # 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. """ CLI interface for nova management. """ from __future__ import print_function import functools import re import sys import traceback from dateutil import parser as dateutil_parser import decorator from keystoneauth1 import exceptions as ks_exc import netaddr from oslo_config import cfg from oslo_db import exception as db_exc from oslo_log import log as logging import oslo_messaging as messaging from oslo_utils import encodeutils from oslo_utils import importutils from oslo_utils import uuidutils import prettytable import six import six.moves.urllib.parse as urlparse from sqlalchemy.engine import url as sqla_url from nova.cmd import common as cmd_common from nova.compute import api as compute_api import nova.conf from nova import config from nova import context from nova.db import api as db from nova.db import migration from nova.db.sqlalchemy import api as sa_db from nova import exception from nova.i18n import _ from nova import objects from nova.objects import block_device as block_device_obj from nova.objects import build_request as build_request_obj from nova.objects import compute_node as compute_node_obj from nova.objects import host_mapping as host_mapping_obj from nova.objects import instance as instance_obj from nova.objects import instance_mapping as instance_mapping_obj from nova.objects import quotas as quotas_obj from nova.objects import virtual_interface as virtual_interface_obj from nova import quota from nova import rpc from nova.scheduler.client import report from nova.scheduler import utils as scheduler_utils from nova import utils from nova import version from nova.virt import ironic CONF = nova.conf.CONF LOG = logging.getLogger(__name__) QUOTAS = quota.QUOTAS # Keep this list sorted and one entry per line for readability. _EXTRA_DEFAULT_LOG_LEVELS = ['oslo_concurrency=INFO', 'oslo_db=INFO', 'oslo_policy=INFO'] # Decorators for actions args = cmd_common.args action_description = cmd_common.action_description def mask_passwd_in_url(url): parsed = urlparse.urlparse(url) safe_netloc = re.sub(':.*@', ':****@', parsed.netloc) new_parsed = urlparse.ParseResult( parsed.scheme, safe_netloc, parsed.path, parsed.params, parsed.query, parsed.fragment) return urlparse.urlunparse(new_parsed) class FloatingIpCommands(object): """Class for managing floating IP.""" # TODO(stephenfin): Remove these when we remove cells v1 description = ('DEPRECATED: Floating IP commands are deprecated since ' 'nova-network is deprecated in favor of Neutron. The ' 'floating IP commands will be removed in an upcoming ' 'release.') @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) elif net.size >= 1000000: # NOTE(dripton): If we generate a million IPs and put them in # the database, the system will slow to a crawl and/or run # out of memory and crash. This is clearly a misconfiguration. reason = _("Too many IP addresses will be generated. Please " "increase /%s to reduce the number generated." ) % net.prefixlen raise exception.InvalidInput(reason=reason) else: return net.iter_hosts() @args('--ip_range', metavar='', help='IP range') @args('--pool', metavar='', help='Optional pool') @args('--interface', metavar='', 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, want_result=False) 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) return 1 @args('--ip_range', metavar='', 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', metavar='', 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'])) @decorator.decorator def validate_network_plugin(f, *args, **kwargs): """Decorator to validate the network plugin.""" if utils.is_neutron(): print(_("ERROR: Network commands are not supported when using the " "Neutron API. Use python-neutronclient instead.")) return 2 return f(*args, **kwargs) class NetworkCommands(object): """Class for managing networks.""" # TODO(stephenfin): Remove these when we remove cells v1 description = ('DEPRECATED: Network commands are deprecated since ' 'nova-network is deprecated in favor of Neutron. The ' 'network commands will be removed in an upcoming release.') @validate_network_plugin @args('--label', metavar='