hashicorptools 0.2.2 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3480aac6dcba04268d682dbd19fddb5d3fa43220e5e9b3cc0c679391749d217e
4
- data.tar.gz: fe0b0c9a625b495dc830913a3a4b957ec7a1c68dc3aa98b41ac48888abea33e4
3
+ metadata.gz: 8678bee5e4e1f1c2a2efa53625d495e3c91eb1b1170ca29831f9f21c0b92d6a1
4
+ data.tar.gz: e233456a2da0aca57736ddcbe400ea97bc0366a8d5e3b11cfb9f2b77b08dee22
5
5
  SHA512:
6
- metadata.gz: 16bdfd1e3ecf8152f230e5f145b70d8e0356cef6af22651294567a8b1eb33c66edc1e4582816610a8180ce53067873d4894203dd03a2b1699183b04007d9d5c2
7
- data.tar.gz: e61e5e7c5418954fedf936e187d778c8f413236020cc193bd80934b95efa72135a74f4f13cef32b21553c8198978a5400501cee9de98723f5eb1c55ee4d3c9c6
6
+ metadata.gz: c5c10e25f54a76390e3b39434e166f4bbd754a19096063ef760feaafd01a4cfccaa971674ecf7d61f9f0165a0d71651400d62615248da3fe7940e7b21bb6d326
7
+ data.tar.gz: 8a09c1eaac106fbc2716a43f26384fbaab1cc2d6a0386167e187e363ed043e88efe693a0cebabb1e9d050bb3bc8bb1ed0d769ae53b40002725627f0475b6cca6
@@ -1 +1 @@
1
- ruby-2.5.1
1
+ ruby-2.6.6
@@ -1,3 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.2.5"
3
+ - "2.6.6"
4
+ # TravisCI uses Bundler 1 by default, but we want Bundler 2
5
+ # https://docs.travis-ci.com/user/languages/ruby/#bundler-20
6
+ before_install:
7
+ - gem install bundler
data/Gemfile CHANGED
@@ -3,21 +3,18 @@ source "http://rubygems.org"
3
3
  # try to slowly migrate to v2 of the aws api
4
4
  gem 'aws-sdk', '~> 2'
5
5
 
6
- gem 'dynect_rest'
6
+ # this is somewhat undesirable but lets us update json gem version. We should really replace the old v1 code.
7
+ gem 'aws-sdk-v1-ruby24', github: 'seielit/aws-sdk-v1-ruby24', ref: 'aws-sdk-v1-ruby24'
8
+ gem 'dotenv', '~> 2.2', '>= 2.2.1'
9
+ gem 'thor', '>= 0.20.0'
10
+ gem 'activesupport', '>= 5.1.4'
11
+ gem 'byebug', '>= 10.0.2'
12
+ gem 'git', '> 1.3'
7
13
 
8
- gem 'aws-sdk-v1'
9
- gem 'dotenv'
10
- gem 'thor'
11
- gem 'activesupport'
12
- gem 'byebug'
13
- gem 'git'
14
-
15
- # Add dependencies to develop your gem here.
16
- # Include everything needed to run rake, tests, features, etc.
17
14
  group :development do
18
- gem "rspec"
19
- gem "rdoc", "~> 3.12"
20
- gem "bundler", "~> 1.0"
21
- gem "juwelier"
22
- gem "simplecov", ">= 0"
15
+ gem 'rspec', '> 3.7'
16
+ gem 'rdoc', '> 3.12'
17
+ gem 'bundler', '> 2.0'
18
+ gem 'juwelier', git: 'https://github.com/flajann2/juwelier.git'
19
+ gem 'simplecov', '>= 0'
23
20
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.5.1
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: hashicorptools 0.2.2 ruby lib
5
+ # stub: hashicorptools 0.5.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "hashicorptools".freeze
9
- s.version = "0.2.2"
9
+ s.version = "0.5.1"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Nathan Woodhull".freeze]
14
- s.date = "2018-07-20"
14
+ s.date = "2020-07-29"
15
15
  s.description = "Wrappers for terraform and packer".freeze
16
16
  s.email = "systems@controlshiftlabs.com".freeze
17
17
  s.executables = ["ec2_host".freeze]
@@ -24,7 +24,6 @@ Gem::Specification.new do |s|
24
24
  ".ruby-version",
25
25
  ".travis.yml",
26
26
  "Gemfile",
27
- "Gemfile.lock",
28
27
  "LICENSE",
29
28
  "README.md",
30
29
  "Rakefile",
@@ -38,7 +37,6 @@ Gem::Specification.new do |s|
38
37
  "lib/hashicorptools/ec2_utilities.rb",
39
38
  "lib/hashicorptools/host.rb",
40
39
  "lib/hashicorptools/packer.rb",
41
- "lib/hashicorptools/terraform.rb",
42
40
  "lib/hashicorptools/update_launch_configuration.rb",
43
41
  "lib/hashicorptools/variables.rb",
44
42
  "spec/hashicorptools_spec.rb",
@@ -46,7 +44,7 @@ Gem::Specification.new do |s|
46
44
  ]
47
45
  s.homepage = "http://github.com/woodhull/hashicorptools".freeze
48
46
  s.licenses = ["MIT".freeze]
49
- s.rubygems_version = "2.7.6".freeze
47
+ s.rubygems_version = "3.0.8".freeze
50
48
  s.summary = "Wrappers for terraform and packer".freeze
51
49
 
52
50
  if s.respond_to? :specification_version then
@@ -54,45 +52,42 @@ Gem::Specification.new do |s|
54
52
 
55
53
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
54
  s.add_runtime_dependency(%q<aws-sdk>.freeze, ["~> 2"])
57
- s.add_runtime_dependency(%q<dynect_rest>.freeze, [">= 0"])
58
- s.add_runtime_dependency(%q<aws-sdk-v1>.freeze, [">= 0"])
59
- s.add_runtime_dependency(%q<dotenv>.freeze, [">= 0"])
60
- s.add_runtime_dependency(%q<thor>.freeze, [">= 0"])
61
- s.add_runtime_dependency(%q<activesupport>.freeze, [">= 0"])
62
- s.add_runtime_dependency(%q<byebug>.freeze, [">= 0"])
63
- s.add_runtime_dependency(%q<git>.freeze, [">= 0"])
64
- s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
65
- s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
66
- s.add_development_dependency(%q<bundler>.freeze, ["~> 1.0"])
55
+ s.add_runtime_dependency(%q<aws-sdk-v1-ruby24>.freeze, [">= 0"])
56
+ s.add_runtime_dependency(%q<dotenv>.freeze, ["~> 2.2", ">= 2.2.1"])
57
+ s.add_runtime_dependency(%q<thor>.freeze, [">= 0.20.0"])
58
+ s.add_runtime_dependency(%q<activesupport>.freeze, [">= 5.1.4"])
59
+ s.add_runtime_dependency(%q<byebug>.freeze, [">= 10.0.2"])
60
+ s.add_runtime_dependency(%q<git>.freeze, ["> 1.3"])
61
+ s.add_development_dependency(%q<rspec>.freeze, ["> 3.7"])
62
+ s.add_development_dependency(%q<rdoc>.freeze, ["> 3.12"])
63
+ s.add_development_dependency(%q<bundler>.freeze, ["> 2.0"])
67
64
  s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
68
65
  s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
69
66
  else
70
67
  s.add_dependency(%q<aws-sdk>.freeze, ["~> 2"])
71
- s.add_dependency(%q<dynect_rest>.freeze, [">= 0"])
72
- s.add_dependency(%q<aws-sdk-v1>.freeze, [">= 0"])
73
- s.add_dependency(%q<dotenv>.freeze, [">= 0"])
74
- s.add_dependency(%q<thor>.freeze, [">= 0"])
75
- s.add_dependency(%q<activesupport>.freeze, [">= 0"])
76
- s.add_dependency(%q<byebug>.freeze, [">= 0"])
77
- s.add_dependency(%q<git>.freeze, [">= 0"])
78
- s.add_dependency(%q<rspec>.freeze, [">= 0"])
79
- s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
80
- s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
68
+ s.add_dependency(%q<aws-sdk-v1-ruby24>.freeze, [">= 0"])
69
+ s.add_dependency(%q<dotenv>.freeze, ["~> 2.2", ">= 2.2.1"])
70
+ s.add_dependency(%q<thor>.freeze, [">= 0.20.0"])
71
+ s.add_dependency(%q<activesupport>.freeze, [">= 5.1.4"])
72
+ s.add_dependency(%q<byebug>.freeze, [">= 10.0.2"])
73
+ s.add_dependency(%q<git>.freeze, ["> 1.3"])
74
+ s.add_dependency(%q<rspec>.freeze, ["> 3.7"])
75
+ s.add_dependency(%q<rdoc>.freeze, ["> 3.12"])
76
+ s.add_dependency(%q<bundler>.freeze, ["> 2.0"])
81
77
  s.add_dependency(%q<juwelier>.freeze, [">= 0"])
82
78
  s.add_dependency(%q<simplecov>.freeze, [">= 0"])
83
79
  end
84
80
  else
85
81
  s.add_dependency(%q<aws-sdk>.freeze, ["~> 2"])
86
- s.add_dependency(%q<dynect_rest>.freeze, [">= 0"])
87
- s.add_dependency(%q<aws-sdk-v1>.freeze, [">= 0"])
88
- s.add_dependency(%q<dotenv>.freeze, [">= 0"])
89
- s.add_dependency(%q<thor>.freeze, [">= 0"])
90
- s.add_dependency(%q<activesupport>.freeze, [">= 0"])
91
- s.add_dependency(%q<byebug>.freeze, [">= 0"])
92
- s.add_dependency(%q<git>.freeze, [">= 0"])
93
- s.add_dependency(%q<rspec>.freeze, [">= 0"])
94
- s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
95
- s.add_dependency(%q<bundler>.freeze, ["~> 1.0"])
82
+ s.add_dependency(%q<aws-sdk-v1-ruby24>.freeze, [">= 0"])
83
+ s.add_dependency(%q<dotenv>.freeze, ["~> 2.2", ">= 2.2.1"])
84
+ s.add_dependency(%q<thor>.freeze, [">= 0.20.0"])
85
+ s.add_dependency(%q<activesupport>.freeze, [">= 5.1.4"])
86
+ s.add_dependency(%q<byebug>.freeze, [">= 10.0.2"])
87
+ s.add_dependency(%q<git>.freeze, ["> 1.3"])
88
+ s.add_dependency(%q<rspec>.freeze, ["> 3.7"])
89
+ s.add_dependency(%q<rdoc>.freeze, ["> 3.12"])
90
+ s.add_dependency(%q<bundler>.freeze, ["> 2.0"])
96
91
  s.add_dependency(%q<juwelier>.freeze, [">= 0"])
97
92
  s.add_dependency(%q<simplecov>.freeze, [">= 0"])
98
93
  end
@@ -4,7 +4,6 @@ require 'thor'
4
4
  require 'active_support/all'
5
5
  require 'aws-sdk-v1'
6
6
  require 'aws-sdk'
7
- require 'dynect_rest'
8
7
 
9
8
  module Hashicorptools
10
9
  end
