leeroy_app 0.1.0 → 0.2.0

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
  SHA1:
3
- metadata.gz: a33c630bfff44d8f1fbaff8694c65891aef0f8c5
4
- data.tar.gz: ad0999e31aec974b08fb8f1e10c268b62a653004
3
+ metadata.gz: 0c6837848cfe4074d257010b7e9ee430844ab59b
4
+ data.tar.gz: 743dc38168b8eb748a440372aaa0ee5598c9daf3
5
5
  SHA512:
6
- metadata.gz: faf7735d2cdcd8f9cf9cb0e834210f465802fb614845bdca5c8ccd7bb1f3bd8da3d81cda343c036bfe2cf1488d32196c7b28ee6eb5d2c7dab40fc96aa2eedf0e
7
- data.tar.gz: a5c965a55dc5be2683f0f27e98405e7c200ef6f0566ef000b62e760d8150e3e58b57c2e4b74193fd697abfb35949e3c1dfc853adb932fc423ed4109a0065dddf
6
+ metadata.gz: 167b5061e5a7323724d11850d3468f6f9b09e3fe3d941729ab9122b22d3e257377bb1cacd53af7a4bc1d305b1c7269ed230eb6c842533e6ca03b48575428eaa8
7
+ data.tar.gz: db277e54f900b5e6acd2b50e525debabacf2f146ecf50352dac914c91523f2b69619f34cdca2910ad0c74be688452763aa2b606612fe0428c20accc689b09247
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # leeroy
1
+ # leeroy [![Gem Version](https://badge.fury.io/rb/leeroy_app.svg)](https://badge.fury.io/rb/leeroy_app) [![Code Climate](https://codeclimate.com/github/FitnessKeeper/leeroy/badges/gpa.svg)](https://codeclimate.com/github/FitnessKeeper/leeroy)
2
2
  o rly? ya rly!
3
3
 
4
4
  ## Installation/Configuration
data/lib/leeroy/app.rb CHANGED
@@ -8,6 +8,7 @@ require 'leeroy/task/instantiate'
8
8
  require 'leeroy/task/terminate'
9
9
  require 'leeroy/task/sleep'
10
10
  require 'leeroy/task/stub'
11
+ require 'leeroy/types/phase'
11
12
 
12
13
  include GLI::App
13
14
 
@@ -15,7 +16,7 @@ module Leeroy
15
16
  module App
16
17
 
17
18
  # constants
18
- VALID_PHASE = ['gold_master','application']
19
+ VALID_PHASE = Leeroy::Types::Phase::VALID_PHASE
19
20
 
20
21
  program_desc 'Automate tasks with Jenkins'
21
22
 
data/lib/leeroy/env.rb CHANGED
@@ -14,11 +14,13 @@ module Leeroy
14
14
 
15
15
  # constants
16
16
  S3_PREFIXES = {
17
- :secrets => 'secrets',
18
- :jenkins => 'jenkins',
19
17
  :builds => 'builds',
18
+ :fixtures => 'fixtures',
19
+ :jenkins => 'jenkins',
20
20
  :logs => 'logs',
21
+ :secrets => 'secrets',
21
22
  :semaphores => 'semaphores',
23
+ :sql => 'fixtures/sql',
22
24
  :tests => 'tests',
23
25
  }
24
26
 
@@ -38,7 +40,7 @@ module Leeroy
38
40
  'LEEROY_POLL_TIMEOUT' => '<number of seconds to wait between giving up on long-running AWS operations>',
39
41
  'LEEROY_PROVISIONING_TEMPLATE_PREFIX' => '<path on local filesystem to directory containing provisioning templates>',
40
42
  'LEEROY_S3_BUCKET' => '<name of bucket used as datastore>',
41
- 'LEEROY_PROVISIONING_TEMPLATE_PREFIX' => '<path on local filesystem to directory containing user-data templates>',
43
+ 'LEEROY_USER_DATA_PREFIX' => '<path on local filesystem to directory containing user-data scripts>',
42
44
  }
43
45
 
44
46
  ENV_EXTRAS = {
@@ -13,7 +13,7 @@ module Leeroy
13
13
  module AWS
14
14
  include Leeroy::Helpers
15
15
 
16
- attr :ec2, :s3
16
+ attr :ec2, :rds, :s3
17
17
 
18
18
  def initialize(*args, &block)
19
19
  super(*args, &block)
@@ -21,6 +21,7 @@ module Leeroy
21
21
  logger.debug "initializing AWS helpers"
22
22
 
23
23
  @ec2 = Aws::EC2::Client.new
24
+ @rds = Aws::RDS::Client.new
24
25
  @s3 = Aws::S3::Client.new
25
26
 
26
27
  logger.debug "AWS helpers initialized"
@@ -31,7 +32,6 @@ module Leeroy
31
32
  def ec2Request(method, params = {}, ec2 = self.ec2, options = self.options, global_options = self.global_options)
32
33
  begin
33
34
  logger.debug "constructing EC2 request for '#{method}'"
34
- logger.debug "params: #{params.inspect}"
35
35
 
36
36
  params_mash = Leeroy::Types::Mash.new(params)
37
37
  params = params_mash
@@ -40,8 +40,6 @@ module Leeroy
40
40
 
41
41
  params.dry_run = dry_run
42
42
 
43
- logger.debug "params: #{params.inspect}"
44
-
45
43
  resp = ec2.send(method.to_sym, params)
46
44
 
47
45
  logger.debug "resp: #{resp.inspect}"
@@ -207,7 +205,7 @@ module Leeroy
207
205
 
208
206
  resp = ec2Request(:describe_images, run_params)
209
207
 
210
- # now filter based on callback
208
+ # now filter based on callbacks
211
209
  resp.images.select {|x| selector.call(x)}.collect {|x| collector.call(x)}
212
210
 
213
211
  rescue Aws::EC2::Errors::DryRunOperation => e
@@ -219,30 +217,58 @@ module Leeroy
219
217
  end
220
218
  end
221
219
 
220
+ def getImageByName(image_name)
221
+ begin
222
+
223
+ raise "image_name parameter cannot be nil" if image_name.nil?
224
+
225
+ selector = lambda {|image| image.name == image_name}
226
+ collector = lambda {|image| image.image_id}
227
+
228
+ image_ids = filterImages(selector, collector)
229
+ logger.debug image_ids.inspect
230
+ logger.debug "image_name: #{image_name}"
231
+
232
+ image_ids[0]
233
+
234
+ rescue StandardError => e
235
+ raise e
236
+ end
237
+ end
238
+
239
+
222
240
  def getGoldMasterInstanceName(env_name = 'LEEROY_GOLD_MASTER_NAME')
223
241
  checkEnv(env_name)
224
242
  end
225
243
 
226
- def getApplicationInstanceName(index, env_app = 'LEEROY_APP_NAME', env_name = 'LEEROY_BUILD_TARGET')
227
- name_prefix = [checkEnv(env_app), checkEnv(env_name), index].join('-')
244
+ def getApplicationInstanceName(index = nil, env_app = 'LEEROY_APP_NAME', env_name = 'LEEROY_BUILD_TARGET')
245
+ name_prefix = [checkEnv(env_app), checkEnv(env_name)].join('-')
228
246
  logger.debug "name_prefix: #{name_prefix}"
229
247
 
230
248
  if index.nil?
231
- # determine the index by looking at existing images
232
- selector = lambda {|image| image.name =~ /^#{name_prefix}/}
233
- # and extract the names
234
- collector = lambda {|image| image.name}
235
-
236
- image_names = filterImages(selector, collector)
237
- logger.debug image_names.awesome_inspect
249
+ index = getApplicationImageIndex
238
250
  end
239
251
 
252
+ instance_name = [name_prefix, index].join('-')
253
+ logger.debug "instance_name: #{instance_name}"
254
+
255
+ instance_name
256
+
240
257
  end
241
258
 
242
259
  def getGoldMasterImageIndex(env_prefix = 'LEEROY_GOLD_MASTER_IMAGE_PREFIX')
243
260
  name_prefix = checkEnv(env_prefix)
244
- logger.debug "name_prefix: #{name_prefix}"
261
+ getMaxImageIndex(name_prefix)
262
+ end
245
263
 
264
+ def getApplicationImageIndex(env_build_target = 'LEEROY_BUILD_TARGET', env_app_name = 'LEEROY_APP_NAME')
265
+ app_name = checkEnv(env_app_name)
266
+ build_target = checkEnv(env_build_target)
267
+ name_prefix = [app_name, build_target].join('-')
268
+ getMaxImageIndex(name_prefix)
269
+ end
270
+
271
+ def getMaxImageIndex(name_prefix)
246
272
  # determine the index by looking at existing images
247
273
  selector = lambda {|image| image.name =~ /^#{name_prefix}/}
248
274
  # and extract the names
@@ -255,13 +281,54 @@ module Leeroy
255
281
  end
256
282
  end
257
283
 
258
- latest_image = image_numbers.sort.compact.uniq.pop
284
+ latest_image = image_numbers.sort.compact.uniq.pop || 1
259
285
  logger.debug "latest_image: #{latest_image}"
260
286
 
261
287
  latest_image
262
288
 
263
289
  end
264
290
 
291
+ # RDS
292
+
293
+ def rdsRequest(method, params = {}, rds = self.rds, options = self.options, global_options = self.global_options)
294
+ begin
295
+ logger.debug "constructing RDS request for '#{method}'"
296
+
297
+ params_mash = Leeroy::Types::Mash.new(params)
298
+ params = params_mash
299
+
300
+ logger.debug "params: #{params.inspect}"
301
+
302
+ resp = rds.send(method.to_sym, params)
303
+
304
+ logger.debug "resp: #{resp.inspect}"
305
+
306
+ resp
307
+
308
+ rescue StandardError => e
309
+ raise e
310
+ end
311
+ end
312
+
313
+ def getRDSInstanceEndpoint(instancename, rds = self.rds)
314
+ begin
315
+ logger.debug "getting DB Instance Endpoint for '#{instancename}'"
316
+
317
+ resp = rdsRequest(:describe_db_instances, {:db_instance_identifier => instancename})
318
+ db_instances = resp.db_instances
319
+ logger.debug "db_instances: #{db_instances.inspect}"
320
+
321
+ db_instances[0].endpoint.address
322
+
323
+ rescue Aws::EC2::Errors::DryRunOperation => e
324
+ logger.info e.message
325
+ "DRYRUN_DUMMY_VALUE: #{self.class.to_s}"
326
+
327
+ rescue StandardError => e
328
+ raise e
329
+ end
330
+ end
331
+
265
332
  # S3
266
333
 
267
334
  def s3Request(method, params = {}, s3 = self.s3, options = self.options, global_options = self.global_options)
@@ -0,0 +1,81 @@
1
+ # Helper methods for managing inventory (images, instances, etc.)
2
+ #
3
+ require 'leeroy/helpers'
4
+ require 'leeroy/helpers/aws'
5
+ require 'leeroy/helpers/logging'
6
+
7
+ module Leeroy
8
+ module Helpers
9
+ module Inventory
10
+ include Leeroy::Helpers::AWS
11
+ include Leeroy::Helpers::Logging
12
+
13
+ # determine the name of an AMI to use in creating an instance
14
+ def genImageName(phase = nil, state = self.state, options = self.options)
15
+ begin
16
+ # extract phase from state if not provided
17
+ phase = state.phase if phase.nil?
18
+
19
+ raise "no phase provided in state data or as param, exiting." if phase.nil?
20
+
21
+ # were we given an app_name?
22
+ app_name = state.app_name? ? state.app_name : checkEnv('LEEROY_APP_NAME')
23
+ logger.debug "app_name: #{app_name}"
24
+
25
+ # build target depends on phase
26
+ build_target = case phase
27
+ when 'gold_master'
28
+ 'master'
29
+ when 'application'
30
+ checkEnv('LEEROY_BUILD_TARGET')
31
+ else
32
+ raise "unable to build target for phase"
33
+ end
34
+
35
+ # were we given an image index?
36
+ index = genImageIndex(state, self.env, self.ec2, options).to_s
37
+ logger.debug "index: #{index}"
38
+
39
+ image_name = [app_name, build_target, index].join('-')
40
+
41
+ logger.debug "image_name: #{image_name}"
42
+
43
+ image_name
44
+
45
+ rescue StandardError => e
46
+ raise e
47
+ end
48
+ end
49
+
50
+ def genImageIndex(state = self.state, env = self.env, ec2 = self.ec2, options = self.options)
51
+ begin
52
+ index = options[:index]
53
+
54
+ if index
55
+ logger.debug "index provided: #{index}"
56
+ else
57
+ logger.debug "index not provided, calculating"
58
+ phase = state.phase
59
+
60
+ index = case phase
61
+ when 'gold_master'
62
+ getGoldMasterImageIndex.to_i + 1
63
+ when 'application'
64
+ getGoldMasterImageIndex.to_i
65
+ else
66
+ raise "unable to determine image index for phase '#{phase.to_s}'"
67
+ end
68
+ end
69
+
70
+ logger.debug "index: #{index}"
71
+
72
+ index
73
+
74
+ rescue StandardError => e
75
+ raise e
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,23 @@
1
+ require 'leeroy/helpers'
2
+
3
+ module Leeroy
4
+ module Helpers
5
+ module Template
6
+ include Leeroy::Helpers
7
+
8
+ def renderTemplate(template, b = binding)
9
+ begin
10
+ logger.debug "processing template '#{template}'"
11
+
12
+ # run the ERB renderer in a separate thread, restricted
13
+ # http://www.stuartellis.eu/articles/erb/
14
+ ERB.new(File.read(template), 0).result(binding)
15
+
16
+ rescue StandardError => e
17
+ raise e
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -21,26 +21,14 @@ module Leeroy
21
21
  def initialize(params = {})
22
22
  begin
23
23
  @global_options = params.fetch(:global_options, {})
24
- logger.debug("global_options: #{self.global_options.to_s}")
25
-
26
- logger.debug("setting options")
27
24
  @options = params.fetch(:options, {})
28
- logger.debug("options: #{self.options.to_s}")
29
-
30
- logger.debug("setting args")
31
25
  @args = params.fetch(:args, {})
32
- logger.debug("args: #{self.args.to_s}")
33
26
 
34
- logger.debug("setting env")
35
27
  @env = Leeroy::Env.new({}, params.fetch(:env, ENV))
36
- logger.debug("env: #{self.env.to_s}")
37
28
 
38
- logger.debug("setting state")
39
29
  @state = Leeroy::State.new(state_from_pipe(params.fetch(:state, {})))
40
30
  rotate_task_metadata
41
- logger.debug("state: #{self.state}")
42
31
 
43
- logger.debug("base initialization of #{self.class.to_s} complete")
44
32
  rescue StandardError => e
45
33
  raise e
46
34
  end
@@ -51,6 +39,7 @@ module Leeroy
51
39
  self.logger.info("performing #{self.class.to_s}")
52
40
  self.logger.debug("args: #{args.inspect}")
53
41
  self.logger.debug("options: #{options.inspect}")
42
+ self.logger.debug("global_options: #{global_options.inspect}")
54
43
 
55
44
  rescue StandardError => e
56
45
  raise e
@@ -1,6 +1,7 @@
1
1
  require 'leeroy'
2
2
  require 'leeroy/task'
3
3
  require 'leeroy/helpers/aws'
4
+ require 'leeroy/helpers/inventory'
4
5
  require 'leeroy/helpers/polling'
5
6
  require 'leeroy/types/image'
6
7
  require 'leeroy/types/phase'
@@ -9,6 +10,7 @@ module Leeroy
9
10
  module Task
10
11
  class Image < Leeroy::Task::Base
11
12
  include Leeroy::Helpers::AWS
13
+ include Leeroy::Helpers::Inventory
12
14
  include Leeroy::Helpers::Polling
13
15
 
14
16
  def perform(args = self.args, options = self.options, global_options = self.global_options)
@@ -90,18 +92,8 @@ module Leeroy
90
92
  logger.debug "instance_id: #{instance_id}"
91
93
  image_params.instance_id = instance_id
92
94
 
93
- # were we given an app_name?
94
- app_name = state.app_name? ? state.app_name : checkEnv('LEEROY_APP_NAME')
95
- logger.debug "app_name: #{app_name}"
96
-
97
- # were we given an image index?
98
- index = _genImageIndex(state, env, ec2, options).to_s
99
- logger.debug "index: #{index}"
100
-
101
- # build target depends on phase
102
- build_target = phase == 'gold_master' ? 'master' : checkEnv('LEEROY_BUILD_TARGET')
103
-
104
- image_params.name = [app_name, build_target, index].join('-')
95
+ # generate image name based on state data
96
+ image_params.name = genImageName(phase, state)
105
97
 
106
98
  image_params
107
99
 
@@ -110,17 +102,6 @@ module Leeroy
110
102
  end
111
103
  end
112
104
 
113
- def _genImageIndex(state = self.state, env = self.env, ec2 = self.ec2, options = self.options)
114
- begin
115
- logger.debug "determining gold master instance ID"
116
-
117
- options[:index] or getGoldMasterImageIndex.to_i + 1
118
-
119
- rescue StandardError => e
120
- raise e
121
- end
122
- end
123
-
124
105
  end
125
106
  end
126
107
  end
@@ -1,13 +1,17 @@
1
1
  require 'leeroy'
2
2
  require 'leeroy/task'
3
3
  require 'leeroy/helpers/aws'
4
+ require 'leeroy/helpers/inventory'
4
5
  require 'leeroy/helpers/polling'
6
+ require 'leeroy/helpers/template'
5
7
 
6
8
  module Leeroy
7
9
  module Task
8
10
  class Instantiate < Leeroy::Task::Base
9
11
  include Leeroy::Helpers::AWS
12
+ include Leeroy::Helpers::Inventory
10
13
  include Leeroy::Helpers::Polling
14
+ include Leeroy::Helpers::Template
11
15
 
12
16
  def perform(args = self.args, options = self.options, global_options = self.global_options)
13
17
  begin
@@ -88,22 +92,7 @@ module Leeroy
88
92
  def _readSemaphore(phase)
89
93
  begin
90
94
  template = File.join(checkEnv('LEEROY_PROVISIONING_TEMPLATE_PREFIX'), "#{phase}.erb")
91
- logger.debug "processing template '#{template}'"
92
-
93
- # this is heinous
94
- # http://stackoverflow.com/a/22777806/17597
95
- rendered = String.new
96
-
97
- begin
98
- old_stdout = $stdout
99
- $stdout = StringIO.new('','w')
100
- ERB.new(File.read(template)).run
101
- rendered = $stdout.string
102
- ensure
103
- $stdout = old_stdout
104
- end
105
-
106
- rendered
95
+ renderTemplate(template, binding)
107
96
 
108
97
  rescue StandardError => e
109
98
  raise e
@@ -166,15 +155,18 @@ module Leeroy
166
155
  phase = options[:phase]
167
156
  logger.debug "phase is #{phase}"
168
157
 
158
+ instance_params.phase = phase
159
+
169
160
  # AMI id depends on phase
170
- if phase == 'gold_master'
171
- image_id = checkEnv('LEEROY_AWS_LINUX_AMI')
172
- elsif phase == 'application'
173
- image_id = state.imageid
161
+ image_id = case phase
162
+ when 'gold_master'
163
+ checkEnv('LEEROY_AWS_LINUX_AMI')
164
+ when 'application'
165
+ state.imageid || getImageByName(genImageName('gold_master'))
166
+ else
167
+ nil
174
168
  end
175
169
 
176
- instance_params.phase = phase
177
-
178
170
  raise "unable to determine image ID for phase '#{phase}'" if image_id.nil?
179
171
 
180
172
  instance_params.image_id = image_id
@@ -1,6 +1,10 @@
1
+ require 'leeroy/helpers/logging'
2
+
1
3
  module Leeroy
2
4
  module Types
3
5
  class Phase < String
6
+ include Leeroy::Helpers::Logging
7
+
4
8
  VALID_PHASE = ['gold_master', 'application']
5
9
 
6
10
  def initialize(*args, &block)
@@ -10,6 +14,9 @@ module Leeroy
10
14
  phase = self.to_s
11
15
  raise "invalid value for phase: '#{phase}'" unless VALID_PHASE.include?(phase)
12
16
 
17
+ rescue TypeError => e
18
+ raise "invalid value for phase: #{e.message}"
19
+
13
20
  rescue StandardError => e
14
21
  raise e
15
22
  end
@@ -6,7 +6,7 @@ module Leeroy
6
6
  module Types
7
7
  class UserData < Leeroy::Types::PackedString
8
8
  def encoded_for_ec2(input = self.to_s)
9
- Base64.urlsafe_encode64(input)
9
+ Base64.encode64(input)
10
10
  end
11
11
  end
12
12
  end
@@ -1,3 +1,3 @@
1
1
  module Leeroy
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leeroy_app
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Huff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-02 00:00:00.000000000 Z
11
+ date: 2016-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aruba
@@ -276,9 +276,11 @@ files:
276
276
  - lib/leeroy/helpers/aws.rb
277
277
  - lib/leeroy/helpers/dumpable.rb
278
278
  - lib/leeroy/helpers/env.rb
279
+ - lib/leeroy/helpers/inventory.rb
279
280
  - lib/leeroy/helpers/logging.rb
280
281
  - lib/leeroy/helpers/polling.rb
281
282
  - lib/leeroy/helpers/state.rb
283
+ - lib/leeroy/helpers/template.rb
282
284
  - lib/leeroy/state.rb
283
285
  - lib/leeroy/task.rb
284
286
  - lib/leeroy/task/base.rb