loom-core 0.0.4 → 0.0.5
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/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
|