@@ -13,7 +12,6 @@ require_relative 'hashicorptools/variables'
13
12
  require_relative 'hashicorptools/ec2_utilities'
14
13
  require_relative 'hashicorptools/auto_scaling_group'
15
14
  require_relative 'hashicorptools/packer'
16
- require_relative 'hashicorptools/terraform'
17
15
  require_relative 'hashicorptools/host'
18
16
  require_relative 'hashicorptools/update_launch_configuration'
19
17
  require_relative 'hashicorptools/code_deploy'
@@ -15,6 +15,7 @@
15
15
  }
16
16
  ],
17
17
  "region": "us-east-1",
18
+ "ami_regions": ["us-east-1", "eu-central-1"],
18
19
  "run_tags": {
19
20
  "kind": "packer",
20
21
  "role": "AMI builder"
@@ -2,7 +2,7 @@ require "timeout"
2
2
 
3
3
  module Hashicorptools
4
4
  class AutoScalingGroup
5
- attr_accessor :name
5
+ attr_accessor :name, :region
6
6
 
7
7
  def initialize(attrs = {})
8
8
  attrs.each do |key,value|
@@ -115,15 +115,15 @@ module Hashicorptools
115
115
  end
116
116
 
117
117
  def autoscaling
118
- @autoscaling ||= Aws::AutoScaling::Client.new(region: 'us-east-1')
118
+ @autoscaling ||= Aws::AutoScaling::Client.new(region: region)
119
119
  end
120
120
 
121
121
  def ec2
122
- @ec2 ||= Aws::EC2::Client.new(region: 'us-east-1')
122
+ @ec2 ||= Aws::EC2::Client.new(region: region)
123
123
  end
124
124
 
125
125
  def elb
126
- @elb ||= Aws::ElasticLoadBalancing::Client.new(region: 'us-east-1')
126
+ @elb ||= Aws::ElasticLoadBalancing::Client.new(region: region)
127
127
  end
128
128
 
129
129
  def groups
@@ -7,52 +7,98 @@ require 'logger'
7
7
  require 'thor'
8
8
 
9
9
  module Hashicorptools
10
+ class RegionDeployment
11
+ attr_accessor :aws_region, :environment
12
+
13
+ def initialize(aws_region:, environment:)
14
+ @aws_region = aws_region
15
+ @environment = environment
16
+ end
17
+
18
+ def create_deployment(commit_id, commit_message)
19
+ client = Aws::CodeDeploy::Client.new(region: aws_region)
20
+ response = client.create_deployment({
21
+ application_name: application_name,
22
+ deployment_group_name: "#{application_name}-#{@environment}",
23
+ revision: {
24
+ revision_type: 'GitHub',
25
+ git_hub_location: {
26
+ repository: "controlshift/#{application_name}",
27
+ commit_id: commit_id
28
+ }
29
+ },
30
+ description: (commit_message || "commit #{commit_id}").slice(0,99)
31
+ })
32
+ output "created deployment #{response.deployment_id}"
33
+ output "https://console.aws.amazon.com/codedeploy/home?region=#{aws_region}#/deployments/#{response.deployment_id}"
34
+ end
35
+
36
+ private
37
+
38
+ def application_name
39
+ raise "implement me"
40
+ end
41
+
42
+ def output(text)
43
+ puts "[#{aws_region}] #{text}"
44
+ end
45
+ end
46
+
10
47
  class CodeDeploy < Thor
48
+ AWS_REGION_US_EAST_1 = 'us-east-1'
11
49
 
12
50
  desc 'deploy', 'deploy latest code to environment'
13
- option :environment, :required => true
14
- option :branch, default: 'master'
51
+ option :environment, required: true
52
+ option :branch
53
+ option :aws_regions, type: :array
15
54
  option :commit
16
55
  def deploy
17
56
  g = Git.open('..')
18
57
 
58
+ # We set defaults (depending on environment) for aws_regions if not passed in
59
+ aws_regions = options[:aws_regions] || default_regions
60
+
19
61
  commit = if options[:commit].present?
20
62
  g.gcommit(options[:commit])
21
63
  else
22
- g.checkout(options[:branch].to_sym)
64
+ branch = options[:branch].nil? ? :main : options[:branch].to_sym
65
+ g.checkout(branch)
23
66
  g.log.first
24
67
  end
25
68
 
69
+ puts "Deploying to environment #{options[:environment]} - regions: #{aws_regions.join(', ')}
70
+ commit: #{commit.sha}
71
+ message: #{commit.message}"
26
72
 
27
- puts "deploying commit: #{commit.sha} #{commit.message}"
73
+ puts "Deploying for regions: #{aws_regions}"
28
74
 
29
- create_deployment(commit.sha, commit.message)
75
+ threads = []
76
+ aws_regions.each_slice(2) do |aws_regions_batch|
77
+ puts "Deploying for batch of regions: #{aws_regions_batch}"
78
+ aws_regions_batch.each do |aws_region|
79
+ thread = Thread.new{ region_deployment(aws_region).create_deployment(commit.sha, commit.message) }
80
+ threads.push(thread)
81
+ end
82
+
83
+ threads.each_with_index do |thread, index|
84
+ begin
85
+ thread.join
86
+ rescue Exception => e
87
+ # Don't quit whole program on exception in thread, just print exception and exit thread
88
+ puts "[#{aws_regions[index]}] EXCEPTION: #{e}"
89
+ end
90
+ end
91
+ end
30
92
  end
31
93
 
32
94
  private
33
95
 
34
- def create_deployment(commit_id, commit_message = nil)
35
- Dotenv.load
36
-
37
- client = Aws::CodeDeploy::Client.new
38
- response = client.create_deployment({
39
- application_name: application_name,
40
- deployment_group_name: "#{application_name}-#{options[:environment]}",
41
- revision: {
42
- revision_type: 'GitHub',
43
- git_hub_location: {
44
- repository: "controlshift/#{application_name}",
45
- commit_id: commit_id
46
- }
47
- },
48
- description: (commit_message || "commit #{commit_id}").slice(0,99)
49
- })
50
- puts "created deployment #{response.deployment_id}"
51
- puts "https://console.aws.amazon.com/codedeploy/home?region=#{ENV['AWS_REGION']}#/deployments/#{response.deployment_id}"
96
+ def region_deployment(aws_region)
97
+ RegionDeployment.new(aws_region: aws_region, environment: options[:environment])
52
98
  end
53
99
 
54
- def application_name
55
- raise "implement me"
100
+ def default_regions
101
+ [AWS_REGION_US_EAST_1]
56
102
  end
57
103
  end
58
104
  end
@@ -33,7 +33,7 @@ module Hashicorptools
33
33
 
34
34
  desc "list", "list all available amis"
35
35
  def list
36
- amis.each do |ami|
36
+ amis_in_region(region).each do |ami|
37
37
  puts ami.image_id
38
38
  end
39
39
  end
@@ -69,8 +69,10 @@ module Hashicorptools
69
69
  max_count: 1,
70
70
  instance_type: "t2.micro")
