Hierarchy levels API handled in the fuel2

Referecne to level values added to DB model and level marshalling.
Fuel2 commands lvl show, lvl list added.

Change-Id: I11fb465c00c411464d75229fc2f8bffdbb8dcc53
Closes-Bug: #1642326
This commit is contained in:
Alexander Kislitsky 2016-11-16 18:05:43 +03:00
parent ed1760d83e
commit 70158d0e1f
9 changed files with 212 additions and 15 deletions

View File

@ -68,6 +68,8 @@ tuning_box.cli =
def_show = tuning_box.cli.resource_definitions:ShowResourceDefinition
def_delete = tuning_box.cli.resource_definitions:DeleteResourceDefinition
def_update = tuning_box.cli.resource_definitions:UpdateResourceDefinition
lvl_list = tuning_box.cli.hierarchy_levels:ListHierarchyLevels
lvl_show = tuning_box.cli.hierarchy_levels:ShowHierarchyLevel
fuelclient =
config_get = tuning_box.fuelclient:Get
config_set = tuning_box.fuelclient:Set
@ -89,6 +91,8 @@ fuelclient =
config_def_show = tuning_box.fuelclient:ShowResourceDefinition
config_def_delete = tuning_box.fuelclient:DeleteResourceDefinition
config_def_update = tuning_box.fuelclient:UpdateResourceDefinition
config_lvl_list = tuning_box.fuelclient:ListHierarchyLevels
config_lvl_show = tuning_box.fuelclient:ShowHierarchyLevel
console_scripts =
tuningbox_db_upgrade = tuning_box.migration:upgrade
tuningbox_db_downgrade = tuning_box.migration:downgrade

View File

@ -95,7 +95,7 @@ api.add_resource(
api.add_resource(
hierarchy_levels.EnvironmentHierarchyLevels,
'/environments/<int:environment_id>/hierarchy_levels/'
'<string:level>'
'<id_or_name:id_or_name>'
)

View File

@ -99,7 +99,7 @@ class BaseOneCommand(BaseCommand):
parser.add_argument(
'id',
type=int,
help='Id of the {0} to delete.'.format(self.entity_name))
help='Id of the {0}'.format(self.entity_name))
return parser
def get_url(self, parsed_args):

View File

@ -0,0 +1,71 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from cliff import lister
from cliff import show
from fuelclient.cli import error as fc_error
from fuelclient.common import data_utils
from tuning_box.cli import base
class HierarchyLevelsCommand(base.BaseCommand):
columns = ('id', 'name', 'parent', 'values')
def get_parser(self, *args, **kwargs):
parser = super(HierarchyLevelsCommand, self).get_parser(
*args, **kwargs)
parser.add_argument(
'-e', '--env',
type=int,
required=True,
help="ID of environment to get data from",
)
return parser
def get_base_url(self, parsed_args):
return '/environments/{}/hierarchy_levels'.format(parsed_args.env)
class ListHierarchyLevels(HierarchyLevelsCommand, lister.Lister):
def take_action(self, parsed_args):
result = self.get_client().get(self.get_base_url(parsed_args))
try:
data = data_utils.get_display_data_multi(self.columns, result)
return self.columns, data
except fc_error.BadDataException:
return zip(*result.items())
class ShowHierarchyLevel(HierarchyLevelsCommand, show.ShowOne):
def get_parser(self, *args, **kwargs):
parser = super(ShowHierarchyLevel, self).get_parser(*args, **kwargs)
parser.add_argument(
'name',
type=str,
help='Hierarchy level name'
)
return parser
def get_url(self, parsed_args):
base_url = self.get_base_url(parsed_args)
return base_url + '/{0}'.format(parsed_args.name)
def take_action(self, parsed_args):
result = self.get_client().get(self.get_url(parsed_args))
try:
data = data_utils.get_display_data_single(self.columns, result)
return self.columns, data
except fc_error.BadDataException:
return zip(*result.items())

View File

@ -196,6 +196,8 @@ class EnvironmentHierarchyLevel(ModelMixin, db.Model):
env_levels.append(env_levels[-1].child)
return env_levels
values = db.relationship('EnvironmentHierarchyLevelValue')
class EnvironmentHierarchyLevelValue(ModelMixin, db.Model):
level_id = fk(EnvironmentHierarchyLevel, ondelete='CASCADE')

View File

