dopi 0.17.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 +20 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +322 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +102 -0
- data/LICENSE.txt +177 -0
- data/README.md +309 -0
- data/Rakefile +44 -0
- data/Vagrantfile +64 -0
- data/bin/dopi +4 -0
- data/doc/getting_started.md +247 -0
- data/doc/getting_started_examples/001_hello_world.yaml +17 -0
- data/doc/getting_started_examples/002_connecting_over_ssh.yaml +35 -0
- data/doc/plugins/custom.md +88 -0
- data/doc/plugins/mco/rpc.md +82 -0
- data/doc/plugins/ssh/custom.md +141 -0
- data/doc/plugins/ssh/file_contains.md +37 -0
- data/doc/plugins/ssh/file_deploy.md +52 -0
- data/doc/plugins/ssh/file_exists.md +31 -0
- data/doc/plugins/ssh/file_replace.md +37 -0
- data/doc/plugins/ssh/puppet_agent_run.md +50 -0
- data/doc/plugins/ssh/reboot.md +22 -0
- data/doc/plugins/ssh/wait_for_login.md +53 -0
- data/doc/plugins/winrm/cmd.md +161 -0
- data/doc/plugins/winrm/file_contains.md +39 -0
- data/doc/plugins/winrm/file_exists.md +31 -0
- data/doc/plugins/winrm/powershell.md +27 -0
- data/doc/plugins/winrm/puppet_agent_run.md +49 -0
- data/doc/plugins/winrm/reboot.md +17 -0
- data/doc/plugins/winrm/wait_for_login.md +55 -0
- data/dopi.gemspec +42 -0
- data/lib/dopi/cli/command_add.rb +35 -0
- data/lib/dopi/cli/command_list.rb +19 -0
- data/lib/dopi/cli/command_remove.rb +31 -0
- data/lib/dopi/cli/command_reset.rb +27 -0
- data/lib/dopi/cli/command_run.rb +68 -0
- data/lib/dopi/cli/command_show.rb +109 -0
- data/lib/dopi/cli/command_update.rb +37 -0
- data/lib/dopi/cli/command_validate.rb +27 -0
- data/lib/dopi/cli/global_options.rb +55 -0
- data/lib/dopi/cli/log.rb +33 -0
- data/lib/dopi/cli.rb +57 -0
- data/lib/dopi/command/custom.rb +52 -0
- data/lib/dopi/command/dummy.rb +27 -0
- data/lib/dopi/command/mco/rpc.rb +158 -0
- data/lib/dopi/command/ssh/custom.rb +48 -0
- data/lib/dopi/command/ssh/file_contains.rb +70 -0
- data/lib/dopi/command/ssh/file_deploy.rb +71 -0
- data/lib/dopi/command/ssh/file_exists.rb +54 -0
- data/lib/dopi/command/ssh/file_replace.rb +96 -0
- data/lib/dopi/command/ssh/puppet_agent_run.rb +63 -0
- data/lib/dopi/command/ssh/reboot.rb +50 -0
- data/lib/dopi/command/ssh/wait_for_login.rb +68 -0
- data/lib/dopi/command/winrm/cmd.rb +44 -0
- data/lib/dopi/command/winrm/file_contains.rb +66 -0
- data/lib/dopi/command/winrm/file_exists.rb +51 -0
- data/lib/dopi/command/winrm/powershell.rb +16 -0
- data/lib/dopi/command/winrm/puppet_agent_run.rb +61 -0
- data/lib/dopi/command/winrm/reboot.rb +33 -0
- data/lib/dopi/command/winrm/wait_for_login.rb +49 -0
- data/lib/dopi/command.rb +239 -0
- data/lib/dopi/command_parser/arguments.rb +38 -0
- data/lib/dopi/command_parser/credentials.rb +59 -0
- data/lib/dopi/command_parser/env.rb +37 -0
- data/lib/dopi/command_parser/exec.rb +27 -0
- data/lib/dopi/command_parser/exit_code.rb +73 -0
- data/lib/dopi/command_parser/output.rb +126 -0
- data/lib/dopi/command_set.rb +66 -0
- data/lib/dopi/connector/local.rb +77 -0
- data/lib/dopi/connector/ssh.rb +170 -0
- data/lib/dopi/connector/winrm.rb +167 -0
- data/lib/dopi/error.rb +43 -0
- data/lib/dopi/log.rb +18 -0
- data/lib/dopi/node.rb +70 -0
- data/lib/dopi/plan.rb +99 -0
- data/lib/dopi/pluginmanager.rb +62 -0
- data/lib/dopi/state.rb +226 -0
- data/lib/dopi/state_store.rb +155 -0
- data/lib/dopi/step.rb +227 -0
- data/lib/dopi/step_set.rb +70 -0
- data/lib/dopi/version.rb +3 -0
- data/lib/dopi.rb +165 -0
- data/spec/command_helper.rb +11 -0
- data/spec/fixtures/mco_client.cfg +26 -0
- data/spec/fixtures/plans/fail_on_timeout.yaml +20 -0
- data/spec/fixtures/plans/hello_world.yaml +34 -0
- data/spec/fixtures/plans/non_existing_node.yaml +26 -0
- data/spec/fixtures/plans/test_role_variable.yaml +29 -0
- data/spec/fixtures/puppet/Puppetfile +8 -0
- data/spec/fixtures/puppet/Puppetfile.lock +57 -0
- data/spec/fixtures/puppet/hiera.yaml +6 -0
- data/spec/fixtures/puppet/manifests/site.pp +52 -0
- data/spec/fixtures/test_configuration.yaml +54 -0
- data/spec/fixtures/test_credentials.yaml +11 -0
- data/spec/fixtures/test_deloyed_file.txt +5 -0
- data/spec/fixtures/test_infrastructure.yaml +12 -0
- data/spec/fixtures/test_nodes.yaml +45 -0
- data/spec/fixtures/testenv_plan.yaml +159 -0
- data/spec/integration/dopi/addrun_spec.rb +31 -0
- data/spec/integration/dopi/cli/command_run_spec.rb +38 -0
- data/spec/integration/dopi/cli/global_options_spec.rb +128 -0
- data/spec/integration/dopi/command_spec.rb +66 -0
- data/spec/integration/dopi/fail_check_plans/file_exists_fails.yaml +38 -0
- data/spec/integration/dopi/fail_check_plans/output_parser.yaml +39 -0
- data/spec/integration/dopi/fail_check_plans/powershell_fail.yaml +25 -0
- data/spec/integration/dopi/fail_check_plans/timeout.yaml +29 -0
- data/spec/integration/dopi/fail_check_plans/verify_commands.yaml +33 -0
- data/spec/integration/dopi/failplan.rb +27 -0
- data/spec/integration/dopi/plan.rb +27 -0
- data/spec/integration/dopi/plans/dummy.yaml +29 -0
- data/spec/integration/dopi/plans/max_per_role.yaml +55 -0
- data/spec/integration/dopi/plans/no_timeout.yaml +29 -0
- data/spec/integration/dopi/plans/node_and_role_patterns.yaml +58 -0
- data/spec/integration/dopi/plans/node_by_config.yaml +116 -0
- data/spec/integration/dopi/plans/plugin_defaults.yaml +86 -0
- data/spec/integration/dopi/plans/plugins/mco/rpc.yaml +33 -0
- data/spec/integration/dopi/plans/plugins/ssh/custom.yaml +97 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_contains.yaml +51 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_deploy.yaml +82 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_exists.yaml +69 -0
- data/spec/integration/dopi/plans/plugins/ssh/file_replace.yaml +55 -0
- data/spec/integration/dopi/plans/plugins/ssh/puppet_agent_run.yaml +45 -0
- data/spec/integration/dopi/plans/plugins/ssh/reboot.yaml +43 -0
- data/spec/integration/dopi/plans/plugins/ssh/wait_for_login.yaml +45 -0
- data/spec/integration/dopi/plans/plugins/winrm/cmd.yaml +39 -0
- data/spec/integration/dopi/plans/plugins/winrm/file_contains.yaml +51 -0
- data/spec/integration/dopi/plans/plugins/winrm/file_exists.yaml +69 -0
- data/spec/integration/dopi/plans/plugins/winrm/reboot.yaml +31 -0
- data/spec/integration/dopi/plans/resolve_roles_on_validate.yaml +23 -0
- data/spec/integration/dopi/plans/ssh_parallel.yaml +37 -0
- data/spec/integration/dopi/plans/verify_commands.yaml +49 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/unit/dopi/command/custom_spec.rb +58 -0
- data/spec/unit/dopi/command/mco/rpc_spec.rb +157 -0
- data/spec/unit/dopi/command/ssh/custom_spec.rb +30 -0
- data/spec/unit/dopi/command/ssh/file_deploy_spec.rb +42 -0
- data/spec/unit/dopi/command/ssh/file_replace_spec.rb +35 -0
- data/spec/unit/dopi/command_parser/credentials_spec.rb +53 -0
- data/spec/unit/dopi/command_parser/exit_code_spec.rb +63 -0
- data/spec/unit/dopi/command_parser/output_spec.rb +129 -0
- data/spec/unit/dopi/command_spec.rb +14 -0
- data/spec/unit/dopi/connector/winrm_spec.rb +111 -0
- data/spec/unit/dopi/node_spec.rb +24 -0
- data/spec/unit/dopi/plan_spec.rb +31 -0
- data/spec/unit/dopi/state_spec.rb +109 -0
- data/spec/unit/dopi/step_spec.rb +13 -0
- metadata +448 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: Deploy File
|
|
3
|
+
#
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require "base64"
|
|
6
|
+
|
|
7
|
+
module Dopi
|
|
8
|
+
class Command
|
|
9
|
+
class Ssh
|
|
10
|
+
class FileDeploy < Dopi::Command
|
|
11
|
+
include DopCommon::HashParser
|
|
12
|
+
include Dopi::Connector::Ssh
|
|
13
|
+
include Dopi::CommandParser::ExitCode
|
|
14
|
+
|
|
15
|
+
public
|
|
16
|
+
|
|
17
|
+
def validate
|
|
18
|
+
validate_ssh
|
|
19
|
+
validate_exit_code
|
|
20
|
+
log_validation_method('file_valid?', CommandParsingError)
|
|
21
|
+
log_validation_method('content_valid?', CommandParsingError)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run
|
|
25
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = ssh_command({}, command_string)
|
|
26
|
+
check_exit_code(cmd_exit_code)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run_noop
|
|
30
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def file
|
|
34
|
+
file_valid? ? hash[:file] : nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def content
|
|
38
|
+
content_valid? ? load_content(hash[:content]) : nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def command_string
|
|
44
|
+
"echo -n #{Base64.strict_encode64(content)} | base64 -d > #{file}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def file_valid?
|
|
48
|
+
hash[:file] or
|
|
49
|
+
raise CommandParsingError, "Plugin #{name}: The key 'file' needs to be specified"
|
|
50
|
+
hash[:file].kind_of?(String) or
|
|
51
|
+
raise CommandParsingError, "Plugin #{name}: The value for key 'file' has to be a String"
|
|
52
|
+
begin
|
|
53
|
+
Pathname.new(hash[:file]).absolute? or
|
|
54
|
+
raise CommandParsingError, "Plugin #{name}: The path for 'file' has to be absolute"
|
|
55
|
+
rescue ArgumentError => e
|
|
56
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'file' is not a valid file path: #{e.message}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def content_valid?
|
|
61
|
+
hash[:content] or
|
|
62
|
+
raise CommandParsingError, "Plugin #{name}: The key 'content' needs to be specified"
|
|
63
|
+
load_content_valid?(hash[:content])
|
|
64
|
+
rescue DopCommon::PlanParsingError => e
|
|
65
|
+
raise CommandParsingError, "Plugin #{name}: value content not valid: #{e.message}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: File Exists
|
|
3
|
+
#
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
module Dopi
|
|
7
|
+
class Command
|
|
8
|
+
class Ssh
|
|
9
|
+
class FileExists < Dopi::Command
|
|
10
|
+
include Dopi::Connector::Ssh
|
|
11
|
+
include Dopi::CommandParser::ExitCode
|
|
12
|
+
|
|
13
|
+
public
|
|
14
|
+
|
|
15
|
+
def validate
|
|
16
|
+
validate_ssh
|
|
17
|
+
validate_exit_code
|
|
18
|
+
log_validation_method('file_valid?', CommandParsingError)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def run
|
|
22
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = ssh_command({}, command_string)
|
|
23
|
+
check_exit_code(cmd_exit_code)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run_noop
|
|
27
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def file
|
|
31
|
+
@file ||= file_valid? ? hash[:file] : nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def command_string
|
|
37
|
+
"[ -e #{file} ]"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def file_valid?
|
|
41
|
+
hash[:file] or
|
|
42
|
+
raise CommandParsingError, "Plugin #{name}: The key 'file' needs to be specified"
|
|
43
|
+
begin
|
|
44
|
+
Pathname.new(hash[:file]).absolute? or
|
|
45
|
+
raise CommandParsingError, "Plugin #{name}: The path for 'file' has to be absolute"
|
|
46
|
+
rescue ArgumentError => e
|
|
47
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'file' is not a valid file path: #{e.message}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: File Replace
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
module Dopi
|
|
6
|
+
class Command
|
|
7
|
+
class Ssh
|
|
8
|
+
class FileReplace < Dopi::Command
|
|
9
|
+
include Dopi::Connector::Ssh
|
|
10
|
+
include Dopi::CommandParser::ExitCode
|
|
11
|
+
|
|
12
|
+
public
|
|
13
|
+
|
|
14
|
+
def validate
|
|
15
|
+
validate_ssh
|
|
16
|
+
validate_exit_code
|
|
17
|
+
log_validation_method(:replacement_valid?, CommandParsingError)
|
|
18
|
+
log_validation_method(:global_valid?, CommandParsingError)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def run
|
|
22
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = ssh_command({}, command_string)
|
|
23
|
+
check_exit_code(cmd_exit_code)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run_noop
|
|
27
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def replacement
|
|
31
|
+
@replacement ||= replacement_valid? ?
|
|
32
|
+
hash[:replacement] : nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def global
|
|
36
|
+
@global ||= global_valid? ?
|
|
37
|
+
hash[:global] : true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def file
|
|
41
|
+
@file ||= file_valid? ? hash[:file] : nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def pattern
|
|
45
|
+
@pattern ||= pattern_valid? ?
|
|
46
|
+
hash[:pattern] : nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def command_string
|
|
52
|
+
"sed -i \"s/#{pattern}/#{replacement}/#{global_string}\" #{file}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def global_string
|
|
56
|
+
global ? 'g' : ''
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def replacement_valid?
|
|
60
|
+
hash[:replacement] or
|
|
61
|
+
raise CommandParsingError, "Plugin #{name}: The key 'replacement' needs to be specified"
|
|
62
|
+
hash[:replacement].kind_of?(String) or
|
|
63
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'replacement' has to be a String"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def global_valid?
|
|
67
|
+
return false if hash[:global].nil? # is optional
|
|
68
|
+
hash[:global].kind_of?(TrueClass) or hash[:global].kind_of?(FalseClass) or
|
|
69
|
+
raise CommandParsingError, "Plugin #{name}: The value for 'global' must be boolean"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def file_valid?
|
|
73
|
+
hash[:file] or
|
|
74
|
+
raise CommandParsingError, "Plugin #{name}: The key 'file' needs to be specified"
|
|
75
|
+
begin
|
|
76
|
+
Pathname.new(hash[:file]).absolute? or
|
|
77
|
+
raise CommandParsingError, "Plugin #{name}: The path for 'file' has to be absolute"
|
|
78
|
+
rescue ArgumentError => e
|
|
79
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'file' is not a valid file path: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def pattern_valid?
|
|
84
|
+
hash[:pattern] or
|
|
85
|
+
raise CommandParsingError, "Plugin #{name}: The key 'pattern' needs to be specified"
|
|
86
|
+
begin
|
|
87
|
+
Regexp.new(hash[:pattern])
|
|
88
|
+
rescue
|
|
89
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'pattern' is not a valid regexp: #{e.message}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#
|
|
2
|
+
# SSH custom command
|
|
3
|
+
#
|
|
4
|
+
module Dopi
|
|
5
|
+
class Command
|
|
6
|
+
class Ssh
|
|
7
|
+
class PuppetAgentRun < Dopi::Command
|
|
8
|
+
include Dopi::Connector::Ssh
|
|
9
|
+
include Dopi::CommandParser::Env
|
|
10
|
+
include Dopi::CommandParser::Arguments
|
|
11
|
+
include Dopi::CommandParser::ExitCode
|
|
12
|
+
include Dopi::CommandParser::Output
|
|
13
|
+
|
|
14
|
+
public
|
|
15
|
+
|
|
16
|
+
def initialize(command_parser, step, node, is_verify_command)
|
|
17
|
+
command_parser.overwrite_defaults = { :plugin_timeout => 1800 }
|
|
18
|
+
super(command_parser, step, node, is_verify_command)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate
|
|
22
|
+
validate_ssh
|
|
23
|
+
validate_env
|
|
24
|
+
validate_arguments
|
|
25
|
+
validate_exit_code
|
|
26
|
+
validate_output
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run
|
|
30
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = ssh_command(env, command_string)
|
|
31
|
+
check_output(cmd_stdout) &&
|
|
32
|
+
check_output(cmd_stderr) &&
|
|
33
|
+
check_exit_code(cmd_exit_code)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def run_noop
|
|
37
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def expect_exit_codes_defaults
|
|
41
|
+
[ 0, 2 ]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def parse_output_defaults
|
|
45
|
+
{ :error => [
|
|
46
|
+
'^Error:'
|
|
47
|
+
],
|
|
48
|
+
:warning => [
|
|
49
|
+
'^Warning:'
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def command_string
|
|
57
|
+
"puppet agent --test --color false #{arguments}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: Reboot a node
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
module Dopi
|
|
6
|
+
class Command
|
|
7
|
+
class Ssh
|
|
8
|
+
class Reboot < Dopi::Command::Ssh::WaitForLogin
|
|
9
|
+
|
|
10
|
+
def validate
|
|
11
|
+
super
|
|
12
|
+
log_validation_method(:reboot_cmd_valid?, CommandParsingError)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
ssh_command({}, reboot_cmd)
|
|
17
|
+
connected = true
|
|
18
|
+
@connection_timeout = 1
|
|
19
|
+
while connected
|
|
20
|
+
begin connected = check_exit_code(ssh_command({}, 'exit')[2])
|
|
21
|
+
rescue Dopi::NodeConnectionError, Dopi::CommandConnectionError
|
|
22
|
+
connected = false
|
|
23
|
+
end
|
|
24
|
+
if connected
|
|
25
|
+
sleep 1
|
|
26
|
+
raise GracefulExit if signals[:stop]
|
|
27
|
+
log(:info, "Still able to login, waiting for shutdown")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
log(:info, "Node is down, starting to check for login")
|
|
31
|
+
@connection_timeout = nil
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def reboot_cmd
|
|
36
|
+
@reboot_cmd ||= reboot_cmd_valid? ? hash[:reboot_cmd] : 'shutdown -r now'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def reboot_cmd_valid?
|
|
42
|
+
return false if hash[:reboot_cmd].nil? # is optional
|
|
43
|
+
hash[:reboot_cmd].class == String or
|
|
44
|
+
raise CommandParsingError, "Plugin #{name}: the value of 'reboot_cmd' has to be a string"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: Wait For Login
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
module Dopi
|
|
6
|
+
class Command
|
|
7
|
+
class Ssh
|
|
8
|
+
class WaitForLogin < Dopi::Command
|
|
9
|
+
include Dopi::Connector::Ssh
|
|
10
|
+
include Dopi::CommandParser::ExitCode
|
|
11
|
+
|
|
12
|
+
DEFAULT_CONNECTION_TIMEOUT = 0
|
|
13
|
+
DEFAULT_INTERVAL = 10
|
|
14
|
+
|
|
15
|
+
def validate
|
|
16
|
+
validate_ssh
|
|
17
|
+
validate_exit_code
|
|
18
|
+
log_validation_method(:connection_timeout_valid?, CommandParsingError)
|
|
19
|
+
log_validation_method(:interval_valid?, CommandParsingError)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run
|
|
23
|
+
connected = false
|
|
24
|
+
until connected
|
|
25
|
+
begin connected = check_exit_code(ssh_command({}, 'exit')[2])
|
|
26
|
+
rescue Dopi::NodeConnectionError, Dopi::CommandConnectionError
|
|
27
|
+
end
|
|
28
|
+
unless connected
|
|
29
|
+
sleep interval
|
|
30
|
+
raise GracefulExit if signals[:stop]
|
|
31
|
+
log(:info, "Retrying connect to node")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def connection_timeout
|
|
38
|
+
@connection_timeout ||= connection_timeout_valid? ?
|
|
39
|
+
hash[:connection_timeout] : DEFAULT_CONNECTION_TIMEOUT
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def interval
|
|
43
|
+
@interval ||= interval_valid? ?
|
|
44
|
+
hash[:interval] : DEFAULT_INTERVAL
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def ssh_options_defaults
|
|
48
|
+
[" -o ConnectTimeout=#{connection_timeout} -q "]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def connection_timeout_valid?
|
|
54
|
+
return false if hash[:connection_timeout].nil? # is optional
|
|
55
|
+
hash[:connection_timeout].class == Fixnum or
|
|
56
|
+
raise CommandParsingError, "Plugin #{name}: the value of 'connection_timeout' has to be a number"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def interval_valid?
|
|
60
|
+
return false if hash[:interval].nil? # is optional
|
|
61
|
+
hash[:interval].class == Fixnum or
|
|
62
|
+
raise CommandParsingError, "Plugin #{name}: the value of 'interval' has to be a number"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: WinRM Command
|
|
3
|
+
#
|
|
4
|
+
require 'winrm'
|
|
5
|
+
|
|
6
|
+
module Dopi
|
|
7
|
+
class Command
|
|
8
|
+
class Winrm
|
|
9
|
+
class Cmd < Dopi::Command
|
|
10
|
+
include Dopi::Connector::Winrm
|
|
11
|
+
include Dopi::CommandParser::Exec
|
|
12
|
+
include Dopi::CommandParser::Env
|
|
13
|
+
include Dopi::CommandParser::Arguments
|
|
14
|
+
include Dopi::CommandParser::ExitCode
|
|
15
|
+
include Dopi::CommandParser::Output
|
|
16
|
+
|
|
17
|
+
def validate
|
|
18
|
+
validate_winrm
|
|
19
|
+
validate_exec
|
|
20
|
+
validate_env
|
|
21
|
+
validate_arguments
|
|
22
|
+
validate_exit_code
|
|
23
|
+
validate_output
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run
|
|
27
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = winrm_command(command_string)
|
|
28
|
+
check_output(cmd_stdout) &&
|
|
29
|
+
check_output(cmd_stderr) &&
|
|
30
|
+
check_exit_code(cmd_exit_code)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def run_noop
|
|
34
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def command_string
|
|
38
|
+
exec + ' ' + arguments
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: File Contains
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
module Dopi
|
|
6
|
+
class Command
|
|
7
|
+
class Winrm
|
|
8
|
+
class FileContains < Dopi::Command
|
|
9
|
+
include Dopi::Connector::Winrm
|
|
10
|
+
include Dopi::CommandParser::ExitCode
|
|
11
|
+
|
|
12
|
+
def validate
|
|
13
|
+
validate_winrm
|
|
14
|
+
validate_exit_code
|
|
15
|
+
log_validation_method('file_valid?', CommandParsingError)
|
|
16
|
+
log_validation_method('pattern_valid?', CommandParsingError)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = winrm_powershell_command(command_string)
|
|
21
|
+
check_exit_code(cmd_exit_code)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run_noop
|
|
25
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def command_string
|
|
29
|
+
"if(-not(Select-String -Pattern #{pattern} -Path '#{file}' -Quiet)) { exit 1 }"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def file
|
|
33
|
+
@file ||= file_valid? ?
|
|
34
|
+
hash[:file] : nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def pattern
|
|
38
|
+
@pattern ||= pattern_valid? ?
|
|
39
|
+
hash[:pattern] : nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def file_valid?
|
|
43
|
+
hash[:file] or
|
|
44
|
+
raise CommandParsingError, "Plugin #{name}: The key 'file' needs to be specified"
|
|
45
|
+
begin
|
|
46
|
+
hash[:file][/[a-zA-Z]+:\\/] or hash[:file][/\\\\\w+/] or
|
|
47
|
+
raise CommandParsingError, "Plugin #{name}: The path for 'file' has to be absolute"
|
|
48
|
+
rescue ArgumentError => e
|
|
49
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'file' is not a valid file path: #{e.message}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def pattern_valid?
|
|
54
|
+
hash[:pattern] or
|
|
55
|
+
raise CommandParsingError, "Plugin #{name}: The key 'pattern' needs to be specified"
|
|
56
|
+
begin
|
|
57
|
+
Regexp.new(hash[:pattern])
|
|
58
|
+
rescue
|
|
59
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'pattern' is not a valid regexp: #{e.message}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: File Exists
|
|
3
|
+
#
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
module Dopi
|
|
7
|
+
class Command
|
|
8
|
+
class Winrm
|
|
9
|
+
class FileExists < Dopi::Command
|
|
10
|
+
include Dopi::Connector::Winrm
|
|
11
|
+
include Dopi::CommandParser::ExitCode
|
|
12
|
+
|
|
13
|
+
def validate
|
|
14
|
+
validate_winrm
|
|
15
|
+
validate_exit_code
|
|
16
|
+
log_validation_method(:file_valid?, CommandParsingError)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = winrm_powershell_command(command_string)
|
|
21
|
+
check_exit_code(cmd_exit_code)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run_noop
|
|
25
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def command_string
|
|
29
|
+
"if(-not(Test-Path '#{file}')) { exit 1 }"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def file
|
|
33
|
+
@file ||= file_valid? ?
|
|
34
|
+
hash[:file] : nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def file_valid?
|
|
38
|
+
hash[:file] or
|
|
39
|
+
raise CommandParsingError, "Plugin #{name}: The key 'file' needs to be specified"
|
|
40
|
+
begin
|
|
41
|
+
hash[:file][/[a-zA-Z]+:\\/] or hash[:file][/\\\\\w+/] or
|
|
42
|
+
raise CommandParsingError, "Plugin #{name}: The path for 'file' has to be absolute"
|
|
43
|
+
rescue ArgumentError => e
|
|
44
|
+
raise CommandParsingError, "Plugin #{name}: The value in 'file' is not a valid file path: #{e.message}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Dopi
|
|
2
|
+
class Command
|
|
3
|
+
class Winrm
|
|
4
|
+
class Powershell < Dopi::Command::Winrm::Cmd
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = winrm_powershell_command(command_string)
|
|
8
|
+
check_output(cmd_stdout) &&
|
|
9
|
+
check_output(cmd_stderr) &&
|
|
10
|
+
check_exit_code(cmd_exit_code)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#
|
|
2
|
+
# WinRM Puppet Agent Plugin
|
|
3
|
+
#
|
|
4
|
+
module Dopi
|
|
5
|
+
class Command
|
|
6
|
+
class Winrm
|
|
7
|
+
class PuppetAgentRun < Dopi::Command
|
|
8
|
+
include Dopi::Connector::Winrm
|
|
9
|
+
include Dopi::CommandParser::Arguments
|
|
10
|
+
include Dopi::CommandParser::ExitCode
|
|
11
|
+
include Dopi::CommandParser::Output
|
|
12
|
+
|
|
13
|
+
public
|
|
14
|
+
|
|
15
|
+
def initialize(command_parser, step, node, is_verify_command)
|
|
16
|
+
command_parser.overwrite_defaults = { :plugin_timeout => 1800 }
|
|
17
|
+
super(command_parser, step, node, is_verify_command)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def validate
|
|
21
|
+
validate_winrm
|
|
22
|
+
validate_arguments
|
|
23
|
+
validate_exit_code
|
|
24
|
+
validate_output
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run
|
|
28
|
+
cmd_stdout, cmd_stderr, cmd_exit_code = winrm_powershell_command(command_string)
|
|
29
|
+
check_output(cmd_stdout) &&
|
|
30
|
+
check_output(cmd_stderr) &&
|
|
31
|
+
check_exit_code(cmd_exit_code)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def run_noop
|
|
35
|
+
log(:info, "(NOOP) Executing '#{command_string}' for command #{name}")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def expect_exit_codes_defaults
|
|
39
|
+
[ 0, 2 ]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def parse_output_defaults
|
|
43
|
+
{ :error => [
|
|
44
|
+
'^Error:'
|
|
45
|
+
],
|
|
46
|
+
:warning => [
|
|
47
|
+
'^Warning:'
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def command_string
|
|
55
|
+
"puppet agent --test --color false #{arguments}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#
|
|
2
|
+
# DOPi Plugin: Wait For Login
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
module Dopi
|
|
6
|
+
class Command
|
|
7
|
+
class Winrm
|
|
8
|
+
class Reboot < Dopi::Command::Winrm::WaitForLogin
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
winrm_powershell_command('shutdown /r /f /t 0')
|
|
12
|
+
connected = true
|
|
13
|
+
while connected
|
|
14
|
+
begin
|
|
15
|
+
@node.reset_address(port)
|
|
16
|
+
@node.address(port)
|
|
17
|
+
rescue Dopi::NodeConnectionError
|
|
18
|
+
connected = false
|
|
19
|
+
end
|
|
20
|
+
if connected
|
|
21
|
+
sleep 1
|
|
22
|
+
raise GracefulExit if signals[:stop]
|
|
23
|
+
log(:info, "Still able to login, waiting for shutdown")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
log(:info, "Node is down, starting to check for login")
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|