loom-core 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +99 -0
  6. data/Guardfile +54 -0
  7. data/Rakefile +6 -0
  8. data/bin/loom +185 -0
  9. data/lib/env/development.rb +1 -0
  10. data/lib/loom.rb +44 -0
  11. data/lib/loom/all.rb +20 -0
  12. data/lib/loom/config.rb +106 -0
  13. data/lib/loom/core_ext.rb +37 -0
  14. data/lib/loom/dsl.rb +60 -0
  15. data/lib/loom/facts.rb +13 -0
  16. data/lib/loom/facts/all.rb +2 -0
  17. data/lib/loom/facts/fact_file_provider.rb +86 -0
  18. data/lib/loom/facts/fact_set.rb +138 -0
  19. data/lib/loom/host_spec.rb +32 -0
  20. data/lib/loom/inventory.rb +124 -0
  21. data/lib/loom/logger.rb +141 -0
  22. data/lib/loom/method_signature.rb +174 -0
  23. data/lib/loom/mods.rb +4 -0
  24. data/lib/loom/mods/action_proxy.rb +105 -0
  25. data/lib/loom/mods/all.rb +3 -0
  26. data/lib/loom/mods/mod_loader.rb +80 -0
  27. data/lib/loom/mods/module.rb +113 -0
  28. data/lib/loom/pattern.rb +15 -0
  29. data/lib/loom/pattern/all.rb +7 -0
  30. data/lib/loom/pattern/definition_context.rb +74 -0
  31. data/lib/loom/pattern/dsl.rb +176 -0
  32. data/lib/loom/pattern/hook.rb +28 -0
  33. data/lib/loom/pattern/loader.rb +48 -0
  34. data/lib/loom/pattern/reference.rb +71 -0
  35. data/lib/loom/pattern/reference_set.rb +169 -0
  36. data/lib/loom/pattern/result_reporter.rb +77 -0
  37. data/lib/loom/runner.rb +209 -0
  38. data/lib/loom/shell.rb +12 -0
  39. data/lib/loom/shell/all.rb +10 -0
  40. data/lib/loom/shell/api.rb +48 -0
  41. data/lib/loom/shell/cmd_result.rb +33 -0
  42. data/lib/loom/shell/cmd_wrapper.rb +164 -0
  43. data/lib/loom/shell/core.rb +226 -0
  44. data/lib/loom/shell/harness_blob.rb +26 -0
  45. data/lib/loom/shell/harness_command_builder.rb +50 -0
  46. data/lib/loom/shell/session.rb +25 -0
  47. data/lib/loom/trap.rb +44 -0
  48. data/lib/loom/version.rb +3 -0
  49. data/lib/loomext/all.rb +4 -0
  50. data/lib/loomext/corefacts.rb +6 -0
  51. data/lib/loomext/corefacts/all.rb +8 -0
  52. data/lib/loomext/corefacts/facter_provider.rb +24 -0
  53. data/lib/loomext/coremods.rb +5 -0
  54. data/lib/loomext/coremods/all.rb +13 -0
  55. data/lib/loomext/coremods/exec.rb +50 -0
  56. data/lib/loomext/coremods/files.rb +104 -0
  57. data/lib/loomext/coremods/net.rb +33 -0
  58. data/lib/loomext/coremods/package/adapter.rb +100 -0
  59. data/lib/loomext/coremods/package/package.rb +62 -0
  60. data/lib/loomext/coremods/user.rb +82 -0
  61. data/lib/loomext/coremods/vm.rb +0 -0
  62. data/lib/loomext/coremods/vm/all.rb +6 -0
  63. data/lib/loomext/coremods/vm/vbox.rb +84 -0
  64. data/loom.gemspec +39 -0
  65. data/loom/inventory.yml +13 -0
  66. data/scripts/harness.sh +242 -0
  67. data/spec/loom/host_spec_spec.rb +101 -0
  68. data/spec/loom/inventory_spec.rb +154 -0
  69. data/spec/loom/method_signature_spec.rb +275 -0
  70. data/spec/loom/pattern/dsl_spec.rb +207 -0
  71. data/spec/loom/shell/cmd_wrapper_spec.rb +239 -0
  72. data/spec/loom/shell/harness_blob_spec.rb +42 -0
  73. data/spec/loom/shell/harness_command_builder_spec.rb +36 -0
  74. data/spec/runloom.sh +35 -0
  75. data/spec/scripts/harness_spec.rb +385 -0
  76. data/spec/spec_helper.rb +94 -0
  77. data/spec/test.loom +370 -0
  78. data/spec/test_loom_spec.rb +57 -0
  79. metadata +287 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '00595d8a3c27f3c3a2567849e6d188c68a3c5914646238f0009767bff5769687'
