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:
parent
002fd5faa1
commit
ebda9cd07e
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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."""
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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='')
|
|
@ -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__),
|
||||||
'..', '..', '..', '..'))
|
'..', '..', '..', '..'))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue