rake_cloudspin 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +327 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rake_cloudspin/exceptions.rb +4 -0
- data/lib/rake_cloudspin/paths.rb +23 -0
- data/lib/rake_cloudspin/statebucket/deployment_statebucket.rb +13 -0
- data/lib/rake_cloudspin/tasklib.rb +98 -0
- data/lib/rake_cloudspin/tasks/all.rb +175 -0
- data/lib/rake_cloudspin/tasks/base_task.rb +44 -0
- data/lib/rake_cloudspin/tasks/deployment_statebucket_task.rb +96 -0
- data/lib/rake_cloudspin/tasks/hiera.yaml +16 -0
- data/lib/rake_cloudspin/tasks/ssh_key_task.rb +46 -0
- data/lib/rake_cloudspin/tasks/stack_task.rb +108 -0
- data/lib/rake_cloudspin/tasks/stack_test_task.rb +133 -0
- data/lib/rake_cloudspin/version.rb +3 -0
- data/lib/rake_cloudspin.rb +19 -0
- data/lib/statebucket/infra/backend.tf +1 -0
- data/lib/statebucket/infra/outputs.tf +3 -0
- data/lib/statebucket/infra/provider.tf +8 -0
- data/lib/statebucket/infra/state_bucket.tf +10 -0
- data/lib/statebucket/infra/variables.tf +6 -0
- data/rake_cloudspin.gemspec +35 -0
- metadata +187 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 718feeca897645f5430cf25838521b1d9f61e70f2dc137e123ad2da60bbc57f9
|
4
|
+
data.tar.gz: 5320da339ee454d484ad524634be3de9c16320937dd71dc7f12b267026e5645b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: eb5e94a709f07f6d174a6ccf2cc8a750d6728359cb02c3442c92fbe07372b97d43d8c21b4330665756480c4c5eed9273589c29b22507be14632a86b8b29e51a3
|
7
|
+
data.tar.gz: bdc760a200da9c72b09953040dcacce32086697fdd0eec6bcb1a9916e29733ac0da9a3d1c92dd662c632e6e81c709d9f692d76c133c2a1e572aae0c8b5a0a640
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at tobyclemson@gmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in rake_cloudspin.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem 'aws_ssh_key', :path => '../aws_ssh_key'
|
9
|
+
# gem 'aws_ssh_key', :git => 'https://github.com/cloudspinners/aws_ssh_key.git'
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Kief Morris
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,327 @@
|
|
1
|
+
# RakeCloudspin
|
2
|
+
|
3
|
+
This library of Rake tasks is a prototype for an infrastructure project build framework. It is intended as a basis for exploring project structures, conventions, and functionality, but is not currently in a stable state. Feel free to copy and use it, but be prepared to extend and modify it in order to make it usable, and be aware that there isn't likely to be a clean path to upgrade your projects as this thing evolves.
|
4
|
+
|
5
|
+
|
6
|
+
## What's the point of this?
|
7
|
+
|
8
|
+
Currently, most people and teams managing infrastructure with tools such as Terraform, CloudFormation, etc. define their own project structures, and write their own wrapper scripts to run that tool and associated tasks. Essentially, each project is a unique snowflake.
|
9
|
+
|
10
|
+
The goal for cloudspin is to evolve a common structure and build tooling for infrastructure projects, focused on the lifecycle of "[stacks](http://infrastructure-as-code.com/patterns/2018/03/28/defining-stacks.html)" - infrastructure elements provisioned on dynamic infrastructure such as IaaS clouds.
|
11
|
+
|
12
|
+
Our hypothesis is that, with a common project structure and tooling:
|
13
|
+
|
14
|
+
- Teams will spend less time building and maintaining snowflake build systems,
|
15
|
+
- New team members can more quickly get up to speed when joining an infrastructure project,
|
16
|
+
- People can create and share tools and scripts that work with the common structure, creating an ecosystem,
|
17
|
+
- People can create and share infrastructure code for running various software and services, creating a community library.
|
18
|
+
|
19
|
+
|
20
|
+
## Philosophy
|
21
|
+
|
22
|
+
- [Convention over configuration](https://en.wikipedia.org/wiki/Convention_over_configuration).
|
23
|
+
-- The tool should discover elements of the project based on folder structure
|
24
|
+
-- A given configuration value should be set in a single place
|
25
|
+
-- Implies a highly "[opinionated](https://medium.com/@stueccles/the-rise-of-opinionated-software-ca1ba0140d5b)" approach
|
26
|
+
- Encourage good agile engineering practices for the infrastructure code
|
27
|
+
-- Writing and running tests should be a natural thing
|
28
|
+
-- Building and using [infrastructure pipelines](http://infrastructure-as-code.com/book/2017/08/02/environment-pipeline.html) should be a natural thing
|
29
|
+
- Support evolutionary architecture
|
30
|
+
-- Loose coupling of infrastructure elements
|
31
|
+
- Empower developers / users of infrastructure
|
32
|
+
|
33
|
+
|
34
|
+
# Structure of a project
|
35
|
+
|
36
|
+
Cloudspin is used to manage Terraform projects for AWS infrastructure. It uses Ruby rake. There are some example projects, [simple-stack](https://github.com/cloudspinners/spin-simple-stack) is a simple example.
|
37
|
+
|
38
|
+
Each cloudspin project represents a **Component**. A Component is a collection of stacks (as defined above) that together provide a useful service of some sort. Each instance of a service provisioned in the cloud is a *Deployment*. You may have Deployments for environments, e.g. a QA deployment, Staging deployment, Production deployment, etc. You might also have multiple production deployments, for example you might provision a deployment for each of your customers.
|
39
|
+
|
40
|
+
## Project structure
|
41
|
+
|
42
|
+
Your component project should have the following basic structure:
|
43
|
+
|
44
|
+
```
|
45
|
+
COMPONENT-ROOT
|
46
|
+
|-- deployment/
|
47
|
+
|-- delivery/
|
48
|
+
|-- component.yaml
|
49
|
+
|-- component-local.yaml
|
50
|
+
|-- Rakefile
|
51
|
+
└-- go*
|
52
|
+
```
|
53
|
+
|
54
|
+
## Deployment stacks
|
55
|
+
|
56
|
+
The `COMPONENT-ROOT/deployment/` folder has a subfolder for each stack that is provisioned for a deployment of the component.
|
57
|
+
|
58
|
+
```
|
59
|
+
COMPONENT-ROOT
|
60
|
+
└-- deployment/
|
61
|
+
|-- networking/
|
62
|
+
|-- cluster/
|
63
|
+
└-- database/
|
64
|
+
```
|
65
|
+
|
66
|
+
In this example, we have one stack for networking (VPC, subnets, etc.), one for a cluster (ECS cluster), and a third for a database (RDS instance).
|
67
|
+
|
68
|
+
|
69
|
+
## Stack folders
|
70
|
+
|
71
|
+
Each stack has the following structure:
|
72
|
+
|
73
|
+
```
|
74
|
+
deployment/
|
75
|
+
└── networking/
|
76
|
+
├── stack.yaml
|
77
|
+
├── infra/
|
78
|
+
│ ├── backend.tf
|
79
|
+
│ ├── bastion.tf
|
80
|
+
│ ├── dns.tf
|
81
|
+
│ ├── outputs.tf
|
82
|
+
│ ├── subnets.tf
|
83
|
+
│ ├── variables.tf
|
84
|
+
│ └── vpc.tf
|
85
|
+
└── tests/
|
86
|
+
└── inspec/
|
87
|
+
├── controls/
|
88
|
+
│ ├── bastion.rb
|
89
|
+
│ ├── subnets.rb
|
90
|
+
│ └── vpc.rb
|
91
|
+
└── inspec.yml
|
92
|
+
```
|
93
|
+
|
94
|
+
See below for details on the `stack.yaml` file.
|
95
|
+
|
96
|
+
|
97
|
+
## Delivery stacks
|
98
|
+
|
99
|
+
The `COMPONENT-ROOT/delivery/` folder can have a number of subfolders, each representing a stack that provisions things needed for delivery. Each of these is typically provisioned only once per component. Examples include pipeline definitions, and artefact repository configurations.
|
100
|
+
|
101
|
+
```bash
|
102
|
+
delivery/
|
103
|
+
└── aws-pipeline
|
104
|
+
├── infra
|
105
|
+
│ ├── artefact_bucket.tf
|
106
|
+
│ ├── backend.tf
|
107
|
+
│ ├── outputs.tf
|
108
|
+
│ ├── packaging_codebuild_stage.tf
|
109
|
+
│ ├── pipeline.tf
|
110
|
+
│ ├── prodapply_codebuild_stage.tf
|
111
|
+
│ ├── testapply_codebuild_stage.tf
|
112
|
+
│ └── variables.tf
|
113
|
+
└── stack.yaml
|
114
|
+
```
|
115
|
+
|
116
|
+
|
117
|
+
# Setting up a cloudspin project
|
118
|
+
|
119
|
+
These are the steps to set up a new cloudspin infrastructure project:
|
120
|
+
|
121
|
+
1. Import the `rake_cloudspin` gem.
|
122
|
+
2. Create component configuration
|
123
|
+
3. Create one or more deployment and delivery stacks
|
124
|
+
|
125
|
+
|
126
|
+
## Adding the rake_cloudspin gem to your project
|
127
|
+
|
128
|
+
### Install the gem
|
129
|
+
|
130
|
+
Add this line to your application's Gemfile:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
gem 'rake_cloudspin', :git => 'https://github.com/cloudspinners/rake_cloudspin.git'
|
134
|
+
```
|
135
|
+
|
136
|
+
(TODO: Publish releases of this gem properly)
|
137
|
+
|
138
|
+
And then execute:
|
139
|
+
|
140
|
+
$ bundle install
|
141
|
+
|
142
|
+
Or install it yourself as:
|
143
|
+
|
144
|
+
$ gem install rake_cloudspin
|
145
|
+
|
146
|
+
|
147
|
+
## Import the library into your Rakefile
|
148
|
+
|
149
|
+
Here is an example Rakefile:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
require 'rake/clean'
|
153
|
+
require 'rake_cloudspin'
|
154
|
+
|
155
|
+
CLEAN.include('build')
|
156
|
+
CLEAN.include('work')
|
157
|
+
CLEAN.include('dist')
|
158
|
+
CLOBBER.include('vendor')
|
159
|
+
|
160
|
+
task :default => [ :plan ]
|
161
|
+
|
162
|
+
RakeCloudspin.define_tasks
|
163
|
+
|
164
|
+
```
|
165
|
+
|
166
|
+
Many of our example projects use a `go` script as a wrapper to run rake. This makes sure prerequisites are installed, including the gems. See [example go script](https://raw.githubusercontent.com/cloudspinners/spin-simple-stack/master/go) from the spin-simple-stack project.
|
167
|
+
|
168
|
+
|
169
|
+
## Component configuration (component.yaml)
|
170
|
+
|
171
|
+
There are two files used to configure your Component, both of which live at the root of the project, alongside the Rakefile.
|
172
|
+
|
173
|
+
* `component.yaml` has the default configuration options, and is intended to be checked into source control with the rest of your project.
|
174
|
+
* `component-local.yaml` allows you to override configuration options when you run cloudspin locally. This is intended to be excluded from source control, so each person who works on the project can have their own custom options.
|
175
|
+
|
176
|
+
Here is an example, again from the *simpleweb* project, of a `component.yaml` file.
|
177
|
+
|
178
|
+
|
179
|
+
```yaml
|
180
|
+
---
|
181
|
+
estate: cloudspin
|
182
|
+
component: simple
|
183
|
+
region: eu-west-1
|
184
|
+
```
|
185
|
+
|
186
|
+
Some of these configuration variables are used for naming things, others are for configuring infrastructure.
|
187
|
+
|
188
|
+
- *estate* is an identifier that runs across all components, all deployments. It may be the name of the organisation, division, etc.
|
189
|
+
- *component* is the name of this component.
|
190
|
+
- *region* is the default region for deploying stacks.
|
191
|
+
|
192
|
+
|
193
|
+
Other variables are used to configure infrastructure, generally passed to Terraform code. The specific variables that are available in your component configuration will depend on your own project code. They will tend to be driven by the `stack.yaml` files for the deployment and delivery stacks in your project.
|
194
|
+
|
195
|
+
|
196
|
+
# Stack configuration (stack.yaml)
|
197
|
+
|
198
|
+
Each stack in `deployment/*` and `delivery/*` must have a `stack.yaml` file in its root. Otherwise, the cloudspin build won't recognize the stack.
|
199
|
+
|
200
|
+
Here's another example from simpleweb.
|
201
|
+
|
202
|
+
```yaml
|
203
|
+
---
|
204
|
+
vars:
|
205
|
+
region: "%{hiera('region')}"
|
206
|
+
component: "%{hiera('component')}"
|
207
|
+
deployment_identifier: "%{hiera('deployment_identifier')}"
|
208
|
+
estate: "%{hiera('estate')}"
|
209
|
+
service: "%{hiera('service')}"
|
210
|
+
base_dns_domain: "%{hiera('domain_name')}"
|
211
|
+
|
212
|
+
webserver_ssh_public_key_path: "../ssh_keys/webserver_ssh_key.pub"
|
213
|
+
bastion_ssh_public_key_path: "../ssh_keys/bastion_ssh_key.pub"
|
214
|
+
allowed_cidr: "%{hiera('my_ip')}/32"
|
215
|
+
|
216
|
+
ssh_keys:
|
217
|
+
- webserver_ssh_key
|
218
|
+
- bastion_ssh_key
|
219
|
+
|
220
|
+
state:
|
221
|
+
type: s3
|
222
|
+
scope: deployment
|
223
|
+
```
|
224
|
+
|
225
|
+
|
226
|
+
## Terraform variables
|
227
|
+
|
228
|
+
The `vars:` section of the `stack.yaml` file defines variables that are passed to terraform. See the [terraform configuration documentation](https://www.terraform.io/docs/configuration/variables.html) for how these are used. Cloudspin passes the variables defined in the `stack.yaml` file to the terraform command on the commandline.
|
229
|
+
|
230
|
+
The values in the configuration file can include values from component variables or other variables set by cloudspin. Cloudspin uses hiera to do this, so the syntax is:
|
231
|
+
|
232
|
+
```
|
233
|
+
"%{hiera('VARIABLE_NAME')}"
|
234
|
+
```
|
235
|
+
|
236
|
+
## SSH keys
|
237
|
+
|
238
|
+
Some infrastructure needs ssh keys, for example keypairs used by EC2 instances. Cloudspin can manage these for you if your stack.yaml file has an `ssh_key` section as below:
|
239
|
+
|
240
|
+
```yaml
|
241
|
+
ssh_keys:
|
242
|
+
- webserver_ssh_key
|
243
|
+
- bastion_ssh_key
|
244
|
+
```
|
245
|
+
|
246
|
+
Each keyname listed in here represents an ssh public/private key pair required by the stack. When run the first time, cloudspin will generate an ssh key pair, and upload both keys to the AWS SSM Parameter Store as values encrypted with KMS. On later runs, Cloudspin will retrieve the existing keys and use those as appropriate.
|
247
|
+
|
248
|
+
A separate keypair is used for each deployment of the given stack. So keys are not shared between components, stacks, or environments. They don't need to be checked into version control. Ephemeral test instances of the stack will have keys automatically generated, and these will be destroyed afterwards along with the environment.
|
249
|
+
|
250
|
+
The keys are written or downloaded to the local filesystem, so they can be passed to Terraform. In the simpleweb example, two keypairs are generated, and the location of their public keys are passed as vars:
|
251
|
+
|
252
|
+
```yaml
|
253
|
+
vars:
|
254
|
+
...
|
255
|
+
webserver_ssh_public_key_path: "../ssh_keys/webserver_ssh_key.pub"
|
256
|
+
bastion_ssh_public_key_path: "../ssh_keys/bastion_ssh_key.pub"
|
257
|
+
```
|
258
|
+
|
259
|
+
TODO: The location of the keyfiles should be set in variables by cloudspin, so you don't need to know the location.
|
260
|
+
|
261
|
+
If you don't want cloudspin to generate ssh keys for you, don't list the keys under the `ssh_keys` section of the `stack.yaml` file, and simply give the path to the keyfile you want to use in the `vars` section.
|
262
|
+
|
263
|
+
|
264
|
+
# Running cloudspin tasks
|
265
|
+
|
266
|
+
You run cloudspin either by running `rake`, or using a wrapper like the `go` script. Our examples assume the `go` script is used.
|
267
|
+
|
268
|
+
## ${deployment_identifier}
|
269
|
+
|
270
|
+
You must set a unique `deployment_identifier` value for each unique instance of your component. You can set a default in your `component.yaml` file, although this is dangerous - it will be easy for someone to forget to set the value in some other way, and accidentally make changes to that instance. So if you do this, make sure the named environment is one you don't care about accidentally breaking.
|
271
|
+
|
272
|
+
Your **production** environment should of course NEVER be the default `deployment_identifier`.
|
273
|
+
|
274
|
+
It's common for each person to set their own `deployment_identifier` in `component-local.yaml`, so they can run cloudspin locally to create a personal "sandbox" instance to work on. It's useful to have a naming convention for this, so it's easy to manage instances, e.g. to destroy unneeded developer instances.
|
275
|
+
|
276
|
+
Most non-sandbox instances of the component will be provisioned and managed by the pipeline. In these cases, the pipeline configuration will set the `deployment_identifier` value.
|
277
|
+
|
278
|
+
The most common way to set the `deployment_identifier` is with an environment variable:
|
279
|
+
|
280
|
+
```bash
|
281
|
+
DEPLOYMENT_IDENTIFIER=mytest ./go provision
|
282
|
+
```
|
283
|
+
|
284
|
+
## Cloudspin tasks
|
285
|
+
|
286
|
+
You can see the tasks by running `rake -T` or `./go -T`.
|
287
|
+
|
288
|
+
The main lifecycle tasks are:
|
289
|
+
|
290
|
+
- plan: Show what Terraform will do to the existing component instance
|
291
|
+
- provision: Create or update all deployment stacks in the instance
|
292
|
+
- test: Run all component tests against the instance
|
293
|
+
- destroy: Completely destroy all deployment stacks in the instance
|
294
|
+
- vars: Show the Terraform variables that will be set by cloudspin
|
295
|
+
|
296
|
+
Each of these commands can be run to affect all deployment stacks in the instance. They will not affect the delivery stacks.
|
297
|
+
|
298
|
+
It's also possible to run these commands for a specific deployment stack (or delivery stack):
|
299
|
+
|
300
|
+
```bash
|
301
|
+
rake deployment:simpleweb:plan # Plan deployment-simpleweb using terraform
|
302
|
+
rake deployment:simpleweb:provision # Provision deployment-simpleweb using terraform
|
303
|
+
rake deployment:simpleweb:test # Run inspec tests
|
304
|
+
rake deployment:simpleweb:destroy # Destroy deployment-simpleweb using terraform
|
305
|
+
rake deployment:simpleweb:vars # Show terraform variables for stack 'simpleweb'
|
306
|
+
```
|
307
|
+
|
308
|
+
Replace `simpleweb` with the name of a different stack as appropriate. For delivery stacks, the syntax is to `rake delivery:STACKNAME:task`.
|
309
|
+
|
310
|
+
|
311
|
+
# Runtime details
|
312
|
+
|
313
|
+
What's the `work` folder about?
|
314
|
+
|
315
|
+
|
316
|
+
# General info
|
317
|
+
|
318
|
+
|
319
|
+
## Contributing
|
320
|
+
|
321
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rake_cloudspin.
|
322
|
+
|
323
|
+
|
324
|
+
## Components
|
325
|
+
|
326
|
+
This is largely based on code from [Infrablocks](https://github.com/infrablocks), and uses some components, including [rake_terraform](https://github.com/infrablocks/rake_terraform).
|
327
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rake_cloudspin"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Paths
|
2
|
+
class <<self
|
3
|
+
def project_root_directory
|
4
|
+
File.expand_path(Rake.application.original_dir)
|
5
|
+
end
|
6
|
+
|
7
|
+
def from_project_root_directory(*segments)
|
8
|
+
join_and_expand(project_root_directory, *segments)
|
9
|
+
end
|
10
|
+
|
11
|
+
def join_and_expand(*segments)
|
12
|
+
File.expand_path(join(*segments))
|
13
|
+
end
|
14
|
+
|
15
|
+
def join(*segments)
|
16
|
+
File.join(*segments.compact)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self_directory
|
20
|
+
File.dirname(__FILE__)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'rake/tasklib'
|
2
|
+
require_relative 'exceptions'
|
3
|
+
|
4
|
+
module RakeCloudspin
|
5
|
+
class TaskLib < ::Rake::TaskLib
|
6
|
+
class << self
|
7
|
+
def parameter_definitions
|
8
|
+
@parameter_definitions ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def parameter(name, options = {})
|
12
|
+
parameter_definition = ParameterDefinition.new(
|
13
|
+
name, options[:default], options[:required])
|
14
|
+
name = parameter_definition.name
|
15
|
+
|
16
|
+
attr_accessor(name)
|
17
|
+
|
18
|
+
parameter_definitions[name] = parameter_definition
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup_defaults_for(instance)
|
22
|
+
parameter_definitions.values.each do |parameter_definition|
|
23
|
+
parameter_definition.apply_default_to(instance)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_required_for(instance)
|
28
|
+
dissatisfied = parameter_definitions.values.reject do |definition|
|
29
|
+
definition.satisfied_by?(instance)
|
30
|
+
end
|
31
|
+
unless dissatisfied.empty?
|
32
|
+
names = dissatisfied.map(&:name)
|
33
|
+
raise RequiredParameterUnset,
|
34
|
+
"Required parameter#{names.length > 1 ? 's' : ''} #{names.join(',')} unset."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(*args, &block)
|
40
|
+
setup_defaults
|
41
|
+
process_arguments(args)
|
42
|
+
process_block(block)
|
43
|
+
check_required
|
44
|
+
define
|
45
|
+
end
|
46
|
+
|
47
|
+
def setup_defaults
|
48
|
+
self.class.setup_defaults_for(self)
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_arguments(_)
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_block(block)
|
55
|
+
block.call(self) if block
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_required
|
59
|
+
self.class.check_required_for(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
def define
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
class ParameterDefinition
|
68
|
+
attr_reader :name
|
69
|
+
|
70
|
+
def initialize(name, default = nil, required = false)
|
71
|
+
@name = name.to_sym
|
72
|
+
@default = default
|
73
|
+
@required = required
|
74
|
+
end
|
75
|
+
|
76
|
+
def writer_method
|
77
|
+
"#{name}="
|
78
|
+
end
|
79
|
+
|
80
|
+
def reader_method
|
81
|
+
name
|
82
|
+
end
|
83
|
+
|
84
|
+
def apply_default_to(instance)
|
85
|
+
instance.__send__(writer_method, @default) if @default
|
86
|
+
end
|
87
|
+
|
88
|
+
def dissatisfied_by?(instance)
|
89
|
+
value = instance.__send__(reader_method)
|
90
|
+
@required && value.nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
def satisfied_by?(instance)
|
94
|
+
!dissatisfied_by?(instance)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|