4
+ data.tar.gz: 1988e1d88027c87309183db5355a2167f46ef2c48efcde7d5d143daf04011ea3
5
+ SHA512:
6
+ metadata.gz: a48f5d6d82ec87da2c8e0dca0107602a434f8e4d8f42e1eb5d4d5638106aea1733836745d91db52f497b0eb4d2b9812909a42e9aef10a6408a26b23cb227758c
7
+ data.tar.gz: dc23a63efd9405c7834911e66a709f944793e8b9bca62858e0a86864f999d0d8e942a21f9bda9893bd2672291806205d0b7e752cb9dbe70e0b2854630434bb97
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ loom-core (0.0.1)
5
+ bcrypt_pbkdf (= 1.0.0.alpha1)
6
+ commander (~> 4.4)
7
+ net-ssh (>= 3)
8
+ rbnacl-libsodium (= 1.0.10)
9
+ sshkit (~> 1.11)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ bcrypt_pbkdf (1.0.0.alpha1)
15
+ byebug (9.0.6)
16
+ coderay (1.1.1)
17
+ commander (4.4.0)
18
+ highline (~> 1.7.2)
19
+ diff-lcs (1.2.5)
20
+ ffi (1.9.14)
21
+ formatador (0.2.5)
22
+ guard (2.14.0)
23
+ formatador (>= 0.2.4)
24
+ listen (>= 2.7, < 4.0)
25
+ lumberjack (~> 1.0)
26
+ nenv (~> 0.1)
27
+ notiffany (~> 0.0)
28
+ pry (>= 0.9.12)
29
+ shellany (~> 0.0)
30
+ thor (>= 0.18.1)
31
+ guard-compat (1.2.1)
32
+ guard-rspec (4.7.3)
33
+ guard (~> 2.1)
34
+ guard-compat (~> 1.1)
35
+ rspec (>= 2.99.0, < 4.0)
36
+ highline (1.7.8)
37
+ listen (3.1.5)
38
+ rb-fsevent (~> 0.9, >= 0.9.4)
39
+ rb-inotify (~> 0.9, >= 0.9.7)
40
+ ruby_dep (~> 1.2)
41
+ lumberjack (1.0.10)
42
+ method_source (0.8.2)
43
+ nenv (0.3.0)
44
+ net-scp (1.2.1)
45
+ net-ssh (>= 2.6.5)
46
+ net-ssh (3.2.0)
47
+ notiffany (0.1.1)
48
+ nenv (~> 0.1)
49
+ shellany (~> 0.0)
50
+ pry (0.10.4)
51
+ coderay (~> 1.1.0)
52
+ method_source (~> 0.8.1)
53
+ slop (~> 3.4)
54
+ pry-byebug (3.4.0)
55
+ byebug (~> 9.0)
56
+ pry (~> 0.10)
57
+ rake (11.3.0)
58
+ rb-fsevent (0.9.8)
59
+ rb-inotify (0.9.7)
60
+ ffi (>= 0.5.0)
61
+ rbnacl (3.4.0)
62
+ ffi
63
+ rbnacl-libsodium (1.0.10)
64
+ rbnacl (>= 3.0.1)
65
+ rspec (3.5.0)
66
+ rspec-core (~> 3.5.0)
67
+ rspec-expectations (~> 3.5.0)
68
+ rspec-mocks (~> 3.5.0)
69
+ rspec-core (3.5.4)
70
+ rspec-support (~> 3.5.0)
71
+ rspec-expectations (3.5.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.5.0)
74
+ rspec-mocks (3.5.0)
75
+ diff-lcs (>= 1.2.0, < 2.0)
76
+ rspec-support (~> 3.5.0)
77
+ rspec-support (3.5.0)
78
+ ruby_dep (1.5.0)
79
+ shellany (0.0.1)
80
+ slop (3.6.0)
81
+ sshkit (1.11.4)
82
+ net-scp (>= 1.1.2)
83
+ net-ssh (>= 2.8.0)
84
+ thor (0.19.1)
85
+
86
+ PLATFORMS
87
+ ruby
88
+
89
+ DEPENDENCIES
90
+ bundler (~> 1.13)
91
+ guard-rspec (~> 4.7)
92
+ loom-core!
93
+ pry (~> 0.10)
94
+ pry-byebug
95
+ rake (~> 11.3)
96
+ rspec (~> 3.5)
97
+
98
+ BUNDLED WITH
99
+ 1.13.6
data/Guardfile ADDED
@@ -0,0 +1,54 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ # Note: The cmd option is now required due to the increasing number of ways
19
+ # rspec may be run, below are examples of the most common uses.
20
+ # * bundler: 'bundle exec rspec'
21
+ # * bundler binstubs: 'bin/rspec'
22
+ # * spring: 'bin/rspec' (This will use spring if running and you have
23
+ # installed the spring binstubs per the docs)
24
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
25
+ # * 'just' rspec: 'rspec'
26
+
27
+ guard :rspec, cmd: "bundle exec rspec" do
28
+ require "guard/rspec/dsl"
29
+ dsl = Guard::RSpec::Dsl.new(self)
30
+
31
+ # Explicitly speficy emacs in order to disable notify-send notifications
32
+ notification :emacs
33
+
34
+ # Feel free to open issues for suggestions and improvements
35
+
36
+ # RSpec files
37
+ rspec = dsl.rspec
38
+ watch(rspec.spec_helper) { rspec.spec_dir }
39
+ watch(rspec.spec_support) { rspec.spec_dir }
40
+ watch(rspec.spec_files)
41
+
42
+ # Ruby files
43
+ ruby = dsl.ruby
44
+ dsl.watch_spec_files_for(ruby.lib_files)
45
+
46
+ # Loom shell scripts
47
+ watch(%r{^scripts/(.+)\.sh$}) { |m| "spec/scripts/#{m[1]}_spec.rb" }
48
+
49
+ # Turnip features and steps
50
+ watch(%r{^spec/acceptance/(.+)\.feature$})
51
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
52
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
53
+ end
54
+ end
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/loom ADDED
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env ruby
2
+ if __FILE__ == $0
3
+ # for local development, when running bin/loom directly
4
+ $: << 'lib'
5
+ end
6
+
7
+ require 'commander'
8
+ require 'loom'
9
+
10
+ Loom.configure do |c|
11
+ c.log_level = :info
12
+ end
13
+
14
+ module Loom
15
+ class Cli
16
+ include Commander::Methods
17
+
18
+ def run
19
+ program :name, "Loom - Weaving through infrastructure"
20
+ program :version , Loom::VERSION
21
+ program :description, <<EOS
22
+ A lightweight infrastructure managment tool designed to manage hosts
23
+ through SSH, loosely inspired by Python Fabric - http://www.fabfile.org/.
24
+
25
+ Try `loom weave uptime -H localhost` to see an example.
26
+ EOS
27
+
28
+ global_option "-V", "--verbose", "Report verbose results" do |v|
29
+ Loom.configure do |c|
30
+ c.run_verbose = v
31
+ end
32
+ end
33
+
34
+ global_option "-d", "Enable loom debug logging, implies --verbose" do |d|
35
+ Loom.configure do |c|
36
+ c.log_level = :debug
37
+ c.run_verbose = true
38
+ end
39
+ end
40
+
41
+ global_option "--dbg [N]", Integer,
42
+ "Enable deep debug logging, where N is 0-6, implies --verbose" do |n|
43
+ raise "N must be greater than 0" if n < 0
44
+ Loom.configure do |c|
45
+ c.log_level = n * -1
46
+ c.run_verbose = true
47
+ end
48
+ end
49
+
50
+ global_option "-l", "--loom-files file1,f2,f3", Array,
51
+ "Load loom files from FILES instead of from the search path." do |files|
52
+ Loom.configure { |c| c.loom_files = files }
53
+ end
54
+
55
+ global_option "-a", "--all-hosts",
56
+ "Adds all known hostnames to the active inventory, " +
57
+ "can be combined with -H for additional hosts" do |flag|
58
+ Loom.configure { |c| c.inventory_all_hosts = flag }
59
+ end
60
+
61
+ global_option "-H", "--hosts host1,h2,h3", Array,
62
+ "Adds HOSTS to the active inventory" do |hosts|
63
+ Loom.configure { |c| c.inventory_hosts = hosts }
64
+ end
65
+
66
+ global_option "-G", "--groups group1,g2,g3", Array,
67
+ "Adds hostnames in GROUPS to the active inventory" do |groups|
68
+ Loom.configure { |c| c.inventory_groups = groups }
69
+ end
70
+
71
+ global_option "-X", "--custom-config KEY=VAL", String do |config_value|
72
+ key, val, *_rest = config_value.split "="
73
+ Loom.configure do |c|
74
+ c[key.to_sym] = val
75
+ end
76
+ end
77
+
78
+ default_command :weave
79
+
80
+ command :"weave" do |c|
81
+ c.syntax = "loom weave [pattern...] [options]"
82
+ c.description = "Applies the patterns to the active host inventory. " +
83
+ "This is the default."
84
+
85
+ c.option "-A", "--all",
86
+ "Run all loaded the patterns"
87
+ c.option "-n", "--dry-run",
88
+ "Don't run the patterns, only connect and log the expected patterns"
89
+ c.option "-F", "--fact F1=V1[,F2=V2,F3=V3]]]", "add custom fact"
90
+
91
+ c.action do |patterns, options|
92
+ if options.all
93
+ patterns = Loom::Pattern::Loader.load(Loom.config).slugs
94
+ end
95
+
96
+ other_facts = {}
97
+ if options.fact
98
+ fact_pairs = options.fact.split ","
99
+ fact_pairs.each do |pair|
100
+ key, val = pair.split "="
101
+ other_facts[key.to_sym] = val
102
+ end
103
+ end
104
+
105
+ runner = Loom::Runner.new Loom.config, patterns, other_facts
106
+ runner.run options.dry_run
107
+ end
108
+ end
109
+ alias_command :"w", :"weave"
110
+
111
+ command :"mods" do |c|
112
+ c.syntax = "loom mods [mod]"
113
+ c.description = "Prints the list of registered mods."
114
+
115
+ c.action do |mods, options|
116
+ puts "Loom mods are:"
117
+ puts ""
118
+
119
+ Loom::Mods::ModLoader.registered_mods.each do |name, aliases|
120
+ puts aliases.join(", ")
121
+ puts "\t#{name}"
122
+ end
123
+ end
124
+ end
125
+
126
+ command :"patterns" do |c|
127
+ c.syntax = "loom patterns [pattern]"
128
+ c.description = "Prints the list of known patterns."
129
+
130
+ c.option "--print", "Only print the space separted pattern names."
131
+ c.action do |patterns, options|
132
+ pattern_loader = Loom::Pattern::Loader.load Loom.config
133
+ pattern_slugs = pattern_loader.slugs
134
+ if options.print
135
+ puts pattern_slugs.join " "
136
+ return
137
+ end
138
+
139
+ puts "Loom patterns are:"
140
+ puts ""
141
+
142
+ max_slug_len = pattern_slugs.map(&:size).reduce(0) { |*args| args.max }
143
+ pattern_loader.patterns.each do |ref|
144
+ puts "\t#{ref.slug.ljust(max_slug_len)}\t#{ref.desc}"
145
+ end
146
+ end
147
+ end
148
+ alias_command :"p", :"patterns"
149
+
150
+ command :"config" do |c|
151
+ c.syntax = "loom config [options]"
152
+ c.description = "Print the config."
153
+ c.action do
154
+ puts Loom.config.to_yaml
155
+ end
156
+ end
157
+ alias_command :"c", :"config"
158
+
159
+ command :"inventory" do |c|
160
+ c.syntax = "loom inventory [options]"
161
+ c.description = "List all hosts in the inventory."
162
+
163
+ c.option "--active", <<EOS
164
+ Restricts to the hosts in the active inventory, useful to check which
165
+ hosts will be targeted with the config. Using with the -a flag is
166
+ equivalent to omitting --active.
167
+ EOS
168
+
169
+ c.action do |arg, options|
170
+ inventory = if options.active
171
+ Loom::Inventory::InventoryList.active_inventory Loom.config
172
+ else
173
+ Loom::Inventory::InventoryList.total_inventory Loom.config
174
+ end
175
+ puts inventory.hostnames.sort.to_yaml
176
+ end
177
+ end
178
+ alias_command :"i", :"inventory"
179
+
180
+ run!
181
+ end
182
+ end
183
+ end
184
+
185
+ Loom::Cli.new.run
@@ -0,0 +1 @@
1
+ require 'pry'
data/lib/loom.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'env/development'
2
+
3
+ module Loom
4
+
5
+ LoomError = Class.new ::StandardError
6
+ ExecutionError = Class.new LoomError
7
+
8
+ class << self
9
+ def configure(&block)
10
+ @config = Loom::Config.configure @config, &block
11
+ config_changed
12
+ end
13
+
14
+ def config
15
+ unless @config
16
+ @config = Loom::Config.configure
17
+ config_changed
18
+ end
19
+ @config
20
+ end
21
+
22
+ def reset_config
23
+ @config = nil
24
+ end
25
+
26
+ def log
27
+ @logger ||= config_logger
28
+ end
29
+
30
+ private
31
+ def config_changed
32
+ SSHKit.config.output_verbosity = config.sshkit_log_level
33
+ SSHKit.config.default_runner = config.sshkit_execution_strategy
34
+ @logger = nil
35
+ end
36
+
37
+ def config_logger
38
+ @logger = Loom::Logger.configure config
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ require 'loom/all'
data/lib/loom/all.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "sshkit"
2
+
3
+ require_relative "core_ext"
4
+ require_relative "method_signature"
5
+ require_relative "trap"
6
+
7
+ require_relative "logger"
8
+ require_relative "config"
9
+
10
+ require_relative "shell"
11
+ require_relative "host_spec"
12
+ require_relative "dsl"
13
+
14
+ require_relative "inventory"
15
+ require_relative "facts"
16
+ require_relative "pattern"
17
+ require_relative "mods"
18
+ require_relative "runner"
19
+
20
+ require_relative "version"
@@ -0,0 +1,106 @@
1
+ require 'ostruct'
2
+ require 'yaml'
3
+
4
+ module Loom
5
+
6
+ ConfigError = Class.new Loom::LoomError
7
+
8
+ class Config
9
+
10
+ CONFIG_VARS = {
11
+ :loom_search_paths => ['/etc/loom', File.join(ENV['HOME'], '.loom'), './.loom'],
12
+ :loom_files => ['site.loom'],
13
+
14
+ :inventory_all_hosts => false,
15
+ :inventory_hosts => [],
16
+ :inventory_groups => [],
17
+
18
+ :log_level => :warn, # [debug, info, warn, error, fatal, or Integer]
19
+ :log_device => :stderr, # [stderr, stdout, file descriptor, or file name]
20
+ :log_colorize => true,
21
+
22
+ :run_failure_strategy => :exclude_host, # [exclude_host, fail_fast, cowboy]
23
+ :run_verbose => false,
24
+
25
+ :sshkit_execution_strategy => :sequence, # [sequence, parallel, groups]
26
+ :sshkit_log_level => :warn,
27
+ }.freeze
28
+
29
+ attr_reader *CONFIG_VARS.keys, :config_map
30
+
31
+ def initialize(**config_map)
32
+ config_map.each do |k,v|
33
+ # allows attr_reader methods from CONFIG_VAR to work
34
+ instance_variable_set :"@#{k}", v
35
+ end
36
+
37
+ @config_map = config_map
38
+ @file_manager = FileManager.new self
39
+ end
40
+
41
+ def [](key)
42
+ @config_map[key]
43
+ end
44
+
45
+ def to_yaml
46
+ @config_map.to_yaml
47
+ end
48
+ alias_method :dump, :to_yaml # aliased to dump for debugging purposes
49
+
50
+ def files
51
+ @file_manager
52
+ end
53
+
54
+ class << self
55
+ def configure(config=nil, &block)
56
+ # do NOT call Loom.log inside this block, the logger may not be
57
+ # configured, triggering an infinite recursion
58
+
59
+ map = config ? config.config_map : CONFIG_VARS.dup
60
+ config_struct = OpenStruct.new **map
61
+ yield config_struct if block_given?
62
+ Config.new config_struct.to_h
63
+ end
64
+ end
65
+
66
+ private
67
+ class FileManager
68
+
69
+ LOOM_FILE_PATTERNS = ["*.loom"]
70
+
71
+ def initialize(config)
72
+ @loom_search_paths = config.loom_search_paths
73
+ @loom_files = config.loom_files
74
+ end
75
+
76
+ def find(glob_patterns)
77
+ search_loom_paths(glob_patterns)
78
+ end
79
+
80
+ def loom_files
81
+ [@loom_files + search_loom_paths(LOOM_FILE_PATTERNS)].flatten.uniq
82
+ end
83
+
84
+ private
85
+ def search_loom_paths(file_patterns)
86
+ # Maps glob patterns into real file paths, selecting only
87
+ # readable files, and logs the result.
88
+ file_patterns.map do |file_pattern|
89
+ @loom_search_paths.map do |path|
90
+ Dir.glob File.join(path, "**", file_pattern)
91
+ end
92
+ end.flatten.uniq.select do |path|
93
+ should_select = File.file?(path) && File.readable?(path)
94
+ unless should_select
95
+ Loom.log.debug1(self) { "skipping config path => #{path}" }
96
+ end
97
+ should_select
98
+ end.tap do |config_files|
99
+ unless config_files.empty?
100
+ Loom.log.debug1(self) { "found config files => #{config_files}" }
101
+ end
102
+ end.uniq
103
+ end
104
+ end
105
+ end
106
+ end