@ -19,6 +19,7 @@ from tuning_box import cli
from tuning_box.cli import base as cli_base
from tuning_box.cli import components
from tuning_box.cli import environments
from tuning_box.cli import hierarchy_levels
from tuning_box.cli import resource_definitions
from tuning_box.cli import resources
from tuning_box import client as tb_client
@ -147,6 +148,20 @@ class UpdateResourceDefinition(
pass
class ListHierarchyLevels(
FuelBaseCommand,
hierarchy_levels.ListHierarchyLevels
):
pass
class ShowHierarchyLevel(
FuelBaseCommand,
hierarchy_levels.ShowHierarchyLevel
):
pass
class Config(command.Command):
def get_parser(self, *args, **kwargs):
parser = super(Config, self).get_parser(*args, **kwargs)

View File

@ -60,9 +60,11 @@ def get_environment_level_value(environment, levels):
environment_hierarchy_level_fields = {
'id': fields.Integer,
'name': fields.String,
'environment_id': fields.Integer,
'parent': fields.String(attribute='parent.name')
'parent': fields.String(attribute='parent.name'),
'values': fields.List(fields.String(attribute='value'))
}
@ -81,22 +83,28 @@ class EnvironmentHierarchyLevels(flask_restful.Resource):
flask_restful.marshal_with(environment_hierarchy_level_fields)
]
def get(self, environment_id, level):
level = db.find_or_404(db.EnvironmentHierarchyLevel,
environment_id=environment_id,
name=level)
def _get_query_params(self, environment_id, id_or_name):
params = {'environment_id': environment_id}
if isinstance(id_or_name, int):
params['id'] = id_or_name
else:
params['name'] = id_or_name
return params
def get(self, environment_id, id_or_name):
params = self._get_query_params(environment_id, id_or_name)
level = db.find_or_404(db.EnvironmentHierarchyLevel, **params)
return level
@db.with_transaction
def _do_update(self, environment_id, level):
level = db.find_or_404(db.EnvironmentHierarchyLevel,
environment_id=environment_id,
name=level)
def _do_update(self, environment_id, id_or_name):
params = self._get_query_params(environment_id, id_or_name)
level = db.find_or_404(db.EnvironmentHierarchyLevel, **params)
level.name = flask.request.json.get('name', level.name)
def put(self, environment_id, level):
return self.patch(environment_id, level)
def put(self, environment_id, id_or_name):
return self.patch(environment_id, id_or_name)
def patch(self, environment_id, level):
self._do_update(environment_id, level)
def patch(self, environment_id, id_or_name):
self._do_update(environment_id, id_or_name)
return None, 204

View File

@ -0,0 +1,67 @@
# 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.
import testscenarios
from tuning_box.tests.cli import _BaseCLITest
class TestHierarchyLevels(testscenarios.WithScenarios, _BaseCLITest):
scenarios = [
(s[0], dict(zip(('mock_url', 'args', 'expected_result'), s[1])))
for s in [
('json', ('/environments/9/hierarchy_levels',
'lvl list -e 9 -f json', '[]')),
('yaml', ('/environments/9/hierarchy_levels',
'lvl list -e 9 -f yaml', '[]\n'))
]
]
mock_url = None
args = None
expected_result = None
def test_get(self):
self.req_mock.get(
self.BASE_URL + self.mock_url,
headers={'Content-Type': 'application/json'},
json={},
)
self.cli.run(self.args.split())
self.assertEqual(self.expected_result, self.cli.stdout.getvalue())
class TestShowHierarchyLevel(testscenarios.WithScenarios, _BaseCLITest):
scenarios = [
(s[0], dict(zip(('mock_url', 'args', 'expected_result'), s[1])))
for s in [
('json', ('/environments/9/hierarchy_levels/n',
'lvl show -e 9 -f json -c id n',
'{\n "id": 1\n}')),
('yaml', ('/environments/9/hierarchy_levels/nn',
'lvl show -e 9 -f yaml -c id nn',
'id: 1\n'))
]
]
mock_url = None
args = None
expected_result = None
def test_get(self):
self.req_mock.get(
self.BASE_URL + self.mock_url,
headers={'Content-Type': 'application/json'},
json={'id': 1},
)
self.cli.run(self.args.split())
self.assertEqual(self.expected_result, self.cli.stdout.getvalue())

View File

@ -47,6 +47,31 @@ class TestLevelsHierarchy(BaseTest):
self.assertEqual(level.name, 'lvl1')
self.assertIsNone(level.parent)
def test_get_environment_level_values(self):
self._fixture()
env_id = 9
with self.app.app_context(), db.db.session.begin():
# Creating level values
hierarchy_levels.get_environment_level_value(
db.Environment(id=env_id),
[('lvl1', 'val11'), ('lvl2', 'val21')],
)
hierarchy_levels.get_environment_level_value(
db.Environment(id=env_id),
[('lvl1', 'val11'), ('lvl2', 'val22')],
)
hierarchy_levels.get_environment_level_value(
db.Environment(id=env_id),
[('lvl1', 'val12'), ('lvl2', 'val23')],
)
res = self.client.get(self.collection_url.format(9))
lvl1 = res.json[0]
self.assertItemsEqual(['val11', 'val12'], lvl1['values'])
lvl2 = res.json[1]
self.assertItemsEqual(['val21', 'val22', 'val23'], lvl2['values'])
def test_get_environment_level_value_bad_level(self):
self._fixture()
with self.app.app_context(), db.db.session.begin():
@ -84,6 +109,11 @@ class TestLevelsHierarchy(BaseTest):
self.assertEqual(200, res.status_code)
self.assertEqual(level, res.json['name'])
res = self.client.get(self.object_url.format(environment_id,
res.json['id']))
self.assertEqual(200, res.status_code)
self.assertEqual(level, res.json['name'])
def test_get_hierarchy_level_not_found(self):
levels = ['lvl1', 'lvl2']
for level in levels: