Browse Source

Convert cgtsclient from setuptools to pbr. Add tox.

Primary reason for this change was to update the spec and setup files
from basic setuptools to use pbr
This allows the autogenerated  /usr/bin/system file to directly call the
main method without using pkg-resources.
This will provide a performance improvement of .5 seconds per CLI call,
once the other pkg_resources issues are resolved

Second reason for this change was to wire in the tox unit tests.  This
also includes pep8, pylint and coverage.
Currently pep8 does not perform the 80 char limit check
Currently pylint still reports some issues

This should not affect the RPM names being generated or otherwise affect
patching or upgrades.

Change-Id: I9f14c9216fdcc63930a4b2849102b58442706144
changes/99/578899/2
Al Bailey 4 years ago committed by Jack Ding
parent
commit
d7330d0f44
  1. 12
      sysinv/cgts-client/centos/cgts-client.spec
  2. 4
      sysinv/cgts-client/cgts-client/.gitignore
  3. 10
      sysinv/cgts-client/cgts-client/.testr.conf
  4. 0
      sysinv/cgts-client/cgts-client/README.rst
  5. 5
      sysinv/cgts-client/cgts-client/cgtsclient/__init__.py
  6. 10
      sysinv/cgts-client/cgts-client/cgtsclient/client.py
  7. 1
      sysinv/cgts-client/cgts-client/cgtsclient/common/cli_no_wrap.py
  8. 2
      sysinv/cgts-client/cgts-client/cgtsclient/common/constants.py
  9. 21
      sysinv/cgts-client/cgts-client/cgtsclient/common/http.py
  10. 46
      sysinv/cgts-client/cgts-client/cgtsclient/common/utils.py
  11. 166
      sysinv/cgts-client/cgts-client/cgtsclient/common/wrapping_formatters.py
  12. 2
      sysinv/cgts-client/cgts-client/cgtsclient/exc.py
  13. 7
      sysinv/cgts-client/cgts-client/cgtsclient/openstack/common/importutils.py
  14. 10
      sysinv/cgts-client/cgts-client/cgtsclient/shell.py
  15. 0
      sysinv/cgts-client/cgts-client/cgtsclient/tests/__init__.py
  16. 44
      sysinv/cgts-client/cgts-client/cgtsclient/tests/test_http.py
  17. 8
      sysinv/cgts-client/cgts-client/cgtsclient/tests/test_shell.py
  18. 2
      sysinv/cgts-client/cgts-client/cgtsclient/tests/test_utils.py
  19. 47
      sysinv/cgts-client/cgts-client/cgtsclient/tests/v1/test_invServer.py
  20. 4
      sysinv/cgts-client/cgts-client/cgtsclient/v1/__init__.py
  21. 9
      sysinv/cgts-client/cgts-client/cgtsclient/v1/address_pool_shell.py
  22. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/address_shell.py
  23. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ceph_mon.py
  24. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ceph_mon_shell.py
  25. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/certificate_shell.py
  26. 84
      sysinv/cgts-client/cgts-client/cgtsclient/v1/client.py
  27. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/cluster_shell.py
  28. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/controller_fs_shell.py
  29. 17
      sysinv/cgts-client/cgts-client/cgtsclient/v1/drbdconfig_shell.py
  30. 12
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ethernetport_shell.py
  31. 12
      sysinv/cgts-client/cgts-client/cgtsclient/v1/event_log.py
  32. 55
      sysinv/cgts-client/cgts-client/cgtsclient/v1/event_log_shell.py
  33. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/event_suppression.py
  34. 74
      sysinv/cgts-client/cgts-client/cgtsclient/v1/event_suppression_shell.py
  35. 7
      sysinv/cgts-client/cgts-client/cgtsclient/v1/firewallrules_shell.py
  36. 36
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iHost_shell.py
  37. 5
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ialarm.py
  38. 28
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ialarm_shell.py
  39. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/icommunity_shell.py
  40. 37
      sysinv/cgts-client/cgts-client/cgtsclient/v1/icpu.py
  41. 5
      sysinv/cgts-client/cgts-client/cgtsclient/v1/icpu_shell.py
  42. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/idisk.py
  43. 1
      sysinv/cgts-client/cgts-client/cgtsclient/v1/idisk_shell.py
  44. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/idns_shell.py
  45. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iextoam_shell.py
  46. 13
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ihost.py
  47. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iinfra_shell.py
  48. 25
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iinterface_shell.py
  49. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ilvg_shell.py
  50. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory.py
  51. 18
      sysinv/cgts-client/cgts-client/cgtsclient/v1/imemory_shell.py
  52. 4
      sysinv/cgts-client/cgts-client/cgtsclient/v1/inode_shell.py
  53. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/intp_shell.py
  54. 4
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iprofile.py
  55. 10
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iprofile_shell.py
  56. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/ipv_shell.py
  57. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/isensor_shell.py
  58. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/isensorgroup.py
  59. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/isensorgroup_shell.py
  60. 1
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iservice.py
  61. 4
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iservice_shell.py
  62. 10
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iservicegroup_shell.py
  63. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/istor_shell.py
  64. 23
      sysinv/cgts-client/cgts-client/cgtsclient/v1/isystem_shell.py
  65. 1
      sysinv/cgts-client/cgts-client/cgtsclient/v1/itrapdest.py
  66. 5
      sysinv/cgts-client/cgts-client/cgtsclient/v1/itrapdest_shell.py
  67. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/iuser_shell.py
  68. 1
      sysinv/cgts-client/cgts-client/cgtsclient/v1/license.py
  69. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/license_shell.py
  70. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/lldp_agent.py
  71. 14
      sysinv/cgts-client/cgts-client/cgtsclient/v1/lldp_agent_shell.py
  72. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/lldp_neighbour.py
  73. 12
      sysinv/cgts-client/cgts-client/cgtsclient/v1/lldp_neighbour_shell.py
  74. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/partition_shell.py
  75. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/pci_device.py
  76. 12
      sysinv/cgts-client/cgts-client/cgtsclient/v1/pci_device_shell.py
  77. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/port.py
  78. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/port_shell.py
  79. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/remotelogging_shell.py
  80. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/route_shell.py
  81. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sdn_controller.py
  82. 42
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sdn_controller_shell.py
  83. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/service_parameter.py
  84. 12
      sysinv/cgts-client/cgts-client/cgtsclient/v1/service_parameter_shell.py
  85. 81
      sysinv/cgts-client/cgts-client/cgtsclient/v1/shell.py
  86. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sm_service.py
  87. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sm_service_nodes.py
  88. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sm_service_nodes_shell.py
  89. 3
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sm_service_shell.py
  90. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sm_servicegroup.py
  91. 13
      sysinv/cgts-client/cgts-client/cgtsclient/v1/sm_servicegroup_shell.py
  92. 4
      sysinv/cgts-client/cgts-client/cgtsclient/v1/storage_backend.py
  93. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/storage_external.py
  94. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/storage_tier_shell.py
  95. 2
      sysinv/cgts-client/cgts-client/cgtsclient/v1/upgrade.py
  96. 6
      sysinv/cgts-client/cgts-client/cgtsclient/v1/upgrade_shell.py
  97. 218
      sysinv/cgts-client/cgts-client/pylint.rc
  98. 2
      sysinv/cgts-client/cgts-client/requirements.txt
  99. 36
      sysinv/cgts-client/cgts-client/setup.cfg
  100. 29
      sysinv/cgts-client/cgts-client/setup.py
  101. Some files were not shown because too many files have changed in this diff Show More

