summaryrefslogtreecommitdiff
path: root/quantumclient/quantum/v2_0/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'quantumclient/quantum/v2_0/__init__.py')
-rw-r--r--quantumclient/quantum/v2_0/__init__.py574
1 files changed, 3 insertions, 571 deletions
diff --git a/quantumclient/quantum/v2_0/__init__.py b/quantumclient/quantum/v2_0/__init__.py
index 1be1d29..38e43ab 100644
--- a/quantumclient/quantum/v2_0/__init__.py
+++ b/quantumclient/quantum/v2_0/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2012 OpenStack LLC.
+# Copyright 2013 OpenStack Foundation.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -15,574 +15,6 @@
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-import argparse
-import logging
-import re
+from neutronclient.neutron.v2_0 import NeutronCommand
-from cliff.formatters import table
-from cliff import lister
-from cliff import show
-
-from quantumclient.common import command
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-from quantumclient.openstack.common.gettextutils import _
-
-HEX_ELEM = '[0-9A-Fa-f]'
-UUID_PATTERN = '-'.join([HEX_ELEM + '{8}', HEX_ELEM + '{4}',
- HEX_ELEM + '{4}', HEX_ELEM + '{4}',
- HEX_ELEM + '{12}'])
-
-
-def find_resourceid_by_name_or_id(client, resource, name_or_id):
- obj_lister = getattr(client, "list_%ss" % resource)
- # perform search by id only if we are passing a valid UUID
- match = re.match(UUID_PATTERN, name_or_id)
- collection = resource + "s"
- if match:
- data = obj_lister(id=name_or_id, fields='id')
- if data and data[collection]:
- return data[collection][0]['id']
- return _find_resourceid_by_name(client, resource, name_or_id)
-
-
-def _find_resourceid_by_name(client, resource, name):
- obj_lister = getattr(client, "list_%ss" % resource)
- data = obj_lister(name=name, fields='id')
- collection = resource + "s"
- info = data[collection]
- if len(info) > 1:
- msg = (_("Multiple %(resource)s matches found for name '%(name)s',"
- " use an ID to be more specific.") %
- {'resource': resource, 'name': name})
- raise exceptions.QuantumClientException(
- message=msg)
- elif len(info) == 0:
- not_found_message = (_("Unable to find %(resource)s with name "
- "'%(name)s'") %
- {'resource': resource, 'name': name})
- # 404 is used to simulate server side behavior
- raise exceptions.QuantumClientException(
- message=not_found_message, status_code=404)
- else:
- return info[0]['id']
-
-
-def add_show_list_common_argument(parser):
- parser.add_argument(
- '-D', '--show-details',
- help='show detailed info',
- action='store_true',
- default=False, )
- parser.add_argument(
- '--show_details',
- action='store_true',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--fields',
- help=argparse.SUPPRESS,
- action='append',
- default=[])
- parser.add_argument(
- '-F', '--field',
- dest='fields', metavar='FIELD',
- help='specify the field(s) to be returned by server,'
- ' can be repeated',
- action='append',
- default=[])
-
-
-def add_pagination_argument(parser):
- parser.add_argument(
- '-P', '--page-size',
- dest='page_size', metavar='SIZE', type=int,
- help=("specify retrieve unit of each request, then split one request "
- "to several requests"),
- default=None)
-
-
-def add_sorting_argument(parser):
- parser.add_argument(
- '--sort-key',
- dest='sort_key', metavar='FIELD',
- action='append',
- help=("sort list by specified fields (This option can be repeated), "
- "The number of sort_dir and sort_key should match each other, "
- "more sort_dir specified will be omitted, less will be filled "
- "with asc as default direction "),
- default=[])
- parser.add_argument(
- '--sort-dir',
- dest='sort_dir', metavar='{asc,desc}',
- help=("sort list in specified directions "
- "(This option can be repeated)"),
- action='append',
- default=[],
- choices=['asc', 'desc'])
-
-
-def is_number(s):
- try:
- float(s) # for int, long and float
- except ValueError:
- try:
- complex(s) # for complex
- except ValueError:
- return False
-
- return True
-
-
-def parse_args_to_dict(values_specs):
- '''It is used to analyze the extra command options to command.
-
- Besides known options and arguments, our commands also support user to
- put more options to the end of command line. For example,
- list_nets -- --tag x y --key1 value1, where '-- --tag x y --key1 value1'
- is extra options to our list_nets. This feature can support V2.0 API's
- fields selection and filters. For example, to list networks which has name
- 'test4', we can have list_nets -- --name=test4.
-
- value spec is: --key type=int|bool|... value. Type is one of Python
- built-in types. By default, type is string. The key without value is
- a bool option. Key with two values will be a list option.
-
- '''
- # -- is a pseudo argument
- values_specs_copy = values_specs[:]
- if values_specs_copy and values_specs_copy[0] == '--':
- del values_specs_copy[0]
- _options = {}
- current_arg = None
- _values_specs = []
- _value_number = 0
- _list_flag = False
- current_item = None
- for _item in values_specs_copy:
- if _item.startswith('--'):
- if current_arg is not None:
- if _value_number > 1 or _list_flag:
- current_arg.update({'nargs': '+'})
- elif _value_number == 0:
- current_arg.update({'action': 'store_true'})
- _temp = _item
- if "=" in _item:
- _item = _item.split('=')[0]
- if _item in _options:
- raise exceptions.CommandError(
- "duplicated options %s" % ' '.join(values_specs))
- else:
- _options.update({_item: {}})
- current_arg = _options[_item]
- _item = _temp
- elif _item.startswith('type='):
- if current_arg is None:
- raise exceptions.CommandError(
- "invalid values_specs %s" % ' '.join(values_specs))
- if 'type' not in current_arg:
- _type_str = _item.split('=', 2)[1]
- current_arg.update({'type': eval(_type_str)})
- if _type_str == 'bool':
- current_arg.update({'type': utils.str2bool})
- elif _type_str == 'dict':
- current_arg.update({'type': utils.str2dict})
- continue
- elif _item == 'list=true':
- _list_flag = True
- continue
- if not _item.startswith('--'):
- if (not current_item or '=' in current_item or
- _item.startswith('-') and not is_number(_item)):
- raise exceptions.CommandError(
- "Invalid values_specs %s" % ' '.join(values_specs))
- _value_number += 1
- elif _item.startswith('--'):
- current_item = _item
- if '=' in current_item:
- _value_number = 1
- else:
- _value_number = 0
- _list_flag = False
- _values_specs.append(_item)
- if current_arg is not None:
- if _value_number > 1 or _list_flag:
- current_arg.update({'nargs': '+'})
- elif _value_number == 0:
- current_arg.update({'action': 'store_true'})
- _args = None
- if _values_specs:
- _parser = argparse.ArgumentParser(add_help=False)
- for opt, optspec in _options.iteritems():
- _parser.add_argument(opt, **optspec)
- _args = _parser.parse_args(_values_specs)
- result_dict = {}
- if _args:
- for opt in _options.iterkeys():
- _opt = opt.split('--', 2)[1]
- _opt = _opt.replace('-', '_')
- _value = getattr(_args, _opt)
- if _value is not None:
- result_dict.update({_opt: _value})
- return result_dict
-
-
-def _merge_args(qCmd, parsed_args, _extra_values, value_specs):
- """Merge arguments from _extra_values into parsed_args.
-
- If an argument value are provided in both and it is a list,
- the values in _extra_values will be merged into parsed_args.
-
- @param parsed_args: the parsed args from known options
- @param _extra_values: the other parsed arguments in unknown parts
- @param values_specs: the unparsed unknown parts
- """
- temp_values = _extra_values.copy()
- for key, value in temp_values.iteritems():
- if hasattr(parsed_args, key):
- arg_value = getattr(parsed_args, key)
- if arg_value is not None and value is not None:
- if isinstance(arg_value, list):
- if value and isinstance(value, list):
- if type(arg_value[0]) == type(value[0]):
- arg_value.extend(value)
- _extra_values.pop(key)
-
-
-def update_dict(obj, dict, attributes):
- for attribute in attributes:
- if hasattr(obj, attribute) and getattr(obj, attribute):
- dict[attribute] = getattr(obj, attribute)
-
-
-class TableFormater(table.TableFormatter):
- """This class is used to keep consistency with prettytable 0.6.
-
- https://bugs.launchpad.net/python-quantumclient/+bug/1165962
- """
- def emit_list(self, column_names, data, stdout, parsed_args):
- if column_names:
- super(TableFormater, self).emit_list(column_names, data, stdout,
- parsed_args)
- else:
- stdout.write('\n')
-
-
-class QuantumCommand(command.OpenStackCommand):
- api = 'network'
- log = logging.getLogger(__name__ + '.QuantumCommand')
- values_specs = []
- json_indent = None
-
- def __init__(self, app, app_args):
- super(QuantumCommand, self).__init__(app, app_args)
- if hasattr(self, 'formatters'):
- self.formatters['table'] = TableFormater()
-
- def get_client(self):
- return self.app.client_manager.quantum
-
- def get_parser(self, prog_name):
- parser = super(QuantumCommand, self).get_parser(prog_name)
- parser.add_argument(
- '--request-format',
- help=_('the xml or json request format'),
- default='json',
- choices=['json', 'xml', ], )
- parser.add_argument(
- '--request_format',
- choices=['json', 'xml', ],
- help=argparse.SUPPRESS)
-
- return parser
-
- def format_output_data(self, data):
- # Modify data to make it more readable
- if self.resource in data:
- for k, v in data[self.resource].iteritems():
- if isinstance(v, list):
- value = '\n'.join(utils.dumps(
- i, indent=self.json_indent) if isinstance(i, dict)
- else str(i) for i in v)
- data[self.resource][k] = value
- elif isinstance(v, dict):
- value = utils.dumps(v, indent=self.json_indent)
- data[self.resource][k] = value
- elif v is None:
- data[self.resource][k] = ''
-
- def add_known_arguments(self, parser):
- pass
-
- def args2body(self, parsed_args):
- return {}
-
-
-class CreateCommand(QuantumCommand, show.ShowOne):
- """Create a resource for a given tenant
-
- """
-
- api = 'network'
- resource = None
- log = None
-
- def get_parser(self, prog_name):
- parser = super(CreateCommand, self).get_parser(prog_name)
- parser.add_argument(
- '--tenant-id', metavar='TENANT_ID',
- help=_('the owner tenant ID'), )
- parser.add_argument(
- '--tenant_id',
- help=argparse.SUPPRESS)
- self.add_known_arguments(parser)
- return parser
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = parse_args_to_dict(self.values_specs)
- _merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- body = self.args2body(parsed_args)
- body[self.resource].update(_extra_values)
- obj_creator = getattr(quantum_client,
- "create_%s" % self.resource)
- data = obj_creator(body)
- self.format_output_data(data)
- # {u'network': {u'id': u'e9424a76-6db4-4c93-97b6-ec311cd51f19'}}
- info = self.resource in data and data[self.resource] or None
- if info:
- print >>self.app.stdout, _('Created a new %s:') % self.resource
- else:
- info = {'': ''}
- return zip(*sorted(info.iteritems()))
-
-
-class UpdateCommand(QuantumCommand):
- """Update resource's information
- """
-
- api = 'network'
- resource = None
- log = None
-
- def get_parser(self, prog_name):
- parser = super(UpdateCommand, self).get_parser(prog_name)
- parser.add_argument(
- 'id', metavar=self.resource.upper(),
- help='ID or name of %s to update' % self.resource)
- self.add_known_arguments(parser)
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = parse_args_to_dict(self.values_specs)
- _merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- body = self.args2body(parsed_args)
- if self.resource in body:
- body[self.resource].update(_extra_values)
- else:
- body[self.resource] = _extra_values
- if not body[self.resource]:
- raise exceptions.CommandError(
- "Must specify new values to update %s" % self.resource)
- _id = find_resourceid_by_name_or_id(quantum_client,
- self.resource,
- parsed_args.id)
- obj_updator = getattr(quantum_client,
- "update_%s" % self.resource)
- obj_updator(_id, body)
- print >>self.app.stdout, (
- _('Updated %(resource)s: %(id)s') %
- {'id': parsed_args.id, 'resource': self.resource})
- return
-
-
-class DeleteCommand(QuantumCommand):
- """Delete a given resource
-
- """
-
- api = 'network'
- resource = None
- log = None
- allow_names = True
-
- def get_parser(self, prog_name):
- parser = super(DeleteCommand, self).get_parser(prog_name)
- if self.allow_names:
- help_str = 'ID or name of %s to delete'
- else:
- help_str = 'ID of %s to delete'
- parser.add_argument(
- 'id', metavar=self.resource.upper(),
- help=help_str % self.resource)
- return parser
-
- def run(self, parsed_args):
- self.log.debug('run(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- obj_deleter = getattr(quantum_client,
- "delete_%s" % self.resource)
- if self.allow_names:
- _id = find_resourceid_by_name_or_id(quantum_client, self.resource,
- parsed_args.id)
- else:
- _id = parsed_args.id
- obj_deleter(_id)
- print >>self.app.stdout, (_('Deleted %(resource)s: %(id)s')
- % {'id': parsed_args.id,
- 'resource': self.resource})
- return
-
-
-class ListCommand(QuantumCommand, lister.Lister):
- """List resources that belong to a given tenant
-
- """
-
- api = 'network'
- resource = None
- log = None
- _formatters = {}
- list_columns = []
- unknown_parts_flag = True
- pagination_support = False
- sorting_support = False
-
- def get_parser(self, prog_name):
- parser = super(ListCommand, self).get_parser(prog_name)
- add_show_list_common_argument(parser)
- if self.pagination_support:
- add_pagination_argument(parser)
- if self.sorting_support:
- add_sorting_argument(parser)
- return parser
-
- def args2search_opts(self, parsed_args):
- search_opts = {}
- fields = parsed_args.fields
- if parsed_args.fields:
- search_opts.update({'fields': fields})
- if parsed_args.show_details:
- search_opts.update({'verbose': 'True'})
- return search_opts
-
- def call_server(self, quantum_client, search_opts, parsed_args):
- obj_lister = getattr(quantum_client,
- "list_%ss" % self.resource)
- data = obj_lister(**search_opts)
- return data
-
- def retrieve_list(self, parsed_args):
- """Retrieve a list of resources from Quantum server"""
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
- _extra_values = parse_args_to_dict(self.values_specs)
- _merge_args(self, parsed_args, _extra_values,
- self.values_specs)
- search_opts = self.args2search_opts(parsed_args)
- search_opts.update(_extra_values)
- if self.pagination_support:
- page_size = parsed_args.page_size
- if page_size:
- search_opts.update({'limit': page_size})
- if self.sorting_support:
- keys = parsed_args.sort_key
- if keys:
- search_opts.update({'sort_key': keys})
- dirs = parsed_args.sort_dir
- len_diff = len(keys) - len(dirs)
- if len_diff > 0:
- dirs += ['asc'] * len_diff
- elif len_diff < 0:
- dirs = dirs[:len(keys)]
- if dirs:
- search_opts.update({'sort_dir': dirs})
- data = self.call_server(quantum_client, search_opts, parsed_args)
- collection = self.resource + "s"
- return data.get(collection, [])
-
- def extend_list(self, data, parsed_args):
- """Update a retrieved list.
-
- This method provides a way to modify a original list returned from
- the quantum server. For example, you can add subnet cidr information
- to a list network.
- """
- pass
-
- def setup_columns(self, info, parsed_args):
- _columns = len(info) > 0 and sorted(info[0].keys()) or []
- if not _columns:
- # clean the parsed_args.columns so that cliff will not break
- parsed_args.columns = []
- elif parsed_args.columns:
- _columns = [x for x in parsed_args.columns if x in _columns]
- elif self.list_columns:
- # if no -c(s) by user and list_columns, we use columns in
- # both list_columns and returned resource.
- # Also Keep their order the same as in list_columns
- _columns = [x for x in self.list_columns if x in _columns]
- return (_columns, (utils.get_item_properties(
- s, _columns, formatters=self._formatters, )
- for s in info), )
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- data = self.retrieve_list(parsed_args)
- self.extend_list(data, parsed_args)
- return self.setup_columns(data, parsed_args)
-
-
-class ShowCommand(QuantumCommand, show.ShowOne):
- """Show information of a given resource
-
- """
-
- api = 'network'
- resource = None
- log = None
- allow_names = True
-
- def get_parser(self, prog_name):
- parser = super(ShowCommand, self).get_parser(prog_name)
- add_show_list_common_argument(parser)
- if self.allow_names:
- help_str = 'ID or name of %s to look up'
- else:
- help_str = 'ID of %s to look up'
- parser.add_argument(
- 'id', metavar=self.resource.upper(),
- help=help_str % self.resource)
- return parser
-
- def get_data(self, parsed_args):
- self.log.debug('get_data(%s)' % parsed_args)
- quantum_client = self.get_client()
- quantum_client.format = parsed_args.request_format
-
- params = {}
- if parsed_args.show_details:
- params = {'verbose': 'True'}
- if parsed_args.fields:
- params = {'fields': parsed_args.fields}
- if self.allow_names:
- _id = find_resourceid_by_name_or_id(quantum_client, self.resource,
- parsed_args.id)
- else:
- _id = parsed_args.id
-
- obj_shower = getattr(quantum_client, "show_%s" % self.resource)
- data = obj_shower(_id, **params)
- self.format_output_data(data)
- resource = data[self.resource]
- if self.resource in data:
- return zip(*sorted(resource.iteritems()))
- else:
- return None
+QuantumCommand = NeutronCommand