Merge "Implement VNFC support"
This commit is contained in:
commit
4349df4ece
57
doc/source/devref/vnf_component_usage_guide.rst
Normal file
57
doc/source/devref/vnf_component_usage_guide.rst
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
========================
|
||||||
|
VNF Component in Tacker
|
||||||
|
========================
|
||||||
|
|
||||||
|
This section will cover how to deploy `vnf component` in Tacker with the
|
||||||
|
examples of how to write VNF descriptors.
|
||||||
|
|
||||||
|
|
||||||
|
Sample TOSCA with vnfc
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The following example shows vnfc resource using TOSCA template.
|
||||||
|
The target (VDU1) of the 'firewall_vnfc' in this example need to be
|
||||||
|
described firstly like other TOSCA templates in Tacker.
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
node_templates:
|
||||||
|
firewall_vnfc:
|
||||||
|
type: tosca.nodes.nfv.VNFC.Tacker
|
||||||
|
requirements:
|
||||||
|
- host: VDU1
|
||||||
|
interfaces:
|
||||||
|
Standard:
|
||||||
|
create: install_vnfc.sh
|
||||||
|
|
||||||
|
Every vnfc node must be of type 'tosca.nodes.nfv.VNFC.Tacker'. It takes
|
||||||
|
two parameters:
|
||||||
|
|
||||||
|
1) requirements: This node will accept list of hosts on which VNFC has to be
|
||||||
|
installed.
|
||||||
|
2) interfaces: This node will accept the absolute path of shell script to be run
|
||||||
|
on the VDUs. This shell script should reside in the machine where tacker
|
||||||
|
server is running.
|
||||||
|
|
||||||
|
|
||||||
|
How to setup environment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
To make use of VNFC in Tacker, we have to upload the image to the glance in
|
||||||
|
which heat-config and heat-config agents are installed. The installation steps
|
||||||
|
can be referred `here <https://github.com/openstack/heat-templates/blob/master/
|
||||||
|
hot/software-config/elements/README.rst>`_.
|
||||||
|
|
||||||
|
Currently VNFC feature works by using `heat software config <http://docs.openstack.org/
|
||||||
|
developer/heat/template_guide/openstack.html#OS::Heat::SoftwareConfig>`_ which
|
||||||
|
makes use of heat API.
|
||||||
|
|
||||||
|
So the glance images which has heat-config agents installed are only to be
|
||||||
|
passed to VDU.
|
||||||
|
|
||||||
|
Known Limitations
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
1) Only one VNFC is supported for one VDU. Multiple VNFC per VDU will
|
||||||
|
be introduced in future.
|
||||||
|
2) The shell script for vnfc has to be placed in the machine where tacker
|
||||||
|
server is running.
|
@ -61,6 +61,7 @@ Feature Documentation
|
|||||||
devref/vnffgd_template_description.rst
|
devref/vnffgd_template_description.rst
|
||||||
devref/vnffg_usage_guide.rst
|
devref/vnffg_usage_guide.rst
|
||||||
devref/nsd_usage_guide.rst
|
devref/nsd_usage_guide.rst
|
||||||
|
devref/vnf_component_usage_guide.rst
|
||||||
|
|
||||||
API Documentation
|
API Documentation
|
||||||
=================
|
=================
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add support to pass shell script to install VNF
|
||||||
|
components in the tosca template
|
||||||
|
other:
|
||||||
|
- Only one VNFC is supported for one VDU. Multiple VNFC per VDU will
|
||||||
|
be introduced in future.
|
||||||
|
- The shell script for vnfc has to be placed in the machine where tacker server is running
|
40
samples/tosca-templates/vnfd/test_tosca_vnfc.yaml
Normal file
40
samples/tosca-templates/vnfd/test_tosca_vnfc.yaml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
|
||||||
|
metadata:
|
||||||
|
template_name: sample-tosca-vnfd-for-vnfc
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
node_templates:
|
||||||
|
firewall_vnfc:
|
||||||
|
type: tosca.nodes.nfv.VNFC.Tacker
|
||||||
|
requirements:
|
||||||
|
- host: VDU1
|
||||||
|
interfaces:
|
||||||
|
Standard:
|
||||||
|
create: install_vnfc.sh
|
||||||
|
|
||||||
|
VDU1:
|
||||||
|
type: tosca.nodes.nfv.VDU.Tacker
|
||||||
|
properties:
|
||||||
|
image: fedora-software-config
|
||||||
|
flavor: m1.small
|
||||||
|
mgmt_driver: noop
|
||||||
|
key_name: stack_key
|
||||||
|
config: |
|
||||||
|
param0: key1
|
||||||
|
param1: key2
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: tosca.nodes.nfv.CP.Tacker
|
||||||
|
properties:
|
||||||
|
management: true
|
||||||
|
anti_spoofing_protection: false
|
||||||
|
requirements:
|
||||||
|
- virtualLink:
|
||||||
|
node: VL1
|
||||||
|
- virtualBinding:
|
||||||
|
node: VDU1
|
||||||
|
VL1:
|
||||||
|
type: tosca.nodes.nfv.VL
|
||||||
|
properties:
|
||||||
|
network_name: net1
|
||||||
|
vendor: Tacker
|
@ -0,0 +1,63 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
|
||||||
|
metadata:
|
||||||
|
template_name: sample-tosca-vnfd-for-vnfc
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
node_templates:
|
||||||
|
firewall_vnfc:
|
||||||
|
type: tosca.nodes.nfv.VNFC.Tacker
|
||||||
|
requirements:
|
||||||
|
- host: VDU1
|
||||||
|
- host: VDU2
|
||||||
|
interfaces:
|
||||||
|
Standard:
|
||||||
|
create: /home/bharatht/install_vnfc.sh
|
||||||
|
|
||||||
|
VDU1:
|
||||||
|
type: tosca.nodes.nfv.VDU.Tacker
|
||||||
|
properties:
|
||||||
|
image: fedora-software-config
|
||||||
|
flavor: m1.small
|
||||||
|
mgmt_driver: noop
|
||||||
|
key_name: stack_key
|
||||||
|
config: |
|
||||||
|
param0: key1
|
||||||
|
param1: key2
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: tosca.nodes.nfv.CP.Tacker
|
||||||
|
properties:
|
||||||
|
management: true
|
||||||
|
anti_spoofing_protection: false
|
||||||
|
requirements:
|
||||||
|
- virtualLink:
|
||||||
|
node: VL1
|
||||||
|
- virtualBinding:
|
||||||
|
node: VDU1
|
||||||
|
VDU2:
|
||||||
|
type: tosca.nodes.nfv.VDU.Tacker
|
||||||
|
properties:
|
||||||
|
image: fedora-software-config
|
||||||
|
flavor: m1.small
|
||||||
|
mgmt_driver: noop
|
||||||
|
key_name: stack_key
|
||||||
|
config: |
|
||||||
|
param0: key1
|
||||||
|
param1: key2
|
||||||
|
|
||||||
|
CP2:
|
||||||
|
type: tosca.nodes.nfv.CP.Tacker
|
||||||
|
properties:
|
||||||
|
management: true
|
||||||
|
anti_spoofing_protection: false
|
||||||
|
requirements:
|
||||||
|
- virtualLink:
|
||||||
|
node: VL1
|
||||||
|
- virtualBinding:
|
||||||
|
node: VDU2
|
||||||
|
|
||||||
|
VL1:
|
||||||
|
type: tosca.nodes.nfv.VL
|
||||||
|
properties:
|
||||||
|
network_name: private
|
||||||
|
vendor: Tacker
|
@ -13,6 +13,7 @@
|
|||||||
POLICY_ALARMING = 'tosca.policies.tacker.Alarming'
|
POLICY_ALARMING = 'tosca.policies.tacker.Alarming'
|
||||||
DEFAULT_ALARM_ACTIONS = ['respawn', 'log', 'log_and_kill', 'notify']
|
DEFAULT_ALARM_ACTIONS = ['respawn', 'log', 'log_and_kill', 'notify']
|
||||||
VNF_CIRROS_CREATE_TIMEOUT = 300
|
VNF_CIRROS_CREATE_TIMEOUT = 300
|
||||||
|
VNFC_CREATE_TIMEOUT = 600
|
||||||
VNF_CIRROS_DELETE_TIMEOUT = 300
|
VNF_CIRROS_DELETE_TIMEOUT = 300
|
||||||
VNF_CIRROS_DEAD_TIMEOUT = 250
|
VNF_CIRROS_DEAD_TIMEOUT = 250
|
||||||
ACTIVE_SLEEP_TIME = 3
|
ACTIVE_SLEEP_TIME = 3
|
||||||
|
2
tacker/tests/etc/samples/install_vnfc.sh
Normal file
2
tacker/tests/etc/samples/install_vnfc.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
echo "Successfully installed VNFC" > /tacker
|
42
tacker/tests/etc/samples/sample_tosca_vnfc.yaml
Normal file
42
tacker/tests/etc/samples/sample_tosca_vnfc.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
|
||||||
|
metadata:
|
||||||
|
template_name: sample-tosca-vnfd-for-vnfc
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
node_templates:
|
||||||
|
firewall_vnfc:
|
||||||
|
type: tosca.nodes.nfv.VNFC.Tacker
|
||||||
|
requirements:
|
||||||
|
- host: VDU1
|
||||||
|
interfaces:
|
||||||
|
Standard:
|
||||||
|
create: install_vnfc.sh
|
||||||
|
|
||||||
|
VDU1:
|
||||||
|
type: tosca.nodes.nfv.VDU.Tacker
|
||||||
|
properties:
|
||||||
|
flavor: m1.small
|
||||||
|
mgmt_driver: noop
|
||||||
|
config: |
|
||||||
|
param0: key1
|
||||||
|
param1: key2
|
||||||
|
artifacts:
|
||||||
|
fedora:
|
||||||
|
type: tosca.artifacts.Deployment.Image.VM
|
||||||
|
file: https://github.com/bharaththiruveedula/dotfiles/raw/master/fedora-sw.qcow2
|
||||||
|
CP1:
|
||||||
|
type: tosca.nodes.nfv.CP.Tacker
|
||||||
|
properties:
|
||||||
|
management: true
|
||||||
|
anti_spoofing_protection: false
|
||||||
|
requirements:
|
||||||
|
- virtualLink:
|
||||||
|
node: VL1
|
||||||
|
- virtualBinding:
|
||||||
|
node: VDU1
|
||||||
|
|
||||||
|
VL1:
|
||||||
|
type: tosca.nodes.nfv.VL
|
||||||
|
properties:
|
||||||
|
network_name: private
|
||||||
|
vendor: Tacker
|
110
tacker/tests/functional/vnfm/test_tosca_vnfc.py
Normal file
110
tacker/tests/functional/vnfm/test_tosca_vnfc.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# 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
|
||||||
|
from oslo_config import cfg
|
||||||
|
from toscaparser import tosca_template
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from tacker.common import utils
|
||||||
|
from tacker.plugins.common import constants as evt_constants
|
||||||
|
from tacker.tests import constants
|
||||||
|
from tacker.tests.functional import base
|
||||||
|
from tacker.tests.utils import read_file
|
||||||
|
from tacker.vnfm.tosca import utils as toscautils
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
SOFTWARE_DEPLOYMENT = 'OS::Heat::SoftwareDeployment'
|
||||||
|
|
||||||
|
|
||||||
|
class VnfTestToscaVNFC(base.BaseTackerTest):
|
||||||
|
def test_create_delete_tosca_vnfc(self):
|
||||||
|
input_yaml = read_file('sample_tosca_vnfc.yaml')
|
||||||
|
tosca_dict = yaml.safe_load(input_yaml)
|
||||||
|
path = os.path.abspath(os.path.join(
|
||||||
|
os.path.dirname(__file__), "../../etc/samples"))
|
||||||
|
vnfd_name = 'sample-tosca-vnfc'
|
||||||
|
tosca_dict['topology_template']['node_templates'
|
||||||
|
]['firewall_vnfc'
|
||||||
|
]['interfaces'
|
||||||
|
]['Standard']['create'] = path \
|
||||||
|
+ '/install_vnfc.sh'
|
||||||
|
tosca_arg = {'vnfd': {'name': vnfd_name,
|
||||||
|
'attributes': {'vnfd': tosca_dict}}}
|
||||||
|
|
||||||
|
# Create vnfd with tosca template
|
||||||
|
vnfd_instance = self.client.create_vnfd(body=tosca_arg)
|
||||||
|
self.assertIsNotNone(vnfd_instance)
|
||||||
|
|
||||||
|
# Create vnf with vnfd_id
|
||||||
|
vnfd_id = vnfd_instance['vnfd']['id']
|
||||||
|
vnf_arg = {'vnf': {'vnfd_id': vnfd_id, 'name':
|
||||||
|
"test_tosca_vnfc"}}
|
||||||
|
vnf_instance = self.client.create_vnf(body=vnf_arg)
|
||||||
|
|
||||||
|
vnf_id = vnf_instance['vnf']['id']
|
||||||
|
self.wait_until_vnf_active(vnf_id,
|
||||||
|
constants.VNFC_CREATE_TIMEOUT,
|
||||||
|
constants.ACTIVE_SLEEP_TIME)
|
||||||
|
self.assertEqual('ACTIVE',
|
||||||
|
self.client.show_vnf(vnf_id)['vnf']['status'])
|
||||||
|
self.validate_vnf_instance(vnfd_instance, vnf_instance)
|
||||||
|
|
||||||
|
self.verify_vnf_crud_events(
|
||||||
|
vnf_id, evt_constants.RES_EVT_CREATE, evt_constants.PENDING_CREATE,
|
||||||
|
cnt=2)
|
||||||
|
self.verify_vnf_crud_events(
|
||||||
|
vnf_id, evt_constants.RES_EVT_CREATE, evt_constants.ACTIVE)
|
||||||
|
|
||||||
|
# Validate mgmt_url with input yaml file
|
||||||
|
mgmt_url = self.client.show_vnf(vnf_id)['vnf']['mgmt_url']
|
||||||
|
self.assertIsNotNone(mgmt_url)
|
||||||
|
mgmt_dict = yaml.load(str(mgmt_url))
|
||||||
|
|
||||||
|
input_dict = yaml.load(input_yaml)
|
||||||
|
toscautils.updateimports(input_dict)
|
||||||
|
|
||||||
|
tosca = tosca_template.ToscaTemplate(parsed_params={}, a_file=False,
|
||||||
|
yaml_dict_tpl=input_dict)
|
||||||
|
|
||||||
|
vdus = toscautils.findvdus(tosca)
|
||||||
|
|
||||||
|
self.assertEqual(len(vdus), len(mgmt_dict.keys()))
|
||||||
|
for vdu in vdus:
|
||||||
|
self.assertIsNotNone(mgmt_dict[vdu.name])
|
||||||
|
self.assertEqual(True, utils.is_valid_ipv4(mgmt_dict[vdu.name]))
|
||||||
|
|
||||||
|
# Check the status of SoftwareDeployment
|
||||||
|
heat_stack_id = self.client.show_vnf(vnf_id)['vnf']['instance_id']
|
||||||
|
resource_types = self.h_client.resources
|
||||||
|
resources = resource_types.list(stack_id=heat_stack_id)
|
||||||
|
for resource in resources:
|
||||||
|
resource = resource.to_dict()
|
||||||
|
if resource['resource_type'] == \
|
||||||
|
SOFTWARE_DEPLOYMENT:
|
||||||
|
self.assertEqual('CREATE_COMPLETE',
|
||||||
|
resource['resource_status'])
|
||||||
|
break
|
||||||
|
|
||||||
|
# Delete vnf_instance with vnf_id
|
||||||
|
try:
|
||||||
|
self.client.delete_vnf(vnf_id)
|
||||||
|
except Exception:
|
||||||
|
assert False, "vnf Delete of test_vnf_with_multiple_vdus failed"
|
||||||
|
|
||||||
|
self.wait_until_vnf_delete(vnf_id,
|
||||||
|
constants.VNF_CIRROS_DELETE_TIMEOUT)
|
||||||
|
self.verify_vnf_crud_events(vnf_id, evt_constants.RES_EVT_DELETE,
|
||||||
|
evt_constants.PENDING_DELETE, cnt=2)
|
||||||
|
|
||||||
|
# Delete vnfd_instance
|
||||||
|
self.addCleanup(self.client.delete_vnfd, vnfd_id)
|
@ -0,0 +1,36 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
parameters: {}
|
||||||
|
resources:
|
||||||
|
VDU1:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
config_drive: false
|
||||||
|
flavor: m1.small
|
||||||
|
image: Fedora
|
||||||
|
networks:
|
||||||
|
- port:
|
||||||
|
get_resource: CP1
|
||||||
|
user_data_format: SOFTWARE_CONFIG
|
||||||
|
CP1:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: existing_network_1
|
||||||
|
port_security_enabled: false
|
||||||
|
firewall_vnfc_create_config:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
config: 'echo "Test case for Tacker";'
|
||||||
|
group: script
|
||||||
|
firewall_vnfc_create_deploy:
|
||||||
|
type: OS::Heat::SoftwareDeployment
|
||||||
|
properties:
|
||||||
|
config: {get_resource: firewall_vnfc_create_config}
|
||||||
|
server: {get_resource: VDU1}
|
||||||
|
depends_on:
|
||||||
|
- VDU1
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
mgmt_ip-VDU1:
|
||||||
|
value:
|
||||||
|
get_attr: [CP1, fixed_ips, 0, ip_address]
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
|
||||||
|
metadata:
|
||||||
|
template_name: sample-tosca-vnfd-for-vnfc
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
node_templates:
|
||||||
|
firewall_vnfc:
|
||||||
|
type: tosca.nodes.nfv.VNFC.Tacker
|
||||||
|
requirements:
|
||||||
|
- host: VDU1
|
||||||
|
interfaces:
|
||||||
|
Standard:
|
||||||
|
create: install_vnfc.sh
|
||||||
|
|
||||||
|
VDU1:
|
||||||
|
type: tosca.nodes.nfv.VDU.Tacker
|
||||||
|
properties:
|
||||||
|
image: Fedora
|
||||||
|
flavor: m1.small
|
||||||
|
mgmt_driver: noop
|
||||||
|
config: |
|
||||||
|
param0: key1
|
||||||
|
param1: key2
|
||||||
|
|
||||||
|
CP1:
|
||||||
|
type: tosca.nodes.nfv.CP.Tacker
|
||||||
|
properties:
|
||||||
|
management: true
|
||||||
|
anti_spoofing_protection: false
|
||||||
|
requirements:
|
||||||
|
- virtualLink:
|
||||||
|
node: VL1
|
||||||
|
- virtualBinding:
|
||||||
|
node: VDU1
|
||||||
|
VL1:
|
||||||
|
type: tosca.nodes.nfv.VL
|
||||||
|
properties:
|
||||||
|
network_name: net1
|
||||||
|
vendor: Tacker
|
@ -39,7 +39,7 @@ OPTS = [
|
|||||||
help=_("Number of attempts to retry for stack"
|
help=_("Number of attempts to retry for stack"
|
||||||
" creation/deletion")),
|
" creation/deletion")),
|
||||||
cfg.IntOpt('stack_retry_wait',
|
cfg.IntOpt('stack_retry_wait',
|
||||||
default=5,
|
default=10,
|
||||||
help=_("Wait time (in seconds) between consecutive stack"
|
help=_("Wait time (in seconds) between consecutive stack"
|
||||||
" create/delete retries")),
|
" create/delete retries")),
|
||||||
]
|
]
|
||||||
|
@ -257,3 +257,9 @@ node_types:
|
|||||||
required: true
|
required: true
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: tosca.nfv.datatypes.pathType
|
type: tosca.nfv.datatypes.pathType
|
||||||
|
tosca.nodes.nfv.VNFC.Tacker:
|
||||||
|
derived_from: tosca.nodes.SoftwareComponent
|
||||||
|
requirements:
|
||||||
|
- host:
|
||||||
|
node: tosca.nodes.nfv.VDU.Tacker
|
||||||
|
relationship: tosca.relationships.HostedOn
|
||||||
|
@ -35,6 +35,7 @@ TACKERVDU = 'tosca.nodes.nfv.VDU.Tacker'
|
|||||||
TOSCA_BINDS_TO = 'tosca.relationships.network.BindsTo'
|
TOSCA_BINDS_TO = 'tosca.relationships.network.BindsTo'
|
||||||
VDU = 'tosca.nodes.nfv.VDU'
|
VDU = 'tosca.nodes.nfv.VDU'
|
||||||
IMAGE = 'tosca.artifacts.Deployment.Image.VM'
|
IMAGE = 'tosca.artifacts.Deployment.Image.VM'
|
||||||
|
HEAT_SOFTWARE_CONFIG = 'OS::Heat::SoftwareConfig'
|
||||||
OS_RESOURCES = {
|
OS_RESOURCES = {
|
||||||
'flavor': 'get_flavor_dict',
|
'flavor': 'get_flavor_dict',
|
||||||
'image': 'get_image_dict'
|
'image': 'get_image_dict'
|
||||||
@ -254,6 +255,13 @@ def post_process_heat_template(heat_tpl, mgmt_ports, metadata,
|
|||||||
metadata_dict
|
metadata_dict
|
||||||
|
|
||||||
add_resources_tpl(heat_dict, res_tpl)
|
add_resources_tpl(heat_dict, res_tpl)
|
||||||
|
for res in heat_dict["resources"].values():
|
||||||
|
if not res['type'] == HEAT_SOFTWARE_CONFIG:
|
||||||
|
continue
|
||||||
|
config = res["properties"]["config"]
|
||||||
|
if 'get_file' in config:
|
||||||
|
res["properties"]["config"] = open(config["get_file"]).read()
|
||||||
|
|
||||||
if unsupported_res_prop:
|
if unsupported_res_prop:
|
||||||
convert_unsupported_res_prop(heat_dict, unsupported_res_prop)
|
convert_unsupported_res_prop(heat_dict, unsupported_res_prop)
|
||||||
return yaml.dump(heat_dict)
|
return yaml.dump(heat_dict)
|
||||||
|
Loading…
Reference in New Issue
Block a user