loom-core 0.0.6 → 0.0.9
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/.rubocop.yml +31 -0
- data/Gemfile.lock +108 -56
- data/Rakefile +2 -0
- data/bin/loom +3 -0
- data/docs/architecture.jpg +0 -0
- data/gentags.sh +2 -0
- data/lib/loom/all.rb +1 -1
- data/lib/loom/config.rb +2 -2
- data/lib/loom/method_signature.rb +1 -1
- data/lib/loom/mods/action_proxy.rb +2 -2
- data/lib/loom/mods/mod_loader.rb +10 -5
- data/lib/loom/mods/module.rb +6 -5
- data/lib/loom/pattern/all.rb +1 -0
- data/lib/loom/pattern/definition_context.rb +7 -5
- data/lib/loom/pattern/dsl.rb +184 -119
- data/lib/loom/pattern/expanding_reference.rb +82 -6
- data/lib/loom/pattern/loader.rb +2 -18
- data/lib/loom/pattern/pattern.rb +52 -0
- data/lib/loom/pattern/reference.rb +17 -13
- data/lib/loom/pattern/reference_set.rb +71 -50
- data/lib/loom/runner/all.rb +2 -0
- data/lib/loom/runner/execution_context.rb +9 -0
- data/lib/loom/{dsl.rb → runner/sshkit_connector.rb} +5 -7
- data/lib/loom/runner.rb +46 -33
- data/lib/loom/shell/api.rb +3 -3
- data/lib/loom/shell/cmd_wrapper.rb +5 -2
- data/lib/loom/shell/core.rb +16 -16
- data/lib/loom/shell.rb +4 -2
- data/lib/loom/version.rb +1 -1
- data/lib/loomext/coremods/exec.rb +1 -0
- data/lib/loomext/coremods/systemd/all.rb +1 -0
- data/lib/loomext/coremods/systemd/hostname.rb +10 -0
- data/loom.TAGS +797 -0
- data/loom.gemspec +4 -3
- data/spec/.loom/error_handling.loom +1 -0
- data/spec/.loom/fail.loom +27 -13
- data/spec/.loom/files.loom +1 -0
- data/spec/.loom/inventory.yml +3 -0
- data/spec/.loom/net.loom +1 -0
- data/spec/.loom/pattern_context.loom +1 -0
- data/spec/.loom/pkg.loom +1 -0
- data/spec/.loom/regression.loom +23 -0
- data/spec/.loom/shell.loom +1 -0
- data/spec/.loom/test.loom +21 -4
- data/spec/.loom/user.loom +1 -0
- data/spec/.loom/vms.loom +1 -0
- data/spec/loom/host_spec_spec.rb +1 -1
- data/spec/loom/pattern/dsl_spec.rb +3 -2
- data/spec/shared/loom_internals_helper.rb +1 -1
- data/spec/test_loom_spec.rb +102 -42
- data/test +15 -0
- metadata +40 -17
@@ -1,22 +1,25 @@
|
|
1
1
|
module Loom::Pattern
|
2
|
+
# See Loom::Pattern::Pattern for the difference between refs and patterns.
|
2
3
|
class Reference
|
3
4
|
|
4
|
-
attr_reader :slug, :source_file, :desc
|
5
|
+
attr_reader :slug, :source_file, :desc, :pattern
|
5
6
|
|
6
|
-
def initialize(slug,
|
7
|
+
def initialize(slug, pattern, source_file, definition_ctx)
|
7
8
|
@slug = slug
|
8
|
-
@unbound_method = unbound_method
|
9
9
|
@source_file = source_file
|
10
10
|
@definition_ctx = definition_ctx
|
11
|
-
@desc = description
|
11
|
+
@desc = pattern.description
|
12
|
+
@pattern = pattern
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
# Used by Loom::Pattern::Loader to expand weaves. A Pattern::Reference it
|
16
|
+
# just expands to itself.
|
17
|
+
def expand_slugs
|
18
|
+
@slug
|
16
19
|
end
|
17
20
|
|
18
21
|
def call(shell_api, host_fact_set)
|
19
|
-
run_context = RunContext.new @
|
22
|
+
run_context = RunContext.new @pattern, @definition_ctx
|
20
23
|
|
21
24
|
fact_set = @definition_ctx.fact_set host_fact_set
|
22
25
|
Loom.log.debug5(self) {
|
@@ -30,7 +33,7 @@ module Loom::Pattern
|
|
30
33
|
begin
|
31
34
|
run_context.run shell_api, fact_set
|
32
35
|
rescue => e
|
33
|
-
error_msg = "error executing '#{slug}' in #{source_file}
|
36
|
+
error_msg = "error executing '#{slug}' in #{source_file} =>\n\t#{e}\n%s"
|
34
37
|
Loom.log.error(error_msg % e.backtrace.join("\n\t"))
|
35
38
|
raise
|
36
39
|
end
|
@@ -42,8 +45,8 @@ module Loom::Pattern
|
|
42
45
|
# A small class to bind the unbound_method to and provide context
|
43
46
|
# in the case of errors.
|
44
47
|
class RunContext
|
45
|
-
def initialize(
|
46
|
-
@
|
48
|
+
def initialize(pattern, definition_ctx)
|
49
|
+
@pattern = pattern
|
47
50
|
@definition_ctx = definition_ctx
|
48
51
|
end
|
49
52
|
|
@@ -55,7 +58,7 @@ module Loom::Pattern
|
|
55
58
|
Loom.log.debug1(self) { "before hooks => #{before_hooks}"}
|
56
59
|
before_hooks.each do |hook|
|
57
60
|
Loom.log.debug2(self) { "executing before hook => #{hook}"}
|
58
|
-
|
61
|
+
instance_exec shell_api, fact_set, &hook.block
|
59
62
|
end
|
60
63
|
|
61
64
|
# This is the entry point into calling patterns.
|
@@ -64,14 +67,15 @@ module Loom::Pattern
|
|
64
67
|
Loom.log.debug1(self) { "after hooks => #{after_hooks}" }
|
65
68
|
after_hooks.each do |hook|
|
66
69
|
Loom.log.debug2(self) { "executing after hook => #{hook}"}
|
67
|
-
|
70
|
+
instance_exec shell_api, fact_set, &hook.block
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
75
|
private
|
76
|
+
|
73
77
|
def apply_pattern(*args)
|
74
|
-
|
78
|
+
instance_exec(*args, &@pattern.pattern_block)
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
@@ -3,10 +3,13 @@
|
|
3
3
|
# into a reference set. There's also a lot of dark magic w/ generating
|
4
4
|
# stacktraces to get the correct .loom file line (but I forget if that's done
|
5
5
|
# here or in pattern/reference.rb maybe?)
|
6
|
+
|
7
|
+
# NB: The use of the word "mod" or "module" in this file probably means a
|
8
|
+
# ::Module, not a Loom::Mods::Module
|
6
9
|
module Loom::Pattern
|
7
10
|
|
8
11
|
DuplicatePatternRef = Class.new Loom::LoomError
|
9
|
-
|
12
|
+
NoReferenceForSlug = Class.new Loom::LoomError
|
10
13
|
InvalidPatternNamespace = Class.new Loom::LoomError
|
11
14
|
|
12
15
|
##
|
@@ -16,7 +19,11 @@ module Loom::Pattern
|
|
16
19
|
class << self
|
17
20
|
def load_from_file(path)
|
18
21
|
Loom.log.debug1(self) { "loading patterns from file => #{path}" }
|
19
|
-
|
22
|
+
builder(File.read(path), path).build
|
23
|
+
end
|
24
|
+
|
25
|
+
def builder(file_src, file_path)
|
26
|
+
Builder.create(file_src, file_path)
|
20
27
|
end
|
21
28
|
end
|
22
29
|
|
@@ -34,21 +41,20 @@ module Loom::Pattern
|
|
34
41
|
|
35
42
|
def get_pattern_ref(slug)
|
36
43
|
ref = @slug_to_ref_map[slug]
|
37
|
-
raise
|
44
|
+
raise NoReferenceForSlug, slug unless ref
|
38
45
|
ref
|
39
46
|
end
|
40
47
|
alias_method :[], :get_pattern_ref
|
41
48
|
|
42
49
|
def merge!(ref_set)
|
43
|
-
|
50
|
+
add_pattern_refs(ref_set.pattern_refs)
|
44
51
|
end
|
45
52
|
|
46
53
|
def add_pattern_refs(refs)
|
47
|
-
map = @slug_to_ref_map
|
48
54
|
refs.each do |ref|
|
49
55
|
Loom.log.debug2(self) { "adding ref to set => #{ref.slug}" }
|
50
|
-
raise DuplicatePatternRef, ref.slug if
|
51
|
-
|
56
|
+
raise DuplicatePatternRef, ref.slug if @slug_to_ref_map[ref.slug]
|
57
|
+
@slug_to_ref_map[ref.slug] = ref
|
52
58
|
end
|
53
59
|
end
|
54
60
|
|
@@ -57,83 +63,95 @@ module Loom::Pattern
|
|
57
63
|
|
58
64
|
class << self
|
59
65
|
def create(ruby_code, source_file)
|
66
|
+
# Creates an anonymous parent module in which to evaluate the .loom
|
67
|
+
# file src. This module acts as a global context for the .loom file.
|
68
|
+
# TODO: How should this be hardened?
|
60
69
|
shell_module = Module.new
|
61
70
|
shell_module.include Loom::Pattern
|
62
71
|
# TODO: I think this is my black magic for capturing stacktrace
|
63
72
|
# info... I forget the details. Add documentation.
|
73
|
+
# TODO: This is where I would need to hack into to auto-include
|
74
|
+
# Loom::Pattern in .loom file modules
|
64
75
|
shell_module.module_eval ruby_code, source_file, 1
|
65
76
|
shell_module.namespace ""
|
66
77
|
|
67
|
-
self.new
|
78
|
+
self.new shell_module, source_file
|
68
79
|
end
|
69
80
|
end
|
70
81
|
|
71
82
|
def initialize(shell_module, source_file)
|
72
83
|
@shell_module = shell_module
|
73
|
-
@pattern_mod_specs = pattern_mod_specs
|
74
84
|
@source_file = source_file
|
75
85
|
end
|
76
86
|
|
77
87
|
def build
|
78
88
|
ref_set = ReferenceSet.new
|
89
|
+
|
90
|
+
dsl_specs = create_dsl_specs
|
91
|
+
pattern_refs = create_pattern_refs dsl_specs, ref_set
|
92
|
+
|
79
93
|
ref_set.add_pattern_refs pattern_refs
|
80
94
|
ref_set
|
81
95
|
end
|
82
96
|
|
83
97
|
private
|
84
|
-
|
85
|
-
|
98
|
+
# TODO: I don't like passing in the ref set build target here.... but
|
99
|
+
# ExpandingReference needs it... Can I do this w/o an instance variable
|
100
|
+
# and w/o plumbing the param through methods?
|
101
|
+
def create_pattern_refs(dsl_specs, builder_target_ref_set)
|
102
|
+
dsl_specs.flat_map do |dsl_spec|
|
103
|
+
create_refs_for_dsl_spec dsl_spec, builder_target_ref_set
|
104
|
+
end
|
86
105
|
end
|
87
106
|
|
88
|
-
def
|
89
|
-
|
90
|
-
context = context_for_mod_spec mod_spec
|
107
|
+
def create_refs_for_dsl_spec(dsl_spec, builder_target_ref_set)
|
108
|
+
context = create_defn_context_for_dsl_spec dsl_spec
|
91
109
|
|
92
|
-
|
93
|
-
slug = compute_slug
|
110
|
+
dsl_spec[:dsl_builder].patterns.map do |pattern|
|
111
|
+
slug = compute_slug dsl_spec[:namespace_list], pattern.name
|
94
112
|
|
95
|
-
|
113
|
+
case pattern.kind
|
114
|
+
when :weave
|
96
115
|
Loom.log.debug2(self) { "adding ExpandingReference for weave: #{slug}" }
|
97
|
-
|
116
|
+
create_expanding_reference(pattern, slug, builder_target_ref_set)
|
98
117
|
else
|
99
118
|
Loom.log.debug2(self) { "adding Reference for pattern: #{slug}" }
|
100
|
-
|
119
|
+
create_pattern_reference(pattern, slug, context)
|
101
120
|
end
|
102
121
|
end
|
103
122
|
end
|
104
123
|
|
105
|
-
def
|
106
|
-
desc =
|
124
|
+
def create_expanding_reference(pattern, slug, ref_set)
|
125
|
+
desc = pattern.description
|
107
126
|
Loom.log.warn "no descripiton for weave => #{slug}" unless desc
|
108
127
|
|
109
|
-
ExpandingReference.new slug,
|
128
|
+
ExpandingReference.new slug, pattern, ref_set
|
110
129
|
end
|
111
130
|
|
112
|
-
def
|
113
|
-
|
114
|
-
desc = mod.pattern_description pattern_name
|
131
|
+
def create_pattern_reference(pattern, slug, context)
|
132
|
+
desc = pattern.description
|
115
133
|
Loom.log.warn "no descripiton for pattern => #{slug}" unless desc
|
116
134
|
|
117
|
-
Reference.new slug,
|
135
|
+
Reference.new slug, pattern, @source_file, context
|
118
136
|
end
|
119
137
|
|
120
|
-
|
121
|
-
|
122
|
-
|
138
|
+
# Creates a DefinitionContext for dsl_module by flattening and mapping
|
139
|
+
# parent ::Modules to a contextualized DefinitionContext.
|
140
|
+
def create_defn_context_for_dsl_spec(dsl_spec)
|
141
|
+
parents = dsl_spec[:parent_modules].find_all do |mod|
|
142
|
+
dsl_module? mod
|
123
143
|
end
|
124
144
|
parent_context = parents.reduce(nil) do |parent_ctx, parent_mod|
|
125
|
-
DefinitionContext.new parent_mod, parent_ctx
|
145
|
+
DefinitionContext.new parent_mod.dsl_builder, parent_ctx
|
126
146
|
end
|
127
|
-
|
128
|
-
mod = mod_spec[:module]
|
129
|
-
DefinitionContext.new mod, parent_context
|
147
|
+
DefinitionContext.new dsl_spec[:dsl_builder], parent_context
|
130
148
|
end
|
131
149
|
|
132
150
|
def compute_slug(namespace_list, pattern_method_name)
|
133
151
|
namespace_list.dup.push(pattern_method_name).join ":"
|
134
152
|
end
|
135
153
|
|
136
|
-
def
|
154
|
+
def create_namespace_list(pattern, parent_modules)
|
137
155
|
mods = parent_modules.dup << pattern
|
138
156
|
mods.reduce([]) do |memo, mod|
|
139
157
|
mod_name = if mod.respond_to?(:namespace) && mod.namespace
|
@@ -149,32 +167,35 @@ module Loom::Pattern
|
|
149
167
|
end
|
150
168
|
end
|
151
169
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
Loom.log.debug2(self) { "found pattern module => #{
|
156
|
-
|
170
|
+
def create_dsl_specs
|
171
|
+
dsl_mods = []
|
172
|
+
traverse_dsl_modules @shell_module do |dsl_mod, parent_modules|
|
173
|
+
Loom.log.debug2(self) { "found pattern module => #{dsl_mod}" }
|
174
|
+
|
175
|
+
dsl_builder = dsl_mod.dsl_builder
|
176
|
+
next if dsl_builder.patterns.empty?
|
157
177
|
|
158
|
-
|
159
|
-
|
160
|
-
:
|
161
|
-
:
|
162
|
-
:
|
163
|
-
:parent_modules => parent_modules.dup
|
178
|
+
dsl_mods << {
|
179
|
+
namespace_list: create_namespace_list(dsl_mod, parent_modules),
|
180
|
+
dsl_builder: dsl_builder,
|
181
|
+
dsl_module: dsl_mod,
|
182
|
+
parent_modules: parent_modules
|
164
183
|
}
|
165
184
|
end
|
166
|
-
|
185
|
+
dsl_mods
|
167
186
|
end
|
168
187
|
|
169
|
-
def
|
188
|
+
def dsl_module?(mod)
|
170
189
|
mod.included_modules.include? Loom::Pattern
|
171
190
|
end
|
172
191
|
|
173
|
-
|
192
|
+
# Recursive method to walk the tree of dsl_builders representative of the
|
193
|
+
# .loom file pattern modules
|
194
|
+
def traverse_dsl_modules(mod, pattern_parents=[], visited={}, &block)
|
174
195
|
return if visited[mod.name] # prevent cycles
|
175
196
|
visited[mod.name] = true
|
176
197
|
|
177
|
-
yield mod, pattern_parents.dup if
|
198
|
+
yield mod, pattern_parents.dup if dsl_module?(mod)
|
178
199
|
|
179
200
|
# Traverse all sub modules, even ones that aren't
|
180
201
|
# Loom::Pattern[s], since they might contain more sub modules
|
@@ -185,7 +206,7 @@ module Loom::Pattern
|
|
185
206
|
|
186
207
|
pattern_parents << mod
|
187
208
|
sub_modules.each do |sub_mod|
|
188
|
-
|
209
|
+
traverse_dsl_modules sub_mod, pattern_parents.dup, visited, &block
|
189
210
|
end
|
190
211
|
end
|
191
212
|
end
|
@@ -5,12 +5,8 @@ require 'socket'
|
|
5
5
|
# https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/abstract.rb
|
6
6
|
# https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/netssh.rb
|
7
7
|
# https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/local.rb
|
8
|
-
module Loom
|
9
|
-
|
10
|
-
# TODO: Rename this to something like SSHKitWrapper, DSL is a
|
11
|
-
# terribly misinformative name.
|
12
|
-
module DSL
|
13
|
-
|
8
|
+
module Loom::RunnerModule
|
9
|
+
module SSHKitConnector
|
14
10
|
UnexpectedHostError = Class.new Loom::LoomError
|
15
11
|
SSHConnectionError = Class.new Loom::LoomError
|
16
12
|
|
@@ -22,7 +18,9 @@ module Loom
|
|
22
18
|
# +&block+ should accept an SSHKit::Backend and SSHKit::Host
|
23
19
|
def on_host(host_specs, &run_block)
|
24
20
|
host_specs.each do |spec|
|
25
|
-
|
21
|
+
unless spec.is_a? Loom::HostSpec
|
22
|
+
raise UnexpectedHostError "not a HostSpec => #{spec}"
|
23
|
+
end
|
26
24
|
end
|
27
25
|
|
28
26
|
host_spec_map = host_specs.reduce({}) do |map, spec|
|
data/lib/loom/runner.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
module Loom
|
2
|
+
# TODO: Make Loom::Runner a module and move this to
|
3
|
+
# Loom::Runner::Core. Loom::RunnerModule is set up as a temporary namespace
|
4
|
+
# until that happens.
|
2
5
|
class Runner
|
3
6
|
|
4
7
|
PatternExecutionError = Class.new Loom::LoomError
|
5
8
|
FailFastExecutionError = Class.new PatternExecutionError
|
6
9
|
|
7
|
-
include Loom::
|
10
|
+
include Loom::RunnerModule::SSHKitConnector
|
8
11
|
|
9
12
|
def initialize(loom_config, pattern_slugs=[], other_facts={})
|
10
13
|
@pattern_slugs = pattern_slugs
|
@@ -73,11 +76,13 @@ module Loom
|
|
73
76
|
exit 97
|
74
77
|
rescue Loom::LoomError => e
|
75
78
|
Loom.log.error "Loom::LoomError => #{e.inspect}, run with -d for more"
|
76
|
-
|
79
|
+
backtrace = e.cause.nil? ? e.backtrace : e.cause.backtrace
|
80
|
+
Loom.log.debug backtrace.join "\n\t"
|
81
|
+
Loom.log.debug backtrace.join "\n\t"
|
77
82
|
exit 98
|
78
83
|
rescue => e
|
79
|
-
|
80
|
-
Loom.log.fatal e.backtrace.join
|
84
|
+
# TODO: Make error/exception logging look like this everywhere
|
85
|
+
Loom.log.fatal "fatal error =>\n#{e.inspect}\n\t#{e.backtrace.join("\n\t\t")}"
|
81
86
|
|
82
87
|
loom_files = @loom_config.files.loom_files
|
83
88
|
loom_errors = e.backtrace.select { |line| line =~ /(#{loom_files.join("|")})/ }
|
@@ -119,7 +124,7 @@ module Loom
|
|
119
124
|
@pattern_refs = pattern_loader.patterns @pattern_slugs
|
120
125
|
|
121
126
|
@loom_config[:loomfile_autoloads].each do |path|
|
122
|
-
Loom.log.debug { "
|
127
|
+
Loom.log.debug { "requiring config[:loomfile_autoloads]: #{path}" }
|
123
128
|
require path
|
124
129
|
end
|
125
130
|
@mod_loader = Loom::Mods::ModLoader.new @loom_config
|
@@ -135,40 +140,18 @@ module Loom
|
|
135
140
|
|
136
141
|
begin
|
137
142
|
@pattern_refs.each do |pattern_ref|
|
138
|
-
slug = pattern_ref.slug
|
139
|
-
pattern_description = "[#{hostname} => #{slug}]"
|
140
|
-
|
141
143
|
if @caught_sig_int
|
142
|
-
Loom.log.warn "caught SIGINT, skipping #{
|
144
|
+
Loom.log.warn "caught SIGINT, skipping #{log_token(pattern_ref, hostname)}"
|
143
145
|
next
|
144
146
|
elsif inventory_list.disabled? hostname
|
145
147
|
Loom.log.warn "host disabled due to previous failure, " +
|
146
|
-
"skipping: #{
|
148
|
+
"skipping: #{log_token(pattern_ref, hostname)}"
|
147
149
|
next
|
148
150
|
end
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# new fact.
|
154
|
-
fact_shell = Loom::Shell.create @mod_loader, sshkit_backend, dry_run
|
155
|
-
fact_set = Loom::Facts.fact_set(host_spec, fact_shell, @loom_config)
|
156
|
-
.merge @other_facts
|
157
|
-
|
158
|
-
Loom.log.info "running pattern => #{pattern_description}"
|
159
|
-
# Creates a new shell for executing the pattern, so as not to be
|
160
|
-
# tainted by the fact finding shell above.
|
161
|
-
pattern_shell = Loom::Shell.create @mod_loader, sshkit_backend, dry_run
|
162
|
-
|
163
|
-
Loom.log.warn "dry run only => #{pattern_description}" if dry_run
|
164
|
-
failures = execute_pattern pattern_ref, pattern_shell, fact_set
|
165
|
-
|
166
|
-
if failures.empty?
|
167
|
-
Loom.log.debug "success on => #{pattern_description}"
|
168
|
-
else
|
169
|
-
Loom.log.error "failures on => #{pattern_description}:\n\t%s" % (
|
170
|
-
failures.join("\n\t"))
|
171
|
-
end
|
152
|
+
# wip-patternbuilder is adding this feature
|
153
|
+
# run_analysis_phase(pattern_ref, host_spec, sshkit_backend)
|
154
|
+
run_execution_phase(pattern_ref, host_spec, sshkit_backend, dry_run)
|
172
155
|
end
|
173
156
|
rescue IOError => e
|
174
157
|
# TODO: Try to patch SSHKit for a more specific error for unexpected
|
@@ -184,6 +167,32 @@ module Loom
|
|
184
167
|
end
|
185
168
|
end
|
186
169
|
|
170
|
+
def run_execution_phase(pattern_ref, host_spec, sshkit_backend, dry_run)
|
171
|
+
log_token = log_token(pattern_ref, host_spec.hostname)
|
172
|
+
Loom.log.debug "collecting facts for => #{log_token}"
|
173
|
+
# Collects facts for each pattern run on each host, this way if one
|
174
|
+
# pattern run updates would be facts, the next pattern will see the
|
175
|
+
# new fact.
|
176
|
+
fact_shell = Loom::Shell.create @mod_loader, sshkit_backend, dry_run
|
177
|
+
fact_set = Loom::Facts.fact_set(host_spec, fact_shell, @loom_config)
|
178
|
+
.merge @other_facts
|
179
|
+
|
180
|
+
Loom.log.info "running pattern => #{log_token}"
|
181
|
+
# Creates a new shell for executing the pattern, so as not to be
|
182
|
+
# tainted by the fact finding shell above.
|
183
|
+
pattern_shell = Loom::Shell.create @mod_loader, sshkit_backend, dry_run
|
184
|
+
|
185
|
+
Loom.log.warn "dry run only => #{log_token}" if dry_run
|
186
|
+
failures = execute_pattern pattern_ref, pattern_shell, fact_set
|
187
|
+
|
188
|
+
if failures.empty?
|
189
|
+
Loom.log.debug "success on => #{log_token}"
|
190
|
+
else
|
191
|
+
Loom.log.error "failures on => #{log_token}:\n\t%s" % (
|
192
|
+
failures.join("\n\t"))
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
187
196
|
def execute_pattern(pattern_ref, shell, fact_set)
|
188
197
|
shell_session = shell.session
|
189
198
|
hostname = fact_set.hostname
|
@@ -218,7 +227,11 @@ module Loom
|
|
218
227
|
run_failure
|
219
228
|
end
|
220
229
|
|
221
|
-
|
230
|
+
def log_token(pattern_ref, hostname)
|
231
|
+
slug = pattern_ref.slug
|
232
|
+
"[#{hostname} => #{slug}]"
|
233
|
+
end
|
234
|
+
|
222
235
|
def handle_host_failure_strategy(hostname, failure_summary=nil)
|
223
236
|
failure_strategy = @loom_config.run_failure_strategy.to_sym
|
224
237
|
|
data/lib/loom/shell/api.rb
CHANGED
@@ -20,14 +20,14 @@ module Loom::Shell
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# This is the entry point for `loom.foo` calls from .loom files.
|
23
|
-
def method_missing(name, *args, &block)
|
24
|
-
Loom.log.debug3(self) { "shell api => #{name} #{args} #{block}" }
|
23
|
+
def method_missing(name, *args, **kwargs, &block)
|
24
|
+
Loom.log.debug3(self) { "shell api => #{name} #{args} #{kwargs} #{block}" }
|
25
25
|
# TODO: The relationship between shell and mod_loader seems leaky here, a
|
26
26
|
# Shell::Api should have a shell and not care about the mod_loader,
|
27
27
|
# currently it seems to violate Demeter. The shell should dispatch to the
|
28
28
|
# mod_loader only as an implementation detail. Otherwise this is harder to
|
29
29
|
# test.
|
30
|
-
@mod_loader.send name, @shell, *args, &block
|
30
|
+
@mod_loader.send name, @shell, *args, **kwargs, &block
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "shellwords"
|
1
|
+
require "shellwords"
|
2
2
|
|
3
3
|
module Loom::Shell
|
4
4
|
|
@@ -27,7 +27,7 @@ module Loom::Shell
|
|
27
27
|
parts
|
28
28
|
end
|
29
29
|
end
|
30
|
-
CmdWrapper.new *cmd_parts.flatten, {
|
30
|
+
CmdWrapper.new *cmd_parts.flatten, **{
|
31
31
|
:should_quote => should_quote,
|
32
32
|
:is_wrapped => true
|
33
33
|
}
|
@@ -39,6 +39,9 @@ module Loom::Shell
|
|
39
39
|
# @param :redirc [Array<CmdRedirect>] STDIO redirection for the command
|
40
40
|
# in quotes.
|
41
41
|
def initialize(*cmd, should_quote: false, is_wrapped: false, redirect: [])
|
42
|
+
if cmd.last.is_a?(Hash)
|
43
|
+
raise ArgumentError.new "kwargs mixed into cmd"
|
44
|
+
end
|
42
45
|
@cmd_parts = cmd.flatten
|
43
46
|
@should_quote = should_quote
|
44
47
|
@is_wrapped = is_wrapped
|
data/lib/loom/shell/core.rb
CHANGED
@@ -168,22 +168,22 @@ module Loom::Shell
|
|
168
168
|
cmd_parts.compact!
|
169
169
|
raise "empty command passed to execute" if cmd_parts.empty?
|
170
170
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
Loom.log.debug
|
185
|
-
Loom.log.debug
|
186
|
-
|
171
|
+
sshkit_result = if @dry_run
|
172
|
+
wrap(:printf, first: true) do
|
173
|
+
r = execute_internal(*cmd_parts, **cmd_opts)
|
174
|
+
Loom.log.info { "\t%s" % prompt_fmt(r.full_stdout.strip) }
|
175
|
+
r
|
176
|
+
end
|
177
|
+
else
|
178
|
+
execute_internal(*cmd_parts, **cmd_opts)
|
179
|
+
end
|
180
|
+
result =
|
181
|
+
CmdResult.create_from_sshkit_command(sshkit_result, is_test, self)
|
182
|
+
|
183
|
+
@session << result
|
184
|
+
Loom.log.debug result.stdout unless result.stdout.empty?
|
185
|
+
Loom.log.debug result.stderr unless result.stderr.empty?
|
186
|
+
result
|
187
187
|
end
|
188
188
|
alias_method :exec, :execute
|
189
189
|
|
data/lib/loom/shell.rb
CHANGED
@@ -3,8 +3,10 @@ module Loom
|
|
3
3
|
|
4
4
|
VerifyError = Class.new Loom::LoomError
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
class << self
|
7
|
+
def create(mod_loader, sshkit_backend, dry_run, no_exec: false)
|
8
|
+
Loom::Shell::Core.new mod_loader, sshkit_backend, dry_run
|
9
|
+
end
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
data/lib/loom/version.rb
CHANGED