loom-core 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fca395ca95a28376331f0163c1748fcd3eb083c2f6d677627edb04a795c5b858
4
- data.tar.gz: 29fc16366271bfe121eb57b7315daa87a6d8017210d41a061cdecc6665bb26bc
3
+ metadata.gz: ba730790e0a31bfadc0f837eb2574f9e21aed1833afd06881987cb76bc6bce2d
4
+ data.tar.gz: 6e3936463bef27cf155cdd9873f0268547495d1e0609dce16e5e7089699bd8f5
5
5
  SHA512:
6
- metadata.gz: 291da2a4d0b793019dd65c511dfc1caa113a3a12c3a7f2ab12e9b991a8e5ce09b4fba97fb150b15b01edd6c67f0ea0536f16fc00384bf80c6ec54f9b21c9c1c2
7
- data.tar.gz: 0b18248b8cf5583a48fb3844c39e15b0db216ad6c6ab62a160b5013d05e6f8931bbf165c35c7e107ce3de28a88e7227662480fd263f11031fb5356da2729c5a6
6
+ metadata.gz: bd86c4cafa91fcf0032f214999be470547f198f930cf1b4ff50e1aba0948aa6d78133205f05c91c81aedc2f4809266398365a5b57d878c6655ad92dc5f349100
7
+ data.tar.gz: a9338a3ff37ed372683af92825b196e5a6c0db4ba9fc14b75a345357dcc92474aeb3008058243e88f24d09e752dcde000551fc79f76bfe3a08c42facc0c426c5
data/.gitignore CHANGED
@@ -1,2 +1,2 @@
1
1
  pkg
2
- loom-core-0.0.1.gem
2
+ loom-core-*.gem
@@ -1,2 +1,3 @@
1
+ require_relative "provider"
1
2
  require_relative "fact_set"
2
3
  require_relative "fact_file_provider"
@@ -1,45 +1,9 @@
1
1
  module Loom::Facts
2
2
 
3
- class Provider
4
- attr_reader :fact_map
5
-
6
- class << self
7
- def disable_for_host(host_spec, klass)
8
- Loom.log.warn "disabling fact provider => #{klass} on #{host_spec.hostname}"
9
- @disabled_providers ||= {}
10
- @disabled_providers[host_spec.hostname] ||= []
11
- @disabled_providers[host_spec.hostname] << klass
12
- end
13
-
14
- def disabled_for_host?(host_spec, klass)
15
- @disabled_providers ||= {}
16
- @disabled_providers[host_spec.hostname] ||= []
17
- @disabled_providers[host_spec.hostname].include? klass
18
- end
19
-
20
- def register_factory(klass, &block)
21
- @provider_factories ||= []
22
- @provider_factories << block
23
- Loom.log.debug1(self) { "registered fact provider => #{klass}" }
24
- end
25
-
26
- def create_fact_providers(host_spec, shell, loom_config)
27
- @provider_factories.map do |block|
28
- block.call(host_spec, shell, loom_config)
29
- end.flatten
30
- end
31
- end
32
-
33
- def disable(host_spec)
34
- Provider.disable_for_host host_spec, self.class
35
- end
36
-
37
- # Should return a Hash
38
- def collect_facts
39
- raise 'not implemented'
40
- end
41
- end
42
-
3
+ ##
4
+ # A factset is created by running each registered Loom::Facts::Provider and
5
+ # calling Provider+collect_facts+. See ./fact_file_provider.rb and
6
+ # lib/loomext/facts/facter_provider.rb for examples of fact providers.
43
7
  class FactSet
44
8
 
45
9
  InvalidFactName = Class.new Loom::LoomError
@@ -53,19 +17,33 @@ module Loom::Facts
53
17
  fact_providers.each do |provider|
54
18
  next if Provider.disabled_for_host?(host_spec, provider.class)
55
19
 
56
- Loom.log.debug { "loading facts from provider => #{provider}" }
20
+ namespace = provider.namespace
21
+ Loom.log.debug { "loading facts from provider => #{provider}[#{namespace}]" }
57
22
 
