asger 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 +7 -0
- data/.gitignore +14 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +2 -0
- data/asger.gemspec +28 -0
- data/bin/asger +7 -0
- data/lib/asger.rb +5 -0
- data/lib/asger/cli.rb +97 -0
- data/lib/asger/runner.rb +75 -0
- data/lib/asger/task.rb +78 -0
- data/lib/asger/util.rb +31 -0
- data/lib/asger/version.rb +4 -0
- data/stock_scripts/chef_deregister.rb +61 -0
- data/stock_scripts/echo.rb +9 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1d7e123884650c6770de89781c7fb27cd17106c1
|
4
|
+
data.tar.gz: 85913ef76261482b872a1d87ec892c6869bbc212
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ddee73b770fb2fc1b69b59f5e89d230ec95d135264dd697920f453756dfd0e883a69d02f25eb477905538a424a9d99ca12edcf67a1b9ca2d2a07bfa286b4e99b
|
7
|
+
data.tar.gz: f0ac3696d8f16ece760f270a9cf0d5a9ba887f58bfc20218fff238562ed58ed648c81c09b9d2a454e4c379a23cafd6b67c2c835885e4e150f37f8a66f7986384
|
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--private --list-undoc --markup markdown - LICENSE.md
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Ed Ropple
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# `asger` #
|
2
|
+
|
3
|
+
`asger` is a tool designed to field notifications from Amazon EC2 auto-scaling groups via a SNS topic subscribed to an SQS queue. (Which probably sounds alarmingly specific, but it's the most common way to do this!) Once a notification is fielded, the user can define Tasks that then perform actions on instance creation ("up" functions) and termination ("down" functions).
|
4
|
+
|
5
|
+
### Important Notes ###
|
6
|
+
- When multiple tasks are running in a single `asger` instance, they will be run in order on instance creation and _in reverse order_ on instance termination.
|
7
|
+
|
8
|
+
## Contributors ##
|
9
|
+
`asger` was built primarily at [Leaf](http://leaf.me) by [Ed Ropple](mailto:ed+asger@edropple.com) ([twitter](https://twitter.com/edropple)).
|
10
|
+
|
11
|
+
## Standalone ##
|
12
|
+
|
13
|
+
`asger` is designed primarily to be run as a daemon, accepting "tasks" in the form of Ruby files. Tasks are [fairly simple](https://github.com/eropple/asger/blob/master/samples/echo.rb); more documentation will be forthcoming.
|
14
|
+
|
15
|
+
Sample usage:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
./bin/asger --queue-url 'https://sqs.us-east-1.amazonaws.com/ACCOUNT_ID/QUEUE_NAME' --shared-credentials=CREDS --parameter-file /tmp/some_params.yaml --task-file %/echo.rb --task-file %/chef_deregister.rb
|
19
|
+
```
|
20
|
+
|
21
|
+
(Note: `%` is a special path character when passed to `--task-file`; it refers to the `stock_scripts` directory within the gem, so you can get started right away with the stock scripts.)
|
22
|
+
|
23
|
+
## Embedded ##
|
24
|
+
|
25
|
+
Add this line to your application's Gemfile:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'asger'
|
29
|
+
```
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
```bash
|
34
|
+
bundle
|
35
|
+
```
|
36
|
+
|
37
|
+
Or install it yourself as:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
gem install asger
|
41
|
+
```
|
42
|
+
|
43
|
+
Yardocs are available with `yard`, though they aren't complete. Nothing in `asger` is particularly complicated, though, so I recommend just taking a look at the source.
|
44
|
+
|
45
|
+
## Contributing ##
|
46
|
+
|
47
|
+
1. Fork it ( https://github.com/[my-github-username]/asger/fork )
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/asger.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'asger/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "asger"
|
8
|
+
spec.version = Asger::VERSION
|
9
|
+
spec.authors = ["Ed Ropple"]
|
10
|
+
spec.email = ["ed@edropple.com"]
|
11
|
+
spec.summary = %q{A persistent daemon that watches an AWS autoscaling group for changes and dispatches your code.}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency "pry"
|
23
|
+
|
24
|
+
spec.add_runtime_dependency 'aws-sdk', '~> 2.0.27'
|
25
|
+
spec.add_runtime_dependency 'trollop', '~> 2.1.1'
|
26
|
+
spec.add_runtime_dependency "hashie", "~> 3.3"
|
27
|
+
spec.add_runtime_dependency 'activesupport', '~> 4.2.0'
|
28
|
+
end
|
data/bin/asger
ADDED
data/lib/asger.rb
ADDED
data/lib/asger/cli.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require 'trollop'
|
5
|
+
|
6
|
+
require 'aws-sdk'
|
7
|
+
require 'active_support'
|
8
|
+
|
9
|
+
require 'asger/runner'
|
10
|
+
|
11
|
+
module Asger
|
12
|
+
# Command line functionality for Asger.
|
13
|
+
module CLI
|
14
|
+
# Entry point called from `bin/asger`.
|
15
|
+
def self.main()
|
16
|
+
opts = Trollop::options do
|
17
|
+
opt :task_file, "path to a task (Ruby file; pass in order of execution; % refers to the stock_scripts directory)",
|
18
|
+
:type => :string, :multi => true
|
19
|
+
opt :parameter_file, "path to a params file (YAML or JSON; later files override earlier ones)",
|
20
|
+
:type => :string, :multi => true
|
21
|
+
opt :queue_url, "URL of the SQS queue to read from",
|
22
|
+
:type => :string
|
23
|
+
opt :pause_time, "Time (in seconds) to pause between polls.",
|
24
|
+
:default => 0
|
25
|
+
opt :verbose, "enables verbose logging",
|
26
|
+
:default => false
|
27
|
+
opt :die_on_error, "Terminates if an exception is thrown within the task runner.",
|
28
|
+
:default => true
|
29
|
+
|
30
|
+
opt :aws_logging, "Provides the Asger logger to AWS (use for deep debugging).", :default => false
|
31
|
+
|
32
|
+
opt :shared_credentials, "Tells Asger to use shared credentials from '~/.aws/credentials'.", :type => :string
|
33
|
+
end
|
34
|
+
|
35
|
+
logger = Logger.new($stderr)
|
36
|
+
logger.info "Initializing Asger."
|
37
|
+
|
38
|
+
logger.level = opts[:verbose] ? Logger::DEBUG : Logger::INFO
|
39
|
+
|
40
|
+
if !opts[:queue_url]
|
41
|
+
logger.error "--queue-url is required."
|
42
|
+
exit(1)
|
43
|
+
end
|
44
|
+
logger.warn "No tasks configured; Asger will run, but won't do much." unless (opts[:task_file] && !opts[:task_file].empty?)
|
45
|
+
|
46
|
+
param_files =
|
47
|
+
opts[:parameter_file].map do |pf|
|
48
|
+
logger.debug "Parsing parameter file '#{pf}'."
|
49
|
+
case File.extname(pf)
|
50
|
+
when ".json"
|
51
|
+
JSON.parse(File.read(pf))
|
52
|
+
when ".yaml"
|
53
|
+
YAML.load(File.read(pf))
|
54
|
+
else
|
55
|
+
raise "Unrecognized parameter file: '#{pf}'."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
parameters = {}
|
60
|
+
param_files.each { |p| parameters.deep_merge!(p) }
|
61
|
+
|
62
|
+
credentials = nil
|
63
|
+
if opts[:shared_credentials]
|
64
|
+
logger.info "Using shared credentials '#{opts[:shared_credentials]}'."
|
65
|
+
credentials = Aws::SharedCredentials.new(profile_name: opts[:shared_credentials])
|
66
|
+
end
|
67
|
+
|
68
|
+
aws_logger = opts[:aws_logging] ? logger : nil
|
69
|
+
sqs_client = Aws::SQS::Client.new(logger: aws_logger, credentials: credentials)
|
70
|
+
ec2_client = Aws::EC2::Client.new(logger: aws_logger, credentials: credentials)
|
71
|
+
|
72
|
+
|
73
|
+
stock_scripts_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "stock_scripts"))
|
74
|
+
task_files = opts[:task_file].map { |f| f.gsub("%", stock_scripts_dir)}
|
75
|
+
|
76
|
+
logger.info "Using task files:"
|
77
|
+
task_files.each { |tf| logger.info " - #{tf}" }
|
78
|
+
runner = Runner.new(logger, sqs_client, ec2_client, opts[:queue_url], parameters, task_files)
|
79
|
+
|
80
|
+
logger.info "Beginning run loop. Sleeping between steps for #{opts[:pause_time]} seconds."
|
81
|
+
loop do
|
82
|
+
begin
|
83
|
+
runner.step()
|
84
|
+
rescue StandardError => err
|
85
|
+
logger.error "Encountered an error."
|
86
|
+
logger.error "#{err.class.name}: #{err.message}"
|
87
|
+
err.backtrace.each { |bt| logger.error bt }
|
88
|
+
|
89
|
+
if opts[:die_on_error]
|
90
|
+
raise err
|
91
|
+
end
|
92
|
+
end
|
93
|
+
sleep opts[:pause_time] unless opts[:pause_time] == 0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/asger/runner.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'aws-sdk'
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
require 'asger/task'
|
6
|
+
|
7
|
+
module Asger
|
8
|
+
class Runner
|
9
|
+
# @param logger [Logger] the logger for Asger to use
|
10
|
+
# @param sqs_client [Aws::SQS::Client] the SQS client to use for polling
|
11
|
+
# @param ec2_client [Aws::EC2::Client] the EC2 client to use to get instance information
|
12
|
+
# @param queue_url [String] the queue URL to poll
|
13
|
+
# @param parameters [Hash] a hash of parameters to pass to {Task}s
|
14
|
+
# @param task_files [Array<String>] list of file paths to load as {Task}s
|
15
|
+
def initialize(logger, sqs_client, ec2_client, queue_url, parameters, task_files)
|
16
|
+
@logger = logger
|
17
|
+
@sqs_client = sqs_client
|
18
|
+
@ec2_client = ec2_client
|
19
|
+
@ec2_resource_client = Aws::EC2::Resource.new(client: @ec2_client)
|
20
|
+
@queue_url = queue_url
|
21
|
+
@parameters = Hashie::Mash.new(parameters)
|
22
|
+
@tasks = task_files.map { |tf| Task.from_file(@logger, tf) }
|
23
|
+
|
24
|
+
@logger.info "#{@tasks.length} task(s) set up."
|
25
|
+
|
26
|
+
@tasks.each { |t| t.invoke_sanity_check(@parameters) }
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def step()
|
31
|
+
messages = @sqs_client.receive_message(queue_url: @queue_url)[:messages]
|
32
|
+
messages.each do |msg|
|
33
|
+
notification = JSON.parse(JSON.parse(msg[:body])["Message"])
|
34
|
+
if notification["Event"] != nil
|
35
|
+
case notification["Event"].gsub("autoscaling:", "")
|
36
|
+
when "EC2_INSTANCE_LAUNCH"
|
37
|
+
instance_id = notification["EC2InstanceId"]
|
38
|
+
@logger.info "Instance launched: #{instance_id}"
|
39
|
+
|
40
|
+
instance = @ec2_resource_client.instance(instance_id)
|
41
|
+
@tasks.each do |task|
|
42
|
+
task.invoke_up(instance, @parameters)
|
43
|
+
end
|
44
|
+
|
45
|
+
delete_message(msg)
|
46
|
+
when "EC2_INSTANCE_LAUNCH_ERROR"
|
47
|
+
@logger.warn "Instance launch error received."
|
48
|
+
delete_message(msg)
|
49
|
+
when "EC2_INSTANCE_TERMINATE"
|
50
|
+
instance_id = notification["EC2InstanceId"]
|
51
|
+
@logger.info "Instance terminated: #{instance_id}"
|
52
|
+
|
53
|
+
@tasks.reverse_each do |task|
|
54
|
+
task.invoke_down(instance_id, @parameters)
|
55
|
+
end
|
56
|
+
delete_message(msg)
|
57
|
+
when "EC2_INSTANCE_TERMINATE_ERROR"
|
58
|
+
@logger.warn "Instance terminate error received."
|
59
|
+
delete_message(msg)
|
60
|
+
when "TEST_NOTIFICATION"
|
61
|
+
@logger.debug "Found test notification in queue."
|
62
|
+
delete_message(msg)
|
63
|
+
else
|
64
|
+
@logger.debug "Unrecognized notification '#{notification["Event"]}', ignoring."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def delete_message(msg)
|
72
|
+
@sqs_client.delete_message(queue_url: @queue_url, receipt_handle: msg[:receipt_handle])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/asger/task.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'asger/util'
|
2
|
+
|
3
|
+
module Asger
|
4
|
+
# A `Task` is a wrapper around an `up` and a `down` function. Up functions
|
5
|
+
# are called when an auto-scaling group adds an instance, and Asger retrieves
|
6
|
+
# the instance data for the task. Down functions are called when an
|
7
|
+
# auto-scaling group downs an instance, and Asger passes along only the
|
8
|
+
# instance ID (because it's all we've got).
|
9
|
+
class Task
|
10
|
+
attr_reader :logger
|
11
|
+
|
12
|
+
def initialize(logger, code, filename = "unknown_file.rb")
|
13
|
+
@logger = logger
|
14
|
+
@name = File.basename(filename)
|
15
|
+
instance_eval(code, filename, 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
def invoke_sanity_check(parameters)
|
19
|
+
if @sanity_check_proc
|
20
|
+
logger.debug "Sanity checking for '#{@name}'..."
|
21
|
+
@sanity_check_proc.call(parameters)
|
22
|
+
else
|
23
|
+
logger.debug "No sanity check for '#{@name}'."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def invoke_up(instance, parameters)
|
28
|
+
if @up_proc
|
29
|
+
logger.debug "Invoking up for '#{@name}'..."
|
30
|
+
@up_proc.call(instance, parameters)
|
31
|
+
logger.debug "Up invoked for '#{@name}'..."
|
32
|
+
else
|
33
|
+
logger.debug "No up for '#{@name}'."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def invoke_down(instance_id, parameters)
|
38
|
+
if @down_proc
|
39
|
+
logger.debug "Invoking down for '#{@name}'..."
|
40
|
+
@down_proc.call(instance_id, parameters)
|
41
|
+
logger.debug "Down invoked for '#{@name}'..."
|
42
|
+
else
|
43
|
+
logger.debug "No down for '#{@name}'."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.from_file(logger, file)
|
48
|
+
Task.new(logger, File.read(file), file)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
# Defines a sanity check function, which should raise and fail (which will halt
|
53
|
+
# Asger before it does anything with the actual queue) if there's a problem with
|
54
|
+
# the parameter set.
|
55
|
+
#
|
56
|
+
# @yield [parameters]
|
57
|
+
# @yieldparam parameters [Hash] the parameters passed in to Asger
|
58
|
+
def sanity_check(&block)
|
59
|
+
@sanity_check_proc = block
|
60
|
+
end
|
61
|
+
|
62
|
+
# Defines an 'up' function.
|
63
|
+
# @yield [instance, parameters]
|
64
|
+
# @yieldparam instance [Aws::EC2::Instance] the instance that has been created
|
65
|
+
# @yieldparam parameters [Hash] the parameters passed in to Asger
|
66
|
+
def up(&block)
|
67
|
+
@up_proc = block
|
68
|
+
end
|
69
|
+
|
70
|
+
# Defines a 'down' function.
|
71
|
+
# @yield [instance_id, parameters]
|
72
|
+
# @yieldparam instance_id [String] the ID of the recently terminated instance
|
73
|
+
# @yieldparam parameters [Hash] the parameters passed in to Asger
|
74
|
+
def down(&block)
|
75
|
+
@down_proc = block
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/asger/util.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Asger
|
4
|
+
module Util
|
5
|
+
|
6
|
+
def self.run_command(subcommand_name, command, logger = nil, directory = nil)
|
7
|
+
directory = directory || Dir.getwd()
|
8
|
+
logger.info "[#{subcommand_name}] => #{command}" unless !logger
|
9
|
+
|
10
|
+
lines = []
|
11
|
+
|
12
|
+
Dir.chdir(directory) do
|
13
|
+
# TODO: this should probably raise on nonzero.
|
14
|
+
thread = Open3::popen3(command) do |stdin, stdout, stderr, wait_thr|
|
15
|
+
stdout.read.split("\n").each do |line|
|
16
|
+
lines << line
|
17
|
+
logger.debug "[#{subcommand_name}] O: #{line}" unless !logger
|
18
|
+
end
|
19
|
+
stderr.read.split("\n").each do |line|
|
20
|
+
logger.debug "[#{subcommand_name}] E: #{line}" unless !logger
|
21
|
+
end
|
22
|
+
|
23
|
+
wait_thr
|
24
|
+
end
|
25
|
+
|
26
|
+
[ thread.value.exitstatus, lines.join("\n") ]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# This script will deregister a node from the Chef server given in the parameters files.
|
2
|
+
# It will perform a Chef search for an 'instance_id' tag that matches the instance ID
|
3
|
+
# provided by the AWS notification. To tag a node with the instance_id from bash, do
|
4
|
+
# something like this on-node (probably in cloud-init):
|
5
|
+
#
|
6
|
+
# ```bash
|
7
|
+
# knife tag create -c /path/to/client.rb $NODE_NAME $INSTANCE_ID
|
8
|
+
# ```
|
9
|
+
#
|
10
|
+
# Which, in our naming scheme at Leaf, becomes:
|
11
|
+
#
|
12
|
+
# ```bash
|
13
|
+
# knife tag create -c /etc/chef/client.rb vpn.test-cloud.infra.06f1d39c i-06f1d39c
|
14
|
+
# ```
|
15
|
+
#
|
16
|
+
# PARAMETERS:
|
17
|
+
#
|
18
|
+
# chef_deregister.knife_config: the path to the knife config to use for search/node delete
|
19
|
+
|
20
|
+
require 'json'
|
21
|
+
|
22
|
+
sanity_check do |parameters|
|
23
|
+
knife_config = parameters[:chef_deregister][:knife_config]
|
24
|
+
raise "parameters[:chef_deregister][:knife_config] is not set" unless knife_config
|
25
|
+
|
26
|
+
raise "file '#{knife_config}' does not exist" unless File.exist?(knife_config)
|
27
|
+
end
|
28
|
+
|
29
|
+
down do |instance_id, parameters|
|
30
|
+
knife_config = parameters[:chef_deregister][:knife_config]
|
31
|
+
|
32
|
+
search_result = Asger::Util::run_command("knife search: #{instance_id}",
|
33
|
+
"knife search node -c '#{knife_config}' -i -F json 'tags:#{instance_id}'",
|
34
|
+
logger)
|
35
|
+
|
36
|
+
raise "knife search for '#{instance_id}' failed with exit code #{search_result[0]}." unless search_result[0] == 0
|
37
|
+
|
38
|
+
search_json = JSON.parse(search_result[1])
|
39
|
+
|
40
|
+
case search_json["rows"].length
|
41
|
+
when 0
|
42
|
+
logger.warn "No Chef entry found for instance '#{instance_id}'."
|
43
|
+
logger.warn "Make sure the instance was Chef-tagged and came up successfully."
|
44
|
+
when 1
|
45
|
+
node_name = search_json["rows"][0]
|
46
|
+
delete_node_result = Asger::Util::run_command("knife node delete: #{node_name}",
|
47
|
+
"knife node delete -y -c '#{knife_config}' #{node_name}",
|
48
|
+
logger)
|
49
|
+
raise "knife node delete for '#{instance_id}' failed with exit code #{search_result[0]}." unless delete_node_result[0] == 0
|
50
|
+
delete_client_result = Asger::Util::run_command("knife client delete: #{node_name}",
|
51
|
+
"knife client delete -y -c '#{knife_config}' #{node_name}",
|
52
|
+
logger)
|
53
|
+
|
54
|
+
raise "knife client delete for '#{instance_id}' failed with exit code #{search_result[0]}." unless delete_client_result[0] == 0
|
55
|
+
else
|
56
|
+
logger.error "#{search_json["rows"].length} entries found in Chef for '#{instance_id}."
|
57
|
+
logger.error "I don't know what to safely do; you should handle this yourself."
|
58
|
+
end
|
59
|
+
|
60
|
+
logger.info "Removed instance '#{instance_id}' from Chef."
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ed Ropple
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: aws-sdk
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.27
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.27
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: trollop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.1.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.1.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: hashie
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.3'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activesupport
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.2.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.2.0
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- ed@edropple.com
|
114
|
+
executables:
|
115
|
+
- asger
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".gitignore"
|
120
|
+
- ".yardopts"
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- asger.gemspec
|
126
|
+
- bin/asger
|
127
|
+
- lib/asger.rb
|
128
|
+
- lib/asger/cli.rb
|
129
|
+
- lib/asger/runner.rb
|
130
|
+
- lib/asger/task.rb
|
131
|
+
- lib/asger/util.rb
|
132
|
+
- lib/asger/version.rb
|
133
|
+
- stock_scripts/chef_deregister.rb
|
134
|
+
- stock_scripts/echo.rb
|
135
|
+
homepage: ''
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata: {}
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.2.2
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: A persistent daemon that watches an AWS autoscaling group for changes and
|
159
|
+
dispatches your code.
|
160
|
+
test_files: []
|
161
|
+
has_rdoc:
|