Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package linstor-client for openSUSE:Factory checked in at 2021-02-19 23:43:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/linstor-client (Old) and /work/SRC/openSUSE:Factory/.linstor-client.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "linstor-client" Fri Feb 19 23:43:23 2021 rev:3 rq:866740 version:1.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/linstor-client/linstor-client.changes 2020-09-22 21:15:07.864136749 +0200 +++ /work/SRC/openSUSE:Factory/.linstor-client.new.28504/linstor-client.changes 2021-02-19 23:44:58.891346699 +0100 @@ -1,0 +2,18 @@ +Tue Jan 26 06:23:29 UTC 2021 - nick wang <nw...@suse.com> + +- bsc#1181397, update to 1.6.1 + * Fix reconnect on timeout error in interactive mode + * Fix incorrect resource toggle-disk short option -dflt -> --dflt + * Toggle disk storage pool options are now optional + * node list now shows DELETING and EVICTED nodes + * Added diskless placement and additional placement count for auto-place + * Added node restore command for evicted nodes + * depend on python-linstor v1.6.0 + * migrate: remove unused AllowLargerVolumeSize property + * fix incorrect use of argparse.ArgumentTypeError + * drbd-options: add units to error message + * Allow setting options via environment variables, prefix is `LS_CLIENT_` + * Added error-report delete command + * Commandline choices(enums) are now mostly case insensitive + +------------------------------------------------------------------- Old: ---- linstor-client-1.3.0.tar.gz New: ---- linstor-client-1.6.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ linstor-client.spec ++++++ --- /var/tmp/diff_new_pack.AkELv1/_old 2021-02-19 23:44:59.479347275 +0100 +++ /var/tmp/diff_new_pack.AkELv1/_new 2021-02-19 23:44:59.483347279 +0100 @@ -1,7 +1,7 @@ # # spec file for package linstor-client # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,8 +17,9 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} +%define python_linstor 1.6 Name: linstor-client -Version: 1.3.0 +Version: 1.6.1 Release: 0 Summary: DRBD distributed resource management utility License: GPL-3.0-only @@ -27,15 +28,22 @@ Source: http://www.linbit.com/downloads/linstor/%{name}-%{version}.tar.gz Patch1: change-location-of-bash-completion.patch BuildRequires: %{python_module devel} -BuildRequires: %{python_module linstor >= %{version}} +BuildRequires: %{python_module linstor >= %{python_linstor}} BuildRequires: %{python_module setuptools} BuildRequires: fdupes -Requires: %{python_module linstor >= %{version}} +Requires: %{python_module linstor >= %{python_linstor}} %python_subpackages %description This client program communicates to a linstor controller node which manages the DRBD9 resources. +%package -n linstor +Summary: Binaries of linstor client +Group: Productivity/Clustering/HA + +%description -n linstor +Binaries of linstor client + %prep %setup -q %patch1 -p1 @@ -55,9 +63,9 @@ %files %{python_files} %{python_sitelib} -# FIXME: with python3_only, binaries only exist in python3-linstor-client -%python3_only %{_bindir}/linstor -%python3_only %{_mandir}/man8/linstor* -%python3_only %{_datadir}/bash-completion/completions/linstor + +%files -n linstor +%{_bindir}/linstor +%{_datadir}/bash-completion/completions/linstor %changelog ++++++ _service ++++++ --- /var/tmp/diff_new_pack.AkELv1/_old 2021-02-19 23:44:59.503347298 +0100 +++ /var/tmp/diff_new_pack.AkELv1/_new 2021-02-19 23:44:59.507347302 +0100 @@ -5,10 +5,10 @@ <param name="filename">linstor-client</param> <!-- build service using release linstor-client atm. - <param name="version">1.3.0</param> + <param name="version">1.6.1</param> Need to use the corresponding linstor-api-py --> - <param name="versionformat">1.3.0+git.%h</param> + <param name="versionformat">1.6.1+git.%h</param> <param name="revision">master</param> </service> ++++++ linstor-client-1.3.0.tar.gz -> linstor-client-1.6.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/Dockerfile new/linstor-client-1.6.1/Dockerfile --- old/linstor-client-1.3.0/Dockerfile 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/Dockerfile 2021-01-13 10:56:42.000000000 +0100 @@ -1,7 +1,7 @@ FROM centos:centos7 as builder -ENV LINSTOR_CLI_VERSION 1.3.0 -ENV PYTHON_LINSTOR_VERSION 1.3.0 +ENV LINSTOR_CLI_VERSION 1.6.1 +ENV PYTHON_LINSTOR_VERSION 1.6.0 ENV LINSTOR_CLI_PKGNAME linstor-client ENV LINSTOR_CLI_TGZ ${LINSTOR_CLI_PKGNAME}-${LINSTOR_CLI_VERSION}.tar.gz @@ -45,7 +45,7 @@ MAINTAINER Roland Kammerer <roland.kamme...@linbit.com> # ENV can not be shared between builder and "main" -ENV LINSTOR_CLI_VERSION 1.3.0 +ENV LINSTOR_CLI_VERSION 1.6.1 ARG release=1 LABEL name="linstor-client" \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/Makefile new/linstor-client-1.6.1/Makefile --- old/linstor-client-1.3.0/Makefile 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/Makefile 2021-01-13 10:56:42.000000000 +0100 @@ -16,6 +16,7 @@ DOCKERREGPATH_QUAY = $(DOCKERREGISTRY_QUAY)/linbit/linstor-client DOCKERREGPATH_DOCKER = linbit/linstor-client DOCKER_TAG ?= latest +NO_DOC ?= all: doc $(PYTHON) setup.py build @@ -38,15 +39,17 @@ $(info "Version strings/Changelogs up to date") endif -release: up2date clean doc +release: doc + make release-no-doc + +release-no-doc: up2date clean $(PYTHON) setup.py sdist @echo && echo "Did you run distclean?" - @echo && echo "Did you generate and commit the latest drbdsetup options?" debrelease: echo 'recursive-include debian *' >> MANIFEST.in dh_clean || true - make release + make release$(NO_DOC) git checkout MANIFEST.in ifneq ($(FORCE),1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/PKG-INFO new/linstor-client-1.6.1/PKG-INFO --- old/linstor-client-1.3.0/PKG-INFO 2020-08-17 15:42:00.463261600 +0200 +++ new/linstor-client-1.6.1/PKG-INFO 2021-01-13 10:56:46.487815000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: linstor-client -Version: 1.3.0 +Version: 1.6.1 Summary: DRBD distributed resource management utility Home-page: https://www.linbit.com Author: Robert Altnoeder <robert.altnoe...@linbit.com>, Roland Kammerer <roland.kamme...@linbit.com>, Rene Peinthor <rene.peint...@linbit.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/__init__.py new/linstor-client-1.6.1/linstor_client/commands/__init__.py --- old/linstor-client-1.3.0/linstor_client/commands/__init__.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/__init__.py 2021-01-13 10:56:42.000000000 +0100 @@ -15,3 +15,4 @@ from .migrate_cmds import MigrateCommands from .zsh_completer import ZshGenerator from .physical_storage_cmds import PhysicalStorageCommands +from .error_report_cmds import ErrorReportCommands diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/commands.py new/linstor-client-1.6.1/linstor_client/commands/commands.py --- old/linstor-client-1.3.0/linstor_client/commands/commands.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/commands.py 2021-01-13 10:56:42.000000000 +0100 @@ -6,7 +6,7 @@ from datetime import datetime, timedelta import linstor -from linstor.sharedconsts import NAMESPC_AUXILIARY +import linstor.sharedconsts as apiconsts from linstor.properties import properties from linstor import SizeCalc import linstor_client @@ -61,6 +61,7 @@ DRBD_PROXY = 'drbd-proxy' PHYSICAL_STORAGE = 'physical-storage' SOS_REPORT = 'sos-report' + SPACE_REPORTING = 'space-reporting' MainList = [ CONTROLLER, @@ -81,7 +82,8 @@ SNAPSHOT, DRBD_PROXY, PHYSICAL_STORAGE, - SOS_REPORT + SOS_REPORT, + SPACE_REPORTING ] Hidden = [ DMMIGRATE, @@ -90,9 +92,9 @@ ] def __init__(self): - self._linstor = None # type: linstor.Linstor + self._linstor = None # type: Optional[linstor.Linstor] # _linstor_completer is just here as a cache for completer calls - self._linstor_completer = None # type: linstor.Linstor + self._linstor_completer = None # type: Optional[linstor.Linstor] class Subcommands(object): @@ -252,6 +254,10 @@ LONG = "ship-list" SHORT = "shl" + class Query(object): + LONG = "query" + SHORT = "qry" + @staticmethod def generate_desc(subcommands): """ @@ -467,7 +473,7 @@ @classmethod def _attach_aux_prop(cls, args): if args.aux: - args.key = NAMESPC_AUXILIARY + '/' + args.key + args.key = apiconsts.NAMESPC_AUXILIARY + '/' + args.key return args @classmethod @@ -480,14 +486,14 @@ if use_place_count: parser.add_argument( '--place-count', - type=int, + type=str, metavar="REPLICA_COUNT", help='Auto place a resource to a specified number of nodes, set 0 to remove' ) else: parser.add_argument( '--auto-place', - type=int, + type=str, metavar="REPLICA_COUNT", help='Auto place a resource to a specified number of nodes' ) @@ -539,6 +545,39 @@ "Possible providers are: " + ",".join(linstor.Linstor.provider_list())) @classmethod + def parse_place_count_args(cls, args, use_place_count=False): + """ + + :param args: argparse arguments + :param bool use_place_count: if replica count is named `place-count` or `auto-place` + :return: Tuple with (place_count, additional_place_count, diskless_type) + """ + if args.drbd_diskless: + diskless_type = apiconsts.FLAG_DRBD_DISKLESS + elif args.nvme_initiator: + diskless_type = apiconsts.FLAG_NVME_INITIATOR + elif hasattr(args, "diskless") and args.diskless: + diskless_type = apiconsts.FLAG_DISKLESS + else: + diskless_type = None + + place_count_arg = args.place_count if use_place_count else args.auto_place + + additional_place_count = None + place_count = None + + if place_count_arg: + if place_count_arg.startswith("+"): + additional_place_count = int(place_count_arg[1:]) + elif place_count_arg in ['max', 'all']: + place_count = -1 + additional_place_count = 0 + else: + place_count = int(place_count_arg) + + return place_count, additional_place_count, diskless_type + + @classmethod def parse_diskless_on_remaining(cls, args): if hasattr(args, 'diskless_on_remaining'): if args.diskless_on_remaining is None: @@ -548,6 +587,29 @@ return None @staticmethod + def parse_time_str(timestr): + """ + Parses a day and hour string to a datetime from the current time. + e.g.: `1d10h or 3h` + :param str timestr: string to parse + :return: datetime of the timestr + :rtype: datetime + """ + m = re.match(r'(\d+\W*d)?(\d+\W*h)?', timestr) + if m: + since_dt = datetime.now() + if m.group(1): + since_dt -= timedelta(days=int(m.group(1)[:-1])) + if m.group(2): + since_dt -= timedelta(hours=int(m.group(2)[:-1])) + return since_dt + else: + raise LinstorClientError( + "Unable to parse since string: '{s_str}'. e.g.: 1d10h or 3h'".format(s_str=timestr), + ExitCode.ARGPARSE_ERROR + ) + + @staticmethod def show_group_completer(lst, where): def completer(prefix, parsed_args, **kwargs): possible = lst @@ -720,7 +782,7 @@ layer_list = [] for layer in layer_data.split(','): if layer.lower() not in linstor.Linstor.layer_list(): - raise argparse.ArgumentTypeError('Layer name "{lay}" not valid'.format(lay=layer)) + raise ArgumentError('Layer name "{lay}" not valid'.format(lay=layer)) layer_list.append(layer) return layer_list @@ -742,7 +804,7 @@ provider_list = [] for provider in providers.split(","): if provider.upper() not in linstor.Linstor.provider_list(): - raise argparse.ArgumentTypeError('Provider "{prov}" not valid'.format(prov=provider)) + raise ArgumentError('Provider "{prov}" not valid'.format(prov=provider)) provider_list.append(provider) return provider_list @@ -897,55 +959,6 @@ self.check_subcommands(crypt_subp, crypt_subcmds) - # Error subcommands - error_subcmds = [ - Commands.Subcommands.List, - Commands.Subcommands.Show - ] - error_parser = parser.add_parser( - Commands.ERROR_REPORTS, - aliases=["err"], - formatter_class=argparse.RawTextHelpFormatter, - description="Error report subcommands") - - error_subp = error_parser.add_subparsers( - title="Error report commands", - metavar="", - description=Commands.Subcommands.generate_desc(error_subcmds) - ) - - c_list_error_reports = error_subp.add_parser( - Commands.Subcommands.List.LONG, - aliases=[Commands.Subcommands.List.SHORT], - description='List error reports.' - ) - c_list_error_reports.add_argument('-s', '--since', help='Show errors since n days. e.g. "3days"') - c_list_error_reports.add_argument('-t', '--to', help='Show errors to specified date. Format YYYY-MM-DD.') - c_list_error_reports.add_argument( - '-n', - '--nodes', - help='Only show error reports from these nodes.', - nargs='+' - ) - c_list_error_reports.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') - c_list_error_reports.add_argument( - '--report-id', - nargs='+', - help="Restrict to id's that begin with the given ones." - ) - c_list_error_reports.add_argument('-f', '--full', action="store_true", help='Show all error info fields') - c_list_error_reports.set_defaults(func=self.cmd_list_error_reports) - - c_error_report = error_subp.add_parser( - Commands.Subcommands.Show.LONG, - aliases=[Commands.Subcommands.Show.SHORT], - description='Output content of an error report.' - ) - c_error_report.add_argument("report_id", nargs='+') - c_error_report.set_defaults(func=self.cmd_error_report) - - self.check_subcommands(error_subp, error_subcmds) - sos_subcommands = [ Commands.Subcommands.Create, Commands.Subcommands.Download @@ -981,6 +994,30 @@ c_sos_download.set_defaults(func=self.cmd_sos_report_download) self.check_subcommands(sos_subp, sos_subcommands) + space_reporting_subcmds = [ + Commands.Subcommands.Query + ] + spc_rep_parser = parser.add_parser( + Commands.SPACE_REPORTING, + aliases=["spr"], + formatter_class=argparse.RawTextHelpFormatter, + description="Space reporting subcommands") + + spc_rep_subp = spc_rep_parser.add_subparsers( + title="Space reporting commands", + metavar="", + description=Commands.Subcommands.generate_desc(space_reporting_subcmds) + ) + + c_spc_report_query = spc_rep_subp.add_parser( + Commands.Subcommands.Query.LONG, + aliases=[Commands.Subcommands.Query.SHORT], + description='Queries the space reporting string' + ) + c_spc_report_query.set_defaults(func=self.cmd_spc_report_query) + + self.check_subcommands(spc_rep_subp, space_reporting_subcmds) + @staticmethod def _summarize_api_call_responses(responses): return "; ".join([response.message for response in responses]) @@ -1022,81 +1059,6 @@ replies = self._linstor.crypt_modify_passphrase(old_passphrase, new_passphrase) return self.handle_replies(args, replies) - @classmethod - def show_error_report_list(cls, args, lstmsg): - """ - - :param args: - :param list[linstor.responses.ErrorReport] lstmsg: - :return: - """ - tbl = linstor_client.Table(utf8=not args.no_utf8, colors=not args.no_color, pastable=args.pastable) - tbl.add_header(linstor_client.TableHeader("Id")) - tbl.add_header(linstor_client.TableHeader("Datetime")) - tbl.add_header(linstor_client.TableHeader("Node")) - tbl.add_header(linstor_client.TableHeader("Exception")) - if args.full: - tbl.add_header(linstor_client.TableHeader("Location")) - tbl.add_header(linstor_client.TableHeader("Version")) - - for error in lstmsg: - msg = error.exception_message if len(error.exception_message) < 60 else error.exception_message[0:57]+'...' - row = [ - error.id, - str(error.datetime)[:19], - (error.module[0] + '|' if error.module else "") + error.node_names, - error.exception + (": " + msg if msg else "")] - if args.full: - row += ["{f}:{l}".format(f=error.origin_file, l=error.origin_line) if error.origin_file else "", - error.version] - tbl.add_row(row) - tbl.show() - - @staticmethod - def parse_time_str(timestr): - """ - Parses a day and hour string to a datetime from the current time. - e.g.: `1d10h or 3h` - :param str timestr: string to parse - :return: datetime of the timestr - :rtype: datetime - """ - m = re.match(r'(\d+\W*d)?(\d+\W*h)?', timestr) - if m: - since_dt = datetime.now() - if m.group(1): - since_dt -= timedelta(days=int(m.group(1)[:-1])) - if m.group(2): - since_dt -= timedelta(hours=int(m.group(2)[:-1])) - return since_dt - else: - raise LinstorClientError( - "Unable to parse since string: '{s_str}'. e.g.: 1d10h or 3h'".format(s_str=timestr), - ExitCode.ARGPARSE_ERROR - ) - - def cmd_list_error_reports(self, args): - since = args.since - since_dt = None - if since: - since_dt = MiscCommands.parse_time_str(since) - - to_dt = None - if args.to: - to_dt = datetime.strptime(args.to, '%Y-%m-%d') - to_dt = to_dt.replace(hour=23, minute=59, second=59) - - lstmsg = self._linstor.error_report_list(nodes=args.nodes, since=since_dt, to=to_dt, ids=args.report_id) - return self.output_list(args, lstmsg, self.show_error_report_list, single_item=False) - - def show_error_report(self, args, lstmsg): - for error in lstmsg: - print(Output.utf8(error.text)) - - def cmd_error_report(self, args): - lstmsg = self._linstor.error_report_list(with_content=True, ids=args.report_id) - return self.output_list(args, lstmsg, self.show_error_report, single_item=False) - def cmd_sos_report_create(self, args): since_dt = None if args.since: @@ -1109,3 +1071,16 @@ if args.since: since_dt = MiscCommands.parse_time_str(args.since) return self.handle_replies(args, self.get_linstorapi().sos_report_download(since=since_dt, to_file=args.path)) + + def show_space_report(self, args, space_report): + """ + + :param args: + :param space_report: responses.SpaceReport + :return: + """ + print(space_report.report) + + def cmd_spc_report_query(self, args): + reply = self.get_linstorapi().space_reporting_query() + return self.output_list(args, reply, self.show_space_report) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/drbd_setup_cmds.py new/linstor-client-1.6.1/linstor_client/commands/drbd_setup_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/drbd_setup_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/drbd_setup_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -1,7 +1,7 @@ import linstor_client.argparse.argparse as argparse from linstor_client.utils import rangecheck, filter_new_args from linstor.properties import properties -import linstor.sharedconsts as apiconsts +from linstor_client.commands import ArgumentError from linstor import SizeCalc, LinstorError @@ -35,12 +35,12 @@ try: i = int(x) if i not in range(_min, _max): - raise argparse.ArgumentTypeError("{v} not in range [{min}-{max}].".format(v=i, min=_min, max=_max)) + raise ArgumentError("{v} not in range [{min}-{max}].".format(v=i, min=_min, max=_max)) return i except ValueError as va: pass if x not in _symbols: - raise argparse.ArgumentTypeError("'{v}' must be one of {s}.".format(v=x, s=_symbols)) + raise ArgumentError("'{v}' must be one of {s}.".format(v=x, s=_symbols)) return x return foo @@ -66,6 +66,7 @@ parser.add_argument( '--' + opt_key, choices=['yes', 'no'], + type=str.lower, help="yes/no (Default: %s)" % (option['default']) ) elif option['type'] == 'string': @@ -97,7 +98,9 @@ parser.add_argument( '--' + opt_key, type=str, - help="Range: [%d, %d]; Default: %s%s" % (min_, max_, str(default), unit) + help="Range: [%d%s, %d%s]; Default: %s%s" % ( + min_, option.get('unit_prefix', ''), + max_, option.get('unit_prefix', ''), str(default), unit) ) else: parser.add_argument('--' + opt_key, type=rangecheck(min_, max_), @@ -141,13 +144,12 @@ if option['min'] <= value <= option['max']: value = str(value) else: - raise argparse.ArgumentTypeError( - prop_name + " value {v} is out of range [{mi}-{ma}]".format( + raise ArgumentError( + prop_name + " value {v}{u} is out of range [{mi}-{ma}]".format( v=value, - mi=option['min'], - ma=option['max'] - ) - ) + u=SizeCalc.unit_to_str(unit), + mi=str(option['min']) + option.get('unit_prefix', ''), + ma=str(option['max']) + option.get('unit_prefix', ''))) modify[key] = str(value) return modify, deletes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/error_report_cmds.py new/linstor-client-1.6.1/linstor_client/commands/error_report_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/error_report_cmds.py 1970-01-01 01:00:00.000000000 +0100 +++ new/linstor-client-1.6.1/linstor_client/commands/error_report_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -0,0 +1,166 @@ +import linstor_client.argparse.argparse as argparse + +import linstor +from linstor_client.table import Table, TableHeader +from linstor_client.utils import Output +from linstor_client.commands import Commands + +from datetime import datetime + + +class ErrorReportCommands(Commands): + def __init__(self): + super(ErrorReportCommands, self).__init__() + + def setup_commands(self, parser): + # Error subcommands + error_subcmds = [ + Commands.Subcommands.List, + Commands.Subcommands.Show, + Commands.Subcommands.Delete + ] + error_parser = parser.add_parser( + Commands.ERROR_REPORTS, + aliases=["err"], + formatter_class=argparse.RawTextHelpFormatter, + description="Error report subcommands") + + error_subp = error_parser.add_subparsers( + title="Error report commands", + metavar="", + description=Commands.Subcommands.generate_desc(error_subcmds) + ) + + c_list_error_reports = error_subp.add_parser( + Commands.Subcommands.List.LONG, + aliases=[Commands.Subcommands.List.SHORT], + description='List error reports.' + ) + c_list_error_reports.add_argument('-s', '--since', help='Show errors since n days. e.g. "3days"') + c_list_error_reports.add_argument('-t', '--to', help='Show errors to specified date. Format YYYY-MM-DD.') + c_list_error_reports.add_argument( + '-n', + '--nodes', + help='Only show error reports from these nodes.', + nargs='+' + ) + c_list_error_reports.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') + c_list_error_reports.add_argument( + '--report-id', + nargs='+', + help="Restrict to id's that begin with the given ones." + ) + c_list_error_reports.add_argument('-f', '--full', action="store_true", help='Show all error info fields') + c_list_error_reports.set_defaults(func=self.cmd_list_error_reports) + + c_error_report = error_subp.add_parser( + Commands.Subcommands.Show.LONG, + aliases=[Commands.Subcommands.Show.SHORT], + description='Output content of an error report.' + ) + c_error_report.add_argument("report_id", nargs='+') + c_error_report.set_defaults(func=self.cmd_error_report) + + c_del_err_report = error_subp.add_parser( + Commands.Subcommands.Delete.LONG, + aliases=[Commands.Subcommands.Delete.SHORT], + description='Delete one or more error reports.' + ) + c_del_err_report.add_argument("--nodes", nargs="+", help="Only delete error reports from the given nodes") + c_del_err_report.add_argument( + "--since", help="Datetime since when to delete error reports. Date format: 2020-08-30 13:40:00") + c_del_err_report.add_argument( + "--to", type=str, help="Datetime until to delete error reports. Date format: 2020-08-30 13:40:00") + c_del_err_report.add_argument("--exception", help="Only delete error reports matching the exception") + c_del_err_report.add_argument("id", nargs="*", help="Delete error reports matching the given ids") + c_del_err_report.set_defaults(func=self.cmd_del_error_report) + + self.check_subcommands(error_subp, error_subcmds) + + @classmethod + def show_error_report_list(cls, args, lstmsg): + """ + + :param args: + :param list[linstor.responses.ErrorReport] lstmsg: + :return: + """ + tbl = Table(utf8=not args.no_utf8, colors=not args.no_color, pastable=args.pastable) + tbl.add_header(TableHeader("Id")) + tbl.add_header(TableHeader("Datetime")) + tbl.add_header(TableHeader("Node")) + tbl.add_header(TableHeader("Exception")) + if args.full: + tbl.add_header(TableHeader("Location")) + tbl.add_header(TableHeader("Version")) + + for error in lstmsg: + msg = error.exception_message if len(error.exception_message) < 60 else error.exception_message[0:57]+'...' + row = [ + error.id, + str(error.datetime)[:19], + (error.module[0] + '|' if error.module else "") + error.node_names, + error.exception + (": " + msg if msg else "")] + if args.full: + row += ["{f}:{l}".format(f=error.origin_file, l=error.origin_line) if error.origin_file else "", + error.version] + tbl.add_row(row) + tbl.show() + + def cmd_list_error_reports(self, args): + since = args.since + since_dt = None + if since: + since_dt = self.parse_time_str(since) + + to_dt = None + if args.to: + to_dt = datetime.strptime(args.to, '%Y-%m-%d') + to_dt = to_dt.replace(hour=23, minute=59, second=59) + + lstmsg = self._linstor.error_report_list(nodes=args.nodes, since=since_dt, to=to_dt, ids=args.report_id) + return self.output_list(args, lstmsg, self.show_error_report_list, single_item=False) + + def show_error_report(self, args, lstmsg): + for error in lstmsg: + print(Output.utf8(error.text)) + + def cmd_error_report(self, args): + lstmsg = self._linstor.error_report_list(with_content=True, ids=args.report_id) + return self.output_list(args, lstmsg, self.show_error_report, single_item=False) + + @classmethod + def fill_str_part(cls, fill_str, default_str): + """ + Fill fill_str with missing parts from default_str. + + :param fill_str: + :param default_str: + :return: + """ + return fill_str + default_str[len(fill_str):] + + def cmd_del_error_report(self, args): + since_dt = None + to_dt = None + + dt_format = '%Y-%m-%d %H:%M:%S' + def_dt_str = '0000-00-00 23:59:59' + + if args.since: + since_str = self.fill_str_part(args.since, def_dt_str) + since_dt = datetime.strptime(since_str, dt_format) + + if args.to: + to_str = self.fill_str_part(args.to, def_dt_str) + to_dt = datetime.strptime(to_str, dt_format) + + replies = self.get_linstorapi().error_report_delete( + args.nodes, + since=since_dt, + to=to_dt, + exception=args.exception, + version=None, + ids=args.id + ) + return self.handle_replies(args, replies) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/migrate_cmds.py new/linstor-client-1.6.1/linstor_client/commands/migrate_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/migrate_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/migrate_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -206,8 +206,6 @@ '--minor', str(vol['minor']), r, str(vol['_size_kiB'])+'K') MigrateCommands.lsc(of, 'volume-definition', 'set-property', r, vnr_str, 'OverrideVlmId', bdname) - MigrateCommands.lsc(of, 'volume-definition', 'set-property', r, vnr_str, - 'AllowLargerVolumeSize', 'true') cgi = vol.get('props', {}).get('current-gi', None) if cgi is not None: MigrateCommands.lsc(of, 'volume-definition', 'set-property', r, vnr_str, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/node_cmds.py new/linstor-client-1.6.1/linstor_client/commands/node_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/node_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/node_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -70,7 +70,8 @@ Commands.Subcommands.SetProperty, Commands.Subcommands.ListProperties, Commands.Subcommands.Modify, - NodeCommands.Reconnect + NodeCommands.Reconnect, + Commands.Subcommands.Restore ] node_parser = parser.add_parser( @@ -108,16 +109,22 @@ apiconsts.DFLT_CTRL_PORT_SSL, apiconsts.VAL_NETCOM_TYPE_SSL)) ntype_def = apiconsts.VAL_NODE_TYPE_STLT - p_new_node.add_argument('--node-type', choices=node_types, - default=apiconsts.VAL_NODE_TYPE_STLT, help='Node type (default: %s)' % ntype_def) + p_new_node.add_argument('--node-type', choices=[x.lower() for x in node_types], + default=apiconsts.VAL_NODE_TYPE_STLT, + type=str.lower, + help='Node type (default: %s)' % ntype_def.lower()) ctype_def = apiconsts.VAL_NETCOM_TYPE_PLAIN p_new_node.add_argument('--communication-type', - choices=(apiconsts.VAL_NETCOM_TYPE_PLAIN, apiconsts.VAL_NETCOM_TYPE_SSL), + choices=(apiconsts.VAL_NETCOM_TYPE_PLAIN.lower(), + apiconsts.VAL_NETCOM_TYPE_SSL.lower()), default=ctype_def, - help='Communication type (default: %s)' % ctype_def) + type=str.lower, + help='Communication type (default: %s)' % ctype_def.lower()) itype_def = apiconsts.VAL_NETIF_TYPE_IP - p_new_node.add_argument('--interface-type', choices=(apiconsts.VAL_NETIF_TYPE_IP,), default=itype_def, - help='Interface type (default: %s)' % itype_def) + p_new_node.add_argument('--interface-type', choices=(apiconsts.VAL_NETIF_TYPE_IP.lower(),), + type=str.lower, + default=itype_def, + help='Interface type (default: %s)' % itype_def.lower()) iname_def = 'default' p_new_node.add_argument('--interface-name', default=iname_def, help='Interface name (default: %s)' % iname_def) @@ -155,9 +162,10 @@ ) p_modify_node.add_argument( '--node-type', '-t', - choices=node_types, + choices=[x.lower() for x in node_types], + type=str.lower, default=apiconsts.VAL_NODE_TYPE_STLT, - help='Node type (default: %s)' % ntype_def + help='Node type (default: %s)' % ntype_def.lower() ) p_modify_node.add_argument( 'node_name', @@ -261,9 +269,10 @@ ) p_create_netinterface.add_argument( '--communication-type', - choices=(apiconsts.VAL_NETCOM_TYPE_PLAIN, apiconsts.VAL_NETCOM_TYPE_SSL), + choices=(apiconsts.VAL_NETCOM_TYPE_PLAIN.lower(), apiconsts.VAL_NETCOM_TYPE_SSL.lower()), + type=str.lower, default=ctype_def, - help='Communication type (default: %s)' % ctype_def + help='Communication type (default: %s)' % ctype_def.lower() ) p_create_netinterface.add_argument( '--active', @@ -290,9 +299,10 @@ ) p_mod_netif.add_argument( '--communication-type', - choices=(apiconsts.VAL_NETCOM_TYPE_PLAIN, apiconsts.VAL_NETCOM_TYPE_SSL), + choices=(apiconsts.VAL_NETCOM_TYPE_PLAIN.lower(), apiconsts.VAL_NETCOM_TYPE_SSL.lower()), + type=str.lower, default=ctype_def, - help='Communication type (default: %s)' % ctype_def + help='Communication type (default: %s)' % ctype_def.lower() ) p_mod_netif.add_argument( '--active', @@ -322,7 +332,7 @@ p_delete_netinterface.set_defaults(func=self.delete_netif) # list nodes - node_groupby = [x.name for x in self._node_headers] + node_groupby = [x.name.lower() for x in self._node_headers] node_group_completer = Commands.show_group_completer(node_groupby, "groupby") p_lnodes = node_subp.add_parser( @@ -331,7 +341,7 @@ description='Prints a list of all cluster nodes known to linstor. ' 'By default, the list is printed as a human readable table.') p_lnodes.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') - p_lnodes.add_argument('-g', '--groupby', nargs='+', + p_lnodes.add_argument('-g', '--groupby', nargs='+', type=str.lower, choices=node_groupby).completer = node_group_completer p_lnodes.add_argument('-n', '--nodes', nargs='+', type=str, help='Filter by list of nodes').completer = self.node_completer @@ -390,6 +400,19 @@ Commands.add_parser_keyvalue(p_setp, "node") p_setp.set_defaults(func=self.set_props) + # restore evicted node + p_restore_node = node_subp.add_parser( + Commands.Subcommands.Restore.LONG, + aliases=[Commands.Subcommands.Restore.SHORT], + formatter_class=argparse.RawTextHelpFormatter, + description="Restore an evicted node." + ) + p_restore_node.add_argument( + 'node_name', + help="Evicted node to restore" + ).completer = self.node_completer + p_restore_node.set_defaults(func=self.restore_node) + self.check_subcommands(interface_subp, netif_subcmds) self.check_subcommands(node_subp, subcmds) @@ -500,8 +523,15 @@ if net_if.is_active and net_if.stlt_port: active_ip = net_if.address + ":" + str(net_if.stlt_port) + " (" + net_if.stlt_encryption_type + ")" - aux_props = ["{k}={v}".format(k=k, v=v) for k, v in node.properties.items() if k.startswith(apiconsts.NAMESPC_AUXILIARY + '/')] - conn_stat = conn_stat_dict[node.connection_status] + aux_props = ["{k}={v}".format(k=k, v=v) + for k, v in node.properties.items() if k.startswith(apiconsts.NAMESPC_AUXILIARY + '/')] + + if apiconsts.FLAG_EVICTED in node.flags: + conn_stat = (apiconsts.FLAG_EVICTED, Color.RED) + elif apiconsts.FLAG_DELETE in node.flags: + conn_stat = (apiconsts.FLAG_DELETE, Color.RED) + else: + conn_stat = conn_stat_dict.get(node.connection_status) row = [node.name, node.type, active_ip] if args.show_aux_props: @@ -784,6 +814,9 @@ ) return self.handle_replies(args, replies) + def restore_node(self, args): + return self.handle_replies(args, self.get_linstorapi().node_restore(node_name=args.node_name)) + def create_netif(self, args): replies = self._linstor.netinterface_create( args.node_name, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/physical_storage_cmds.py new/linstor-client-1.6.1/linstor_client/commands/physical_storage_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/physical_storage_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/physical_storage_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -44,7 +44,10 @@ aliases=[Commands.Subcommands.CreateDevicePool.SHORT], description='Creates a LVM/ZFS(thin) pool with an optional VDO on the device' ) - p_create.add_argument('provider_kind', choices=["LVM", "LVMTHIN", "ZFS", "SPDK"], help='Provider kind') + p_create.add_argument('provider_kind', + choices=[x.lower() for x in ["LVM", "LVMTHIN", "ZFS", "SPDK"]], + type=str.lower, + help='Provider kind') p_create.add_argument('node_name', help="Node name").completer = self.node_completer p_create.add_argument('device_paths', nargs='+', help="List of full device paths to use") p_create.add_argument( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/rsc_cmds.py new/linstor-client-1.6.1/linstor_client/commands/rsc_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/rsc_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/rsc_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -141,7 +141,7 @@ help='Name of the resource to delete').completer = self.resource_completer p_rm_res.set_defaults(func=self.delete) - resgroupby = [x.name for x in ResourceCommands._resource_headers] + resgroupby = [x.name.lower() for x in ResourceCommands._resource_headers] res_group_completer = Commands.show_group_completer(resgroupby, "groupby") p_lreses = res_subp.add_parser( @@ -153,7 +153,8 @@ p_lreses.add_argument( '-g', '--groupby', nargs='+', - choices=resgroupby).completer = res_group_completer + choices=resgroupby, + type=str.lower).completer = res_group_completer p_lreses.add_argument( '-r', '--resources', nargs='+', @@ -263,14 +264,14 @@ Commands.Subcommands.ToggleDisk.LONG, aliases=[Commands.Subcommands.ToggleDisk.SHORT], description='Toggles a resource between diskless and having disks.') - p_toggle_disk_group_storage = p_toggle_disk.add_mutually_exclusive_group(required=True) + p_toggle_disk_group_storage = p_toggle_disk.add_mutually_exclusive_group(required=False) p_toggle_disk_group_storage.add_argument( '--storage-pool', '-s', type=str, help="Add disks to a diskless resource using this storage pool name" ).completer = self.storage_pool_dfn_completer p_toggle_disk_group_storage.add_argument( - '--default-storage-pool', '-dflt', + '--default-storage-pool', '--dflt', action='store_true', help="Add disks to a diskless resource using the storage pools determined from the properties of the " "objects to which the volumes belong" @@ -397,10 +398,12 @@ print("Error: --auto-place not allowed in state '{state.name}'".format(state=current_state)) return ExitCode.ILLEGAL_STATE + place_count, additional_place_count, diskless_type = self.parse_place_count_args(args) + # auto-place resource replies = self._linstor.resource_auto_place( args.resource_definition_name, - args.auto_place, + place_count, args.storage_pool, args.do_not_place_with, args.do_not_place_with_regex, @@ -411,7 +414,9 @@ diskless_on_remaining=self.parse_diskless_on_remaining(args), async_msg=async_flag, layer_list=args.layer_list, - provider_list=args.providers + provider_list=args.providers, + additional_place_count=additional_place_count, + diskless_type=diskless_type ) return self.handle_replies(args, replies) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/rsc_conn_cmds.py new/linstor-client-1.6.1/linstor_client/commands/rsc_conn_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/rsc_conn_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/rsc_conn_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -46,7 +46,7 @@ description=Commands.Subcommands.generate_desc(subcmds) ) - rescon_groubby = [x.name for x in ResourceConnectionCommands._headers] + rescon_groubby = [x.name.lower() for x in ResourceConnectionCommands._headers] res_group_completer = Commands.show_group_completer(rescon_groubby, "groupby") p_lresconn = subp.add_parser( @@ -59,7 +59,8 @@ p_lresconn.add_argument( '-g', '--groupby', nargs='+', - choices=rescon_groubby).completer = res_group_completer + choices=rescon_groubby, + type=str.lower).completer = res_group_completer p_lresconn.add_argument( 'resource_name', help="Resource name" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/rsc_dfn_cmds.py new/linstor-client-1.6.1/linstor_client/commands/rsc_dfn_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/rsc_dfn_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/rsc_dfn_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -79,6 +79,16 @@ 'resource_definition_name', help='Name of the resource definition to auto place' ) + p_auto_place.add_argument( + '--nvme-initiator', + action="store_true", + help='Mark this resource as initiator' + ) + p_auto_place.add_argument( + '--drbd-diskless', + action="store_true", + help='Mark this resource as drbd diskless' + ) p_auto_place.set_defaults(func=self.auto_place) # modify-resource definition @@ -116,7 +126,7 @@ help='Name of the resource to delete').completer = self.resource_dfn_completer p_rm_res_dfn.set_defaults(func=self.delete) - rsc_dfn_groupby = [x.name for x in self._rsc_dfn_headers] + rsc_dfn_groupby = [x.name.lower() for x in self._rsc_dfn_headers] rsc_dfn_group_completer = Commands.show_group_completer(rsc_dfn_groupby, "groupby") p_lrscdfs = res_def_subp.add_parser( @@ -126,7 +136,8 @@ 'linstor. By default, the list is printed as a human readable table.') p_lrscdfs.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') p_lrscdfs.add_argument('-g', '--groupby', nargs='+', - choices=rsc_dfn_groupby).completer = rsc_dfn_group_completer + choices=rsc_dfn_groupby, + type=str.lower).completer = rsc_dfn_group_completer p_lrscdfs.add_argument('-r', '--resource-definitions', nargs='+', type=str, help='Filter by list of resource definitions').completer = self.resource_dfn_completer p_lrscdfs.add_argument('-e', '--external-name', action="store_true", help='Show user specified name.') @@ -185,9 +196,12 @@ return self.handle_replies(args, replies) def auto_place(self, args): + + place_count, additional_place_count, diskless_type = self.parse_place_count_args(args, use_place_count=True) + replies = self.get_linstorapi().resource_auto_place( rsc_name=args.resource_definition_name, - place_count=args.place_count, + place_count=place_count, storage_pool=args.storage_pool, do_not_place_with=args.do_not_place_with, do_not_place_with_regex=args.do_not_place_with_regex, @@ -196,7 +210,9 @@ args.replicas_on_different, linstor.consts.NAMESPC_AUXILIARY + '/'), diskless_on_remaining=self.parse_diskless_on_remaining(args), layer_list=args.layer_list, - provider_list=args.providers) + provider_list=args.providers, + additional_place_count=additional_place_count, + diskless_type=diskless_type) return self.handle_replies(args, replies) def modify(self, args): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/rsc_grp_cmds.py new/linstor-client-1.6.1/linstor_client/commands/rsc_grp_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/rsc_grp_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/rsc_grp_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -89,7 +89,7 @@ # ------------ DELETE END # ------------ LIST START - rsc_grp_groupby = [x.name for x in self._rsc_grp_headers] + rsc_grp_groupby = [x.name.lower() for x in self._rsc_grp_headers] rsc_grp_group_completer = Commands.show_group_completer(rsc_grp_groupby, "groupby") p_lrscgrps = res_grp_subp.add_parser( @@ -99,7 +99,8 @@ 'linstor. By default, the list is printed as a human readable table.') p_lrscgrps.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') p_lrscgrps.add_argument('-g', '--groupby', nargs='+', - choices=rsc_grp_groupby).completer = rsc_grp_group_completer + choices=rsc_grp_groupby, + type=str.lower).completer = rsc_grp_group_completer p_lrscgrps.add_argument('-r', '--resource-groups', nargs='+', type=str, help='Filter by list of resource groups').completer = self.resource_grp_completer p_lrscgrps.add_argument('--props', nargs='+', type=str, help='Filter list by object properties') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/snapshot_cmds.py new/linstor-client-1.6.1/linstor_client/commands/snapshot_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/snapshot_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/snapshot_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -131,8 +131,8 @@ p_ship_list.add_argument( '--status', nargs='+', - choices=[x.value for x in consts.SnapshotShipStatus], - type=str, + choices=[x.value.lower() for x in consts.SnapshotShipStatus], + type=str.lower, help='Filter by list of statuses').completer = self.node_completer p_ship_list.set_defaults(func=self.shiplist) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/storpool_cmds.py new/linstor-client-1.6.1/linstor_client/commands/storpool_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/storpool_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/storpool_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -254,7 +254,7 @@ p_rm_storpool.set_defaults(func=self.delete) # list storpool - storpoolgroupby = [x.name for x in self._stor_pool_headers] + storpoolgroupby = [x.name.lower() for x in self._stor_pool_headers] storpool_group_completer = Commands.show_group_completer(storpoolgroupby, "groupby") p_lstorpool = sp_subp.add_parser( @@ -264,7 +264,8 @@ 'linstor. By default, the list is printed as a human readable table.') p_lstorpool.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') p_lstorpool.add_argument('-g', '--groupby', nargs='+', - choices=storpoolgroupby).completer = storpool_group_completer + choices=storpoolgroupby, + type=str.lower).completer = storpool_group_completer p_lstorpool.add_argument('-s', '--storage-pools', nargs='+', type=str, help='Filter by list of storage pools').completer = self.storage_pool_completer p_lstorpool.add_argument('-n', '--nodes', nargs='+', type=str, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/vlm_dfn_cmds.py new/linstor-client-1.6.1/linstor_client/commands/vlm_dfn_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/vlm_dfn_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/vlm_dfn_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -110,7 +110,7 @@ p_rm_vol.set_defaults(func=self.delete) # list volume definitions - vlm_dfn_groupby = [x.name for x in self._vlm_dfn_headers] + vlm_dfn_groupby = [x.name.lower() for x in self._vlm_dfn_headers] vlm_dfn_group_completer = Commands.show_group_completer(vlm_dfn_groupby, "groupby") p_lvols = vol_def_subp.add_parser( @@ -120,7 +120,8 @@ 'By default, the list is printed as a human readable table.') p_lvols.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') p_lvols.add_argument('-g', '--groupby', nargs='+', - choices=vlm_dfn_groupby).completer = vlm_dfn_group_completer + choices=vlm_dfn_groupby, + type=str.lower).completer = vlm_dfn_group_completer p_lvols.add_argument('-r', '--resource-definitions', nargs='+', type=str, help='Filter by list of resource definitions').completer = self.resource_dfn_completer p_lvols.add_argument('-e', '--external-name', action="store_true", help='Show user specified name.') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/commands/vlm_grp_cmds.py new/linstor-client-1.6.1/linstor_client/commands/vlm_grp_cmds.py --- old/linstor-client-1.3.0/linstor_client/commands/vlm_grp_cmds.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/commands/vlm_grp_cmds.py 2021-01-13 10:56:42.000000000 +0100 @@ -68,7 +68,7 @@ # ------------ DELETE END # ------------ LIST START - vlm_grp_groupby = [x.name for x in self._vlm_grp_headers] + vlm_grp_groupby = [x.name.lower() for x in self._vlm_grp_headers] vlm_grp_group_completer = Commands.show_group_completer(vlm_grp_groupby, "groupby") p_lvlmgrps = vlm_grp_subp.add_parser( @@ -78,7 +78,8 @@ 'linstor. By default, the list is printed as a human readable table.') p_lvlmgrps.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output') p_lvlmgrps.add_argument('-g', '--groupby', nargs='+', - choices=vlm_grp_groupby).completer = vlm_grp_group_completer + choices=vlm_grp_groupby, + type=str.lower).completer = vlm_grp_group_completer p_lvlmgrps.add_argument('-R', '--resources', nargs='+', type=str, help='Filter by list of resource groups').completer = self.resource_grp_completer p_lvlmgrps.add_argument('name', help="Resource group name.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/consts.py new/linstor-client-1.6.1/linstor_client/consts.py --- old/linstor-client-1.3.0/linstor_client/consts.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/consts.py 2021-01-13 10:56:42.000000000 +0100 @@ -21,7 +21,7 @@ Global constants for linstor """ -VERSION = "1.3.0" +VERSION = "1.6.1" try: from linstor.consts_githash import GITHASH diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/consts_githash.py new/linstor-client-1.6.1/linstor_client/consts_githash.py --- old/linstor-client-1.3.0/linstor_client/consts_githash.py 2020-08-17 15:41:57.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/consts_githash.py 2021-01-13 10:56:46.000000000 +0100 @@ -1 +1 @@ -GITHASH = 'GIT-hash: 32bff01ed9ef35dd1e333974eb6921c0d3a9366e' +GITHASH = 'GIT-hash: fb64eb21c1a48feaa9c7b3a5c8e1b2c670e63e26' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/table.py new/linstor-client-1.6.1/linstor_client/table.py --- old/linstor-client-1.3.0/linstor_client/table.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/table.py 2021-01-13 10:56:42.000000000 +0100 @@ -286,7 +286,8 @@ hdrnames = [h['name'] for h in self.header] if self.groups and self.table: - group_bys = [hdrnames.index(g) for g in self.groups if g in hdrnames] + low_hdrnames = [h.lower() for h in hdrnames] + group_bys = [low_hdrnames.index(g.lower()) for g in self.groups if g.lower() in low_hdrnames] for row in self.table: for idx in group_bys: try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client/utils.py new/linstor-client-1.6.1/linstor_client/utils.py --- old/linstor-client-1.3.0/linstor_client/utils.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client/utils.py 2021-01-13 10:56:42.000000000 +0100 @@ -149,10 +149,9 @@ # "type" used for argparse def rangecheck(i, j): def range(v): - import linstor_client.argparse.argparse as argparse v = int(v) if not checkrange(v, i, j): - raise argparse.ArgumentTypeError('%d not in range: [%d, %d]' % (v, i, j)) + raise LinstorClientError('%d not in range: [%d, %d]' % (v, i, j), exit_code=2) return v return range diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client.egg-info/PKG-INFO new/linstor-client-1.6.1/linstor_client.egg-info/PKG-INFO --- old/linstor-client-1.3.0/linstor_client.egg-info/PKG-INFO 2020-08-17 15:42:00.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client.egg-info/PKG-INFO 2021-01-13 10:56:46.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: linstor-client -Version: 1.3.0 +Version: 1.6.1 Summary: DRBD distributed resource management utility Home-page: https://www.linbit.com Author: Robert Altnoeder <robert.altnoe...@linbit.com>, Roland Kammerer <roland.kamme...@linbit.com>, Rene Peinthor <rene.peint...@linbit.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client.egg-info/SOURCES.txt new/linstor-client-1.6.1/linstor_client.egg-info/SOURCES.txt --- old/linstor-client-1.3.0/linstor_client.egg-info/SOURCES.txt 2020-08-17 15:42:00.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client.egg-info/SOURCES.txt 2021-01-13 10:56:46.000000000 +0100 @@ -32,6 +32,7 @@ linstor_client/commands/controller_cmds.py linstor_client/commands/drbd_proxy_cmds.py linstor_client/commands/drbd_setup_cmds.py +linstor_client/commands/error_report_cmds.py linstor_client/commands/migrate_cmds.py linstor_client/commands/node_cmds.py linstor_client/commands/physical_storage_cmds.py @@ -45,29 +46,6 @@ linstor_client/commands/vlm_dfn_cmds.py linstor_client/commands/vlm_grp_cmds.py linstor_client/commands/zsh_completer.py -man-pages/linstor-controller.8.gz -man-pages/linstor-dm-migrate.8.gz -man-pages/linstor-drbd-proxy.8.gz -man-pages/linstor-encryption.8.gz -man-pages/linstor-error-reports.8.gz -man-pages/linstor-exit.8.gz -man-pages/linstor-gen-zsh-completer.8.gz -man-pages/linstor-help.8.gz -man-pages/linstor-interactive.8.gz -man-pages/linstor-list-commands.8.gz -man-pages/linstor-node.8.gz -man-pages/linstor-physical-storage.8.gz -man-pages/linstor-resource-connection.8.gz -man-pages/linstor-resource-definition.8.gz -man-pages/linstor-resource-group.8.gz -man-pages/linstor-resource.8.gz -man-pages/linstor-snapshot.8.gz -man-pages/linstor-sos-report.8.gz -man-pages/linstor-storage-pool.8.gz -man-pages/linstor-volume-definition.8.gz -man-pages/linstor-volume-group.8.gz -man-pages/linstor-volume.8.gz -man-pages/linstor.8.gz man-pages/linstor.xml man-pages/linstor_header.xml man-pages/linstor_trailer.xml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client.egg-info/requires.txt new/linstor-client-1.6.1/linstor_client.egg-info/requires.txt --- old/linstor-client-1.3.0/linstor_client.egg-info/requires.txt 2020-08-17 15:42:00.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client.egg-info/requires.txt 2021-01-13 10:56:46.000000000 +0100 @@ -1 +1 @@ -python-linstor>=1.3.0 +python-linstor>=1.6.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/linstor_client_main.py new/linstor-client-1.6.1/linstor_client_main.py --- old/linstor-client-1.3.0/linstor_client_main.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/linstor_client_main.py 2021-01-13 10:56:42.000000000 +0100 @@ -43,6 +43,7 @@ DrbdProxyCommands, MigrateCommands, PhysicalStorageCommands, + ErrorReportCommands, ZshGenerator, MiscCommands, Commands, @@ -110,6 +111,7 @@ self._drbd_proxy_commands = DrbdProxyCommands() self._misc_commands = MiscCommands() self._physical_storage_commands = PhysicalStorageCommands() + self._error_report_commands = ErrorReportCommands() self._zsh_generator = None self._parser = self.setup_parser() self._all_commands = self.parser_cmds(self._parser) @@ -223,6 +225,8 @@ self._physical_storage_commands.setup_commands(subp) + self._error_report_commands.setup_commands(subp) + # misc commands self._misc_commands.setup_commands(subp) @@ -258,7 +262,19 @@ pargs.insert(1, val) return pargs + @staticmethod + def merge_environ_arguments(pargs): + for key, val in os.environ.items(): + if key.startswith("LS_CLIENT_"): + arg = key[10:].lower().replace("_", "-") + pargs.insert(0, "--" + arg) + if val: + pargs.insert(1, val) + return pargs + def parse(self, pargs): + # read global environment options + pargs = LinStorCLI.merge_environ_arguments(pargs) # read global options from config file if '--disable-config' not in pargs: pargs = LinStorCLI.merge_config_arguments(pargs) @@ -328,6 +344,7 @@ self._drbd_proxy_commands._linstor = self._linstorapi self._misc_commands._linstor = self._linstorapi self._physical_storage_commands._linstor = self._linstorapi + self._error_report_commands._linstor = self._linstorapi self._linstorapi.connect() break except linstor.LinstorNetworkError as le: @@ -364,6 +381,8 @@ except linstor.LinstorTimeoutError as le: self._report_linstor_error(le) rc = ExitCode.CONNECTION_TIMEOUT + self._linstorapi.disconnect() + self._linstorapi = None # should trigger reconnect in interactive mode except linstor.LinstorError as le: self._report_linstor_error(le) rc = ExitCode.UNKNOWN_ERROR Binary files old/linstor-client-1.3.0/man-pages/linstor-controller.8.gz and new/linstor-client-1.6.1/man-pages/linstor-controller.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-dm-migrate.8.gz and new/linstor-client-1.6.1/man-pages/linstor-dm-migrate.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-drbd-proxy.8.gz and new/linstor-client-1.6.1/man-pages/linstor-drbd-proxy.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-encryption.8.gz and new/linstor-client-1.6.1/man-pages/linstor-encryption.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-error-reports.8.gz and new/linstor-client-1.6.1/man-pages/linstor-error-reports.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-exit.8.gz and new/linstor-client-1.6.1/man-pages/linstor-exit.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-gen-zsh-completer.8.gz and new/linstor-client-1.6.1/man-pages/linstor-gen-zsh-completer.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-help.8.gz and new/linstor-client-1.6.1/man-pages/linstor-help.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-interactive.8.gz and new/linstor-client-1.6.1/man-pages/linstor-interactive.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-list-commands.8.gz and new/linstor-client-1.6.1/man-pages/linstor-list-commands.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-node.8.gz and new/linstor-client-1.6.1/man-pages/linstor-node.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-physical-storage.8.gz and new/linstor-client-1.6.1/man-pages/linstor-physical-storage.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-resource-connection.8.gz and new/linstor-client-1.6.1/man-pages/linstor-resource-connection.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-resource-definition.8.gz and new/linstor-client-1.6.1/man-pages/linstor-resource-definition.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-resource-group.8.gz and new/linstor-client-1.6.1/man-pages/linstor-resource-group.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-resource.8.gz and new/linstor-client-1.6.1/man-pages/linstor-resource.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-snapshot.8.gz and new/linstor-client-1.6.1/man-pages/linstor-snapshot.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-sos-report.8.gz and new/linstor-client-1.6.1/man-pages/linstor-sos-report.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-storage-pool.8.gz and new/linstor-client-1.6.1/man-pages/linstor-storage-pool.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-volume-definition.8.gz and new/linstor-client-1.6.1/man-pages/linstor-volume-definition.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-volume-group.8.gz and new/linstor-client-1.6.1/man-pages/linstor-volume-group.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor-volume.8.gz and new/linstor-client-1.6.1/man-pages/linstor-volume.8.gz differ Binary files old/linstor-client-1.3.0/man-pages/linstor.8.gz and new/linstor-client-1.6.1/man-pages/linstor.8.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/man-pages/linstor.xml new/linstor-client-1.6.1/man-pages/linstor.xml --- old/linstor-client-1.3.0/man-pages/linstor.xml 2020-08-17 15:41:57.000000000 +0200 +++ new/linstor-client-1.6.1/man-pages/linstor.xml 2021-01-13 10:56:43.000000000 +0100 @@ -396,6 +396,24 @@ <varlistentry> <term> <command moreinfo="none">linstor</command> + <arg choice="plain" rep="norepeat">space-reporting + </arg> + </term> + <listitem> + <para> + Space reporting subcommands + </para> + <para>For furter information see + <citerefentry> + <refentrytitle>linstor-space-reporting</refentrytitle> + <manvolnum>8</manvolnum></citerefentry> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command moreinfo="none">linstor</command> <arg choice="plain" rep="norepeat">storage-pool </arg> </term> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/setup.cfg new/linstor-client-1.6.1/setup.cfg --- old/linstor-client-1.3.0/setup.cfg 2020-08-17 15:42:00.463261600 +0200 +++ new/linstor-client-1.6.1/setup.cfg 2021-01-13 10:56:46.487815000 +0100 @@ -6,7 +6,7 @@ build-requires = python3-setuptools requires = - python-linstor >= 1.3.0 + python-linstor >= 1.6.0 [egg_info] tag_build = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/setup.cfg.py2 new/linstor-client-1.6.1/setup.cfg.py2 --- old/linstor-client-1.3.0/setup.cfg.py2 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/setup.cfg.py2 2021-01-13 10:56:42.000000000 +0100 @@ -6,4 +6,4 @@ build-requires = python2-setuptools requires = - python-linstor >= 1.3.0 + python-linstor >= 1.6.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/linstor-client-1.3.0/setup.py new/linstor-client-1.6.1/setup.py --- old/linstor-client-1.3.0/setup.py 2020-08-17 15:29:15.000000000 +0200 +++ new/linstor-client-1.6.1/setup.py 2021-01-13 10:56:42.000000000 +0100 @@ -197,7 +197,7 @@ "linstor_client.commands" ], install_requires=[ - "python-linstor>=1.3.0" + "python-linstor>=1.6.0" ], py_modules=["linstor_client_main"], scripts=["scripts/linstor"],