Add osc command "schema"
Change-Id: I02f3b79b81843da8342489f87663629d7112cc07
This commit is contained in:
parent
5b30efba6f
commit
b1bf7d47e9
@ -374,3 +374,44 @@ class TypeList(command.Lister):
|
||||
column_headers = [c.capitalize() for c in columns]
|
||||
return (column_headers,
|
||||
data)
|
||||
|
||||
|
||||
class TypeSchema(command.Lister):
|
||||
"""Schema of type name."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TypeSchema, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'type_name',
|
||||
metavar='<TYPE_NAME>',
|
||||
action=TypeMapperAction,
|
||||
help='Name of artifact type.',
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
LOG.debug('take_action({0})'.format(parsed_args))
|
||||
client = self.app.client_manager.artifact
|
||||
data = client.artifacts.get_type_schema(
|
||||
type_name=parsed_args.type_name)['properties']
|
||||
|
||||
columns = ('name', 'glare_type', 'mutable', 'required',
|
||||
'sortable', 'filters', 'available_values')
|
||||
column_headers = [c.capitalize() for c in columns]
|
||||
|
||||
table = []
|
||||
|
||||
for name, values in six.iteritems(data):
|
||||
row = (
|
||||
name,
|
||||
values.get('glareType'),
|
||||
values.get('mutable', False),
|
||||
values.get('required_on_activate', True),
|
||||
values.get('sortable', False),
|
||||
values.get('filter_ops'),
|
||||
values.get('enum', '')
|
||||
)
|
||||
table.append(row)
|
||||
|
||||
return (column_headers,
|
||||
table)
|
||||
|
@ -15,11 +15,12 @@
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
from glareclient.common import utils as g_utils
|
||||
import mock
|
||||
from osc_lib.tests import utils
|
||||
|
||||
from glareclient.common import utils as g_utils
|
||||
from glareclient.tests.unit.osc.v1 import fakes_schemas
|
||||
|
||||
blob_fixture = {
|
||||
"status": "active",
|
||||
"url": "fake_url",
|
||||
@ -70,6 +71,10 @@ def mock_g_servs(*args, **kwargs):
|
||||
'status': 'active'}
|
||||
|
||||
|
||||
def mock_g_schema(*args, **kwargs):
|
||||
return fakes_schemas.FIXTURE_SCHEMA
|
||||
|
||||
|
||||
def mock_get_data_file(*args, **kwargs):
|
||||
return 'data'
|
||||
|
||||
@ -90,6 +95,8 @@ class TestArtifacts(utils.TestCommand):
|
||||
self.app.client_manager.artifact.artifacts.publish = mock_g_servs
|
||||
self.app.client_manager.artifact.blobs.upload_blob = mock_g_servs
|
||||
self.app.client_manager.artifact.blobs.download_blob = mock_g_servs
|
||||
self.app.client_manager.artifact.artifacts.get_type_schema = \
|
||||
mock_g_schema
|
||||
g_utils.get_data_file = mock.MagicMock()
|
||||
g_utils.get_data_file = mock_get_data_file
|
||||
g_utils.save_blob = mock.MagicMock()
|
||||
|
372
glareclient/tests/unit/osc/v1/fakes_schemas.py
Normal file
372
glareclient/tests/unit/osc/v1/fakes_schemas.py
Normal file
@ -0,0 +1,372 @@
|
||||
# Copyright 2016 OpenStack Foundation
|
||||
# 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.
|
||||
|
||||
FIXTURE_SCHEMA = {
|
||||
u'name': u'sample_artifact',
|
||||
u'properties': {
|
||||
u'activated_at': {
|
||||
u'description': u'Datetime when artifact has became active.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in',
|
||||
u'gt',
|
||||
u'gte',
|
||||
u'lt',
|
||||
u'lte'],
|
||||
u'format': u'date-time',
|
||||
u'glareType': u'DateTime',
|
||||
u'readOnly': True,
|
||||
u'required_on_activate': False,
|
||||
u'sortable': True,
|
||||
u'type': [u'string',
|
||||
u'null']},
|
||||
u'created_at': {
|
||||
u'description': u'Datetime when artifact has been created.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in',
|
||||
u'gt',
|
||||
u'gte',
|
||||
u'lt',
|
||||
u'lte'],
|
||||
u'format': u'date-time',
|
||||
u'glareType': u'DateTime',
|
||||
u'readOnly': True,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'description': {u'default': u'',
|
||||
u'description': u'Artifact description.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 4096,
|
||||
u'mutable': True,
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'string',
|
||||
u'null']},
|
||||
u'icon': {u'additionalProperties': False,
|
||||
u'description': u'Artifact icon.',
|
||||
u'filter_ops': [],
|
||||
u'glareType': u'Blob',
|
||||
u'properties': {u'md5': {u'type': [u'string', u'null']},
|
||||
u'sha1': {u'type': [u'string', u'null']},
|
||||
u'sha256': {u'type': [u'string', u'null']},
|
||||
u'content_type': {u'type': u'string'},
|
||||
u'external': {u'type': u'boolean'},
|
||||
u'size': {u'type': [u'number',
|
||||
u'null']},
|
||||
u'status': {u'enum': [u'saving',
|
||||
u'active',
|
||||
u'pending_delete'],
|
||||
u'type': u'string'}},
|
||||
u'required': [u'size',
|
||||
u'md5', u'sha1', u'sha256',
|
||||
u'external',
|
||||
u'status',
|
||||
u'content_type'],
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'id': {u'description': u'Artifact UUID.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 255,
|
||||
u'pattern': u'^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-'
|
||||
u'fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$',
|
||||
u'readOnly': True,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'license': {u'description': u'Artifact license type.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 255,
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'string',
|
||||
u'null']},
|
||||
u'license_url': {u'description': u'URL to artifact license.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 255,
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'string',
|
||||
u'null']},
|
||||
u'metadata': {u'additionalProperties': {u'type': u'string'},
|
||||
u'default': {},
|
||||
u'description': u'Key-value dict with useful information'
|
||||
u'about an artifact.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq'],
|
||||
u'glareType': u'StringDict',
|
||||
u'maxProperties': 255,
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'name': {u'description': u'Artifact Name.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 255,
|
||||
u'required_on_activate': False,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'owner': {u'description': u'ID of user/tenant who uploaded artifact.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 255,
|
||||
u'readOnly': True,
|
||||
u'required_on_activate': False,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'provided_by': {u'additionalProperties': False,
|
||||
u'description': u'Info about artifact authors.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'StringDict',
|
||||
u'maxProperties': 255,
|
||||
u'properties': {u'company': {u'type': u'string'},
|
||||
u'href': {u'type': u'string'},
|
||||
u'name': {u'type': u'string'}},
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'release': {u'default': [],
|
||||
u'description': u'Target OpenStack release for artifact. '
|
||||
u'It is usually the same when artifact '
|
||||
u'was uploaded.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'StringList',
|
||||
u'items': {u'type': u'string'},
|
||||
u'maxItems': 255,
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'array',
|
||||
u'null'],
|
||||
u'unique': True},
|
||||
u'status': {u'default': u'drafted',
|
||||
u'description': u'Artifact status.',
|
||||
u'enum': [u'drafted',
|
||||
u'active',
|
||||
u'deactivated',
|
||||
u'deleted'],
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'String',
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'supported_by': {u'additionalProperties': {u'type': u'string'},
|
||||
u'description': u'Info about persons who '
|
||||
u'responsible for artifact support',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'StringDict',
|
||||
u'maxProperties': 255,
|
||||
u'required': [u'name'],
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'tags': {u'default': [],
|
||||
u'description': u'List of tags added to Artifact.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in'],
|
||||
u'glareType': u'StringList',
|
||||
u'items': {u'type': u'string'},
|
||||
u'maxItems': 255,
|
||||
u'mutable': True,
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'array',
|
||||
u'null']},
|
||||
u'updated_at': {
|
||||
u'description': u'Datetime when artifact has been updated '
|
||||
u'last time.',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in',
|
||||
u'gt',
|
||||
u'gte',
|
||||
u'lt',
|
||||
u'lte'],
|
||||
u'format': u'date-time',
|
||||
u'glareType': u'DateTime',
|
||||
u'readOnly': True,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'version': {u'default': u'0.0.0',
|
||||
u'description': u'Artifact version(semver).',
|
||||
u'filter_ops': [u'eq',
|
||||
u'neq',
|
||||
u'in',
|
||||
u'gt',
|
||||
u'gte',
|
||||
u'lt',
|
||||
u'lte'],
|
||||
u'glareType': u'String',
|
||||
u'pattern': u'/^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-'
|
||||
u'([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?'
|
||||
u'(?:\\+[0-9A-Za-z-]+)?$/',
|
||||
u'required_on_activate': False,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'visibility': {u'default': u'private',
|
||||
u'description': u'Artifact visibility that defines if '
|
||||
u'artifact can be available to other '
|
||||
u'users.',
|
||||
u'filter_ops': [u'eq'],
|
||||
u'glareType': u'String',
|
||||
u'maxLength': 255,
|
||||
u'sortable': True,
|
||||
u'type': u'string'},
|
||||
u'image': {u'additionalProperties': False,
|
||||
u'description': u'Image binary.',
|
||||
u'filter_ops': [],
|
||||
u'glareType': u'Blob',
|
||||
u'properties': {
|
||||
u'md5': {u'type': [u'string', u'null']},
|
||||
u'sha1': {u'type': [u'string', u'null']},
|
||||
u'sha256': {u'type': [u'string', u'null']},
|
||||
u'content_type': {u'type': u'string'},
|
||||
u'external': {u'type': u'boolean'},
|
||||
u'size': {u'type': [u'number',
|
||||
u'null']},
|
||||
u'status': {u'enum': [u'saving',
|
||||
u'active',
|
||||
u'pending_delete'],
|
||||
u'type': u'string'}},
|
||||
u'required': [u'size',
|
||||
u'md5', u'sha1', u'sha256',
|
||||
u'external',
|
||||
u'status',
|
||||
u'content_type'],
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object', u'null']},
|
||||
u'package': {
|
||||
u'additionalProperties': False,
|
||||
u'description': u'Murano Package binary.',
|
||||
u'filter_ops': [],
|
||||
u'glareType': u'Blob',
|
||||
u'properties': {u'md5': {u'type': [u'string', u'null']},
|
||||
u'sha1': {u'type': [u'string', u'null']},
|
||||
u'sha256': {u'type': [u'string', u'null']},
|
||||
u'content_type': {u'type': u'string'},
|
||||
u'external': {u'type': u'boolean'},
|
||||
u'size': {u'type': [u'number',
|
||||
u'null']},
|
||||
u'status': {u'enum': [u'saving',
|
||||
u'active',
|
||||
u'pending_delete'],
|
||||
u'type': u'string'}},
|
||||
u'required': [u'size',
|
||||
u'md5', u'sha1', u'sha256',
|
||||
u'external',
|
||||
u'status',
|
||||
u'content_type'],
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'environment': {
|
||||
u'additionalProperties': False,
|
||||
u'description': u'Heat Environment text body.',
|
||||
u'filter_ops': [],
|
||||
u'glareType': u'Blob',
|
||||
u'properties': {u'md5': {u'type': [u'string', u'null']},
|
||||
u'sha1': {u'type': [u'string', u'null']},
|
||||
u'sha256': {u'type': [u'string', u'null']},
|
||||
u'content_type': {u'type': u'string'},
|
||||
u'external': {u'type': u'boolean'},
|
||||
u'size': {u'type': [u'number',
|
||||
u'null']},
|
||||
u'status': {u'enum': [u'saving',
|
||||
u'active',
|
||||
u'pending_delete'],
|
||||
u'type': u'string'}},
|
||||
u'required': [u'size',
|
||||
u'md5', u'sha1', u'sha256',
|
||||
u'external',
|
||||
u'status',
|
||||
u'content_type'],
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'blob': {
|
||||
u'additionalProperties': False,
|
||||
u'description': u'I am Blob',
|
||||
u'filter_ops': [],
|
||||
u'glareType': u'Blob',
|
||||
u'mutable': True,
|
||||
u'properties': {
|
||||
u'md5': {u'type': [u'string', u'null']},
|
||||
u'sha1': {u'type': [u'string', u'null']},
|
||||
u'sha256': {u'type': [u'string', u'null']},
|
||||
u'content_type': {
|
||||
u'type': u'string'},
|
||||
u'external': {
|
||||
u'type': u'boolean'},
|
||||
u'size': {u'type': [
|
||||
u'number',
|
||||
u'null']},
|
||||
u'status': {
|
||||
u'enum': [
|
||||
u'saving',
|
||||
u'active',
|
||||
u'pending_delete'],
|
||||
u'type': u'string'}},
|
||||
u'required': [u'size',
|
||||
u'md5', u'sha1', u'sha256',
|
||||
u'external',
|
||||
u'status',
|
||||
u'content_type'],
|
||||
u'required_on_activate': False,
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
u'template': {
|
||||
u'additionalProperties': False,
|
||||
u'description': u'TOSCA template body.',
|
||||
u'filter_ops': [],
|
||||
u'glareType': u'Blob',
|
||||
u'properties': {
|
||||
u'md5': {u'type': [u'string', u'null']},
|
||||
u'sha1': {u'type': [u'string', u'null']},
|
||||
u'sha256': {u'type': [u'string', u'null']},
|
||||
u'content_type': {
|
||||
u'type': u'string'},
|
||||
u'external': {u'type': u'boolean'},
|
||||
u'size': {u'type': [u'number',
|
||||
u'null']},
|
||||
u'status': {u'enum': [u'saving',
|
||||
u'active',
|
||||
u'pending_delete'],
|
||||
u'type': u'string'}},
|
||||
u'required': [u'size',
|
||||
u'md5', u'sha1', u'sha256',
|
||||
u'external',
|
||||
u'status',
|
||||
u'content_type'],
|
||||
u'type': [u'object',
|
||||
u'null']},
|
||||
}
|
||||
}
|
@ -341,3 +341,69 @@ class TestPublishArtifacts(TestArtifacts):
|
||||
name_fields = set([column[0] for column in data])
|
||||
# Check that columns are correct
|
||||
self.assertEqual(self.COLUMNS, name_fields)
|
||||
|
||||
|
||||
class TypeSchema(TestArtifacts):
|
||||
|
||||
def setUp(self):
|
||||
super(TypeSchema, self).setUp()
|
||||
self.artifact_mock.call.return_value = \
|
||||
api_art.Controller(self.http, type_name='sample_artifact')
|
||||
|
||||
# Command to test
|
||||
self.cmd = osc_art.TypeSchema(self.app, None)
|
||||
|
||||
def test_get_schema(self):
|
||||
arglist = ['sample_artifact']
|
||||
verify = [('type_name', 'sample_artifact')]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verify)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
exp_columns = ['Name', 'Glare_type', 'Mutable', 'Required',
|
||||
'Sortable', 'Filters', 'Available_values']
|
||||
exp_data = [
|
||||
(u'image', u'Blob', False, False, False, [], ''),
|
||||
(u'updated_at', u'DateTime', False, True, True,
|
||||
[u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], ''),
|
||||
(u'owner', u'String', False, False, True,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'provided_by', u'StringDict', False, False, False,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'id', u'String', False, True, True, [u'eq', u'neq', u'in'], ''),
|
||||
(u'environment', u'Blob', False, True, False, [], ''),
|
||||
(u'version', u'String', False, False, True,
|
||||
[u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], ''),
|
||||
(u'blob', u'Blob', True, False, False, [], ''),
|
||||
(u'template', u'Blob', False, True, False, [], ''),
|
||||
(u'metadata', u'StringDict', False, False, False,
|
||||
[u'eq', u'neq'], ''),
|
||||
(u'status', u'String', False, True, True, [u'eq', u'neq', u'in'],
|
||||
[u'drafted', u'active', u'deactivated', u'deleted']),
|
||||
(u'description', u'String', True, False, False,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'tags', u'StringList', True, False, False,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'activated_at', u'DateTime', False, False, True,
|
||||
[u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], ''),
|
||||
(u'supported_by', u'StringDict', False, False, False,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'visibility', u'String', False, True, True, [u'eq'], ''),
|
||||
(u'icon', u'Blob', False, False, False, [], ''),
|
||||
(u'name', u'String', False, False, True,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'license', u'String', False, False, False,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'package', u'Blob', False, False, False, [], ''),
|
||||
(u'created_at', u'DateTime', False, True, True,
|
||||
[u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], ''),
|
||||
(u'license_url', u'String', False, False, False,
|
||||
[u'eq', u'neq', u'in'], ''),
|
||||
(u'release', u'StringList', False, False, False,
|
||||
[u'eq', u'neq', u'in'], '')]
|
||||
|
||||
data.sort(key=lambda x: x[0])
|
||||
exp_data.sort(key=lambda x: x[0])
|
||||
|
||||
# Check that columns are correct
|
||||
self.assertEqual(exp_columns, columns)
|
||||
self.assertEqual(exp_data, data)
|
||||
|
@ -198,5 +198,16 @@ data_fixtures = {
|
||||
'heat_environments': {'name': 'heat_environments',
|
||||
'version': '1.0'}}}
|
||||
)
|
||||
},
|
||||
'/schemas/images': {
|
||||
'GET': (
|
||||
{},
|
||||
{'schemas': {
|
||||
'images': {'name': 'images',
|
||||
'version': '1.0',
|
||||
'properties': {'foo': 'bar'}
|
||||
}}}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -374,3 +374,11 @@ class TestController(testtools.TestCase):
|
||||
expect_call = [('GET', '/schemas', {}, None)]
|
||||
self.assertEqual(expect_call, self.api.calls)
|
||||
self.assertEqual(expect_data, data)
|
||||
|
||||
def test_get_schema(self):
|
||||
data = self.controller.get_type_schema(type_name='images')
|
||||
expect_data = {'name': 'images', 'version': '1.0',
|
||||
'properties': {'foo': 'bar'}}
|
||||
expect_call = [('GET', '/schemas/images', {}, None)]
|
||||
self.assertEqual(expect_call, self.api.calls)
|
||||
self.assertEqual(expect_data, data)
|
||||
|
@ -47,6 +47,7 @@ openstack.artifact.v1 =
|
||||
artifact_upload = glareclient.osc.v1.blobs:UploadBlob
|
||||
artifact_download = glareclient.osc.v1.blobs:DownloadBlob
|
||||
artifact_type-list = glareclient.osc.v1.artifacts:TypeList
|
||||
artifact_schema = glareclient.osc.v1.artifacts:TypeSchema
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
Loading…
x
Reference in New Issue
Block a user