Implement support for provisioning hosts to ClimateClient

Cloud Admin must have possibility to dedicate hosts to Climate.
Consequently, adding host-{list,CRUD} to shell commands.

Partially implements blueprint python-client

Change-Id: I93c52d4b9c29aad3c3ff7aba2a105adb60422466
This commit is contained in:
Sylvain Bauza 2014-01-14 12:55:07 +01:00
parent aaf7c93ae6
commit 8a1830ae28
5 changed files with 188 additions and 7 deletions

View File

@ -14,6 +14,7 @@
# limitations under the License.
from __future__ import print_function
import ast
import logging
import six
@ -62,6 +63,7 @@ class ClimateCommand(OpenStackCommand):
values_specs = []
json_indent = None
resource = None
allow_names = True
def __init__(self, app, app_args):
super(ClimateCommand, self).__init__(app, app_args)
@ -82,6 +84,18 @@ class ClimateCommand(OpenStackCommand):
def format_output_data(self, data):
for k, v in six.iteritems(data):
if isinstance(v, six.text_type):
try:
# Deserialize if possible into dict, lists, tuples...
v = ast.literal_eval(v)
except SyntaxError:
# NOTE(sbauza): This is probably a datetime string, we need
# to keep it unchanged.
pass
except ValueError:
# NOTE(sbauza): This is not something AST can evaluate,
# probably a string.
pass
if isinstance(v, list):
value = '\n'.join(utils.dumps(
i, indent=self.json_indent) if isinstance(i, dict)
@ -131,9 +145,13 @@ class UpdateCommand(ClimateCommand):
def get_parser(self, prog_name):
parser = super(UpdateCommand, 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='ID or name of %s to update' % self.resource
help=help_str % self.resource
)
self.add_known_arguments(parser)
return parser
@ -142,9 +160,12 @@ class UpdateCommand(ClimateCommand):
self.log.debug('run(%s)' % parsed_args)
climate_client = self.get_client()
body = self.args2body(parsed_args)
res_id = utils.find_resource_id_by_name_or_id(climate_client,
self.resource,
parsed_args.id)
if self.allow_names:
res_id = utils.find_resource_id_by_name_or_id(climate_client,
self.resource,
parsed_args.id)
else:
res_id = parsed_args.id
resource_manager = getattr(climate_client, self.resource)
resource_manager.update(res_id, **body)
print(self.app.stdout, 'Updated %s: %s' % (self.resource,
@ -158,7 +179,6 @@ class DeleteCommand(ClimateCommand):
api = 'reservation'
resource = None
log = None
allow_names = True
def get_parser(self, prog_name):
parser = super(DeleteCommand, self).get_parser(prog_name)
@ -234,7 +254,6 @@ class ShowCommand(ClimateCommand, show.ShowOne):
api = 'reservation'
resource = None
log = None
allow_names = True
def get_parser(self, prog_name):
parser = super(ShowCommand, self).get_parser(prog_name)

View File

@ -32,6 +32,7 @@ from climateclient import client as climate_client
from climateclient import exception
from climateclient.openstack.common import strutils
from climateclient import utils
from climateclient.v1.shell_commands import hosts
from climateclient.v1.shell_commands import leases
from climateclient import version as base_version
@ -40,7 +41,12 @@ COMMANDS_V1 = {
'lease-show': leases.ShowLease,
'lease-create': leases.CreateLease,
'lease-update': leases.UpdateLease,
'lease-delete': leases.DeleteLease
'lease-delete': leases.DeleteLease,
'host-list': hosts.ListHosts,
'host-show': hosts.ShowHost,
'host-create': hosts.CreateHost,
'host-update': hosts.UpdateHost,
'host-delete': hosts.DeleteHost
}
VERSION = 1

View File

@ -14,6 +14,7 @@
# limitations under the License.
from climateclient.v1 import hosts
from climateclient.v1 import leases
@ -36,3 +37,5 @@ class Client(object):
self.lease = leases.LeaseClientManager(self.climate_url,
self.auth_token)
self.host = hosts.ComputeHostClientManager(self.climate_url,
self.auth_token)

47
climateclient/v1/hosts.py Normal file
View File

@ -0,0 +1,47 @@
# Copyright (c) 2014 Bull.
#
# 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.
from climateclient import base
from climateclient.openstack.common.gettextutils import _ # noqa
class ComputeHostClientManager(base.BaseClientManager):
"""Manager for the ComputeHost connected requests."""
def create(self, name, **kwargs):
"""Creates host from values passed."""
values = {'name': name}
values.update(**kwargs)
return self._create('/os-hosts', values, response_key='host')
def get(self, host_id):
"""Describes host specifications such as name and details."""
return self._get('/os-hosts/%s' % host_id, 'host')
def update(self, host_id, values):
"""Update attributes of the host."""
if not values:
return _('No values to update passed.')
return self._update('/os-hosts/%s' % host_id, values,
response_key='host')
def delete(self, host_id):
"""Deletes host with specified ID."""
self._delete('/os-hosts/%s' % host_id)
def list(self):
"""List all hosts."""
return self._get('/os-hosts', 'hosts')

View File

@ -0,0 +1,106 @@
# Copyright (c) 2014 Bull.
#
# 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.
import logging
from climateclient import command
class ListHosts(command.ListCommand):
resource = 'host'
log = logging.getLogger(__name__ + '.ListHosts')
list_columns = ['id', 'hypervisor_hostname', 'vcpus', 'memory_mb',
'local_gb']
class ShowHost(command.ShowCommand):
resource = 'host'
json_indent = 4
# NOTE(sbauza): We can't find by name as there is currently no column
# called 'name' but rather 'hypervisor_hostname'
allow_names = False
log = logging.getLogger(__name__ + '.ShowHost')
class CreateHost(command.CreateCommand):
resource = 'host'
json_indent = 4
log = logging.getLogger(__name__ + '.CreateHost')
def get_parser(self, prog_name):
parser = super(CreateHost, self).get_parser(prog_name)
parser.add_argument(
'name', metavar=self.resource.upper(),
help='Name of the host to add'
)
parser.add_argument(
'--extra', metavar='<key>=<value>',
action='append',
dest='extra_capabilities',
default=[],
help='Extra capabilities key/value pairs to add for the host'
)
return parser
def args2body(self, parsed_args):
params = {}
if parsed_args.name:
params['name'] = parsed_args.name
extras = {}
if parsed_args.extra_capabilities:
for capa in parsed_args.extra_capabilities:
key, _sep, value = capa.partition('=')
# NOTE(sbauza): multiple copies of the same capability will
# result in only the last value to be stored
extras[key] = value
params.update(extras)
return params
class UpdateHost(command.UpdateCommand):
resource = 'host'
allow_names = False
log = logging.getLogger(__name__ + '.UpdateHost')
def get_parser(self, prog_name):
parser = super(UpdateHost, self).get_parser(prog_name)
parser.add_argument(
'--extra', metavar='<key>=<value>',
action='append',
dest='extra_capabilities',
default=[],
help='Extra capabilities key/value pairs to update for the host'
)
return parser
def args2body(self, parsed_args):
params = {}
extras = {}
if parsed_args.extra_capabilities:
for capa in parsed_args.extra_capabilities:
key, _sep, value = capa.partition('=')
# NOTE(sbauza): multiple copies of the same capability will
# result in only the last value to be stored
extras[key] = value
params['values'] = extras
return params
class DeleteHost(command.DeleteCommand):
resource = 'host'
# NOTE(sbauza): We can't find by name as there is currently no column
# called 'name' but rather 'hypervisor_hostname'
allow_names = False
log = logging.getLogger(__name__ + '.DeleteHost')