12
sysinv/cgts-client/centos/cgts-client.spec

@ -32,10 +32,16 @@ Contains SDK files for %{name} package
%prep
%autosetup -n %{name}-%{version} -S git
# Remove bundled egg-info
rm -rf *.egg-info
%build
export PBR_VERSION=%{version}
%{__python} setup.py build
%install
export PBR_VERSION=%{version}
%{__python} setup.py install --root=$RPM_BUILD_ROOT \
--install-lib=%{pythonroot} \
--prefix=/usr \
@ -59,10 +65,8 @@ rm -rf $RPM_BUILD_ROOT
%doc LICENSE
%{local_bindir}/*
%{local_etc_bash_completiond}/*
%dir %{pythonroot}/cgtsclient
%{pythonroot}/cgtsclient/*
%dir %{pythonroot}/cgtsclient-%{version}.0-py2.7.egg-info
%{pythonroot}/cgtsclient-%{version}.0-py2.7.egg-info/*
%{pythonroot}/cgtsclient
%{pythonroot}/cgtsclient-%{version}*.egg-info
%files sdk
/usr/share/remote-clients/python-wrs-system-client-%{version}.tgz

4
sysinv/cgts-client/cgts-client/.gitignore vendored

@ -0,0 +1,4 @@
.testrepository
coverage.xml
.coverage
cover

10
sysinv/cgts-client/cgts-client/.testr.conf

@ -0,0 +1,10 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-160} \
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./cgtsclient/tests} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list
# group tests when running concurrently
# This regex groups by classname
#group_regex=([^\.]+\.)+

0
sysinv/cgts-client/cgts-client/README.rst

5
sysinv/cgts-client/cgts-client/cgtsclient/__init__.py

@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
# import pbr.version
try:
import cgtsclient.client
Client = cgtsclient.client.Client
@ -22,5 +20,4 @@ except ImportError:
import warnings
warnings.warn("Could not import cgtsclient.client", ImportWarning)
__version__ = "1.0"
#__version__ = pbr.version.VersionInfo('python-cgtsclient').version_string()
__version__ = "1.0.0"

10
sysinv/cgts-client/cgts-client/cgtsclient/client.py

@ -4,10 +4,9 @@
# SPDX-License-Identifier: Apache-2.0
#
from cgtsclient import exc
from cgtsclient.common import utils
from cgtsclient import exc
from cgtsclient.openstack.common.gettextutils import _
from keystoneclient.v3 import client as ksclient
def _get_ksclient(**kwargs):
@ -22,6 +21,7 @@ def _get_ksclient(**kwargs):
* insecure: allow insecure SSL (no cert verification)
* project_name: Project name for project scoping.
"""
from keystoneclient.v3 import client as ksclient
return ksclient.Client(username=kwargs.get('username'),
password=kwargs.get('password'),
user_domain_name=kwargs.get('user_domain_name'),
@ -89,9 +89,7 @@ def get_client(api_version, **kwargs):
'os_cacert': kwargs.get('ca_file')
}
_ksclient = _get_ksclient(**ks_kwargs)
token = kwargs.get('os_auth_token') \
if kwargs.get('os_auth_token') \
else _ksclient.auth_ref.auth_token
token = kwargs.get('os_auth_token') if kwargs.get('os_auth_token') else _ksclient.auth_ref.auth_token
ep_kwargs = {
'service_type': kwargs.get('os_service_type'),
@ -117,8 +115,6 @@ def get_client(api_version, **kwargs):
'cert_file': kwargs.get('cert_file'),
'key_file': kwargs.get('key_file'),
'auth_ref': auth_ref,
#'tenant_id': kwargs.get('os_tenant_id'),
#'tenant_name': kwargs.get('os_tenant_name'),
'auth_url': kwargs.get('os_auth_url'),
'smapi_endpoint': 'http:localhost:7777',
}

1
sysinv/cgts-client/cgts-client/cgtsclient/common/cli_no_wrap.py

@ -11,6 +11,7 @@ used by the wrapping_formatters module
_no_wrap = [False]
def is_nowrap_set(no_wrap=None):
"""
returns True if no wrapping desired.

2
sysinv/cgts-client/cgts-client/cgtsclient/common/constants.py

@ -65,7 +65,7 @@ PARTITION_USER_MANAGED_GUID_PREFIX = "ba5eba11-0000-1111-2222-"
USER_PARTITION_PHYSICAL_VOLUME = (PARTITION_USER_MANAGED_GUID_PREFIX +
"000000000001")
# Size conversion types
# Size conversion types
KiB = 1
MiB = 2
GiB = 3

21
sysinv/cgts-client/cgts-client/cgtsclient/common/http.py

@ -15,13 +15,10 @@
# under the License.
#
import copy
import httplib
import logging
import os
import requests
import socket
import StringIO
import httplib2
@ -31,7 +28,7 @@ import six.moves.urllib.parse as urlparse
try:
import ssl
except ImportError:
#TODO(bcwaldon): Handle this failure more gracefully
# TODO(bcwaldon): Handle this failure more gracefully
pass
try:
@ -46,7 +43,6 @@ if not hasattr(urlparse, 'parse_qsl'):
from cgtsclient import exc as exceptions
from neutronclient.common import utils
from cgtsclient.openstack.common.gettextutils import _
_logger = logging.getLogger(__name__)
@ -157,13 +153,13 @@ class HTTPClient(httplib2.Http):
def http_log_resp(_logger, resp, body=None):
if not _logger.isEnabledFor(logging.DEBUG):
return
resp_status_code = resp.get('status_code') or ""
resp_headers = resp.get('headers') or ""
_logger.debug("RESP:%(code)s %(headers)s %(body)s\n",
{'code': resp_status_code,
'headers': resp_headers,
'body': body})
{'code': resp_status_code,
'headers': resp_headers,
'body': body})
def _cs_request(self, *args, **kwargs):
kargs = {}
@ -248,8 +244,8 @@ class HTTPClient(httplib2.Http):
connection_url = self._get_connection_url(url)
try:
resp, body_iter = self._cs_request(connection_url, method,
**kwargs)
resp, body_iter = self._cs_request(connection_url,
method, **kwargs)
except exceptions.HTTPUnauthorized:
self.authenticate()
resp, body_iter = self._cs_request(
@ -408,8 +404,7 @@ class HTTPClient(httplib2.Http):
body = json.loads(body)
for endpoint in body.get('endpoints', []):
if (endpoint['type'] == 'platform' and
endpoint.get('region') == self.region_name):
if (endpoint['type'] == 'platform' and endpoint.get('region') == self.region_name):
if self.endpoint_type not in endpoint:
raise exceptions.EndpointTypeNotFound(
self.endpoint_type)

46
sysinv/cgts-client/cgts-client/cgtsclient/common/utils.py

@ -17,22 +17,25 @@
try:
import tsconfig.tsconfig as tsc
is_remote = False
except:
except Exception:
is_remote = True
import argparse
import copy
import dateutil
import os
import prettytable
import re
import six
import sys
import textwrap
import uuid
import six
import prettytable
from prettytable import FRAME, ALL, NONE
from prettytable import ALL
from prettytable import FRAME
from prettytable import NONE
import re
from datetime import datetime
import dateutil
from dateutil import parser
from cgtsclient import exc
@ -217,9 +220,11 @@ def _sort_for_list(objs, fields, formatters={}, sortby=0, reversesort=False):
return rows_to_sort
def default_printer(s):
print s
def pt_builder(field_labels, fields, formatters, paging, printer=default_printer):
"""
returns an object that 'fronts' a prettyTable object
@ -269,7 +274,7 @@ def pt_builder(field_labels, fields, formatters, paging, printer=default_printer
else:
printer(self.get_string())
if self.terminal_lines_left > 0:
printer("\n" * (self.terminal_lines_left-1))
printer("\n" * (self.terminal_lines_left - 1))
s = raw_input("Press Enter to continue or 'q' to exit...")
if s == 'q':
@ -359,7 +364,7 @@ def print_list(objs, fields, field_labels, formatters={}, sortby=0,
# print_list() is the same as print_long_list() with paging turned off
return print_long_list(objs, fields, field_labels, formatters=formatters, sortby=sortby,
reversesort=reversesort, no_wrap_fields=no_wrap_fields,
no_paging=True, printer=printer)
no_paging=True, printer=printer)
def _build_row_from_object(fields, formatters, o):
@ -421,7 +426,7 @@ def row_height(texts):
def print_long_list(objs, fields, field_labels, formatters={}, sortby=0, reversesort=False, no_wrap_fields=[],
no_paging=False, printer=default_printer):
no_paging=False, printer=default_printer):
formatters = wrapping_formatters.as_wrapping_formatters(objs, fields, field_labels, formatters,
no_wrap_fields=no_wrap_fields)
@ -440,7 +445,7 @@ def print_dict(d, dict_property="Property", wrap=0):
pt = prettytable.PrettyTable([dict_property, 'Value'],
caching=False, print_empty=False)
pt.align = 'l'
for k, v in d.iteritems():
for k, v in sorted(d.iteritems()):
v = parse_date(v)
# convert dict to str to check length
if isinstance(v, dict):
@ -516,9 +521,8 @@ def args_array_to_dict(kwargs, key_to_convert):
kwargs[key_to_convert] = dict(v.split("=", 1)
for v in values_to_convert)
except ValueError:
raise exc.CommandError(
'%s must be a list of KEY=VALUE not "%s"' % (
key_to_convert, values_to_convert))
raise exc.CommandError('%s must be a list of KEY=VALUE not "%s"' %
(key_to_convert, values_to_convert))
return kwargs
@ -634,16 +638,17 @@ def is_uuid_like(val):
def get_terminal_size():
"""Returns a tuple (x, y) representing the width(x) and the height(x)
in characters of the terminal window."""
in characters of the terminal window.
"""
def ioctl_GWINSZ(fd):
try:
import fcntl
import termios
import struct
import termios
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
'1234'))
except:
except Exception:
return None
if cr == (0, 0):
return None
@ -657,7 +662,7 @@ def get_terminal_size():
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except:
except Exception:
pass
if not cr:
cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80))
@ -675,8 +680,7 @@ def normalize_field_data(obj, fields):
class WRPrettyTable(prettytable.PrettyTable):
""" A PrettyTable that allows word wrapping of its headers.
"""
"""A PrettyTable that allows word wrapping of its headers."""
def __init__(self, field_names=None, **kwargs):
super(WRPrettyTable, self).__init__(field_names, **kwargs)
@ -742,10 +746,12 @@ def extract_keypairs(args):
attributes[key] = value
return attributes
# Convert size from BYTE to KiB, MiB, GiB, TiB, PiB
# 1 - KiB, 2 - MiB, 3 - GiB, 4 - TiB, 5 - PiB
def convert_size_from_bytes(bytes, type):
return '%.2f' % (float(bytes) / (1024**type))
return '%.2f' % (float(bytes) / (1024 ** type))
def _get_system_info(cc):
"""Gets the system mode and type"""

166
sysinv/cgts-client/cgts-client/cgtsclient/common/wrapping_formatters.py

@ -21,30 +21,33 @@ The basic idea is:
the existing prettyTable code base for rendering.
"""
import six
import copy
import textwrap, re
import re
import six
import textwrap
from cgtsclient.common.cli_no_wrap import is_nowrap_set
from cgtsclient.common.cli_no_wrap import set_no_wrap
from prettytable import _get_size
from cgtsclient.common.cli_no_wrap import is_nowrap_set, set_no_wrap
UUID_MIN_LENGTH = 36
# monkey patch (customize) how the textwrap module breaks text into chunks
wordsep_re = re.compile(
r'(\s+|' # any whitespace
r',|'
r'=|'
r'\.|'
r':|'
r'[^\s\w]*\w+[^0-9\W]-(?=\w+[^0-9\W])|' # hyphenated words
r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash
wordsep_re = re.compile(r'(\s+|' # any whitespace
r',|'
r'=|'
r'\.|'
r':|'
r'[^\s\w]*\w+[^0-9\W]-(?=\w+[^0-9\W])|' # hyphenated words
r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash
textwrap.TextWrapper.wordsep_re = wordsep_re
def _get_width(value):
if value is None:
return 0
# TODO: take into account \n
# TODO(jkung): take into account \n
return _get_size(six.text_type(value))[0] # get width from [width,height]
@ -137,7 +140,7 @@ def field_value_function_factory(formatter, field):
class WrapperFormatter(object):
""" Base (abstract) class definition of wrapping formatters """
"""Base (abstract) class definition of wrapping formatters"""
def __init__(self, ctx, field):
self.ctx = ctx
@ -159,7 +162,7 @@ class WrapperFormatter(object):
def get_calculated_desired_width(self):
basic_desired_width = self.get_basic_desired_width()
if self.header_width > basic_desired_width:
if self.header_width > basic_desired_width:
return self.header_width
return basic_desired_width
@ -186,8 +189,7 @@ class WrapperFormatter(object):
self.actual_column_char_len = actual
def get_actual_column_char_len(self, desired_char_len, check_remaining_row_chars=True):
"""
Utility method to adjust desired width to a width
"""Utility method to adjust desired width to a width
that can actually be applied based on current table width
and current terminal width
@ -216,7 +218,7 @@ class WrapperFormatter(object):
if actual > self.min_width:
# shrink column
while actual > self.min_width:
actual -= 1 # TODO: fix in next sprint
actual -= 1 # TODO(jkung): fix in next sprint
# each column needs to share in
# table shrinking - but this is good
# enough for now - also - why the loop?
@ -269,7 +271,7 @@ class WrapperFormatter(object):
class WrapperLambdaFormatter(WrapperFormatter):
""" A wrapper formatter that adapts a function (callable)
"""A wrapper formatter that adapts a function (callable)
to look like a WrapperFormatter
"""
@ -282,8 +284,8 @@ class WrapperLambdaFormatter(WrapperFormatter):
class WrapperFixedWidthFormatter(WrapperLambdaFormatter):
""" A wrapper formatter that forces the text to wrap within
a specific width (in chars)
"""A wrapper formatter that forces the text to wrap within
a specific width (in chars)
"""
def __init__(self, ctx, field, width):
@ -298,8 +300,8 @@ class WrapperFixedWidthFormatter(WrapperLambdaFormatter):
class WrapperPercentWidthFormatter(WrapperFormatter):
""" A wrapper formatter that forces the text to wrap within
a specific percentage width of the current terminal width
"""A wrapper formatter that forces the text to wrap within
a specific percentage width of the current terminal width
"""
def __init__(self, ctx, field, width_as_decimal):
@ -318,11 +320,11 @@ class WrapperPercentWidthFormatter(WrapperFormatter):
class WrapperWithCustomFormatter(WrapperLambdaFormatter):
""" A wrapper formatter that allows the programmer to have a custom
formatter (in the form of a function) that is first applied
and then a wrapper function is applied to the result
"""A wrapper formatter that allows the programmer to have a custom
formatter (in the form of a function) that is first applied
and then a wrapper function is applied to the result
See wrapperFormatterFactory for a better explanation! :-)
See wrapperFormatterFactory for a better explanation! :-)
"""
# noinspection PyUnusedLocal
@ -360,6 +362,7 @@ class WrapperWithCustomFormatter(WrapperLambdaFormatter):
def get_basic_desired_width(self):
return self.wrapper_formatter.get_basic_desired_width()
def wrapper_formatter_factory(ctx, field, formatter):
"""
This function is a factory for building WrapperFormatter objects.
@ -462,28 +465,26 @@ def build_column_stats_for_best_guess_formatting(objs, fields, field_labels, cus
self.average_percent = float(self.average_width) / float(avg_total_width)
def __str__(self):
return str(
[self.field,
self.average_width,
self.min_width,
self.max_width,
self.total_width,
self.count,
self.average_percent,
self.max_percent,
self.isUUID])
return str([self.field,
self.average_width,
self.min_width,
self.max_width,
self.total_width,
self.count,
self.average_percent,
self.max_percent,
self.isUUID])
def __repr__(self):
return str(
[self.field,
self.average_width,
self.min_width,
self.max_width,
self.total_width,
self.count,
self.average_percent,
self.max_percent,
self.isUUID])
return str([self.field,
self.average_width,
self.min_width,
self.max_width,
self.total_width,
self.count,
self.average_percent,
self.max_percent,
self.isUUID])
if objs is None or len(objs) == 0:
return {"stats": {},
@ -520,7 +521,7 @@ def build_best_guess_formatters_using_average_widths(objs, fields, field_labels,
# Handle no wrap fields by building formatters that will not wrap
for f in [ff for ff in fields if ff in no_wrap_fields]:
format_spec[f] = {"hard_width" : column_info["stats"][f].max_width }
format_spec[f] = {"hard_width": column_info["stats"][f].max_width}
custom_formatter = custom_formatters.get(f, None)
if custom_formatter:
format_spec[f] = {"formatter": custom_formatter, "wrapperFormatter": format_spec[f]}
@ -538,7 +539,7 @@ def build_best_guess_formatters_using_max_widths(objs, fields, field_labels, cus
# Handle no wrap fields by building formatters that will not wrap
for f in [ff for ff in fields if ff in no_wrap_fields]:
format_spec[f] = {"hard_width" : column_info["stats"][f].max_width }
format_spec[f] = {"hard_width": column_info["stats"][f].max_width}
custom_formatter = custom_formatters.get(f, None)
if custom_formatter:
format_spec[f] = {"formatter": custom_formatter, "wrapperFormatter": format_spec[f]}
@ -566,17 +567,17 @@ def needs_wrapping_formatters(formatters, no_wrap=None):
def as_wrapping_formatters(objs, fields, field_labels, formatters, no_wrap=None, no_wrap_fields=[]):
""" This function is the entry point for building the "best guess"
word wrapping formatters. A best guess formatter guesses what the best
columns widths should be for the table celldata. It does this by collecting
various stats on the celldata (min, max average width of column celldata) and from
this celldata decides the desired widths and the minimum widths.
Given a list of formatters and the list of objects (objs), this function
first determines if we need to augment the passed formatters with word wrapping
formatters. If the no_wrap parameter or global no_wrap flag is set,
then we do not build wrapping formatters. If any of the formatters within formatters
is a word wrapping formatter, then it is assumed no more wrapping is required.
"""This function is the entry point for building the "best guess"
word wrapping formatters. A best guess formatter guesses what the best
columns widths should be for the table celldata. It does this by collecting
various stats on the celldata (min, max average width of column celldata) and from
this celldata decides the desired widths and the minimum widths.
Given a list of formatters and the list of objects (objs), this function
first determines if we need to augment the passed formatters with word wrapping
formatters. If the no_wrap parameter or global no_wrap flag is set,
then we do not build wrapping formatters. If any of the formatters within formatters
is a word wrapping formatter, then it is assumed no more wrapping is required.
:param objs:
:param fields:
@ -717,13 +718,13 @@ def set_no_wrap_on_formatters(no_wrap, formatters):
global_orig_no_wrap = is_nowrap_set()
set_no_wrap(no_wrap)
for k,f in formatters.iteritems():
for k, f in formatters.iteritems():
if WrapperFormatter.is_wrapper_formatter(f):
formatter_no_wrap_settings[k] = (f.wrapper_formatter.no_wrap, f.wrapper_formatter)
f.wrapper_formatter.no_wrap = no_wrap
return { "global_orig_no_wrap" : global_orig_no_wrap,
"formatter_no_wrap_settings" : formatter_no_wrap_settings }
return {"global_orig_no_wrap": global_orig_no_wrap,
"formatter_no_wrap_settings": formatter_no_wrap_settings}
def unset_no_wrap_on_formatters(orig_no_wrap_settings):
@ -740,7 +741,7 @@ def unset_no_wrap_on_formatters(orig_no_wrap_settings):
formatters = {}
for k,v in formatter_no_wrap_settings.iteritems():
for k, v in formatter_no_wrap_settings.iteritems():
formatters[k] = v[1]
formatters[k].no_wrap = v[0]
@ -758,49 +759,46 @@ def _simpleTestHarness(no_wrap):
def buildFormatter(field, width):
def f(dict):
if field=='number':
if field == 'number':
return dict[field]
return "{}".format(dict[field]).replace("_"," ")
return {"formatter":f,"wrapperFormatter":width}
return "{}".format(dict[field]).replace("_", " ")
return {"formatter": f, "wrapperFormatter": width}
set_no_wrap(no_wrap)
field_labels = ['Time Stamp', 'State', 'Event Log ID', 'Reason Text',
'Entity Instance ID', 'Severity','Number']
'Entity Instance ID', 'Severity', 'Number']
fields = ['timestamp', 'state', 'event_log_id', 'reason_text',
'entity_instance_id', 'severity','number']
formatterSpecX = {
"timestamp" : 10,
"state" : 8,
"event_log_id" : 70,
"reason_text" : 30,
"entity_instance_id" : 30,
"severity" : 12,
"number" : 4
}
'entity_instance_id', 'severity', 'number']
formatterSpecX = {"timestamp": 10,
"state": 8,
"event_log_id": 70,
"reason_text": 30,
"entity_instance_id": 30,
"severity": 12,
"number": 4}
formatterSpec = {}
for f in fields:
formatterSpec[f] = buildFormatter(f,formatterSpecX[f])
formatterSpec[f] = buildFormatter(f, formatterSpecX[f])
logs = []
for i in xrange(0,30):
for i in xrange(0, 30):
log = {}
for f in fields:
if f == 'number':
log[f] = i
else:
log[f] = "{}{}".format(f,i)
log[f] = "{}{}".format(f, i)
logs.append(utils.objectify(log))
formatterSpec = formatterSpecX
formatters = build_wrapping_formatters(logs, fields, field_labels, formatterSpec)
utils.print_list(logs, fields, field_labels, formatters=formatters, sortby=6,
reversesort=True,no_wrap_fields=['entity_instance_id'])
utils.print_list(logs, fields, field_labels, formatters=formatters, sortby=6,
reversesort=True, no_wrap_fields=['entity_instance_id'])
print "nowrap = {}".format(is_nowrap_set())

2
sysinv/cgts-client/cgts-client/cgtsclient/exc.py

@ -139,7 +139,7 @@ class HTTPServiceUnavailable(ServiceUnavailable):
pass
#NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception
# NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception
# classes
_code_map = {}
for obj_name in dir(sys.modules[__name__]):

7
sysinv/cgts-client/cgts-client/cgtsclient/openstack/common/importutils.py

@ -41,10 +41,9 @@ def import_object(import_str, *args, **kwargs):
def import_object_ns(name_space, import_str, *args, **kwargs):
"""
Import a class and return an instance of it, first by trying
to find the class in a default namespace, then failing back to
a full path if not found in the default namespace.
"""Import a class and return an instance of it, first by trying
to find the class in a default namespace, then failing back to
a full path if not found in the default namespace.
"""
import_value = "%s.%s" % (name_space, import_str)
try:

10
sysinv/cgts-client/cgts-client/cgtsclient/shell.py

@ -28,7 +28,6 @@ from cgtsclient import client as cgclient
from cgtsclient.common import utils
from cgtsclient import exc
import keyring
import os
@ -151,8 +150,7 @@ class CgtsShell(object):
help=argparse.SUPPRESS)
parser.add_argument('--system-api-version',
default=utils.env(
'SYSTEM_API_VERSION', default='1'),
default=utils.env('SYSTEM_API_VERSION', default='1'),
help='Defaults to env[SYSTEM_API_VERSION] '
'or 1')
@ -233,9 +231,7 @@ class CgtsShell(object):
httplib2.debuglevel = 1
else:
logging.basicConfig(
format="%(levelname)s %(message)s",
level=logging.CRITICAL)
logging.basicConfig(format="%(levelname)s %(message)s", level=logging.CRITICAL)
def main(self, argv):
# Parse args once to find version
@ -274,6 +270,7 @@ class CgtsShell(object):
if not args.os_password:
# priviledge check (only allow Keyring retrieval if we are root)
if os.geteuid() == 0:
import keyring
args.os_password = keyring.get_password('CGCS', args.os_username)
else:
raise exc.CommandError("You must provide a password via "
@ -315,7 +312,6 @@ class CgtsShell(object):
commands.remove('bash_completion')
print(' '.join(commands | options))
@utils.arg('command', metavar='<subcommand>', nargs='?',
help='Display help for <subcommand>')
def do_help(self, args):

0
sysinv/cgts-client/cgts-client/cgtsclient/tests/__init__.py

44
sysinv/cgts-client/cgts-client/cgtsclient/tests/test_http.py

@ -1,44 +0,0 @@
# Copyright 2012 OpenStack LLC.
# All Rights Reserved.
#
# 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 cgtsclient.tests import utils
from cgtsclient.common import http
fixtures = {}
class HttpClientTest(utils.BaseTestCase):
def test_url_generation_trailing_slash_in_base(self):
client = http.HTTPClient('http://localhost/')
url = client._make_connection_url('/v1/resources')
self.assertEqual(url, '/v1/resources')
def test_url_generation_without_trailing_slash_in_base(self):
client = http.HTTPClient('http://localhost')
url = client._make_connection_url('/v1/resources')
self.assertEqual(url, '/v1/resources')
def test_url_generation_prefix_slash_in_path(self):
client = http.HTTPClient('http://localhost/')
url = client._make_connection_url('/v1/resources')
self.assertEqual(url, '/v1/resources')
def test_url_generation_without_prefix_slash_in_path(self):
client = http.HTTPClient('http://localhost')
url = client._make_connection_url('v1/resources')
self.assertEqual(url, '/v1/resources')

8
sysinv/cgts-client/cgts-client/cgtsclient/tests/test_shell.py

@ -78,8 +78,12 @@ class ShellTest(utils.BaseTestCase):
def test_help_on_subcommand(self):
required = [
'.*?^usage: system host-show',
".*?^Show a host",
'.*?^usage: system host-show <hostname or id>'
'',
".*?^Show host attributes.",
'',
".*?^Positional arguments:",
".*?^ <hostname or id> Name or ID of host",
]
argstrings = [
'help host-show',

2
sysinv/cgts-client/cgts-client/cgtsclient/tests/test_utils.py

@ -69,7 +69,7 @@ class UtilsTest(test_utils.BaseTestCase):
self.assertEqual(patch, [{'op': 'add',
'value': 'bar',
'path': '/foo'},
{'op': 'add',
{'op': 'add',
'value': 'baz',
'path': '/extra/bar'}])

47
sysinv/cgts-client/cgts-client/cgtsclient/tests/v1/test_invServer.py

@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 Hewlett-Packard Development Company, L.P.
@ -23,25 +22,22 @@
import copy
import testtools
#hello
from cgtsclient.tests import utils
import cgtsclient.v1.ihost
IHOST = {'id': 123,
'uuid': '66666666-7777-8888-9999-000000000000',
'hostname': 'cgtshost',
'personality': 'controller',
'mgmt_mac': '11:22:33:44:55:66',
'mgmt_ip': '192.168.24.11',
'serialid': 'sn123456',
'location': {'City': 'Ottawa'},
'boot_device': 'sda',
'rootfs_device': 'sda',
'install_output': "text",
'console': 'ttyS0,115200',
'tboot': '',
}
# 'administrative': 'unlocked'} if have this, fails create
'uuid': '66666666-7777-8888-9999-000000000000',
'hostname': 'cgtshost',
'personality': 'controller',
'mgmt_mac': '11:22:33:44:55:66',
'mgmt_ip': '192.168.24.11',
'serialid': 'sn123456',
'location': {'City': 'Ottawa'},
'boot_device': 'sda',
'rootfs_device': 'sda',
'install_output': "text",
'console': 'ttyS0,115200',
'tboot': ''}
PORT = {'id': 456,
'uuid': '11111111-2222-3333-4444-555555555555',
@ -57,9 +53,6 @@ UPDATED_IHOST = copy.deepcopy(IHOST)
NEW_LOC = 'newlocOttawa'
UPDATED_IHOST['location'] = NEW_LOC
#NEW_MTCADMINSTATE = 'locked'
#UPDATED_IHOST['administrative'] = NEW_MTCADMINSTATE
fixtures = {
'/v1/ihosts':
@ -142,23 +135,9 @@ class ihostManagerTest(testtools.TestCase):
'value': NEW_LOC,
'path': '/location'}
ihost = self.mgr.update(ihost_id=IHOST['uuid'],
patch=patch)
patch=patch)
expect = [
('PATCH', '/v1/ihosts/%s' % IHOST['uuid'], {}, patch),
]
self.assertEqual(self.api.calls, expect)
self.assertEqual(ihost.location, NEW_LOC)
#def test_ihost_port_list(self):
# ports = self.mgr.list_iport(IHOST['uuid'])
#def test_ihost_port_list(self):
# ports = self.mgr.list_iport(IHOST['uuid'])
# expect = [
# ('GET', '/v1/ihosts/%s/iport'
# % IHOST['uuid'], {}, None),
# ]
# self.assertEqual(self.api.calls, expect)
# self.assertEqual(len(ports), 1)
# self.assertEqual(ports[0].uuid, PORT['uuid'])
# self.assertEqual(ports[0].address, PORT['address'])

4
sysinv/cgts-client/cgts-client/cgtsclient/v1/__init__.py

@ -1,6 +1,3 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Red Hat, Inc.
# All Rights Reserved.
#
@ -18,4 +15,3 @@
#
# Copyright (c) 2013-2014 Wind River Systems, Inc.
#

9
sysinv/cgts-client/cgts-client/cgtsclient/v1/address_pool_shell.py

@ -63,9 +63,8 @@ def do_addrpool_delete(cc, args):
def _get_range_tuples(data):
"""
Split the ranges field from a comma separated list of start-end to a
real list of (start, end) tuples.
"""Split the ranges field from a comma separated list of start-end to a
real list of (start, end) tuples.
"""
ranges = []
for r in data['ranges'].split(',') or []:
@ -94,7 +93,7 @@ def do_addrpool_add(cc, args):
field_list = ['name', 'network', 'prefix', 'order', 'ranges']
## Prune input fields down to required/expected values
# Prune input fields down to required/expected values
data = dict((k, v) for (k, v) in vars(args).items()
if k in field_list and not (v is None))
@ -135,7 +134,7 @@ def do_addrpool_modify(cc, args):
patch = []
for (k, v) in data.items():
patch.append({'op':'replace', 'path':'/'+k, 'value':v})
patch.append({'op': 'replace', 'path': '/' + k, 'value': v})
address_pool = cc.address_pool.update(args.address_pool_uuid, patch)
_print_address_pool_show(address_pool)

6
sysinv/cgts-client/cgts-client/cgtsclient/v1/address_shell.py

@ -71,15 +71,15 @@ def do_host_addr_add(cc, args):
field_list = ['address', 'prefix']
## Lookup parent host and interface
# Lookup parent host and interface
ihost = ihost_utils._find_ihost(cc, args.hostnameorid)
iinterface = iinterface_utils._find_interface(cc, ihost, args.ifnameorid)
## Prune input fields down to required/expected values
# Prune input fields down to required/expected values
data = dict((k, v) for (k, v) in vars(args).items()
if k in field_list and not (v is None))
## Insert interface UUID
# Insert interface UUID
data['interface_uuid'] = iinterface.uuid
address = cc.address.create(**data)

2
sysinv/cgts-client/cgts-client/cgtsclient/v1/ceph_mon.py

@ -8,9 +8,7 @@
#
from cgtsclient.common import base
from cgtsclient.common import utils
from cgtsclient import exc
from cgtsclient.v1 import ihost as ihost_utils
CREATION_ATTRIBUTES = ['ceph_mon_gib', 'ceph_mon_dev',
'ceph_mon_dev_ctrl0', 'ceph_mon_dev_ctrl1']

6
sysinv/cgts-client/cgts-client/cgtsclient/v1/ceph_mon_shell.py

@ -9,8 +9,8 @@
# All Rights Reserved.
#
from cgtsclient.common import utils
from cgtsclient.common import constants
from cgtsclient.common import utils
from cgtsclient.v1 import ihost as ihost_utils
@ -36,8 +36,7 @@ def _print_ceph_mon_list(cc):
constants.CONTROLLER_1_HOSTNAME],
help='Specify controller host name <%s | %s> ' % (
constants.CONTROLLER_0_HOSTNAME,
constants.CONTROLLER_1_HOSTNAME
))
constants.CONTROLLER_1_HOSTNAME))
@utils.arg('attributes',
metavar='<path=value>',
nargs='+',
@ -76,6 +75,7 @@ def do_ceph_mon_list(cc, args):
"""List ceph mons"""
_print_ceph_mon_list(cc)
@utils.arg('hostnameorid',
metavar='<hostname or id>',
help="name or ID of host [REQUIRED]")

6
sysinv/cgts-client/cgts-client/cgtsclient/v1/certificate_shell.py

@ -9,9 +9,9 @@
# All Rights Reserved.
#
import os
from cgtsclient import exc
from cgtsclient.common import utils
from collections import OrderedDict
from cgtsclient import exc
def _print_certificate_show(certificate):
@ -77,7 +77,7 @@ def do_certificate_install(cc, args):
certificate_file = args.certificate_file
try:
sec_file = open(certificate_file, 'rb')
except:
except Exception:
raise exc.CommandError("Error: Could not open file %s." %
certificate_file)

84
sysinv/cgts-client/cgts-client/cgtsclient/v1/client.py

@ -20,59 +20,59 @@
from cgtsclient.common import http
from cgtsclient.v1 import address
from cgtsclient.v1 import address_pool
from cgtsclient.v1 import isystem
from cgtsclient.v1 import ihost
from cgtsclient.v1 import inode
from cgtsclient.v1 import icpu
from cgtsclient.v1 import imemory
from cgtsclient.v1 import iinterface
from cgtsclient.v1 import idisk
from cgtsclient.v1 import istor
from cgtsclient.v1 import ipv
from cgtsclient.v1 import ilvg
from cgtsclient.v1 import iuser
from cgtsclient.v1 import idns
from cgtsclient.v1 import intp
from cgtsclient.v1 import iextoam
from cgtsclient.v1 import controller_fs
from cgtsclient.v1 import storage_backend
from cgtsclient.v1 import storage_lvm
from cgtsclient.v1 import storage_file
from cgtsclient.v1 import storage_external
from cgtsclient.v1 import storage_ceph
from cgtsclient.v1 import ceph_mon
from cgtsclient.v1 import certificate
from cgtsclient.v1 import cluster
from cgtsclient.v1 import controller_fs
from cgtsclient.v1 import drbdconfig
from cgtsclient.v1 import iprofile
from cgtsclient.v1 import icommunity
from cgtsclient.v1 import itrapdest
from cgtsclient.v1 import ialarm
from cgtsclient.v1 import iinfra
from cgtsclient.v1 import port
from cgtsclient.v1 import ethernetport
from cgtsclient.v1 import route
from cgtsclient.v1 import event_log
from cgtsclient.v1 import event_suppression
from cgtsclient.v1 import firewallrules
from cgtsclient.v1 import health
from cgtsclient.v1 import ialarm
from cgtsclient.v1 import icommunity
from cgtsclient.v1 import icpu
from cgtsclient.v1 import idisk
from cgtsclient.v1 import idns
from cgtsclient.v1 import iextoam
from cgtsclient.v1 import ihost
from cgtsclient.v1 import iinfra
from cgtsclient.v1 import iinterface
from cgtsclient.v1 import ilvg
from cgtsclient.v1 import imemory
from cgtsclient.v1 import inode
from cgtsclient.v1 import intp
from cgtsclient.v1 import iprofile
from cgtsclient.v1 import ipv
from cgtsclient.v1 import isensor
from cgtsclient.v1 import isensorgroup
from cgtsclient.v1 import istor
from cgtsclient.v1 import isystem
from cgtsclient.v1 import itrapdest
from cgtsclient.v1 import iuser
from cgtsclient.v1 import license
from cgtsclient.v1 import lldp_agent
from cgtsclient.v1 import lldp_neighbour
from cgtsclient.v1 import load
from cgtsclient.v1 import pci_device
from cgtsclient.v1 import upgrade
from cgtsclient.v1 import network
from cgtsclient.v1 import partition
from cgtsclient.v1 import pci_device
from cgtsclient.v1 import port
from cgtsclient.v1 import remotelogging
from cgtsclient.v1 import route
from cgtsclient.v1 import sdn_controller
from cgtsclient.v1 import service_parameter
from cgtsclient.v1 import cluster
from cgtsclient.v1 import lldp_agent
from cgtsclient.v1 import lldp_neighbour
from cgtsclient.v1 import license
from cgtsclient.v1 import sm_service_nodes
from cgtsclient.v1 import sm_service
from cgtsclient.v1 import sm_service_nodes
from cgtsclient.v1 import sm_servicegroup
from cgtsclient.v1 import health
from cgtsclient.v1 import remotelogging
from cgtsclient.v1 import sdn_controller
from cgtsclient.v1 import firewallrules
from cgtsclient.v1 import partition
from cgtsclient.v1 import certificate
from cgtsclient.v1 import storage_backend
from cgtsclient.v1 import storage_ceph
from cgtsclient.v1 import storage_external
from cgtsclient.v1 import storage_file
from cgtsclient.v1 import storage_lvm
from cgtsclient.v1 import storage_tier
from cgtsclient.v1 import upgrade