Add openstackclient support
This adds support for the recommended CLI using the OpenStackClient, without modifying the existing Blazar shell CLI. The existing shell command classes are used, by introducing a check in the base comand class to use either the client passed by Blazar shell, or the client using the osc_lib client_manager. The argument --physical-reservation is also removed for the create lease command when using the OpenStack client. Implements: blueprint openstackclient-support Change-Id: I97a7b91f0d05efc887307ac167e5c368276d4f81
This commit is contained in:
@@ -81,6 +81,11 @@ class BlazarCommand(OpenStackCommand):
|
|||||||
# self.formatters['table'] = TableFormatter()
|
# self.formatters['table'] = TableFormatter()
|
||||||
|
|
||||||
def get_client(self):
|
def get_client(self):
|
||||||
|
# client_manager.reservation is used for osc_lib, and should be used
|
||||||
|
# if it exists
|
||||||
|
if hasattr(self.app, 'client_manager'):
|
||||||
|
return self.app.client_manager.reservation
|
||||||
|
else:
|
||||||
return self.app.client
|
return self.app.client
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
|
|||||||
0
blazarclient/osc/__init__.py
Normal file
0
blazarclient/osc/__init__.py
Normal file
66
blazarclient/osc/plugin.py
Normal file
66
blazarclient/osc/plugin.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# 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 osc_lib import utils
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DEFAULT_API_VERSION = '1'
|
||||||
|
|
||||||
|
# Required by the OSC plugin interface
|
||||||
|
API_NAME = 'reservation'
|
||||||
|
API_VERSION_OPTION = 'os_reservations_api_version'
|
||||||
|
API_VERSIONS = {
|
||||||
|
'1': 'blazarclient.v1.client.Client',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Required by the OSC plugin interface
|
||||||
|
def make_client(instance):
|
||||||
|
reservation_client = utils.get_client_class(
|
||||||
|
API_NAME,
|
||||||
|
instance._api_version[API_NAME],
|
||||||
|
API_VERSIONS)
|
||||||
|
|
||||||
|
LOG.debug("Instantiating reservation client: %s", reservation_client)
|
||||||
|
|
||||||
|
client = reservation_client(
|
||||||
|
instance._api_version[API_NAME],
|
||||||
|
session=instance.session,
|
||||||
|
endpoint_override=instance.get_endpoint_for_service_type(
|
||||||
|
API_NAME,
|
||||||
|
interface=instance.interface,
|
||||||
|
region_name=instance._region_name)
|
||||||
|
)
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
# Required by the OSC plugin interface
|
||||||
|
def build_option_parser(parser):
|
||||||
|
"""Hook to add global options.
|
||||||
|
Called from openstackclient.shell.OpenStackShell.__init__()
|
||||||
|
after the builtin parser has been initialized. This is
|
||||||
|
where a plugin can add global options such as an API version setting.
|
||||||
|
:param argparse.ArgumentParser parser: The parser object that has been
|
||||||
|
initialized by OpenStackShell.
|
||||||
|
"""
|
||||||
|
parser.add_argument(
|
||||||
|
"--os-reservation-api-version",
|
||||||
|
metavar="<reservation-api-version>",
|
||||||
|
help="Reservation API version, default="
|
||||||
|
"{} (Env: OS_RESERVATION_API_VERSION)".format(
|
||||||
|
DEFAULT_API_VERSION)
|
||||||
|
)
|
||||||
|
return parser
|
||||||
@@ -60,9 +60,19 @@ class BlazarCommandTestCase(tests.TestCase):
|
|||||||
self.command = command.BlazarCommand(self.app, [])
|
self.command = command.BlazarCommand(self.app, [])
|
||||||
|
|
||||||
def test_get_client(self):
|
def test_get_client(self):
|
||||||
|
# Test that either client_manager.reservation or client is used,
|
||||||
|
# whichever exists
|
||||||
|
|
||||||
|
client_manager = self.app.client_manager
|
||||||
|
del self.app.client_manager
|
||||||
client = self.command.get_client()
|
client = self.command.get_client()
|
||||||
self.assertEqual(self.app.client, client)
|
self.assertEqual(self.app.client, client)
|
||||||
|
|
||||||
|
self.app.client_manager = client_manager
|
||||||
|
del self.app.client
|
||||||
|
client = self.command.get_client()
|
||||||
|
self.assertEqual(self.app.client_manager.reservation, client)
|
||||||
|
|
||||||
def test_get_parser(self):
|
def test_get_parser(self):
|
||||||
self.command.get_parser('TestCase')
|
self.command.get_parser('TestCase')
|
||||||
self.parser.assert_called_once_with('TestCase')
|
self.parser.assert_called_once_with('TestCase')
|
||||||
|
|||||||
36
blazarclient/tests/test_plugin.py
Normal file
36
blazarclient/tests/test_plugin.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# 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 unittest import mock
|
||||||
|
|
||||||
|
from blazarclient.osc import plugin
|
||||||
|
from blazarclient import tests
|
||||||
|
|
||||||
|
|
||||||
|
class ReservationPluginTests(tests.TestCase):
|
||||||
|
|
||||||
|
@mock.patch("blazarclient.v1.client.Client")
|
||||||
|
def test_make_client(self, mock_client):
|
||||||
|
instance = mock.Mock()
|
||||||
|
instance._api_version = {"reservation": "1"}
|
||||||
|
endpoint = "blazar_endpoint"
|
||||||
|
instance.get_endpoint_for_service_type = mock.Mock(
|
||||||
|
return_value=endpoint
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin.make_client(instance)
|
||||||
|
|
||||||
|
mock_client.assert_called_with(
|
||||||
|
"1",
|
||||||
|
session=instance.session,
|
||||||
|
endpoint_override=endpoint
|
||||||
|
)
|
||||||
@@ -91,7 +91,7 @@ class ShowLease(command.ShowCommand):
|
|||||||
log = logging.getLogger(__name__ + '.ShowLease')
|
log = logging.getLogger(__name__ + '.ShowLease')
|
||||||
|
|
||||||
|
|
||||||
class CreateLease(command.CreateCommand):
|
class CreateLeaseBase(command.CreateCommand):
|
||||||
"""Create a lease."""
|
"""Create a lease."""
|
||||||
resource = 'lease'
|
resource = 'lease'
|
||||||
json_indent = 4
|
json_indent = 4
|
||||||
@@ -100,7 +100,7 @@ class CreateLease(command.CreateCommand):
|
|||||||
default_end = _utc_now() + datetime.timedelta(days=1)
|
default_end = _utc_now() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(CreateLease, self).get_parser(prog_name)
|
parser = super(CreateLeaseBase, self).get_parser(prog_name)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'name', metavar=self.resource.upper(),
|
'name', metavar=self.resource.upper(),
|
||||||
help='Name for the %s' % self.resource
|
help='Name for the %s' % self.resource
|
||||||
@@ -126,22 +126,6 @@ class CreateLease(command.CreateCommand):
|
|||||||
'the end of the lease (default: depends on system default)',
|
'the end of the lease (default: depends on system default)',
|
||||||
default=None
|
default=None
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
'--physical-reservation',
|
|
||||||
metavar="<min=int,max=int,hypervisor_properties=str,"
|
|
||||||
"resource_properties=str,before_end=str>",
|
|
||||||
action='append',
|
|
||||||
dest='physical_reservations',
|
|
||||||
help='Create a reservation for physical compute hosts. '
|
|
||||||
'Specify option multiple times to create multiple '
|
|
||||||
'reservations. '
|
|
||||||
'min: minimum number of hosts to reserve. '
|
|
||||||
'max: maximum number of hosts to reserve. '
|
|
||||||
'hypervisor_properties: JSON string, see doc. '
|
|
||||||
'resource_properties: JSON string, see doc. '
|
|
||||||
'before_end: JSON string, see doc. ',
|
|
||||||
default=[]
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--reservation',
|
'--reservation',
|
||||||
metavar="<key=value>",
|
metavar="<key=value>",
|
||||||
@@ -165,36 +149,12 @@ class CreateLease(command.CreateCommand):
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
def args2body(self, parsed_args):
|
def args2body(self, parsed_args):
|
||||||
def parse_params(str_params, default):
|
params = self._generate_params(parsed_args)
|
||||||
request_params = {}
|
if not params['reservations']:
|
||||||
prog = re.compile('^(?:(.*),)?(%s)=(.*)$'
|
raise exception.IncorrectLease
|
||||||
% "|".join(default.keys()))
|
return params
|
||||||
|
|
||||||
while str_params != "":
|
|
||||||
match = prog.search(str_params)
|
|
||||||
|
|
||||||
if match is None:
|
|
||||||
raise exception.IncorrectLease(err_msg)
|
|
||||||
|
|
||||||
self.log.info("Matches: %s", match.groups())
|
|
||||||
k, v = match.group(2, 3)
|
|
||||||
if k in request_params.keys():
|
|
||||||
raise exception.DuplicatedLeaseParameters(err_msg)
|
|
||||||
else:
|
|
||||||
if strutils.is_int_like(v):
|
|
||||||
request_params[k] = int(v)
|
|
||||||
elif isinstance(defaults[k], list):
|
|
||||||
request_params[k] = jsonutils.loads(v)
|
|
||||||
else:
|
|
||||||
request_params[k] = v
|
|
||||||
|
|
||||||
str_params = match.group(1) if match.group(1) else ""
|
|
||||||
|
|
||||||
request_params.update({k: v for k, v in default.items()
|
|
||||||
if k not in request_params.keys() and
|
|
||||||
v is not None})
|
|
||||||
return request_params
|
|
||||||
|
|
||||||
|
def _generate_params(self, parsed_args):
|
||||||
params = {}
|
params = {}
|
||||||
if parsed_args.name:
|
if parsed_args.name:
|
||||||
params['name'] = parsed_args.name
|
params['name'] = parsed_args.name
|
||||||
@@ -243,6 +203,115 @@ class CreateLease(command.CreateCommand):
|
|||||||
params['reservations'] = []
|
params['reservations'] = []
|
||||||
params['events'] = []
|
params['events'] = []
|
||||||
|
|
||||||
|
reservations = []
|
||||||
|
for res_str in parsed_args.reservations:
|
||||||
|
err_msg = ("Invalid reservation argument '%s'. "
|
||||||
|
"Reservation arguments must be of the "
|
||||||
|
"form --reservation <key=value>"
|
||||||
|
% res_str)
|
||||||
|
|
||||||
|
if "physical:host" in res_str:
|
||||||
|
defaults = CREATE_RESERVATION_KEYS['physical:host']
|
||||||
|
elif "virtual:instance" in res_str:
|
||||||
|
defaults = CREATE_RESERVATION_KEYS['virtual:instance']
|
||||||
|
elif "virtual:floatingip" in res_str:
|
||||||
|
defaults = CREATE_RESERVATION_KEYS['virtual:floatingip']
|
||||||
|
else:
|
||||||
|
defaults = CREATE_RESERVATION_KEYS['others']
|
||||||
|
|
||||||
|
res_info = self._parse_params(res_str, defaults, err_msg)
|
||||||
|
reservations.append(res_info)
|
||||||
|
|
||||||
|
if reservations:
|
||||||
|
params['reservations'] += reservations
|
||||||
|
|
||||||
|
events = []
|
||||||
|
for event_str in parsed_args.events:
|
||||||
|
err_msg = ("Invalid event argument '%s'. "
|
||||||
|
"Event arguments must be of the "
|
||||||
|
"form --event <event_type=str,event_date=time>"
|
||||||
|
% event_str)
|
||||||
|
event_info = {"event_type": "", "event_date": ""}
|
||||||
|
for kv_str in event_str.split(","):
|
||||||
|
try:
|
||||||
|
k, v = kv_str.split("=", 1)
|
||||||
|
except ValueError:
|
||||||
|
raise exception.IncorrectLease(err_msg)
|
||||||
|
if k in event_info:
|
||||||
|
event_info[k] = v
|
||||||
|
else:
|
||||||
|
raise exception.IncorrectLease(err_msg)
|
||||||
|
if not event_info['event_type'] and not event_info['event_date']:
|
||||||
|
raise exception.IncorrectLease(err_msg)
|
||||||
|
event_date = event_info['event_date']
|
||||||
|
try:
|
||||||
|
date = datetime.datetime.strptime(event_date, '%Y-%m-%d %H:%M')
|
||||||
|
event_date = datetime.datetime.strftime(date, '%Y-%m-%d %H:%M')
|
||||||
|
event_info['event_date'] = event_date
|
||||||
|
except ValueError:
|
||||||
|
raise exception.IncorrectLease
|
||||||
|
events.append(event_info)
|
||||||
|
if events:
|
||||||
|
params['events'] = events
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
def _parse_params(self, str_params, default, err_msg):
|
||||||
|
request_params = {}
|
||||||
|
prog = re.compile('^(?:(.*),)?(%s)=(.*)$'
|
||||||
|
% "|".join(default.keys()))
|
||||||
|
|
||||||
|
while str_params != "":
|
||||||
|
match = prog.search(str_params)
|
||||||
|
|
||||||
|
if match is None:
|
||||||
|
raise exception.IncorrectLease(err_msg)
|
||||||
|
|
||||||
|
self.log.info("Matches: %s", match.groups())
|
||||||
|
k, v = match.group(2, 3)
|
||||||
|
if k in request_params.keys():
|
||||||
|
raise exception.DuplicatedLeaseParameters(err_msg)
|
||||||
|
else:
|
||||||
|
if strutils.is_int_like(v):
|
||||||
|
request_params[k] = int(v)
|
||||||
|
elif isinstance(default[k], list):
|
||||||
|
request_params[k] = jsonutils.loads(v)
|
||||||
|
else:
|
||||||
|
request_params[k] = v
|
||||||
|
|
||||||
|
str_params = match.group(1) if match.group(1) else ""
|
||||||
|
|
||||||
|
request_params.update({k: v for k, v in default.items()
|
||||||
|
if k not in request_params.keys() and
|
||||||
|
v is not None})
|
||||||
|
return request_params
|
||||||
|
|
||||||
|
|
||||||
|
class CreateLease(CreateLeaseBase):
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(CreateLease, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'--physical-reservation',
|
||||||
|
metavar="<min=int,max=int,hypervisor_properties=str,"
|
||||||
|
"resource_properties=str,before_end=str>",
|
||||||
|
action='append',
|
||||||
|
dest='physical_reservations',
|
||||||
|
help='Create a reservation for physical compute hosts. '
|
||||||
|
'Specify option multiple times to create multiple '
|
||||||
|
'reservations. '
|
||||||
|
'min: minimum number of hosts to reserve. '
|
||||||
|
'max: maximum number of hosts to reserve. '
|
||||||
|
'hypervisor_properties: JSON string, see doc. '
|
||||||
|
'resource_properties: JSON string, see doc. '
|
||||||
|
'before_end: JSON string, see doc. ',
|
||||||
|
default=[]
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def args2body(self, parsed_args):
|
||||||
|
params = self._generate_params(parsed_args)
|
||||||
|
|
||||||
physical_reservations = []
|
physical_reservations = []
|
||||||
for phys_res_str in parsed_args.physical_reservations:
|
for phys_res_str in parsed_args.physical_reservations:
|
||||||
err_msg = ("Invalid physical-reservation argument '%s'. "
|
err_msg = ("Invalid physical-reservation argument '%s'. "
|
||||||
@@ -252,7 +321,7 @@ class CreateLease(command.CreateCommand):
|
|||||||
"before_end=str>"
|
"before_end=str>"
|
||||||
% phys_res_str)
|
% phys_res_str)
|
||||||
defaults = CREATE_RESERVATION_KEYS["physical:host"]
|
defaults = CREATE_RESERVATION_KEYS["physical:host"]
|
||||||
phys_res_info = parse_params(phys_res_str, defaults)
|
phys_res_info = self._parse_params(phys_res_str, defaults, err_msg)
|
||||||
|
|
||||||
if not (phys_res_info['min'] and phys_res_info['max']):
|
if not (phys_res_info['min'] and phys_res_info['max']):
|
||||||
raise exception.IncorrectLease(err_msg)
|
raise exception.IncorrectLease(err_msg)
|
||||||
@@ -284,61 +353,10 @@ class CreateLease(command.CreateCommand):
|
|||||||
phys_res_info['resource_type'] = 'physical:host'
|
phys_res_info['resource_type'] = 'physical:host'
|
||||||
physical_reservations.append(phys_res_info)
|
physical_reservations.append(phys_res_info)
|
||||||
if physical_reservations:
|
if physical_reservations:
|
||||||
params['reservations'] += physical_reservations
|
# We prepend the physical_reservations to preserve legacy order
|
||||||
|
# of reservations
|
||||||
reservations = []
|
params['reservations'] = physical_reservations \
|
||||||
for res_str in parsed_args.reservations:
|
+ params['reservations']
|
||||||
err_msg = ("Invalid reservation argument '%s'. "
|
|
||||||
"Reservation arguments must be of the "
|
|
||||||
"form --reservation <key=value>"
|
|
||||||
% res_str)
|
|
||||||
|
|
||||||
if "physical:host" in res_str:
|
|
||||||
defaults = CREATE_RESERVATION_KEYS['physical:host']
|
|
||||||
elif "virtual:instance" in res_str:
|
|
||||||
defaults = CREATE_RESERVATION_KEYS['virtual:instance']
|
|
||||||
elif "virtual:floatingip" in res_str:
|
|
||||||
defaults = CREATE_RESERVATION_KEYS['virtual:floatingip']
|
|
||||||
else:
|
|
||||||
defaults = CREATE_RESERVATION_KEYS['others']
|
|
||||||
|
|
||||||
res_info = parse_params(res_str, defaults)
|
|
||||||
reservations.append(res_info)
|
|
||||||
|
|
||||||
if reservations:
|
|
||||||
params['reservations'] += reservations
|
|
||||||
|
|
||||||
if not params['reservations']:
|
|
||||||
raise exception.IncorrectLease
|
|
||||||
|
|
||||||
events = []
|
|
||||||
for event_str in parsed_args.events:
|
|
||||||
err_msg = ("Invalid event argument '%s'. "
|
|
||||||
"Event arguments must be of the "
|
|
||||||
"form --event <event_type=str,event_date=time>"
|
|
||||||
% event_str)
|
|
||||||
event_info = {"event_type": "", "event_date": ""}
|
|
||||||
for kv_str in event_str.split(","):
|
|
||||||
try:
|
|
||||||
k, v = kv_str.split("=", 1)
|
|
||||||
except ValueError:
|
|
||||||
raise exception.IncorrectLease(err_msg)
|
|
||||||
if k in event_info:
|
|
||||||
event_info[k] = v
|
|
||||||
else:
|
|
||||||
raise exception.IncorrectLease(err_msg)
|
|
||||||
if not event_info['event_type'] and not event_info['event_date']:
|
|
||||||
raise exception.IncorrectLease(err_msg)
|
|
||||||
event_date = event_info['event_date']
|
|
||||||
try:
|
|
||||||
date = datetime.datetime.strptime(event_date, '%Y-%m-%d %H:%M')
|
|
||||||
event_date = datetime.datetime.strftime(date, '%Y-%m-%d %H:%M')
|
|
||||||
event_info['event_date'] = event_date
|
|
||||||
except ValueError:
|
|
||||||
raise exception.IncorrectLease
|
|
||||||
events.append(event_info)
|
|
||||||
if events:
|
|
||||||
params['events'] = events
|
|
||||||
|
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ msgpack-python==0.4.0
|
|||||||
netaddr==0.7.18
|
netaddr==0.7.18
|
||||||
netifaces==0.10.4
|
netifaces==0.10.4
|
||||||
os-client-config==1.28.0
|
os-client-config==1.28.0
|
||||||
|
osc-lib==1.3.0
|
||||||
oslo.config==5.2.0
|
oslo.config==5.2.0
|
||||||
oslo.context==2.19.2
|
oslo.context==2.19.2
|
||||||
oslo.i18n==3.15.3
|
oslo.i18n==3.15.3
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add openstackclient plugin support, enabling blazar commands to be used
|
||||||
|
within the openstack CLI.
|
||||||
@@ -9,3 +9,4 @@ oslo.i18n>=3.15.3 # Apache-2.0
|
|||||||
oslo.log>=3.36.0 # Apache-2.0
|
oslo.log>=3.36.0 # Apache-2.0
|
||||||
oslo.utils>=3.33.0 # Apache-2.0
|
oslo.utils>=3.33.0 # Apache-2.0
|
||||||
keystoneauth1>=3.4.0 # Apache-2.0
|
keystoneauth1>=3.4.0 # Apache-2.0
|
||||||
|
osc-lib>=1.3.0 # Apache-2.0
|
||||||
|
|||||||
19
setup.cfg
19
setup.cfg
@@ -30,3 +30,22 @@ packages =
|
|||||||
[entry_points]
|
[entry_points]
|
||||||
console_scripts =
|
console_scripts =
|
||||||
blazar = blazarclient.shell:main
|
blazar = blazarclient.shell:main
|
||||||
|
|
||||||
|
openstack.cli.extension =
|
||||||
|
reservation = blazarclient.osc.plugin
|
||||||
|
|
||||||
|
openstack.reservation.v1 =
|
||||||
|
reservation_floatingip_create = blazarclient.v1.shell_commands.floatingips:CreateFloatingIP
|
||||||
|
reservation_floatingip_delete = blazarclient.v1.shell_commands.floatingips:DeleteFloatingIP
|
||||||
|
reservation_floatingip_list = blazarclient.v1.shell_commands.floatingips:ListFloatingIPs
|
||||||
|
reservation_floatingip_show = blazarclient.v1.shell_commands.floatingips:ShowFloatingIP
|
||||||
|
reservation_host_create = blazarclient.v1.shell_commands.hosts:CreateHost
|
||||||
|
reservation_host_delete = blazarclient.v1.shell_commands.hosts:DeleteHost
|
||||||
|
reservation_host_list = blazarclient.v1.shell_commands.hosts:ListHosts
|
||||||
|
reservation_host_set = blazarclient.v1.shell_commands.hosts:UpdateHost
|
||||||
|
reservation_host_show = blazarclient.v1.shell_commands.hosts:ShowHost
|
||||||
|
reservation_lease_create = blazarclient.v1.shell_commands.leases:CreateLeaseBase
|
||||||
|
reservation_lease_delete = blazarclient.v1.shell_commands.leases:DeleteLease
|
||||||
|
reservation_lease_list = blazarclient.v1.shell_commands.leases:ListLeases
|
||||||
|
reservation_lease_set = blazarclient.v1.shell_commands.leases:UpdateLease
|
||||||
|
reservation_lease_show = blazarclient.v1.shell_commands.leases:ShowLease
|
||||||
|
|||||||
Reference in New Issue
Block a user