rundock 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +39 -0
- data/.rspec +2 -0
- data/.rubocop.yml +49 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +74 -0
- data/Rakefile +137 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/circle.yml +11 -0
- data/default_ssh.yml +8 -0
- data/exe/rundock +4 -0
- data/lib/rundock/backend.rb +130 -0
- data/lib/rundock/cli.rb +50 -0
- data/lib/rundock/ext/hash.rb +23 -0
- data/lib/rundock/ext/object/blank.rb +45 -0
- data/lib/rundock/logger.rb +106 -0
- data/lib/rundock/node.rb +27 -0
- data/lib/rundock/operation/base.rb +20 -0
- data/lib/rundock/operation/command.rb +11 -0
- data/lib/rundock/operation/task.rb +16 -0
- data/lib/rundock/operation_factory.rb +30 -0
- data/lib/rundock/runner.rb +182 -0
- data/lib/rundock/scenario.rb +7 -0
- data/lib/rundock/version.rb +3 -0
- data/lib/rundock.rb +17 -0
- data/rundock.gemspec +30 -0
- data/scenario_sample.yml +53 -0
- data/spec/integration/platforms/centos6/Dockerfile +16 -0
- data/spec/integration/platforms/centos6/setup.sh +78 -0
- data/spec/integration/platforms/localhost/scenarios/simple_echo_scenario.yml +9 -0
- data/spec/integration/platforms/localhost/scenarios/use_default_ssh_scenario.yml +4 -0
- data/spec/integration/recipes/simple_echo_scenario_spec.rb +6 -0
- data/spec/integration/recipes/simple_echo_spec.rb +6 -0
- data/spec/integration/scenarios/simple_echo_scenario.yml +33 -0
- data/spec/integration/scenarios/use_default_ssh_scenario.yml +4 -0
- data/spec/integration/spec_helper.rb +19 -0
- metadata +202 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9bae0415498290a96be0d1867e1b8390995a818c
|
4
|
+
data.tar.gz: 72ecb870b1108accdd2c9ea8c38dd5291843379c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cf8bde9f38284afd6b37c109dd58cdf22258d7bd2bc178ae4c4dae7e1ccb13329453228e85f1068548ce30a5a2440bb38cffd051b9f6edfefad78cfee1f45bbc
|
7
|
+
data.tar.gz: ae60ee17c14eff7a50b2bd0f0557d4e484c4f9d1d67c6076b8d78f6f7471945359fd3d4ca3f551e805fac9b4b1829dda9055c3fae6a3112e836d4df3b0b03aac
|
data/.gitignore
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
Gemfile.lock
|
12
|
+
.vagrant
|
13
|
+
Gemfile.local
|
14
|
+
authorized_keys
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
|
21
|
+
## Documentation cache and generated files:
|
22
|
+
/.yardoc/
|
23
|
+
/_yardoc/
|
24
|
+
/doc/
|
25
|
+
/rdoc/
|
26
|
+
|
27
|
+
## Environment normalisation:
|
28
|
+
/.bundle/
|
29
|
+
/vendor/bundle
|
30
|
+
/lib/bundler/man/
|
31
|
+
|
32
|
+
# for a library or gem, you might want to ignore these files since the code is
|
33
|
+
# intended to run in multiple environments; otherwise, check them in:
|
34
|
+
# Gemfile.lock
|
35
|
+
# .ruby-version
|
36
|
+
# .ruby-gemset
|
37
|
+
|
38
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
39
|
+
.rvmrc
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# see https://github.com/bbatsov/ruby-style-guide#percent-q-shorthand
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
Exclude:
|
5
|
+
- "vendor/**/*" # rubocop config/default.yml
|
6
|
+
- "db/schema.rb"
|
7
|
+
DisplayCopNames: true
|
8
|
+
|
9
|
+
Metrics/LineLength:
|
10
|
+
Max: 500
|
11
|
+
|
12
|
+
Metrics/ClassLength:
|
13
|
+
CountComments: false # count full line comments?
|
14
|
+
Max: 320
|
15
|
+
|
16
|
+
Metrics/MethodLength:
|
17
|
+
CountComments: false # count full line comments?
|
18
|
+
Max: 50
|
19
|
+
|
20
|
+
Metrics/AbcSize:
|
21
|
+
Enabled: true
|
22
|
+
Max: 50
|
23
|
+
|
24
|
+
Metrics/CyclomaticComplexity:
|
25
|
+
Max: 20
|
26
|
+
|
27
|
+
Metrics/PerceivedComplexity:
|
28
|
+
Max: 20
|
29
|
+
|
30
|
+
Style/Documentation:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/SpecialGlobalVars:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/RedundantSelf:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Style/SignalException:
|
40
|
+
EnforcedStyle: only_raise
|
41
|
+
|
42
|
+
Style/HashSyntax:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/FormatString:
|
46
|
+
EnforcedStyle: percent
|
47
|
+
|
48
|
+
Lint/UnusedMethodArgument:
|
49
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 hiracy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Rundock [![Gem Version](https://badge.fury.io/rb/rundock.svg)](http://badge.fury.io/rb/rundock) [![Circle CI](https://circleci.com/gh/hiracy/rundock.png?style=shield&circle-token=0d8a3836c5e285b7ecb6d076f2d51c5deca52d8b)](https://circleci.com/gh/hiracy/rundock)
|
2
|
+
|
3
|
+
Simple and extensible server operation framework based on [specinfra](https://github.com/serverspec/specinfra).
|
4
|
+
|
5
|
+
- [CHANGELOG](https://github.com/hiracy/rundock/blob/master/CHANGELOG.md)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```
|
10
|
+
$ gem install rundock
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Edit your operation scenario to "[scenario.yml](https://github.com/hiracy/rundock/blob/master/scenario_sample.yml)" like this sample.
|
16
|
+
|
17
|
+
```
|
18
|
+
# scenario section
|
19
|
+
- node: 192.168.1.11
|
20
|
+
command:
|
21
|
+
- "sudo hostname new-host-01"
|
22
|
+
- "sudo sed -i -e 's/HOSTNAME=old-host-01/HOSTNAME=new-host-01/g' /etc/sysconfig/network"
|
23
|
+
- node: host-alias-01
|
24
|
+
command:
|
25
|
+
- "sudo yum -y install ruby"
|
26
|
+
task:
|
27
|
+
- update_gem
|
28
|
+
- install_bundler
|
29
|
+
---
|
30
|
+
# host information section
|
31
|
+
host-alias-01:
|
32
|
+
host: 192.168.1.12
|
33
|
+
ssh_opts:
|
34
|
+
port: 2222
|
35
|
+
user: anyuser
|
36
|
+
keys: ["~/.ssh/id_rsa_anyuser"]
|
37
|
+
---
|
38
|
+
# task information section
|
39
|
+
update_gem:
|
40
|
+
- "sudo gem update --system"
|
41
|
+
- "sudo gem update"
|
42
|
+
install_bundler:
|
43
|
+
- "sudo gem install bundler --no-ri --no-rdoc"
|
44
|
+
```
|
45
|
+
|
46
|
+
and do rundock.
|
47
|
+
|
48
|
+
$ rundock do -s /path/to/your-dir/scenario.yml
|
49
|
+
|
50
|
+
You can also specify [ssh_options.yml](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html)(Net::SSH options) file contents that you specified "-d" option to the default ssh options.
|
51
|
+
|
52
|
+
$ rundock do -s /path/to/your-dir/scenario.yml -d /path/to/your-dir/ssh_options.yml
|
53
|
+
|
54
|
+
For more detail. You can see from `rundock -h` command.
|
55
|
+
|
56
|
+
## Documentations
|
57
|
+
|
58
|
+
Now on editing...
|
59
|
+
|
60
|
+
## Run tests
|
61
|
+
|
62
|
+
Requirements: Docker environments
|
63
|
+
|
64
|
+
```
|
65
|
+
$ bundle exec rake spec
|
66
|
+
```
|
67
|
+
|
68
|
+
## Contributing
|
69
|
+
|
70
|
+
1. Fork it ( https://github.com/[my-github-username]/rundock/fork )
|
71
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
72
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
73
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
74
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
run_commands = [
|
5
|
+
'rm -f /var/tmp/hello_rundock;' \
|
6
|
+
'echo \'Hello Rundock.\' > /var/tmp/hello_rundock'
|
7
|
+
]
|
8
|
+
|
9
|
+
run_scenarios = %w(
|
10
|
+
use_default_ssh_scenario
|
11
|
+
simple_echo_scenario
|
12
|
+
)
|
13
|
+
|
14
|
+
def execute(command)
|
15
|
+
puts "[EXECUTE:] #{command}"
|
16
|
+
system command
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup_docker(platform, timeout, interval)
|
20
|
+
Bundler.with_clean_env do
|
21
|
+
execute "./spec/integration/platforms/#{platform}/setup.sh &"
|
22
|
+
found = false
|
23
|
+
(timeout / interval).times do
|
24
|
+
execute 'sudo docker ps | grep rundock'
|
25
|
+
if $?.to_i == 0
|
26
|
+
found = true
|
27
|
+
break
|
28
|
+
end
|
29
|
+
sleep interval
|
30
|
+
end
|
31
|
+
raise 'Docker Error.' unless found
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def do_rundock_ssh(commands, platform)
|
36
|
+
if platform == 'localhost'
|
37
|
+
commands.each do |cmd|
|
38
|
+
execute "bundle exec exe/rundock ssh -c \"#{cmd}\" -h localhost -l debug"
|
39
|
+
end
|
40
|
+
else
|
41
|
+
commands.each do |cmd|
|
42
|
+
execute 'bundle exec exe/rundock' \
|
43
|
+
" ssh -c \"#{cmd}\" -h 127.0.0.1 -p 22222 -u tester" \
|
44
|
+
" -i #{ENV['HOME']}/.ssh/id_rsa_rundock_spec_#{platform}_tmp -l debug"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def do_rundock_scenarios(scenarios, platform)
|
50
|
+
if platform == 'localhost'
|
51
|
+
base_dir = './spec/integration/platforms/localhost'
|
52
|
+
else
|
53
|
+
base_dir = "#{ENV['HOME']}/.rundock/#{platform}"
|
54
|
+
end
|
55
|
+
|
56
|
+
scenarios.each do |scenario|
|
57
|
+
default_ssh_opt = ''
|
58
|
+
if scenario =~ /use_default_ssh/ && platform != 'localhost'
|
59
|
+
default_ssh_opt = " -d #{base_dir}/integration_default_ssh.yml"
|
60
|
+
end
|
61
|
+
|
62
|
+
execute 'bundle exec exe/rundock' \
|
63
|
+
" do -s #{base_dir}/scenarios/#{scenario}.yml#{default_ssh_opt} -l debug"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Cleaning environments'
|
68
|
+
|
69
|
+
task :clean do
|
70
|
+
Bundler.with_clean_env do
|
71
|
+
Dir.glob('./spec/integration/platforms/*').each do |platform|
|
72
|
+
execute "#{platform}/setup.sh --clean"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'execute rubocop'
|
78
|
+
task :rubocop do
|
79
|
+
Bundler.with_clean_env do
|
80
|
+
execute 'rubocop'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'Run all tests.'
|
85
|
+
task :spec => ['rubocop', 'spec:integration:all']
|
86
|
+
|
87
|
+
namespace :spec do
|
88
|
+
desc 'Run all tests for localhost.'
|
89
|
+
task :local => 'integration:localhost:all'
|
90
|
+
|
91
|
+
namespace :integration do
|
92
|
+
targets = ['localhost']
|
93
|
+
Dir.glob('./spec/integration/platforms/*').each do |result|
|
94
|
+
targets << File.basename(result)
|
95
|
+
end
|
96
|
+
|
97
|
+
desc 'Run all tests for all platforms.'
|
98
|
+
task :all => targets.map { |t| "spec:integration:#{t}:all" }
|
99
|
+
|
100
|
+
targets.each do |target|
|
101
|
+
namespace target.to_sym do
|
102
|
+
desc "Run rundock and serverspec tests for #{target}"
|
103
|
+
|
104
|
+
if target != 'localhost'
|
105
|
+
task :all => [:docker, :rundock, :serverspec]
|
106
|
+
else
|
107
|
+
task :all => [:rundock, :serverspec]
|
108
|
+
end
|
109
|
+
|
110
|
+
unless target == 'localhost'
|
111
|
+
desc "Setup Docker for #{target}"
|
112
|
+
task :docker do
|
113
|
+
# timeout 3 minutes and wait interval 10 seconds
|
114
|
+
setup_docker(target, 180, 10)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
desc "Run rundock for #{target}"
|
119
|
+
|
120
|
+
task :rundock do
|
121
|
+
Bundler.with_clean_env do
|
122
|
+
do_rundock_ssh(run_commands, target)
|
123
|
+
do_rundock_scenarios(run_scenarios, target)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
desc "Run serverspec tests for #{target}"
|
128
|
+
|
129
|
+
RSpec::Core::RakeTask.new(:serverspec) do |t|
|
130
|
+
ENV['TARGET_HOST'] = target
|
131
|
+
t.ruby_opts = '-I ./spec/integration'
|
132
|
+
t.pattern = './spec/integration/recipes/*_spec.rb'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rundock'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/circle.yml
ADDED
data/default_ssh.yml
ADDED
data/exe/rundock
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'rundock'
|
2
|
+
require 'singleton'
|
3
|
+
require 'specinfra/core'
|
4
|
+
require 'io/console'
|
5
|
+
require 'net/ssh'
|
6
|
+
|
7
|
+
Specinfra::Configuration.error_on_missing_backend_type = true
|
8
|
+
|
9
|
+
module Rundock
|
10
|
+
module Backend
|
11
|
+
CommandResultStatusError = Class.new(StandardError)
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def create(type, options = {})
|
15
|
+
self.const_get(type.capitalize).new(options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Base
|
20
|
+
attr_reader :options
|
21
|
+
attr_reader :backend
|
22
|
+
|
23
|
+
def initialize(options)
|
24
|
+
@options = parse(options)
|
25
|
+
@backend = create_specinfra_backend
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_commands(cmd, options = {})
|
29
|
+
Array(cmd).each do |c|
|
30
|
+
run_command(c)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def run_command(cmd, options = {})
|
37
|
+
command = cmd.strip
|
38
|
+
command = "cd #{Shellwords.escape(options[:cwd])} && #{command}" if options[:cwd]
|
39
|
+
command = "sudo -H -u #{Shellwords.escape(user)} -- /bin/sh -c #{command}" if options[:user]
|
40
|
+
|
41
|
+
Logger.debug(%(Start executing: "#{command}"))
|
42
|
+
|
43
|
+
result = @backend.run_command(command)
|
44
|
+
exit_status = result.exit_status
|
45
|
+
|
46
|
+
Logger.formatter.indent do
|
47
|
+
Logger.error("#{result.stderr}") unless result.stderr.blank?
|
48
|
+
Logger.info("#{result.stdout.strip}") unless result.stdout.strip.blank?
|
49
|
+
Logger.debug("exit status: #{exit_status}")
|
50
|
+
end
|
51
|
+
|
52
|
+
if options[:no_continue_if_error] && exit_status != 0
|
53
|
+
raise CommandResultStatucError
|
54
|
+
end
|
55
|
+
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse(options)
|
60
|
+
raise NotImplementedError
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_specinfra_backend
|
64
|
+
raise NotImplementedError
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Local < Base
|
69
|
+
private
|
70
|
+
|
71
|
+
def parse(options)
|
72
|
+
options
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_specinfra_backend
|
76
|
+
Specinfra::Backend::Exec.new
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Ssh < Base
|
81
|
+
private
|
82
|
+
|
83
|
+
def parse(options)
|
84
|
+
if options['ssh_config'] && FileTest.exists?(options['ssh_config'])
|
85
|
+
ssh_opts = Net::SSH::Config.for(options['host'], [options['ssh_config']])
|
86
|
+
else
|
87
|
+
ssh_opts = Net::SSH::Config.for(options['host'])
|
88
|
+
end
|
89
|
+
|
90
|
+
ssh_opts[:host_name] = options['host']
|
91
|
+
ssh_opts[:user] = options['user']
|
92
|
+
ssh_opts[:keys] = options['keys']
|
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
|
+
|
97
|
+
ssh_opts.merge!(filter_net_ssh_options(options))
|
98
|
+
|
99
|
+
Logger.debug(%(Net::SSH Options: "#{ssh_opts}"))
|
100
|
+
|
101
|
+
ssh_opts
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_password_from_stdin
|
105
|
+
print 'password: '
|
106
|
+
passwd = STDIN.noecho(&:gets).strip
|
107
|
+
print "\n"
|
108
|
+
passwd
|
109
|
+
end
|
110
|
+
|
111
|
+
def filter_net_ssh_options(options)
|
112
|
+
opts = {}
|
113
|
+
options.each do |k, v|
|
114
|
+
opts[k.to_sym] = v if Net::SSH::VALID_OPTIONS.include?(k.to_sym)
|
115
|
+
end
|
116
|
+
|
117
|
+
opts
|
118
|
+
end
|
119
|
+
|
120
|
+
def create_specinfra_backend
|
121
|
+
Specinfra::Backend::Ssh.new(
|
122
|
+
request_pty: true,
|
123
|
+
host: @options[:host_name],
|
124
|
+
disable_sudo: !@options[:sudo],
|
125
|
+
ssh_options: @options
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/rundock/cli.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rundock'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Rundock
|
5
|
+
class CLI < Thor
|
6
|
+
DEFAULT_SCENARIO_FILE_PATH = './scenario.yml'
|
7
|
+
DEFAULT_SSH_OPTIONS_DEFAULT_FILE_PATH = './default_ssh.yml'
|
8
|
+
|
9
|
+
class_option :log_level, type: :string, aliases: ['-l'], default: 'info'
|
10
|
+
class_option :color, type: :boolean, default: true
|
11
|
+
|
12
|
+
def initialize(args, opts, config)
|
13
|
+
super(args, opts, config)
|
14
|
+
|
15
|
+
Rundock::Logger.level = ::Logger.const_get(options[:log_level].upcase)
|
16
|
+
Rundock::Logger.formatter.colored = options[:color]
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'version', 'Print version'
|
20
|
+
def version
|
21
|
+
puts "#{Rundock::VERSION}"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'do [SCENARIO] [options]', 'Run rundock from scenario file'
|
25
|
+
option :sudo, type: :boolean, default: false
|
26
|
+
option :scenario_yaml, type: :string, aliases: ['-s'], default: DEFAULT_SCENARIO_FILE_PATH
|
27
|
+
option :default_ssh_opts_yaml, type: :string, aliases: ['-d'], default: DEFAULT_SSH_OPTIONS_DEFAULT_FILE_PATH
|
28
|
+
def do(*scenario_file_path)
|
29
|
+
scenario_file_path = [DEFAULT_SCENARIO_FILE_PATH] if scenario_file_path.empty?
|
30
|
+
opts = { :scenario_yaml => scenario_file_path[0] }
|
31
|
+
|
32
|
+
Runner.run(opts.merge(options))
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'ssh [options]', 'Run rundock ssh with various options'
|
36
|
+
option :command, type: :string, aliases: ['-c'], banner: "NOTICE: Scenario's task is ignored."
|
37
|
+
option :default_ssh_opts_yaml, type: :string, aliases: ['-d'], default: DEFAULT_SSH_OPTIONS_DEFAULT_FILE_PATH
|
38
|
+
option :host, type: :string, aliases: ['-h']
|
39
|
+
option :user, type: :string, aliases: ['-u']
|
40
|
+
option :key, type: :string, aliases: ['-i']
|
41
|
+
option :port, type: :numeric, aliases: ['-p']
|
42
|
+
option :ssh_config, type: :string, aliases: ['-F']
|
43
|
+
option :ask_password, type: :boolean, default: false
|
44
|
+
option :sudo, type: :boolean, default: false
|
45
|
+
def ssh
|
46
|
+
opts = {}
|
47
|
+
Runner.run(opts.merge(options))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Hash
|
2
|
+
def depth
|
3
|
+
1 + (values.map { |v| v.is_a?(Hash) ? v.depth : 1 }.max)
|
4
|
+
end
|
5
|
+
|
6
|
+
def deep_symbolize_keys
|
7
|
+
self.each_with_object({}) do |(k, v), h|
|
8
|
+
if v.is_a?(Array)
|
9
|
+
v = v.map do |vv|
|
10
|
+
if vv.is_a?(Hash)
|
11
|
+
vv.deep_symbolize_keys
|
12
|
+
else
|
13
|
+
vv
|
14
|
+
end
|
15
|
+
end
|
16
|
+
elsif v.is_a?(Hash)
|
17
|
+
v = v.deep_symbolize_keys
|
18
|
+
end
|
19
|
+
|
20
|
+
h[k.to_s.to_sym] = v
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Object
|
2
|
+
def blank?
|
3
|
+
respond_to?(:empty?) ? empty? : !self
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class NilClass
|
8
|
+
def blank?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class FalseClass
|
14
|
+
def blank?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TrueClass
|
20
|
+
def blank?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Array
|
26
|
+
alias_method :blank?, :empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
class Hash
|
30
|
+
alias_method :blank?, :empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
class String
|
34
|
+
BLANK_RE = /\A[[:space:]]*\z/
|
35
|
+
|
36
|
+
def blank?
|
37
|
+
self =~ BLANK_RE
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Numeric
|
42
|
+
def blank?
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|