Adds support to deploy already created DU

This patch adds support to deploy a DU image
that is available in glance.

Change-Id: I8f3fddad005baaf054d8a41a2b14029dce6633ab
Partial-Bug:#1535462
This commit is contained in:
Devdatta Kulkarni 2016-01-21 19:36:17 -06:00
parent 002fd5faa1
commit ebda9cd07e
8 changed files with 125 additions and 15 deletions

View File

@ -51,6 +51,7 @@ class Workflow(wtypes.Base):
source = {wtypes.text: wtypes.text} source = {wtypes.text: wtypes.text}
config = {wtypes.text: wtypes.text} config = {wtypes.text: wtypes.text}
actions = [wtypes.text] actions = [wtypes.text]
du_id = wtypes.text
status = wtypes.text status = wtypes.text
result = wtypes.text result = wtypes.text
scale_target = wtypes.text scale_target = wtypes.text

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_config import cfg
import pecan import pecan
from pecan import rest from pecan import rest
import wsmeext.pecan as wsme_pecan import wsmeext.pecan as wsme_pecan
@ -20,12 +21,15 @@ from solum.api.controllers.v1.datamodel import workflow
from solum.api.controllers.v1 import userlog as userlog_controller from solum.api.controllers.v1 import userlog as userlog_controller
from solum.api.handlers import app_handler from solum.api.handlers import app_handler
from solum.api.handlers import workflow_handler as wf_handler from solum.api.handlers import workflow_handler as wf_handler
from solum.common import clients
from solum.common import exception from solum.common import exception
from solum.common import request from solum.common import request
from solum.openstack.common import log as logging from solum.openstack.common import log as logging
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
cfg.CONF.import_opt('image_storage', 'solum.worker.config', group='worker')
class WorkflowController(rest.RestController): class WorkflowController(rest.RestController):
"""Manages operations on a single workflow.""" """Manages operations on a single workflow."""
@ -87,9 +91,16 @@ class WorkflowsController(rest.RestController):
data.source = app_model.source data.source = app_model.source
wf_data = data.as_dict(workflow.Workflow) wf_data = data.as_dict(workflow.Workflow)
du_id = None
if data.du_id:
du_id = data.du_id
self._verify_du_exists(pecan.request.security_context, du_id)
return workflow.Workflow.from_db_model(handler.create(wf_data, return workflow.Workflow.from_db_model(handler.create(wf_data,
commit_sha='', commit_sha='',
status_url=''), status_url='',
du_id=du_id),
pecan.request.host_url) pecan.request.host_url)
@exception.wrap_pecan_controller_exception @exception.wrap_pecan_controller_exception
@ -102,3 +113,22 @@ class WorkflowsController(rest.RestController):
pecan.request.host_url) pecan.request.host_url)
for obj in handler.get_all(app_id=self.app_id)] for obj in handler.get_all(app_id=self.app_id)]
return all_wfs return all_wfs
def _verify_du_exists(self, ctxt, du_id):
du_image_backend = cfg.CONF.worker.image_storage
if du_image_backend.lower() == 'glance':
self._verify_du_image_exists_in_glance(ctxt, du_id)
elif du_image_backend.lower() == 'swift':
self._verify_du_image_exists_in_swift(ctxt, du_id)
else:
raise exception.BadRequest(message="DU image id not recognized.")
return
def _verify_du_image_exists_in_glance(self, ctxt, du_id):
osc = clients.OpenStackClients(ctxt)
osc.glance().images.get(du_id)
return
def _verify_du_image_exists_in_swift(self, du_id):
# TODO(devkulkarni): Check if specified du_id exists in swift
return

View File

@ -127,7 +127,8 @@ class AppHandler(handler.Handler):
'config': app.workflow_config, 'config': app.workflow_config,
'actions': wf 'actions': wf
} }
wfhand.create(wfdata, commit_sha=commit_sha, status_url=status_url) wfhand.create(wfdata, commit_sha=commit_sha, status_url=status_url,
du_id=None)
def get_all(self): def get_all(self):
"""Return all apps.""" """Return all apps."""

