Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,22 @@ Improvements

Contributed by @cognifloyd.

* Update majority of the "resource get" CLI commands (e.g. ``st2 execution get``,
``st2 action get``, ``st2 rule get``, ``st2 pack get``, ``st2 apikey get``, ``st2 trace get``,
``st2 key get``, ``st2 webhook get``, ``st2 timer get``, etc.) so they allow for retrieval
and printing of information for multiple resources using the following notation:
``st2 <resource> get <id 1> <id 2> <id n>``, e.g. ``st2 action.get pack.show packs.get
packs.delete``

This change is fully backward compatible when retrieving only a single resource (aka single
id is passed to the command).

When retrieving a single source the command will throw and exit with non-zero if a resource is
not found, but when retrieving multiple resources, command will just print an error and
continue with printing the details of any other found resources. (new feature) #4912

Contributed by @Kami.

Fixed
~~~~~

Expand Down
4 changes: 1 addition & 3 deletions st2actions/st2actions/notifier/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
from st2common.constants.system import VERSION_STRING
from st2common.constants.system import DEFAULT_CONFIG_FILE_PATH

common_config.register_opts()

CONF = cfg.CONF


Expand All @@ -44,7 +42,7 @@ def get_logging_config_path():


def _register_common_opts(ignore_errors=False):
common_config.register_opts()
common_config.register_opts(ignore_errors=ignore_errors)


def _register_notifier_opts(ignore_errors=False):
Expand Down
21 changes: 12 additions & 9 deletions st2client/st2client/commands/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -1473,6 +1473,7 @@ class ActionExecutionGetCommand(ActionRunCommandMixin, ResourceViewCommand):
"end_timestamp",
"log",
]
pk_argument_name = "id"

def __init__(self, resource, *args, **kwargs):
super(ActionExecutionGetCommand, self).__init__(
Expand All @@ -1484,7 +1485,9 @@ def __init__(self, resource, *args, **kwargs):
)

self.parser.add_argument(
"id", help=("ID of the %s." % resource.get_display_name().lower())
"id",
nargs="+",
help=("ID of the %s." % resource.get_display_name().lower()),
)
self.parser.add_argument(
"-x",
Expand All @@ -1510,21 +1513,21 @@ def run(self, args, **kwargs):
if args.exclude_result:
kwargs["params"] = {"exclude_attributes": "result"}

execution = self.get_resource_by_id(id=args.id, **kwargs)
return execution
resource_ids = getattr(args, self.pk_argument_name, None)
resources = self._get_multiple_resources(
resource_ids=resource_ids, kwargs=kwargs
)
return resources

@add_auth_token_to_kwargs_from_cli
def run_and_print(self, args, **kwargs):
try:
execution = self.run(args, **kwargs)
executions = self.run(args, **kwargs)

for execution in executions:
if not args.json and not args.yaml:
# Include elapsed time for running executions
execution = format_execution_status(execution)
except resource.ResourceNotFoundError:
self.print_not_found(args.id)
raise ResourceNotFoundError("Execution with id %s not found." % (args.id))
return self._print_execution_details(execution=execution, args=args, **kwargs)
self._print_execution_details(execution=execution, args=args, **kwargs)


class ActionExecutionCancelCommand(resource.ResourceCommand):
Expand Down
5 changes: 0 additions & 5 deletions st2client/st2client/commands/inquiry.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,6 @@ class InquiryGetCommand(resource.ResourceGetCommand):
def __init__(self, kv_resource, *args, **kwargs):
super(InquiryGetCommand, self).__init__(kv_resource, *args, **kwargs)

@resource.add_auth_token_to_kwargs_from_cli
def run(self, args, **kwargs):
resource_name = getattr(args, self.pk_argument_name, None)
return self.get_resource_by_id(id=resource_name, **kwargs)


class InquiryRespondCommand(resource.ResourceCommand):
display_attributes = ["id", "response"]
Expand Down
8 changes: 6 additions & 2 deletions st2client/st2client/commands/keyvalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,16 @@ def __init__(self, kv_resource, *args, **kwargs):

@resource.add_auth_token_to_kwargs_from_cli
def run(self, args, **kwargs):
resource_name = getattr(args, self.pk_argument_name, None)
decrypt = getattr(args, "decrypt", False)
scope = getattr(args, "scope", DEFAULT_GET_SCOPE)
kwargs["params"] = {"decrypt": str(decrypt).lower()}
kwargs["params"]["scope"] = scope
return self.get_resource_by_id(id=resource_name, **kwargs)

resource_ids = getattr(args, self.pk_argument_name, None)
resources = self._get_multiple_resources(
resource_ids=resource_ids, kwargs=kwargs
)
return resources


class KeyValuePairSetCommand(resource.ResourceCommand):
Expand Down
51 changes: 42 additions & 9 deletions st2client/st2client/commands/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@

from __future__ import absolute_import

from typing import List
from typing import Any
from typing import Dict

import os
import abc
import six
Expand Down Expand Up @@ -238,6 +242,35 @@ def get_resource_by_ref_or_id(self, ref_or_id, **kwargs):
raise ResourceNotFoundError(message)
return instance

def _get_multiple_resources(
self, resource_ids: List[str], kwargs: Dict[str, Any]
) -> List[Any]:
"""
Return multiple resource instances for the provided resource ids.
If a resource is not found, an error is printed. This method only throws when operating on
a single resource.
:param resource_ids: A list of resources to retrieve instances for.
:param kwargs: Dictionary with keyword arguments which are passed to get_resource_by_id.
"""
more_than_one_resource = len(resource_ids) > 1

resources = []
for resource_id in resource_ids:
try:
resource = self.get_resource_by_id(resource_id, **kwargs)
except ResourceNotFoundError:
self.print_not_found(resource_id)

if not more_than_one_resource:
# For backward compatibility reasons and to comply with common "get one"
# behavior, we only fail if a single source is requested
raise ResourceNotFoundError("Resource %s not found." % resource_id)

continue

resources.append(resource)
return resources

@abc.abstractmethod
def run(self, args, **kwargs):
raise NotImplementedError
Expand Down Expand Up @@ -421,7 +454,7 @@ def __init__(self, resource, *args, **kwargs):
resource=resource, argument=self.pk_argument_name
)