71
71
 
72
- ec2.create_tags( resources: run_instances_resp.instances.collect{|i| i.instance_id },
73
- tags: [ {key: 'Name', value: "packer test boot #{tag_name}"}, {key: 'environment', value: 'packer-development'}, {key: 'temporary', value: 'kill me'}])
72
+ ec2.create_tags( resources: run_instances_resp.instances.collect(&:instance_id),
73
+ tags: [ {key: 'Name', value: "packer test boot #{tag_name}"},
74
+ {key: 'environment', value: 'packer-development'},
75
+ {key: 'temporary', value: 'kill me'}])
74
76
 
75
77
  require 'byebug'
76
78
  byebug
@@ -127,39 +129,49 @@ module Hashicorptools
127
129
  'us-east-1'
128
130
  end
129
131
 
130
- def auto_scaling
131
- @auto_scaling ||= Aws::AutoScaling::Client.new(region: region)
132
+ def auto_scaling(client_region=region)
133
+ @auto_scaling ||= Aws::AutoScaling::Client.new(region: client_region)
132
134
  end
133
135
 
134
- def ec2_v2
135
- @ec2 ||= Aws::EC2::Client.new(region: region)
136
+ def ec2_v2(client_region=region)
137
+ @ec2 ||= Aws::EC2::Client.new(region: client_region)
136
138
  end
137
139
 
138
- def amis_in_use
139
- launch_configs = auto_scaling.describe_launch_configurations
140
+ def amis_in_use(client_region)
141
+ launch_configs = auto_scaling(client_region).describe_launch_configurations
140
142
  image_ids = launch_configs.data['launch_configurations'].collect{|lc| lc.image_id}.flatten
141
143
 
142
- ec2_reservations = ec2_v2.describe_instances
144
+ ec2_reservations = ec2_v2(client_region).describe_instances
143
145
  image_ids << ec2_reservations.reservations.collect{|res| res.instances.collect{|r| r.image_id}}.flatten
144
146
  image_ids.flatten
145
147
  end
146
148
 
149
+ def ami_regions
150
+ ['us-east-1', 'eu-central-1']
151
+ end
152
+
147
153
  def clean_amis
148
- ami_ids = amis.collect{|a| a.image_id}
149
- ami_ids_to_remove = ami_ids - amis_in_use
150
- potential_amis_to_remove = amis
154
+ ami_regions.each do |ami_region|
155
+ clean_amis_for_region(ami_region)
156
+ end
157
+ end
158
+
159
+ def clean_amis_for_region(region_to_clean)
160
+ ami_ids = amis_in_region(region_to_clean).collect{|a| a.image_id}
161
+ ami_ids_to_remove = ami_ids - amis_in_use(region_to_clean)
162
+ potential_amis_to_remove = amis_in_region(region_to_clean)
151
163
  potential_amis_to_remove.keep_if {|a| ami_ids_to_remove.include?(a.image_id) }
152
164
 
153
165
  if potential_amis_to_remove.size > NUMBER_OF_AMIS_TO_KEEP
154
166
  amis_to_remove = potential_amis_to_remove[NUMBER_OF_AMIS_TO_KEEP..-1]
155
167
  amis_to_keep = potential_amis_to_remove[0..(NUMBER_OF_AMIS_TO_KEEP-1)]
156
168
 
157
- puts "Deregistering old AMIs..."
169
+ puts "Deregistering old AMIs in #{region_to_clean}..."
158
170
  amis_to_remove.each do |ami|
159
171
  ebs_mappings = ami.block_device_mappings
160
172
  puts "Deregistering #{ami.image_id}"
161
173
  ami.deregister
162
- delete_ami_snapshots(ebs_mappings)
174
+ delete_ami_snapshots(ebs_mappings, snapshot_region: region_to_clean)
163
175
  end
164
176
 
165
177
  puts "Currently active AMIs..."
@@ -167,15 +179,21 @@ module Hashicorptools
167
179
  puts ami.image_id
168
180
  end
169
181
  else
170
- puts "no AMIs to clean."
182
+ puts "no AMIs to clean in #{region_to_clean}."
171
183
  end
172
184
  end
173
185
 
174
- def delete_ami_snapshots(ebs_mappings)
186
+ def amis_in_region(ami_region)
187
+ regional_ec2_client = AWS::EC2.new(region: ami_region)
188
+
189
+ sort_by_created_at( regional_ec2_client.images.with_owner('self').with_tag('Name', tag_name).to_a )
190
+ end
191
+
192
+ def delete_ami_snapshots(ebs_mappings, snapshot_region:)
193
+ regional_ec2_client = AWS::EC2::Client.new(region: snapshot_region)
175
194
  ebs_mappings.each do |volume, attributes|
176
195
  puts "Deleting snapshot #{attributes[:snapshot_id]}"
177
- snapshot = AWS::EC2::Snapshot.new(attributes[:snapshot_id])
178
- snapshot.delete
196
+ regional_ec2_client.delete_snapshot(snapshot_id: attributes[:snapshot_id])
179
197
  end
180
198
  end
181
199
  end
@@ -1,8 +1,9 @@
1
1
  module Hashicorptools
2
2
  class UpdateLaunchConfiguration < Thor
3
3
  desc 'deploy ASG_NAME', 'recycle instances in the ASG with no downtime'
4
+ option :aws_region, default: 'us-east-1'
4
5
  def deploy(asg_name)
5
- asg = AutoScalingGroup.new(name: asg_name)
6
+ asg = AutoScalingGroup.new(name: asg_name, region: options[:aws_region])
6
7
  if asg.group.nil?
7
8
  raise "could not find asg #{asg_name}"
8
9
  end
@@ -1,12 +1,8 @@
1
1
  module Hashicorptools
2
2
  module Variables
3
- def aws_credentials_settings(settings_overrides = {})
4
- {aws_access_key: ENV['AWS_ACCESS_KEY_ID'],
5
- aws_secret_key: ENV['AWS_SECRET_ACCESS_KEY']}.merge(settings_overrides)
6
- end
7
3
 
8
4
  def variables(settings_overrides = {})
9
- aws_credentials_settings(settings_overrides).collect{|key,value| format_variable(key, value)}.join(' ')
5
+ settings_overrides.collect{|key,value| format_variable(key, value)}.join(' ')
10
6
  end
11
7
 
12
8
  protected
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashicorptools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Woodhull
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-20 00:00:00.000000000 Z
11
+ date: 2020-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -25,21 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: dynect_rest
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: aws-sdk-v1
28
+ name: aws-sdk-v1-ruby24
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
@@ -56,114 +42,120 @@ dependencies:
56
42
  name: dotenv
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.2'
59
48
  - - ">="
60
49
  - !ruby/object:Gem::Version
61
- version: '0'
50
+ version: 2.2.1
62
51
  type: :runtime
63
52
  prerelease: false
64
53
  version_requirements: !ruby/object:Gem::Requirement
65
54
  requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '2.2'
66
58
  - - ">="
67
59
  - !ruby/object:Gem::Version
68
- version: '0'
60
+ version: 2.2.1
69
61
  - !ruby/object:Gem::Dependency
70
62
  name: thor
71
63
  requirement: !ruby/object:Gem::Requirement
72
64
  requirements:
73
65
  - - ">="
74
66
  - !ruby/object:Gem::Version
75
- version: '0'
67
+ version: 0.20.0
76
68
  type: :runtime
77
69
  prerelease: false
78
70
  version_requirements: !ruby/object:Gem::Requirement
79
71
  requirements:
80
72
  - - ">="
81
73
  - !ruby/object:Gem::Version
82
- version: '0'
74
+ version: 0.20.0
83
75
  - !ruby/object:Gem::Dependency
84
76
  name: activesupport
85
77
  requirement: !ruby/object:Gem::Requirement
86
78
  requirements:
87
79
  - - ">="
88
80
  - !ruby/object:Gem::Version
89
- version: '0'
81
+ version: 5.1.4
90
82
  type: :runtime
91
83
  prerelease: false
92
84
  version_requirements: !ruby/object:Gem::Requirement
93
85
  requirements:
94
86
  - - ">="
95
87
  - !ruby/object:Gem::Version
96
- version: '0'
88
+ version: 5.1.4
97
89
  - !ruby/object:Gem::Dependency
98
90
  name: byebug
99
91
  requirement: !ruby/object:Gem::Requirement
100
92
  requirements:
101
93
  - - ">="
102
94
  - !ruby/object:Gem::Version
103
- version: '0'
95
+ version: 10.0.2
104
96
  type: :runtime
105
97
  prerelease: false
106
98
  version_requirements: !ruby/object:Gem::Requirement
107
99
  requirements:
108
100
  - - ">="
109
101
  - !ruby/object:Gem::Version
110
- version: '0'
102
+ version: 10.0.2
111
103
  - !ruby/object:Gem::Dependency
112
104
  name: git
113
105
  requirement: !ruby/object:Gem::Requirement
114
106
  requirements:
115
- - - ">="
107
+ - - ">"
116
108
  - !ruby/object:Gem::Version
117
- version: '0'
109
+ version: '1.3'
118
110
  type: :runtime
119
111
  prerelease: false
120
112
  version_requirements: !ruby/object:Gem::Requirement
121
113
  requirements:
122
- - - ">="
114
+ - - ">"
123
115
  - !ruby/object:Gem::Version
124
- version: '0'
116
+ version: '1.3'
125
117
  - !ruby/object:Gem::Dependency
126
118
  name: rspec
127
119
  requirement: !ruby/object:Gem::Requirement
128
120
  requirements:
129
- - - ">="
121
+ - - ">"
130
122
  - !ruby/object:Gem::Version
131
- version: '0'
123
+ version: '3.7'
132
124
  type: :development
133
125
  prerelease: false
134
126
  version_requirements: !ruby/object:Gem::Requirement
135
127
  requirements:
136
- - - ">="
128
+ - - ">"
137
129
  - !ruby/object:Gem::Version
138
- version: '0'
130
+ version: '3.7'
139
131
  - !ruby/object:Gem::Dependency
140
132
  name: rdoc
141
133
  requirement: !ruby/object:Gem::Requirement
142
134
  requirements:
143
- - - "~>"
135
+ - - ">"
144
136
  - !ruby/object:Gem::Version
145
137
  version: '3.12'
146
138
  type: :development
147
139
  prerelease: false
148
140
  version_requirements: !ruby/object:Gem::Requirement
149
141
  requirements:
150
- - - "~>"
142
+ - - ">"
151
143
  - !ruby/object:Gem::Version
152
144
  version: '3.12'
153
145
  - !ruby/object:Gem::Dependency
154
146
  name: bundler
155
147
  requirement: !ruby/object:Gem::Requirement
156
148
  requirements:
157
- - - "~>"
149
+ - - ">"
158
150
  - !ruby/object:Gem::Version
159
- version: '1.0'
151
+ version: '2.0'
160
152
  type: :development
161
153
  prerelease: false
162
154
  version_requirements: !ruby/object:Gem::Requirement
163
155
  requirements:
164
- - - "~>"
156
+ - - ">"
165
157
  - !ruby/object:Gem::Version
166
- version: '1.0'
158
+ version: '2.0'
167
159
  - !ruby/object:Gem::Dependency
168
160
  name: juwelier
169
161
  requirement: !ruby/object:Gem::Requirement
@@ -205,7 +197,6 @@ files:
205
197
  - ".ruby-version"
206
198
  - ".travis.yml"
207
199
  - Gemfile
208
- - Gemfile.lock
209
200
  - LICENSE
210
201
  - README.md
211
202
  - Rakefile
@@ -219,7 +210,6 @@ files:
219
210
  - lib/hashicorptools/ec2_utilities.rb
220
211
  - lib/hashicorptools/host.rb
221
212
  - lib/hashicorptools/packer.rb
222
- - lib/hashicorptools/terraform.rb
223
213
  - lib/hashicorptools/update_launch_configuration.rb
224
214
  - lib/hashicorptools/variables.rb
225
215
  - spec/hashicorptools_spec.rb
@@ -243,8 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
233
  - !ruby/object:Gem::Version
244
234
  version: '0'
245
235
  requirements: []
246
- rubyforge_project:
247
- rubygems_version: 2.7.6
236
+ rubygems_version: 3.0.8
248
237
  signing_key:
249
238
  specification_version: 4
250
239
  summary: Wrappers for terraform and packer