View File

@ -89,7 +89,7 @@ class WorkflowHandler(handler.Handler):
db_obj = objects.registry.Workflow.get_by_uuid(self.context, id) db_obj = objects.registry.Workflow.get_by_uuid(self.context, id)
db_obj.destroy(self.context) db_obj.destroy(self.context)
def create(self, data, commit_sha, status_url): def create(self, data, commit_sha, status_url, du_id):
"""Create a new workflow.""" """Create a new workflow."""
db_obj = objects.registry.Workflow() db_obj = objects.registry.Workflow()
db_obj.id = str(uuid.uuid4()) db_obj.id = str(uuid.uuid4())
@ -120,7 +120,8 @@ class WorkflowHandler(handler.Handler):
workflow.Workflow.insert(self.context, db_obj) workflow.Workflow.insert(self.context, db_obj)
self._execute_workflow_actions(db_obj, app_obj, assem, self._execute_workflow_actions(db_obj, app_obj, assem,
commit_sha=app_obj.source['revision']) commit_sha=app_obj.source['revision'],
du_id=du_id)
# TODO(devkulkarni): Update status of actions # TODO(devkulkarni): Update status of actions
@ -137,7 +138,8 @@ class WorkflowHandler(handler.Handler):
def _execute_workflow_actions(self, wf_obj, app_obj, assem, def _execute_workflow_actions(self, wf_obj, app_obj, assem,
verb='launch_workflow', verb='launch_workflow',
commit_sha='', status_url=None): commit_sha='', status_url=None,
du_id=None):
image = objects.registry.Image() image = objects.registry.Image()
image.name = app_obj.name image.name = app_obj.name
@ -182,7 +184,8 @@ class WorkflowHandler(handler.Handler):
assembly_id=assem.id, assembly_id=assem.id,
workflow=assem.workflow, workflow=assem.workflow,
test_cmd=test_cmd, test_cmd=test_cmd,
run_cmd=run_cmd) run_cmd=run_cmd,
du_id=du_id)
class PlanAssemblyAdapter(): class PlanAssemblyAdapter():

View File

@ -91,7 +91,8 @@ class TestWorkflowHandler(base.BaseTestCase):
handler = workflow_handler.WorkflowHandler(self.ctx) handler = workflow_handler.WorkflowHandler(self.ctx)
res = handler.create(workflow_data, commit_sha='', status_url='') res = handler.create(workflow_data, commit_sha='', status_url='',
du_id='')
self.assertEqual(wf_obj, res) self.assertEqual(wf_obj, res)
git_info = { git_info = {
'source_url': app_obj.source['repository'], 'source_url': app_obj.source['repository'],
@ -105,4 +106,4 @@ class TestWorkflowHandler(base.BaseTestCase):
git_info=git_info, test_cmd=test_cmd, ports=app_obj.ports, git_info=git_info, test_cmd=test_cmd, ports=app_obj.ports,
base_image_id=fi.base_image_id, base_image_id=fi.base_image_id,
source_format=fi.source_format, source_format=fi.source_format,
image_format=fi.image_format, run_cmd=run_cmd) image_format=fi.image_format, run_cmd=run_cmd, du_id='')

View File

