aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Collins <rbtcollins@hp.com>2014-02-20 17:14:43 +1300
committerRobert Collins <rbtcollins@hp.com>2014-02-21 11:13:10 +1300
commit70494ab2cb75e7f7ca83a169eac823b22eb6e180 (patch)
treea39f0002c980c07f8b5b283bde414d2720f8a95e
parent8403b8ae9fd7eef452fe7cd96df814e195fea916 (diff)
Add a Merge::Map feature.
We need to scatter gather in a few situations - determining rabbit cluster membership, galera membership and configuring hosts for Nova to permit live migration (which requires host->host communication). This patch is a proof of concept for an eventual heat feature, expressed in merge.py. The example given should work for actual use, but I'll deliver that change separately. Change-Id: I68e9b2471866810cc698ca3ea28ddf5bb1688d7b
-rw-r--r--examples/scale_map.yaml55
-rw-r--r--examples/scale_map2.yaml54
-rw-r--r--examples/scale_map_result.yaml235
-rwxr-xr-xtest_merge.bash1
-rw-r--r--tripleo_heat_merge/merge.py22
5 files changed, 367 insertions, 0 deletions
diff --git a/examples/scale_map.yaml b/examples/scale_map.yaml
new file mode 100644
index 00000000..7c79ad57
--- /dev/null
+++ b/examples/scale_map.yaml
@@ -0,0 +1,55 @@
+Resources:
+ ComputeUser:
+ Type: AWS::IAM::User
+ Properties:
+ Policies: [ { Ref: ComputeAccessPolicy } ]
+ GlobalAccessPolicy:
+ Type: OS::Heat::AccessPolicy
+ NovaCompute0Key:
+ Type: FileInclude
+ Path: examples/scale_map2.yaml
+ SubKey: Resources.NovaCompute0Key
+ NovaCompute0CompletionCondition:
+ Type: FileInclude
+ Path: examples/scale_map2.yaml
+ SubKey: Resources.NovaCompute0CompletionCondition
+ NovaCompute0CompletionHandle:
+ Type: FileInclude
+ Path: examples/scale_map2.yaml
+ SubKey: Resources.NovaCompute0CompletionHandle
+ NovaCompute0Config:
+ Type: FileInclude
+ Path: examples/scale_map2.yaml
+ SubKey: Resources.NovaCompute0Config
+ Parameters:
+ AllHosts:
+ Fn::Join:
+ - "\n"
+ - Merge::Map:
+ NovaCompute0:
+ Fn::Join:
+ - ' '
+ - - Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute0
+ - networks
+ - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute0
+ - show
+ - Fn::Join:
+ - '.'
+ - - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute0
+ - show
+ - 'local'
+ NovaCompute0:
+ Type: FileInclude
+ Path: examples/scale_map2.yaml
+ SubKey: Resources.NovaCompute0
diff --git a/examples/scale_map2.yaml b/examples/scale_map2.yaml
new file mode 100644
index 00000000..7e5c839c
--- /dev/null
+++ b/examples/scale_map2.yaml
@@ -0,0 +1,54 @@
+HeatTemplateFormatVersion: '2012-12-12'
+Parameters:
+ AllHosts:
+ Type: String
+ ComputeImage:
+ Type: String
+Resources:
+ ComputeAccessPolicy:
+ Type: OS::Heat::AccessPolicy
+ Properties:
+ AllowedResources: [ NovaCompute0 ]
+ NovaCompute0Key:
+ Type: AWS::IAM::AccessKey
+ Properties:
+ UserName:
+ Ref: ComputeUser
+ NovaCompute0CompletionCondition:
+ Type: AWS::CloudFormation::WaitCondition
+ DependsOn: notcompute
+ Properties:
+ Handle: {Ref: NovaCompute0CompletionHandle}
+ Count: '1'
+ Timeout: '1800'
+ NovaCompute0CompletionHandle:
+ Type: AWS::CloudFormation::WaitConditionHandle
+ NovaCompute0:
+ Type: OS::Nova::Server
+ Properties:
+ image:
+ Ref: ComputeImage
+ Metadata:
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute0Key
+ secret_access_key:
+ Fn::GetAtt: [ NovaCompute0Key, SecretAccessKey ]
+ stack_name: {Ref: 'AWS::StackName'}
+ path: NovaCompute0Config.Metadata
+ NovaCompute0Config:
+ Type: AWS::AutoScaling::LaunchConfiguration
+ Metadata:
+ completion-handle:
+ Ref: NovaCompute0CompletionHandle
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute0Key
+ secret_access_key:
+ Fn::GetAtt: [ NovaCompute0Key, SecretAccessKey ]
+ stack_name: {Ref: 'AWS::StackName'}
+ path: NovaCompute0Config.Metadata
+ hosts:
+ Ref: AllHosts
diff --git a/examples/scale_map_result.yaml b/examples/scale_map_result.yaml
new file mode 100644
index 00000000..5fa02291
--- /dev/null
+++ b/examples/scale_map_result.yaml
@@ -0,0 +1,235 @@
+Description: examples/scale_map.yaml
+HeatTemplateFormatVersion: '2012-12-12'
+Resources:
+ ComputeUser:
+ Properties:
+ Policies:
+ - Ref: ComputeAccessPolicy
+ Type: AWS::IAM::User
+ GlobalAccessPolicy:
+ Type: OS::Heat::AccessPolicy
+ NovaCompute0:
+ Metadata:
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute0Key
+ path: NovaCompute0Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute0Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ Properties:
+ image:
+ Ref: ComputeImage
+ Type: OS::Nova::Server
+ NovaCompute0CompletionCondition:
+ DependsOn: notcompute
+ Properties:
+ Count: '1'
+ Handle:
+ Ref: NovaCompute0CompletionHandle
+ Timeout: '1800'
+ Type: AWS::CloudFormation::WaitCondition
+ NovaCompute0CompletionHandle:
+ Type: AWS::CloudFormation::WaitConditionHandle
+ NovaCompute0Config:
+ Metadata:
+ completion-handle:
+ Ref: NovaCompute0CompletionHandle
+ hosts:
+ Fn::Join:
+ - '
+
+ '
+ - - Fn::Join:
+ - ' '
+ - - Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute0
+ - networks
+ - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute0
+ - show
+ - Fn::Join:
+ - .
+ - - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute0
+ - show
+ - local
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute0Key
+ path: NovaCompute0Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute0Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ Type: AWS::AutoScaling::LaunchConfiguration
+ NovaCompute0Key:
+ Properties:
+ UserName:
+ Ref: ComputeUser
+ Type: AWS::IAM::AccessKey
+ NovaCompute1:
+ Metadata:
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute1Key
+ path: NovaCompute1Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute1Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ Properties:
+ image:
+ Ref: ComputeImage
+ Type: OS::Nova::Server
+ NovaCompute1CompletionCondition:
+ DependsOn: notcompute
+ Properties:
+ Count: '1'
+ Handle:
+ Ref: NovaCompute1CompletionHandle
+ Timeout: '1800'
+ Type: AWS::CloudFormation::WaitCondition
+ NovaCompute1CompletionHandle:
+ Type: AWS::CloudFormation::WaitConditionHandle
+ NovaCompute1Config:
+ Metadata:
+ completion-handle:
+ Ref: NovaCompute1CompletionHandle
+ hosts:
+ Fn::Join:
+ - '
+
+ '
+ - - Fn::Join:
+ - ' '
+ - - Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute1
+ - networks
+ - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute1
+ - show
+ - Fn::Join:
+ - .
+ - - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute1
+ - show
+ - local
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute1Key
+ path: NovaCompute1Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute1Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ Type: AWS::AutoScaling::LaunchConfiguration
+ NovaCompute1Key:
+ Properties:
+ UserName:
+ Ref: ComputeUser
+ Type: AWS::IAM::AccessKey
+ NovaCompute2:
+ Metadata:
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute2Key
+ path: NovaCompute2Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute2Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ Properties:
+ image:
+ Ref: ComputeImage
+ Type: OS::Nova::Server
+ NovaCompute2CompletionCondition:
+ DependsOn: notcompute
+ Properties:
+ Count: '1'
+ Handle:
+ Ref: NovaCompute2CompletionHandle
+ Timeout: '1800'
+ Type: AWS::CloudFormation::WaitCondition
+ NovaCompute2CompletionHandle:
+ Type: AWS::CloudFormation::WaitConditionHandle
+ NovaCompute2Config:
+ Metadata:
+ completion-handle:
+ Ref: NovaCompute2CompletionHandle
+ hosts:
+ Fn::Join:
+ - '
+
+ '
+ - - Fn::Join:
+ - ' '
+ - - Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute2
+ - networks
+ - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute2
+ - show
+ - Fn::Join:
+ - .
+ - - Fn::Select:
+ - name
+ - Fn::GetAtt:
+ - NovaCompute2
+ - show
+ - local
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute2Key
+ path: NovaCompute2Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute2Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ Type: AWS::AutoScaling::LaunchConfiguration
+ NovaCompute2Key:
+ Properties:
+ UserName:
+ Ref: ComputeUser
+ Type: AWS::IAM::AccessKey
diff --git a/test_merge.bash b/test_merge.bash
index f9bc7fb6..19d75377 100755
--- a/test_merge.bash
+++ b/test_merge.bash
@@ -29,6 +29,7 @@ run_test "python $merge_py examples/source2.yaml" examples/source2_lib_result.ya
run_test "python $merge_py examples/source_include_subkey.yaml" examples/source_include_subkey_result.yaml
run_test "python $merge_py examples/launchconfig1.yaml examples/launchconfig2.yaml" examples/launchconfig_result.yaml
run_test "python $merge_py --scale NovaCompute=3 examples/scale1.yaml" examples/scale_result.yaml
+run_test "python $merge_py --scale NovaCompute=3 examples/scale_map.yaml" examples/scale_map_result.yaml
echo
trap - EXIT
exit $fail
diff --git a/tripleo_heat_merge/merge.py b/tripleo_heat_merge/merge.py
index dd254ab4..0de27e24 100644
--- a/tripleo_heat_merge/merge.py
+++ b/tripleo_heat_merge/merge.py
@@ -4,6 +4,27 @@ import yaml
import argparse
+def apply_maps(template):
+ """Apply Merge::Map within template.
+
+ Any dict {'Merge::Map': {'Foo': 'Bar', 'Baz': 'Quux'}}
+ will resolve to ['Bar', 'Quux'] - that is a dict with key
+ 'Merge::Map' is replaced entirely by that dict['Merge::Map'].values().
+ """
+ if isinstance(template, dict):
+ if 'Merge::Map' in template:
+ return sorted(
+ apply_maps(value) for value in template['Merge::Map'].values()
+ )
+ else:
+ return dict((key, apply_maps(value))
+ for key, value in template.items())
+ elif isinstance(template, list):
+ return [apply_maps(item) for item in template]
+ else:
+ return template
+
+
def apply_scaling(template, scaling, in_copies=None):
"""Apply a set of scaling operations to template.
@@ -301,6 +322,7 @@ def merge(templates, master_role=None, slave_roles=None,
end_template['Resources'][r] = rbody
end_template = apply_scaling(end_template, scaling)
+ end_template = apply_maps(end_template)
def fix_ref(item, old, new):
if isinstance(item, dict):