23
+ provider_facts = {}
58
24
  begin
59
25
  provider.collect_facts.each do |k, v|
60
26
  k = k.to_sym
61
- if fact_map[k]
62
- Loom.log.warn "overriding fact => #{k}"
27
+ provider_facts[k] = v
28
+ end
29
+
30
+ if namespace
31
+ if fact_map[namespace]
32
+ Loom.log.warn "overriding fact[#{namespace}] with namespace"
33
+ end
34
+ fact_map[namespace] = provider_facts
35
+ else
36
+ provider_facts.each do |k, v|
37
+ if fact_map[k]
38
+ Loom.log.warn "overriding fact[#{k}]"
39
+ end
40
+ Loom.log.debug5(self) { "adding fact => #{k}=#{v.to_s}" }
41
+ fact_map[k] = v
63
42
  end
64
- Loom.log.debug5(self) { "adding fact => #{k}=#{v.to_s}" }
65
- fact_map[k] = v
66
43
  end
67
44
  rescue => e
68
45
  Loom.log.error "error executing fact provider #{provider.class} => #{e.message}"
46
+ Loom.log.debug(self) { e.backtrace.join("\n\t") }
69
47
  provider.disable(host_spec)
70
48
  end
71
49
  end
@@ -0,0 +1,43 @@
1
+ module Loom::Facts
2
+
3
+ class Provider
4
+ # TODO: add documentation re: use of namespace in fact_set.rb
5
+ attr_reader :fact_map, :namespace
6
+
7
+ class << self
8
+ def disable_for_host(host_spec, klass)
9
+ Loom.log.warn "disabling fact provider => #{klass} on #{host_spec.hostname}"
10
+ @disabled_providers ||= {}
11
+ @disabled_providers[host_spec.hostname] ||= []
12
+ @disabled_providers[host_spec.hostname] << klass
13
+ end
14
+
15
+ def disabled_for_host?(host_spec, klass)
16
+ @disabled_providers ||= {}
17
+ @disabled_providers[host_spec.hostname] ||= []
18
+ @disabled_providers[host_spec.hostname].include? klass
19
+ end
20
+
21
+ def register_factory(klass, &block)
22
+ @provider_factories ||= []
23
+ @provider_factories << block
24
+ Loom.log.debug1(self) { "registered fact provider => #{klass}" }
25
+ end
26
+
27
+ def create_fact_providers(host_spec, shell, loom_config)
28
+ @provider_factories.map do |block|
29
+ block.call(host_spec, shell, loom_config)
30
+ end.flatten
31
+ end
32
+ end
33
+
34
+ def disable(host_spec)
35
+ Provider.disable_for_host host_spec, self.class
36
+ end
37
+
38
+ # Should return a Hash of fact_name => fact_value entries
39
+ def collect_facts
40
+ raise 'not implemented'
41
+ end
42
+ end
43
+ end
@@ -30,7 +30,7 @@ module Loom::Mods
30
30
  raise ModDefinedError, name if instance_methods.include? name
31
31
 
32
32
  define_mod_factory name, klass
33
- Loom.log.debug1(self) { "registered mod => #{klass} as #{name}" }
33
+ Loom.log.debug(self) { "registered mod => #{klass} as #{name}" }
34
34
 
35
35
  opts.each do |k,v|
36
36
  case k
@@ -49,12 +49,19 @@ module Loom::Mods
49
49
 
50
50
  class << self
51
51
 
52
+ ##
53
+ # Registers a mod as a new namespace on the loom object.
54
+ # Mods add actions either via a `mod_block` or via registering
55
+ # actions. Only 1 mod_block may be registered per module (which should
56
+ # be fixed), otherwise actions are imported to add module behavior.
57
+ # See loom/lib/loomext/coremods.rb and files.rb for examples.
52
58
  def register_mod(name, **opts, &block)
53
59
  Loom.log.debug2(self) { "registered mod => #{name}" }
54
60
 
61
+ # TODO: allow multiple mod_blocks per mod. Should probably stop
62
+ # dynamically defining :mod_block to do so. Current behavior, is the
63
+ # last register_mod w/ a mod_block wins. This is obvsiously shitty.
55
64
  if block_given?
56
- # TODO: i forget what mod_blocks are. read through, remember, and
57
- # document them.
58
65
  Loom.log.debug2(self) { "acting as mod_block => #{name}:#{block}" }
59
66
  define_method :mod_block, &block
60
67
  end
data/lib/loom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Loom
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -6,3 +6,4 @@ end
6
6
  require "loom"
7
7
 
8
8
  require_relative "facter_provider"
9
+ require_relative "system_info_provider"
@@ -9,6 +9,7 @@ module LoomExt::CoreFacts
9
9
  @has_facter = shell.test :which, "facter"
10
10
  disable(host_spec) unless @has_facter
11
11
  @shell = shell
12
+ @namespace = :facter
12
13
  end
13
14
 
14
15
  def collect_facts
@@ -0,0 +1,104 @@
1
+ module LoomExt::CoreFacts
2
+ class SystemInfoProvider < Loom::Facts::Provider
3
+
4
+ using Loom::CoreExt # using +underscore+ for key name creation
5
+
6
+ Loom::Facts::Provider.register_factory(self) do |host_spec, shell, loom_config|
7
+ SystemInfoProvider.new host_spec, shell
8
+ end
9
+
10
+ def initialize(host_spec, shell)
11
+ @shell = shell
12
+ @namespace = :system_info
13
+ end
14
+
15
+ def collect_facts
16
+ # see:
17
+ # https://linux.die.net/man/8/vmstat
18
+ # https://linux.die.net/man/5/proc
19
+ # https://linux.die.net/man/1/df
20
+ # https://www.cyberciti.biz/faq/linux-find-out-raspberry-pi-gpu-and-arm-cpu-temperature-command/
21
+ {
22
+ :vmstat => facts_from_vmstat,
23
+ :loadavg => facts_from_proc_loadavg,
24
+ :df => facts_from_df,
25
+ :os_release => facts_from_etc_os_release,
26
+ :cpu_temp => facts_from_sys_class_thermal_zones
27
+ }
28
+ end
29
+
30
+ private
31
+ def facts_from_vmstat
32
+ # NB: requires the host to support `vmstat -s` for table formatted output
33
+ vmstat_table = @shell.capture :vmstat, "-s"
34
+ vmstat_table.each_line.reduce({}) do |memo, line|
35
+ _, str_value, label = line.match(/\s*(\d+)\s(.*)/).to_a
36
+ int_value = str_value.to_i
37
+ value = int_value.to_s == str_value ? int_value : str_value
38
+ memo.merge label.strip.underscore.to_sym => value
39
+ end
40
+ end
41
+
42
+ def facts_from_proc_loadavg
43
+ loadavg = @shell.capture :cat, "/proc/loadavg"
44
+
45
+ one, five, fifteen, kernel_scheduling_entities, lastpid = loadavg.split
46
+ current_entities, total_entities = kernel_scheduling_entities.split("/")
47
+
48
+ {
49
+ :"1_min_avg" => one.to_f,
50
+ :"5_min_avg" => five.to_f,
51
+ :"15_min_avg" => fifteen.to_f,
52
+ :kernel_scheduling_entities => kernel_scheduling_entities,
53
+ :current_scheduling_entities => current_entities.to_i,
54
+ :total_scheduling_entities => total_entities.to_i,
55
+ :lastpid => lastpid
56
+ }
57
+ end
58
+
59
+ def facts_from_df
60
+ df = @shell.capture :df
61
+
62
+ headers = df.lines.first.split.map do |h|
63
+ h = "UsePercent" if h == "Use%"
64
+ h.strip.underscore.to_sym
65
+ end
66
+
67
+ info_lines = df.lines.drop(1).map { |l| l.strip }
68
+ info_lines.map do |info|
69
+ info_parts = info.split.map { |i| i.strip }
70
+ header_info_pairs = headers.zip(info_parts)
71
+ header_info_pairs.reduce({}) do |memo, pair|
72
+ str_value = pair[1]
73
+ int_value = str_value.to_i
74
+ value = int_value.to_s == str_value ? int_value : str_value
75
+ memo.merge pair[0] => value
76
+ end
77
+ end
78
+ end
79
+
80
+ def facts_from_etc_os_release
81
+ os_release = @shell.capture :cat, "/etc/os-release"
82
+
83
+ facts = {}
84
+ os_release.each_line do |l|
85
+ l = l.strip
86
+ key, value = l.split("=")
87
+ unquoted_value = value.gsub(/^"(.+)"$/) { |m| $1 }
88
+ facts[key.to_sym] = unquoted_value
89
+ end
90
+ facts
91
+ end
92
+
93
+ def facts_from_sys_class_thermal_zones
94
+ thermal_zones = @shell.capture :ls, "/sys/class/thermal"
95
+ thermal_zones
96
+ .split
97
+ .delete_if { |f| !f.strip.match(/^thermal_zone/) }
98
+ .map do |tz_dir|
99
+ temp = @shell.capture :cat, "/sys/class/thermal/#{tz_dir}/temp"
100
+ temp.strip.to_f / 1000
101
+ end
102
+ end
103
+ end
104
+ end
@@ -2,6 +2,7 @@ module LoomExt::CoreMods
2
2
  class Files < Loom::Mods::Module