@ -20,6 +20,7 @@ import uuid
import mock import mock
from oslo_config import cfg from oslo_config import cfg
from solum.common import exception
from solum.openstack.common.gettextutils import _ from solum.openstack.common.gettextutils import _
from solum.tests import base from solum.tests import base
from solum.tests import fakes from solum.tests import fakes
@ -89,6 +90,58 @@ class HandlerTest(base.BaseTestCase):
super(HandlerTest, self).setUp() super(HandlerTest, self).setUp()
self.ctx = utils.dummy_context() self.ctx = utils.dummy_context()
@mock.patch('solum.common.clients.OpenStackClients')
def test_get_du_details_glance(self, mock_client):
handler = shell_handler.Handler()
du_id = 'dummy_du_id'
cfg.CONF.set_override('image_storage', 'glance',
group='worker')
fake_du = fakes.FakeImage()
fake_du.id = 2
fake_du.name = 'name'
mock_glance = mock_client.return_value.glance
mock_get = mock_glance.return_value.images.get
mock_get.return_value = fake_du
du_loc, du_name = handler.get_du_details(self.ctx, du_id)
self.assertTrue(mock_get.called)
self.assertTrue(du_loc, 2)
self.assertTrue(du_name, 'name')
@mock.patch('solum.common.clients.OpenStackClients')
def test_get_du_details_GLANCE(self, mock_client):
handler = shell_handler.Handler()
du_id = 'dummy_du_id'
cfg.CONF.set_override('image_storage', 'GLANCE',
group='worker')
fake_du = fakes.FakeImage()
fake_du.id = 2
fake_du.name = 'name'
mock_glance = mock_client.return_value.glance
mock_get = mock_glance.return_value.images.get
mock_get.return_value = fake_du
du_loc, du_name = handler.get_du_details(self.ctx, du_id)
self.assertTrue(mock_get.called)
self.assertTrue(du_loc, 2)
self.assertTrue(du_name, 'name')
@mock.patch('solum.common.clients.OpenStackClients')
def test_get_du_details_swift(self, mock_client):
handler = shell_handler.Handler()
du_id = 'dummy_du_id'
cfg.CONF.set_override('image_storage', 'swift',
group='worker')
try:
handler.get_du_details(self.ctx, du_id)
self.assertTrue(False)
except exception.NotImplemented:
self.assertTrue(True)
@mock.patch('solum.worker.handlers.shell.Handler._get_environment') @mock.patch('solum.worker.handlers.shell.Handler._get_environment')
@mock.patch('solum.objects.registry') @mock.patch('solum.objects.registry')
@mock.patch('solum.conductor.api.API.update_assembly') @mock.patch('solum.conductor.api.API.update_assembly')
@ -223,7 +276,7 @@ class HandlerTest(base.BaseTestCase):
workflow=['unittest', 'build', 'deploy'], ports=[80], workflow=['unittest', 'build', 'deploy'], ports=[80],
name='new_app', base_image_id=self.base_image_id, name='new_app', base_image_id=self.base_image_id,
source_format='heroku', image_format='docker', assembly_id=44, source_format='heroku', image_format='docker', assembly_id=44,
test_cmd=None, run_cmd=None) test_cmd=None, run_cmd=None, du_id=None)
proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', '..')) '..', '..', '..', '..'))
@ -289,7 +342,7 @@ class HandlerTest(base.BaseTestCase):
workflow=['unitetst', 'build', 'deploy'], ports=[80], workflow=['unitetst', 'build', 'deploy'], ports=[80],
name='new_app', base_image_id=self.base_image_id, name='new_app', base_image_id=self.base_image_id,
source_format='heroku', image_format='docker', assembly_id=44, source_format='heroku', image_format='docker', assembly_id=44,
test_cmd=None, run_cmd=None) test_cmd=None, run_cmd=None, du_id=None)
proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', '..')) '..', '..', '..', '..'))
@ -497,7 +550,7 @@ class HandlerTest(base.BaseTestCase):
workflow=['unittest', 'build', 'deploy'], ports=[80], workflow=['unittest', 'build', 'deploy'], ports=[80],
name='new_app', base_image_id=self.base_image_id, name='new_app', base_image_id=self.base_image_id,
source_format='heroku', image_format='docker', assembly_id=44, source_format='heroku', image_format='docker', assembly_id=44,
test_cmd='faketests', run_cmd=None) test_cmd='faketests', run_cmd=None, du_id=None)
proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', '..')) '..', '..', '..', '..'))
@ -553,7 +606,8 @@ class HandlerTest(base.BaseTestCase):
self.ctx, build_id=5, git_info=git_info, name='new_app', self.ctx, build_id=5, git_info=git_info, name='new_app',
base_image_id=self.base_image_id, source_format='chef', base_image_id=self.base_image_id, source_format='chef',
image_format='docker', assembly_id=44, ports=[80], image_format='docker', assembly_id=44, ports=[80],
test_cmd='faketests', run_cmd=None, workflow=['unittest', 'build']) test_cmd='faketests', run_cmd=None, workflow=['unittest', 'build'],
du_id=None)
proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', '..')) '..', '..', '..', '..'))

