Add Plan versioning management
* Version can now be passed in attribute of the Plan YAML File. Version attribute is a mandatory field. * According to the version specified, the appropriate WSME Plan and Plan Handler are created and called. * Plan validation is done by the WSME framework. * How to add a new Plan version (e.g with version 2) ? - Add your Plan_v2 WSME object in datamodels - Add your Plan_v2_handler in handlers - Add init_plan_v2 method in Plan controller. Change-Id: I7fcc6e11391b9f026768a4afafaaa638c43ec303 Closes-Bug: #1291114
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
version: 1
|
||||
name: ex1
|
||||
description: Nodejs express.
|
||||
artifacts:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
version: 1
|
||||
name: ghost
|
||||
description: ghost blogging platform
|
||||
artifacts:
|
||||
|
||||
@@ -19,7 +19,8 @@ from functionaltests.api import base
|
||||
assembly_data = {'name': 'test_assembly',
|
||||
'description': 'desc assembly'}
|
||||
|
||||
plan_data = {'name': 'test_plan',
|
||||
plan_data = {'version': '1',
|
||||
'name': 'test_plan',
|
||||
'description': 'A test to create plan'}
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ sample_data = {"name": "test_assembly",
|
||||
"status": "status",
|
||||
"application_uri": "http://localhost:5000"}
|
||||
|
||||
plan_sample_data = {"name": "test_plan",
|
||||
plan_sample_data = {"version": "1",
|
||||
"name": "test_plan",
|
||||
"description": "A test to create plan",
|
||||
"project_id": "project_id",
|
||||
"user_id": "user_id"}
|
||||
|
||||
@@ -26,7 +26,8 @@ sample_data = {'name': 'test_service',
|
||||
assembly_sample_data = {'name': 'test_assembly',
|
||||
'description': 'desc assembly'}
|
||||
|
||||
plan_sample_data = {'name': 'test_plan',
|
||||
plan_sample_data = {'version': '1',
|
||||
'name': 'test_plan',
|
||||
'description': 'A test to create plan'}
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ import yaml
|
||||
|
||||
from functionaltests.api import base
|
||||
|
||||
sample_data = {"name": "test_plan",
|
||||
sample_data = {"version": "1",
|
||||
"name": "test_plan",
|
||||
"description": "A test to create plan",
|
||||
"artifacts": [{
|
||||
"name": "No_deus",
|
||||
@@ -110,7 +111,8 @@ class TestPlanController(base.TestCase):
|
||||
|
||||
def test_plans_put(self):
|
||||
uuid = self._create_plan()
|
||||
updated_data = {"name": "test_plan_updated",
|
||||
updated_data = {"version": "1",
|
||||
"name": "test_plan_updated",
|
||||
"description": "A test to create plan updated",
|
||||
"type": "plan",
|
||||
"artifacts": []}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
import sys
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
import yaml
|
||||
|
||||
@@ -24,6 +25,25 @@ from solum.common import yamlutils
|
||||
from solum import objects
|
||||
|
||||
|
||||
def init_plan_v1(yml_input_plan):
|
||||
plan_handler_v1 = plan_handler.PlanHandler(
|
||||
pecan.request.security_context)
|
||||
plan_v1 = plan.Plan(**yml_input_plan)
|
||||
return plan_handler_v1, plan_v1
|
||||
|
||||
|
||||
def init_plan_by_version(yml_input_plan):
|
||||
version = yml_input_plan.get('version')
|
||||
if version is None:
|
||||
raise exception.BadRequest(
|
||||
reason='Version attribute is missing in Plan')
|
||||
mod = sys.modules[__name__]
|
||||
if not hasattr(mod, 'init_plan_v%s' % version):
|
||||
raise exception.BadRequest(reason='Plan version %s is invalid.'
|
||||
% version)
|
||||
return getattr(mod, 'init_plan_v%s' % version)(yml_input_plan)
|
||||
|
||||
|
||||
class PlanController(rest.RestController):
|
||||
"""Manages operations on a single plan."""
|
||||
|
||||
@@ -44,14 +64,13 @@ class PlanController(rest.RestController):
|
||||
@pecan.expose(content_type='application/x-yaml')
|
||||
def put(self):
|
||||
"""Modify this plan."""
|
||||
handler = plan_handler.PlanHandler(pecan.request.security_context)
|
||||
if not pecan.request.body or len(pecan.request.body) < 1:
|
||||
raise exception.BadRequest
|
||||
try:
|
||||
yml_input_plan = yamlutils.load(pecan.request.body)
|
||||
except ValueError as excp:
|
||||
raise exception.BadRequest('Plan is invalid. ' + excp.message)
|
||||
data = plan.Plan(**yml_input_plan)
|
||||
handler, data = init_plan_by_version(yml_input_plan)
|
||||
updated_plan_yml = yaml.dump(handler.update(
|
||||
self._id, data.as_dict(objects.registry.Plan)).refined_content())
|
||||
pecan.response.status = 200
|
||||
@@ -78,14 +97,13 @@ class PlansController(rest.RestController):
|
||||
@pecan.expose(content_type='application/x-yaml')
|
||||
def post(self):
|
||||
"""Create a new plan."""
|
||||
handler = plan_handler.PlanHandler(pecan.request.security_context)
|
||||
if not pecan.request.body or len(pecan.request.body) < 1:
|
||||
raise exception.BadRequest
|
||||
try:
|
||||
yml_input_plan = yamlutils.load(pecan.request.body)
|
||||
except ValueError as excp:
|
||||
raise exception.BadRequest('Plan is invalid. ' + excp.message)
|
||||
data = plan.Plan(**yml_input_plan)
|
||||
handler, data = init_plan_by_version(yml_input_plan)
|
||||
create_plan_yml = yaml.dump(handler.create(
|
||||
data.as_dict(objects.registry.Plan)).refined_content())
|
||||
pecan.response.status = 201
|
||||
|
||||
@@ -60,26 +60,38 @@ class TestPlanController(base.BaseTestCase):
|
||||
self.assertEqual(400, resp_mock.status)
|
||||
|
||||
def test_plan_put_not_found(self, PlanHandler, resp_mock, request_mock):
|
||||
data = 'name: ex_plan1\ndescription: yaml plan1.'
|
||||
data = 'version: 1\nname: ex_plan1\ndescription: dsc1.'
|
||||
request_mock.body = data
|
||||
request_mock.content_type = 'application/x-yaml'
|
||||
hand_update = PlanHandler.return_value.update
|
||||
hand_update.side_effect = exception.ResourceNotFound(
|
||||
name='plan', plan_id='test_id')
|
||||
plan.PlanController('test_id').put()
|
||||
hand_update.assert_called_with('test_id', yaml.load(data))
|
||||
hand_update.assert_called_with('test_id', {'name': 'ex_plan1',
|
||||
'description': u'dsc1.'})
|
||||
self.assertEqual(404, resp_mock.status)
|
||||
|
||||
def test_plan_put_ok(self, PlanHandler, resp_mock, request_mock):
|
||||
data = 'name: ex_plan1\ndescription: yaml plan1.'
|
||||
data = 'version: 1\nname: ex_plan1\ndescription: dsc1.'
|
||||
request_mock.body = data
|
||||
request_mock.content_type = 'application/x-yaml'
|
||||
hand_update = PlanHandler.return_value.update
|
||||
hand_update.return_value = fakes.FakePlan()
|
||||
plan.PlanController('test_id').put()
|
||||
hand_update.assert_called_with('test_id', yaml.load(data))
|
||||
hand_update.assert_called_with('test_id', {'name': 'ex_plan1',
|
||||
'description': u'dsc1.'})
|
||||
self.assertEqual(200, resp_mock.status)
|
||||
|
||||
def test_plan_put_version_not_found(self, PlanHandler,
|
||||
resp_mock, request_mock):
|
||||
data = 'name: ex_plan1\ndescription: yaml plan1.\nversion: 2'
|
||||
request_mock.body = data
|
||||
request_mock.content_type = 'application/x-yaml'
|
||||
hand_update = PlanHandler.return_value.update
|
||||
hand_update.return_value = fakes.FakePlan()
|
||||
plan.PlanController('test_id').put()
|
||||
self.assertEqual(400, resp_mock.status)
|
||||
|
||||
def test_plan_delete_not_found(self, PlanHandler, resp_mock, request_mock):
|
||||
hand_delete = PlanHandler.return_value.delete
|
||||
hand_delete.side_effect = exception.ResourceNotFound(
|
||||
@@ -118,15 +130,24 @@ class TestPlansController(base.BaseTestCase):
|
||||
hand_get.assert_called_with()
|
||||
|
||||
def test_plans_post(self, PlanHandler, resp_mock, request_mock):
|
||||
request_mock.body = 'name: ex_plan1\ndescription: yaml plan1.'
|
||||
request_mock.body = 'version: 1\nname: ex_plan1\ndescription: dsc1.'
|
||||
request_mock.content_type = 'application/x-yaml'
|
||||
hand_create = PlanHandler.return_value.create
|
||||
hand_create.return_value = fakes.FakePlan()
|
||||
plan.PlansController().post()
|
||||
hand_create.assert_called_with({'name': 'ex_plan1',
|
||||
'description': 'yaml plan1.'})
|
||||
'description': 'dsc1.'})
|
||||
self.assertEqual(201, resp_mock.status)
|
||||
|
||||
def test_plans_post_version_not_found(self, PlanHandler,
|
||||
resp_mock, request_mock):
|
||||
request_mock.body = 'version: 2\nname: ex_plan1\ndescription: dsc1.'
|
||||
request_mock.content_type = 'application/x-yaml'
|
||||
hand_create = PlanHandler.return_value.create
|
||||
hand_create.return_value = fakes.FakePlan()
|
||||
plan.PlansController().post()
|
||||
self.assertEqual(400, resp_mock.status)
|
||||
|
||||
def test_plans_post_nodata(self, handler_mock, resp_mock, request_mock):
|
||||
request_mock.body = ''
|
||||
request_mock.content_type = 'application/json'
|
||||
|
||||
Reference in New Issue
Block a user