guignol 0.1.2.1 → 0.3.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.
- data/.gitignore +2 -0
- data/.rspec +2 -1
- data/Gemfile.lock +29 -18
- data/LICENCE +26 -0
- data/README.md +67 -38
- data/Rakefile +0 -26
- data/bin/guignol +3 -33
- data/guignol.gemspec +4 -30
- data/lib/core_ext/array/collect_key.rb +6 -0
- data/lib/core_ext/hash/map_to_hash.rb +31 -0
- data/lib/guignol.rb +15 -35
- data/lib/guignol/commands/base.rb +53 -66
- data/lib/guignol/commands/clone.rb +49 -0
- data/lib/guignol/commands/create.rb +14 -33
- data/lib/guignol/commands/execute.rb +69 -0
- data/lib/guignol/commands/fix_dns.rb +12 -33
- data/lib/guignol/commands/kill.rb +18 -36
- data/lib/guignol/commands/list.rb +19 -45
- data/lib/guignol/commands/start.rb +14 -33
- data/lib/guignol/commands/stop.rb +18 -37
- data/lib/guignol/commands/uuid.rb +19 -32
- data/lib/guignol/configuration.rb +43 -0
- data/lib/guignol/connection.rb +33 -0
- data/lib/guignol/env.rb +19 -0
- data/lib/guignol/logger.rb +29 -0
- data/lib/guignol/models/base.rb +125 -0
- data/lib/guignol/models/instance.rb +244 -0
- data/lib/guignol/models/volume.rb +91 -0
- data/lib/guignol/shell.rb +27 -42
- data/lib/guignol/tty_spinner.rb +6 -29
- data/lib/guignol/version.rb +1 -27
- data/spec/guignol/configuration_spec.rb +72 -0
- data/spec/guignol/instance_spec.rb +48 -8
- data/spec/guignol/volume_spec.rb +17 -0
- data/spec/spec_helper.rb +12 -0
- data/tmp/.keepme +0 -0
- metadata +79 -52
- data/lib/guignol/array/collect_key.rb +0 -32
- data/lib/guignol/commands.rb +0 -48
- data/lib/guignol/commands/help.rb +0 -77
- data/lib/guignol/instance.rb +0 -270
- data/lib/guignol/shared.rb +0 -80
- data/lib/guignol/volume.rb +0 -124
data/lib/guignol.rb
CHANGED
@@ -1,38 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
-
# list of conditions and the following disclaimer.
|
9
|
-
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
-
# this list of conditions and the following disclaimer in the documentation
|
11
|
-
# and/or other materials provided with the distribution.
|
12
|
-
#
|
13
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
-
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
-
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
-
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
-
#
|
24
|
-
# The views and conclusions contained in the software and documentation are those
|
25
|
-
# of the authors and should not be interpreted as representing official policies,
|
26
|
-
# either expressed or implied, of the authors.
|
1
|
+
|
2
|
+
require 'core_ext/array/collect_key'
|
3
|
+
require 'core_ext/hash/map_to_hash'
|
4
|
+
require 'guignol/logger'
|
5
|
+
require 'guignol/configuration'
|
6
|
+
require 'guignol/env'
|
27
7
|
|
28
8
|
module Guignol
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
9
|
+
DefaultConnectionOptions = {
|
10
|
+
:provider => :aws,
|
11
|
+
:region => 'eu-west-1'
|
12
|
+
}
|
13
|
+
DefaultServerOptions = {
|
14
|
+
:flavor_id => 't1.micro',
|
15
|
+
:volumes => []
|
16
|
+
}
|
17
|
+
DefaultVolumeOptions = {}
|
38
18
|
end
|
@@ -1,88 +1,75 @@
|
|
1
|
-
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
-
# list of conditions and the following disclaimer.
|
9
|
-
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
-
# this list of conditions and the following disclaimer in the documentation
|
11
|
-
# and/or other materials provided with the distribution.
|
12
|
-
#
|
13
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
-
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
-
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
-
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
-
#
|
24
|
-
# The views and conclusions contained in the software and documentation are those
|
25
|
-
# of the authors and should not be interpreted as representing official policies,
|
26
|
-
# either expressed or implied, of the authors.
|
27
|
-
|
28
|
-
|
1
|
+
require 'thor'
|
29
2
|
require 'pathname'
|
30
3
|
require 'parallel'
|
31
|
-
require 'guignol
|
32
|
-
require 'guignol/
|
4
|
+
require 'guignol'
|
5
|
+
require 'guignol/configuration'
|
6
|
+
require 'guignol/models/instance'
|
7
|
+
require 'core_ext/array/collect_key'
|
33
8
|
|
34
9
|
module Guignol::Commands
|
35
10
|
class Base
|
36
11
|
|
37
|
-
def initialize(
|
38
|
-
@
|
39
|
-
|
40
|
-
@configs = argv.map { |pattern|
|
41
|
-
@all_configs.select { |config|
|
42
|
-
config[:name] =~ /#{pattern}/
|
43
|
-
}
|
44
|
-
}.flatten.uniq
|
12
|
+
def initialize(patterns, options = {})
|
13
|
+
@configs = select_configs(patterns)
|
14
|
+
@options = options
|
45
15
|
end
|
46
16
|
|
17
|
+
# Run the block for each server in +configs+ (in parallel).
|
47
18
|
def run
|
48
|
-
before_run or return
|
19
|
+
before_run(@configs) or return
|
20
|
+
results = {}
|
49
21
|
|
50
|
-
Parallel.each(@configs) do |config|
|
51
|
-
|
22
|
+
Parallel.each(@configs, parallel_options) do |name,config|
|
23
|
+
instance = Guignol::Models::Instance.new(name, config)
|
24
|
+
results[name] = run_on_server(instance, @options)
|
52
25
|
end
|
26
|
+
|
27
|
+
after_run(results)
|
53
28
|
end
|
54
29
|
|
55
|
-
protected
|
56
30
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
31
|
+
protected
|
32
|
+
|
33
|
+
# Override in subclasses
|
34
|
+
def before_run(configs) ; true ; end
|
35
|
+
|
36
|
+
# Override in subclasses
|
37
|
+
def after_run(data) ; true ; end
|
38
|
+
|
39
|
+
|
40
|
+
def shell
|
41
|
+
Guignol::Shell.shared_shell
|
62
42
|
end
|
63
43
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
[
|
69
|
-
Pathname.new(ENV['GUIGNOL_YML'] || '/var/nonexistent'),
|
70
|
-
Pathname.new('guignol.yml'),
|
71
|
-
Pathname.new('config/guignol.yml'),
|
72
|
-
Pathname.new(ENV['HOME']).join('.guignol.yml')
|
73
|
-
].each do |pathname|
|
74
|
-
next unless pathname.exist?
|
75
|
-
return YAML.load(pathname.read)
|
44
|
+
|
45
|
+
def synchronize
|
46
|
+
(@mutex ||= Mutex.new).synchronize do
|
47
|
+
yield
|
76
48
|
end
|
77
|
-
return {}
|
78
49
|
end
|
79
50
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
|
55
|
+
def parallel_options
|
56
|
+
if RUBY_VERSION >= '1.9.3'
|
57
|
+
# 1.9.3 has bugs with Excon / SSL connections
|
58
|
+
{ :in_threads => 0 }
|
59
|
+
else
|
60
|
+
{ :in_threads => @configs.size }
|
61
|
+
end
|
86
62
|
end
|
63
|
+
|
64
|
+
# Put all the servers matching one of the +names+ in +configs+.
|
65
|
+
def select_configs(patterns)
|
66
|
+
patterns = patterns.map { |pattern|
|
67
|
+
pattern.kind_of?(String) ? Regexp.new(pattern) : pattern
|
68
|
+
}
|
69
|
+
Guignol.configuration.delete_if { |name,config|
|
70
|
+
patterns.none? { |pattern| name.to_s =~ pattern }
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
87
74
|
end
|
88
75
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
require 'guignol/configuration'
|
3
|
+
require 'guignol/commands/base'
|
4
|
+
require 'uuidtools'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
|
8
|
+
Guignol::Shell.class_eval do
|
9
|
+
desc 'clone SOURCE', 'Print a new config similar to the server named SOURCE'
|
10
|
+
method_option :name,
|
11
|
+
:aliases => %w(-n),
|
12
|
+
:type => :string, :default => 'new-server',
|
13
|
+
:desc => 'Name to use for the new server'
|
14
|
+
def clone(source)
|
15
|
+
Guignol::Commands::Clone.new(source, options[:name]).run
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
module Guignol::Commands
|
21
|
+
class Clone
|
22
|
+
def initialize(source_name, target_name)
|
23
|
+
@source_name = source_name
|
24
|
+
@target_name = target_name
|
25
|
+
|
26
|
+
@source_config = Guignol.configuration[source_name]
|
27
|
+
unless @source_config
|
28
|
+
raise Thor::Error.new "machine '#{source_name}' is unknown"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def run
|
34
|
+
new_config = @source_config.map_to_hash(:deep => true) do |key,value|
|
35
|
+
value = value.gsub(/#{@source_name}/, @target_name) if value.kind_of?(String)
|
36
|
+
key = key.gsub( /#{@source_name}/, @target_name) if key.kind_of?(String)
|
37
|
+
|
38
|
+
case key
|
39
|
+
when :uuid
|
40
|
+
[key, UUIDTools::UUID.random_create.to_s.upcase]
|
41
|
+
else
|
42
|
+
[key, value]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
$stdout.puts({@target_name => new_config}.to_yaml)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,41 +1,22 @@
|
|
1
|
-
# Copyright (c) 2012, HouseTrip SA.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
-
# list of conditions and the following disclaimer.
|
9
|
-
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
-
# this list of conditions and the following disclaimer in the documentation
|
11
|
-
# and/or other materials provided with the distribution.
|
12
|
-
#
|
13
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
-
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
-
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
-
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
-
#
|
24
|
-
# The views and conclusions contained in the software and documentation are those
|
25
|
-
# of the authors and should not be interpreted as representing official policies,
|
26
|
-
# either expressed or implied, of the authors.
|
27
1
|
|
28
2
|
require 'guignol/commands/base'
|
29
|
-
require 'guignol/instance'
|
3
|
+
require 'guignol/models/instance'
|
30
4
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
5
|
+
Guignol::Shell.class_eval do
|
6
|
+
desc 'create PATTERNS', 'Create and start all instances matching PATTERNS and their volumes'
|
7
|
+
def create(*patterns)
|
8
|
+
if patterns.empty?
|
9
|
+
raise Thor::Error.new('You must specify at least one PATTERN.')
|
35
10
|
end
|
11
|
+
Guignol::Commands::Create.new(patterns).run
|
12
|
+
end
|
13
|
+
end
|
36
14
|
|
37
|
-
|
38
|
-
|
15
|
+
|
16
|
+
module Guignol::Commands
|
17
|
+
class Create < Base
|
18
|
+
def run_on_server(instance, options = {})
|
19
|
+
instance.create
|
39
20
|
end
|
40
21
|
end
|
41
22
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'guignol/commands/base'
|
2
|
+
|
3
|
+
Guignol::Shell.class_eval do
|
4
|
+
desc 'execute COMMAND', 'Execute a command over SSH on instances'
|
5
|
+
method_option :on,
|
6
|
+
:banner => 'PATTERNS',
|
7
|
+
:type => :array, :default => ['.*'],
|
8
|
+
:desc => 'A list of regexps matching servers on which to run'
|
9
|
+
method_option :verbose,
|
10
|
+
:aliases => %w(-v), :type => :boolean, :default => false,
|
11
|
+
:desc => 'Output the command output to the local terminal'
|
12
|
+
method_option :aws_key,
|
13
|
+
:aliases => %w(-k), :type => :string,
|
14
|
+
:desc => 'Path the the SSH key file to use to connect'
|
15
|
+
method_option :user,
|
16
|
+
:aliases => %w(-u), :type => :string,
|
17
|
+
:desc => 'Username used to connect (takes precedence over the name defined in the config file)'
|
18
|
+
long_desc %Q{
|
19
|
+
Connect to each server matching one of the PATTERNS (defaults to all
|
20
|
+
known servers) over SSH, and run the COMMAND on them, in parallel.
|
21
|
+
}
|
22
|
+
def execute(*words)
|
23
|
+
words.shift if words.first =~ /^-+$/
|
24
|
+
command = words.join(' ')
|
25
|
+
Guignol::Commands::Execute.
|
26
|
+
new(options[:on], options.merge(:command => command)).
|
27
|
+
run
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Guignol::Commands
|
32
|
+
class Execute < Base
|
33
|
+
private
|
34
|
+
def run_on_server(instance, options = {})
|
35
|
+
if instance.state != 'running'
|
36
|
+
print_output(instance.name, "Instance not running", :red)
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
instance.subject.username = options[:user] if options[:user]
|
41
|
+
results = instance.subject.ssh(options[:command], :keys => options[:aws_key])
|
42
|
+
|
43
|
+
return unless options[:verbose]
|
44
|
+
results.each do |result|
|
45
|
+
print_output(instance.name, result.stderr, :yellow)
|
46
|
+
print_output(instance.name, result.stdout, :green)
|
47
|
+
end
|
48
|
+
|
49
|
+
rescue Net::SSH::AuthenticationFailed => e
|
50
|
+
print_output(instance.name, "#{e.message} (#{e.class.name})", :red)
|
51
|
+
end
|
52
|
+
|
53
|
+
def before_run(configs)
|
54
|
+
@max_width = configs.keys.map(&:size).max
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def print_output(name, data, color)
|
59
|
+
synchronize do
|
60
|
+
name_string = name.ljust(@max_width+1)
|
61
|
+
data.split(/\r?\n/).each do |line|
|
62
|
+
shell.say name_string, color
|
63
|
+
shell.say line, :clear, true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -1,41 +1,20 @@
|
|
1
|
-
# Copyright (c) 2012, HouseTrip SA.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
-
# list of conditions and the following disclaimer.
|
9
|
-
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
-
# this list of conditions and the following disclaimer in the documentation
|
11
|
-
# and/or other materials provided with the distribution.
|
12
|
-
#
|
13
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
-
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
-
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
-
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
-
#
|
24
|
-
# The views and conclusions contained in the software and documentation are those
|
25
|
-
# of the authors and should not be interpreted as representing official policies,
|
26
|
-
# either expressed or implied, of the authors.
|
27
1
|
|
28
2
|
require 'guignol/commands/base'
|
29
|
-
require 'guignol/instance'
|
3
|
+
require 'guignol/models/instance'
|
4
|
+
|
5
|
+
Guignol::Shell.class_eval do
|
6
|
+
desc 'fixdns [PATTERNS]', 'Make sure the DNS mappings are correct for servers matching PATTERNS'
|
7
|
+
def fixdns(*patterns)
|
8
|
+
patterns.push('.*') if patterns.empty?
|
9
|
+
Guignol::Commands::FixDNS.new(patterns).run
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
30
13
|
|
31
14
|
module Guignol::Commands
|
32
15
|
class FixDNS < Base
|
33
|
-
def run_on_server(
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.short_usage
|
38
|
-
["<regexps>", "Make sure the DNS mappings are correct."]
|
16
|
+
def run_on_server(instance, options = {})
|
17
|
+
instance.update_dns
|
39
18
|
end
|
40
19
|
end
|
41
20
|
end
|
@@ -1,47 +1,29 @@
|
|
1
|
-
# Copyright (c) 2012, HouseTrip SA.
|
2
|
-
# All rights reserved.
|
3
|
-
#
|
4
|
-
# Redistribution and use in source and binary forms, with or without
|
5
|
-
# modification, are permitted provided that the following conditions are met:
|
6
|
-
#
|
7
|
-
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
-
# list of conditions and the following disclaimer.
|
9
|
-
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
-
# this list of conditions and the following disclaimer in the documentation
|
11
|
-
# and/or other materials provided with the distribution.
|
12
|
-
#
|
13
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
-
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
-
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
-
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
-
#
|
24
|
-
# The views and conclusions contained in the software and documentation are those
|
25
|
-
# of the authors and should not be interpreted as representing official policies,
|
26
|
-
# either expressed or implied, of the authors.
|
27
1
|
|
28
2
|
require 'guignol/commands/base'
|
29
|
-
require 'guignol/instance'
|
3
|
+
require 'guignol/models/instance'
|
4
|
+
|
5
|
+
Guignol::Shell.class_eval do
|
6
|
+
desc 'kill PATTERNS', 'Terminate all instances matching PATTERNS'
|
7
|
+
def kill(*patterns)
|
8
|
+
if patterns.empty?
|
9
|
+
raise Thor::Error.new('You must specify at least one PATTERN.')
|
10
|
+
end
|
11
|
+
Guignol::Commands::Kill.new(patterns).run
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
30
15
|
|
31
16
|
module Guignol::Commands
|
32
17
|
class Kill < Base
|
33
|
-
def before_run
|
34
|
-
return true if @configs.empty?
|
35
|
-
names = @configs.map { |config| config[:name] }.join(", ")
|
36
|
-
confirm "Are you sure you want to destroy servers #{names}"
|
37
|
-
end
|
38
18
|
|
39
|
-
def
|
40
|
-
|
19
|
+
def before_run(configs)
|
20
|
+
return true if configs.empty?
|
21
|
+
names = configs.keys.join(", ")
|
22
|
+
shell.yes? "Are you sure you want to destroy servers #{names}? [y/N]", :cyan
|
41
23
|
end
|
42
24
|
|
43
|
-
def
|
44
|
-
|
25
|
+
def run_on_server(instance, options = {})
|
26
|
+
instance.destroy
|
45
27
|
end
|
46
28
|
end
|
47
29
|
end
|