Drop the legacy client
Change-Id: I1d367e87f25daa1adad28409903c1de9d5a1d801
This commit is contained in:
parent
393960b3a6
commit
c36e647d95
@ -1,171 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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 argparse
|
||||
|
||||
from masakariclient.common.i18n import _
|
||||
from masakariclient.common import utils
|
||||
|
||||
|
||||
def add_global_args(parser, version):
|
||||
# GLOBAL ARGUMENTS
|
||||
parser.add_argument(
|
||||
'-h', '--help', action='store_true',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--masakari-api-version', action='version', version=version,
|
||||
default=utils.env('MASAKARI_API_VERSION', default='1'),
|
||||
help=_('Version number for Masakari API to use, Default to "1".'))
|
||||
|
||||
parser.add_argument(
|
||||
'-d', '--debug',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Print debugging output.'))
|
||||
|
||||
|
||||
def add_global_identity_args(parser):
|
||||
parser.add_argument(
|
||||
'--os-auth-plugin', dest='auth_plugin', metavar='AUTH_PLUGIN',
|
||||
default=utils.env('OS_AUTH_PLUGIN', default=None),
|
||||
help=_('Authentication plugin, default to env[OS_AUTH_PLUGIN]'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-auth-url', dest='auth_url', metavar='AUTH_URL',
|
||||
default=utils.env('OS_AUTH_URL'),
|
||||
help=_('Defaults to env[OS_AUTH_URL]'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-id', dest='project_id', metavar='PROJECT_ID',
|
||||
default=utils.env('OS_PROJECT_ID'),
|
||||
help=_('Defaults to env[OS_PROJECT_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-name', dest='project_name', metavar='PROJECT_NAME',
|
||||
default=utils.env('OS_PROJECT_NAME'),
|
||||
help=_('Defaults to env[OS_PROJECT_NAME].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-tenant-id', dest='tenant_id', metavar='TENANT_ID',
|
||||
default=utils.env('OS_TENANT_ID'),
|
||||
help=_('Defaults to env[OS_TENANT_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-tenant-name', dest='tenant_name', metavar='TENANT_NAME',
|
||||
default=utils.env('OS_TENANT_NAME'),
|
||||
help=_('Defaults to env[OS_TENANT_NAME].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-domain-id', dest='domain_id', metavar='DOMAIN_ID',
|
||||
default=utils.env('OS_DOMAIN_ID'),
|
||||
help=_('Domain ID for scope of authorization, defaults to '
|
||||
'env[OS_DOMAIN_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-domain-name', dest='domain_name', metavar='DOMAIN_NAME',
|
||||
default=utils.env('OS_DOMAIN_NAME'),
|
||||
help=_('Domain name for scope of authorization, defaults to '
|
||||
'env[OS_DOMAIN_NAME].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-domain-id', dest='project_domain_id',
|
||||
metavar='PROJECT_DOMAIN_ID',
|
||||
default=utils.env('OS_PROJECT_DOMAIN_ID'),
|
||||
help=_('Project domain ID for scope of authorization, defaults to '
|
||||
'env[OS_PROJECT_DOMAIN_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-project-domain-name', dest='project_domain_name',
|
||||
metavar='PROJECT_DOMAIN_NAME',
|
||||
default=utils.env('OS_PROJECT_DOMAIN_NAME'),
|
||||
help=_('Project domain name for scope of authorization, defaults to '
|
||||
'env[OS_PROJECT_DOMAIN_NAME].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-user-domain-id', dest='user_domain_id',
|
||||
metavar='USER_DOMAIN_ID',
|
||||
default=utils.env('OS_USER_DOMAIN_ID'),
|
||||
help=_('User domain ID for scope of authorization, defaults to '
|
||||
'env[OS_USER_DOMAIN_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-user-domain-name', dest='user_domain_name',
|
||||
metavar='USER_DOMAIN_NAME',
|
||||
default=utils.env('OS_USER_DOMAIN_NAME'),
|
||||
help=_('User domain name for scope of authorization, defaults to '
|
||||
'env[OS_USER_DOMAIN_NAME].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-username', dest='username', metavar='USERNAME',
|
||||
default=utils.env('OS_USERNAME'),
|
||||
help=_('Defaults to env[OS_USERNAME].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-user-id', dest='user_id', metavar='USER_ID',
|
||||
default=utils.env('OS_USER_ID'),
|
||||
help=_('Defaults to env[OS_USER_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-password', dest='password', metavar='PASSWORD',
|
||||
default=utils.env('OS_PASSWORD'),
|
||||
help=_('Defaults to env[OS_PASSWORD]'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-trust-id', dest='trust_id', metavar='TRUST_ID',
|
||||
default=utils.env('OS_TRUST_ID'),
|
||||
help=_('Defaults to env[OS_TRUST_ID]'))
|
||||
|
||||
verify_group = parser.add_mutually_exclusive_group()
|
||||
|
||||
verify_group.add_argument(
|
||||
'--os-cacert', dest='verify', metavar='CA_BUNDLE_FILE',
|
||||
default=utils.env('OS_CACERT', default=True),
|
||||
help=_('Path of CA TLS certificate(s) used to verify the remote '
|
||||
'server\'s certificate. Without this option masakari looks '
|
||||
'for the default system CA certificates.'))
|
||||
|
||||
verify_group.add_argument(
|
||||
'--verify',
|
||||
action='store_true',
|
||||
help=_('Verify server certificate (default)'))
|
||||
|
||||
verify_group.add_argument(
|
||||
'--insecure', dest='verify', action='store_false',
|
||||
help=_('Explicitly allow masakariclient to perform "insecure SSL" '
|
||||
'(HTTPS) requests. The server\'s certificate will not be '
|
||||
'verified against any certificate authorities. This '
|
||||
'option should be used with caution.'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-token', dest='token', metavar='TOKEN',
|
||||
default=utils.env('OS_TOKEN', default=None),
|
||||
help=_('A string token to bootstrap the Keystone database, defaults '
|
||||
'to env[OS_TOKEN]'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-access-info', dest='access_info', metavar='ACCESS_INFO',
|
||||
default=utils.env('OS_ACCESS_INFO'),
|
||||
help=_('Access info, defaults to env[OS_ACCESS_INFO]'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-interface', dest='interface', metavar='INTERFACE',
|
||||
default=utils.env('OS_INTERFACE', default='internal'),
|
||||
help=_('API Interface to use [public, internal, admin]'
|
||||
', defaults to env[OS_INTERFACE]'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-region-name', dest='region_name', metavar='REGION_NAME',
|
||||
default=utils.env('OS_REGION_NAME'),
|
||||
help=_('Region of the cloud to use, defaults to env[OS_REGION_NAME]'))
|
@ -1,28 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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 masakariclient.common import utils
|
||||
|
||||
|
||||
def Client(api_ver, *args, **kwargs):
|
||||
"""Import versioned client module.
|
||||
|
||||
:param api_ver: API version required.
|
||||
:param args: API args.
|
||||
:param kwargs: the auth parameters for client.
|
||||
"""
|
||||
module = utils.import_versioned_module(api_ver, 'client')
|
||||
cls = getattr(module, 'Client')
|
||||
|
||||
return cls(*args, **kwargs)
|
@ -12,20 +12,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import prettytable
|
||||
import textwrap
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from masakariclient.common import exception as exc
|
||||
from masakariclient.common.i18n import _
|
||||
|
||||
|
||||
def format_parameters(params, parse_semicolon=True):
|
||||
def _format_parameters(params, parse_semicolon=True):
|
||||
"""Reformat parameters into dict of format expected by the API."""
|
||||
if not params:
|
||||
return {}
|
||||
@ -62,113 +55,6 @@ def remove_unspecified_items(attrs):
|
||||
return attrs
|
||||
|
||||
|
||||
def import_versioned_module(version, submodule=None):
|
||||
module = 'masakariclient.v%s' % version
|
||||
if submodule:
|
||||
module = '.'.join((module, submodule))
|
||||
return importutils.import_module(module)
|
||||
|
||||
|
||||
def arg(*args, **kwargs):
|
||||
"""Decorator for CLI args."""
|
||||
|
||||
def _decorator(func):
|
||||
if not hasattr(func, 'arguments'):
|
||||
func.arguments = []
|
||||
|
||||
if (args, kwargs) not in func.arguments:
|
||||
func.arguments.insert(0, (args, kwargs))
|
||||
|
||||
return func
|
||||
|
||||
return _decorator
|
||||
|
||||
|
||||
def env(*args, **kwargs):
|
||||
"""Returns the first environment variable set.
|
||||
|
||||
If all are empty, defaults to '' or keyword arg `default`.
|
||||
"""
|
||||
for arg in args:
|
||||
value = os.environ.get(arg)
|
||||
if value:
|
||||
return value
|
||||
return kwargs.get('default', '')
|
||||
|
||||
|
||||
def print_list(objs, fields, formatters={}, sortby_index=None):
|
||||
"""Print list data by PrettyTable."""
|
||||
|
||||
if sortby_index is None:
|
||||
sortby = None
|
||||
else:
|
||||
sortby = fields[sortby_index]
|
||||
mixed_case_fields = ['serverId']
|
||||
pt = prettytable.PrettyTable([f for f in fields], caching=False)
|
||||
pt.align = 'l'
|
||||
|
||||
for o in objs:
|
||||
row = []
|
||||
for field in fields:
|
||||
if field in formatters:
|
||||
row.append(formatters[field](o))
|
||||
else:
|
||||
if field in mixed_case_fields:
|
||||
field_name = field.replace(' ', '_')
|
||||
else:
|
||||
field_name = field.lower().replace(' ', '_')
|
||||
data = getattr(o, field_name, '')
|
||||
if data is None:
|
||||
data = '-'
|
||||
# '\r' would break the table, so remove it.
|
||||
data = str(data).replace("\r", "")
|
||||
row.append(data)
|
||||
pt.add_row(row)
|
||||
|
||||
if sortby is not None:
|
||||
result = encodeutils.safe_encode(pt.get_string(sortby=sortby))
|
||||
else:
|
||||
result = encodeutils.safe_encode(pt.get_string())
|
||||
|
||||
result = result.decode()
|
||||
|
||||
print(result)
|
||||
|
||||
|
||||
def print_dict(d, dict_property="Property", dict_value="Value", wrap=0):
|
||||
"""Print dictionary data (eg. show) by PrettyTable."""
|
||||
|
||||
pt = prettytable.PrettyTable([dict_property, dict_value], caching=False)
|
||||
pt.align = 'l'
|
||||
for k, v in sorted(d.items()):
|
||||
# convert dict to str to check length
|
||||
if isinstance(v, (dict, list)):
|
||||
v = jsonutils.dumps(v)
|
||||
if wrap > 0:
|
||||
v = textwrap.fill(str(v), wrap)
|
||||
# if value has a newline, add in multiple rows
|
||||
# e.g. fault with stacktrace
|
||||
if v and isinstance(v, str) and (r'\n' in v or '\r' in v):
|
||||
# '\r' would break the table, so remove it.
|
||||
if '\r' in v:
|
||||
v = v.replace('\r', '')
|
||||
lines = v.strip().split(r'\n')
|
||||
col1 = k
|
||||
for line in lines:
|
||||
pt.add_row([col1, line])
|
||||
col1 = ''
|
||||
else:
|
||||
if v is None:
|
||||
v = '-'
|
||||
pt.add_row([k, v])
|
||||
|
||||
result = encodeutils.safe_encode(pt.get_string())
|
||||
|
||||
result = result.decode()
|
||||
|
||||
print(result)
|
||||
|
||||
|
||||
def format_sort_filter_params(parsed_args):
|
||||
queries = {}
|
||||
limit = parsed_args.limit
|
||||
@ -196,7 +82,7 @@ def format_sort_filter_params(parsed_args):
|
||||
queries['sort_dir'] = sort_dirs
|
||||
|
||||
if parsed_args.filters:
|
||||
queries.update(format_parameters(parsed_args.filters))
|
||||
queries.update(_format_parameters(parsed_args.filters))
|
||||
|
||||
return queries
|
||||
|
||||
|
@ -1,206 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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 argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from oslo_utils import encodeutils
|
||||
|
||||
import masakariclient
|
||||
from masakariclient import cliargs
|
||||
from masakariclient import client as masakari_client
|
||||
from masakariclient.common import exception as exc
|
||||
from masakariclient.common.i18n import _
|
||||
from masakariclient.common import utils
|
||||
|
||||
USER_AGENT = 'python-masakariclient'
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MasakariShell(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def do_bash_completion(self, args):
|
||||
"""All of the commands and options to stdout."""
|
||||
commands = set()
|
||||
options = set()
|
||||
for sc_str, sc in self.subcommands.items():
|
||||
if sc_str == 'bash_completion' or sc_str == 'bash-completion':
|
||||
continue
|
||||
|
||||
commands.add(sc_str)
|
||||
for option in list(sc._optionals._option_string_actions):
|
||||
options.add(option)
|
||||
|
||||
print(' '.join(commands | options))
|
||||
|
||||
def _add_bash_completion_subparser(self, subparsers):
|
||||
subparser = subparsers.add_parser('bash_completion',
|
||||
add_help=False,
|
||||
formatter_class=HelpFormatter)
|
||||
|
||||
subparser.set_defaults(func=self.do_bash_completion)
|
||||
self.subcommands['bash_completion'] = subparser
|
||||
|
||||
def _get_subcommand_parser(self, base_parser, version):
|
||||
parser = base_parser
|
||||
|
||||
self.subcommands = {}
|
||||
subparsers = parser.add_subparsers(metavar='<subcommand>')
|
||||
submodule = utils.import_versioned_module(version, 'shell')
|
||||
self._find_actions(subparsers, submodule)
|
||||
self._add_bash_completion_subparser(subparsers)
|
||||
|
||||
return parser
|
||||
|
||||
def _find_actions(self, subparsers, actions_module):
|
||||
for attr in (a for a in dir(actions_module) if a.startswith('do_')):
|
||||
command = attr[3:].replace('_', '-')
|
||||
callback = getattr(actions_module, attr)
|
||||
|
||||
desc = callback.__doc__ or ''
|
||||
help = desc.strip().split('\n')[0]
|
||||
arguments = getattr(callback, 'arguments', [])
|
||||
|
||||
subparser = subparsers.add_parser(command,
|
||||
help=help,
|
||||
description=desc,
|
||||
add_help=False,
|
||||
formatter_class=HelpFormatter)
|
||||
|
||||
subparser.add_argument('-h', '--help',
|
||||
action='help',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
for (args, kwargs) in arguments:
|
||||
subparser.add_argument(*args, **kwargs)
|
||||
subparser.set_defaults(func=callback)
|
||||
|
||||
self.subcommands[command] = subparser
|
||||
|
||||
def _setup_masakari_client(self, api_ver, args):
|
||||
"""Create masakari client using given args."""
|
||||
kwargs = {
|
||||
'auth_plugin': args.auth_plugin or 'password',
|
||||
'auth_url': args.auth_url,
|
||||
'project_name': args.project_name or args.tenant_name,
|
||||
'project_id': args.project_id or args.tenant_id,
|
||||
'domain_name': args.domain_name,
|
||||
'domain_id': args.domain_id,
|
||||
'project_domain_name': args.project_domain_name,
|
||||
'project_domain_id': args.project_domain_id,
|
||||
'user_domain_name': args.user_domain_name,
|
||||
'user_domain_id': args.user_domain_id,
|
||||
'username': args.username,
|
||||
'user_id': args.user_id,
|
||||
'password': args.password,
|
||||
'verify': args.verify,
|
||||
'token': args.token,
|
||||
'trust_id': args.trust_id,
|
||||
'interface': args.interface,
|
||||
'region_name': args.region_name,
|
||||
}
|
||||
|
||||
return masakari_client.Client(api_ver, user_agent=USER_AGENT, **kwargs)
|
||||
|
||||
def _setup_logging(self, debug):
|
||||
if debug:
|
||||
log_level = logging.DEBUG
|
||||
else:
|
||||
log_level = logging.WARNING
|
||||
log_format = "%(levelname)s (%(module)s) %(message)s"
|
||||
logging.basicConfig(format=log_format, level=log_level)
|
||||
logging.getLogger('iso8601').setLevel(logging.WARNING)
|
||||
logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING)
|
||||
|
||||
def main(self, argv):
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='masakari',
|
||||
description="masakari shell",
|
||||
epilog='Type "masakari help <COMMAND>" for help on a specific '
|
||||
'command.',
|
||||
add_help=False,
|
||||
)
|
||||
# add add arguments
|
||||
cliargs.add_global_args(parser, masakariclient.__version__)
|
||||
cliargs.add_global_identity_args(parser)
|
||||
|
||||
# parse main arguments
|
||||
(options, args) = parser.parse_known_args(argv)
|
||||
|
||||
self._setup_logging(options.debug)
|
||||
|
||||
base_parser = parser
|
||||
api_ver = options.masakari_api_version
|
||||
|
||||
# add subparser
|
||||
subcommand_parser = self._get_subcommand_parser(base_parser, api_ver)
|
||||
self.parser = subcommand_parser
|
||||
|
||||
# --help/-h or no arguments
|
||||
if not args and options.help or not argv:
|
||||
self.do_help(options)
|
||||
return 0
|
||||
|
||||
args = subcommand_parser.parse_args(argv)
|
||||
|
||||
sc = self._setup_masakari_client(api_ver, args)
|
||||
# call specified function
|
||||
args.func(sc.service, args)
|
||||
|
||||
@utils.arg('command', metavar='<subcommand>', nargs='?',
|
||||
help=_('Display help for <subcommand>.'))
|
||||
def do_help(self, args):
|
||||
"""Display help about this program or one of its subcommands."""
|
||||
if getattr(args, 'command', None):
|
||||
if args.command in self.subcommands:
|
||||
self.subcommands[args.command].print_help()
|
||||
else:
|
||||
raise exc.CommandError("'%s' is not a valid subcommand" %
|
||||
args.command)
|
||||
else:
|
||||
self.parser.print_help()
|
||||
|
||||
|
||||
class HelpFormatter(argparse.HelpFormatter):
|
||||
def start_section(self, heading):
|
||||
heading = '%s%s' % (heading[0].upper(), heading[1:])
|
||||
super(HelpFormatter, self).start_section(heading)
|
||||
|
||||
|
||||
def main(args=None):
|
||||
try:
|
||||
print(_("Deprecated: masakari CLI is deprecated and will be removed "
|
||||
"after Stein is released. Use openstack CLI instead."),
|
||||
file=sys.stderr)
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
|
||||
MasakariShell().main(args)
|
||||
except KeyboardInterrupt:
|
||||
print(_("KeyboardInterrupt masakari client"), sys.stderr)
|
||||
return 130
|
||||
except Exception as e:
|
||||
if '--debug' in args or '-d' in args:
|
||||
raise
|
||||
else:
|
||||
print(encodeutils.safe_encode(str(e), sys.stderr))
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,73 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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 testtools
|
||||
from unittest import mock
|
||||
|
||||
from masakariclient import cliargs
|
||||
|
||||
|
||||
class TestCliArgs(testtools.TestCase):
|
||||
|
||||
def test_add_global_identity_args(self):
|
||||
parser = mock.Mock()
|
||||
cliargs.add_global_identity_args(parser)
|
||||
expected = [
|
||||
'--os-auth-plugin',
|
||||
'--os-auth-url',
|
||||
'--os-project-id',
|
||||
'--os-project-name',
|
||||
'--os-tenant-id',
|
||||
'--os-tenant-name',
|
||||
'--os-domain-id',
|
||||
'--os-domain-name',
|
||||
'--os-project-domain-id',
|
||||
'--os-project-domain-name',
|
||||
'--os-user-domain-id',
|
||||
'--os-user-domain-name',
|
||||
'--os-username',
|
||||
'--os-user-id',
|
||||
'--os-password',
|
||||
'--os-trust-id',
|
||||
'--os-token',
|
||||
'--os-access-info',
|
||||
'--os-interface',
|
||||
'--os-region-name'
|
||||
]
|
||||
|
||||
options = [arg[0][0] for arg in parser.add_argument.call_args_list]
|
||||
self.assertEqual(expected, options)
|
||||
|
||||
parser.add_mutually_exclusive_group.assert_called_once_with()
|
||||
group = parser.add_mutually_exclusive_group.return_value
|
||||
|
||||
verify_opts = [arg[0][0] for arg in group.add_argument.call_args_list]
|
||||
verify_args = [
|
||||
'--os-cacert',
|
||||
'--verify',
|
||||
'--insecure'
|
||||
]
|
||||
self.assertEqual(verify_args, verify_opts)
|
||||
|
||||
def test_add_global_args(self):
|
||||
parser = mock.Mock()
|
||||
cliargs.add_global_args(parser, '1')
|
||||
expected = [
|
||||
'-h',
|
||||
'--masakari-api-version',
|
||||
'-d'
|
||||
]
|
||||
|
||||
options = [arg[0][0] for arg in parser.add_argument.call_args_list]
|
||||
self.assertEqual(expected, options)
|
@ -1,47 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
test_masakariclient
|
||||
----------------------------------
|
||||
|
||||
Tests for `masakariclient` module.
|
||||
"""
|
||||
from unittest import mock
|
||||
|
||||
from masakariclient import client as mc
|
||||
from masakariclient.common import utils
|
||||
from masakariclient.tests import base
|
||||
|
||||
|
||||
class FakeClient(object):
|
||||
|
||||
def __init__(self, session):
|
||||
super(FakeClient, self).__init__()
|
||||
self.session = session
|
||||
|
||||
|
||||
class TestMasakariclient(base.TestCase):
|
||||
|
||||
@mock.patch.object(utils, 'import_versioned_module')
|
||||
def test_client_init(self, mock_import):
|
||||
the_module = mock.Mock()
|
||||
the_module.Client = FakeClient
|
||||
mock_import.return_value = the_module
|
||||
session = mock.Mock()
|
||||
|
||||
res = mc.Client('FAKE_VER', session)
|
||||
|
||||
mock_import.assert_called_once_with('FAKE_VER', 'client')
|
||||
self.assertIsInstance(res, FakeClient)
|
@ -1,128 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
test_shell
|
||||
----------------------------------
|
||||
|
||||
Tests for `masakariclient` module.
|
||||
"""
|
||||
import io
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
import sys
|
||||
import testtools
|
||||
|
||||
from masakariclient import shell
|
||||
from masakariclient.tests import base
|
||||
|
||||
|
||||
class FakeClient(object):
|
||||
|
||||
def __init__(self):
|
||||
super(FakeClient, self).__init__()
|
||||
self.service = FakeService()
|
||||
|
||||
|
||||
class FakeService(object):
|
||||
|
||||
def __init__(self):
|
||||
super(FakeService, self).__init__()
|
||||
|
||||
def do_notification_list(self):
|
||||
pass
|
||||
|
||||
|
||||
class HelpFormatterTest(testtools.TestCase):
|
||||
|
||||
def test_start_section(self):
|
||||
formatter = shell.HelpFormatter('masakari')
|
||||
res = formatter.start_section(('dummyheading', 'dummy', 'dummy'))
|
||||
self.assertIsNone(res)
|
||||
heading = formatter._current_section.heading
|
||||
self.assertEqual("DUMMYHEADING('dummy', 'dummy')", heading)
|
||||
|
||||
|
||||
class TestMasakariShell(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestMasakariShell, self).setUp()
|
||||
|
||||
def _shell(self, func, *args, **kwargs):
|
||||
orig_out = sys.stdout
|
||||
sys.stdout = io.StringIO()
|
||||
func(*args, **kwargs)
|
||||
output = sys.stdout.getvalue()
|
||||
sys.stdout.close()
|
||||
sys.stdout = orig_out
|
||||
|
||||
return output
|
||||
|
||||
def test_do_bash_completion(self):
|
||||
sh = shell.MasakariShell()
|
||||
sc1 = mock.Mock()
|
||||
sc2 = mock.Mock()
|
||||
sc1._optionals._option_string_actions = ('A1', 'A2', 'C')
|
||||
sc2._optionals._option_string_actions = ('B1', 'B2', 'C')
|
||||
sh.subcommands = {
|
||||
'command-foo': sc1,
|
||||
'command-bar': sc2,
|
||||
'bash-completion': None,
|
||||
'bash_completion': None,
|
||||
}
|
||||
|
||||
output = self._shell(sh.do_bash_completion, None)
|
||||
|
||||
output = output.split('\n')[0]
|
||||
output_list = output.split(' ')
|
||||
for option in ('A1', 'A2', 'C', 'B1', 'B2',
|
||||
'command-foo', 'command-bar'):
|
||||
self.assertIn(option, output_list)
|
||||
|
||||
@mock.patch.object(logging, 'basicConfig')
|
||||
@mock.patch.object(logging, 'getLogger')
|
||||
def test_setup_logging_debug_true(self, moc_getLogger,
|
||||
moc_basicConfig):
|
||||
sh = shell.MasakariShell()
|
||||
sh._setup_logging(True)
|
||||
|
||||
moc_basicConfig.assert_called_once_with(
|
||||
format="%(levelname)s (%(module)s) %(message)s",
|
||||
level=logging.DEBUG)
|
||||
mock_calls = [
|
||||
mock.call('iso8601'),
|
||||
mock.call().setLevel(logging.WARNING),
|
||||
mock.call('urllib3.connectionpool'),
|
||||
mock.call().setLevel(logging.WARNING),
|
||||
]
|
||||
moc_getLogger.assert_has_calls(mock_calls)
|
||||
|
||||
@mock.patch.object(logging, 'basicConfig')
|
||||
@mock.patch.object(logging, 'getLogger')
|
||||
def test_setup_logging_debug_false(self,
|
||||
moc_getLogger,
|
||||
moc_basicConfig):
|
||||
sh = shell.MasakariShell()
|
||||
sh._setup_logging(False)
|
||||
|
||||
moc_basicConfig.assert_called_once_with(
|
||||
format="%(levelname)s (%(module)s) %(message)s",
|
||||
level=logging.WARNING)
|
||||
mock_calls = [
|
||||
mock.call('iso8601'),
|
||||
mock.call().setLevel(logging.WARNING),
|
||||
mock.call('urllib3.connectionpool'),
|
||||
mock.call().setLevel(logging.WARNING),
|
||||
]
|
||||
moc_getLogger.assert_has_calls(mock_calls)
|
@ -1,29 +0,0 @@
|
||||
# Copyright(c) 2017 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
class FakeSegment(object):
|
||||
def __init__(self, segment_values):
|
||||
self.segment_values = segment_values
|
||||
|
||||
def to_dict(self):
|
||||
return self.segment_values
|
||||
|
||||
|
||||
class FakeHost(object):
|
||||
def __init__(self, host_values):
|
||||
self.host_values = host_values
|
||||
|
||||
def to_dict(self):
|
||||
return self.host_values
|
@ -1,86 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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.
|
||||
"""
|
||||
test_masakariclient
|
||||
----------------------------------
|
||||
|
||||
Tests for `masakariclient` module.
|
||||
"""
|
||||
from unittest import mock
|
||||
|
||||
from keystoneauth1.identity.generic import password as ks_password
|
||||
from keystoneauth1 import session as ks_session
|
||||
from openstack import connection
|
||||
|
||||
from masakariclient.tests import base
|
||||
import masakariclient.v1.client as mc
|
||||
|
||||
|
||||
class FakeConnection(object):
|
||||
|
||||
def __init__(self, prof=None, user_agent=None, **kwargs):
|
||||
super(FakeConnection, self).__init__()
|
||||
self.ha = None
|
||||
|
||||
|
||||
class TestV1Client(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestV1Client, self).setUp()
|
||||
self.auth = mock.Mock()
|
||||
self.session = mock.Mock()
|
||||
self.conn = mock.Mock()
|
||||
self.service = mock.Mock()
|
||||
self.conn.instance_ha = self.service
|
||||
|
||||
@mock.patch.object(connection, 'Connection')
|
||||
@mock.patch.object(ks_session, 'Session')
|
||||
@mock.patch.object(ks_password, 'Password')
|
||||
def test_client_init(self, mock_password, mock_session, mock_connection):
|
||||
|
||||
mock_password.return_value = self.auth
|
||||
mock_session.return_value = self.session
|
||||
mock_connection.return_value = self.conn
|
||||
|
||||
fake_auth_url = 'fake_auth_url'
|
||||
fake_username = 'fake_username'
|
||||
fake_password = 'fake_password'
|
||||
fake_user_domain_id = 'fake_user_domain_id'
|
||||
fake_project_name = 'fake_project_name'
|
||||
fake_project_domain_id = 'fake_project_domain_id'
|
||||
fake_interface = 'fake_interface'
|
||||
fake_region_name = 'fake_region_name'
|
||||
|
||||
res = mc.Client(auth_url=fake_auth_url,
|
||||
username=fake_username,
|
||||
password=fake_password,
|
||||
user_domain_id=fake_user_domain_id,
|
||||
project_name=fake_project_name,
|
||||
project_domain_id=fake_project_domain_id,
|
||||
interface=fake_interface,
|
||||
region_name=fake_region_name)
|
||||
|
||||
self.assertEqual(self.conn.instance_ha, res.service)
|
||||
mock_password.assert_called_once_with(
|
||||
auth_url=fake_auth_url,
|
||||
username=fake_username,
|
||||
password=fake_password,
|
||||
user_domain_id=fake_user_domain_id,
|
||||
project_name=fake_project_name,
|
||||
project_domain_id=fake_project_domain_id)
|
||||
mock_session.assert_called_once_with(auth=self.auth)
|
||||
mock_connection.assert_called_once_with(
|
||||
session=self.session, interface=fake_interface,
|
||||
region_name=fake_region_name,
|
||||
ha_api_version=None)
|
@ -1,371 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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.
|
||||
"""
|
||||
test_masakariclient
|
||||
----------------------------------
|
||||
|
||||
Tests for `masakariclient` module.
|
||||
"""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
import io
|
||||
import sys
|
||||
|
||||
from openstack import exceptions as sdk_exc
|
||||
from openstack.instance_ha.v1 import _proxy
|
||||
|
||||
from masakariclient.common.i18n import _
|
||||
from masakariclient.common import utils
|
||||
from masakariclient import shell
|
||||
from masakariclient.tests import base
|
||||
from masakariclient.tests.unit.v1 import fakes
|
||||
import masakariclient.v1.shell as ms
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestV1Shell(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestV1Shell, self).setUp()
|
||||
self.notification_vals = {
|
||||
'notification_uuid': 'b3bf75d7-c2e9-4023-a10b-e5b464b9b539',
|
||||
'source_host_uuid': '68fa7386-983e-4497-b5c4-3780f774d302',
|
||||
'created_at': '2016-11-15T12:24:39.000000',
|
||||
'updated_at': None,
|
||||
'payload': {'event': 'STOPPED'},
|
||||
'generated_time': '2016-10-10T10:00:00.000000',
|
||||
'type': 'VM',
|
||||
'id': '27'}
|
||||
|
||||
self.segment_vals = {
|
||||
'uuid': '870da19d-37ec-41d2-a4b2-7be54b0d6ec9',
|
||||
'created_at': '2016-11-17T10:08:32.000000',
|
||||
'recovery_method': 'auto',
|
||||
'updated_at': '2016-11-17T10:09:56.000000',
|
||||
'name': 'testsegment05',
|
||||
'service_type': 'testsegment01_auto',
|
||||
'id': '14',
|
||||
'description': 'UPDATE Discription'}
|
||||
|
||||
self.hosts_vals = {
|
||||
'reserved': False,
|
||||
'uuid': '0951e72c-49f5-46aa-8465-2d61ed3b46d9',
|
||||
'deleted': False,
|
||||
'on_maintenance': False,
|
||||
'created_at': '2016-11-29T11:10:51.000000',
|
||||
'control_attributes': 'control-attributesX',
|
||||
'updated_at': '2016-11-29T11:30:18.000000',
|
||||
'name': 'new_host-3',
|
||||
'failover_segment': {
|
||||
'uuid': '6b985a8a-f8c0-42e4-beaa-d2fcd8dabbb6',
|
||||
'deleted': False,
|
||||
'created_at': '2016-11-16T04:46:38.000000',
|
||||
'description': None,
|
||||
'recovery_method': 'auto',
|
||||
'updated_at': None,
|
||||
'service_type': 'testsegment01_auto',
|
||||
'deleted_at': None,
|
||||
'id': 3,
|
||||
'name': 'testsegment01'},
|
||||
'deleted_at': None,
|
||||
'type': 'typeX',
|
||||
'id': 10,
|
||||
'failover_segment_id': '6b985a8a-f8c0-42e4-beaa-d2fcd8dabbb6'}
|
||||
self.hosts_object = fakes.FakeHost(self.hosts_vals)
|
||||
|
||||
def _run_command(self, cmd):
|
||||
shell.main(cmd.split())
|
||||
|
||||
@mock.patch.object(utils, 'print_list')
|
||||
def test_do_notification_list(self, mock_print_list):
|
||||
service = mock.Mock()
|
||||
service.notifications.return_value = self.notification_vals
|
||||
args = mock.Mock()
|
||||
columns = [
|
||||
'notification_uuid',
|
||||
'generated_time',
|
||||
'status',
|
||||
'source_host_uuid',
|
||||
'type']
|
||||
|
||||
ms.do_notification_list(service, args)
|
||||
|
||||
mock_print_list.assert_called_once_with(
|
||||
self.notification_vals,
|
||||
columns)
|
||||
|
||||
@mock.patch.object(utils, 'print_list')
|
||||
def test_do_segment_list(self, mock_print_list):
|
||||
service = mock.Mock()
|
||||
service.segments.return_value = self.segment_vals
|
||||
args = mock.Mock()
|
||||
columns = [
|
||||
'uuid',
|
||||
'name',
|
||||
'description',
|
||||
'service_type',
|
||||
'recovery_method']
|
||||
|
||||
ms.do_segment_list(service, args)
|
||||
|
||||
mock_print_list.assert_called_once_with(
|
||||
self.segment_vals,
|
||||
columns)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_segment_show(self, mock_get_uuid_by_name, mock_print_dict):
|
||||
mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
|
||||
service = mock.Mock()
|
||||
segment_object = fakes.FakeSegment(self.segment_vals)
|
||||
service.get_segment.return_value = segment_object
|
||||
args = mock.Mock()
|
||||
|
||||
ms.do_segment_show(service, args)
|
||||
mock_get_uuid_by_name.assert_called_once_with(service, args.id)
|
||||
mock_print_dict.assert_called_once_with(self.segment_vals)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@ddt.data({"recovery_method": "auto"},
|
||||
{"recovery_method": "reserved_host"},
|
||||
{"recovery_method": "auto_priority"},
|
||||
{"recovery_method": "rh_priority"})
|
||||
def test_do_segment_create_with_all_recovery_methods(
|
||||
self, ddt_data, mock_print_dict):
|
||||
service = mock.Mock()
|
||||
args = mock.Mock()
|
||||
self.segment_vals['recovery_method'] = ddt_data['recovery_method']
|
||||
segment_object = fakes.FakeSegment(self.segment_vals)
|
||||
service.create_segment.return_value = segment_object
|
||||
self._run_command(
|
||||
"segment-create "
|
||||
"--name 'test-segment'"
|
||||
" --recovery-method %s "
|
||||
"--service-type test_service" % ddt_data['recovery_method'])
|
||||
ms.do_segment_create(service, args)
|
||||
mock_print_dict.assert_called_once_with(
|
||||
self.segment_vals)
|
||||
|
||||
def test_do_segment_create_with_invalid_recovery_method(self):
|
||||
cmd = ("segment-create --name 'test-segment' --recovery-method"
|
||||
" invalid_recovery_method --service-type test_service")
|
||||
self.assertRaises(SystemExit, self._run_command, cmd)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'remove_unspecified_items')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
@ddt.data({"recovery_method": "auto"},
|
||||
{"recovery_method": "reserved_host"},
|
||||
{"recovery_method": "auto_priority"},
|
||||
{"recovery_method": "rh_priority"})
|
||||
def test_do_segment_update(self, ddt_data,
|
||||
mock_get_uuid_by_name,
|
||||
mock_remove_unspecified_items,
|
||||
mock_print_dict):
|
||||
mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
|
||||
self.segment_vals['recovery_method'] = ddt_data['recovery_method']
|
||||
mock_remove_unspecified_items.return_value = self.segment_vals
|
||||
service = mock.Mock()
|
||||
segment_object = fakes.FakeSegment(self.segment_vals)
|
||||
service.update_segment.return_value = segment_object
|
||||
args = mock.Mock()
|
||||
args.recovery_method = ddt_data['recovery_method']
|
||||
ms.do_segment_update(service, args)
|
||||
mock_get_uuid_by_name.assert_called_once_with(service, args.id)
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'description': args.description,
|
||||
'recovery_method': args.recovery_method,
|
||||
'service_type': args.service_type,
|
||||
}
|
||||
mock_remove_unspecified_items.assert_called_once_with(attrs)
|
||||
mock_print_dict.assert_called_once_with(self.segment_vals)
|
||||
|
||||
def test_do_segment_update_with_invalid_recovery_method(self):
|
||||
cmd = ("segment-update --id bdba001e-c01b-490e-9405-fdf72d849b41 "
|
||||
"--recovery-method invalid_recovery_method")
|
||||
self.assertRaises(SystemExit, self._run_command, cmd)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_segment_delete(self, mock_get_uuid_by_name, mock_print_dict):
|
||||
mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
|
||||
service = mock.Mock()
|
||||
segment_object = fakes.FakeSegment(self.segment_vals)
|
||||
service.delete_segment.return_value = segment_object
|
||||
args = mock.Mock()
|
||||
|
||||
ms.do_segment_delete(service, args)
|
||||
mock_get_uuid_by_name.assert_called_once_with(service, args.id)
|
||||
mock_print_dict.assert_called_once_with(self.segment_vals)
|
||||
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
@mock.patch.object(_proxy.Proxy, 'delete_segment')
|
||||
def test_do_segment_delete_with_non_existing_uuid(
|
||||
self, mock_get_uuid_by_name, mock_delete_segment):
|
||||
mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
|
||||
|
||||
expected_msg = _("No failover segment with "
|
||||
"id (%s)") % mock_get_uuid_by_name
|
||||
|
||||
def fake_delete_segment(self, mock_get_uuid_by_name,
|
||||
ignore_missing=False):
|
||||
if not ignore_missing:
|
||||
raise sdk_exc.ResourceNotFound(expected_msg)
|
||||
|
||||
mock_delete_segment.side_effect = fake_delete_segment
|
||||
service = mock.Mock()
|
||||
args = mock.Mock()
|
||||
|
||||
original = sys.stdout
|
||||
sys.stdout = io.StringIO()
|
||||
ms.do_segment_delete(service, args)
|
||||
output = sys.stdout.getvalue()
|
||||
sys.stdout = original
|
||||
self.assertIn(expected_msg, output)
|
||||
|
||||
@mock.patch.object(utils, 'print_list')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_host_list(self, mock_get_uuid_by_name, mock_print_list):
|
||||
mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
|
||||
service = mock.Mock()
|
||||
service.hosts.return_value = self.hosts_vals
|
||||
args = mock.Mock()
|
||||
columns = [
|
||||
'uuid',
|
||||
'name',
|
||||
'type',
|
||||
'control_attributes',
|
||||
'reserved',
|
||||
'on_maintenance',
|
||||
'failover_segment_id']
|
||||
|
||||
ms.do_host_list(service, args)
|
||||
|
||||
mock_get_uuid_by_name.assert_called_once_with(service, args.segment_id)
|
||||
mock_print_list.assert_called_once_with(
|
||||
self.hosts_vals,
|
||||
columns)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_host_show(self, mock_get_uuid_by_name, mock_print_dict):
|
||||
mock_get_uuid_by_name.side_effect = [self.segment_vals.get('uuid'),
|
||||
self.hosts_vals.get('uuid')]
|
||||
service = mock.Mock()
|
||||
service.get_host.return_value = self.hosts_object
|
||||
args = mock.Mock()
|
||||
|
||||
ms.do_host_show(service, args)
|
||||
mock_get_uuid_by_name.assert_any_call(service, args.segment_id)
|
||||
mock_get_uuid_by_name.assert_any_call(
|
||||
service, args.id, segment=self.segment_vals.get('uuid'))
|
||||
mock_print_dict.assert_called_once_with(self.hosts_vals)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'remove_unspecified_items')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_host_create(self,
|
||||
mock_get_uuid_by_name,
|
||||
mock_remove_unspecified_items,
|
||||
mock_print_dict):
|
||||
mock_get_uuid_by_name.return_value = self.hosts_vals.get('uuid')
|
||||
mock_remove_unspecified_items.return_value = self.hosts_vals
|
||||
service = mock.Mock()
|
||||
service.create_host.return_value = self.hosts_object
|
||||
args = mock.Mock()
|
||||
|
||||
ms.do_host_create(service, args)
|
||||
mock_get_uuid_by_name.assert_called_once_with(service, args.segment_id)
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'type': args.type,
|
||||
'control_attributes': args.control_attributes,
|
||||
'reserved': args.reserved,
|
||||
'on_maintenance': args.on_maintenance,
|
||||
}
|
||||
mock_remove_unspecified_items.assert_called_once_with(attrs)
|
||||
mock_print_dict.assert_called_once_with(self.hosts_vals)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'remove_unspecified_items')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_host_update(self,
|
||||
mock_get_uuid_by_name,
|
||||
mock_remove_unspecified_items,
|
||||
mock_print_dict):
|
||||
mock_get_uuid_by_name.side_effect = [self.segment_vals.get('uuid'),
|
||||
self.hosts_vals.get('uuid')]
|
||||
mock_remove_unspecified_items.return_value = self.hosts_vals
|
||||
service = mock.Mock()
|
||||
service.update_host.return_value = self.hosts_object
|
||||
args = mock.Mock()
|
||||
|
||||
ms.do_host_update(service, args)
|
||||
mock_get_uuid_by_name.assert_any_call(service, args.segment_id)
|
||||
mock_get_uuid_by_name.assert_any_call(
|
||||
service, args.id, segment=self.segment_vals.get('uuid'))
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'type': args.type,
|
||||
'control_attributes': args.control_attributes,
|
||||
'reserved': args.reserved,
|
||||
'on_maintenance': args.on_maintenance,
|
||||
}
|
||||
mock_remove_unspecified_items.assert_called_once_with(attrs)
|
||||
mock_print_dict.assert_called_once_with(self.hosts_vals)
|
||||
|
||||
@mock.patch.object(utils, 'print_dict')
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
def test_do_host_delete(self, mock_get_uuid_by_name, mock_print_dict):
|
||||
mock_get_uuid_by_name.side_effect = [self.segment_vals.get('uuid'),
|
||||
self.hosts_vals.get('uuid')]
|
||||
service = mock.Mock()
|
||||
service.delete_host.return_value = self.hosts_object
|
||||
args = mock.Mock()
|
||||
|
||||
ms.do_host_delete(service, args)
|
||||
mock_get_uuid_by_name.assert_any_call(service, args.segment_id)
|
||||
mock_get_uuid_by_name.assert_any_call(
|
||||
service, args.id, segment=self.segment_vals.get('uuid'))
|
||||
mock_print_dict.assert_called_once_with(self.hosts_vals)
|
||||
|
||||
@mock.patch.object(utils, 'get_uuid_by_name')
|
||||
@mock.patch.object(_proxy.Proxy, 'delete_host')
|
||||
def test_do_host_delete_with_non_existing_uuid(self,
|
||||
mock_get_uuid_by_name,
|
||||
mock_delete_host):
|
||||
mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
|
||||
host_id = self.hosts_vals.get('uuid')
|
||||
expected_msg = _("Host '%(host_id)s' under failover_segment " "'"
|
||||
"%(seg_id)s' ""could not be found") % {
|
||||
'host_id': host_id, 'seg_id': mock_get_uuid_by_name}
|
||||
|
||||
def fake_delete_host(
|
||||
host_id, mock_get_uuid_by_name, ignore_missing=False):
|
||||
if not ignore_missing:
|
||||
raise sdk_exc.ResourceNotFound(expected_msg)
|
||||
|
||||
mock_delete_host.side_effect = fake_delete_host
|
||||
service = mock.Mock()
|
||||
args = mock.Mock()
|
||||
|
||||
original = sys.stdout
|
||||
sys.stdout = io.StringIO()
|
||||
ms.do_host_delete(service, args)
|
||||
output = sys.stdout.getvalue()
|
||||
sys.stdout = original
|
||||
self.assertIn(expected_msg, output)
|
@ -1,40 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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 keystoneauth1.identity.generic import password as ks_password
|
||||
from keystoneauth1 import session as ks_session
|
||||
from openstack import connection
|
||||
|
||||
|
||||
class Client(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
session = kwargs.get('session')
|
||||
if session is None:
|
||||
auth = ks_password.Password(
|
||||
auth_url=kwargs.get('auth_url'),
|
||||
username=kwargs.get('username'),
|
||||
password=kwargs.get('password'),
|
||||
user_domain_id=kwargs.get('user_domain_id'),
|
||||
project_name=kwargs.get('project_name'),
|
||||
project_domain_id=kwargs.get('project_domain_id'))
|
||||
|
||||
session = ks_session.Session(auth=auth)
|
||||
|
||||
con = connection.Connection(
|
||||
session=session,
|
||||
interface=kwargs.get('interface'),
|
||||
region_name=kwargs.get('region_name'),
|
||||
ha_api_version=kwargs.get('api_version'))
|
||||
self.service = con.instance_ha
|
@ -1,292 +0,0 @@
|
||||
# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation
|
||||
#
|
||||
# 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 oslo_serialization import jsonutils
|
||||
|
||||
from masakariclient.common import utils
|
||||
|
||||
|
||||
def do_notification_list(service, args):
|
||||
"""List notifications.
|
||||
|
||||
:param service: service object.
|
||||
:param args: API args.
|
||||
"""
|
||||
try:
|
||||
notifications = service.notifications()
|
||||
columns = [
|
||||
'notification_uuid', 'generated_time', 'status',
|
||||
'source_host_uuid', 'type']
|
||||
utils.print_list(notifications, columns)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--id', metavar='<NOTIFICATION_ID>', required=True,
|
||||
help='Notification to display (name or ID)')
|
||||
def do_notification_show(service, args):
|
||||
"""Show a notification details."""
|
||||
try:
|
||||
notification = service.get_notification(args.id)
|
||||
utils.print_dict(notification.to_dict())
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--type', metavar='<TYPE>', required=True,
|
||||
choices=['COMPUTE_HOST', 'VM', 'PROCESS'],
|
||||
help='Type of failure. The supported options are: '
|
||||
'COMPUTE_HOST, VM, PROCESS.')
|
||||
@utils.arg('--hostname', metavar='<HOSTNAME>', required=True,
|
||||
help='Hostname of notification.')
|
||||
@utils.arg('--generated-time', metavar='<GENERATED_TIME>', required=True,
|
||||
help='Timestamp for notification. e.g. 2016-01-01T01:00:00.000')
|
||||
@utils.arg('--payload', metavar='<PAYLOAD>', required=True,
|
||||
help='JSON string about failure event.')
|
||||
def do_notification_create(service, args):
|
||||
"""Create a notification."""
|
||||
try:
|
||||
payload = jsonutils.loads(args.payload)
|
||||
attrs = {
|
||||
'type': args.type,
|
||||
'hostname': args.hostname,
|
||||
'generated_time': args.generated_time,
|
||||
'payload': payload,
|
||||
}
|
||||
notification = service.create_notification(**attrs)
|
||||
utils.print_dict(notification.to_dict())
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def do_segment_list(service, args):
|
||||
"""List segments."""
|
||||
try:
|
||||
segments = service.segments()
|
||||
fields = [
|
||||
'uuid', 'name', 'description',
|
||||
'service_type', 'recovery_method']
|
||||
utils.print_list(segments, fields)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Segment to display (name or ID)')
|
||||
def do_segment_show(service, args):
|
||||
"""Show a segment details."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(service, args.id)
|
||||
segment = service.get_segment(segment_id)
|
||||
utils.print_dict(segment.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--name', metavar='<SEGMENT_NAME>', required=True,
|
||||
help='Name of segment.')
|
||||
@utils.arg('--recovery-method', metavar='<RECOVERY_METHOD>', required=True,
|
||||
choices=['auto', 'reserved_host', 'auto_priority', 'rh_priority'],
|
||||
help='Recovery method. '
|
||||
'The supported options are: auto, reserved_host,'
|
||||
' auto_priority, rh_priority.')
|
||||
@utils.arg('--service-type', metavar='<SERVICE_TYPE>', required=True,
|
||||
help='Service type of segment.')
|
||||
@utils.arg('--description', metavar='<DESCRIPTION>', required=False,
|
||||
help='Description of segment.')
|
||||
def do_segment_create(service, args):
|
||||
"""Create segment."""
|
||||
try:
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'description': args.description,
|
||||
'recovery_method': args.recovery_method,
|
||||
'service_type': args.service_type,
|
||||
}
|
||||
segment = service.create_segment(**attrs)
|
||||
utils.print_dict(segment.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--id', metavar='<SEGMENT_ID>',
|
||||
required=True, help='Name or ID of segment.')
|
||||
@utils.arg('--name', metavar='<SEGMENT_NAME>',
|
||||
required=False, help='Name of segment.')
|
||||
@utils.arg('--recovery-method', metavar='<RECOVERY_METHOD>',
|
||||
choices=['auto', 'reserved_host', 'auto_priority', 'rh_priority'],
|
||||
required=False,
|
||||
help='Recovery method. '
|
||||
'The supported options are: auto, reserved_host, '
|
||||
'auto_priority, rh_priority.')
|
||||
@utils.arg('--service-type', metavar='<SERVICE_TYPE>',
|
||||
required=False, help='Service type of segment.')
|
||||
@utils.arg('--description', metavar='<DESCRIPTION>',
|
||||
required=False, help='Description of segment.')
|
||||
def do_segment_update(service, args):
|
||||
"""Update a segment."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.id)
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'description': args.description,
|
||||
'recovery_method': args.recovery_method,
|
||||
'service_type': args.service_type,
|
||||
}
|
||||
attrs = utils.remove_unspecified_items(attrs)
|
||||
segment = service.update_segment(segment_id, **attrs)
|
||||
utils.print_dict(segment.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Name or ID of the segment to delete.')
|
||||
def do_segment_delete(service, args):
|
||||
"""Delete a segment."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.id)
|
||||
segment = service.delete_segment(segment_id, ignore_missing=False)
|
||||
utils.print_dict(segment.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--segment-id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Segment to display (name or ID)')
|
||||
def do_host_list(service, args):
|
||||
"""List hosts."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.segment_id)
|
||||
hosts = service.hosts(segment_id)
|
||||
fields = [
|
||||
'uuid', 'name', 'type', 'control_attributes', 'reserved',
|
||||
'on_maintenance', 'failover_segment_id']
|
||||
utils.print_list(hosts, fields)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--segment-id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Segment to display (name or ID)')
|
||||
@utils.arg('--id', metavar='<HOST_ID>', required=True,
|
||||
help='Host to display (name or ID)')
|
||||
def do_host_show(service, args):
|
||||
"""Show a host details."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.segment_id)
|
||||
host_id = utils.get_uuid_by_name(
|
||||
service, args.id, segment=segment_id)
|
||||
host = service.get_host(host_id, segment_id=segment_id)
|
||||
utils.print_dict(host.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--name', metavar='<HOST_NAME>', required=True,
|
||||
help='Name of host.')
|
||||
@utils.arg('--type', metavar='<TYPE>', required=True,
|
||||
help='Type of host.')
|
||||
@utils.arg('--control-attributes', metavar='<CONTROL_ATTRIBUTES>',
|
||||
required=True, help='Control attributes of host.')
|
||||
@utils.arg('--segment-id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Name or ID of segment.')
|
||||
@utils.arg('--reserved', metavar='<RESERVED>', required=False,
|
||||
choices=['True', 'False'],
|
||||
help='Host reservation. The supported options are: True, False.')
|
||||
@utils.arg('--on-maintenance', metavar='<ON_MAINTENANCE>', required=False,
|
||||
choices=['True', 'False'],
|
||||
help='Maintenance status of host. The supported options are: '
|
||||
'True, False.')
|
||||
def do_host_create(service, args):
|
||||
"""Create a host."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.segment_id)
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'type': args.type,
|
||||
'control_attributes': args.control_attributes,
|
||||
'reserved': args.reserved,
|
||||
'on_maintenance': args.on_maintenance,
|
||||
}
|
||||
utils.remove_unspecified_items(attrs)
|
||||
host = service.create_host(segment_id, **attrs)
|
||||
utils.print_dict(host.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--segment-id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Name or ID of segment.')
|
||||
@utils.arg('--id', metavar='<HOST_ID>', required=True,
|
||||
help='Name or ID of host.')
|
||||
@utils.arg('--reserved', metavar='<RESERVED>', required=False,
|
||||
choices=['True', 'False'],
|
||||
help='Host reservation. The supported options are: True, False.')
|
||||
@utils.arg('--on-maintenance', metavar='<ON_MAINTENANCE>',
|
||||
required=False, choices=['True', 'False'],
|
||||
help='Maintenance status of host. The supported options are: '
|
||||
'True, False.')
|
||||
@utils.arg('--name', metavar='<HOST_NAME>', required=False,
|
||||
help='Name of host.')
|
||||
@utils.arg('--type', metavar='<TYPE>', required=False,
|
||||
help='Type of host.')
|
||||
@utils.arg('--control-attributes', metavar='<CONTROL_ATTRIBUTES>',
|
||||
required=False, help='Control attributes of host.')
|
||||
def do_host_update(service, args):
|
||||
"""Update a host."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.segment_id)
|
||||
host_id = utils.get_uuid_by_name(
|
||||
service, args.id, segment=segment_id)
|
||||
attrs = {
|
||||
'name': args.name,
|
||||
'type': args.type,
|
||||
'control_attributes': args.control_attributes,
|
||||
'reserved': args.reserved,
|
||||
'on_maintenance': args.on_maintenance,
|
||||
}
|
||||
attrs = utils.remove_unspecified_items(attrs)
|
||||
host = service.update_host(host_id, segment_id=segment_id, **attrs)
|
||||
utils.print_dict(host.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
@utils.arg('--segment-id', metavar='<SEGMENT_ID>', required=True,
|
||||
help='Name or ID of segment.')
|
||||
@utils.arg('--id', metavar='<HOST_ID>', required=True,
|
||||
help='Name or ID of the host to delete.')
|
||||
def do_host_delete(service, args):
|
||||
"""Delete a host."""
|
||||
try:
|
||||
segment_id = utils.get_uuid_by_name(
|
||||
service, args.segment_id)
|
||||
host_id = utils.get_uuid_by_name(
|
||||
service, args.id, segment=segment_id)
|
||||
host = service.delete_host(host_id, segment_id=segment_id,
|
||||
ignore_missing=False)
|
||||
utils.print_dict(host.to_dict())
|
||||
except Exception as e:
|
||||
print(e)
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
The legacy Masakari client (invoked by calling ``masakari`` as opposed to
|
||||
``openstack``) has been removed. It has been deprecated since
|
||||
Stein.
|
Loading…
Reference in New Issue
Block a user