View File

@ -28,12 +28,12 @@ class API(service.API):
def build_app(self, verb, build_id, git_info, ports, name, base_image_id, def build_app(self, verb, build_id, git_info, ports, name, base_image_id,
source_format, image_format, assembly_id, workflow, source_format, image_format, assembly_id, workflow,
test_cmd=None, run_cmd=None): test_cmd=None, run_cmd=None, du_id=None):
self._cast(verb, build_id=build_id, git_info=git_info, ports=ports, self._cast(verb, build_id=build_id, git_info=git_info, ports=ports,
name=name, base_image_id=base_image_id, name=name, base_image_id=base_image_id,
source_format=source_format, image_format=image_format, source_format=source_format, image_format=image_format,
assembly_id=assembly_id, workflow=workflow, assembly_id=assembly_id, workflow=workflow,
test_cmd=test_cmd, run_cmd=run_cmd) test_cmd=test_cmd, run_cmd=run_cmd, du_id=du_id)
def build_lp(self, image_id, git_info, name, source_format, image_format, def build_lp(self, image_id, git_info, name, source_format, image_format,
artifact_type): artifact_type):

View File

@ -163,6 +163,23 @@ class Handler(object):
def echo(self, ctxt, message): def echo(self, ctxt, message):
LOG.debug("%s" % message) LOG.debug("%s" % message)
@exception.wrap_keystone_exception
def get_du_details(self, ctxt, du_id):
du_loc = None
du_name = None
du_image_backend = cfg.CONF.worker.image_storage
if du_image_backend.lower() == 'glance':
img = clients.OpenStackClients(ctxt).glance().images.get(du_id)
du_loc = img.id
du_name = img.name
elif du_image_backend.lower() == 'swift':
raise exception.NotImplemented()
else:
LOG.error("Invalid image storage option.")
raise exception.ResourceNotFound()
return du_loc, du_name
@exception.wrap_keystone_exception @exception.wrap_keystone_exception
def _get_environment(self, ctxt, source_uri, assembly_id=None, def _get_environment(self, ctxt, source_uri, assembly_id=None,
test_cmd=None, run_cmd=None, lp_access=None): test_cmd=None, run_cmd=None, lp_access=None):
@ -328,7 +345,8 @@ class Handler(object):
def launch_workflow(self, ctxt, build_id, git_info, ports, name, def launch_workflow(self, ctxt, build_id, git_info, ports, name,
base_image_id, source_format, image_format, base_image_id, source_format, image_format,
assembly_id, workflow, test_cmd, run_cmd): assembly_id, workflow, test_cmd, run_cmd, du_id):
if 'unittest' in workflow: if 'unittest' in workflow:
if self._do_unittest(ctxt, build_id, git_info, name, base_image_id, if self._do_unittest(ctxt, build_id, git_info, name, base_image_id,
source_format, image_format, assembly_id, source_format, image_format, assembly_id,
@ -343,6 +361,8 @@ class Handler(object):
image_format, assembly_id, run_cmd) image_format, assembly_id, run_cmd)
if 'deploy' in workflow: if 'deploy' in workflow:
if du_id:
du_image_loc, du_image_name = self.get_du_details(ctxt, du_id)
if du_image_loc and du_image_name: if du_image_loc and du_image_name:
self._do_deploy(ctxt, assembly_id, ports, du_image_loc, self._do_deploy(ctxt, assembly_id, ports, du_image_loc,
du_image_name) du_image_name)