Merge "Adds a --json flag to request JSON output"
This commit is contained in:
@@ -14,15 +14,18 @@
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import pprint
|
||||
|
||||
from solumclient import client as solum_client
|
||||
from solumclient.common import exc
|
||||
from solumclient.openstack.common import cliutils
|
||||
|
||||
|
||||
class CommandsBase(object):
|
||||
"""Base command parsing class."""
|
||||
parser = None
|
||||
solum = None
|
||||
json_output = False
|
||||
|
||||
def __init__(self, parser):
|
||||
self.parser = parser
|
||||
@@ -130,7 +133,44 @@ class CommandsBase(object):
|
||||
def _get_global_flags(self):
|
||||
"""Get global flags."""
|
||||
# Good location to add_argument() global options like --verbose
|
||||
pass
|
||||
self.parser.add_argument('--json',
|
||||
action='store_true',
|
||||
help='JSON formatted output')
|
||||
|
||||
args, _ = self.parser.parse_known_args()
|
||||
if args.json:
|
||||
self.json_output = True
|
||||
|
||||
def _sanitized_fields(self, fields):
|
||||
def allowed(field):
|
||||
if field.startswith('_'):
|
||||
return False
|
||||
if field == 'manager':
|
||||
return False
|
||||
if field == 'artifacts':
|
||||
return False
|
||||
return True
|
||||
return [f for f in fields
|
||||
if allowed(f)]
|
||||
|
||||
def _print_dict(self, obj, fields, dict_property="Property", wrap=0):
|
||||
fields = self._sanitized_fields(fields)
|
||||
subset = dict([(f, getattr(obj, f, '')) for f in fields])
|
||||
if self.json_output:
|
||||
pprint.pprint(subset, width=wrap)
|
||||
else:
|
||||
cliutils.print_dict(subset, dict_property, wrap)
|
||||
|
||||
def _print_list(self, objs, fields, formatters=None, sortby_index=0,
|
||||
mixed_case_fields=None, field_labels=None):
|
||||
fields = self._sanitized_fields(fields)
|
||||
if self.json_output:
|
||||
subsets = [dict([(f, getattr(obj, f, '')) for f in fields])
|
||||
for obj in objs]
|
||||
pprint.pprint(subsets)
|
||||
else:
|
||||
cliutils.print_list(objs, fields, formatters, sortby_index,
|
||||
mixed_case_fields, field_labels)
|
||||
|
||||
|
||||
def env(*vars, **kwargs):
|
||||
|
@@ -50,7 +50,6 @@ from solumclient.common import exc
|
||||
from solumclient.common import github
|
||||
from solumclient.common import yamlutils
|
||||
from solumclient.openstack.common.apiclient import exceptions
|
||||
from solumclient.openstack.common import cliutils
|
||||
from solumclient.v1 import assembly as cli_assem
|
||||
from solumclient.v1 import languagepack as cli_lp
|
||||
from solumclient.v1 import pipeline as cli_pipe
|
||||
@@ -115,11 +114,8 @@ Available commands:
|
||||
raise exc.CommandError(message=message)
|
||||
plan = self.client.plans.create(yamlutils.dump(definition))
|
||||
fields = ['uuid', 'name', 'description', 'uri', 'artifacts']
|
||||
data = dict([(f, getattr(plan, f, ''))
|
||||
for f in fields])
|
||||
artifacts = copy.deepcopy(data['artifacts'])
|
||||
del data['artifacts']
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
artifacts = copy.deepcopy(vars(plan).get('artifacts'))
|
||||
self._print_dict(plan, fields, wrap=72)
|
||||
self._show_public_keys(artifacts)
|
||||
|
||||
def delete(self):
|
||||
@@ -138,20 +134,17 @@ Available commands:
|
||||
help="Plan uuid or name")
|
||||
self.parser._names['plan_uuid'] = 'plan'
|
||||
args = self.parser.parse_args()
|
||||
response = self.client.plans.find(name_or_id=args.plan_uuid)
|
||||
plan = self.client.plans.find(name_or_id=args.plan_uuid)
|
||||
fields = ['uuid', 'name', 'description', 'uri', 'artifacts']
|
||||
data = dict([(f, getattr(response, f, ''))
|
||||
for f in fields])
|
||||
artifacts = copy.deepcopy(data['artifacts'])
|
||||
del data['artifacts']
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
artifacts = copy.deepcopy(vars(plan).get('artifacts'))
|
||||
self._print_dict(plan, fields, wrap=72)
|
||||
self._show_public_keys(artifacts)
|
||||
|
||||
def list(self):
|
||||
"""List all plans."""
|
||||
fields = ['uuid', 'name', 'description']
|
||||
response = self.client.plans.list()
|
||||
cliutils.print_list(response, fields)
|
||||
plans = self.client.plans.list()
|
||||
self._print_list(plans, fields)
|
||||
|
||||
def _show_public_keys(self, artifacts):
|
||||
public_keys = {}
|
||||
@@ -220,9 +213,7 @@ Available commands:
|
||||
plan_uri=plan_uri)
|
||||
fields = ['uuid', 'name', 'description', 'status', 'application_uri',
|
||||
'trigger_uri']
|
||||
data = dict([(f, getattr(assembly, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(assembly, fields, wrap=72)
|
||||
|
||||
def delete(self):
|
||||
"""Delete an assembly."""
|
||||
@@ -238,8 +229,8 @@ Available commands:
|
||||
"""List all assemblies."""
|
||||
fields = ['uuid', 'name', 'description', 'status', 'created_at',
|
||||
'updated_at']
|
||||
response = self.client.assemblies.list()
|
||||
cliutils.print_list(response, fields, sortby_index=5)
|
||||
assemblies = self.client.assemblies.list()
|
||||
self._print_list(assemblies, fields, sortby_index=5)
|
||||
|
||||
def logs(self):
|
||||
"""Get Logs."""
|
||||
@@ -247,11 +238,11 @@ Available commands:
|
||||
help="Assembly uuid or name")
|
||||
args = self.parser.parse_args()
|
||||
assem = self.client.assemblies.find(name_or_id=args.assembly)
|
||||
response = cli_assem.AssemblyManager(self.client).logs(
|
||||
loglist = cli_assem.AssemblyManager(self.client).logs(
|
||||
assembly_id=str(assem.uuid))
|
||||
|
||||
fields = ["resource_uuid"]
|
||||
for log in response:
|
||||
for log in loglist:
|
||||
strategy_info = json.loads(log.strategy_info)
|
||||
if log.strategy == 'local':
|
||||
if 'local_storage' not in fields:
|
||||
@@ -268,7 +259,7 @@ Available commands:
|
||||
if 'location' not in fields:
|
||||
fields.append('location')
|
||||
|
||||
cliutils.print_list(response, fields)
|
||||
self._print_list(loglist, fields)
|
||||
|
||||
def show(self):
|
||||
"""Show an assembly's resource."""
|
||||
@@ -276,12 +267,10 @@ Available commands:
|
||||
help="Assembly uuid or name")
|
||||
self.parser._names['assembly_uuid'] = 'assembly'
|
||||
args = self.parser.parse_args()
|
||||
response = self.client.assemblies.find(name_or_id=args.assembly_uuid)
|
||||
assemblies = self.client.assemblies.find(name_or_id=args.assembly_uuid)
|
||||
fields = ['uuid', 'name', 'description', 'status', 'application_uri',
|
||||
'trigger_uri', 'created_at', 'updated_at']
|
||||
data = dict([(f, getattr(response, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(assemblies, fields, wrap=72)
|
||||
|
||||
|
||||
class ComponentCommands(cli_utils.CommandsBase):
|
||||
@@ -303,17 +292,15 @@ Available commands:
|
||||
help="Component uuid or name")
|
||||
self.parser._names['component_uuid'] = 'component'
|
||||
args = self.parser.parse_args()
|
||||
response = self.client.components.find(name_or_id=args.component_uuid)
|
||||
component = self.client.components.find(name_or_id=args.component_uuid)
|
||||
fields = ['uuid', 'name', 'description', 'uri', 'assembly_uuid']
|
||||
data = dict([(f, getattr(response, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(component, fields, wrap=72)
|
||||
|
||||
def list(self):
|
||||
"""List all components."""
|
||||
fields = ['uuid', 'name', 'description', 'assembly_uuid']
|
||||
response = self.client.components.list()
|
||||
cliutils.print_list(response, fields)
|
||||
components = self.client.components.list()
|
||||
self._print_list(components, fields)
|
||||
|
||||
|
||||
class PipelineCommands(cli_utils.CommandsBase):
|
||||
@@ -360,9 +347,7 @@ Available commands:
|
||||
workbook_name=args.workbook_name)
|
||||
fields = ['uuid', 'name', 'description',
|
||||
'trigger_uri']
|
||||
data = dict([(f, getattr(pipeline, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(pipeline, fields, wrap=72)
|
||||
|
||||
def delete(self):
|
||||
"""Delete an pipeline."""
|
||||
@@ -377,8 +362,8 @@ Available commands:
|
||||
def list(self):
|
||||
"""List all pipelines."""
|
||||
fields = ['uuid', 'name', 'description']
|
||||
response = self.client.pipelines.list()
|
||||
cliutils.print_list(response, fields)
|
||||
pipelines = self.client.pipelines.list()
|
||||
self._print_list(pipelines, fields)
|
||||
|
||||
def show(self):
|
||||
"""Show a pipeline's resource."""
|
||||
@@ -386,12 +371,10 @@ Available commands:
|
||||
help="Pipeline uuid or name")
|
||||
self.parser._names['pipeline_uuid'] = 'pipeline'
|
||||
args = self.parser.parse_args()
|
||||
response = self.client.pipelines.find(name_or_id=args.pipeline_uuid)
|
||||
pipelines = self.client.pipelines.find(name_or_id=args.pipeline_uuid)
|
||||
fields = ['uuid', 'name', 'description',
|
||||
'trigger_uri', 'workbook_name', 'last_execution']
|
||||
data = dict([(f, getattr(response, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(pipelines, fields, wrap=72)
|
||||
|
||||
|
||||
class LanguagePackCommands(cli_utils.CommandsBase):
|
||||
@@ -435,8 +418,9 @@ Available commands:
|
||||
except ValueError as excp:
|
||||
message = ("Malformed metadata file: %s" % str(excp))
|
||||
raise exc.CommandError(message=message)
|
||||
languagepack = {}
|
||||
try:
|
||||
response = self.client.languagepacks.create(
|
||||
languagepack = self.client.languagepacks.create(
|
||||
name=args.name, source_uri=args.git_url,
|
||||
lp_metadata=lp_metadata)
|
||||
except exceptions.Conflict as conflict:
|
||||
@@ -444,9 +428,7 @@ Available commands:
|
||||
raise exc.CommandError(message=message)
|
||||
|
||||
fields = ['uuid', 'name', 'description', 'state']
|
||||
data = dict([(f, getattr(response, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(languagepack, fields, wrap=72)
|
||||
|
||||
def delete(self):
|
||||
"""Delete a language pack."""
|
||||
@@ -459,8 +441,8 @@ Available commands:
|
||||
def list(self):
|
||||
"""List all language packs."""
|
||||
fields = ['uuid', 'name', 'description', 'state', 'source_uri']
|
||||
response = self.client.languagepacks.list()
|
||||
cliutils.print_list(response, fields)
|
||||
languagepacks = self.client.languagepacks.list()
|
||||
self._print_list(languagepacks, fields)
|
||||
|
||||
def show(self):
|
||||
"""Get a language pack."""
|
||||
@@ -468,22 +450,20 @@ Available commands:
|
||||
help="Language pack id")
|
||||
self.parser._names['lp_id'] = 'languagepack'
|
||||
args = self.parser.parse_args()
|
||||
response = self.client.languagepacks.find(name_or_id=args.lp_id)
|
||||
languagepack = self.client.languagepacks.find(name_or_id=args.lp_id)
|
||||
fields = ['uuid', 'name', 'description', 'state', 'source_uri']
|
||||
data = dict([(f, getattr(response, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(languagepack, fields, wrap=72)
|
||||
|
||||
def logs(self):
|
||||
"""Get Logs."""
|
||||
self.parser.add_argument('lp_id',
|
||||
help="languagepack uuid or name")
|
||||
args = self.parser.parse_args()
|
||||
response = cli_lp.LanguagePackManager(self.client).logs(
|
||||
loglist = cli_lp.LanguagePackManager(self.client).logs(
|
||||
lp_id=str(args.lp_id))
|
||||
|
||||
fields = ["resource_uuid"]
|
||||
for log in response:
|
||||
for log in loglist:
|
||||
strategy_info = json.loads(log.strategy_info)
|
||||
if log.strategy == 'local':
|
||||
if 'local_storage' not in fields:
|
||||
@@ -500,7 +480,7 @@ Available commands:
|
||||
if 'location' not in fields:
|
||||
fields.append('location')
|
||||
|
||||
cliutils.print_list(response, fields)
|
||||
self._print_dict(loglist, fields, wrap=72)
|
||||
|
||||
|
||||
class AppCommands(cli_utils.CommandsBase):
|
||||
@@ -553,12 +533,12 @@ Available commands:
|
||||
|
||||
def list(self):
|
||||
"""Print a list of all deployed applications."""
|
||||
# This is just "app list".
|
||||
# This is just "plan list".
|
||||
# TODO(datsun180b): List each plan and its associated
|
||||
# assemblies.
|
||||
fields = ['uuid', 'name', 'description']
|
||||
response = self.client.plans.list()
|
||||
cliutils.print_list(response, fields)
|
||||
plans = self.client.plans.list()
|
||||
self._print_list(plans, fields, sortby_index=5)
|
||||
|
||||
def show(self):
|
||||
"""Print detailed information about one application."""
|
||||
@@ -586,14 +566,11 @@ Available commands:
|
||||
updated = a.updated_at
|
||||
app_uri = a.application_uri
|
||||
|
||||
plan.application_uri = app_uri
|
||||
fields = ['uuid', 'name', 'description', 'uri', 'artifacts',
|
||||
'trigger_uri']
|
||||
data = dict([(f, getattr(plan, f, ''))
|
||||
for f in fields])
|
||||
data['application_uri'] = app_uri
|
||||
artifacts = copy.deepcopy(data['artifacts'])
|
||||
del data['artifacts']
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
'trigger_uri', 'application_uri']
|
||||
self._print_dict(plan, fields, wrap=72)
|
||||
artifacts = copy.deepcopy(vars(plan).get('artifacts'))
|
||||
self._show_public_keys(artifacts)
|
||||
|
||||
def create(self):
|
||||
@@ -663,7 +640,7 @@ Available commands:
|
||||
langpacks = self.client.languagepacks.list()
|
||||
lpnames = [lp.name for lp in langpacks]
|
||||
fields = ['uuid', 'name', 'description', 'state', 'source_uri']
|
||||
cliutils.print_list(langpacks, fields)
|
||||
self._print_list(langpacks, fields)
|
||||
langpack = raw_input("Please choose a languagepack from the "
|
||||
"above list.\n> ")
|
||||
while langpack not in lpnames:
|
||||
@@ -727,11 +704,8 @@ Available commands:
|
||||
plan = self.client.plans.create(yamlutils.dump(plan_definition))
|
||||
fields = ['uuid', 'name', 'description', 'uri', 'artifacts',
|
||||
'trigger_uri']
|
||||
data = dict([(f, getattr(plan, f, ''))
|
||||
for f in fields])
|
||||
artifacts = copy.deepcopy(data['artifacts'])
|
||||
del data['artifacts']
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
artifacts = copy.deepcopy(plan['artifacts'])
|
||||
self._print_dict(plan, fields, wrap=72)
|
||||
self._show_public_keys(artifacts)
|
||||
|
||||
if artifacts and args.setup_triggers:
|
||||
@@ -760,9 +734,7 @@ Available commands:
|
||||
plan_uri=plan.uri)
|
||||
fields = ['uuid', 'name', 'description', 'status', 'application_uri',
|
||||
'trigger_uri']
|
||||
data = dict([(f, getattr(assembly, f, ''))
|
||||
for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
self._print_dict(assembly, fields, wrap=72)
|
||||
|
||||
def delete(self):
|
||||
"""Delete an application and all related artifacts."""
|
||||
|
@@ -36,7 +36,9 @@ class TestCli_Utils(base.TestCase):
|
||||
'os_tenant_name': 'tenant_name',
|
||||
'os_auth_url': 'http://no.where',
|
||||
'os_password': 'password',
|
||||
'action': 'create'})),
|
||||
'action': 'create',
|
||||
'json': False,
|
||||
})),
|
||||
('token', dict(
|
||||
fake_env={'OS_AUTH_TOKEN': '123456',
|
||||
'SOLUM_URL': 'http://10.0.2.15:9777'},
|
||||
@@ -46,7 +48,9 @@ class TestCli_Utils(base.TestCase):
|
||||
'os_username': '',
|
||||
'os_tenant_name': '',
|
||||
'os_password': '',
|
||||
'action': 'create'})),
|
||||
'action': 'create',
|
||||
'json': False,
|
||||
})),
|
||||
('solum_url_with_no_token', dict(
|
||||
fake_env={'OS_USERNAME': 'username',
|
||||
'OS_PASSWORD': 'password',
|
||||
@@ -59,7 +63,9 @@ class TestCli_Utils(base.TestCase):
|
||||
'os_username': 'username',
|
||||
'os_tenant_name': 'tenant_name',
|
||||
'os_password': 'password',
|
||||
'action': 'create'})),
|
||||
'action': 'create',
|
||||
'json': False,
|
||||
})),
|
||||
]
|
||||
|
||||
# Patch os.environ to avoid reading auth info
|
||||
|
@@ -25,7 +25,6 @@ from testtools import matchers
|
||||
|
||||
from solumclient.common import yamlutils
|
||||
from solumclient.openstack.common.apiclient import auth
|
||||
from solumclient.openstack.common import cliutils
|
||||
from solumclient import solum
|
||||
from solumclient.tests import base
|
||||
from solumclient.v1 import assembly
|
||||
@@ -256,15 +255,13 @@ class TestSolum(base.TestCase):
|
||||
mock_pipeline_find.assert_called_once_with(name_or_id='app2')
|
||||
|
||||
# Plan Tests #
|
||||
@mock.patch.object(cliutils, "print_dict")
|
||||
@mock.patch.object(plan.PlanManager, "create")
|
||||
def test_plan_create(self, mock_plan_create, mock_print_dict):
|
||||
def test_plan_create(self, mock_plan_create):
|
||||
FakeResource = collections.namedtuple("FakeResource",
|
||||
"uuid name description uri")
|
||||
|
||||
mock_plan_create.return_value = FakeResource('foo', 'foo', 'foo',
|
||||
'foo')
|
||||
expected_printed_dict_args = mock_plan_create.return_value._asdict()
|
||||
raw_data = 'version: 1\nname: ex_plan1\ndescription: dsc1.'
|
||||
plan_data = yamlutils.dump(yamlutils.load(raw_data))
|
||||
mopen = mock.mock_open(read_data=raw_data)
|
||||
@@ -272,22 +269,17 @@ class TestSolum(base.TestCase):
|
||||
self.make_env()
|
||||
self.shell("plan create /dev/null")
|
||||
mock_plan_create.assert_called_once_with(plan_data)
|
||||
mock_print_dict.assert_called_once_with(
|
||||
expected_printed_dict_args,
|
||||
wrap=72)
|
||||
|
||||
@mock.patch.object(cliutils, "print_dict")
|
||||
@mock.patch.object(solum.PlanCommands, "_show_public_keys")
|
||||
@mock.patch.object(plan.PlanManager, "create")
|
||||
def test_plan_create_with_private_github_repo(self, mock_plan_create,
|
||||
mock_show_pub_keys,
|
||||
mock_print_dict):
|
||||
mock_show_pub_keys):
|
||||
FakeResource = collections.namedtuple(
|
||||
"FakeResource", "uuid name description uri artifacts")
|
||||
|
||||
mock_plan_create.return_value = FakeResource('foo', 'foo', 'foo',
|
||||
'foo', 'artifacts')
|
||||
expected_printed_dict_args = mock_plan_create.return_value._asdict()
|
||||
expected_printed_dict_args = vars(mock_plan_create.return_value)
|
||||
expected_printed_dict_args.pop('artifacts')
|
||||
expected_show_pub_keys_args = 'artifacts'
|
||||
raw_data = 'version: 1\nname: ex_plan1\ndescription: dsc1.'
|
||||
@@ -297,9 +289,6 @@ class TestSolum(base.TestCase):
|
||||
self.make_env()
|
||||
self.shell("plan create /dev/null")
|
||||
mock_plan_create.assert_called_once_with(plan_data)
|
||||
mock_print_dict.assert_called_once_with(
|
||||
expected_printed_dict_args,
|
||||
wrap=72)
|
||||
mock_show_pub_keys.assert_called_once_with(
|
||||
expected_show_pub_keys_args)
|
||||
|
||||
@@ -359,6 +348,7 @@ class TestSolum(base.TestCase):
|
||||
mopen = mock.mock_open(read_data=lp_metadata)
|
||||
with mock.patch('%s.open' % solum.__name__, mopen, create=True):
|
||||
self.make_env()
|
||||
|
||||
self.shell("languagepack create lp_name github.com/test "
|
||||
"--lp_metadata=/dev/null")
|
||||
mock_lp_create.assert_called_once_with(
|
||||
|
Reference in New Issue
Block a user