Add support for heat files
Sends all files under /Resources/HotFiles to Heat when deploying a Murano environment, while keeping the format Heat expects Partially implements: blueprint add-support-for-heat-environments-and-files Change-Id: Id7574642b8e09a7f659e4d9576a95f9f6efd8792
This commit is contained in:
parent
74b3176d22
commit
6559890242
@ -40,6 +40,7 @@ class HeatStack(murano_object.MuranoObject):
|
||||
self._name = name
|
||||
self._template = None
|
||||
self._parameters = {}
|
||||
self._files = {}
|
||||
self._applied = True
|
||||
self._description = description
|
||||
self._clients = helpers.get_environment(_context).clients
|
||||
@ -84,6 +85,10 @@ class HeatStack(murano_object.MuranoObject):
|
||||
self._parameters = parameters
|
||||
self._applied = False
|
||||
|
||||
def setFiles(self, files):
|
||||
self._files = files
|
||||
self._applied = False
|
||||
|
||||
def updateTemplate(self, _context, template):
|
||||
template_version = template.get('heat_template_version',
|
||||
HEAT_TEMPLATE_VERSION)
|
||||
@ -174,6 +179,7 @@ class HeatStack(murano_object.MuranoObject):
|
||||
stack_name=self._name,
|
||||
parameters=self._parameters,
|
||||
template=template,
|
||||
files=self._files,
|
||||
disable_rollback=True)
|
||||
|
||||
self._wait_state(
|
||||
@ -186,6 +192,7 @@ class HeatStack(murano_object.MuranoObject):
|
||||
trust_client.stacks.update(
|
||||
stack_id=self._name,
|
||||
parameters=self._parameters,
|
||||
files=self._files,
|
||||
template=template,
|
||||
disable_rollback=True)
|
||||
self._wait_state(
|
||||
|
@ -94,7 +94,8 @@ class HotPackage(murano.packages.application_package.ApplicationPackage):
|
||||
parameters.update(HotPackage._translate_outputs(hot))
|
||||
translated['Properties'] = parameters
|
||||
|
||||
translated.update(HotPackage._generate_workflow(hot))
|
||||
files = HotPackage._translate_files(self._source_directory)
|
||||
translated.update(HotPackage._generate_workflow(hot, files))
|
||||
self._translated_class = translated
|
||||
|
||||
@staticmethod
|
||||
@ -149,6 +150,24 @@ class HotPackage(murano.packages.application_package.ApplicationPackage):
|
||||
}
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _translate_files(source_directory):
|
||||
heat_files_dir = os.path.join(source_directory, 'Resources/HotFiles')
|
||||
result = {}
|
||||
if os.path.isdir(heat_files_dir):
|
||||
result = HotPackage._build_heat_files_dict(heat_files_dir)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _build_heat_files_dict(basedir):
|
||||
result = []
|
||||
for root, _, files in os.walk(os.path.abspath(basedir)):
|
||||
for f in files:
|
||||
full_path = os.path.join(root, f)
|
||||
relative_path = os.path.relpath(full_path, basedir)
|
||||
result.append(relative_path)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _translate_constraint(constraint):
|
||||
if 'allowed_values' in constraint:
|
||||
@ -200,10 +219,14 @@ class HotPackage(murano.packages.application_package.ApplicationPackage):
|
||||
return str(value)
|
||||
|
||||
@staticmethod
|
||||
def _generate_workflow(hot):
|
||||
def _generate_workflow(hot, files):
|
||||
template_parameters = {}
|
||||
for key, value in (hot.get('parameters') or {}).items():
|
||||
template_parameters[key] = YAQL("$." + key)
|
||||
hot_files_map = {}
|
||||
for f in files:
|
||||
file_path = "$resources.string('HotFiles/%s')" % f
|
||||
hot_files_map[f] = YAQL(file_path)
|
||||
|
||||
copy_outputs = []
|
||||
for key, value in (hot.get('outputs') or {}).items():
|
||||
@ -232,8 +255,10 @@ class HotPackage(murano.packages.application_package.ApplicationPackage):
|
||||
{YAQL('$resources'): YAQL("new('io.murano.system.Resources')")},
|
||||
{YAQL('$template'): YAQL("$resources.yaml(type($this))")},
|
||||
{YAQL('$parameters'): template_parameters},
|
||||
{YAQL('$files'): hot_files_map},
|
||||
YAQL('$stack.setTemplate($template)'),
|
||||
YAQL('$stack.setParameters($parameters)'),
|
||||
YAQL('$stack.setFiles($files)'),
|
||||
|
||||
YAQL("$reporter.report($this, 'Stack creation has started')"),
|
||||
{
|
||||
|
0
murano/tests/unit/packages/hot_package/__init__.py
Normal file
0
murano/tests/unit/packages/hot_package/__init__.py
Normal file
51
murano/tests/unit/packages/hot_package/test_hot_package.py
Normal file
51
murano/tests/unit/packages/hot_package/test_hot_package.py
Normal file
@ -0,0 +1,51 @@
|
||||
#
|
||||
# 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 os
|
||||
|
||||
import murano.packages.hot_package
|
||||
import murano.packages.load_utils as load_utils
|
||||
import murano.tests.unit.base as test_base
|
||||
|
||||
|
||||
class TestHotPackage(test_base.MuranoTestCase):
|
||||
def test_heat_files_generated(self):
|
||||
package_dir = os.path.abspath(
|
||||
os.path.join(__file__,
|
||||
'../../test_packages/test.hot.v1.app_with_files')
|
||||
)
|
||||
load_utils.load_from_dir(package_dir)
|
||||
|
||||
result = murano.packages.hot_package.HotPackage._translate_files(
|
||||
package_dir)
|
||||
expected_result = [
|
||||
"testHeatFile",
|
||||
"middle_file/testHeatFile",
|
||||
"middle_file/inner_file/testHeatFile",
|
||||
"middle_file/inner_file2/testHeatFile"
|
||||
]
|
||||
msg = "hot files were not generated correctly"
|
||||
self.assertEqual(expected_result, result, msg)
|
||||
|
||||
def test_heat_files_generated_empty(self):
|
||||
package_dir = os.path.abspath(
|
||||
os.path.join(__file__,
|
||||
'../../test_packages/test.hot.v1.app')
|
||||
)
|
||||
load_utils.load_from_dir(package_dir)
|
||||
|
||||
result = murano.packages.hot_package.HotPackage._translate_files(
|
||||
package_dir)
|
||||
msg = "heat files were not generated correctly. Expected empty dict"
|
||||
self.assertEqual(result, {}, msg)
|
@ -0,0 +1 @@
|
||||
inner file
|
@ -0,0 +1 @@
|
||||
inner file 2
|
@ -0,0 +1 @@
|
||||
middle file
|
@ -0,0 +1 @@
|
||||
file
|
@ -0,0 +1,17 @@
|
||||
Format: Heat.HOT/1.0
|
||||
Type: Application
|
||||
FullName: test.hot.v1.app
|
||||
Name: Test HOT v1 App
|
||||
Description: Test HOT v1 Application
|
||||
Author: Test Runner
|
||||
Tags: [Linux]
|
||||
Logo: test_logo.png
|
||||
Supplier:
|
||||
Name: Supplier Name
|
||||
CompanyUrl:
|
||||
Text: Example Company
|
||||
Link: http://example.com
|
||||
Logo: test_supplier_logo.png
|
||||
Summary: Company summary goes here
|
||||
Description: Marked up company description goes here
|
||||
|
@ -0,0 +1,8 @@
|
||||
heat_template_version: '2013-05-23'
|
||||
resources:
|
||||
test-server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
flavor: test.flavor
|
||||
image: Some image name
|
||||
key_name: default
|
@ -59,6 +59,7 @@ class TestHeatStack(base.MuranoTestCase):
|
||||
hs._name = 'test-stack'
|
||||
hs._description = 'Generated by TestHeatStack'
|
||||
hs._template = {'resources': {'test': 1}}
|
||||
hs._files = {}
|
||||
hs._parameters = {}
|
||||
hs._applied = False
|
||||
hs._clients = self.client_manager_mock
|
||||
@ -73,7 +74,8 @@ class TestHeatStack(base.MuranoTestCase):
|
||||
stack_name='test-stack',
|
||||
disable_rollback=True,
|
||||
parameters={},
|
||||
template=expected_template
|
||||
template=expected_template,
|
||||
files={}
|
||||
)
|
||||
self.assertTrue(hs._applied)
|
||||
|
||||
@ -93,6 +95,7 @@ class TestHeatStack(base.MuranoTestCase):
|
||||
hs._name = 'test-stack'
|
||||
hs._description = None
|
||||
hs._template = {'resources': {'test': 1}}
|
||||
hs._files = {}
|
||||
hs._parameters = {}
|
||||
hs._applied = False
|
||||
hs.push(None)
|
||||
@ -105,7 +108,42 @@ class TestHeatStack(base.MuranoTestCase):
|
||||
stack_name='test-stack',
|
||||
disable_rollback=True,
|
||||
parameters={},
|
||||
template=expected_template
|
||||
template=expected_template,
|
||||
files={}
|
||||
)
|
||||
self.assertTrue(hs._applied)
|
||||
|
||||
def test_heat_files_are_sent(self):
|
||||
"""Assert that if heat_template_version is omitted, it's added."""
|
||||
# Note that the 'with x as y, a as b:' syntax was introduced in
|
||||
# python 2.7, and contextlib.nested was deprecated in py2.7
|
||||
with mock.patch(MOD_NAME + '.HeatStack._get_status') as status_get:
|
||||
with mock.patch(MOD_NAME + '.HeatStack._wait_state') as wait_st:
|
||||
|
||||
status_get.return_value = 'NOT_FOUND'
|
||||
wait_st.return_value = {}
|
||||
|
||||
hs = heat_stack.HeatStack(self.mock_murano_class,
|
||||
None, self.mock_object_store, None)
|
||||
hs._clients = self.client_manager_mock
|
||||
hs._name = 'test-stack'
|
||||
hs._description = None
|
||||
hs._template = {'resources': {'test': 1}}
|
||||
hs._files = {"heatFile": "file"}
|
||||
hs._parameters = {}
|
||||
hs._applied = False
|
||||
hs.push(None)
|
||||
|
||||
expected_template = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'resources': {'test': 1}
|
||||
}
|
||||
self.heat_client_mock.stacks.create.assert_called_with(
|
||||
stack_name='test-stack',
|
||||
disable_rollback=True,
|
||||
parameters={},
|
||||
template=expected_template,
|
||||
files={"heatFile": "file"}
|
||||
)
|
||||
self.assertTrue(hs._applied)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user