@@ -1,139 +0,0 @@
1
- GEM
2
- remote: http://rubygems.org/
3
- specs:
4
- activesupport (5.1.4)
5
- concurrent-ruby (~> 1.0, >= 1.0.2)
6
- i18n (~> 0.7)
7
- minitest (~> 5.1)
8
- tzinfo (~> 1.1)
9
- addressable (2.5.2)
10
- public_suffix (>= 2.0.2, < 4.0)
11
- aws-sdk (2.11.86)
12
- aws-sdk-resources (= 2.11.86)
13
- aws-sdk-core (2.11.86)
14
- aws-sigv4 (~> 1.0)
15
- jmespath (~> 1.0)
16
- aws-sdk-resources (2.11.86)
17
- aws-sdk-core (= 2.11.86)
18
- aws-sdk-v1 (1.67.0)
19
- json (~> 1.4)
20
- nokogiri (~> 1)
21
- aws-sigv4 (1.0.3)
22
- builder (3.2.3)
23
- byebug (10.0.2)
24
- concurrent-ruby (1.0.5)
25
- descendants_tracker (0.0.4)
26
- thread_safe (~> 0.3, >= 0.3.1)
27
- diff-lcs (1.3)
28
- docile (1.1.5)
29
- domain_name (0.5.20170404)
30
- unf (>= 0.0.5, < 1.0.0)
31
- dotenv (2.2.1)
32
- dynect_rest (0.4.6)
33
- rest-client
34
- faraday (0.12.2)
35
- multipart-post (>= 1.2, < 3)
36
- git (1.3.0)
37
- github_api (0.18.2)
38
- addressable (~> 2.4)
39
- descendants_tracker (~> 0.0.4)
40
- faraday (~> 0.8)
41
- hashie (~> 3.5, >= 3.5.2)
42
- oauth2 (~> 1.0)
43
- hashie (3.5.6)
44
- highline (1.7.10)
45
- http-cookie (1.0.3)
46
- domain_name (~> 0.5)
47
- i18n (0.9.1)
48
- concurrent-ruby (~> 1.0)
49
- jmespath (1.4.0)
50
- json (1.8.6)
51
- juwelier (2.4.7)
52
- builder
53
- bundler
54
- git
55
- github_api
56
- highline
57
- kamelcase (~> 0)
58
- nokogiri
59
- psych
60
- rake
61
- rdoc
62
- semver2
63
- jwt (1.5.6)
64
- kamelcase (0.0.1)
65
- semver2 (~> 3)
66
- mime-types (3.1)
67
- mime-types-data (~> 3.2015)
68
- mime-types-data (3.2016.0521)
69
- mini_portile2 (2.3.0)
70
- minitest (5.10.3)
71
- multi_json (1.12.2)
72
- multi_xml (0.6.0)
73
- multipart-post (2.0.0)
74
- netrc (0.11.0)
75
- nokogiri (1.8.4)
76
- mini_portile2 (~> 2.3.0)
77
- oauth2 (1.4.0)
78
- faraday (>= 0.8, < 0.13)
79
- jwt (~> 1.0)
80
- multi_json (~> 1.3)
81
- multi_xml (~> 0.5)
82
- rack (>= 1.2, < 3)
83
- psych (2.2.4)
84
- public_suffix (3.0.1)
85
- rack (2.0.3)
86
- rake (12.3.0)
87
- rdoc (3.12.2)
88
- json (~> 1.4)
89
- rest-client (2.0.2)
90
- http-cookie (>= 1.0.2, < 2.0)
91
- mime-types (>= 1.16, < 4.0)
92
- netrc (~> 0.8)
93
- rspec (3.7.0)
94
- rspec-core (~> 3.7.0)
95
- rspec-expectations (~> 3.7.0)
96
- rspec-mocks (~> 3.7.0)
97
- rspec-core (3.7.0)
98
- rspec-support (~> 3.7.0)
99
- rspec-expectations (3.7.0)
100
- diff-lcs (>= 1.2.0, < 2.0)
101
- rspec-support (~> 3.7.0)
102
- rspec-mocks (3.7.0)
103
- diff-lcs (>= 1.2.0, < 2.0)
104
- rspec-support (~> 3.7.0)
105
- rspec-support (3.7.0)
106
- semver2 (3.4.2)
107
- simplecov (0.15.1)
108
- docile (~> 1.1.0)
109
- json (>= 1.8, < 3)
110
- simplecov-html (~> 0.10.0)
111
- simplecov-html (0.10.2)
112
- thor (0.20.0)
113
- thread_safe (0.3.6)
114
- tzinfo (1.2.4)
115
- thread_safe (~> 0.1)
116
- unf (0.1.4)
117
- unf_ext
118
- unf_ext (0.0.7.4)
119
-
120
- PLATFORMS
121
- ruby
122
-
123
- DEPENDENCIES
124
- activesupport
125
- aws-sdk (~> 2)
126
- aws-sdk-v1
127
- bundler (~> 1.0)
128
- byebug
129
- dotenv
130
- dynect_rest
131
- git
132
- juwelier
133
- rdoc (~> 3.12)
134
- rspec
135
- simplecov
136
- thor
137
-
138
- BUNDLED WITH
139
- 1.16.2
@@ -1,299 +0,0 @@
1
- module Hashicorptools
2
- class Terraform < Thor
3
- TERRAFORM_VERSION = '0.11.0'
4
-
5
- include Ec2Utilities
6
- include Variables
7
-
8
- desc 'bootstrap', 'terraform a new infrastructure from scratch'
9
- option :environment, :required => true
10
- def bootstrap
11
- apply
12
- end
13
-
14
- desc 'init', 'install providers into local terraform'
15
- option :environment, :required => true
16
- def init
17
-
18
- end
19
-
20
- [:apply, :plan, :destroy, :pull, :refresh].each do |cmd|
21
- desc cmd, "terraform #{cmd}"
22
- option :environment, :required => true
23
- option :debug, :required => false
24
-
25
- define_method cmd do
26
- send("_#{cmd}")
27
- end
28
-
29
- no_commands do
30
- define_method "_#{cmd}" do |settings_overrides = {}|
31
- enforce_version!
32
- raise 'invalid environment' unless ['staging', 'production'].include?(options[:environment])
33
-
34
- execute(state_path, var_file_path) do
35
-
36
- settings_overrides
37
- .merge!({ app_environment: options[:environment] }
38
- .merge(env_variable_keys)
39
- .merge(settings)
40
- .merge(shared_plan_variables))
41
-
42
- send("before_#{cmd}")
43
-
44
- terraform_command = "terraform #{cmd} #{variables(settings_overrides)} -state #{state_path} #{var_file_param} #{config_directory}"
45
-
46
- if (options[:debug])
47
- puts "[DEBUG] running command: '#{terraform_command}"
48
- end
49
-
50
- result = system terraform_command
51
-
52
- if result
53
- send("after_#{cmd}")
54
- end
55
- end
56
- end
57
-
58
- define_method "before_#{cmd}" do
59
- # no-op
60
- end
61
- end
62
-
63
- no_commands do
64
- define_method "before_shared_#{cmd}" do
65
- # no-op
66
- end
67
-
68
- define_method "after_#{cmd}" do
69
- # no-op
70
- end
71
-
72
- define_method "after_shared_#{cmd}" do
73
- # no-op
74
- end
75
- end
76
-
77
- desc cmd, "terraform #{cmd} for shared plan"
78
- option :debug, :required => false
79
- define_method "shared_#{cmd}" do
80
- enforce_version!
81
-
82
- execute(shared_state_path) do
83
- send("before_shared_#{cmd}")
84
-
85
- terraform_command = "terraform #{cmd} #{variables(env_variable_keys.merge(settings))} -state #{shared_state_path} #{shared_config_directory}"
86
- if (options[:debug])
87
- puts "[DEBUG] running command: '#{terraform_command}"
88
- end
89
- result = system terraform_command
90
-
91
- if result
92
- send("after_shared_#{cmd}")
93
- end
94
- end
95
- end
96
- end
97
-
98
- desc 'output', 'terraform output'
99
- option :environment, :required => true
100
- option :name, :required => true
101
- def output
102
- execute(state_path) do
103
- system output_cmd(state_path, options[:name])
104
- end
105
- end
106
-
107
- desc 'shared_output', 'terraform output for shared plan'
108
- option :name, :required => true
109
- def shared_output
110
- execute(shared_state_path) do
111
- system output_cmd(shared_state_path, options[:name])
112
- end
113
- end
114
-
115
- desc 'taint', 'terraform taint'
116
- option :environment, :required => true
117
- option :name, :required => true
118
- option :module, :required => false
119
- def taint
120
- execute(state_path) do
121
- if options[:module].present?
122
- system "terraform taint -module #{options[:module]} -state #{state_path} #{options[:name]}"
123
- else
124
- system "terraform taint -state #{state_path} #{options[:name]}"
125
- end
126
- end
127
- end
128
-
129
- desc 'shared_taint', 'terraform taint for shared plan'
130
- option :name, :required => true
131
- option :module, :required => false
132
- def shared_taint
133
- execute(shared_state_path) do
134
- if options[:module].present?
135
- system "terraform taint -module #{options[:module]} -state #{shared_state_path} #{options[:name]}"
136
- else
137
- system "terraform taint -state #{shared_state_path} #{options[:name]}"
138
- end
139
- end
140
- end
141
-
142
- desc 'show', 'terraform show'
143
- option :environment, :required => true
144
- def show
145
- execute(state_path) do
146
- system "terraform show #{state_path}"
147
- end
148
- end
149
-
150
- desc 'shared_show', 'terraform show for shared plan'
151
- def shared_show
152
- execute(shared_state_path) do
153
- system "terraform show #{shared_state_path}"
154
- end
155
- end
156
-
157
- desc "console", "interactive session"
158
- def console
159
- require 'pry-byebug'
160
- binding.pry
161
- end
162
-
163
- protected
164
-
165
- def var_file_param
166
- File.exist?(var_file_path) ?
167
- "-var-file #{var_file_path}" :
168
- ""
169
- end
170
-
171
- def execute(state_file_path, var_file_path=nil)
172
- begin
173
- yield
174
- rescue StandardError => e
175
- puts e.message
176
- puts e.backtrace
177
- end
178
- end
179
-
180
- def state_path
181
- "#{config_environment_path}/#{options[:environment]}.tfstate"
182
- end
183
-
184
- def shared_state_path
185
- "#{shared_config_directory}/shared.tfstate"
186
- end
187
-
188
- def var_file_path
189
- "#{config_environment_path}/variables.tfvars"
190
- end
191
-
192
- def config_directory
193
- "config/infrastructure/#{infrastructure}"
194
- end
195
-
196
- def shared_config_directory
197
- "config/infrastructure/#{infrastructure}/shared"
198
- end
199
-
200
- def config_environment_path
201
- "#{config_directory}/environments/#{options[:environment]}"
202
- end
203
-
204
- def infrastructure
205
- raise 'implement me'
206
- end
207
-
208
- def output_cmd(state_file_path, name=nil)
209
- "terraform output -state=#{state_file_path} #{name}"
210
- end
211
-
212
- def output_variable(state_file_path, name)
213
- `#{output_cmd(state_file_path, name)}`.chomp
214
- end
215
-
216
- def output_variables(state_file_path)
217
- raw_plan_output = `#{output_cmd(state_file_path)}`
218
- parse_key_value_variables(raw_plan_output)
219
- end
220
-
221
- def var_file_variables
222
- raise "Vars file #{var_file_path} does not exist" unless File.exist?(var_file_path)
223
-
224
- raw_var_file_variables = File.read(var_file_path)
225
- parse_key_value_variables(raw_var_file_variables)
226
- end
227
-
228
- def terraform_version
229
- version_string = `terraform version`.chomp
230
- version = /(\d+.\d+.\d+)/.match(version_string)
231
- version[0]
232
- end
233
-
234
- def enforce_version!
235
- if Gem::Version.new(terraform_version) < Gem::Version.new(TERRAFORM_VERSION)
236
- raise "Terraform #{terraform_version} is out of date, please upgrade"
237
- end
238
- end
239
-
240
- def settings
241
- {} # override me to pass more variables into the terraform plan.
242
- end
243
-
244
- def asg_launch_config_name(asg_name)
245
- asg_client = Aws::AutoScaling::Client.new(region: 'us-east-1')
246
- group = asg_client.describe_auto_scaling_groups(auto_scaling_group_names: [asg_name]).auto_scaling_groups.first
247
- group.try(:launch_configuration_name)
248
- end
249
-
250
- def env_variable_keys
251
- {} # override me to pass environmental variables into the terraform plan
252
- end
253
-
254
- def shared_plan_variables
255
- if File.exist?(shared_state_path)
256
- output_variables(shared_state_path)
257
- else
258
- {}
259
- end
260
- end
261
-
262
- def fetch_terraform_modules
263
- system "terraform get -update=true #{config_directory}"
264
- end
265
-
266
- def current_tfstate
267
- return @current_tfstate if defined?(@current_tfstate)
268
- raw_conf = File.read(state_path)
269
- @current_tfstate = JSON.parse(raw_conf)
270
- end
271
-
272
- def read_config_file(path)
273
- File.new('config/' + path).read
274
- template = ERB.new File.new("config/#{path}").read, nil, "%"
275
- template.result(OpenStruct.new(options).instance_eval { binding })
276
- end
277
-
278
- def dynect
279
- @dynect ||= DynectRest.new("controlshiftlabs", ENV['DYNECT_USERNAME'], ENV['DYNECT_PASSWORD'], "controlshiftlabs.com")
280
- end
281
-
282
- def dns_record_exists?(parent_node_fqdn, record)
283
- dynect.node_list(nil, parent_node_fqdn).include?(record.fqdn)
284
- end
285
-
286
- private
287
-
288
- def parse_key_value_variables(vars_string)
289
- vars = {}
290
- vars_string.split("\n").each do |string_var|
291
- next if string_var.blank?
292
- key, value = string_var.split("=")
293
- vars[key.strip] = value.strip.gsub('"', '')
294
- end
295
-
296
- vars
297
- end
298
- end
299
- end