Update compute client bits
* add server create, delete, pause, reboot, rebuild resume, suspend, unpause commands Change-Id: I728ec199e4562bd621c3a73106c90d8b790b459a
This commit is contained in:
parent
8010e773ac
commit
90a1c65f3a
@ -17,19 +17,28 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from novaclient import client as nova_client
|
from openstackclient.common import exceptions as exc
|
||||||
|
from openstackclient.common import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
API_NAME = 'compute'
|
API_NAME = 'compute'
|
||||||
|
API_VERSIONS = {
|
||||||
|
'1.1': 'novaclient.v1_1.client.Client',
|
||||||
|
'2': 'novaclient.v1_1.client.Client',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def make_client(instance):
|
def make_client(instance):
|
||||||
"""Returns a compute service client.
|
"""Returns a compute service client.
|
||||||
"""
|
"""
|
||||||
LOG.debug('instantiating compute client')
|
compute_client = utils.get_client_class(
|
||||||
client = nova_client.Client(
|
API_NAME,
|
||||||
version=instance._api_version[API_NAME],
|
instance._api_version[API_NAME],
|
||||||
|
API_VERSIONS,
|
||||||
|
)
|
||||||
|
LOG.debug('instantiating compute client: %s' % compute_client)
|
||||||
|
client = compute_client(
|
||||||
username=instance._username,
|
username=instance._username,
|
||||||
api_key=instance._password,
|
api_key=instance._password,
|
||||||
project_id=instance._tenant_name,
|
project_id=instance._tenant_name,
|
||||||
|
@ -21,11 +21,15 @@ Server action implementations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
from cliff import command
|
from cliff import command
|
||||||
from cliff import lister
|
from cliff import lister
|
||||||
from cliff import show
|
from cliff import show
|
||||||
|
|
||||||
|
from novaclient.v1_1 import servers
|
||||||
|
from openstackclient.common import exceptions
|
||||||
from openstackclient.common import utils
|
from openstackclient.common import utils
|
||||||
|
|
||||||
|
|
||||||
@ -33,6 +37,7 @@ def _format_servers_list_networks(server):
|
|||||||
"""Return a string containing the networks a server is attached to.
|
"""Return a string containing the networks a server is attached to.
|
||||||
|
|
||||||
:param server: a single Server resource
|
:param server: a single Server resource
|
||||||
|
:rtype: a string of formatted network addresses
|
||||||
"""
|
"""
|
||||||
output = []
|
output = []
|
||||||
for (network, addresses) in server.networks.items():
|
for (network, addresses) in server.networks.items():
|
||||||
@ -44,6 +49,318 @@ def _format_servers_list_networks(server):
|
|||||||
return '; '.join(output)
|
return '; '.join(output)
|
||||||
|
|
||||||
|
|
||||||
|
def _prep_server_detail(compute_client, server):
|
||||||
|
"""Prepare the detailed server dict for printing
|
||||||
|
|
||||||
|
:param compute_client: a compute client instance
|
||||||
|
:param server: a Server resource
|
||||||
|
:rtype: a dict of server details
|
||||||
|
"""
|
||||||
|
info = server._info.copy()
|
||||||
|
|
||||||
|
# Call .get() to retrieve all of the server information
|
||||||
|
# as findall(name=blah) and REST /details are not the same
|
||||||
|
# and do not return flavor and image information.
|
||||||
|
server = compute_client.servers.get(info['id'])
|
||||||
|
info.update(server._info)
|
||||||
|
|
||||||
|
# Convert the image blob to a name
|
||||||
|
image_info = info.get('image', {})
|
||||||
|
image_id = image_info.get('id', '')
|
||||||
|
image = utils.find_resource(compute_client.images, image_id)
|
||||||
|
info['image'] = "%s (%s)" % (image.name, image_id)
|
||||||
|
|
||||||
|
# Convert the flavor blob to a name
|
||||||
|
flavor_info = info.get('flavor', {})
|
||||||
|
flavor_id = flavor_info.get('id', '')
|
||||||
|
flavor = utils.find_resource(compute_client.flavors, flavor_id)
|
||||||
|
info['flavor'] = "%s (%s)" % (flavor.name, flavor_id)
|
||||||
|
|
||||||
|
# NOTE(dtroyer): novaclient splits these into separate entries...
|
||||||
|
# Format addresses in a useful way
|
||||||
|
info['addresses'] = _format_servers_list_networks(server)
|
||||||
|
|
||||||
|
# Remove values that are long and not too useful
|
||||||
|
info.pop('links', None)
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_for_status(poll_fn, obj_id, final_ok_states, poll_period=5,
|
||||||
|
status_field="status"):
|
||||||
|
"""Block while an action is being performed
|
||||||
|
|
||||||
|
:param poll_fn: a function to retrieve the state of the object
|
||||||
|
:param obj_id: the id of the object
|
||||||
|
:param final_ok_states: a tuple of the states of the object that end the
|
||||||
|
wait as success, ex ['active']
|
||||||
|
:param poll_period: the wait time between checks of object status
|
||||||
|
:param status_field: field name containing the status to be checked
|
||||||
|
"""
|
||||||
|
log = logging.getLogger(__name__ + '._wait_for_status')
|
||||||
|
while True:
|
||||||
|
obj = poll_fn(obj_id)
|
||||||
|
|
||||||
|
status = getattr(obj, status_field)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
status = status.lower()
|
||||||
|
|
||||||
|
if status in final_ok_states:
|
||||||
|
log.debug('Wait terminated with success')
|
||||||
|
retval = True
|
||||||
|
break
|
||||||
|
elif status == "error":
|
||||||
|
log.error('Wait terminated with an error')
|
||||||
|
retval = False
|
||||||
|
break
|
||||||
|
|
||||||
|
time.sleep(poll_period)
|
||||||
|
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
class CreateServer(show.ShowOne):
|
||||||
|
"""Create server command"""
|
||||||
|
|
||||||
|
api = "compute"
|
||||||
|
log = logging.getLogger(__name__ + '.CreateServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(CreateServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server_name',
|
||||||
|
metavar='<server-name>',
|
||||||
|
help='New server name',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--image',
|
||||||
|
metavar='<image>',
|
||||||
|
required=True,
|
||||||
|
help='Create server from this image',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--flavor',
|
||||||
|
metavar='<flavor>',
|
||||||
|
required=True,
|
||||||
|
help='Create server with this flavor',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--security-group',
|
||||||
|
metavar='<security-group-name>',
|
||||||
|
action='append',
|
||||||
|
default=[],
|
||||||
|
help='Security group to assign to this server ' \
|
||||||
|
'(repeat for multiple groups)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--key-name',
|
||||||
|
metavar='<key-name>',
|
||||||
|
help='Keypair to inject into this server (optional extension)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--meta-data',
|
||||||
|
metavar='<key=value>',
|
||||||
|
action='append',
|
||||||
|
default=[],
|
||||||
|
help='Metadata to store for this server ' \
|
||||||
|
'(repeat for multiple values)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--file',
|
||||||
|
metavar='<dest-filename=source-filename>',
|
||||||
|
action='append',
|
||||||
|
default=[],
|
||||||
|
help='File to inject into image before boot ' \
|
||||||
|
'(repeat for multiple files)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--user-data',
|
||||||
|
metavar='<user-data>',
|
||||||
|
help='User data file to be serverd by the metadata server',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--availability-zone',
|
||||||
|
metavar='<zone-name>',
|
||||||
|
help='Keypair to inject into this server',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--block-device-mapping',
|
||||||
|
metavar='<dev-name=mapping>',
|
||||||
|
action='append',
|
||||||
|
default=[],
|
||||||
|
help='Map block devices; map is ' \
|
||||||
|
'<id>:<type>:<size(GB)>:<delete_on_terminate> ' \
|
||||||
|
'(optional extension)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--nic',
|
||||||
|
metavar='<nic-config-string>',
|
||||||
|
action='append',
|
||||||
|
default=[],
|
||||||
|
help='Specify NIC configuration (optional extension)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--hint',
|
||||||
|
metavar='<key=value>',
|
||||||
|
action='append',
|
||||||
|
default=[],
|
||||||
|
help='Hints for the scheduler (optional extension)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--config-drive',
|
||||||
|
metavar='<config-drive-volume>|True',
|
||||||
|
default=False,
|
||||||
|
help='Use specified volume as the config drive, ' \
|
||||||
|
'or \'True\' to use an ephemeral drive',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--min',
|
||||||
|
metavar='<count>',
|
||||||
|
type=int,
|
||||||
|
default=1,
|
||||||
|
help='Minimum number of servers to launch (default=1)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--max',
|
||||||
|
metavar='<count>',
|
||||||
|
type=int,
|
||||||
|
default=1,
|
||||||
|
help='Maximum number of servers to launch (default=1)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--wait',
|
||||||
|
dest='wait',
|
||||||
|
action='store_true',
|
||||||
|
help='Wait for server to become active to return',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
|
||||||
|
# Lookup parsed_args.image
|
||||||
|
image = utils.find_resource(compute_client.images,
|
||||||
|
parsed_args.image)
|
||||||
|
|
||||||
|
# Lookup parsed_args.flavor
|
||||||
|
flavor = utils.find_resource(compute_client.flavors,
|
||||||
|
parsed_args.flavor)
|
||||||
|
|
||||||
|
boot_args = [parsed_args.server_name, image, flavor]
|
||||||
|
|
||||||
|
meta = dict(v.split('=', 1) for v in parsed_args.meta_data)
|
||||||
|
|
||||||
|
files = {}
|
||||||
|
for f in parsed_args.file:
|
||||||
|
dst, src = f.split('=', 1)
|
||||||
|
try:
|
||||||
|
files[dst] = open(src)
|
||||||
|
except IOError, e:
|
||||||
|
raise exceptions.CommandError("Can't open '%s': %s" % (src, e))
|
||||||
|
|
||||||
|
if parsed_args.min > parsed_args.max:
|
||||||
|
raise exceptions.CommandError("min instances should be <= "
|
||||||
|
"max instances")
|
||||||
|
if parsed_args.min < 1:
|
||||||
|
raise exceptions.CommandError("min instances should be > 0")
|
||||||
|
if parsed_args.max < 1:
|
||||||
|
raise exceptions.CommandError("max instances should be > 0")
|
||||||
|
|
||||||
|
userdata = None
|
||||||
|
if parsed_args.user_data:
|
||||||
|
try:
|
||||||
|
userdata = open(parsed_args.user_data)
|
||||||
|
except IOError, e:
|
||||||
|
raise exceptions.CommandError("Can't open '%s': %s" % \
|
||||||
|
(parsed_args.user_data, e))
|
||||||
|
|
||||||
|
block_device_mapping = dict(v.split('=', 1)
|
||||||
|
for v in parsed_args.block_device_mapping)
|
||||||
|
|
||||||
|
nics = []
|
||||||
|
for nic_str in parsed_args.nic:
|
||||||
|
nic_info = {"net-id": "", "v4-fixed-ip": ""}
|
||||||
|
nic_info.update(dict(kv_str.split("=", 1)
|
||||||
|
for kv_str in nic_str.split(",")))
|
||||||
|
nics.append(nic_info)
|
||||||
|
|
||||||
|
hints = {}
|
||||||
|
for hint in parsed_args.hint:
|
||||||
|
key, _sep, value = hint.partition('=')
|
||||||
|
# NOTE(vish): multiple copies of the same hint will
|
||||||
|
# result in a list of values
|
||||||
|
if key in hints:
|
||||||
|
if isinstance(hints[key], basestring):
|
||||||
|
hints[key] = [hints[key]]
|
||||||
|
hints[key] += [value]
|
||||||
|
else:
|
||||||
|
hints[key] = value
|
||||||
|
|
||||||
|
# What does a non-boolean value for config-drive do?
|
||||||
|
# --config-drive argument is either a volume id or
|
||||||
|
# 'True' (or '1') to use an ephemeral volume
|
||||||
|
if str(parsed_args.config_drive).lower() in ("true", "1"):
|
||||||
|
config_drive = True
|
||||||
|
elif str(parsed_args.config_drive).lower() in ("false", "0",
|
||||||
|
"", "none"):
|
||||||
|
config_drive = None
|
||||||
|
else:
|
||||||
|
config_drive = parsed_args.config_drive
|
||||||
|
|
||||||
|
boot_kwargs = dict(
|
||||||
|
meta=meta,
|
||||||
|
files=files,
|
||||||
|
reservation_id=None,
|
||||||
|
min_count=parsed_args.min,
|
||||||
|
max_count=parsed_args.max,
|
||||||
|
security_groups=parsed_args.security_group,
|
||||||
|
userdata=userdata,
|
||||||
|
key_name=parsed_args.key_name,
|
||||||
|
availability_zone=parsed_args.availability_zone,
|
||||||
|
block_device_mapping=block_device_mapping,
|
||||||
|
nics=nics,
|
||||||
|
scheduler_hints=hints,
|
||||||
|
config_drive=config_drive,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.log.debug('boot_args: %s' % boot_args)
|
||||||
|
self.log.debug('boot_kwargs: %s' % boot_kwargs)
|
||||||
|
server = compute_client.servers.create(*boot_args, **boot_kwargs)
|
||||||
|
|
||||||
|
if parsed_args.wait:
|
||||||
|
_wait_for_status(compute_client.servers.get, server._info['id'],
|
||||||
|
['active'])
|
||||||
|
|
||||||
|
details = _prep_server_detail(compute_client, server)
|
||||||
|
return zip(*sorted(details.iteritems()))
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteServer(command.Command):
|
||||||
|
"""Delete server command"""
|
||||||
|
|
||||||
|
api = 'compute'
|
||||||
|
log = logging.getLogger(__name__ + '.DeleteServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(DeleteServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Name or ID of server to delete',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
compute_client.servers.delete(server.id)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class ListServer(lister.Lister):
|
class ListServer(lister.Lister):
|
||||||
"""List server command"""
|
"""List server command"""
|
||||||
|
|
||||||
@ -54,40 +371,48 @@ class ListServer(lister.Lister):
|
|||||||
parser = super(ListServer, self).get_parser(prog_name)
|
parser = super(ListServer, self).get_parser(prog_name)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--reservation-id',
|
'--reservation-id',
|
||||||
|
metavar='<reservation-id>',
|
||||||
help='only return instances that match the reservation',
|
help='only return instances that match the reservation',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--ip',
|
'--ip',
|
||||||
|
metavar='<ip-address-regex>',
|
||||||
help='regular expression to match IP address',
|
help='regular expression to match IP address',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--ip6',
|
'--ip6',
|
||||||
|
metavar='<ip-address-regex>',
|
||||||
help='regular expression to match IPv6 address',
|
help='regular expression to match IPv6 address',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--name',
|
'--name',
|
||||||
|
metavar='<name>',
|
||||||
help='regular expression to match name',
|
help='regular expression to match name',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--instance-name',
|
'--instance-name',
|
||||||
|
metavar='<server-name>',
|
||||||
help='regular expression to match instance name',
|
help='regular expression to match instance name',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--status',
|
'--status',
|
||||||
|
metavar='<status>',
|
||||||
help='search by server status',
|
help='search by server status',
|
||||||
# FIXME(dhellmann): Add choices?
|
# FIXME(dhellmann): Add choices?
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--flavor',
|
'--flavor',
|
||||||
|
metavar='<flavor>',
|
||||||
help='search by flavor ID',
|
help='search by flavor ID',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--image',
|
'--image',
|
||||||
|
metavar='<image>',
|
||||||
help='search by image ID',
|
help='search by image ID',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--host',
|
'--host',
|
||||||
metavar='HOSTNAME',
|
metavar='<hostname>',
|
||||||
help='search by hostname',
|
help='search by hostname',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -100,23 +425,23 @@ class ListServer(lister.Lister):
|
|||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
self.log.debug('take_action(%s)' % parsed_args)
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
nova_client = self.app.client_manager.compute
|
compute_client = self.app.client_manager.compute
|
||||||
search_opts = {
|
search_opts = {
|
||||||
'all_tenants': parsed_args.all_tenants,
|
|
||||||
'reservation_id': parsed_args.reservation_id,
|
'reservation_id': parsed_args.reservation_id,
|
||||||
'ip': parsed_args.ip,
|
'ip': parsed_args.ip,
|
||||||
'ip6': parsed_args.ip6,
|
'ip6': parsed_args.ip6,
|
||||||
'name': parsed_args.name,
|
'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,
|
'instance_name': parsed_args.instance_name,
|
||||||
|
'status': parsed_args.status,
|
||||||
|
'flavor': parsed_args.flavor,
|
||||||
|
'image': parsed_args.image,
|
||||||
|
'host': parsed_args.host,
|
||||||
|
'all_tenants': parsed_args.all_tenants,
|
||||||
}
|
}
|
||||||
self.log.debug('search options: %s', search_opts)
|
self.log.debug('search options: %s', search_opts)
|
||||||
# FIXME(dhellmann): Consider adding other columns
|
# FIXME(dhellmann): Consider adding other columns
|
||||||
columns = ('ID', 'Name', 'Status', 'Networks')
|
columns = ('ID', 'Name', 'Status', 'Networks')
|
||||||
data = nova_client.servers.list(search_opts=search_opts)
|
data = compute_client.servers.list(search_opts=search_opts)
|
||||||
return (columns,
|
return (columns,
|
||||||
(utils.get_item_properties(
|
(utils.get_item_properties(
|
||||||
s, columns,
|
s, columns,
|
||||||
@ -125,6 +450,165 @@ class ListServer(lister.Lister):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PauseServer(command.Command):
|
||||||
|
"""Pause server command"""
|
||||||
|
|
||||||
|
api = 'compute'
|
||||||
|
log = logging.getLogger(__name__ + '.PauseServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(PauseServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Name or ID of server to pause',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
server.pause()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class RebootServer(command.Command):
|
||||||
|
"""Reboot server command"""
|
||||||
|
|
||||||
|
api = 'compute'
|
||||||
|
log = logging.getLogger(__name__ + '.RebootServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(RebootServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Name or ID of server to reboot',
|
||||||
|
)
|
||||||
|
group = parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
|
'--hard',
|
||||||
|
dest='reboot_type',
|
||||||
|
action='store_const',
|
||||||
|
const=servers.REBOOT_HARD,
|
||||||
|
default=servers.REBOOT_SOFT,
|
||||||
|
help='Perform a hard reboot',
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--soft',
|
||||||
|
dest='reboot_type',
|
||||||
|
action='store_const',
|
||||||
|
const=servers.REBOOT_SOFT,
|
||||||
|
default=servers.REBOOT_SOFT,
|
||||||
|
help='Perform a soft reboot',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--wait',
|
||||||
|
dest='wait',
|
||||||
|
action='store_true',
|
||||||
|
help='Wait for server to become active to return',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
server.reboot(parsed_args.reboot_type)
|
||||||
|
|
||||||
|
if parsed_args.wait:
|
||||||
|
_wait_for_status(compute_client.servers.get, server.id,
|
||||||
|
['active'])
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class RebuildServer(show.ShowOne):
|
||||||
|
"""Rebuild server command"""
|
||||||
|
|
||||||
|
api = "compute"
|
||||||
|
log = logging.getLogger(__name__ + '.RebuildServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(RebuildServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Server name or ID',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--image',
|
||||||
|
metavar='<image>',
|
||||||
|
required=True,
|
||||||
|
help='Recreate server from this image',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--rebuild-password',
|
||||||
|
metavar='<rebuild_password>',
|
||||||
|
default=False,
|
||||||
|
help="Set the provided password on the rebuild instance",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--wait',
|
||||||
|
dest='wait',
|
||||||
|
action='store_true',
|
||||||
|
help='Wait for server to become active to return',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
|
||||||
|
# Lookup parsed_args.image
|
||||||
|
image = utils.find_resource(compute_client.images, parsed_args.image)
|
||||||
|
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
|
||||||
|
_password = None
|
||||||
|
if parsed_args.rebuild_password is not False:
|
||||||
|
_password = args.rebuild_password
|
||||||
|
|
||||||
|
kwargs = {}
|
||||||
|
server = server.rebuild(image, _password, **kwargs)
|
||||||
|
|
||||||
|
# TODO(dtroyer): force silent=True if output filter != table
|
||||||
|
if parsed_args.wait:
|
||||||
|
_wait_for_status(compute_client.servers.get, server._info['id'],
|
||||||
|
['active'])
|
||||||
|
|
||||||
|
details = _prep_server_detail(compute_client, server)
|
||||||
|
return zip(*sorted(details.iteritems()))
|
||||||
|
|
||||||
|
|
||||||
|
class ResumeServer(command.Command):
|
||||||
|
"""Resume server command"""
|
||||||
|
|
||||||
|
api = 'compute'
|
||||||
|
log = logging.getLogger(__name__ + '.ResumeServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ResumeServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Name or ID of server to resume',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
server.resume()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class ShowServer(show.ShowOne):
|
class ShowServer(show.ShowOne):
|
||||||
"""Show server command"""
|
"""Show server command"""
|
||||||
|
|
||||||
@ -136,32 +620,62 @@ class ShowServer(show.ShowOne):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'server',
|
'server',
|
||||||
metavar='<server>',
|
metavar='<server>',
|
||||||
help='Name or ID of server to display')
|
help='Name or ID of server to display'),
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
self.log.debug('take_action(%s)' % parsed_args)
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
nova_client = self.app.client_manager.compute
|
compute_client = self.app.client_manager.compute
|
||||||
server = utils.find_resource(nova_client.servers, parsed_args.server)
|
server = utils.find_resource(compute_client.servers,
|
||||||
|
parsed_args.server)
|
||||||
|
|
||||||
info = {}
|
details = _prep_server_detail(compute_client, server)
|
||||||
info.update(server._info)
|
return zip(*sorted(details.iteritems()))
|
||||||
|
|
||||||
# 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
|
class SuspendServer(command.Command):
|
||||||
image_info = info.get('image', {})
|
"""Suspend server command"""
|
||||||
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
|
api = 'compute'
|
||||||
info['addresses'] = _format_servers_list_networks(server)
|
log = logging.getLogger(__name__ + '.SuspendServer')
|
||||||
|
|
||||||
# Remove a couple of values that are long and not too useful
|
def get_parser(self, prog_name):
|
||||||
info.pop('links', None)
|
parser = super(SuspendServer, self).get_parser(prog_name)
|
||||||
return zip(*sorted(info.iteritems()))
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Name or ID of server to suspend',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
server.suspend()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class UnpauseServer(command.Command):
|
||||||
|
"""Unpause server command"""
|
||||||
|
|
||||||
|
api = 'compute'
|
||||||
|
log = logging.getLogger(__name__ + '.UnpauseServer')
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(UnpauseServer, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help='Name or ID of server to unpause',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug('take_action(%s)' % parsed_args)
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
server = utils.find_resource(
|
||||||
|
compute_client.servers, parsed_args.server)
|
||||||
|
server.unpause()
|
||||||
|
return
|
||||||
|
29
setup.py
29
setup.py
@ -55,6 +55,15 @@ setuptools.setup(
|
|||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': ['openstack=openstackclient.shell:main'],
|
'console_scripts': ['openstack=openstackclient.shell:main'],
|
||||||
'openstack.cli': [
|
'openstack.cli': [
|
||||||
|
'create_endpoint=' +
|
||||||
|
'openstackclient.identity.v2_0.endpoint:CreateEndpoint',
|
||||||
|
'delete_endpoint=' +
|
||||||
|
'openstackclient.identity.v2_0.endpoint:DeleteEndpoint',
|
||||||
|
'list_endpoint=' +
|
||||||
|
'openstackclient.identity.v2_0.endpoint:ListEndpoint',
|
||||||
|
'show_endpoint=' +
|
||||||
|
'openstackclient.identity.v2_0.endpoint:ShowEndpoint',
|
||||||
|
|
||||||
'add_role=' +
|
'add_role=' +
|
||||||
'openstackclient.identity.v2_0.role:AddRole',
|
'openstackclient.identity.v2_0.role:AddRole',
|
||||||
'create_role=' +
|
'create_role=' +
|
||||||
@ -65,22 +74,25 @@ setuptools.setup(
|
|||||||
'remove_role=' +
|
'remove_role=' +
|
||||||
'openstackclient.identity.v2_0.role:RemoveRole',
|
'openstackclient.identity.v2_0.role:RemoveRole',
|
||||||
'show_role=openstackclient.identity.v2_0.role:ShowRole',
|
'show_role=openstackclient.identity.v2_0.role:ShowRole',
|
||||||
|
|
||||||
|
'create_server=openstackclient.compute.v2.server:CreateServer',
|
||||||
|
'delete_server=openstackclient.compute.v2.server:DeleteServer',
|
||||||
'list_server=openstackclient.compute.v2.server:ListServer',
|
'list_server=openstackclient.compute.v2.server:ListServer',
|
||||||
|
'pause_server=openstackclient.compute.v2.server:PauseServer',
|
||||||
|
'reboot_server=openstackclient.compute.v2.server:RebootServer',
|
||||||
|
'rebuild_server=openstackclient.compute.v2.server:RebuildServer',
|
||||||
|
'resume_server=openstackclient.compute.v2.server:ResumeServer',
|
||||||
'show_server=openstackclient.compute.v2.server:ShowServer',
|
'show_server=openstackclient.compute.v2.server:ShowServer',
|
||||||
'create_endpoint=' +
|
'suspend_server=openstackclient.compute.v2.server:SuspendServer',
|
||||||
'openstackclient.identity.v2_0.endpoint:CreateEndpoint',
|
'unpause_server=openstackclient.compute.v2.server:UnpauseServer',
|
||||||
'delete_endpoint=' +
|
|
||||||
'openstackclient.identity.v2_0.endpoint:DeleteEndpoint',
|
|
||||||
'list_endpoint=' +
|
|
||||||
'openstackclient.identity.v2_0.endpoint:ListEndpoint',
|
|
||||||
'show_endpoint=' +
|
|
||||||
'openstackclient.identity.v2_0.endpoint:ShowEndpoint',
|
|
||||||
'create_service=' +
|
'create_service=' +
|
||||||
'openstackclient.identity.v2_0.service:CreateService',
|
'openstackclient.identity.v2_0.service:CreateService',
|
||||||
'delete_service=' +
|
'delete_service=' +
|
||||||
'openstackclient.identity.v2_0.service:DeleteService',
|
'openstackclient.identity.v2_0.service:DeleteService',
|
||||||
'list_service=openstackclient.identity.v2_0.service:ListService',
|
'list_service=openstackclient.identity.v2_0.service:ListService',
|
||||||
'show_service=openstackclient.identity.v2_0.service:ShowService',
|
'show_service=openstackclient.identity.v2_0.service:ShowService',
|
||||||
|
|
||||||
'create_tenant=' +
|
'create_tenant=' +
|
||||||
'openstackclient.identity.v2_0.tenant:CreateTenant',
|
'openstackclient.identity.v2_0.tenant:CreateTenant',
|
||||||
'delete_tenant=' +
|
'delete_tenant=' +
|
||||||
@ -88,6 +100,7 @@ setuptools.setup(
|
|||||||
'list_tenant=openstackclient.identity.v2_0.tenant:ListTenant',
|
'list_tenant=openstackclient.identity.v2_0.tenant:ListTenant',
|
||||||
'set_tenant=openstackclient.identity.v2_0.tenant:SetTenant',
|
'set_tenant=openstackclient.identity.v2_0.tenant:SetTenant',
|
||||||
'show_tenant=openstackclient.identity.v2_0.tenant:ShowTenant',
|
'show_tenant=openstackclient.identity.v2_0.tenant:ShowTenant',
|
||||||
|
|
||||||
'create_user=' +
|
'create_user=' +
|
||||||
'openstackclient.identity.v2_0.user:CreateUser',
|
'openstackclient.identity.v2_0.user:CreateUser',
|
||||||
'delete_user=' +
|
'delete_user=' +
|
||||||
|
Loading…
x
Reference in New Issue
Block a user