3
3
 
4
4
  register_mod :files
5
+ required_commands :cat, :mv, :tee, :chown, :rm, :touch, :sudo, :mkdir, :echo
5
6
 
6
7
  # TODO: document loom file statements like:
7
8
  # `loom.files("some", "different/paths").cat`
@@ -88,6 +89,8 @@ module LoomExt::CoreMods
88
89
  each_path :action => :mkdir, :flags => flags
89
90
  end
90
91
 
92
+ # TODO this sudo line is just another instance of needing the harness to
93
+ # work properly (in this case to provides a hack for sudo_append)
91
94
  def ensure_line(line, sudo: false)
92
95
  if loom.is_sudo?
93
96
  Loom.log.warn "do not use files.ensure_line in sudo due to poor command escaping" +
@@ -97,17 +100,21 @@ module LoomExt::CoreMods
97
100
  each_path do |p|
98
101
  file = shell.capture :cat, p
99
102
 
100
- unless file.match(line)
103
+ matches = file.match(/^#{line}$/)
104
+ unless matches
101
105
  if sudo
102
106
  sudo_append(line)
103
107
  else
104
108
  append(line)
105
109
  end
110
+ else
111
+ Loom.log.debug(self) { "ensure_line match found: #{matches[0]}"}
106
112
  end
107
113
  end
108
114
  end
109
115
 
110
- # this is a hack to accomodate append being f'd inside sudo blocks
116
+ # TODO: Get the harness working, this is a hack to accomodate append being
117
+ # f'd inside sudo blocks
111
118
  def sudo_append(text="")
112
119
  if text.index "\n"
113
120
  Loom.log.warn "append lines individually until cmd escaping is fixed.... "
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loom-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erick Johnson
@@ -214,6 +214,7 @@ files:
214
214
  - lib/loom/facts/all.rb
215
215
  - lib/loom/facts/fact_file_provider.rb
216
216
  - lib/loom/facts/fact_set.rb
217
+ - lib/loom/facts/provider.rb
217
218
  - lib/loom/host_spec.rb
218
219
  - lib/loom/inventory.rb
219
220
  - lib/loom/logger.rb
@@ -249,6 +250,7 @@ files:
249
250
  - lib/loomext/corefacts.rb
250
251
  - lib/loomext/corefacts/all.rb
251
252
  - lib/loomext/corefacts/facter_provider.rb
253
+ - lib/loomext/corefacts/system_info_provider.rb
252
254
  - lib/loomext/coremods.rb
253
255
  - lib/loomext/coremods/all.rb
254
256
  - lib/loomext/coremods/exec.rb