sparkle-guides 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/docs/apply-and-nested.md +375 -0
- data/docs/getting-started.md +734 -0
- data/sparkle-guides.gemspec +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6d84bfd1702300758e47d0348e9905a0d70c0f8
|
4
|
+
data.tar.gz: c2a02647503ca0fd162e28a3c33bae7cb2c53e81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 824eba256e15ac401704765d07500313c61fa7930637992f9bf793d03978c88e0922b5059e3757f345b21a65af082de1c9f2ea7009684ed23cc5ea9c9d7a4031
|
7
|
+
data.tar.gz: e76f5398b1baa00c49d3abf332662e63c5ca4bcf36474cb9b524daead8418fa9baa690a5f47b124f3e3186f5ded5a414104c18afe682302d7b3cc5e8f17e8d8f
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,375 @@
|
|
1
|
+
---
|
2
|
+
title: "Stack Interdependencies"
|
3
|
+
weight: 2
|
4
|
+
anchors:
|
5
|
+
- title: "Overview"
|
6
|
+
url: "#overview"
|
7
|
+
- title: "Apply stack"
|
8
|
+
url: "#apply-stack-implementation"
|
9
|
+
- title: "Nested stack"
|
10
|
+
url: "#nested-stack-implementation"
|
11
|
+
- title: "Apply nested stack"
|
12
|
+
url: "#apply-nested-stack"
|
13
|
+
---
|
14
|
+
|
15
|
+
## Overview
|
16
|
+
|
17
|
+
### Apply stack
|
18
|
+
|
19
|
+
The SparkleFormation CLI includes functionality to ease the sharing
|
20
|
+
of resources between isolated stacks. This functionality enables
|
21
|
+
groupings of similar resources which can define logical units of
|
22
|
+
a full architecture. The sharing is accomplished using a combination
|
23
|
+
of stack outputs and stack parameters. This feature is commonly
|
24
|
+
referred to as the _apply stack_ functionality.
|
25
|
+
|
26
|
+
One drawback of the _apply stack_ functionality is that it introduces
|
27
|
+
dependencies between disparate stacks. These dependencies must be
|
28
|
+
manually resolved when resource modifications occur. When an infrastructure
|
29
|
+
is composed of few stacks, the _apply stack_ approach can be sufficient
|
30
|
+
to manage stack dependencies leaving the user to ensure updates are
|
31
|
+
properly applied. For larger implementations composed of many interdependent
|
32
|
+
stacks, the _nested stack_ functionality is recommended.
|
33
|
+
|
34
|
+
### Nested stack
|
35
|
+
|
36
|
+
_Nested stack_ functionality is a generic feature provided by the SparkleFormation
|
37
|
+
library which the SparkleFormation CLI then specializes based on the target provider.
|
38
|
+
The _nested stack_ functionality utilizes a core feature provided by orchestration
|
39
|
+
APIs. This features allows nesting stack resources within a stack allowing a
|
40
|
+
parent stack to have many child stacks. By nesting stack resources, the provider
|
41
|
+
API will be aware of child stack interdependencies and automatically apply updates
|
42
|
+
when resources have been modified. This removes the requirement of stack updates
|
43
|
+
being tracked and applied manually.
|
44
|
+
|
45
|
+
The behavior of the _nested stack_ functionality is based directly on the
|
46
|
+
behavior of the _apply stack_ functionality. This commonality in behavior
|
47
|
+
allows for initial testing development using the _apply stack_ functionality
|
48
|
+
and, once stable, migrating to _nested stack_ functionality without requiring any
|
49
|
+
modifications to existing templates. The commonality also allows for the two
|
50
|
+
functionalities to be mixed in practice.
|
51
|
+
|
52
|
+
This guide will first display template implementations using the _apply stack_
|
53
|
+
functionality. The example templates will then be used to provide a _nested stack_
|
54
|
+
implementation.
|
55
|
+
|
56
|
+
_NOTE: This guide targets the AWS provider for simplicity to allow focus on the
|
57
|
+
features discussed. All providers support this behavior._
|
58
|
+
|
59
|
+
## Apply stack implementation
|
60
|
+
|
61
|
+
Lets start by defining a simple infrastructure. Our infrastructure will be composed
|
62
|
+
of a "network" and a collection of "computes" that utilizes the network. This
|
63
|
+
infrastructure can be easily defined within two units:
|
64
|
+
|
65
|
+
1. network
|
66
|
+
2. computes
|
67
|
+
|
68
|
+
Lets start by creating a simple `network` template.
|
69
|
+
|
70
|
+
Create a new file: `./sparkleformation/network.rb`
|
71
|
+
|
72
|
+
#### Template sparkles AWS
|
73
|
+
|
74
|
+
~~~ruby
|
75
|
+
SparkleFormation.new(:network) do
|
76
|
+
|
77
|
+
parameters do
|
78
|
+
cidr_prefix do
|
79
|
+
type 'String'
|
80
|
+
default '172.20'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
dynamic!(:ec2_vpc, :network) do
|
85
|
+
properties do
|
86
|
+
cidr_block join!(ref!(:cidr_prefix, '.0.0/24'))
|
87
|
+
enable_dns_support true
|
88
|
+
enable_dns_hostnames true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
dynamic!(:ec2_dhcp_options, :network) do
|
93
|
+
properties do
|
94
|
+
domain_name join!(region!, 'compute.internal')
|
95
|
+
domain_name_servers ['AmazonProvidedDNS']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
dynamic!(:ec2_vpc_dhcp_options_association, :network) do
|
100
|
+
properties do
|
101
|
+
dhcp_options_id ref!(:network_ec2_dhcp_options)
|
102
|
+
vpc_id ref!(:network_ec2_vpc)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
dynamic!(:ec2_internet_gateway, :network)
|
107
|
+
|
108
|
+
dynamic!(:ec2_vpc_gateway_attachment, :network) do
|
109
|
+
properties do
|
110
|
+
internet_gateway_id ref!(:network_ec2_internet_gateway)
|
111
|
+
vpc_id ref!(:network_ec2_vpc)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
dynamic!(:ec2_route_table, :network) do
|
116
|
+
properties.vpc_id ref!(:network_ec2_vpc)
|
117
|
+
end
|
118
|
+
|
119
|
+
dynamic!(:ec2_route, :network_public) do
|
120
|
+
properties do
|
121
|
+
destination_cidr_block '0.0.0.0/0'
|
122
|
+
gateway_id ref!(:network_ec2_internet_gateway)
|
123
|
+
route_table_id ref!(:network_ec2_route_table)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
dynamic!(:ec2_subnet, :network) do
|
128
|
+
properties do
|
129
|
+
availability_zone select!(0, azs!)
|
130
|
+
cidr_block join!(ref!(:cidr_prefix, '.0.0/24'))
|
131
|
+
vpc_id ref!(:network_ec2_vpc)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
dynamic!(:ec2_subnet_route_table_association, :network) do
|
136
|
+
properties do
|
137
|
+
route_table_id ref!(:network_ec2_route_table)
|
138
|
+
subnet_id ref!(:network_ec2_subnet)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
outputs do
|
143
|
+
network_vpc_id.value ref!(:network_ec2_vpc)
|
144
|
+
network_subnet_id.value ref!(:network_ec2_subnet)
|
145
|
+
network_route_table.value ref!(:network_ec2_route_table)
|
146
|
+
network_cidr.value join!(ref!(:cidr_prefix, '.0.0/24'))
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
~~~
|
151
|
+
|
152
|
+
Here we have an extremely simple VPC defined for our infrastructure. It is
|
153
|
+
important to note the outputs defined within our `network` template. These
|
154
|
+
outputs are values that will be required for other resources to effectively
|
155
|
+
utilize the VPC. With the `network` template defined, we can create that unit
|
156
|
+
of our infrastructure:
|
157
|
+
|
158
|
+
~~~
|
159
|
+
$ bundle exec sfn create sparkle-guide-network --file network
|
160
|
+
~~~
|
161
|
+
|
162
|
+
Having successfully built the `network` unit of the infrastructure, we can
|
163
|
+
now compose the `computes` template.
|
164
|
+
|
165
|
+
Create a new file: `./sparkleformation/computes.rb`
|
166
|
+
|
167
|
+
#### Template sparkles AWS
|
168
|
+
|
169
|
+
~~~ruby
|
170
|
+
SparkleFormation.new(:computes) do
|
171
|
+
|
172
|
+
parameters do
|
173
|
+
ssh_key_name.type 'String'
|
174
|
+
network_vpc_id.type 'String'
|
175
|
+
network_subnet_id.type 'String'
|
176
|
+
end
|
177
|
+
|
178
|
+
dynamic!(:ec2_security_group, :compute) do
|
179
|
+
properties do
|
180
|
+
group_description 'SSH Access'
|
181
|
+
security_group_ingress do
|
182
|
+
cidr_ip '0.0.0.0/0'
|
183
|
+
from_port 22
|
184
|
+
to_port 22
|
185
|
+
ip_protocol 'tcp'
|
186
|
+
end
|
187
|
+
vpc_id ref!(:network_vpc_id)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
dynamic!(:ec2_instance, :micro) do
|
192
|
+
properties do
|
193
|
+
image_id 'ami-25c52345'
|
194
|
+
image_type 't2.micro'
|
195
|
+
key_name ref!(:ssh_key_name)
|
196
|
+
network_interfaces array!(
|
197
|
+
->{
|
198
|
+
device_index 0
|
199
|
+
associate_public_ip_address 'true'
|
200
|
+
subnet_id ref!(:network_subnet_id)
|
201
|
+
group_set [ref!(:compute_ec2_security_group)]
|
202
|
+
}
|
203
|
+
)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
dynamic!(:ec2_instance, :small) do
|
208
|
+
properties do
|
209
|
+
image_id 'ami-25c52345'
|
210
|
+
image_type 't2.micro'
|
211
|
+
key_name ref!(:ssh_key_name)
|
212
|
+
network_interfaces array!(
|
213
|
+
->{
|
214
|
+
device_index 0
|
215
|
+
associate_public_ip_address 'true'
|
216
|
+
subnet_id ref!(:network_subnet_id)
|
217
|
+
group_set [ref!(:compute_ec2_security_group)]
|
218
|
+
}
|
219
|
+
)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
outputs do
|
224
|
+
micro_address.value attr!(:micro_ec2_instance, :public_ip)
|
225
|
+
small_address.value attr!(:small_ec2_instance, :public_ip)
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
~~~
|
230
|
+
|
231
|
+
Our `computes` template will create one micro and one small EC2
|
232
|
+
instance and output the public IP addresses of each resource. To
|
233
|
+
build the EC2 instances into the VPC created in the `sparkle-guide-network`
|
234
|
+
stack we need two pieces of information:
|
235
|
+
|
236
|
+
* VPC ID
|
237
|
+
* VPC subnet ID
|
238
|
+
|
239
|
+
In our `computes` template we define two parameters for the required
|
240
|
+
VPC information: `network_vpc_id` and `network_subnet_id`. When we
|
241
|
+
create a stack using this template we can copy the output values from the
|
242
|
+
`sparkle-guide-network` stack and paste them into these parameters, but
|
243
|
+
that is extremely cumbersome. The SparkleFormation CLI instead allows
|
244
|
+
"applying" a stack on creation or update.
|
245
|
+
|
246
|
+
Notice that the output names in our `network` template match the parameter
|
247
|
+
names in our `computes` template.
|
248
|
+
|
249
|
+
~~~ruby
|
250
|
+
# From ./sparkleformation/network.rb
|
251
|
+
outputs do
|
252
|
+
network_vpc_id.value ref!(:network_ec2_vpc)
|
253
|
+
network_subnet_id.value ref!(:network_ec2_subnet)
|
254
|
+
network_route_table.value ref!(:network_ec2_route_table)
|
255
|
+
network_cidr.value join!(ref!(:cidr_prefix, '.0.0/24'))
|
256
|
+
end
|
257
|
+
|
258
|
+
# From ./sparkleformation/computes.rb
|
259
|
+
parameters do
|
260
|
+
ssh_key_name.type 'String'
|
261
|
+
network_vpc_id.type 'String'
|
262
|
+
network_subnet_id.type 'String'
|
263
|
+
end
|
264
|
+
~~~
|
265
|
+
|
266
|
+
The apply stack functionality will automatically collect outputs from
|
267
|
+
the stack names provided and use them to seed the parameters of the
|
268
|
+
stack being created or updated. This means instead of having to copy
|
269
|
+
and paste the VPC ID and subnet ID values, we can instruct the SparkleFormation
|
270
|
+
CLI to automatically use the outputs of our `sparkle-guide-network` stack:
|
271
|
+
|
272
|
+
~~~
|
273
|
+
$ bundle exec sfn create sparkle-guide-computes --file computes --apply-stack sparkle-guide-network
|
274
|
+
~~~
|
275
|
+
|
276
|
+
During the create process, the SparkleFormation CLI will prompt for parameters. The
|
277
|
+
default values for the VPC ID and subnet ID will be automatically inserted, matching
|
278
|
+
the outputs from the `sparkle-guide-network`.
|
279
|
+
|
280
|
+
## Nested stack implementation
|
281
|
+
|
282
|
+
Now that our infrastructure has been successfully created using disparate stacks, lets
|
283
|
+
combine them to create a single `infrastructure` unit composed of sub-units. Using
|
284
|
+
nested stacks requires a bucket to store templates. Create a bucket in S3 and then
|
285
|
+
add the following to the `.sfn` configuration file:
|
286
|
+
|
287
|
+
~~~ruby
|
288
|
+
Configuration.new do
|
289
|
+
...
|
290
|
+
nesting_bucket 'NAME_OF_BUCKET'
|
291
|
+
...
|
292
|
+
end
|
293
|
+
~~~
|
294
|
+
|
295
|
+
With the required bucket in place and SparkleFormation CLI configured we can
|
296
|
+
now create our `infrastructure` template.
|
297
|
+
|
298
|
+
Create a new file: `./sparkleformation/infrastructure.rb`
|
299
|
+
|
300
|
+
#### Template sparkles AWS
|
301
|
+
|
302
|
+
~~~ruby
|
303
|
+
SparkleFormation.new(:infrastructure) do
|
304
|
+
nest!(:network, :infra)
|
305
|
+
nest!(:computes, :infra)
|
306
|
+
end
|
307
|
+
~~~
|
308
|
+
|
309
|
+
This new `infrastructure` template is using SparkleFormation's builtin nesting
|
310
|
+
functionality to create stack resources within our `infrastructure` template
|
311
|
+
composed of our `network` and `computes` template. To see the conceptual result
|
312
|
+
of this nesting, we can print the `infrastructure` template:
|
313
|
+
|
314
|
+
~~~
|
315
|
+
$ bundle exec sfn print --file infrastructure
|
316
|
+
~~~
|
317
|
+
|
318
|
+
There are a few things of note in this output. First, the `Stack` property is
|
319
|
+
not a real resource property. It is used by SparkleFormation for template processing
|
320
|
+
and is included in print functions to display the template in its entirety. Next,
|
321
|
+
the generated URLs are not real URLs. This is due to the SparkleFormation CLI not
|
322
|
+
actually storing the templates in the remote bucket. Lastly, and most importantly,
|
323
|
+
the parameters property of the `ComputesInfra` resource.
|
324
|
+
|
325
|
+
~~~json
|
326
|
+
"Parameters": {
|
327
|
+
"NetworkVpcId": {
|
328
|
+
"Fn::GetAtt": [
|
329
|
+
"NetworkInfra",
|
330
|
+
"Outputs.NetworkVpcId"
|
331
|
+
]
|
332
|
+
},
|
333
|
+
"NetworkSubnetId": {
|
334
|
+
"Fn::GetAtt": [
|
335
|
+
"NetworkInfra",
|
336
|
+
"Outputs.NetworkSubnetId"
|
337
|
+
]
|
338
|
+
}
|
339
|
+
}
|
340
|
+
~~~
|
341
|
+
|
342
|
+
SparkleFormation registers outputs when processing templates and will automatically
|
343
|
+
map outputs to subsequent stack resource parameters if they match. Cross stack resource
|
344
|
+
dependencies are now explicitly defined allowing the orchestration API to automatically
|
345
|
+
determine creation order as well as triggering updates when required.
|
346
|
+
|
347
|
+
Now we can create our full infrastructure with a single command:
|
348
|
+
|
349
|
+
~~~
|
350
|
+
$ bundle exec sfn create sparkle-guide-infrastructure --file infrastructure
|
351
|
+
~~~
|
352
|
+
|
353
|
+
As SparkleFormation processes the nested templates for the `create` command, the SparkleFormation
|
354
|
+
CLI will extract the nested templates, store them in the configured nesting bucket, and updates
|
355
|
+
the template location URL in the resource.
|
356
|
+
|
357
|
+
Using nested templates, `update` commands follow the same behavior as `create` commands. All nested
|
358
|
+
templates are extracted and automatically uploaded prior to execution of the `update` request with
|
359
|
+
the orchestration API. This results in _all_ nested stacks being automatically updated by the API
|
360
|
+
as required based on dependent resource modifications.
|
361
|
+
|
362
|
+
## Apply nested stack
|
363
|
+
|
364
|
+
Nested stacks can be applied to disparate stacks in the same manner described in the apply
|
365
|
+
stack implementation section. When the stack to be applied is a nested stack, SparkleFormation
|
366
|
+
CLI will gather outputs from all the nested stacks, and then apply to the target command. This
|
367
|
+
means using the `sparkle-guide-infrastructure` stack we previously built can be used for creating
|
368
|
+
new `computes` stacks without being nested into the `infrastructure` template.
|
369
|
+
|
370
|
+
~~~
|
371
|
+
$ bundle exec sfn create sparkle-guide-computes-infra --file computes --apply-stack sparkle-guide-infrastructure
|
372
|
+
~~~
|
373
|
+
|
374
|
+
The ability to apply nested stacks to disparate stacks make it easy to provide resources to new
|
375
|
+
stacks, or to test building new stacks in isolation before being nested into the root stack.
|
@@ -0,0 +1,734 @@
|
|
1
|
+
---
|
2
|
+
title: "Getting Started"
|
3
|
+
weight: 1
|
4
|
+
anchors:
|
5
|
+
- title: "Requirements"
|
6
|
+
url: "#requirements"
|
7
|
+
- title: "Installation"
|
8
|
+
url: "#installation"
|
9
|
+
- title: "Configuration"
|
10
|
+
url: "#configuration"
|
11
|
+
- title: "Setup"
|
12
|
+
url: "#setup"
|
13
|
+
- title: "Create a template"
|
14
|
+
url: "#create-a-template"
|
15
|
+
- title: "Create a new stack"
|
16
|
+
url: "#create-a-new-stack"
|
17
|
+
- title: "Template refactor"
|
18
|
+
url: "#template-refactor"
|
19
|
+
- title: "Stack update"
|
20
|
+
url: "#stack-update"
|
21
|
+
- title: "Stack information"
|
22
|
+
url: "#stack-information"
|
23
|
+
- title: "Clean up"
|
24
|
+
url: "#clean-up"
|
25
|
+
---
|
26
|
+
|
27
|
+
## Requirements
|
28
|
+
|
29
|
+
* Ruby (Version `>=` 2.0)
|
30
|
+
* Bundler
|
31
|
+
* Provider Credentials
|
32
|
+
|
33
|
+
### Installing Ruby
|
34
|
+
|
35
|
+
There are a variety of ways to install Ruby depending on platform and toolset. The
|
36
|
+
Ruby website provides information about many of the installation options:
|
37
|
+
|
38
|
+
* [Installing Ruby](https://www.ruby-lang.org/en/documentation/installation/)
|
39
|
+
|
40
|
+
### Installing Bundler
|
41
|
+
|
42
|
+
Once Ruby is installed, install Bundler using the `gem` command:
|
43
|
+
|
44
|
+
~~~
|
45
|
+
$ gem install bundler
|
46
|
+
~~~
|
47
|
+
|
48
|
+
### Provider credentials
|
49
|
+
|
50
|
+
Required credentials differ based on the target provider in use. For more information
|
51
|
+
about credentials specific to a certain provider, reference the miasma library for
|
52
|
+
the provider:
|
53
|
+
|
54
|
+
* [miasma-aws](https://github.com/miasma-rb/miasma-aws)
|
55
|
+
* [miasma-azure](https://github.com/miasma-rb/miasma-azure)
|
56
|
+
* [miasma-open-stack](https://github.com/miasma-rb/miasma-open-stack)
|
57
|
+
* [miasma-rackspace](https://github.com/miasma-rb/miasma-rackspace)
|
58
|
+
|
59
|
+
## Installation
|
60
|
+
|
61
|
+
First, install the `sfn` gem:
|
62
|
+
|
63
|
+
~~~
|
64
|
+
$ gem install sfn
|
65
|
+
~~~
|
66
|
+
|
67
|
+
Now initialize a new project:
|
68
|
+
|
69
|
+
~~~
|
70
|
+
$ sfn init sparkle-guide
|
71
|
+
~~~
|
72
|
+
|
73
|
+
Finally change to the new project directory:
|
74
|
+
|
75
|
+
~~~
|
76
|
+
$ cd sparkle-guide
|
77
|
+
~~~
|
78
|
+
|
79
|
+
## Configuration
|
80
|
+
|
81
|
+
The `init` command will have automatically generated a configuration file
|
82
|
+
within the project directory. To view the current configuration status the
|
83
|
+
`conf` command can be used:
|
84
|
+
|
85
|
+
~~~
|
86
|
+
$ bundle exec sfn conf
|
87
|
+
~~~
|
88
|
+
|
89
|
+
The configuration file for `sfn` is located within the `.sfn` file. Open this file
|
90
|
+
and adjust the credentials section for your desired provider. The generated
|
91
|
+
configuration file uses environment variables for provider configuration. This
|
92
|
+
style of setup makes it easy to automatically set credential information using
|
93
|
+
tools like direnv. Environment variable usage is not required, and credential
|
94
|
+
values can be provided directly.
|
95
|
+
|
96
|
+
_NOTE: It is important to **not** store provider credential secrets within the
|
97
|
+
`.sfn` file if it will be checked into source control._
|
98
|
+
|
99
|
+
### Test configuration
|
100
|
+
|
101
|
+
Test the configuration by running a list command:
|
102
|
+
|
103
|
+
~~~
|
104
|
+
$ bundle exec sfn list
|
105
|
+
~~~
|
106
|
+
|
107
|
+
This should print a list of existing stacks on the configured provider. If no
|
108
|
+
stacks exist, no entries will be shown. If an error message is received, check
|
109
|
+
that the credentials information is properly set and try again.
|
110
|
+
|
111
|
+
## Create a template
|
112
|
+
|
113
|
+
Lets start by creating a full template. This template will create a compute resource
|
114
|
+
on the desired provider and output the remote public address of the new compute instance.
|
115
|
+
|
116
|
+
Create a new file: `./sparkleformation/compute.rb`:
|
117
|
+
|
118
|
+
#### Template sparkles AWS
|
119
|
+
|
120
|
+
~~~ruby
|
121
|
+
SparkleFormation.new(:compute, :provider => :aws) do
|
122
|
+
AWSTemplateFormatVersion '2010-09-09'
|
123
|
+
description 'Sparkle Guide Compute Template'
|
124
|
+
|
125
|
+
parameters do
|
126
|
+
sparkle_image_id.type 'String'
|
127
|
+
sparkle_ssh_key_name.type 'String'
|
128
|
+
sparkle_flavor do
|
129
|
+
type 'String'
|
130
|
+
default 't2.micro'
|
131
|
+
allowed_values ['t2.micro', 't2.small']
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
dynamic!(:ec2_instance, :sparkle) do
|
136
|
+
properties do
|
137
|
+
image_id ref!(:sparkle_image_id)
|
138
|
+
instance_type ref!(:sparkle_flavor)
|
139
|
+
key_name ref!(:sparkle_ssh_key_name)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
outputs.sparkle_public_address do
|
144
|
+
description 'Compute instance public address'
|
145
|
+
value attr!(:sparkle_ec2_instance, :public_ip)
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
~~~
|
150
|
+
|
151
|
+
#### Template sparkles HEAT
|
152
|
+
|
153
|
+
~~~ruby
|
154
|
+
SparkleFormation.new(:compute, :provider => :heat) do
|
155
|
+
heat_template_version '2015-04-30'
|
156
|
+
description 'Sparkle Guide Compute Template'
|
157
|
+
|
158
|
+
parameters do
|
159
|
+
sparkle_image_id.type 'String'
|
160
|
+
sparkle_ssh_key_name.type 'String'
|
161
|
+
sparkle_flavor do
|
162
|
+
type 'String'
|
163
|
+
default 'm1.small'
|
164
|
+
allowed_values ['m1.small', 'm1.medium']
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
dynamic!(:nova_server, :sparkle) do
|
169
|
+
properties do
|
170
|
+
image ref!(:sparkle_image_id)
|
171
|
+
flavor ref!(:sparkle_flavor)
|
172
|
+
key_name ref!(:sparkle_ssh_key_name)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
outputs.sparkle_public_address do
|
177
|
+
description 'Compute instance public address'
|
178
|
+
value attr!(:sparkle_nova_instance, 'accessIPv4')
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
~~~
|
183
|
+
|
184
|
+
#### Template sparkles Azure
|
185
|
+
|
186
|
+
~~~ruby
|
187
|
+
SparkleFormation.new(:compute, :provider => :azure) do
|
188
|
+
set!('$schema', 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#')
|
189
|
+
content_version '1.0.0.0'
|
190
|
+
parameters do
|
191
|
+
sparkle_image_id do
|
192
|
+
type 'string'
|
193
|
+
default_value '14.04.2-LTS'
|
194
|
+
end
|
195
|
+
sparkle_flavor do
|
196
|
+
type 'string'
|
197
|
+
allowed_values [
|
198
|
+
'Standard_D1'
|
199
|
+
]
|
200
|
+
end
|
201
|
+
storage_account_name.type 'string'
|
202
|
+
storage_container_name.type 'string'
|
203
|
+
end
|
204
|
+
|
205
|
+
dynamic!(:network_public_ip_addresses, :sparkle) do
|
206
|
+
properties do
|
207
|
+
set!('publicIPAllocationMethod', 'Dynamic')
|
208
|
+
dns_settings.domain_name_label 'sparkle'
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
dynamic!(:network_virtual_networks, :sparkle) do
|
213
|
+
properties do
|
214
|
+
address_space.address_prefixes ['10.0.0.0/16']
|
215
|
+
subnets array!(
|
216
|
+
->{
|
217
|
+
name 'sparkle-subnet'
|
218
|
+
properties.address_prefix '10.0.0.0/24'
|
219
|
+
}
|
220
|
+
)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
dynamic!(:network_interfaces, :sparkle) do
|
225
|
+
properties.ip_configurations array!(
|
226
|
+
->{
|
227
|
+
name 'ipconfig1'
|
228
|
+
properties do
|
229
|
+
set!('privateIPAllocationMethod', 'Dynamic')
|
230
|
+
set!('publicIPAddress').id resource_id!(:sparkle_network_public_ip_addresses)
|
231
|
+
subnet.id concat!(resource_id!(:sparkle_network_virtual_networks), '/subnets/sparkle-subnet')
|
232
|
+
end
|
233
|
+
}
|
234
|
+
)
|
235
|
+
end
|
236
|
+
|
237
|
+
dynamic!(:compute_virtual_machines, :sparkle) do
|
238
|
+
properties do
|
239
|
+
hardware_profile.vm_size parameters!(:sparkle_flavor)
|
240
|
+
os_profile do
|
241
|
+
computer_name 'sparkle'
|
242
|
+
admin_username 'sparkle'
|
243
|
+
admin_password 'SparkleFormation2016'
|
244
|
+
end
|
245
|
+
storage_profile do
|
246
|
+
image_reference do
|
247
|
+
publisher 'Canonical'
|
248
|
+
offer 'UbuntuServer'
|
249
|
+
sku parameters!(:sparkle_image_id)
|
250
|
+
version 'latest'
|
251
|
+
end
|
252
|
+
os_disk do
|
253
|
+
name 'osdisk'
|
254
|
+
vhd.uri concat!('http://', parameters!(:storage_account_name), '.blob.core.windows.net/', parameters!(:storage_container_name), '/sparkle.vhd')
|
255
|
+
caching 'ReadWrite'
|
256
|
+
create_option 'FromImage'
|
257
|
+
end
|
258
|
+
data_disks array!(
|
259
|
+
->{
|
260
|
+
name 'datadisk1'
|
261
|
+
set!('diskSizeGB', 100)
|
262
|
+
lun 0
|
263
|
+
vhd.uri concat!('http://', parameters!(:storage_account_name), '.blob.core.windows.net/', parameters!(:storage_container_name), '/sparkle-data.vhd')
|
264
|
+
create_option 'Empty'
|
265
|
+
}
|
266
|
+
)
|
267
|
+
end
|
268
|
+
network_profile.network_interfaces array!(
|
269
|
+
->{ id resource_id!(:sparkle_network_interfaces) }
|
270
|
+
)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
outputs.sparkle_public_address do
|
275
|
+
type 'string'
|
276
|
+
value reference!(:sparkle_network_public_ip_addresses).ipAddress
|
277
|
+
end
|
278
|
+
end
|
279
|
+
~~~
|
280
|
+
|
281
|
+
### View template
|
282
|
+
|
283
|
+
View the processed JSON result:
|
284
|
+
|
285
|
+
~~~
|
286
|
+
$ bundle exec sfn print --file compute
|
287
|
+
~~~
|
288
|
+
|
289
|
+
This will output the serialized JSON template generated by SparkleFormation. The JSON is the template
|
290
|
+
content which will be sent to the remote provider API with the stack create request.
|
291
|
+
|
292
|
+
## Create a new stack
|
293
|
+
|
294
|
+
After seeing the result of the compiled and serialized template, lets use that template to
|
295
|
+
create a new stack. To start the stack creation process run the following command:
|
296
|
+
|
297
|
+
~~~
|
298
|
+
$ bundle exec sfn create sparkle-guide-compute --file compute
|
299
|
+
~~~
|
300
|
+
|
301
|
+
Before creating this new stack, `sfn` will prompt for the parameters defined within the template.
|
302
|
+
The `sparkle_image_id` and `sparkle_ssh_key_name` parameters are not defined with default values within the template,
|
303
|
+
so values _must_ be provided when prompted. The prompt for the `sparkle_flavor` parameter will show the
|
304
|
+
default value defined within the template, and can be used or overridden with a different value.
|
305
|
+
|
306
|
+
After `sfn` has completed prompting for stack parameters, it will initiate the stack creation
|
307
|
+
request with the remote provider. The creation request to the API is only for initiation. A successful
|
308
|
+
response does not indicate that the stack was created successfully, rather it indicates that the request
|
309
|
+
to create the stack was successful.
|
310
|
+
|
311
|
+
Once the create request is complete, `sfn` will automatically transition to event polling. Resource
|
312
|
+
events related to the new stack will be displayed until the stack reaches a "complete" state: success
|
313
|
+
or failure. The automatic transition to event polling ensures that the `sfn create` command will return
|
314
|
+
a proper exit code once the stack has reached a completion state.
|
315
|
+
|
316
|
+
At successful completion of the stack creation, the outputs defined within the template will be displayed
|
317
|
+
showing the public address of the newly created compute instance.
|
318
|
+
|
319
|
+
## Template refactor
|
320
|
+
|
321
|
+
A key feature of SparkleFormation is the ability to break down templates into reusable parts which can
|
322
|
+
then be re-used in multiple templates. Lets break down our existing template into re-usable parts and
|
323
|
+
re-build the template using those parts.
|
324
|
+
|
325
|
+
### Registry
|
326
|
+
|
327
|
+
The registry is a place to store values that may be used in multiple places. With the value defined in
|
328
|
+
a single location, updates to the value only require one modification to apply globally. In our `compute`
|
329
|
+
example, the allowed instance flavor values would an ideal candidate for a registry entry.
|
330
|
+
|
331
|
+
Create a new file at `./sparkleformation/registry/instance_flavor.rb`
|
332
|
+
|
333
|
+
#### Registry sparkles AWS
|
334
|
+
|
335
|
+
~~~ruby
|
336
|
+
SfnRegistry.register(:instance_flavor) do
|
337
|
+
['m1.small', 'm1.medium']
|
338
|
+
end
|
339
|
+
~~~
|
340
|
+
|
341
|
+
#### Registry sparkles HEAT
|
342
|
+
|
343
|
+
~~~ruby
|
344
|
+
SfnRegistry.register(:instance_flavor) do
|
345
|
+
['m1.small', 'm1.medium']
|
346
|
+
end
|
347
|
+
~~~
|
348
|
+
|
349
|
+
#### Registry sparkles Azure
|
350
|
+
~~~ruby
|
351
|
+
SfnRegistry.register(:instance_flavor) do
|
352
|
+
['Standard_D1']
|
353
|
+
end
|
354
|
+
~~~
|
355
|
+
|
356
|
+
_NOTE: For more information see: [Registry building blocks](../sparkle_formation/building-blocks.html#registry)_
|
357
|
+
|
358
|
+
### Component
|
359
|
+
|
360
|
+
Components are items which are used a single time within a template. The version information and description
|
361
|
+
are both items in our `compute` template that are only used a single time, but should be defined in all templates.
|
362
|
+
Lets move those items into a component.
|
363
|
+
|
364
|
+
Create a new file at `./sparkleformation/components/base.rb`
|
365
|
+
|
366
|
+
#### Component sparkles AWS
|
367
|
+
|
368
|
+
~~~ruby
|
369
|
+
SparkleFormation.component(:base) do
|
370
|
+
AWSTemplateFormatVersion '2010-09-09'
|
371
|
+
description 'Sparkle Guide Compute Template'
|
372
|
+
end
|
373
|
+
~~~
|
374
|
+
|
375
|
+
#### Component sparkles HEAT
|
376
|
+
|
377
|
+
~~~ruby
|
378
|
+
SparkleFormation.component(:base) do
|
379
|
+
heat_template_version '2015-04-30'
|
380
|
+
description 'Sparkle Guide Compute Template'
|
381
|
+
end
|
382
|
+
~~~
|
383
|
+
|
384
|
+
#### Component sparkles Azure
|
385
|
+
|
386
|
+
~~~ruby
|
387
|
+
SparkleFormation.component(:base) do
|
388
|
+
set!('$schema', 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#')
|
389
|
+
content_version '1.0.0.0'
|
390
|
+
end
|
391
|
+
~~~
|
392
|
+
|
393
|
+
_NOTE: For more information see: [Component building blocks](../sparkle_formation/building-blocks.html#components)_
|
394
|
+
|
395
|
+
### Dynamic
|
396
|
+
|
397
|
+
Dynamics are items which can be used multiple times within a template. A dynamic requires a custom name be provided
|
398
|
+
and allows for an optional Hash of values. Dynamics are useful for injecting a common structure into a template
|
399
|
+
multiple times. In the `compute` template above, we can now extract the remainder of the template and convert it
|
400
|
+
into a dynamic.
|
401
|
+
|
402
|
+
Create a new file at `./sparkleformation/dynamics/node.rb`
|
403
|
+
|
404
|
+
#### Dynamic sparkles AWS
|
405
|
+
|
406
|
+
~~~ruby
|
407
|
+
SparkleFormation.dynamic(:node) do |name, opts={}|
|
408
|
+
|
409
|
+
parameters do
|
410
|
+
set!("#{name}_image_id".to_sym).type 'String'
|
411
|
+
set!("#{name}_ssh_key_name".to_sym).type 'String'
|
412
|
+
set!("#{name}_flavor".to_sym) do
|
413
|
+
type 'String'
|
414
|
+
default 'm1.small'
|
415
|
+
allowed_values registry!(:instance_flavor)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
outputs.set!("#{name}_public_address".to_sym) do
|
420
|
+
description "Compute instance public address - #{name}"
|
421
|
+
value attr!("#{name}_ec2_instance".to_sym, :public_ip)
|
422
|
+
end
|
423
|
+
|
424
|
+
dynamic!(:ec2_instance, name) do
|
425
|
+
properties do
|
426
|
+
image_id ref!("#{name}_image_id".to_sym)
|
427
|
+
instance_type ref!("#{name}_flavor".to_sym)
|
428
|
+
key_name ref!("#{name}_ssh_key_name".to_sym)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
end
|
433
|
+
~~~
|
434
|
+
|
435
|
+
#### Dynamic sparkles HEAT
|
436
|
+
|
437
|
+
~~~ruby
|
438
|
+
SparkleFormation.dynamic(:node) do |name, opts={}|
|
439
|
+
|
440
|
+
parameters do
|
441
|
+
set!("#{name}_image_id".to_sym).type 'String'
|
442
|
+
set!("#{name}_ssh_key_name".to_sym).type 'String'
|
443
|
+
set!("#{name}_flavor".to_sym) do
|
444
|
+
type 'String'
|
445
|
+
default 'm1.small'
|
446
|
+
allowed_values registry!(:instance_flavor)
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
outputs.set!("#{name}_public_address".to_sym) do
|
451
|
+
description "Compute instance public address - #{name}"
|
452
|
+
value attr!("#{name}_nova_server".to_sym, 'accessIPv4')
|
453
|
+
end
|
454
|
+
|
455
|
+
dynamic!(:nova_server, name) do
|
456
|
+
properties do
|
457
|
+
image ref!("#{name}_image_id".to_sym)
|
458
|
+
flavor ref!("#{name}_flavor".to_sym)
|
459
|
+
key_name ref!("#{name}_ssh_key_name".to_sym)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
end
|
464
|
+
~~~
|
465
|
+
|
466
|
+
#### Dynamic sparkles Azure
|
467
|
+
|
468
|
+
~~~~ruby
|
469
|
+
SparkleFormation.dynamic(:node) do |name, opts={}|
|
470
|
+
parameters do
|
471
|
+
set!("#{name}_image_id".to_sym) do
|
472
|
+
type 'string'
|
473
|
+
default_value '14.04.2-LTS'
|
474
|
+
end
|
475
|
+
set!("#{name}_flavor".to_sym) do
|
476
|
+
type 'string'
|
477
|
+
allowed_values registry!(:instance_flavor)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
dynamic!(:network_public_ip_addresses, name) do
|
482
|
+
properties do
|
483
|
+
set!('publicIPAllocationMethod', 'Dynamic')
|
484
|
+
dns_settings.domain_name_label name
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
dynamic!(:network_interfaces, name) do
|
489
|
+
properties.ip_configurations array!(
|
490
|
+
->{
|
491
|
+
name 'ipconfig1'
|
492
|
+
properties do
|
493
|
+
set!('privateIPAllocationMethod', 'Dynamic')
|
494
|
+
set!('publicIPAddress').id resource_id!("#{name}_network_public_ip_addresses".to_sym)
|
495
|
+
subnet.id concat!(resource_id!("#{name}_network_virtual_networks".to_sym), '/subnets/sparkle-subnet')
|
496
|
+
end
|
497
|
+
}
|
498
|
+
)
|
499
|
+
end
|
500
|
+
|
501
|
+
dynamic!(:compute_virtual_machines, name) do
|
502
|
+
properties do
|
503
|
+
hardware_profile.vm_size parameters!("#{name}_flavor".to_sym)
|
504
|
+
os_profile do
|
505
|
+
computer_name 'sparkle'
|
506
|
+
admin_username 'sparkle'
|
507
|
+
admin_password 'SparkleFormation2016'
|
508
|
+
end
|
509
|
+
storage_profile do
|
510
|
+
image_reference do
|
511
|
+
publisher 'Canonical'
|
512
|
+
offer 'UbuntuServer'
|
513
|
+
sku parameters!("#{name}_image_id".to_sym)
|
514
|
+
version 'latest'
|
515
|
+
end
|
516
|
+
os_disk do
|
517
|
+
name 'osdisk'
|
518
|
+
vhd.uri concat!('http://', parameters!(:storage_account_name), '.blob.core.windows.net/', parameters!(:storage_container_name), "/#{name}.vhd")
|
519
|
+
caching 'ReadWrite'
|
520
|
+
create_option 'FromImage'
|
521
|
+
end
|
522
|
+
data_disks array!(
|
523
|
+
->{
|
524
|
+
name 'datadisk1'
|
525
|
+
set!('diskSizeGB', 100)
|
526
|
+
lun 0
|
527
|
+
vhd.uri concat!('http://', parameters!(:storage_account_name), '.blob.core.windows.net/', parameters!(:storage_container_name), "/#{name}-data.vhd")
|
528
|
+
create_option 'Empty'
|
529
|
+
}
|
530
|
+
)
|
531
|
+
end
|
532
|
+
network_profile.network_interfaces array!(
|
533
|
+
->{ id resource_id!("#{name}_network_interfaces".to_sym) }
|
534
|
+
)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
outputs.set!("#{name}_public_address".to_sym) do
|
539
|
+
type 'string'
|
540
|
+
value reference!("#{name}_network_public_ip_addresses".to_sym).ipAddress
|
541
|
+
end
|
542
|
+
end
|
543
|
+
~~~~
|
544
|
+
|
545
|
+
The first thing to note about this dynamic file is the `name` argument at the top.
|
546
|
+
|
547
|
+
`SparkleFormation.dynamic(:node) do |name, opts={}|`
|
548
|
+
|
549
|
+
This variable is used throughout the dynamic to provide uniquely named parameters, resources, and outputs. Also
|
550
|
+
note the use of they registry to define the allowed values for the flavor parameter.
|
551
|
+
|
552
|
+
`allowed_values registry!(:instance_flavor)`
|
553
|
+
|
554
|
+
_NOTE: For more information see: [Dynamic building blocks](../sparkle_formation/building-blocks.html#dynamics)_
|
555
|
+
|
556
|
+
### Template
|
557
|
+
|
558
|
+
Now that the original template has been refactored into re-usable parts, lets update our `./sparkleformation/compute.rb`
|
559
|
+
template:
|
560
|
+
|
561
|
+
#### Template sparkles AWS
|
562
|
+
|
563
|
+
~~~ruby
|
564
|
+
SparkleFormation.new(:compute, :provider => :aws).load(:base).overrides do
|
565
|
+
dynamic!(:node, :sparkle)
|
566
|
+
end
|
567
|
+
~~~
|
568
|
+
|
569
|
+
#### Template sparkles HEAT
|
570
|
+
|
571
|
+
~~~ruby
|
572
|
+
SparkleFormation.new(:compute, :provider => :heat).load(:base).overrides do
|
573
|
+
dynamic!(:node, :sparkle)
|
574
|
+
end
|
575
|
+
~~~
|
576
|
+
|
577
|
+
#### Template sparkles Azure
|
578
|
+
|
579
|
+
~~~ruby
|
580
|
+
SparkleFormation.new(:compute, :provider => :azure).load(:base).overrides do
|
581
|
+
parameters do
|
582
|
+
storage_account_name.type 'string'
|
583
|
+
storage_container_name.type 'string'
|
584
|
+
end
|
585
|
+
|
586
|
+
dynamic!(:network_virtual_networks, :sparkle) do
|
587
|
+
properties do
|
588
|
+
address_space.address_prefixes ['10.0.0.0/16']
|
589
|
+
subnets array!(
|
590
|
+
->{
|
591
|
+
name 'sparkle-subnet'
|
592
|
+
properties.address_prefix '10.0.0.0/24'
|
593
|
+
}
|
594
|
+
)
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
dynamic!(:node, :sparkle)
|
599
|
+
end
|
600
|
+
~~~
|
601
|
+
|
602
|
+
The template is now greatly compacted, and composed entirely of re-usable parts. The `.load(:base)` is inserting
|
603
|
+
the base component we defined above. The `dynamic!(:node, :sparkle)` is inserting the node dynamic we defined
|
604
|
+
above and using the custom name `sparkle`. We can print this template, and see the result is the same as the original
|
605
|
+
template.
|
606
|
+
|
607
|
+
~~~
|
608
|
+
$ sfn print --file compute
|
609
|
+
~~~
|
610
|
+
|
611
|
+
## Stack update
|
612
|
+
|
613
|
+
### The NO-OP update
|
614
|
+
|
615
|
+
We can verify that our new template is the same as our original template by updating the running stack and applying
|
616
|
+
our new template:
|
617
|
+
|
618
|
+
~~~
|
619
|
+
$ sfn update sparkle-guide-compute --file compute --defaults
|
620
|
+
~~~
|
621
|
+
|
622
|
+
The `--defaults` flag will suppress prompts for stack parameters and use the existing values defined for the running
|
623
|
+
stack. The result of this command will either explicitly state that no updates were performed, or the event stream
|
624
|
+
will show that no resources were modified depending on the provider.
|
625
|
+
|
626
|
+
### The real update (parameters)
|
627
|
+
|
628
|
+
Now lets update the stack by modifying the paramters of the running stack. We will change the flavor of the instance
|
629
|
+
which will result in the resource being replaced within the stack. Run the update command but do not provide any
|
630
|
+
flags:
|
631
|
+
|
632
|
+
~~~
|
633
|
+
$ sfn update sparkle-guide-compute
|
634
|
+
~~~
|
635
|
+
|
636
|
+
Now `sfn` will prompt for parameter values. Notice that the default values are the values used when creating the
|
637
|
+
stack. When the `sparkle_flavor` parameter is prompted, choose a different value from the allowed list. After the
|
638
|
+
update has completed, the outputs displayed of the stack will have changed showing a new public address for the
|
639
|
+
compute instance.
|
640
|
+
|
641
|
+
### The real update (template)
|
642
|
+
|
643
|
+
Since our template has been refactored and is now composed of re-usable parts, it's easy to quickly expand our stack.
|
644
|
+
Lets add an additional compute resource to our `./sparkleformation/compute.rb` template:
|
645
|
+
|
646
|
+
#### Template sparkles AWS
|
647
|
+
|
648
|
+
~~~ruby
|
649
|
+
SparkleFormation.new(:compute, :provider => :aws).load(:base).overrides do
|
650
|
+
dynamic!(:node, :sparkle)
|
651
|
+
dynamic!(:node, :unicorn)
|
652
|
+
end
|
653
|
+
~~~
|
654
|
+
|
655
|
+
#### Template sparkles HEAT
|
656
|
+
|
657
|
+
~~~ruby
|
658
|
+
SparkleFormation.new(:compute, :provider => :heat).load(:base).overrides do
|
659
|
+
dynamic!(:node, :sparkle)
|
660
|
+
dynamic!(:node, :unicorn)
|
661
|
+
end
|
662
|
+
~~~
|
663
|
+
|
664
|
+
#### Template sparkles Azure
|
665
|
+
|
666
|
+
~~~ruby
|
667
|
+
SparkleFormation.new(:compute, :provider => :azure).load(:base).overrides do
|
668
|
+
parameters do
|
669
|
+
storage_account_name.type 'string'
|
670
|
+
storage_container_name.type 'string'
|
671
|
+
end
|
672
|
+
|
673
|
+
dynamic!(:network_virtual_networks, :sparkle) do
|
674
|
+
properties do
|
675
|
+
address_space.address_prefixes ['10.0.0.0/16']
|
676
|
+
subnets array!(
|
677
|
+
->{
|
678
|
+
name 'sparkle-subnet'
|
679
|
+
properties.address_prefix '10.0.0.0/24'
|
680
|
+
}
|
681
|
+
)
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
dynamic!(:node, :sparkle)
|
686
|
+
dynamic!(:node, :unicorn)
|
687
|
+
end
|
688
|
+
~~~
|
689
|
+
|
690
|
+
|
691
|
+
Printing the template we can see that by adding a single line we have added not only a new resource to our template,
|
692
|
+
but a new output as well.
|
693
|
+
|
694
|
+
~~~
|
695
|
+
$ sfn print --file compute
|
696
|
+
~~~
|
697
|
+
|
698
|
+
Now we can apply this updated template to our existing stack. On this update command, we _must_ provide the `--file`
|
699
|
+
flag so our modified template will be sent in our request:
|
700
|
+
|
701
|
+
~~~
|
702
|
+
$ sfn update sparkle-guide-compute --file compute
|
703
|
+
~~~
|
704
|
+
|
705
|
+
When `sfn` prompts for parameters, the previously seen `sparkle` parameters will be requested, but we will also
|
706
|
+
see new `unicorn` parameters requested for the new compute resource we added. After the update has completed the
|
707
|
+
stack outputs will be displayed and will now include two public addresses: one for `sparkle` and one for `unicorn`.
|
708
|
+
|
709
|
+
## Stack information
|
710
|
+
|
711
|
+
With stacks currently existing on the remote provider, we can now use the inspection commands:
|
712
|
+
|
713
|
+
~~~
|
714
|
+
$ sfn list
|
715
|
+
~~~
|
716
|
+
|
717
|
+
Will provide a list of current stacks. This may include only the `sparkle-guide-compute` stack or it may include
|
718
|
+
other stacks that were created by other users or the provider itself.
|
719
|
+
|
720
|
+
We can also describe a specific stack. The describe command will list all the resources composing the requested
|
721
|
+
stack, as well as any stack outputs defined for the stack:
|
722
|
+
|
723
|
+
~~~
|
724
|
+
$ sfn describe sparkle-guide-compute
|
725
|
+
~~~
|
726
|
+
|
727
|
+
## Clean up
|
728
|
+
|
729
|
+
To conclude this guide, we want to be sure to remove the example stack we created. This is done using the
|
730
|
+
destroy command:
|
731
|
+
|
732
|
+
~~~
|
733
|
+
$ sfn destroy sparkle-guide-compute
|
734
|
+
~~~
|
data/sparkle-guides.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sparkle-guides
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
@@ -18,6 +18,8 @@ extra_rdoc_files: []
|
|
18
18
|
files:
|
19
19
|
- CHANGELOG.md
|
20
20
|
- README.md
|
21
|
+
- docs/apply-and-nested.md
|
22
|
+
- docs/getting-started.md
|
21
23
|
- sparkle-guides.gemspec
|
22
24
|
homepage: http://github.com/sparkleformation/sparkle-guides
|
23
25
|
licenses:
|