cloudstrap 0.29.1.pre
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 +7 -0
- data/.gitignore +55 -0
- data/LICENSE.txt +21 -0
- data/README.org +114 -0
- data/bin/cloudstrap +115 -0
- data/cloudstrap.gemspec +24 -0
- data/lib/cloudstrap.rb +3 -0
- data/lib/cloudstrap/amazon.rb +2 -0
- data/lib/cloudstrap/amazon/ec2.rb +377 -0
- data/lib/cloudstrap/amazon/iam.rb +20 -0
- data/lib/cloudstrap/amazon/service.rb +35 -0
- data/lib/cloudstrap/amazon/support/rate_limit_handler.rb +33 -0
- data/lib/cloudstrap/bootstrap_agent.rb +461 -0
- data/lib/cloudstrap/config.rb +160 -0
- data/lib/cloudstrap/hdp/bootstrap_properties.rb +76 -0
- data/lib/cloudstrap/seed_properties.rb +30 -0
- data/lib/cloudstrap/ssh.rb +2 -0
- data/lib/cloudstrap/ssh/client.rb +36 -0
- data/lib/cloudstrap/ssh/key.rb +82 -0
- metadata +242 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 79075784a2e532fa8f708f83ab14d4d2d4f7f262
|
4
|
+
data.tar.gz: a36f02ccc53bbba3cd7c6985c9dc778a016ebcbf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: db973e404ee5707cbcb8b5af935815b8aca99df65a77b9f908f362c39cd2a4aa7e389e82227f62321305df04dcdb1f56d93fa2bdcd4be83c7921e3be7fbf925e
|
7
|
+
data.tar.gz: 68112e361736d5a9912f3638a4706547a1d23c4eb9108a96b7bd8ace7b438a699741ea8f8b04f0edfdd92c3083f4a1108870f711ccaa06f442e6b265bdc05bc3
|
data/.gitignore
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
# Created by https://www.gitignore.io/api/ruby
|
3
|
+
|
4
|
+
### Ruby ###
|
5
|
+
*.gem
|
6
|
+
*.rbc
|
7
|
+
/.config
|
8
|
+
/coverage/
|
9
|
+
/InstalledFiles
|
10
|
+
/pkg/
|
11
|
+
/spec/reports/
|
12
|
+
/spec/examples.txt
|
13
|
+
/test/tmp/
|
14
|
+
/test/version_tmp/
|
15
|
+
/tmp/
|
16
|
+
|
17
|
+
# Used by dotenv library to load environment variables.
|
18
|
+
# .env
|
19
|
+
|
20
|
+
## Specific to RubyMotion:
|
21
|
+
.dat*
|
22
|
+
.repl_history
|
23
|
+
build/
|
24
|
+
*.bridgesupport
|
25
|
+
build-iPhoneOS/
|
26
|
+
build-iPhoneSimulator/
|
27
|
+
|
28
|
+
## Specific to RubyMotion (use of CocoaPods):
|
29
|
+
#
|
30
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
31
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
32
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
33
|
+
#
|
34
|
+
# vendor/Pods/
|
35
|
+
|
36
|
+
## Documentation cache and generated files:
|
37
|
+
/.yardoc/
|
38
|
+
/_yardoc/
|
39
|
+
/doc/
|
40
|
+
/rdoc/
|
41
|
+
|
42
|
+
## Environment normalization:
|
43
|
+
/.bundle/
|
44
|
+
/vendor/bundle
|
45
|
+
/lib/bundler/man/
|
46
|
+
|
47
|
+
# for a library or gem, you might want to ignore these files since the code is
|
48
|
+
# intended to run in multiple environments; otherwise, check them in:
|
49
|
+
# Gemfile.lock
|
50
|
+
# .ruby-version
|
51
|
+
# .ruby-gemset
|
52
|
+
|
53
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
54
|
+
.rvmrc
|
55
|
+
.cache/**
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
The MIT License (MIT)
|
3
|
+
Copyright © 2016 Chris Olstrom <chris@olstrom.com>
|
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.org
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#+TITLE: Cloudstrap
|
2
|
+
#+SUBTITLE: Strapping Boots to Clouds
|
3
|
+
#+LATEX: \pagebreak
|
4
|
+
|
5
|
+
* Overview
|
6
|
+
|
7
|
+
=cloudstrap= straps your boots to the cloud. Think of it as sort of a
|
8
|
+
meta-bootstrap tool. It handles pre-bootstrapping, primarily. Once complete, you
|
9
|
+
should have an environment suitable for launching your bootstrapper.
|
10
|
+
|
11
|
+
* Why does this exist?
|
12
|
+
|
13
|
+
To simplify deployment by replacing manual process with glorious automation.
|
14
|
+
|
15
|
+
* Installation
|
16
|
+
|
17
|
+
#+BEGIN_SRC shell
|
18
|
+
gem install --pre cloudstrap
|
19
|
+
#+END_SRC
|
20
|
+
|
21
|
+
* Usage
|
22
|
+
|
23
|
+
Simply run the automated bootstrap tool. You can configure it via ENV or =config.yaml=
|
24
|
+
|
25
|
+
#+BEGIN_SRC shell
|
26
|
+
env BOOTSTRAP_WITHOUT_HUMAN_OVERSIGHT=true cloudstrap
|
27
|
+
#+END_SRC
|
28
|
+
|
29
|
+
The output describes the results, and all settings used in the process.
|
30
|
+
|
31
|
+
#+BEGIN_EXAMPLE
|
32
|
+
# Cloudstrap v0.28.0.pre
|
33
|
+
|
34
|
+
# General Configuration
|
35
|
+
# These settings can be configured via ENV or config.yaml
|
36
|
+
|
37
|
+
BOOTSTRAP_REGION=us-west-2
|
38
|
+
BOOTSTRAP_CACHE_PATH=/Users/colstrom/cloudstrap/.cache
|
39
|
+
BOOTSTRAP_VPC_CIDR_BLOCK=10.0.0.0/16
|
40
|
+
BOOTSTRAP_PUBLIC_CIDR_BLOCK=10.0.0.0/24
|
41
|
+
BOOTSTRAP_PRIVATE_CIDR_BLOCK=10.0.1.0/24
|
42
|
+
BOOTSTRAP_AMI_OWNER=099720109477
|
43
|
+
BOOTSTRAP_UBUNTU_RELEASE=14.04
|
44
|
+
BOOTSTRAP_INSTANCE_TYPE=t2.micro
|
45
|
+
BOOTSTRAP_SSH_DIR=/Users/colstrom/cloudstrap/.ssh
|
46
|
+
BOOTSTRAP_SSH_USERNAME=ubuntu
|
47
|
+
BOOTSTRAP_HDP_DIR=/Users/colstrom/cloudstrap
|
48
|
+
|
49
|
+
# Cached Configuration
|
50
|
+
# These settings can be overridden via ENV only
|
51
|
+
|
52
|
+
BOOTSTRAP_USERNAME=colstrom
|
53
|
+
BOOTSTRAP_UUID=97cb1464-cf44-479e-be47-9a212131ad4c
|
54
|
+
BOOTSTRAP_TAG=lkg@colstrom/97cb1464-cf44-479e-be47-9a212131ad4c
|
55
|
+
BOOTSTRAP_AMI=ami-70b67d10
|
56
|
+
BOOTSTRAP_VPC_ID=vpc-0e93a16a
|
57
|
+
BOOTSTRAP_INTERNET_GATEWAY_ID=igw-942af8f0
|
58
|
+
BOOTSTRAP_JUMPBOX_SECURITY_GROUP=sg-43f9183a
|
59
|
+
BOOTSTRAP_PRIVATE_SUBNET_ID=subnet-b7047dc1
|
60
|
+
BOOTSTRAP_PUBLIC_SUBNET_ID=subnet-9c1c65ea
|
61
|
+
BOOTSTRAP_ROUTE_TABLE_ID=rtb-9d28dcfa
|
62
|
+
BOOTSTRAP_AVAILABILITY_ZONE=us-west-2b
|
63
|
+
BOOTSTRAP_JUMPBOX_ID=i-051c248563a2c3f54
|
64
|
+
BOOTSTRAP.JUMPBOX_IP=52.89.237.123
|
65
|
+
BOOTSTRAP_WITHOUT_HUMAN_OVERSIGHT=true
|
66
|
+
|
67
|
+
# Additional Information
|
68
|
+
# These do not need configuration, and are presented as a debugging checklist
|
69
|
+
|
70
|
+
# Public IPs Enabled in Public Subnet? true
|
71
|
+
# Gateway Attached to VPC? true
|
72
|
+
# Route to Internet via Gateway? true
|
73
|
+
# Route to NAT Gateway from Private Subnet? true
|
74
|
+
# SSH Allowed to Jumpbox? true
|
75
|
+
# SSH Key uploaded to AWS? 1a:c4:ec:25:94:90:ed:ee:c2:66:2e:3c:9c:c8:7a:12
|
76
|
+
# HDP bootstrap.properties configured? true
|
77
|
+
# Jumpbox Running? true
|
78
|
+
|
79
|
+
# No version specified for HDP Bootstrap, falling back to default version
|
80
|
+
INFO [0942f874] Running /usr/bin/env rm -f /home/ubuntu/.ssh/id_rsa as ubuntu@52.89.237.123
|
81
|
+
INFO [0942f874] Finished in 11.547 seconds with exit status 0 (successful).
|
82
|
+
INFO Uploading /Users/colstrom/cloudstrap/.ssh/lkg@colstrom/97cb1464-cf44-479e-be47-9a212131ad4c 100.0%
|
83
|
+
INFO [bec7b898] Running /usr/bin/env chmod -w /home/ubuntu/.ssh/id_rsa as ubuntu@52.89.237.123
|
84
|
+
INFO [bec7b898] Finished in 0.048 seconds with exit status 0 (successful).
|
85
|
+
INFO Uploading /Users/colstrom/bootstrap.properties 100.0%
|
86
|
+
INFO [e091db46] Running /usr/bin/env apt install --assume-yes genisoimage aria2 as ubuntu@54.89.237.123
|
87
|
+
INFO [e091db46] Finished in 8.157 seconds with exit status 0 (successful).
|
88
|
+
INFO [1fa8cae1] Running /usr/bin/env aria2c --continue=true --dir=/opt --out=bootstrap.deb https://s3-us-west-2.amazonaws.com/hcp-concourse/hcp-bootstrap_1.2.30%2Bmaster.77bb464.20160819000448_amd64.deb as ubuntu@52.89.237.123
|
89
|
+
INFO [1fa8cae1] Finished in 3.395 seconds with exit status 0 (successful).
|
90
|
+
INFO [577d4fdc] Running /usr/bin/env dpkg --install /opt/bootstrap.deb as ubuntu@52.89.237.123
|
91
|
+
INFO [577d4fdc] Finished in 3.055 seconds with exit status 0 (successful).
|
92
|
+
|
93
|
+
Contratulations! Your Jumpbox is ready. This instance has been configured with
|
94
|
+
everything you need to deploy your very own Stackato. The SSH key used by this
|
95
|
+
process has been uploaded to your Jumpbox, along with a bootstrap.properties
|
96
|
+
file that has been configured to match the settings used here.
|
97
|
+
|
98
|
+
Human oversight has been disabled.
|
99
|
+
|
100
|
+
Now would be a good time for tea and swordplay (https://xkcd.com/303/). What
|
101
|
+
happens next is non-interactive and will take approximately 30 minutes.
|
102
|
+
|
103
|
+
INFO [03a68da8] Running /usr/bin/env bootstrap install bootstrap.properties as ubuntu@52.89.237.123
|
104
|
+
INFO [03a68da8] Finished in 1457.406 seconds with exit status 0 (successful).
|
105
|
+
#+END_EXAMPLE
|
106
|
+
|
107
|
+
* License
|
108
|
+
|
109
|
+
=cloudstrap= is available under the [[https://tldrlegal.com/license/mit-license][MIT License]]. See ~LICENSE.txt~ for the
|
110
|
+
full text. The software it deploys has its own license.
|
111
|
+
|
112
|
+
* Contributors
|
113
|
+
|
114
|
+
- [[https://colstrom.github.io/][Chris Olstrom]] | [[mailto:chris@olstrom.com][e-mail]] | [[https://twitter.com/ChrisOlstrom][Twitter]]
|
data/bin/cloudstrap
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pastel'
|
4
|
+
|
5
|
+
if ENV['HACKING']
|
6
|
+
require_relative '../lib/cloudstrap'
|
7
|
+
else
|
8
|
+
require 'cloudstrap'
|
9
|
+
end
|
10
|
+
|
11
|
+
gem = Gem::Specification
|
12
|
+
.find_all_by_name('cloudstrap')
|
13
|
+
.sort_by { |spec| spec.version }
|
14
|
+
.last
|
15
|
+
|
16
|
+
config = StackatoLKG::Config.new
|
17
|
+
agent = StackatoLKG::BootstrapAgent.new
|
18
|
+
|
19
|
+
puts <<-EOS
|
20
|
+
# #{gem.name} v#{gem.version}
|
21
|
+
# #{gem.summary}
|
22
|
+
|
23
|
+
# General Configuration
|
24
|
+
# These settings can be configured via ENV or config.yaml
|
25
|
+
|
26
|
+
BOOTSTRAP_REGION=#{config.region}
|
27
|
+
BOOTSTRAP_CACHE_PATH=#{config.cache_path}
|
28
|
+
BOOTSTRAP_VPC_CIDR_BLOCK=#{config.vpc_cidr_block}
|
29
|
+
BOOTSTRAP_PUBLIC_CIDR_BLOCK=#{config.public_cidr_block}
|
30
|
+
BOOTSTRAP_PRIVATE_CIDR_BLOCK=#{config.private_cidr_block}
|
31
|
+
BOOTSTRAP_AMI_OWNER=#{config.ami_owner}
|
32
|
+
BOOTSTRAP_UBUNTU_RELEASE=#{config.ubuntu_release}
|
33
|
+
BOOTSTRAP_INSTANCE_TYPE=#{config.instance_type}
|
34
|
+
BOOTSTRAP_SSH_DIR=#{config.ssh_dir}
|
35
|
+
BOOTSTRAP_SSH_USERNAME=#{config.ssh_username}
|
36
|
+
BOOTSTRAP_HDP_DIR=#{config.hdp_dir}
|
37
|
+
BOOTSTRAP_HDP_BOOTSTRAP_ORIGIN=#{config.hdp_origin}
|
38
|
+
BOOTSTRAP_HDP_BOOTSTRAP_VERSION=#{config.hdp_version}
|
39
|
+
BOOTSTRAP_HDP_BOOTSTRAP_PACKAGE_URL=#{config.hdp_package_url}
|
40
|
+
BOOTSTRAP_PROPERTIES_SEED_URL=#{config.bootstrap_properties_seed_url}
|
41
|
+
|
42
|
+
# Cached Configuration
|
43
|
+
# These settings can be overridden via ENV only
|
44
|
+
|
45
|
+
BOOTSTRAP_USERNAME=#{agent.username}
|
46
|
+
BOOTSTRAP_UUID=#{agent.uuid}
|
47
|
+
BOOTSTRAP_TAG=#{agent.bootstrap_tag}
|
48
|
+
BOOTSTRAP_AMI=#{agent.ami}
|
49
|
+
BOOTSTRAP_VPC_ID=#{agent.vpc}
|
50
|
+
BOOTSTRAP_INTERNET_GATEWAY_ID=#{agent.internet_gateway}
|
51
|
+
BOOTSTRAP_NAT_GATEWAY_ID=#{agent.nat_gateway}
|
52
|
+
BOOTSTRAP_JUMPBOX_SECURITY_GROUP=#{agent.jumpbox_security_group}
|
53
|
+
BOOTSTRAP_PRIVATE_SUBNET_ID=#{agent.private_subnet}
|
54
|
+
BOOTSTRAP_PUBLIC_SUBNET_ID=#{agent.public_subnet}
|
55
|
+
BOOTSTRAP_ROUTE_TABLE_ID=#{agent.route_table}
|
56
|
+
BOOTSTRAP_PRIVATE_ROUTE_TABLE_ID=#{agent.private_route_table}
|
57
|
+
BOOTSTRAP_NAT_ROUTE_ASSOCIATION_ID=#{agent.nat_route_association}
|
58
|
+
BOOTSTRAP_PRIVATE_AVAILABILITY_ZONE=#{agent.private_availability_zone}
|
59
|
+
BOOTSTRAP_PUBLIC_AVAILABILITY_ZONE=#{agent.public_availability_zone}
|
60
|
+
BOOTSTRAP_JUMPBOX_ID=#{agent.jumpbox}
|
61
|
+
BOOTSTRAP_JUMPBOX_IP=#{agent.jumpbox_ip}
|
62
|
+
BOOTSTRAP_WITHOUT_HUMAN_OVERSIGHT=#{!agent.requires_human_oversight?}
|
63
|
+
|
64
|
+
# Additional Information
|
65
|
+
# These do not need configuration, and are presented as a debugging checklist
|
66
|
+
|
67
|
+
# Public IPs Enabled in Public Subnet? #{agent.enable_public_ips}
|
68
|
+
# Gateway Attached to VPC? #{agent.attach_gateway}
|
69
|
+
# Route to Internet via Gateway? #{agent.default_route}
|
70
|
+
# Route to NAT Gateway from Private Subnet? #{agent.nat_route}
|
71
|
+
# SSH Allowed to Jumpbox? #{agent.allow_ssh}
|
72
|
+
# SSH Key uploaded to AWS? #{agent.upload_ssh_key}
|
73
|
+
# HDP bootstrap.properties configured? #{agent.configure_hdp}
|
74
|
+
# Jumpbox Running? #{agent.jumpbox_running?}
|
75
|
+
|
76
|
+
EOS
|
77
|
+
|
78
|
+
if agent.jumpbox_running?
|
79
|
+
agent.configure_jumpbox
|
80
|
+
|
81
|
+
STDERR.puts Pastel.new.green <<-EOS
|
82
|
+
|
83
|
+
Congratulations! Your Jumpbox is ready. This instance has been configured with
|
84
|
+
everything you need to deploy your very own Stackato. The SSH key used by this
|
85
|
+
process has been uploaded to your Jumpbox, along with a bootstrap.properties
|
86
|
+
file that has been configured to match the settings used here.
|
87
|
+
EOS
|
88
|
+
|
89
|
+
if agent.requires_human_oversight?
|
90
|
+
STDERR.puts <<-EOS
|
91
|
+
When you are ready to proceed, the following command will do the rest:
|
92
|
+
|
93
|
+
ssh -l ubuntu -i #{agent.ssh_key.private_file} #{agent.jumpbox_ip} bootstrap
|
94
|
+
|
95
|
+
EOS
|
96
|
+
else
|
97
|
+
STDERR.puts Pastel.new.bold.bright_yellow.on_blue 'Human oversight has been disabled.'
|
98
|
+
|
99
|
+
STDERR.puts Pastel.new.blue <<-EOS
|
100
|
+
|
101
|
+
Now would be a good time for tea and swordplay (https://xkcd.com/303/). What
|
102
|
+
happens next is non-interactive and will take approximately 30 minutes.
|
103
|
+
EOS
|
104
|
+
agent.launch
|
105
|
+
end
|
106
|
+
|
107
|
+
else
|
108
|
+
STDERR.puts Pastel.new.red <<-EOS
|
109
|
+
Your Jumpbox (#{agent.jumpbox}) is not in a "running" state. It is normal for
|
110
|
+
the first boot to take several minutes as the instance configures itself.
|
111
|
+
|
112
|
+
If you wait a few minutes and try again, it should work.
|
113
|
+
EOS
|
114
|
+
abort
|
115
|
+
end
|
data/cloudstrap.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = 'cloudstrap'
|
3
|
+
gem.version = `git describe --tags --abbrev=0`.chomp + '.pre'
|
4
|
+
gem.licenses = 'MIT'
|
5
|
+
gem.authors = ['Chris Olstrom']
|
6
|
+
gem.email = 'chris@olstrom.com'
|
7
|
+
gem.homepage = 'https://github.com/colstrom/cloudstrap'
|
8
|
+
gem.summary = 'Strapping Boots to Clouds'
|
9
|
+
|
10
|
+
gem.files = `git ls-files`.split("\n")
|
11
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
12
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
13
|
+
gem.require_paths = ['lib']
|
14
|
+
|
15
|
+
gem.add_runtime_dependency 'aws-sdk', '~> 2.5', '>= 2.5.0'
|
16
|
+
gem.add_runtime_dependency 'contracts', '~> 0.14', '>= 0.14.0'
|
17
|
+
gem.add_runtime_dependency 'retries', '~> 0.0.5', '>= 0.0.5'
|
18
|
+
gem.add_runtime_dependency 'moneta', '~> 0.8', '>= 0.8.0'
|
19
|
+
gem.add_runtime_dependency 'sshkey', '~> 1.8', '>= 1.8.0'
|
20
|
+
gem.add_runtime_dependency 'sshkit', '~> 1.11', '>= 1.11.0'
|
21
|
+
gem.add_runtime_dependency 'java-properties', '~> 0.1', '>= 0.1.1'
|
22
|
+
gem.add_runtime_dependency 'pastel', '~> 0.6', '>= 0.6.0'
|
23
|
+
gem.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.0'
|
24
|
+
end
|
data/lib/cloudstrap.rb
ADDED
@@ -0,0 +1,377 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'contracts'
|
3
|
+
require_relative 'service'
|
4
|
+
|
5
|
+
module StackatoLKG
|
6
|
+
module Amazon
|
7
|
+
class EC2 < Service
|
8
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Vpc]
|
9
|
+
def vpcs
|
10
|
+
@vpcs ||= vpcs!
|
11
|
+
end
|
12
|
+
|
13
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Vpc]
|
14
|
+
def vpcs!
|
15
|
+
@vpcs = call_api(:describe_vpcs).vpcs
|
16
|
+
end
|
17
|
+
|
18
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Subnet]
|
19
|
+
def subnets
|
20
|
+
@subnets ||= subnets!
|
21
|
+
end
|
22
|
+
|
23
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Subnet]
|
24
|
+
def subnets!
|
25
|
+
@subnets = call_api(:describe_subnets).subnets
|
26
|
+
end
|
27
|
+
|
28
|
+
Contract None => ArrayOf[::Aws::EC2::Types::RouteTable]
|
29
|
+
def route_tables
|
30
|
+
@route_tables ||= route_tables!
|
31
|
+
end
|
32
|
+
|
33
|
+
Contract None => ArrayOf[::Aws::EC2::Types::RouteTable]
|
34
|
+
def route_tables!
|
35
|
+
@route_tables = call_api(:describe_route_tables).route_tables
|
36
|
+
end
|
37
|
+
|
38
|
+
Contract String => ::Aws::EC2::Types::RouteTable
|
39
|
+
def create_route_table(vpc_id)
|
40
|
+
call_api(:create_route_table, vpc_id: vpc_id).route_table
|
41
|
+
.tap { route_tables! }
|
42
|
+
end
|
43
|
+
|
44
|
+
Contract None => ArrayOf[::Aws::EC2::Types::NatGateway]
|
45
|
+
def nat_gateways
|
46
|
+
@nat_gateways ||= nat_gateways!
|
47
|
+
end
|
48
|
+
|
49
|
+
Contract None => ArrayOf[::Aws::EC2::Types::NatGateway]
|
50
|
+
def nat_gateways!
|
51
|
+
@nat_gateways ||= call_api(:describe_nat_gateways).nat_gateways
|
52
|
+
end
|
53
|
+
|
54
|
+
Contract String, String => ::Aws::EC2::Types::NatGateway
|
55
|
+
def create_nat_gateway(subnet_id, allocation_id)
|
56
|
+
call_api(:create_nat_gateway, subnet_id: subnet_id, allocation_id: allocation_id).nat_gateway
|
57
|
+
.tap { nat_gateways! }
|
58
|
+
end
|
59
|
+
|
60
|
+
Contract None => ArrayOf[::Aws::EC2::Types::InternetGateway]
|
61
|
+
def internet_gateways
|
62
|
+
@internet_gateways ||= internet_gateways!
|
63
|
+
end
|
64
|
+
|
65
|
+
Contract None => ArrayOf[::Aws::EC2::Types::InternetGateway]
|
66
|
+
def internet_gateways!
|
67
|
+
@internet_gateways = call_api(:describe_internet_gateways).internet_gateways
|
68
|
+
end
|
69
|
+
|
70
|
+
Contract String => Bool
|
71
|
+
def internet_gateway_exist?(internet_gateway_id)
|
72
|
+
! internet_gateways.select { |igw| igw.internet_gateway_id == internet_gateway_id }.empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
Contract String, String => Bool
|
76
|
+
def internet_gateway_attached?(internet_gateway_id, vpc_id)
|
77
|
+
(internet_gateway_exist?(internet_gateway_id) ? internet_gateways : internet_gateways!)
|
78
|
+
.flat_map { |internet_gateway| internet_gateway.attachments }
|
79
|
+
.any? { |attachment| attachment.vpc_id == vpc_id }
|
80
|
+
end
|
81
|
+
|
82
|
+
Contract String, String => Bool
|
83
|
+
def attach_internet_gateway(internet_gateway_id, vpc_id)
|
84
|
+
call_api(:attach_internet_gateway,
|
85
|
+
internet_gateway_id: internet_gateway_id,
|
86
|
+
vpc_id: vpc_id).successful?
|
87
|
+
rescue ::Aws::EC2::Errors::ResourceAlreadyAssociated
|
88
|
+
internet_gateway_attached? internet_gateway_id, vpc_id
|
89
|
+
end
|
90
|
+
|
91
|
+
Contract String, String, String => Bool
|
92
|
+
def create_route(destination_cidr_block, gateway_id, route_table_id)
|
93
|
+
call_api(:create_route,
|
94
|
+
route_table_id: route_table_id,
|
95
|
+
destination_cidr_block: destination_cidr_block,
|
96
|
+
gateway_id: gateway_id).successful?
|
97
|
+
.tap { route_tables! }
|
98
|
+
rescue ::Aws::EC2::Errors::RouteAlreadyExists
|
99
|
+
route_tables!
|
100
|
+
.select { |route_table| route_table.route_table_id = route_table_id }
|
101
|
+
.flat_map { |route_table| route_table.routes }
|
102
|
+
.select { |route| route.destination_cidr_block == destination_cidr_block }
|
103
|
+
.any? { |route| route.gateway_id == gateway_id || route.nat_gateway_id == gateway_id }
|
104
|
+
end
|
105
|
+
|
106
|
+
Contract String, String => String
|
107
|
+
def associate_route_table(route_table_id, subnet_id)
|
108
|
+
call_api(:associate_route_table,
|
109
|
+
route_table_id: route_table_id,
|
110
|
+
subnet_id: subnet_id).association_id
|
111
|
+
.tap { route_tables! }
|
112
|
+
end
|
113
|
+
|
114
|
+
Contract None => ::Aws::EC2::Types::InternetGateway
|
115
|
+
def create_internet_gateway
|
116
|
+
call_api(:create_internet_gateway).internet_gateway
|
117
|
+
.tap { internet_gateways! }
|
118
|
+
end
|
119
|
+
|
120
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Instance]
|
121
|
+
def instances
|
122
|
+
@instances ||= instances!
|
123
|
+
end
|
124
|
+
|
125
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Instance]
|
126
|
+
def instances!
|
127
|
+
@instances = call_api(:describe_instances)
|
128
|
+
.reservations
|
129
|
+
.flat_map(&:instances)
|
130
|
+
end
|
131
|
+
|
132
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Address]
|
133
|
+
def addresses
|
134
|
+
@addresses ||= addresses!
|
135
|
+
end
|
136
|
+
|
137
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Address]
|
138
|
+
def addresses!
|
139
|
+
@addresses = call_api(:describe_addresses).addresses
|
140
|
+
end
|
141
|
+
|
142
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Address]
|
143
|
+
def unassociated_addresses
|
144
|
+
addresses
|
145
|
+
.select { |address| address.domain == 'vpc' }
|
146
|
+
.select { |address| address.association_id == nil }
|
147
|
+
end
|
148
|
+
|
149
|
+
Contract None => Maybe[String]
|
150
|
+
def unassociated_address
|
151
|
+
unassociated_addresses.map(&:allocation_id).sample
|
152
|
+
end
|
153
|
+
|
154
|
+
Contract None => String
|
155
|
+
def create_address
|
156
|
+
call_api(:allocate_address).allocation_id
|
157
|
+
.tap { addresses! }
|
158
|
+
end
|
159
|
+
|
160
|
+
Contract None => ArrayOf[::Aws::EC2::Types::SecurityGroup]
|
161
|
+
def security_groups
|
162
|
+
@security_groups ||= security_groups!
|
163
|
+
end
|
164
|
+
|
165
|
+
Contract None => ArrayOf[::Aws::EC2::Types::SecurityGroup]
|
166
|
+
def security_groups!
|
167
|
+
@security_groups = call_api(:describe_security_groups).security_groups
|
168
|
+
end
|
169
|
+
|
170
|
+
Contract None => ArrayOf[::Aws::EC2::Types::TagDescription]
|
171
|
+
def tags
|
172
|
+
@tags ||= tags!
|
173
|
+
end
|
174
|
+
|
175
|
+
Contract None => ArrayOf[::Aws::EC2::Types::TagDescription]
|
176
|
+
def tags!
|
177
|
+
@tags = call_api(:describe_tags).tags
|
178
|
+
end
|
179
|
+
|
180
|
+
Contract KeywordArgs[
|
181
|
+
image_id: String,
|
182
|
+
instance_type: String,
|
183
|
+
key_name: Optional[String],
|
184
|
+
client_token: Optional[String],
|
185
|
+
network_interfaces: Optional[ArrayOf[Hash]]
|
186
|
+
] => ::Aws::EC2::Types::Instance
|
187
|
+
def create_instance(**properties)
|
188
|
+
call_api(:run_instances, properties.merge(min_count: 1, max_count: 2)).instances.first
|
189
|
+
.tap { instances! }
|
190
|
+
end
|
191
|
+
|
192
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Image]
|
193
|
+
def images
|
194
|
+
@images ||= images!
|
195
|
+
end
|
196
|
+
|
197
|
+
Contract None => ArrayOf[::Aws::EC2::Types::Image]
|
198
|
+
def images!
|
199
|
+
@images ||= call_api(:describe_images,
|
200
|
+
owners: [config.ami_owner],
|
201
|
+
filters: [
|
202
|
+
{ name: 'virtualization-type', values: ['hvm'] },
|
203
|
+
{ name: 'architecture', values: ['x86_64'] },
|
204
|
+
{ name: 'root-device-type', values: ['ebs'] },
|
205
|
+
{ name: 'block-device-mapping.volume-type', values: ['gp2'] }
|
206
|
+
])
|
207
|
+
.images
|
208
|
+
.reject { |image| image.sriov_net_support.nil? }
|
209
|
+
end
|
210
|
+
|
211
|
+
Contract RespondTo[:to_s] => ArrayOf[::Aws::EC2::Types::Image]
|
212
|
+
def ubuntu_images(release)
|
213
|
+
images
|
214
|
+
.select { |image| image.name.start_with? 'ubuntu/images/' }
|
215
|
+
.select { |image| image.name.include? release.to_s }
|
216
|
+
end
|
217
|
+
|
218
|
+
Contract RespondTo[:to_s] => ::Aws::EC2::Types::Image
|
219
|
+
def latest_ubuntu(release)
|
220
|
+
ubuntu_images(release)
|
221
|
+
.sort_by { |image| image.creation_date }
|
222
|
+
.last
|
223
|
+
end
|
224
|
+
|
225
|
+
Contract None => ArrayOf[::Aws::EC2::Types::KeyPairInfo]
|
226
|
+
def key_pairs
|
227
|
+
@key_pairs ||= key_pairs!
|
228
|
+
end
|
229
|
+
|
230
|
+
Contract None => ArrayOf[::Aws::EC2::Types::KeyPairInfo]
|
231
|
+
def key_pairs!
|
232
|
+
@key_pairs = call_api(:describe_key_pairs).key_pairs
|
233
|
+
end
|
234
|
+
|
235
|
+
Contract String => Maybe[String]
|
236
|
+
def key_fingerprint(key_name)
|
237
|
+
key_pairs
|
238
|
+
.select { |ssh| ssh.key_name == key_name }
|
239
|
+
.map { |ssh| ssh.key_fingerprint }
|
240
|
+
.first
|
241
|
+
end
|
242
|
+
|
243
|
+
Contract String, String => String
|
244
|
+
def import_key_pair(key_name, public_key_material)
|
245
|
+
call_api(:import_key_pair, key_name: key_name, public_key_material: public_key_material).key_fingerprint
|
246
|
+
.tap { key_pairs! }
|
247
|
+
rescue ::Aws::EC2::Errors::InvalidKeyPairDuplicate
|
248
|
+
key_fingerprint(key_name)
|
249
|
+
end
|
250
|
+
|
251
|
+
Contract None => ::Aws::EC2::Types::Vpc
|
252
|
+
def create_vpc
|
253
|
+
call_api(:create_vpc, cidr_block: config.vpc_cidr_block).vpc
|
254
|
+
.tap { vpcs! }
|
255
|
+
end
|
256
|
+
|
257
|
+
Contract KeywordArgs[
|
258
|
+
cidr_block: Optional[String],
|
259
|
+
vpc_id: Optional[String],
|
260
|
+
subnet_id: Optional[String]
|
261
|
+
] => ArrayOf[::Aws::EC2::Types::Subnet]
|
262
|
+
def subnets(cidr_block: nil, vpc_id: nil, subnet_id: nil)
|
263
|
+
subnets
|
264
|
+
.select { |subnet| subnet_id.nil? || subnet.subnet_id == subnet_id }
|
265
|
+
.select { |subnet| vpc_id.nil? || subnet.vpc_id == vpc_id }
|
266
|
+
.select { |subnet| cidr_block.nil? || subnet.cidr_block == cidr_block }
|
267
|
+
end
|
268
|
+
|
269
|
+
Contract Args[Any] => Any
|
270
|
+
def subnets!(**properties)
|
271
|
+
subnets!
|
272
|
+
subnets(properties)
|
273
|
+
end
|
274
|
+
|
275
|
+
Contract Args[Any] => Maybe[::Aws::EC2::Types::Subnet]
|
276
|
+
def subnet(**properties)
|
277
|
+
subnets(properties).first
|
278
|
+
end
|
279
|
+
|
280
|
+
Contract Args[Any] => Any
|
281
|
+
def subnet!(**properties)
|
282
|
+
subnets!
|
283
|
+
subnet(properties)
|
284
|
+
end
|
285
|
+
|
286
|
+
Contract KeywordArgs[
|
287
|
+
cidr_block: String,
|
288
|
+
vpc_id: String
|
289
|
+
] => ::Aws::EC2::Types::Subnet
|
290
|
+
def create_subnet(**properties)
|
291
|
+
call_api(:create_subnet, properties).subnet
|
292
|
+
.tap { subnets! }
|
293
|
+
rescue ::Aws::EC2::Errors::InvalidSubnetConflict
|
294
|
+
subnet(properties) || subnet!(properties)
|
295
|
+
end
|
296
|
+
|
297
|
+
Contract String => Bool
|
298
|
+
def map_public_ip_on_launch?(subnet_id)
|
299
|
+
subnets(subnet_id: subnet_id)
|
300
|
+
.map { |subnet| subnet.map_public_ip_on_launch }
|
301
|
+
.first == true
|
302
|
+
end
|
303
|
+
|
304
|
+
Contract String, Bool => Bool
|
305
|
+
def map_public_ip_on_launch(subnet_id, value)
|
306
|
+
call_api(:modify_subnet_attribute,
|
307
|
+
subnet_id: subnet_id,
|
308
|
+
map_public_ip_on_launch: { value: value }
|
309
|
+
).successful?
|
310
|
+
.tap { subnets! }
|
311
|
+
end
|
312
|
+
|
313
|
+
Contract RespondTo[:to_s], RespondTo[:to_i], RespondTo[:to_s], String => Bool
|
314
|
+
def authorize_security_group_ingress(ip_protocol, port, cidr_ip, group_id)
|
315
|
+
call_api(:authorize_security_group_ingress,
|
316
|
+
group_id: group_id,
|
317
|
+
ip_protocol: ip_protocol.to_s,
|
318
|
+
from_port: port.to_i,
|
319
|
+
to_port: port.to_i,
|
320
|
+
cidr_ip: cidr_ip.to_s
|
321
|
+
).successful?
|
322
|
+
.tap { security_groups! }
|
323
|
+
rescue ::Aws::EC2::Errors::InvalidPermissionDuplicate
|
324
|
+
true
|
325
|
+
end
|
326
|
+
|
327
|
+
Contract RespondTo[:to_s], String => String
|
328
|
+
def create_security_group(group_name, vpc_id)
|
329
|
+
call_api(:create_security_group,
|
330
|
+
group_name: group_name.to_s,
|
331
|
+
description: group_name.to_s,
|
332
|
+
vpc_id: vpc_id).group_id
|
333
|
+
.tap { security_groups! }
|
334
|
+
rescue ::Aws::EC2::Errors::InvalidGroupDuplicate
|
335
|
+
security_group(group_name.to_s, vpc_id)
|
336
|
+
end
|
337
|
+
|
338
|
+
Contract RespondTo[:to_s], String => String
|
339
|
+
def security_group(group_name, vpc_id)
|
340
|
+
security_groups
|
341
|
+
.select { |sg| sg.vpc_id == vpc_id }
|
342
|
+
.select { |sg| sg.group_name == group_name }
|
343
|
+
.first
|
344
|
+
.group_id
|
345
|
+
end
|
346
|
+
|
347
|
+
Contract ArrayOf[String], ArrayOf[{ key: String, value: String}] => Bool
|
348
|
+
def create_tags(resources, tags)
|
349
|
+
call_api(:create_tags, resources: resources, tags: tags).successful?
|
350
|
+
.tap { tags! }
|
351
|
+
end
|
352
|
+
|
353
|
+
Contract String, Args[String] => Bool
|
354
|
+
def assign_name(name, *resources)
|
355
|
+
create_tags(resources, [{ key: 'Name', value: name } ])
|
356
|
+
end
|
357
|
+
|
358
|
+
Contract KeywordArgs[
|
359
|
+
type: Optional[String],
|
360
|
+
key: Optional[String],
|
361
|
+
value: Optional[String]
|
362
|
+
] => ArrayOf[::Aws::EC2::Types::TagDescription]
|
363
|
+
def tagged(type: nil, key: nil, value: nil)
|
364
|
+
tags
|
365
|
+
.select { |tag| type.nil? || tag.resource_type == type }
|
366
|
+
.select { |tag| tag.key == (key || 'Name') }
|
367
|
+
.select { |tag| value.nil? || tag.value == value }
|
368
|
+
end
|
369
|
+
|
370
|
+
private
|
371
|
+
|
372
|
+
def client
|
373
|
+
Aws::EC2::Client
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|