loom-core 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/bin/loom +13 -4
- data/lib/loom/config.rb +2 -0
- data/lib/loom/dsl.rb +5 -0
- data/lib/loom/facts/fact_set.rb +23 -2
- data/lib/loom/pattern/definition_context.rb +15 -4
- data/lib/loom/pattern/dsl.rb +167 -43
- data/lib/loom/pattern/reference.rb +5 -1
- data/lib/loom/runner.rb +27 -6
- data/lib/loom/shell/core.rb +3 -0
- data/lib/loom/version.rb +1 -1
- data/lib/loomext/coremods/exec.rb +2 -0
- data/lib/loomext/coremods/package/adapter.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dd2b1e4959e4556b67f1369c3e8de87bdca21c0082ec446d629319cc58ee748
|
4
|
+
data.tar.gz: edb2d6b2f14a01549b6b75820cf3d456d401fb396f7c13469b812922ae700e2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8459bc0b442c21f59217a8d4646418c17a82a77fa0321f56f1877e8892bc84be56ee16043f9fc362acd437b713296c66f3a8542df0fe9be64c9a08070453bf55
|
7
|
+
data.tar.gz: 3fb25060598c49d64efcc60e23a44e1ca927304ae861ddf45baa3ded0481da9da8d0f40f358b7c2e8df4c6ec2a1bf9cb2f017285cb0cf63a8ade311d7b149282
|
data/Gemfile.lock
CHANGED
data/bin/loom
CHANGED
@@ -19,10 +19,13 @@ module Loom
|
|
19
19
|
program :name, "Loom - Weaving through infrastructure"
|
20
20
|
program :version , Loom::VERSION
|
21
21
|
program :description, <<EOS
|
22
|
-
A lightweight infrastructure managment tool
|
23
|
-
|
22
|
+
A lightweight infrastructure managment tool for managing hosts through SSH,
|
23
|
+
inspired by [Python Fabric](http://www.fabfile.org/) with thanks and nods
|
24
|
+
[Capistrano](https://capistranorb.com/).
|
24
25
|
|
25
26
|
Try `loom weave uptime -H localhost` to see an example.
|
27
|
+
|
28
|
+
Want to know how loom works? @see lib/loom/pattern/dsl.rb
|
26
29
|
EOS
|
27
30
|
|
28
31
|
global_option "-V", "--verbose", "Report verbose results" do |v|
|
@@ -38,8 +41,12 @@ EOS
|
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
|
-
global_option
|
42
|
-
|
44
|
+
global_option("--dbg [N]", Integer, <<EOS
|
45
|
+
Enables deep debug logging, where N is 1-6, implies --verbose. The difference
|
46
|
+
between -d and --dbg is the former is intended for site.loom authors and the
|
47
|
+
latter for authors looking to inspect loom internals.
|
48
|
+
EOS
|
49
|
+
) do |n|
|
43
50
|
raise "N must be greater than 0" if n < 0
|
44
51
|
Loom.configure do |c|
|
45
52
|
c.log_level = n * -1
|
@@ -116,12 +123,14 @@ EOS
|
|
116
123
|
puts "Loom mods are:"
|
117
124
|
puts ""
|
118
125
|
|
126
|
+
# TODO: I think this is broken... fix this.
|
119
127
|
Loom::Mods::ModLoader.registered_mods.each do |name, aliases|
|
120
128
|
puts aliases.join(", ")
|
121
129
|
puts "\t#{name}"
|
122
130
|
end
|
123
131
|
end
|
124
132
|
end
|
133
|
+
alias_command :"m", "mods"
|
125
134
|
|
126
135
|
command :"patterns" do |c|
|
127
136
|
c.syntax = "loom patterns [pattern]"
|
data/lib/loom/config.rb
CHANGED
@@ -7,6 +7,8 @@ module Loom
|
|
7
7
|
|
8
8
|
class Config
|
9
9
|
|
10
|
+
# TODO: Add a more module config_var registry mechanism for Modules and
|
11
|
+
# FactProviders to register their own values & defaults.
|
10
12
|
CONFIG_VARS = {
|
11
13
|
:loom_search_paths => ['/etc/loom', File.join(ENV['HOME'], '.loom'), './.loom'],
|
12
14
|
:loom_files => ['site.loom'],
|
data/lib/loom/dsl.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'socket'
|
2
2
|
|
3
|
+
##
|
4
|
+
# Links to relevant SSHKit code:
|
5
|
+
# https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/abstract.rb
|
6
|
+
# https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/netssh.rb
|
7
|
+
# https://github.com/capistrano/sshkit/blob/master/lib/sshkit/backends/local.rb
|
3
8
|
module Loom
|
4
9
|
|
5
10
|
# TODO: Rename this to something like SSHKitWrapper, DSL is a
|
data/lib/loom/facts/fact_set.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module Loom::Facts
|
2
2
|
|
3
|
+
EMPTY = {}
|
4
|
+
class << EMPTY
|
5
|
+
def [](*args)
|
6
|
+
self
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
3
10
|
##
|
4
11
|
# A factset is created by running each registered Loom::Facts::Provider and
|
5
12
|
# calling Provider+collect_facts+. See ./fact_file_provider.rb and
|
@@ -79,14 +86,28 @@ module Loom::Facts
|
|
79
86
|
end
|
80
87
|
|
81
88
|
def hostname
|
89
|
+
Loom.log.debug(<<NB
|
90
|
+
`facts.hostname ` is actually the name by which SSH knows the host, not
|
91
|
+
necessarily the actual host name. e.g. it may be an ip address, /etc/hosts
|
92
|
+
alias, or ssh config alias. Use `facts.sshname` for the same value without this
|
93
|
+
warning.
|
94
|
+
NB
|
95
|
+
)
|
96
|
+
sshname
|
97
|
+
end
|
98
|
+
|
99
|
+
def sshname
|
82
100
|
host_spec.hostname
|
83
101
|
end
|
84
102
|
|
85
103
|
def get(fact_name)
|
86
104
|
v = @fact_map[fact_name.to_sym]
|
87
105
|
dup = v.dup rescue v
|
88
|
-
|
89
|
-
|
106
|
+
if dup.nil?
|
107
|
+
EMPTY
|
108
|
+
else
|
109
|
+
dup
|
110
|
+
end
|
90
111
|
end
|
91
112
|
alias_method :[], :get
|
92
113
|
|
@@ -6,6 +6,8 @@ module Loom::Pattern
|
|
6
6
|
# includes all contexts of parent modules.
|
7
7
|
class DefinitionContext
|
8
8
|
|
9
|
+
NilLetValueError = Class.new Loom::LoomError
|
10
|
+
|
9
11
|
def initialize(pattern_module, parent_context=nil)
|
10
12
|
@fact_map = pattern_module.facts.dup
|
11
13
|
@let_map = pattern_module.let_map.dup
|
@@ -26,7 +28,9 @@ module Loom::Pattern
|
|
26
28
|
host_fact_set.merge merged_fact_map
|
27
29
|
end
|
28
30
|
|
29
|
-
# TODO: #define_let_readers is a TERRIBLE name. Rename this method.
|
31
|
+
# TODO: #define_let_readers is a TERRIBLE name. Rename this method. Also
|
32
|
+
# consider moving the instance_exec call to inside RunContext, it's a bit
|
33
|
+
# misplaced here.
|
30
34
|
#
|
31
35
|
# The method is called by Reference#call with the Reference::RunContext
|
32
36
|
# instance. The "let" defined local declarations are added as method
|
@@ -34,9 +38,16 @@ module Loom::Pattern
|
|
34
38
|
# let definitions, merged from the associated module, up the namespace
|
35
39
|
# graph, allowing for inheriting and overriding +let+ declarations.
|
36
40
|
def define_let_readers(scope_object, fact_set)
|
37
|
-
@merged_let_map.each do |let_key,
|
38
|
-
|
39
|
-
value = scope_object.instance_exec fact_set, &block
|
41
|
+
@merged_let_map.each do |let_key, let_map_entry|
|
42
|
+
Loom.log.debug { "evaluating let expression[:#{let_key}]" }
|
43
|
+
value = scope_object.instance_exec fact_set, &let_map_entry.block
|
44
|
+
value = value.nil? ? let_map_entry.default : value
|
45
|
+
Loom.log.debug1(self) { "let[:#{let_key}] => #{value}" }
|
46
|
+
|
47
|
+
if value.nil? || value.equal?(Loom::Facts::EMPTY)
|
48
|
+
Loom.log.e "value of let expression[:#{let_key}] is nil"
|
49
|
+
raise NilLetValueError, let_key
|
50
|
+
end
|
40
51
|
scope_object.define_singleton_method(let_key) { value }
|
41
52
|
end
|
42
53
|
end
|
data/lib/loom/pattern/dsl.rb
CHANGED
@@ -1,23 +1,43 @@
|
|
1
1
|
=begin
|
2
2
|
|
3
|
-
#
|
3
|
+
# TODO: DSL extensions:
|
4
|
+
- Pattern+non_idempotent+ marks a pattern as explicitly not idempotent, this
|
5
|
+
let's additional warnings and checks to be added
|
6
|
+
- A history module, store a log of each executed command, a hash of the .loom
|
7
|
+
file, and the requisite facts (the let declarations) for each executed pattern
|
8
|
+
on the host it executes. /var/log/loom/history? Create this log on startup.
|
9
|
+
-- add a new set of history commands through the CLI and a history
|
10
|
+
FactProvider exposing host/loom/pattern_slug execution stats.
|
11
|
+
- Provide automatic command reversion support with a =Module= DSL that ties in
|
12
|
+
with local revision history.
|
13
|
+
-- allow Module actions/mods to define an "undo" command of itself given the
|
14
|
+
original inputs to the action
|
15
|
+
-- using the history to pull previous params (let defns) into a revert command.
|
16
|
+
-- usages of the raw shell, such as `loom.x` and `loom.capture` would be
|
17
|
+
unsupported. so would accesses to the fact_set in any before/after/pattern
|
18
|
+
blocks.
|
19
|
+
-- however patterns that only used let blocks, and used all "revertable"
|
20
|
+
module methods, could have automatic state reversion and integrity checking
|
21
|
+
managed.
|
22
|
+
-- best practices (encouraged through warnings) to be to heavily discourage
|
23
|
+
uses of loom.execute and loom.capture in .loom files and encourage all
|
24
|
+
accesses to fact_set be done in let expressions (enforce this maybe?)
|
25
|
+
-- Later... before/after hooks can ensure the entire loom execution sequence
|
26
|
+
was "revertable"
|
27
|
+
|
28
|
+
## .loom File DSL
|
29
|
+
|
30
|
+
See specs/test.loom for a valid .loom file.
|
31
|
+
|
32
|
+
I've tried to take inspriation from the RSpec DSL for .loom, so hopefully it
|
33
|
+
feels comfortable.
|
4
34
|
|
5
35
|
Loom::Pattern::DSL is the mixin that defines the declarative API for all .loom
|
6
36
|
file defined modules. It is included into Loom::Pattern by default. The outer
|
7
37
|
most module that a .loom file declares has Loom::Pattern mixed in by
|
8
38
|
default. Submodules must explicitly include Loom::Pattern, and will receive DSL.
|
9
39
|
|
10
|
-
|
11
|
-
|
12
|
-
Loom::Runner#load
|
13
|
-
-> Loom::Pattern::Loader.load
|
14
|
-
-> Loom::Pattern::ReferenceSet.load_from_file
|
15
|
-
-> Loom::Pattern::ReferenceSet::Builder.create
|
16
|
-
|
17
|
-
The Loom::Pattern::ReferenceSet::Builder creates a ReferenceSet from a .loom
|
18
|
-
file. A ReferenseSet being a collection of references with uniquely named
|
19
|
-
slugs. The slug of a reference is computed from the module namespace and
|
20
|
-
instance method name. For example, given the following .loom file:
|
40
|
+
For example, given the following .loom file:
|
21
41
|
|
22
42
|
``` ~ruby
|
23
43
|
def top_level; end
|
@@ -42,13 +62,31 @@ It declares a reference set with slugs:
|
|
42
62
|
|
43
63
|
Defining the same pattern slug twice raises a DuplicatPatternRef error.
|
44
64
|
|
45
|
-
|
46
|
-
|
47
|
-
|
65
|
+
#### Code Details
|
66
|
+
|
67
|
+
To follow the code path for .loom file loading see:
|
68
|
+
|
69
|
+
Loom::Runner#load
|
70
|
+
-> Loom::Pattern::Loader.load
|
71
|
+
-> Loom::Pattern::ReferenceSet.load_from_file
|
72
|
+
-> Loom::Pattern::ReferenceSet::Builder.create
|
73
|
+
|
74
|
+
The Loom::Pattern::ReferenceSet::Builder creates a ReferenceSet from a .loom
|
75
|
+
file. A ReferenseSet being a collection of references with uniquely named
|
76
|
+
slugs. The slug of a reference is computed from the module namespace and
|
77
|
+
instance method name.
|
78
|
+
|
79
|
+
### `let`, `before`, and `after`
|
80
|
+
|
81
|
+
Module::Inner, from above, inherits all +let+ declarations from its outer
|
82
|
+
contexts, both :: (root) and ::Outer. +before+ hooks are run from a top-down
|
83
|
+
module ordering, +after+ hooks are run bottom-up. For example, given the
|
84
|
+
following .loom file:
|
48
85
|
|
49
86
|
``` ~ruby
|
50
87
|
let(:var_1) { "v1 value" }
|
51
88
|
let(:var_2) { "v2 value" }
|
89
|
+
let(:var_3, "otherwise") { |facts| facts[:a] || facts[:b] }
|
52
90
|
|
53
91
|
before { puts "runs first +before+" }
|
54
92
|
after { puts "runs last +after+" }
|
@@ -65,13 +103,19 @@ module Submod
|
|
65
103
|
end
|
66
104
|
```
|
67
105
|
|
68
|
-
|
69
106
|
If running `loom submod:a_pattern`, then let declarations would declare values:
|
70
107
|
|
71
108
|
{ :var_1 => "submod value", :var_2 => "v2 value" }
|
72
109
|
|
110
|
+
:var_3 would be set to either fact :a or fact :b. If the let expression
|
111
|
+
evaluates to nil?, then "otherwise" will be used as a default.
|
112
|
+
|
73
113
|
Each let value is effectively available as an `attr_reader` declaration from
|
74
|
-
::Submod#a_pattern.
|
114
|
+
::Submod#a_pattern. Because the attr_reader is defined on the RunContext scope
|
115
|
+
object, let expressions are available all before/after hooks and pattern
|
116
|
+
expresions.
|
117
|
+
|
118
|
+
Before and After hook ordering with pattern execution would
|
75
119
|
look like:
|
76
120
|
|
77
121
|
=> runs first +before+
|
@@ -83,12 +127,16 @@ look like:
|
|
83
127
|
For the code that executes before hooks, pattern, after hooks see
|
84
128
|
Loom::Pattern::Reference::RunContext#run.
|
85
129
|
|
130
|
+
#### Code Details
|
131
|
+
|
86
132
|
The Loom::Pattern::Reference::RunContext acts as the the binding object for each
|
87
|
-
pattern
|
88
|
-
|
89
|
-
|
133
|
+
pattern. i.e. RunContext is the self object for all the blocks defined in a loom
|
134
|
+
file. Let definitions, before and after hooks, and fact maps are unique to each
|
135
|
+
RunContext, for each RunContext they are defined in the
|
90
136
|
Loom::Pattern::DefinitionContext. Each DefinitionContext is merged from it's
|
91
|
-
parent module, see Loom::Pattern::DefinitionContext#merge_contexts for
|
137
|
+
parent module, see Loom::Pattern::DefinitionContext#merge_contexts for
|
138
|
+
info. Each pattern/host combo gets a unique RunContext instance via
|
139
|
+
Loom::Runner+execute_pattern+ -> Loom::Pattern::Reference+call+.
|
92
140
|
|
93
141
|
The RunContext#run method is the actual execution of the pattern. A pattern,
|
94
142
|
before association to a RunContext instance is an unbound method. During
|
@@ -96,6 +144,71 @@ RunContext#initialize the pattern is bound to the RunContext instance and
|
|
96
144
|
executed during RunContext#run with the associated Loom::Shell::Api and
|
97
145
|
Loom::Facts::FactSet as parameters.
|
98
146
|
|
147
|
+
See Loom::Pattern::DefinitionContext for evaluation of `let` blocks and
|
148
|
+
before/after context ordering.
|
149
|
+
|
150
|
+
### `weave`
|
151
|
+
|
152
|
+
The `weave` keyword allows aliasing a sequence of patterns a single
|
153
|
+
name. Pattern execution will be flattened and run sequentially before or after
|
154
|
+
any other patterns in the `$ loom` invocation.
|
155
|
+
|
156
|
+
``` ~ruby
|
157
|
+
pattern :step_1 { ... }
|
158
|
+
pattern :step_2 { ... }
|
159
|
+
|
160
|
+
weave :do_it, [ :step_1, :step_2 ]
|
161
|
+
```
|
162
|
+
|
163
|
+
This creates pattern :do_it, which when run `$ loom do_it` will run :step_1,
|
164
|
+
:step_2. Recursive expansion is explicitly disallowed, only pattern names (not
|
165
|
+
weaves), are allowed in the 2nd param of `weave`.
|
166
|
+
|
167
|
+
#### Code Details
|
168
|
+
|
169
|
+
Weave expansion to pattern slugs is accomplished by creating a
|
170
|
+
Loom::Pattern::ExpandingReference via the Loom::Pattern::Loader+load+ path
|
171
|
+
invoked via Loom::Runner+load+. Expansion happens on read via
|
172
|
+
Loom::Pattern::Loader+patterns+, thus the list of patterns is constant
|
173
|
+
throughout all phases of pattern execution.
|
174
|
+
|
175
|
+
#### Pattern Execution Phases
|
176
|
+
|
177
|
+
Once hosts and patterns are identified in earlier Loom::Runner phases,
|
178
|
+
Loom::Runner+run_internal+, per host, initiates an SSH session and command
|
179
|
+
execution phases of processing the .loom file. First phase is fact collection
|
180
|
+
via +Loom::Facts.fact_set, see Loom::Facts::FactSet for createing, registering,
|
181
|
+
and executing Loom::Facts::FactProviders.
|
182
|
+
|
183
|
+
The inputs to fact collection are a Loom::Shell::Core, Loom::HostSpec, and
|
184
|
+
Loom::Config. Fact collection must be FAST and idempotent (or as reasonably
|
185
|
+
possible). No network requests should be made during fact colleciton. Fact
|
186
|
+
collection is done prior to EACH pattern/host combination in order to ensure
|
187
|
+
having the newest facts from prevoius pattern executions.
|
188
|
+
|
189
|
+
After fact collection is pattern block execution, including before and after
|
190
|
+
block execution. See comments above for pattern code pointers and other details.
|
191
|
+
|
192
|
+
## Decorating the Loom Object with Custom Modules and FactProviders
|
193
|
+
|
194
|
+
TODO
|
195
|
+
|
196
|
+
See lib/loomext/coremods & lib/loomext/corefacts for examples.
|
197
|
+
|
198
|
+
## Facts and Inventory
|
199
|
+
|
200
|
+
TODO
|
201
|
+
|
202
|
+
## Config
|
203
|
+
|
204
|
+
TODO
|
205
|
+
|
206
|
+
## Logger
|
207
|
+
|
208
|
+
TODO
|
209
|
+
|
210
|
+
##
|
211
|
+
|
99
212
|
=end
|
100
213
|
module Loom::Pattern
|
101
214
|
|
@@ -121,9 +234,11 @@ module Loom::Pattern
|
|
121
234
|
@facts = yield_result if yield_result.is_a? Hash
|
122
235
|
end
|
123
236
|
|
124
|
-
def let(name, &block)
|
237
|
+
def let(name, default: nil, &block)
|
238
|
+
raise "malformed let expression: missing block" unless block_given?
|
239
|
+
|
125
240
|
@let_map ||= {}
|
126
|
-
@let_map[name.to_sym] = block
|
241
|
+
@let_map[name.to_sym] = LetMapEntry.new default, &block
|
127
242
|
end
|
128
243
|
|
129
244
|
def pattern(name, &block)
|
@@ -143,26 +258,6 @@ module Loom::Pattern
|
|
143
258
|
define_pattern_internal(name) { |_, _| true }
|
144
259
|
end
|
145
260
|
|
146
|
-
def define_pattern_internal(name, &block)
|
147
|
-
@pattern_methods ||= []
|
148
|
-
@pattern_method_map ||= {}
|
149
|
-
@pattern_descriptions ||= {}
|
150
|
-
|
151
|
-
method_name = name.to_sym
|
152
|
-
|
153
|
-
@pattern_methods << method_name
|
154
|
-
@pattern_method_map[method_name] = true
|
155
|
-
@pattern_descriptions[method_name] = @next_description
|
156
|
-
@next_description = nil
|
157
|
-
|
158
|
-
define_method method_name, &block
|
159
|
-
end
|
160
|
-
|
161
|
-
def hook(scope, &block)
|
162
|
-
@hooks ||= []
|
163
|
-
@hooks << Hook.new(scope, &block)
|
164
|
-
end
|
165
|
-
|
166
261
|
def before(&block)
|
167
262
|
hook :before, &block
|
168
263
|
end
|
@@ -203,5 +298,34 @@ module Loom::Pattern
|
|
203
298
|
def let_map
|
204
299
|
@let_map || {}
|
205
300
|
end
|
301
|
+
|
302
|
+
private
|
303
|
+
def define_pattern_internal(name, &block)
|
304
|
+
@pattern_methods ||= []
|
305
|
+
@pattern_method_map ||= {}
|
306
|
+
@pattern_descriptions ||= {}
|
307
|
+
|
308
|
+
method_name = name.to_sym
|
309
|
+
|
310
|
+
@pattern_methods << method_name
|
311
|
+
@pattern_method_map[method_name] = true
|
312
|
+
@pattern_descriptions[method_name] = @next_description
|
313
|
+
@next_description = nil
|
314
|
+
|
315
|
+
define_method method_name, &block
|
316
|
+
end
|
317
|
+
|
318
|
+
def hook(scope, &block)
|
319
|
+
@hooks ||= []
|
320
|
+
@hooks << Hook.new(scope, &block)
|
321
|
+
end
|
322
|
+
end # DSL
|
323
|
+
|
324
|
+
class LetMapEntry
|
325
|
+
attr_reader :default, :block
|
326
|
+
def initialize(default, &block)
|
327
|
+
@default = default
|
328
|
+
@block = block
|
329
|
+
end
|
206
330
|
end
|
207
331
|
end
|
@@ -19,8 +19,12 @@ module Loom::Pattern
|
|
19
19
|
run_context = RunContext.new @unbound_method, @definition_ctx
|
20
20
|
|
21
21
|
fact_set = @definition_ctx.fact_set host_fact_set
|
22
|
-
Loom.log.debug5(self) {
|
22
|
+
Loom.log.debug5(self) {
|
23
|
+
"fact set for pattern execution => #{fact_set.facts}" }
|
23
24
|
|
25
|
+
# TODO: wrap up this fact_set in a delegator/facade/proxy to eliminate the
|
26
|
+
# .loom file from directly accessing it. Add logging and deprecation
|
27
|
+
# warnings there.... like FactSet+hostname+ currently.
|
24
28
|
@definition_ctx.define_let_readers run_context, fact_set
|
25
29
|
|
26
30
|
begin
|
data/lib/loom/runner.rb
CHANGED
@@ -59,11 +59,21 @@ module Loom
|
|
59
59
|
exit code
|
60
60
|
rescue PatternExecutionError => e
|
61
61
|
num_patterns_failed = @run_failures.size
|
62
|
-
Loom.log.error "error executing #{num_patterns_failed} patterns => #{e}"
|
63
|
-
Loom.log.debug e.backtrace.join "\n"
|
62
|
+
Loom.log.error "error executing #{num_patterns_failed} patterns => #{e}, run with -d for more"
|
63
|
+
Loom.log.debug e.backtrace.join "\n\t"
|
64
|
+
# TODO: I think the max return code is 255. Cap this if so.
|
64
65
|
exit 100 + num_patterns_failed
|
66
|
+
rescue SSHKit::Runner::ExecuteError => e
|
67
|
+
Loom.log.error "wrapped SSHKit::Runner::ExecuteError, run with -d for more"
|
68
|
+
Loom.log.error e.cause
|
69
|
+
Loom.log.debug e.cause.backtrace.join "\n\t"
|
70
|
+
Loom.log.debug1(self) { "Original error:" }
|
71
|
+
Loom.log.debug1(self) { e.inspect }
|
72
|
+
Loom.log.debug1(self) { e.backtrace.join "\n\t" }
|
73
|
+
exit 97
|
65
74
|
rescue Loom::LoomError => e
|
66
|
-
Loom.log.error "
|
75
|
+
Loom.log.error "Loom::LoomError => #{e.inspect}, run with -d for more"
|
76
|
+
Loom.log.debug e.cause.backtrace.join "\n\t"
|
67
77
|
exit 98
|
68
78
|
rescue => e
|
69
79
|
Loom.log.fatal "fatal error => #{e.inspect}"
|
@@ -99,6 +109,8 @@ module Loom
|
|
99
109
|
Loom::Inventory::InventoryList.active_inventory @loom_config
|
100
110
|
@active_hosts = @inventory_list.hosts
|
101
111
|
|
112
|
+
# TODO: the naming inconsistency between Pattern::Loader and
|
113
|
+
# Mods::ModLoader bothers me... :(
|
102
114
|
pattern_loader = Loom::Pattern::Loader.load @loom_config
|
103
115
|
@pattern_refs = pattern_loader.patterns @pattern_slugs
|
104
116
|
|
@@ -141,11 +153,18 @@ module Loom
|
|
141
153
|
pattern_shell = Loom::Shell.create @mod_loader, sshkit_backend, dry_run
|
142
154
|
|
143
155
|
Loom.log.warn "dry run only => #{pattern_description}" if dry_run
|
144
|
-
execute_pattern pattern_ref, pattern_shell, fact_set
|
156
|
+
failures = execute_pattern pattern_ref, pattern_shell, fact_set
|
157
|
+
|
158
|
+
if failures.empty?
|
159
|
+
Loom.log.debug "success on => #{pattern_description}"
|
160
|
+
else
|
161
|
+
Loom.log.error "failures on => #{pattern_description}:\n\t%s" % (
|
162
|
+
failures.join("\n\t"))
|
163
|
+
end
|
145
164
|
end
|
146
165
|
rescue IOError => e
|
147
|
-
# TODO: Try to patch SSHKit for a more specific error for unexpected
|
148
|
-
# disconnections
|
166
|
+
# TODO: Try to patch SSHKit for a more specific error for unexpected
|
167
|
+
# SSH disconnections
|
149
168
|
Loom.log.error "unexpected SSH disconnect => #{hostname}"
|
150
169
|
Loom.log.debug e
|
151
170
|
handle_host_failure_strategy hostname, e.message
|
@@ -168,6 +187,7 @@ module Loom
|
|
168
187
|
# when a command fails and pattern execution should stop. All errors
|
169
188
|
# should come from exceptions. This needs to be thought about wrt to the
|
170
189
|
# defined `failure_strategy`
|
190
|
+
# @see the TODO at Loom::Shell::Core+test+
|
171
191
|
run_failure = []
|
172
192
|
begin
|
173
193
|
pattern_ref.call(shell.shell_api, fact_set)
|
@@ -187,6 +207,7 @@ module Loom
|
|
187
207
|
@result_reports << result_reporter
|
188
208
|
@run_failures << run_failure unless run_failure.empty?
|
189
209
|
end
|
210
|
+
run_failure
|
190
211
|
end
|
191
212
|
|
192
213
|
private
|
data/lib/loom/shell/core.rb
CHANGED
@@ -40,6 +40,7 @@ module Loom::Shell
|
|
40
40
|
# objects and declare style of reporting & error code handling it
|
41
41
|
# has. Commands can be defined to ignore errors and just return their
|
42
42
|
# results.
|
43
|
+
# @see the TODO at Loom::Runner+execute_pattern+
|
43
44
|
execute *cmd, :is_test => true, **cmd_opts
|
44
45
|
|
45
46
|
case check
|
@@ -100,6 +101,8 @@ module Loom::Shell
|
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
104
|
+
# TODO: finish the harness... avoiding dealing w/ shell escaping, like
|
105
|
+
# from sudo, is the goal.
|
103
106
|
# def sudo(user=nil, *sudo_cmd, &block)
|
104
107
|
# # I'm trying to work around crappy double escaping issues caused by
|
105
108
|
# # sudo_legacy... but I'm failing
|
data/lib/loom/version.rb
CHANGED
@@ -7,6 +7,8 @@ module LoomExt::CoreMods
|
|
7
7
|
#
|
8
8
|
# loom << :echo, "hello there"
|
9
9
|
class Exec < Loom::Mods::Module
|
10
|
+
# TODO: add an "example" DSL to Loom::Mods::Module to automate
|
11
|
+
# documentation.
|
10
12
|
register_mod :exec, :alias => [:x, :<<] do |*cmd, **opts|
|
11
13
|
shell.execute *cmd, **opts
|
12
14
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: loom-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erick Johnson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sshkit
|