aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--block-storage.yaml6
-rw-r--r--examples/scale1.yaml30
-rw-r--r--examples/scale2.yaml66
-rw-r--r--examples/scale_result.yaml190
-rw-r--r--examples/source2_lib_result.yaml4
-rw-r--r--examples/source_include_subkey_result.yaml4
-rw-r--r--examples/source_lib_result.yaml4
-rw-r--r--notcompute.yaml12
-rw-r--r--nova-compute-instance.yaml20
-rw-r--r--overcloud-source.yaml89
-rw-r--r--ssl-source.yaml2
-rw-r--r--swift-source.yaml4
-rwxr-xr-xtest_merge.bash3
-rw-r--r--tripleo_heat_merge/merge.py141
-rw-r--r--undercloud-bm-source.yaml1
-rw-r--r--undercloud-source.yaml22
-rw-r--r--undercloud-vm-source.yaml1
18 files changed, 507 insertions, 96 deletions
diff --git a/Makefile b/Makefile
index d7fc543a..2c9c2c0e 100644
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,10 @@ overcloud_source_deps = nova-compute-instance.yaml
all: $(generated_templates)
+# Note that COMPUTESCALE is not a physical dep - 'make overcloud.yaml' won't do
+# the right thing if you change COMPUTESCALE from one run to another.
overcloud.yaml: overcloud-source.yaml swift-source.yaml ssl-source.yaml $(overcloud_source_deps)
- python ./tripleo_heat_merge/merge.py overcloud-source.yaml swift-source.yaml ssl-source.yaml > $@.tmp
+ python ./tripleo_heat_merge/merge.py --scale NovaCompute=$${COMPUTESCALE:-'1'} overcloud-source.yaml swift-source.yaml ssl-source.yaml > $@.tmp
mv $@.tmp $@
overcloud-with-block-storage.yaml: overcloud-source.yaml nova-compute-instance.yaml swift-source.yaml block-storage.yaml
diff --git a/block-storage.yaml b/block-storage.yaml
index 9959bdbc..48496356 100644
--- a/block-storage.yaml
+++ b/block-storage.yaml
@@ -6,13 +6,13 @@ Parameters:
Default: overcloud-cinder-volume
KeystoneHost:
Type: String
- Default: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
+ Default: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
MySQLHost:
Type: String
- Default: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
+ Default: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
RabbitHost:
Type: String
- Default: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
+ Default: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
RabbitPassword:
Type: String
Default: "guest"
diff --git a/examples/scale1.yaml b/examples/scale1.yaml
new file mode 100644
index 00000000..c0a0763d
--- /dev/null
+++ b/examples/scale1.yaml
@@ -0,0 +1,30 @@
+Resources:
+ ComputeUser:
+ Type: AWS::IAM::User
+ Properties:
+ Policies: [ { Ref: ComputeAccessPolicy } ]
+ GlobalAccessPolicy:
+ Type: OS::Heat::AccessPolicy
+ NovaCompute0Key:
+ Type: FileInclude
+ Path: examples/scale2.yaml
+ SubKey: Resources.NovaCompute0Key
+ NovaCompute0CompletionCondition:
+ Type: FileInclude
+ Path: examples/scale2.yaml
+ SubKey: Resources.NovaCompute0CompletionCondition
+ NovaCompute0CompletionHandle:
+ Type: FileInclude
+ Path: examples/scale2.yaml
+ SubKey: Resources.NovaCompute0CompletionHandle
+ NovaCompute0Config:
+ Type: FileInclude
+ Path: examples/scale2.yaml
+ SubKey: Resources.NovaCompute0Config
+ Parameters:
+ ComputeImage: "123"
+ RabbitPassword: "guest"
+ NovaCompute0:
+ Type: FileInclude
+ Path: examples/scale2.yaml
+ SubKey: Resources.NovaCompute0
diff --git a/examples/scale2.yaml b/examples/scale2.yaml
new file mode 100644
index 00000000..d1a81fe5
--- /dev/null
+++ b/examples/scale2.yaml
@@ -0,0 +1,66 @@
+HeatTemplateFormatVersion: '2012-12-12'
+Parameters:
+ ComputeImage:
+ Type: String
+ RabbitPassword:
+ Type: String
+ NoEcho: true
+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
+ neutron:
+ ovs:
+ local_ip:
+ Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute0
+ - networks
+ rabbit:
+ password: {Ref: RabbitPassword}
+
diff --git a/examples/scale_result.yaml b/examples/scale_result.yaml
new file mode 100644
index 00000000..f22d864e
--- /dev/null
+++ b/examples/scale_result.yaml
@@ -0,0 +1,190 @@
+Description: examples/scale1.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
+ neutron:
+ ovs:
+ local_ip:
+ Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute0
+ - networks
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute0Key
+ path: NovaCompute0Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute0Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ rabbit:
+ password: guest
+ 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
+ neutron:
+ ovs:
+ local_ip:
+ Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute1
+ - networks
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute1Key
+ path: NovaCompute1Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute1Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ rabbit:
+ password: guest
+ 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
+ neutron:
+ ovs:
+ local_ip:
+ Fn::Select:
+ - 0
+ - Fn::Select:
+ - ctlplane
+ - Fn::GetAtt:
+ - NovaCompute2
+ - networks
+ os-collect-config:
+ cfn:
+ access_key_id:
+ Ref: NovaCompute2Key
+ path: NovaCompute2Config.Metadata
+ secret_access_key:
+ Fn::GetAtt:
+ - NovaCompute2Key
+ - SecretAccessKey
+ stack_name:
+ Ref: AWS::StackName
+ rabbit:
+ password: guest
+ Type: AWS::AutoScaling::LaunchConfiguration
+ NovaCompute2Key:
+ Properties:
+ UserName:
+ Ref: ComputeUser
+ Type: AWS::IAM::AccessKey
diff --git a/examples/source2_lib_result.yaml b/examples/source2_lib_result.yaml
index d4b19768..172dce0f 100644
--- a/examples/source2_lib_result.yaml
+++ b/examples/source2_lib_result.yaml
@@ -1,7 +1,7 @@
Description: examples/source2.yaml
HeatTemplateFormatVersion: '2012-12-12'
Parameters:
- GenericBImage:
+ BImage:
Type: String
ImportantValue:
Default: a_default
@@ -12,5 +12,5 @@ Resources:
my_meta: Foo
Properties:
image:
- Ref: GenericBImage
+ Ref: BImage
Type: OS::Nova::Server
diff --git a/examples/source_include_subkey_result.yaml b/examples/source_include_subkey_result.yaml
index f5ff80ea..641e8148 100644
--- a/examples/source_include_subkey_result.yaml
+++ b/examples/source_include_subkey_result.yaml
@@ -1,7 +1,7 @@
Description: examples/source_include_subkey.yaml
HeatTemplateFormatVersion: '2012-12-12'
Parameters:
- GenericBImage:
+ Foo:
Type: String
Resources:
GenericB:
@@ -10,5 +10,5 @@ Resources:
Ref: ImportantValue
Properties:
image:
- Ref: GenericBImage
+ Ref: Foo
Type: OS::Nova::Server
diff --git a/examples/source_lib_result.yaml b/examples/source_lib_result.yaml
index a165cabf..ceb8a321 100644
--- a/examples/source_lib_result.yaml
+++ b/examples/source_lib_result.yaml
@@ -1,14 +1,14 @@
Description: examples/source.yaml
HeatTemplateFormatVersion: '2012-12-12'
Parameters:
- AImage: null
Default: my_image
+ SourceImage: null
Type: String
Resources:
A:
Properties:
image:
- Ref: AImage
+ Ref: SourceImage
Type: OS::Nova::Server
B:
Metadata:
diff --git a/notcompute.yaml b/notcompute.yaml
index ef339361..fe66f3bb 100644
--- a/notcompute.yaml
+++ b/notcompute.yaml
@@ -78,9 +78,9 @@ Resources:
AccessPolicy:
Properties:
AllowedResources:
- - notcompute
+ - notCompute0
Type: OS::Heat::AccessPolicy
- Key:
+ notCompute0Key:
Properties:
UserName:
Ref: User
@@ -90,7 +90,7 @@ Resources:
Policies:
- Ref: AccessPolicy
Type: AWS::IAM::User
- notcompute:
+ notCompute0:
Metadata:
OpenStack::ImageBuilder::Elements:
- nova-api
@@ -136,12 +136,12 @@ Resources:
- {Ref: HeatDBPassword}
- '@127.0.0.1/heat'
access_key_id:
- Ref: Key
+ Ref: notCompute0Key
refresh:
- - resource: notcompute
+ - resource: notCompute0
secret_key:
Fn::GetAtt:
- - Key
+ - notCompute0Key
- SecretAccessKey
stack:
name:
diff --git a/nova-compute-instance.yaml b/nova-compute-instance.yaml
index 229615ad..4b6a8a05 100644
--- a/nova-compute-instance.yaml
+++ b/nova-compute-instance.yaml
@@ -83,19 +83,19 @@ Resources:
Type: AWS::IAM::User
Properties:
Policies: [ { Ref: ComputeAccessPolicy } ]
- ComputeKey:
+ NovaCompute0Key:
Type: AWS::IAM::AccessKey
Properties:
UserName:
Ref: ComputeUser
- CompletionCondition:
+ NovaCompute0CompletionCondition:
Type: AWS::CloudFormation::WaitCondition
- DependsOn: notcompute
+ DependsOn: notCompute0
Properties:
- Handle: {Ref: CompletionHandle}
+ Handle: {Ref: NovaCompute0CompletionHandle}
Count: '1'
Timeout: '1800'
- CompletionHandle:
+ NovaCompute0CompletionHandle:
Type: AWS::CloudFormation::WaitConditionHandle
NovaCompute0:
Type: OS::Nova::Server
@@ -110,9 +110,9 @@ Resources:
os-collect-config:
cfn:
access_key_id:
- Ref: ComputeKey
+ Ref: NovaCompute0Key
secret_access_key:
- Fn::GetAtt: [ ComputeKey, SecretAccessKey ]
+ Fn::GetAtt: [ NovaCompute0Key, SecretAccessKey ]
stack_name: {Ref: 'AWS::StackName'}
path: NovaCompute0Config.Metadata
OpenStack::ImageBuilder::Elements: [ nova-compute ]
@@ -123,13 +123,13 @@ Resources:
ImageId: '0'
Metadata:
completion-handle:
- Ref: CompletionHandle
+ Ref: NovaCompute0CompletionHandle
os-collect-config:
cfn:
access_key_id:
- Ref: ComputeKey
+ Ref: NovaCompute0Key
secret_access_key:
- Fn::GetAtt: [ ComputeKey, SecretAccessKey ]
+ Fn::GetAtt: [ NovaCompute0Key, SecretAccessKey ]
stack_name: {Ref: 'AWS::StackName'}
path: NovaCompute0Config.Metadata
nova:
diff --git a/overcloud-source.yaml b/overcloud-source.yaml
index 358de7d6..78ce4aa0 100644
--- a/overcloud-source.yaml
+++ b/overcloud-source.yaml
@@ -107,8 +107,8 @@ Resources:
AccessPolicy:
Properties:
AllowedResources:
- - notcompute
- - notcomputeConfig
+ - notCompute0
+ - notCompute0Config
Type: OS::Heat::AccessPolicy
ComputeAccessPolicy:
Properties:
@@ -116,25 +116,32 @@ Resources:
- NovaCompute0
- NovaCompute0Config
Type: OS::Heat::AccessPolicy
- Key:
+ notCompute0Key:
Properties:
UserName:
Ref: User
Type: AWS::IAM::AccessKey
- CompletionCondition:
+ notCompute0CompletionCondition:
Type: AWS::CloudFormation::WaitCondition
- DependsOn: notcompute
+ DependsOn: notCompute0
Properties:
- Handle: {Ref: CompletionHandle}
- Count: '2'
+ Handle: {Ref: notCompute0CompletionHandle}
+ Count: '1'
Timeout: '1800'
- CompletionHandle:
+ notCompute0CompletionHandle:
Type: OS::Heat::UpdateWaitConditionHandle
- ComputeKey:
- Properties:
- UserName:
- Ref: ComputeUser
- Type: AWS::IAM::AccessKey
+ NovaCompute0Key:
+ Type: FileInclude
+ Path: nova-compute-instance.yaml
+ SubKey: Resources.NovaCompute0Key
+ NovaCompute0CompletionCondition:
+ Type: FileInclude
+ Path: nova-compute-instance.yaml
+ SubKey: Resources.NovaCompute0CompletionCondition
+ NovaCompute0CompletionHandle:
+ Type: FileInclude
+ Path: nova-compute-instance.yaml
+ SubKey: Resources.NovaCompute0CompletionHandle
ComputeUser:
Properties:
Policies:
@@ -145,14 +152,14 @@ Resources:
Path: nova-compute-instance.yaml
SubKey: Resources.NovaCompute0Config
Parameters:
- NovaApiHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
- KeystoneHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
- RabbitHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
- NeutronHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
- GlanceHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ] }
- NovaDSN: {"Fn::Join": ['', ['mysql://nova:unset@', {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ]}, '/nova']]}
- CeilometerDSN: {"Fn::Join": ['', ['mysql://ceilometer:unset@', {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ]}, '/ceilometer']]}
- NeutronDSN: {"Fn::Join": ['', ['mysql://neutron:unset@', {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notcompute, networks]} ]} ]}, '/neutron']]}
+ NovaApiHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
+ KeystoneHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
+ RabbitHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
+ NeutronHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
+ GlanceHost: {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ] }
+ NovaDSN: {"Fn::Join": ['', ['mysql://nova:unset@', {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ]}, '/nova']]}
+ CeilometerDSN: {"Fn::Join": ['', ['mysql://ceilometer:unset@', {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ]}, '/ceilometer']]}
+ NeutronDSN: {"Fn::Join": ['', ['mysql://neutron:unset@', {"Fn::Select": [ 0, {"Fn::Select": [ "ctlplane", {"Fn::GetAtt": [notCompute0, networks]} ]} ]}, '/neutron']]}
NeutronNetworkType: "gre"
NeutronEnableTunnelling: "True"
NeutronNetworkVLANRanges: ""
@@ -168,7 +175,7 @@ Resources:
Policies:
- Ref: AccessPolicy
Type: AWS::IAM::User
- notcomputeConfig:
+ notCompute0Config:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: '0'
@@ -193,14 +200,14 @@ Resources:
service-password:
Ref: CinderPassword
completion-handle:
- Ref: CompletionHandle
+ Ref: notCompute0CompletionHandle
controller-address:
Fn::Select:
- 0
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
db-password: unset
glance:
@@ -212,7 +219,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
service-password:
Ref: GlancePassword
@@ -235,7 +242,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
- ':8003'
metadata_server_url:
@@ -247,7 +254,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
- ':8000'
waitcondition_server_url:
@@ -259,7 +266,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
- ':8000/v1/waitcondition'
keystone:
@@ -270,7 +277,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
neutron:
host:
@@ -279,7 +286,7 @@ Resources:
- Fn::Select:
- ctlplane
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
metadata_proxy_shared_secret: unset
ovs:
@@ -290,7 +297,7 @@ Resources:
- Fn::Select:
- ctlplane
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
bridge_mappings: {Ref: NeutronBridgeMappings}
public_interface:
@@ -320,7 +327,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
metadata-proxy: true
service-password:
@@ -328,11 +335,11 @@ Resources:
os-collect-config:
cfn:
access_key_id:
- Ref: Key
- path: notcomputeConfig.Metadata
+ Ref: notCompute0Key
+ path: notCompute0Config.Metadata
secret_access_key:
Fn::GetAtt:
- - Key
+ - notCompute0Key
- SecretAccessKey
stack_name:
Ref: AWS::StackName
@@ -343,13 +350,13 @@ Resources:
- Fn::Select:
- ctlplane
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
password: guest
ntp:
servers:
- {server: {Ref: NtpServer}, fudge: "stratum 0"}
- notcompute:
+ notCompute0:
Type: OS::Nova::Server
Properties:
image:
@@ -364,11 +371,11 @@ Resources:
os-collect-config:
cfn:
access_key_id:
- Ref: Key
- path: notcomputeConfig.Metadata
+ Ref: notCompute0Key
+ path: notCompute0Config.Metadata
secret_access_key:
Fn::GetAtt:
- - Key
+ - notCompute0Key
- SecretAccessKey
stack_name:
Ref: AWS::StackName
@@ -384,6 +391,6 @@ Outputs:
- Fn::Select:
- ctlplane
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
- :5000/v2.0/
diff --git a/ssl-source.yaml b/ssl-source.yaml
index 9127555a..4fdd0f3b 100644
--- a/ssl-source.yaml
+++ b/ssl-source.yaml
@@ -11,7 +11,7 @@ Parameters:
Type: String
NoEcho: true
Resources:
- notcomputeConfig:
+ notCompute0Config:
Type: AWS::AutoScaling::LaunchConfiguration
Metadata:
stunnel:
diff --git a/swift-source.yaml b/swift-source.yaml
index 14bbf2b9..0a6bf647 100644
--- a/swift-source.yaml
+++ b/swift-source.yaml
@@ -11,7 +11,7 @@ Parameters:
Type: String
NoEcho: true
Resources:
- notcomputeConfig:
+ notCompute0Config:
Type: AWS::AutoScaling::LaunchConfiguration
Metadata:
swift:
@@ -24,7 +24,7 @@ Resources:
- Fn::Select:
- 'ctlplane'
- Fn::GetAtt:
- - notcompute
+ - notCompute0
- networks
- ':%PORT%/d1'
hash:
diff --git a/test_merge.bash b/test_merge.bash
index 2f8a4cc9..f9bc7fb6 100755
--- a/test_merge.bash
+++ b/test_merge.bash
@@ -12,7 +12,7 @@ run_test() {
local expected=$2
result=$(mktemp /tmp/test_merge.XXXXXX)
fail=0
- $cmd > $result
+ $cmd --output $result
if ! cmp $result $expected ; then
diff -u $expected $result || :
echo FAIL - $cmd result does not match expected
@@ -28,6 +28,7 @@ run_test "python $merge_py examples/source.yaml" examples/source_lib_result.yaml
run_test "python $merge_py examples/source2.yaml" examples/source2_lib_result.yaml
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
echo
trap - EXIT
exit $fail
diff --git a/tripleo_heat_merge/merge.py b/tripleo_heat_merge/merge.py
index 053a683a..dd254ab4 100644
--- a/tripleo_heat_merge/merge.py
+++ b/tripleo_heat_merge/merge.py
@@ -4,6 +4,97 @@ import yaml
import argparse
+def apply_scaling(template, scaling, in_copies=None):
+ """Apply a set of scaling operations to template.
+
+ This is a single pass recursive function: for each call we process one
+ dict or list and recurse to handle children containers.
+
+ Values are handled via scale_value.
+
+ Keys in dicts are always copied per the scaling rule.
+ Values are either replaced or copied depending on whether the given
+ scaling rule is in in_copies.
+ """
+ in_copies = dict(in_copies or {})
+ # Shouldn't be needed but to avoid unexpected side effects/bugs we short
+ # circuit no-ops.
+ if not scaling:
+ return template
+ if isinstance(template, dict):
+ new_template = {}
+ for key, value in template.items():
+ for prefix, copy_num, new_key in scale_value(
+ key, scaling, in_copies):
+ if prefix:
+ # e.g. Compute0, 1, Compute1Foo
+ in_copies[prefix] = prefix[:-1] + str(copy_num)
+ if isinstance(value, (dict, list)):
+ new_value = apply_scaling(value, scaling, in_copies)
+ new_template[new_key] = new_value
+ else:
+ new_values = list(scale_value(value, scaling, in_copies))
+ # We have nowhere to multiply a non-container value of a
+ # dict, so it may be copied or unchanged but not scaled.
+ assert len(new_values) == 1
+ new_template[new_key] = new_values[0][2]
+ if prefix:
+ del in_copies[prefix]
+ return new_template
+ elif isinstance(template, list):
+ new_template = []
+ for value in template:
+ if isinstance(value, (dict, list)):
+ new_template.append(apply_scaling(value, scaling, in_copies))
+ else:
+ for _, _, new_value in scale_value(value, scaling, in_copies):
+ new_template.append(new_value)
+ return new_template
+ else:
+ raise Exception("apply_scaling called with non-container %r" % template)
+
+
+def scale_value(value, scaling, in_copies):
+ """Scale out a value.
+
+ :param value: The value to scale (not a container).
+ :param scaling: The scaling map to use.
+ :param in_copies: What containers we're currently copying.
+ :return: An iterator of the new values for the value as tuples:
+ (prefix, copy_num, value). E.g. Compute0, 1, Compute1Foo
+ prefix and copy_num are only set when:
+ - a prefix in scaling matches value
+ - and that prefix is not in in_copies
+ """
+ if isinstance(value, (str, unicode)):
+ for prefix, copies in scaling.items():
+ if not value.startswith(prefix):
+ continue
+ suffix = value[len(prefix):]
+ if prefix in in_copies:
+ # Adjust to the copy number we're on
+ yield None, None, in_copies[prefix] + suffix
+ return
+ else:
+ for n in range(copies):
+ yield prefix, n, prefix[:-1] + str(n) + suffix
+ return
+ yield None, None, value
+ else:
+ yield None, None, value
+
+
+def parse_scaling(scaling_args):
+ """Translate a list of scaling requests to a dict prefix:count."""
+ scaling_args = scaling_args or []
+ result = {}
+ for item in scaling_args:
+ key, value = item.split('=')
+ value = int(value)
+ result[key + '0'] = value
+ return result
+
+
def _translate_role(role, master_role, slave_roles):
if not master_role:
return role
@@ -89,14 +180,36 @@ def main(argv=None):
parser.add_argument('--included-template-dir', nargs='?',
default=INCLUDED_TEMPLATE_DIR,
help='Path for resolving included templates')
+ parser.add_argument('--output',
+ help='File to write output to. - for stdout',
+ default='-')
+ parser.add_argument('--scale', action="append",
+ help="Names to scale out. Pass Prefix=1 to cause a key Prefix0Foo to "
+ "be copied to Prefix1Foo in the output, and value Prefix0Bar to be"
+ "renamed to Prefix1Bar inside that copy, or copied to Prefix1Bar "
+ "outside of any copy.")
+ parser.add_argument(
+ '--change-image-params', action='store_true', default=False,
+ help="Change parameters in templates to match resource names. This was "
+ " the default at one time but it causes issues when parameter "
+ " names need to remain stable.")
args = parser.parse_args(argv)
templates = args.templates
+ scaling = parse_scaling(args.scale)
merged_template = merge(templates, args.master_role, args.slave_roles,
- args.included_template_dir)
- sys.stdout.write(merged_template)
+ args.included_template_dir, scaling=scaling,
+ change_image_params=args.change_image_params)
+ if args.output == '-':
+ out_file = sys.stdout
+ else:
+ out_file = file(args.output, 'wt')
+ out_file.write(merged_template)
+
def merge(templates, master_role=None, slave_roles=None,
- included_template_dir=INCLUDED_TEMPLATE_DIR):
+ included_template_dir=INCLUDED_TEMPLATE_DIR,
+ scaling=None, change_image_params=None):
+ scaling = scaling or {}
errors = []
end_template={'HeatTemplateFormatVersion': '2012-12-12',
'Description': []}
@@ -132,11 +245,12 @@ def merge(templates, master_role=None, slave_roles=None,
new_resources = template.get('Resources', {})
for r, rbody in sorted(new_resources.items()):
if rbody['Type'] in MERGABLE_TYPES:
- if 'image' in MERGABLE_TYPES[rbody['Type']]:
- image_key = MERGABLE_TYPES[rbody['Type']]['image']
- # XXX Assuming ImageId is always a Ref
- ikey_val = end_template['Parameters'][rbody['Properties'][image_key]['Ref']]
- del end_template['Parameters'][rbody['Properties'][image_key]['Ref']]
+ if change_image_params:
+ if 'image' in MERGABLE_TYPES[rbody['Type']]:
+ image_key = MERGABLE_TYPES[rbody['Type']]['image']
+ # XXX Assuming ImageId is always a Ref
+ ikey_val = end_template['Parameters'][rbody['Properties'][image_key]['Ref']]
+ del end_template['Parameters'][rbody['Properties'][image_key]['Ref']]
role = rbody.get('Metadata', {}).get('OpenStack::Role', r)
role = translate_role(role, master_role, slave_roles)
if role != r:
@@ -157,10 +271,11 @@ def merge(templates, master_role=None, slave_roles=None,
if 'Resources' not in end_template:
end_template['Resources'] = {}
end_template['Resources'][role] = rbody
- if 'image' in MERGABLE_TYPES[rbody['Type']]:
- ikey = '%sImage' % (role)
- end_template['Resources'][role]['Properties'][image_key] = {'Ref': ikey}
- end_template['Parameters'][ikey] = ikey_val
+ if change_image_params:
+ if 'image' in MERGABLE_TYPES[rbody['Type']]:
+ ikey = '%sImage' % (role)
+ end_template['Resources'][role]['Properties'][image_key] = {'Ref': ikey}
+ end_template['Parameters'][ikey] = ikey_val
elif rbody['Type'] == 'FileInclude':
# we trust os.path.join to DTRT: if FileInclude path isn't
# absolute, join to included_template_dir (./)
@@ -185,6 +300,8 @@ def merge(templates, master_role=None, slave_roles=None,
end_template['Resources'] = {}
end_template['Resources'][r] = rbody
+ end_template = apply_scaling(end_template, scaling)
+
def fix_ref(item, old, new):
if isinstance(item, dict):
copy_item = dict(item)
diff --git a/undercloud-bm-source.yaml b/undercloud-bm-source.yaml
index 0f546c46..ff00d28c 100644
--- a/undercloud-bm-source.yaml
+++ b/undercloud-bm-source.yaml
@@ -22,7 +22,6 @@ Resources:
ram_allocation_ratio: 1.0
reserved_host_memory_mb: 0
baremetal:
- use_file_injection: "False"
arch:
Ref: BaremetalArch
db: mysql://nova:unset@localhost/nova_bm
diff --git a/undercloud-source.yaml b/undercloud-source.yaml
index 6431dfd4..3ac148c9 100644
--- a/undercloud-source.yaml
+++ b/undercloud-source.yaml
@@ -33,7 +33,7 @@ Parameters:
Description: The password for the Heat service account, used by the Heat services.
Type: String
NoEcho: true
- Image:
+ undercloudImage:
Default: undercloud
Type: String
NeutronPassword:
@@ -52,19 +52,19 @@ Resources:
AllowedResources:
- undercloudConfig
Type: OS::Heat::AccessPolicy
- Key:
+ notCompute0Key:
Properties:
UserName:
Ref: User
Type: AWS::IAM::AccessKey
- CompletionCondition:
+ notCompute0CompletionCondition:
Type: AWS::CloudFormation::WaitCondition
DependsOn: undercloud
Properties:
- Handle: {Ref: CompletionHandle}
+ Handle: {Ref: notCompute0CompletionHandle}
Count: '1'
Timeout: '1800'
- CompletionHandle:
+ notCompute0CompletionHandle:
Type: AWS::CloudFormation::WaitConditionHandle
User:
Properties:
@@ -96,7 +96,7 @@ Resources:
db: mysql://cinder:unset@localhost/cinder
volume_size_mb: '5000'
completion-handle:
- Ref: CompletionHandle
+ Ref: notCompute0CompletionHandle
db-password: unset
glance:
backend: file
@@ -132,11 +132,11 @@ Resources:
os-collect-config:
cfn:
access_key_id:
- Ref: Key
+ Ref: notCompute0Key
path: undercloudConfig.Metadata
secret_access_key:
Fn::GetAtt:
- - Key
+ - notCompute0Key
- SecretAccessKey
stack_name:
Ref: AWS::StackName
@@ -165,7 +165,7 @@ Resources:
Type: OS::Nova::Server
Properties:
image:
- Ref: Image
+ Ref: undercloudImage
flavor:
Ref: Flavor
key_name:
@@ -174,11 +174,11 @@ Resources:
os-collect-config:
cfn:
access_key_id:
- Ref: Key
+ Ref: notCompute0Key
path: undercloudConfig.Metadata
secret_access_key:
Fn::GetAtt:
- - Key
+ - notCompute0Key
- SecretAccessKey
stack_name:
Ref: AWS::StackName
diff --git a/undercloud-vm-source.yaml b/undercloud-vm-source.yaml
index a8987072..e70ef52d 100644
--- a/undercloud-vm-source.yaml
+++ b/undercloud-vm-source.yaml
@@ -26,7 +26,6 @@ Resources:
ram_allocation_ratio: 1.0
reserved_host_memory_mb: 0
baremetal:
- use_file_injection: "False"
arch:
Ref: BaremetalArch
db: mysql://nova:unset@localhost/nova_bm