rundock 0.2.0 → 0.2.2
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 +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +36 -7
- data/Rakefile +16 -20
- data/lib/rundock/backend.rb +15 -18
- data/lib/rundock/builder/backend_builder.rb +21 -20
- data/lib/rundock/builder/default_ssh_builder.rb +3 -3
- data/lib/rundock/builder/operation_builder.rb +88 -0
- data/lib/rundock/builder/scenario_builder.rb +21 -58
- data/lib/rundock/cli.rb +10 -7
- data/lib/rundock/logger.rb +7 -1
- data/lib/rundock/node.rb +4 -0
- data/lib/rundock/operation/command.rb +5 -0
- data/lib/rundock/operation/task.rb +6 -3
- data/lib/rundock/runner.rb +14 -10
- data/lib/rundock/scenario.rb +10 -2
- data/lib/rundock/version.rb +1 -1
- data/lib/rundock.rb +1 -0
- data/rundock.gemspec +1 -1
- data/scenario_sample.yml +15 -5
- data/spec/integration/{scenarios → groups}/simple_host_group.yml +1 -1
- data/spec/integration/platforms/centos6/setup.sh +13 -3
- data/spec/integration/platforms/localhost/scenarios/run_anyway_scenario.yml +14 -0
- data/spec/integration/platforms/localhost/scenarios/simple_echo_scenario.yml +2 -1
- data/spec/integration/scenarios/simple_echo_scenario.yml +7 -5
- data/spec/integration/spec_helper.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eef77dde29974f83d4bef90d7ac82886ebfc46d5
|
4
|
+
data.tar.gz: 484b9c3e7f4f4f557a3ecb1d3d5ce506566bc45d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: adf8f0dc23a9a4f38db95b77eb804ac336dae9aba7d0a8d671572221c635c8ec8fc6fd3b71ef0cc8979162f22253b603345a85b33578e413bbe30005037622be
|
7
|
+
data.tar.gz: a8b0d0a20eb279a2ae8f46cbe800a38fe266736d4087a0eccb15546cea74d7e13525245e72706a999376e64fd622cad4198b8f4245a6b9408a8b397ab781f5da
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## v0.2.2
|
2
|
+
|
3
|
+
Fix
|
4
|
+
|
5
|
+
- Fix ssh options conflict bugs
|
6
|
+
- Support docker 1.6.2 for Circle CI environtment
|
7
|
+
|
8
|
+
## v0.2.1
|
9
|
+
|
10
|
+
Improvements
|
11
|
+
|
12
|
+
- Support error-exit options.(like shellscript set -e/+e)
|
13
|
+
- Change file path option name from '*_yaml' to '*'
|
14
|
+
- Add a option that stdout can no-header
|
15
|
+
|
1
16
|
## v0.2.0
|
2
17
|
|
3
18
|
Refactoring
|
data/README.md
CHANGED
@@ -12,6 +12,28 @@ $ gem install rundock
|
|
12
12
|
|
13
13
|
## Usage
|
14
14
|
|
15
|
+
Edit your hostgroup to "hostgroup.yml" like this sample.
|
16
|
+
|
17
|
+
```
|
18
|
+
# node section
|
19
|
+
- node: 192.168.1.11
|
20
|
+
- node: host-alias-01
|
21
|
+
---
|
22
|
+
# host information section
|
23
|
+
host-alias-01:
|
24
|
+
host: 192.168.1.12
|
25
|
+
ssh_opts:
|
26
|
+
port: 2222
|
27
|
+
user: anyuser
|
28
|
+
keys: ["~/.ssh/id_rsa_anyuser"]
|
29
|
+
```
|
30
|
+
|
31
|
+
and execute rundock.
|
32
|
+
|
33
|
+
$ rundock ssh -g /path/to/your-dir/hostgroup.yml -c 'your-gread-command'
|
34
|
+
|
35
|
+
or
|
36
|
+
|
15
37
|
Edit your operation scenario to "[scenario.yml](https://github.com/hiracy/rundock/blob/master/scenario_sample.yml)" like this sample.
|
16
38
|
|
17
39
|
```
|
@@ -37,19 +59,26 @@ host-alias-01:
|
|
37
59
|
---
|
38
60
|
# task information section
|
39
61
|
update_gem:
|
40
|
-
|
41
|
-
|
62
|
+
command:
|
63
|
+
- "sudo gem update --system"
|
64
|
+
- "sudo gem update"
|
42
65
|
install_bundler:
|
43
|
-
|
66
|
+
command:
|
67
|
+
- "sudo gem install bundler --no-ri --no-rdoc"
|
44
68
|
```
|
45
69
|
|
46
|
-
and
|
70
|
+
and execute rundock.
|
47
71
|
|
48
|
-
$ rundock do
|
72
|
+
$ rundock do /path/to/your-dir/scenario.yml
|
49
73
|
|
50
|
-
You can also specify [
|
74
|
+
You can also specify [default_ssh_options.yml](https://github.com/hiracy/rundock/blob/master/default_ssh.yml) [(Net::SSH options)](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html) file contents that you specified "-d" option to the default ssh options.
|
51
75
|
|
52
|
-
|
76
|
+
```
|
77
|
+
$ rundock ssh -g /path/to/your-dir/hostgroup.yml -c 'your-gread-command' -d /path/to/your-dir/default_ssh_options.yml
|
78
|
+
```
|
79
|
+
```
|
80
|
+
$ rundock do -s /path/to/your-dir/scenario.yml -d /path/to/your-dir/default_ssh_options.yml
|
81
|
+
```
|
53
82
|
|
54
83
|
For more detail. You can see from `rundock -h` command.
|
55
84
|
|
data/Rakefile
CHANGED
@@ -6,15 +6,6 @@ run_commands = [
|
|
6
6
|
'echo \'Hello Rundock.\' > /var/tmp/hello_rundock'
|
7
7
|
]
|
8
8
|
|
9
|
-
run_scenarios = %w(
|
10
|
-
use_default_ssh_scenario
|
11
|
-
simple_echo_scenario
|
12
|
-
)
|
13
|
-
|
14
|
-
run_groups = %w(
|
15
|
-
simple_host_group
|
16
|
-
)
|
17
|
-
|
18
9
|
def execute(command, clean_env)
|
19
10
|
puts "[EXECUTE:] #{command}"
|
20
11
|
|
@@ -42,8 +33,9 @@ def setup_docker(platform, timeout, interval)
|
|
42
33
|
raise 'Docker Error.' unless found
|
43
34
|
end
|
44
35
|
|
45
|
-
def do_rundock_ssh(commands, platform
|
36
|
+
def do_rundock_ssh(commands, platform)
|
46
37
|
base_dir = "#{ENV['HOME']}/.rundock/#{platform}"
|
38
|
+
groups_files_pattern = ["#{base_dir}/groups/*.yml"]
|
47
39
|
|
48
40
|
if platform == 'localhost'
|
49
41
|
commands.each do |cmd|
|
@@ -52,38 +44,42 @@ def do_rundock_ssh(commands, platform, groups)
|
|
52
44
|
else
|
53
45
|
commands.each do |cmd|
|
54
46
|
execute('bundle exec exe/rundock' \
|
55
|
-
" ssh -c \"#{cmd}\" -h
|
47
|
+
" ssh -c \"#{cmd}\" -h 172.17.42.1 -p 22222 -u tester" \
|
56
48
|
" -i #{ENV['HOME']}/.ssh/id_rsa_rundock_spec_#{platform}_tmp -l debug", true)
|
57
|
-
|
49
|
+
Dir.glob(groups_files_pattern).each do |g|
|
58
50
|
execute('bundle exec exe/rundock' \
|
59
|
-
" ssh -c \"#{cmd}\" -g #{
|
51
|
+
" ssh -c \"#{cmd}\" -g #{g} -p 22222 -u tester" \
|
60
52
|
" -i #{ENV['HOME']}/.ssh/id_rsa_rundock_spec_#{platform}_tmp -l debug", true)
|
61
53
|
end
|
62
54
|
end
|
63
55
|
end
|
64
56
|
end
|
65
57
|
|
66
|
-
def do_rundock_scenarios(
|
58
|
+
def do_rundock_scenarios(platform)
|
67
59
|
if platform == 'localhost'
|
68
60
|
base_dir = './spec/integration/platforms/localhost'
|
61
|
+
scenario_files_pattern = ['./spec/integration/platforms/localhost/scenarios/*.yml']
|
69
62
|
else
|
70
63
|
base_dir = "#{ENV['HOME']}/.rundock/#{platform}"
|
64
|
+
scenario_files_pattern = ["#{base_dir}/scenarios/*.yml"]
|
71
65
|
end
|
72
66
|
|
73
|
-
|
74
|
-
default_ssh_opt = ''
|
67
|
+
Dir.glob(scenario_files_pattern).each do |scenario|
|
75
68
|
if scenario =~ /use_default_ssh/ && platform != 'localhost'
|
76
69
|
default_ssh_opt = " -d #{base_dir}/integration_default_ssh.yml"
|
70
|
+
else
|
71
|
+
default_ssh_opt = ''
|
77
72
|
end
|
78
73
|
|
79
74
|
execute('bundle exec exe/rundock' \
|
80
|
-
" do
|
75
|
+
" do #{scenario}#{default_ssh_opt} -l debug", true)
|
81
76
|
end
|
82
77
|
end
|
83
78
|
|
84
79
|
desc 'Cleaning environments'
|
85
80
|
|
86
81
|
task :clean do
|
82
|
+
execute('rm -f /var/tmp/hello_rundock*', false)
|
87
83
|
Dir.glob('./spec/integration/platforms/*').each do |platform|
|
88
84
|
next if platform =~ /localhost$/
|
89
85
|
execute("#{platform}/setup.sh --clean", false)
|
@@ -132,8 +128,8 @@ namespace :spec do
|
|
132
128
|
desc "Run rundock for #{target}"
|
133
129
|
|
134
130
|
task :rundock do
|
135
|
-
do_rundock_ssh(run_commands, target
|
136
|
-
do_rundock_scenarios(
|
131
|
+
do_rundock_ssh(run_commands, target)
|
132
|
+
do_rundock_scenarios(target)
|
137
133
|
end
|
138
134
|
|
139
135
|
desc "Run serverspec tests for #{target}"
|
@@ -141,7 +137,7 @@ namespace :spec do
|
|
141
137
|
RSpec::Core::RakeTask.new(:serverspec) do |t|
|
142
138
|
ENV['TARGET_HOST'] = target
|
143
139
|
t.ruby_opts = '-I ./spec/integration'
|
144
|
-
t.pattern = './spec/integration/recipes/*_spec.rb'
|
140
|
+
t.pattern = ['./spec/integration/recipes/*_spec.rb']
|
145
141
|
end
|
146
142
|
end
|
147
143
|
end
|
data/lib/rundock/backend.rb
CHANGED
@@ -25,18 +25,18 @@ module Rundock
|
|
25
25
|
@backend = create_specinfra_backend
|
26
26
|
end
|
27
27
|
|
28
|
-
def run_commands(cmd,
|
28
|
+
def run_commands(cmd, exec_options = {})
|
29
29
|
Array(cmd).each do |c|
|
30
|
-
run_command(c)
|
30
|
+
run_command(c, exec_options)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
def run_command(cmd,
|
36
|
+
def run_command(cmd, exec_options = {})
|
37
37
|
command = cmd.strip
|
38
|
-
command = "cd #{Shellwords.escape(
|
39
|
-
command = "sudo -H -u #{Shellwords.escape(user)} -- /bin/sh -c #{command}" if
|
38
|
+
command = "cd #{Shellwords.escape(exec_options[:cwd])} && #{command}" if exec_options[:cwd]
|
39
|
+
command = "sudo -H -u #{Shellwords.escape(user)} -- /bin/sh -c #{command}" if exec_options[:user]
|
40
40
|
|
41
41
|
Logger.debug(%(Start executing: "#{command}"))
|
42
42
|
|
@@ -46,11 +46,12 @@ module Rundock
|
|
46
46
|
Logger.formatter.indent do
|
47
47
|
Logger.error("#{result.stderr}") unless result.stderr.blank?
|
48
48
|
Logger.info("#{result.stdout.strip}") unless result.stdout.strip.blank?
|
49
|
+
Logger.debug("errexit: #{exec_options[:errexit]}")
|
49
50
|
Logger.debug("exit status: #{exit_status}")
|
50
51
|
end
|
51
52
|
|
52
|
-
if
|
53
|
-
raise
|
53
|
+
if exec_options[:errexit] && exit_status != 0
|
54
|
+
raise CommandResultStatusError
|
54
55
|
end
|
55
56
|
|
56
57
|
result
|
@@ -81,19 +82,15 @@ module Rundock
|
|
81
82
|
private
|
82
83
|
|
83
84
|
def parse(options)
|
84
|
-
if options[
|
85
|
-
ssh_opts = Net::SSH::Config.for(options[
|
85
|
+
if options[:ssh_config] && FileTest.exists?(options[:ssh_config])
|
86
|
+
ssh_opts = Net::SSH::Config.for(options[:host], [options[:ssh_config]])
|
86
87
|
else
|
87
|
-
ssh_opts = Net::SSH::Config.for(options[
|
88
|
+
ssh_opts = Net::SSH::Config.for(options[:host])
|
88
89
|
end
|
89
90
|
|
90
|
-
ssh_opts[:host_name] = options[
|
91
|
-
ssh_opts[:
|
92
|
-
ssh_opts[:
|
93
|
-
ssh_opts[:keys] = Array(options['key']) if !ssh_opts[:keys] && options['key']
|
94
|
-
ssh_opts[:port] = options['port']
|
95
|
-
ssh_opts[:password] = parse_password_from_stdin if options['ask_password']
|
96
|
-
|
91
|
+
ssh_opts[:host_name] = options[:host]
|
92
|
+
ssh_opts[:keys] = Array(options[:key]) if options[:key]
|
93
|
+
ssh_opts[:password] = parse_password_from_stdin if options[:ask_password]
|
97
94
|
ssh_opts.merge!(filter_net_ssh_options(options))
|
98
95
|
|
99
96
|
Logger.debug(%(Net::SSH Options: "#{ssh_opts}"))
|
@@ -111,7 +108,7 @@ module Rundock
|
|
111
108
|
def filter_net_ssh_options(options)
|
112
109
|
opts = {}
|
113
110
|
options.each do |k, v|
|
114
|
-
opts[k
|
111
|
+
opts[k] = v if Net::SSH::VALID_OPTIONS.include?(k)
|
115
112
|
end
|
116
113
|
|
117
114
|
opts
|
@@ -15,12 +15,14 @@ module Rundock
|
|
15
15
|
opts.merge!(@options)
|
16
16
|
|
17
17
|
# update ssh options for node from node_info
|
18
|
-
opts.merge!(@node_info[@nodename][
|
18
|
+
opts.merge!(@node_info[@nodename.to_sym][:ssh_opts])
|
19
|
+
|
19
20
|
# delete trash ssh_options(node[host::ssh_options])
|
20
|
-
@node_info[@nodename].delete(
|
21
|
+
@node_info[@nodename.to_sym].delete(:ssh_opts)
|
21
22
|
|
22
23
|
# add any attributes for host from node_info
|
23
|
-
opts.merge!(@node_info[@nodename])
|
24
|
+
opts.merge!(@node_info[@nodename.to_sym])
|
25
|
+
|
24
26
|
Backend.create(backend_type, opts)
|
25
27
|
end
|
26
28
|
|
@@ -30,35 +32,34 @@ module Rundock
|
|
30
32
|
opts = {}
|
31
33
|
|
32
34
|
if !@node_info ||
|
33
|
-
!@node_info[@nodename]
|
34
|
-
@node_info = { @nodename => {} }
|
35
|
+
!@node_info[@nodename.to_sym]
|
36
|
+
@node_info = { @nodename.to_sym => {} }
|
35
37
|
end
|
36
|
-
@node_info[@nodename][
|
37
|
-
is_local = @nodename =~ /localhost|127\.0\.0\.1/
|
38
|
+
@node_info[@nodename.to_sym][:ssh_opts] = {} unless @node_info[@nodename.to_sym][:ssh_opts]
|
38
39
|
|
39
40
|
# replace default ssh options if exists
|
40
|
-
@options.keys.select { |o| o =~ /(\w+)_ssh_default$/ }.each do |oo|
|
41
|
-
opt = oo.gsub(/_ssh_default/, '')
|
41
|
+
@options.keys.select { |o| o.to_s =~ /(\w+)_ssh_default$/ }.each do |oo|
|
42
42
|
# no use default ssh options if local
|
43
|
-
#
|
44
|
-
|
43
|
+
# set unless scenario file and cli options specified and not localhost
|
44
|
+
next if @nodename =~ /localhost|127\.0\.0\.1/
|
45
|
+
opt = oo.to_s.gsub(/_ssh_default/, '').to_sym
|
46
|
+
if !@node_info[@nodename.to_sym][:ssh_opts][opt] && !@options[opt]
|
47
|
+
@node_info[@nodename.to_sym][:ssh_opts][opt] = @options[oo]
|
48
|
+
end
|
45
49
|
end
|
46
50
|
|
47
51
|
# replace cli ssh options if exists
|
48
|
-
%w(user key port ssh_config ask_password sudo).each { |o| @node_info[@nodename][
|
49
|
-
|
50
|
-
opts['host'] = @nodename
|
52
|
+
%w(:user :key :port :ssh_config :ask_password :sudo).each { |o| @node_info[@nodename.to_sym][:ssh_opts][o] = @options[o] if @options[o] }
|
51
53
|
|
54
|
+
opts[:host] = @nodename
|
52
55
|
opts
|
53
56
|
end
|
54
57
|
|
55
58
|
def parse_backend_type
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
!@node_info[@nodename][
|
60
|
-
!@node_info[@nodename]['ssh_opts']['user'] &&
|
61
|
-
!@node_info[@nodename]['ssh_opts']['ssh_config']
|
59
|
+
if @nodename =~ /localhost|127\.0\.0\.1/ &&
|
60
|
+
!@node_info[@nodename.to_sym][:ssh_opts][:port] &&
|
61
|
+
!@node_info[@nodename.to_sym][:ssh_opts][:user] &&
|
62
|
+
!@node_info[@nodename.to_sym][:ssh_opts][:ssh_config]
|
62
63
|
backend_type = :local
|
63
64
|
else
|
64
65
|
backend_type = :ssh
|
@@ -12,8 +12,8 @@ module Rundock
|
|
12
12
|
def build
|
13
13
|
opts = {}
|
14
14
|
|
15
|
-
if @options[
|
16
|
-
def_ssh_file = @options[
|
15
|
+
if @options[:default_ssh_opts] && FileTest.exist?(@options[:default_ssh_opts])
|
16
|
+
def_ssh_file = @options[:default_ssh_opts]
|
17
17
|
else
|
18
18
|
def_ssh_file = PRESET_SSH_OPTIONS_DEFAULT_FILE_PATH
|
19
19
|
end
|
@@ -21,7 +21,7 @@ module Rundock
|
|
21
21
|
File.open(def_ssh_file) do |f|
|
22
22
|
YAML.load_documents(f) do |y|
|
23
23
|
y.each do |k, v|
|
24
|
-
opts["#{k}_ssh_default"] = v
|
24
|
+
opts["#{k}_ssh_default".to_sym] = v
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Rundock
|
2
|
+
module Builder
|
3
|
+
class OperationBuilder < Base
|
4
|
+
def build_first(scenario, node_info, tasks)
|
5
|
+
if @options[:hostgroup] && !@options[:command]
|
6
|
+
raise CommandArgNotFoundError, %("--command or -c" option is required if hostgroup specified.)
|
7
|
+
end
|
8
|
+
|
9
|
+
node = nil
|
10
|
+
scen = Scenario.new
|
11
|
+
node_attributes = { :task => {} }
|
12
|
+
tasks.each { |k, v| node_attributes[:task][k] = v } if tasks
|
13
|
+
scen.node_info = node_info
|
14
|
+
scen.tasks = tasks
|
15
|
+
|
16
|
+
# use scenario file
|
17
|
+
scenario.each do |n|
|
18
|
+
scen.nodes.push(node) if node
|
19
|
+
|
20
|
+
n.deep_symbolize_keys.each do |k, v|
|
21
|
+
if k == :node
|
22
|
+
backend = BackendBuilder.new(@options, v, node_info).build
|
23
|
+
node = Node.new(v, backend)
|
24
|
+
node_attributes[:nodename] = v
|
25
|
+
|
26
|
+
if @options[:command]
|
27
|
+
node.add_operation(build_cli_command_operation(@options[:command], @options))
|
28
|
+
end
|
29
|
+
else
|
30
|
+
if @options[:command] && (k == :command || k == :task)
|
31
|
+
Logger.debug(%("--command or -c" option is specified and ignore scenario file.))
|
32
|
+
next
|
33
|
+
end
|
34
|
+
|
35
|
+
next unless node
|
36
|
+
|
37
|
+
ope = build_operations(k, Array(v), node_attributes, @options)
|
38
|
+
node.add_operation(ope)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
scen.nodes.push(node) if node
|
44
|
+
scen
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_task(tasks, backend, node_attributes)
|
48
|
+
node = Node.new(node_attributes[:nodename], backend)
|
49
|
+
scen = Scenario.new
|
50
|
+
|
51
|
+
tasks.each do |k, v|
|
52
|
+
ope = build_operations(k, Array(v), node_attributes, nil)
|
53
|
+
node.add_operation(ope)
|
54
|
+
end
|
55
|
+
|
56
|
+
scen.nodes.push(node) if node
|
57
|
+
scen
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_cli
|
61
|
+
scen = Scenario.new
|
62
|
+
|
63
|
+
@options[:host].split(',').each do |host|
|
64
|
+
backend = BackendBuilder.new(@options, host, nil).build
|
65
|
+
node = Node.new(host, backend)
|
66
|
+
node.add_operation(build_cli_command_operation(@options[:command], @options))
|
67
|
+
scen.nodes.push(node)
|
68
|
+
end
|
69
|
+
|
70
|
+
scen
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def build_cli_command_operation(command, cli_options)
|
76
|
+
node_attributes = {}
|
77
|
+
node_attributes[:errexit] = !cli_options[:run_anyway]
|
78
|
+
Rundock::OperationFactory.instance(:command).create(Array(command), nil)
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_operations(ope_type, ope_content, node_attributes, cli_options)
|
82
|
+
node_attributes[:errexit] = !cli_options[:run_anyway] if cli_options
|
83
|
+
node_attributes[:errexit] = true if cli_options.nil?
|
84
|
+
Rundock::OperationFactory.instance(ope_type).create(Array(ope_content), node_attributes)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -13,82 +13,45 @@ module Rundock
|
|
13
13
|
|
14
14
|
def build
|
15
15
|
# parse default ssh file
|
16
|
-
|
17
|
-
opts.merge!(@options)
|
16
|
+
@options.merge!(@default_ssh_builder.build)
|
18
17
|
|
19
18
|
# use host specified
|
20
|
-
return
|
19
|
+
return build_scenario_with_cli if @options[:host]
|
21
20
|
|
22
21
|
# use scenario file
|
23
|
-
|
22
|
+
build_scenario_with_file
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
def build_scenario_with_host(options)
|
29
|
-
raise CommandArgNotFoundError, %("--command or -c" option is not specified.) unless options['command']
|
30
|
-
|
31
|
-
scen = Scenario.new
|
32
|
-
|
33
|
-
options['host'].split(',').each do |host|
|
34
|
-
backend = BackendBuilder.new(options, host, nil).build
|
35
|
-
node = Node.new(host, backend)
|
36
|
-
node.add_operation(Rundock::OperationFactory.instance(:command).create(Array(options['command']), nil))
|
37
|
-
scen << node
|
38
|
-
end
|
39
|
-
|
40
|
-
scen
|
25
|
+
def build_task(tasks, backend, node_attributes)
|
26
|
+
OperationBuilder.new(@options).build_task(tasks, backend, node_attributes)
|
41
27
|
end
|
42
28
|
|
43
|
-
|
44
|
-
if options['hostgroup_yaml'] && !options['command']
|
45
|
-
raise CommandArgNotFoundError, %("--command or -c" option is required if hostgroup specified.)
|
46
|
-
end
|
29
|
+
private
|
47
30
|
|
48
|
-
|
49
|
-
|
31
|
+
def build_scenario_with_cli
|
32
|
+
raise CommandArgNotFoundError, %("--command or -c" option is not specified.) unless @options[:command]
|
33
|
+
ope = OperationBuilder.new(@options)
|
34
|
+
ope.build_cli
|
35
|
+
end
|
50
36
|
|
37
|
+
def build_scenario_with_file
|
51
38
|
if @scenario_file
|
52
|
-
YAML.load_documents(@scenario_file).each_with_index do |data, idx|
|
53
|
-
scenario_data[type[idx]] = data
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
node = nil
|
58
|
-
scen = Scenario.new
|
59
|
-
|
60
|
-
# use scenario file
|
61
|
-
scenario_data[:main].each do |n|
|
62
|
-
scen << node if node
|
63
39
|
|
64
|
-
|
65
|
-
|
66
|
-
backend = BackendBuilder.new(options, v, scenario_data[:node_info]).build
|
67
|
-
node = Node.new(v, backend)
|
40
|
+
type = [:main, :node_info, :tasks]
|
41
|
+
scenario_data = {}
|
68
42
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
43
|
+
YAML.load_documents(@scenario_file).each_with_index do |data, idx|
|
44
|
+
if idx == 0
|
45
|
+
scenario_data[type[idx]] = data
|
73
46
|
else
|
74
|
-
|
75
|
-
if options['command'] && (k == 'command' || k == 'task')
|
76
|
-
Logger.debug(%("--command or -c" option is specified and ignore scenario file.))
|
77
|
-
next
|
78
|
-
end
|
79
|
-
|
80
|
-
ope = build_operations(k, v, scenario_data[:tasks], options)
|
81
|
-
node.add_operation(ope) if node
|
47
|
+
scenario_data[type[idx]] = data.deep_symbolize_keys unless data.nil?
|
82
48
|
end
|
83
49
|
end
|
84
50
|
end
|
85
51
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
def build_operations(ope_type, ope_content, tasks, options)
|
91
|
-
Rundock::OperationFactory.instance(ope_type.to_sym).create(Array(ope_content), tasks)
|
52
|
+
ope = OperationBuilder.new(@options)
|
53
|
+
ope.build_first(
|
54
|
+
scenario_data[:main], scenario_data[:node_info], scenario_data[:tasks])
|
92
55
|
end
|
93
56
|
end
|
94
57
|
end
|
data/lib/rundock/cli.rb
CHANGED
@@ -9,12 +9,14 @@ module Rundock
|
|
9
9
|
|
10
10
|
class_option :log_level, type: :string, aliases: ['-l'], default: 'info'
|
11
11
|
class_option :color, type: :boolean, default: true
|
12
|
+
class_option :header, type: :boolean, default: true
|
12
13
|
|
13
14
|
def initialize(args, opts, config)
|
14
15
|
super(args, opts, config)
|
15
16
|
|
16
17
|
Rundock::Logger.level = ::Logger.const_get(options[:log_level].upcase)
|
17
18
|
Rundock::Logger.formatter.colored = options[:color]
|
19
|
+
Rundock::Logger.formatter.show_header = options[:header]
|
18
20
|
end
|
19
21
|
|
20
22
|
desc 'version', 'Print version'
|
@@ -24,30 +26,31 @@ module Rundock
|
|
24
26
|
|
25
27
|
desc 'do [SCENARIO] [options]', 'Run rundock from scenario file'
|
26
28
|
option :sudo, type: :boolean, default: false
|
27
|
-
option :
|
28
|
-
option :
|
29
|
+
option :default_ssh_opts, type: :string, aliases: ['-d'], default: DEFAULT_SSH_OPTIONS_DEFAULT_FILE_PATH
|
30
|
+
option :run_anyway, type: :boolean, default: false
|
29
31
|
def do(*scenario_file_path)
|
30
32
|
scenario_file_path = [DEFAULT_SCENARIO_FILE_PATH] if scenario_file_path.empty?
|
31
|
-
opts = { :
|
33
|
+
opts = { :scenario => scenario_file_path[0] }
|
32
34
|
|
33
|
-
Runner.run(opts.merge(options))
|
35
|
+
Runner.run(opts.merge(options.deep_symbolize_keys))
|
34
36
|
end
|
35
37
|
|
36
38
|
desc 'ssh [options]', 'Run rundock ssh with various options'
|
37
39
|
option :command, type: :string, aliases: ['-c']
|
38
|
-
option :
|
40
|
+
option :default_ssh_opts, type: :string, aliases: ['-d'], default: DEFAULT_SSH_OPTIONS_DEFAULT_FILE_PATH
|
39
41
|
option :host, type: :string, aliases: ['-h'], banner: 'You can specify comma separated hosts.[ex: host1,host2,..]'
|
40
|
-
option :
|
42
|
+
option :hostgroup, type: :string, aliases: ['-g']
|
41
43
|
option :user, type: :string, aliases: ['-u']
|
42
44
|
option :key, type: :string, aliases: ['-i']
|
43
45
|
option :port, type: :numeric, aliases: ['-p']
|
44
46
|
option :ssh_config, type: :string, aliases: ['-F']
|
45
47
|
option :ask_password, type: :boolean, default: false
|
46
48
|
option :sudo, type: :boolean, default: false
|
49
|
+
option :run_anyway, type: :boolean, default: false
|
47
50
|
def ssh
|
48
51
|
opts = {}
|
49
52
|
|
50
|
-
Runner.run(opts.merge(options))
|
53
|
+
Runner.run(opts.merge(options.deep_symbolize_keys))
|
51
54
|
end
|
52
55
|
end
|
53
56
|
end
|
data/lib/rundock/logger.rb
CHANGED
@@ -8,6 +8,7 @@ module Rundock
|
|
8
8
|
attr_accessor :colored
|
9
9
|
attr_accessor :indent_depth
|
10
10
|
attr_accessor :color
|
11
|
+
attr_accessor :show_header
|
11
12
|
|
12
13
|
def initialize(*args)
|
13
14
|
super
|
@@ -15,7 +16,12 @@ module Rundock
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def call(severity, datetime, progname, msg)
|
18
|
-
|
19
|
+
if @show_header
|
20
|
+
out = "[\%5s:] %s%s\n" % [severity, ' ' * 2 * indent_depth, msg2str(msg)]
|
21
|
+
else
|
22
|
+
out = "%s\n" % [msg2str(msg)]
|
23
|
+
end
|
24
|
+
|
19
25
|
if colored
|
20
26
|
colorize(out, severity)
|
21
27
|
else
|
data/lib/rundock/node.rb
CHANGED
@@ -18,6 +18,10 @@ module Rundock
|
|
18
18
|
|
19
19
|
def run
|
20
20
|
Logger.debug("run name: #{@name}")
|
21
|
+
if @operations.blank?
|
22
|
+
Logger.warn("no operation running: #{@name}")
|
23
|
+
return
|
24
|
+
end
|
21
25
|
@operations.each do |ope|
|
22
26
|
Logger.debug("operation type: #{ope.class}")
|
23
27
|
ope.run(@backend, ope.attributes)
|
@@ -3,12 +3,15 @@ module Rundock
|
|
3
3
|
class Task < Base
|
4
4
|
def run(backend, attributes = {})
|
5
5
|
@instruction.each do |i|
|
6
|
-
unless attributes.key?(i)
|
7
|
-
Logger.warn("
|
6
|
+
unless attributes[:task].key?(i.to_sym)
|
7
|
+
Logger.warn("task not found and ignored: #{i}")
|
8
8
|
next
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
scenario = Rundock::Builder::ScenarioBuilder.new(nil, nil).build_task(
|
12
|
+
attributes[:task][i.to_sym], backend, attributes)
|
13
|
+
|
14
|
+
scenario.run
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
data/lib/rundock/runner.rb
CHANGED
@@ -7,7 +7,7 @@ module Rundock
|
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def run(options)
|
10
|
-
Logger.
|
10
|
+
Logger.debug 'Starting Rundoc:'
|
11
11
|
|
12
12
|
runner = self.new(options)
|
13
13
|
runner.build(options)
|
@@ -25,24 +25,28 @@ module Rundock
|
|
25
25
|
@scenario.run
|
26
26
|
end
|
27
27
|
|
28
|
+
def run_tasks
|
29
|
+
@scenario.run
|
30
|
+
end
|
31
|
+
|
28
32
|
def build(options)
|
29
|
-
if options[
|
30
|
-
if options[
|
31
|
-
raise ScenarioNotFoundError, "'#{options[
|
32
|
-
elsif options[
|
33
|
-
raise ScenarioNotFoundError, "'#{options[
|
33
|
+
if options[:scenario] || options[:hostgroup]
|
34
|
+
if options[:scenario] && !FileTest.exist?(options[:scenario])
|
35
|
+
raise ScenarioNotFoundError, "'#{options[:scenario]}' scenario file is not found."
|
36
|
+
elsif options[:hostgroup] && !FileTest.exist?(options[:hostgroup])
|
37
|
+
raise ScenarioNotFoundError, "'#{options[:hostgroup]}' hostgroup file is not found."
|
34
38
|
end
|
35
39
|
|
36
|
-
options[
|
40
|
+
options[:scenario] = options[:hostgroup] if options[:hostgroup]
|
37
41
|
|
38
42
|
# parse scenario
|
39
|
-
if options[
|
43
|
+
if options[:scenario] =~ %r{^(http|https)://}
|
40
44
|
# read from http/https
|
41
|
-
open(options[
|
45
|
+
open(options[:scenario]) do |f|
|
42
46
|
@scenario = Rundock::Builder::ScenarioBuilder.new(options, f).build
|
43
47
|
end
|
44
48
|
else
|
45
|
-
File.open(options[
|
49
|
+
File.open(options[:scenario]) do |f|
|
46
50
|
@scenario = Rundock::Builder::ScenarioBuilder.new(options, f).build
|
47
51
|
end
|
48
52
|
end
|
data/lib/rundock/scenario.rb
CHANGED
data/lib/rundock/version.rb
CHANGED
data/lib/rundock.rb
CHANGED
@@ -12,6 +12,7 @@ require 'rundock/backend'
|
|
12
12
|
require 'rundock/builder/base'
|
13
13
|
require 'rundock/builder/default_ssh_builder'
|
14
14
|
require 'rundock/builder/backend_builder'
|
15
|
+
require 'rundock/builder/operation_builder'
|
15
16
|
require 'rundock/builder/scenario_builder'
|
16
17
|
require 'rundock/runner'
|
17
18
|
require 'rundock/cli'
|
data/rundock.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['hiracy']
|
10
10
|
spec.email = ['leizhen@mbr.nifty.com']
|
11
11
|
|
12
|
-
spec.summary = 'Simple
|
12
|
+
spec.summary = 'Simple and extensible server operation framework'
|
13
13
|
spec.homepage = 'https://github.com/hiracy/rundock'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
data/scenario_sample.yml
CHANGED
@@ -38,16 +38,26 @@
|
|
38
38
|
task:
|
39
39
|
- echo_platform
|
40
40
|
- echo_users
|
41
|
+
command:
|
42
|
+
- errexit: true
|
43
|
+
- "rm /tmp/riskyfile"
|
44
|
+
- errexit: false
|
45
|
+
- "rm /tmp/safetyfile"
|
46
|
+
- "ls -1 /tmp"
|
41
47
|
---
|
42
|
-
anyhost-01:
|
48
|
+
- anyhost-01:
|
43
49
|
host: 192.168.1.11
|
44
50
|
ssh_opts:
|
45
51
|
port: 22
|
46
52
|
user: anyuser
|
53
|
+
- anyhost-02:
|
54
|
+
host: 192.168.1.12
|
47
55
|
---
|
48
56
|
echo_platform:
|
49
|
-
|
50
|
-
|
57
|
+
command:
|
58
|
+
- "hostname"
|
59
|
+
- "uname -a"
|
51
60
|
echo_users:
|
52
|
-
|
53
|
-
|
61
|
+
command:
|
62
|
+
- "whoami"
|
63
|
+
- "w"
|
@@ -6,6 +6,7 @@ PROJECT_NAME=rundock_spec
|
|
6
6
|
PLATFORM_NAME=centos6
|
7
7
|
PLATFORM_DIR="${PROJECT_ROOT}/platforms/${PLATFORM_NAME}"
|
8
8
|
DOCKER_IMAGE_NAME="${PROJECT_NAME}/${PLATFORM_NAME}"
|
9
|
+
DOCKER_ADDRESS="172.17.42.1"
|
9
10
|
DOCKER_CACHE_DIR="${HOME}/docker"
|
10
11
|
DOCKER_CACHE_IMAGE_PATH="${DOCKER_CACHE_DIR}/${PLATFORM_NAME}.tar"
|
11
12
|
DOCKER_SSH_PORT=22222
|
@@ -15,12 +16,17 @@ DOCKER_SSH_KEY_PUBLIC_LOCAL="${HOME}/.ssh/id_rsa_${PROJECT_NAME}_${PLATFORM_NAME
|
|
15
16
|
DOCKER_SSH_KEY_PUBLIC_REMOTE="${PLATFORM_DIR}/authorized_keys"
|
16
17
|
DOCKER_SSH_CONFIG="${HOME}/.ssh/config_${PROJECT_NAME}_${PLATFORM_NAME}"
|
17
18
|
RUNDOCK_SCENARIO_DIR="${PROJECT_ROOT}/scenarios"
|
19
|
+
RUNDOCK_GROUP_DIR="${PROJECT_ROOT}/groups"
|
18
20
|
RUNDOCK_CACHE_DIR="${HOME}/.rundock/${PLATFORM_NAME}"
|
19
21
|
RUNDOCK_DEFAULT_SSH_YML="${RUNDOCK_CACHE_DIR}/integration_default_ssh.yml"
|
20
22
|
RUNDOCK_SCENARIO_CACHE_DIR="${RUNDOCK_CACHE_DIR}/scenarios"
|
23
|
+
RUNDOCK_GROUP_CACHE_DIR="${RUNDOCK_CACHE_DIR}/groups"
|
21
24
|
|
22
25
|
if [ "${1}x" = "--cleanx" ];then
|
23
26
|
if sudo docker ps | grep "${DOCKER_IMAGE_NAME}" > /dev/null; then
|
27
|
+
rm -f "/var/tmp/hello_rundock*"
|
28
|
+
rm -f "${RUNDOCK_SCENARIO_CACHE_DIR}/*.yml"
|
29
|
+
rm -f "${RUNDOCK_GROUP_CACHE_DIR}/*.yml"
|
24
30
|
rm -f "${DOCKER_CACHE_IMAGE_PATH}"
|
25
31
|
rm -f "${DOCKER_SSH_KEY_PRIVATE}"
|
26
32
|
rm -f "${DOCKER_SSH_KEY_PUBLIC_LOCAL}"
|
@@ -34,6 +40,7 @@ if [ "${1}x" = "--cleanx" ];then
|
|
34
40
|
fi
|
35
41
|
|
36
42
|
mkdir -p "${RUNDOCK_SCENARIO_CACHE_DIR}"
|
43
|
+
mkdir -p "${RUNDOCK_GROUP_CACHE_DIR}"
|
37
44
|
|
38
45
|
if [ ! -f ${RUNDOCK_DEFAULT_SSH_YML} ]; then
|
39
46
|
(
|
@@ -47,8 +54,11 @@ EOP
|
|
47
54
|
fi
|
48
55
|
|
49
56
|
cp ${RUNDOCK_SCENARIO_DIR}/* ${RUNDOCK_SCENARIO_CACHE_DIR}
|
57
|
+
cp ${RUNDOCK_GROUP_DIR}/* ${RUNDOCK_GROUP_CACHE_DIR}
|
50
58
|
|
51
|
-
find ${RUNDOCK_SCENARIO_CACHE_DIR} -type f -name "*_scenario.yml"
|
59
|
+
find ${RUNDOCK_SCENARIO_CACHE_DIR} -type f -name "*_scenario.yml" | \
|
60
|
+
xargs sed -i -e "s#<replaced_by_platforms>#${DOCKER_SSH_KEY_PRIVATE}#g"
|
61
|
+
find ${RUNDOCK_GROUP_CACHE_DIR} -type f -name "*_group.yml" | \
|
52
62
|
xargs sed -i -e "s#<replaced_by_platforms>#${DOCKER_SSH_KEY_PRIVATE}#g"
|
53
63
|
|
54
64
|
sudo docker ps | grep "${DOCKER_IMAGE_NAME}" && { echo "docker image is already standing."; exit 0; }
|
@@ -68,10 +78,10 @@ sudo docker build -t "${DOCKER_IMAGE_NAME}" ${PLATFORM_DIR}
|
|
68
78
|
rm -f ${DOCKER_SSH_KEY_PUBLIC_REMOTE}
|
69
79
|
mkdir -p ${DOCKER_CACHE_DIR}
|
70
80
|
sudo docker save "${DOCKER_IMAGE_NAME}" > ${DOCKER_CACHE_IMAGE_PATH}
|
71
|
-
sudo docker run -d --privileged -p ${DOCKER_SSH_PORT}:22 "${DOCKER_IMAGE_NAME}"
|
81
|
+
sudo docker run -d --privileged -p ${DOCKER_ADDRESS}:${DOCKER_SSH_PORT}:22 "${DOCKER_IMAGE_NAME}"
|
72
82
|
|
73
83
|
echo "Host ${PLATFORM_NAME}" > $DOCKER_SSH_CONFIG
|
74
|
-
echo " HostName
|
84
|
+
echo " HostName ${DOCKER_ADDRESS}" >> $DOCKER_SSH_CONFIG
|
75
85
|
echo " User ${DOCKER_SSH_USER}" >> $DOCKER_SSH_CONFIG
|
76
86
|
echo " Port ${DOCKER_SSH_PORT}" >> $DOCKER_SSH_CONFIG
|
77
87
|
echo " IdentityFile ${DOCKER_SSH_KEY_PRIVATE}" >> $DOCKER_SSH_CONFIG
|
@@ -14,20 +14,22 @@
|
|
14
14
|
- write_echo
|
15
15
|
---
|
16
16
|
anyhost-01:
|
17
|
-
host:
|
17
|
+
host: 172.17.42.1
|
18
18
|
ssh_opts:
|
19
19
|
port: 22222
|
20
20
|
user: tester
|
21
21
|
key: "<replaced_by_platforms>"
|
22
22
|
anyhost-02:
|
23
|
-
host: "
|
23
|
+
host: "172.17.42.1"
|
24
24
|
ssh_opts:
|
25
25
|
port: 22222
|
26
26
|
user: tester
|
27
27
|
keys: ["<replaced_by_platforms>"]
|
28
28
|
---
|
29
29
|
echo_platform:
|
30
|
-
|
31
|
-
|
30
|
+
command:
|
31
|
+
- "hostname"
|
32
|
+
- "uname -a"
|
32
33
|
write_echo:
|
33
|
-
|
34
|
+
command:
|
35
|
+
- "echo 'Hello Rundock from Scenario.' > /var/tmp/hello_rundock_from_scenario"
|
@@ -9,6 +9,7 @@ if ENV['TARGET_HOST'] != 'localhost'
|
|
9
9
|
options = Net::SSH::Config.for(host, ["#{ENV['HOME']}/.ssh/config_rundock_spec_#{ENV['TARGET_HOST']}"])
|
10
10
|
|
11
11
|
options[:user] ||= Etc.getlogin
|
12
|
+
options[:paranoid] = false
|
12
13
|
|
13
14
|
set :host, options[:host_name] || host
|
14
15
|
set :ssh_options, options
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rundock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hiracy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- lib/rundock/builder/backend_builder.rb
|
156
156
|
- lib/rundock/builder/base.rb
|
157
157
|
- lib/rundock/builder/default_ssh_builder.rb
|
158
|
+
- lib/rundock/builder/operation_builder.rb
|
158
159
|
- lib/rundock/builder/scenario_builder.rb
|
159
160
|
- lib/rundock/cli.rb
|
160
161
|
- lib/rundock/ext/hash.rb
|
@@ -170,14 +171,15 @@ files:
|
|
170
171
|
- lib/rundock/version.rb
|
171
172
|
- rundock.gemspec
|
172
173
|
- scenario_sample.yml
|
174
|
+
- spec/integration/groups/simple_host_group.yml
|
173
175
|
- spec/integration/platforms/centos6/Dockerfile
|
174
176
|
- spec/integration/platforms/centos6/setup.sh
|
177
|
+
- spec/integration/platforms/localhost/scenarios/run_anyway_scenario.yml
|
175
178
|
- spec/integration/platforms/localhost/scenarios/simple_echo_scenario.yml
|
176
179
|
- spec/integration/platforms/localhost/scenarios/use_default_ssh_scenario.yml
|
177
180
|
- spec/integration/recipes/simple_echo_scenario_spec.rb
|
178
181
|
- spec/integration/recipes/simple_echo_spec.rb
|
179
182
|
- spec/integration/scenarios/simple_echo_scenario.yml
|
180
|
-
- spec/integration/scenarios/simple_host_group.yml
|
181
183
|
- spec/integration/scenarios/use_default_ssh_scenario.yml
|
182
184
|
- spec/integration/spec_helper.rb
|
183
185
|
homepage: https://github.com/hiracy/rundock
|
@@ -203,5 +205,5 @@ rubyforge_project:
|
|
203
205
|
rubygems_version: 2.4.5
|
204
206
|
signing_key:
|
205
207
|
specification_version: 4
|
206
|
-
summary: Simple
|
208
|
+
summary: Simple and extensible server operation framework
|
207
209
|
test_files: []
|