diff options
| author | Doug Hellmann <doug.hellmann@dreamhost.com> | 2012-05-02 17:02:08 -0400 |
|---|---|---|
| committer | Doug Hellmann <doug.hellmann@dreamhost.com> | 2012-05-04 09:35:40 -0400 |
| commit | 5e4032150d360a305397e0220e51c5a66f2f5313 (patch) | |
| tree | 77ca626617774880f4eda5fa3143f0c9add642e3 /openstackclient/compute | |
| parent | b5a809d8e39e856a4b5e60383f5f35065a48fd12 (diff) | |
| download | python-openstackclient-5e4032150d360a305397e0220e51c5a66f2f5313.tar.gz | |
Fix "help" command and implement "list server" and "show server"
blueprint client-manager
blueprint nova-client
bug 992841
Move the authentication logic into a new ClientManager class so that only commands that need to authenticate will trigger that code.
Implement "list server" and "show server" commands as examples of using the ClientManager, Lister, and ShowOne classes.
Change-Id: I9845b70b33bae4b193dbe41871bf0ca8e286a727
Diffstat (limited to 'openstackclient/compute')
| -rw-r--r-- | openstackclient/compute/client.py | 32 | ||||
| -rw-r--r-- | openstackclient/compute/v2/server.py | 189 |
2 files changed, 175 insertions, 46 deletions
diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py new file mode 100644 index 00000000..ef0ceb38 --- /dev/null +++ b/openstackclient/compute/client.py @@ -0,0 +1,32 @@ +import logging + +from novaclient import client as nova_client + +LOG = logging.getLogger(__name__) + + +def make_client(instance): + """Returns a compute service client. + """ + LOG.debug('instantiating compute client') + # FIXME(dhellmann): Where is the endpoint value used? + # url = instance.get_endpoint_for_service_type('compute') + client = nova_client.Client( + version=instance._compute_api_version, + username=instance._username, + api_key=instance._password, + project_id=instance._tenant_name, + auth_url=instance._auth_url, + # FIXME(dhellmann): add constructor argument for this + insecure=False, + region_name=instance._region_name, + # FIXME(dhellmann): get endpoint_type from option? + endpoint_type='publicURL', + # FIXME(dhellmann): add extension discovery + extensions=[], + service_type='compute', + # FIXME(dhellmann): what is service_name? + service_name='', + ) + client.authenticate() + return client diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index c7c6add0..69bfc7e8 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -20,45 +20,55 @@ Server action implementations """ import logging +import os + +from cliff import lister +from cliff import show from openstackclient.common import command from openstackclient.common import utils -def _find_server(cs, server): - """Get a server by name or ID.""" - return utils.find_resource(cs.servers, server) - - -def _print_server(cs, server): - # By default when searching via name we will do a - # findall(name=blah) and due a REST /details which is not the same - # as a .get() and doesn't get the information about flavors and - # images. This fix it as we redo the call with the id which does a - # .get() to get all informations. - if not 'flavor' in server._info: - server = _find_server(cs, server.id) - - networks = server.networks - info = server._info.copy() - for network_label, address_list in networks.items(): - info['%s network' % network_label] = ', '.join(address_list) - - flavor = info.get('flavor', {}) - flavor_id = flavor.get('id', '') - info['flavor'] = _find_flavor(cs, flavor_id).name - - image = info.get('image', {}) - image_id = image.get('id', '') - info['image'] = _find_image(cs, image_id).name - - info.pop('links', None) - info.pop('addresses', None) - - utils.print_dict(info) - - -class List_Server(command.OpenStackCommand): +def _format_servers_list_networks(server): + """Return a string containing the networks a server is attached to. + + :param server: a single Server resource + """ + output = [] + for (network, addresses) in server.networks.items(): + if not addresses: + continue + addresses_csv = ', '.join(addresses) + group = "%s=%s" % (network, addresses_csv) + output.append(group) + return '; '.join(output) + + +def get_server_properties(server, fields, formatters={}): + """Return a tuple containing the server properties. + + :param server: a single Server resource + :param fields: tuple of strings with the desired field names + :param formatters: dictionary mapping field names to callables + to format the values + """ + row = [] + mixed_case_fields = ['serverId'] + + for field in fields: + if field in formatters: + row.append(formatters[field](server)) + else: + if field in mixed_case_fields: + field_name = field.replace(' ', '_') + else: + field_name = field.lower().replace(' ', '_') + data = getattr(server, field_name, '') + row.append(data) + return tuple(row) + + +class List_Server(command.OpenStackCommand, lister.Lister): "List server command." api = 'compute' @@ -67,17 +77,79 @@ class List_Server(command.OpenStackCommand): def get_parser(self, prog_name): parser = super(List_Server, self).get_parser(prog_name) parser.add_argument( - '--long', + '--reservation-id', + help='only return instances that match the reservation', + ) + parser.add_argument( + '--ip', + help='regular expression to match IP address', + ) + parser.add_argument( + '--ip6', + help='regular expression to match IPv6 address', + ) + parser.add_argument( + '--name', + help='regular expression to match name', + ) + parser.add_argument( + '--instance-name', + help='regular expression to match instance name', + ) + parser.add_argument( + '--status', + help='search by server status', + # FIXME(dhellmann): Add choices? + ) + parser.add_argument( + '--flavor', + help='search by flavor ID', + ) + parser.add_argument( + '--image', + help='search by image ID', + ) + parser.add_argument( + '--host', + metavar='HOSTNAME', + help='search by hostname', + ) + parser.add_argument( + '--all-tenants', action='store_true', - default=False, - help='Additional fields are listed in output') + default=bool(int(os.environ.get("ALL_TENANTS", 0))), + help='display information from all tenants (admin only)', + ) return parser - def run(self, parsed_args): - self.log.info('v2.List_Server.run(%s)' % parsed_args) - - -class Show_Server(command.OpenStackCommand): + def get_data(self, parsed_args): + self.log.debug('v2.List_Server.run(%s)' % parsed_args) + nova_client = self.app.client_manager.compute + search_opts = { + 'all_tenants': parsed_args.all_tenants, + 'reservation_id': parsed_args.reservation_id, + 'ip': parsed_args.ip, + 'ip6': parsed_args.ip6, + 'name': parsed_args.name, + 'image': parsed_args.image, + 'flavor': parsed_args.flavor, + 'status': parsed_args.status, + 'host': parsed_args.host, + 'instance_name': parsed_args.instance_name, + } + self.log.debug('search options: %s', search_opts) + # FIXME(dhellmann): Consider adding other columns + columns = ('ID', 'Name', 'Status', 'Networks') + data = nova_client.servers.list(search_opts=search_opts) + return (columns, + (get_server_properties( + s, columns, + formatters={'Networks': _format_servers_list_networks}, + ) for s in data), + ) + + +class Show_Server(command.OpenStackCommand, show.ShowOne): "Show server command." api = 'compute' @@ -91,7 +163,32 @@ class Show_Server(command.OpenStackCommand): help='Name or ID of server to display') return parser - def run(self, parsed_args): - self.log.info('v2.Show_Server.run(%s)' % parsed_args) - #s = _find_server(cs, args.server) - #_print_server(cs, s) + def get_data(self, parsed_args): + self.log.debug('v2.Show_Server.run(%s)' % parsed_args) + nova_client = self.app.client_manager.compute + server = utils.find_resource(nova_client.servers, parsed_args.server) + + info = {} + info.update(server._info) + + # Convert the flavor blob to a name + flavor_info = info.get('flavor', {}) + flavor_id = flavor_info.get('id', '') + flavor = utils.find_resource(nova_client.flavors, flavor_id) + info['flavor'] = flavor.name + + # Convert the image blob to a name + image_info = info.get('image', {}) + image_id = image_info.get('id', '') + image = utils.find_resource(nova_client.images, image_id) + info['image'] = image.name + + # Format addresses in a useful way + info['addresses'] = _format_servers_list_networks(server) + + # Remove a couple of values that are long and not too useful + info.pop('links', None) + + columns = sorted(info.keys()) + values = [info[c] for c in columns] + return (columns, values) |