self.parser.add_argument(argument, metavar=metavar, help=help)
self.parser.add_argument(argument, metavar=metavar, nargs="+", help=help)
self.parser.add_argument(
"-a",
"--attr",
Expand All @@ -436,12 +469,16 @@ def __init__(self, resource, *args, **kwargs):

@add_auth_token_to_kwargs_from_cli
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
return self.get_resource_by_id(resource_id, **kwargs)
resource_ids = getattr(args, self.pk_argument_name, None)
resources = self._get_multiple_resources(
resource_ids=resource_ids, kwargs=kwargs
)
return resources

def run_and_print(self, args, **kwargs):
try:
instance = self.run(args, **kwargs)
instances = self.run(args, **kwargs)

for instance in instances:
self.print_output(
instance,
table.PropertyValueTable,
Expand All @@ -450,10 +487,6 @@ def run_and_print(self, args, **kwargs):
yaml=args.yaml,
attribute_display_order=self.attribute_display_order,
)
except ResourceNotFoundError:
resource_id = getattr(args, self.pk_argument_name, None)
self.print_not_found(resource_id)
raise OperationFailureException("Resource %s not found." % resource_id)


class ContentPackResourceGetCommand(ResourceGetCommand):
Expand Down
5 changes: 0 additions & 5 deletions st2client/st2client/commands/rule_enforcement.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ class RuleEnforcementGetCommand(resource.ResourceGetCommand):

pk_argument_name = "id"

@resource.add_auth_token_to_kwargs_from_cli
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
return self.get_resource_by_id(resource_id, **kwargs)


class RuleEnforcementListCommand(resource.ResourceCommand):
display_attributes = [
Expand Down
27 changes: 13 additions & 14 deletions st2client/st2client/commands/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from __future__ import absolute_import

from st2client.models import Resource, Trace, TriggerInstance, Rule, Execution
from st2client.exceptions.operations import OperationFailureException
from st2client.formatters import table
from st2client.formatters import execution as execution_formatter
from st2client.commands import resource
Expand Down Expand Up @@ -327,22 +326,22 @@ def __init__(self, resource, *args, **kwargs):

@resource.add_auth_token_to_kwargs_from_cli
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
return self.get_resource_by_id(resource_id, **kwargs)
resource_ids = getattr(args, self.pk_argument_name, None)
resources = self._get_multiple_resources(
resource_ids=resource_ids, kwargs=kwargs
)
return resources

@resource.add_auth_token_to_kwargs_from_cli
def run_and_print(self, args, **kwargs):
trace = None
try:
trace = self.run(args, **kwargs)
except resource.ResourceNotFoundError:
self.print_not_found(args.id)
raise OperationFailureException("Trace %s not found." % (args.id))
# First filter for causation chains
trace = self._filter_trace_components(trace=trace, args=args)
# next filter for display purposes
trace = self._apply_display_filters(trace=trace, args=args)
return self.print_trace_details(trace=trace, args=args)
traces = self.run(args, **kwargs)

for trace in traces:
# First filter for causation chains
trace = self._filter_trace_components(trace=trace, args=args)
# next filter for display purposes
trace = self._apply_display_filters(trace=trace, args=args)
self.print_trace_details(trace=trace, args=args)

@staticmethod
def _filter_trace_components(trace, args):
Expand Down
5 changes: 0 additions & 5 deletions st2client/st2client/commands/triggerinstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,3 @@ class TriggerInstanceGetCommand(resource.ResourceGetCommand):
attribute_display_order = ["id", "trigger", "occurrence_time", "payload"]

pk_argument_name = "id"

@resource.add_auth_token_to_kwargs_from_cli
def run(self, args, **kwargs):
resource_id = getattr(args, self.pk_argument_name, None)
return self.get_resource_by_id(resource_id, **kwargs)
2 changes: 1 addition & 1 deletion st2client/st2client/models/reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class TriggerType(core.Resource):

class TriggerInstance(core.Resource):
_alias = "Trigger-Instance"
_display_name = "TriggerInstance"
_display_name = "Trigger Instance"
_plural = "Triggerinstances"
_plural_display_name = "TriggerInstances"
_repr_attributes = ["id", "trigger", "occurrence_time", "payload", "status"]
Expand Down
2 changes: 1 addition & 1 deletion st2client/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def tearDown(self):

print("")
print("Captured stdout: %s" % (stdout))
print("Captured stdoerr: %s" % (stderr))
print("Captured stderr: %s" % (stderr))
print("")

def _reset_output_streams(self):
Expand Down
Loading