Class: BjnInventory::ByKey
- Defined in:
- lib/bjn_inventory/bykey.rb,
lib/bjn_inventory/ansible.rb,
lib/bjn_inventory/service_map.rb
Instance Method Summary collapse
-
#_deep_set_service(hsh, path, object) ⇒ Object
Take a path–a list of key components, and deeply set them into a hash of hashes.
- #_endpoint(device) ⇒ Object
- #_field_groups(fields, device, sep = '__') ⇒ Object
- #_interpolate_path(path, device) ⇒ Object
-
#_interpolate_pathlist(spec_keys, groups) ⇒ Object
Take uninterpolated paths and expand them with the groups of devices we have.
- #_interpolate_value(path, device, value) ⇒ Object
- #_join_endpoints(endpoints) ⇒ Object
-
#_pathlist(this_map, prefix = [], cur = {}) ⇒ Object
Create a hash where the keys are paths (arrays of path components) and the values are service specs.
- #escape_name(value) ⇒ Object
- #to_ansible(*args) ⇒ Object
-
#to_groups(kwargs) ⇒ Object
This basically builds an ansible inventory given a hash of hostvars.
- #to_services(kwargs) ⇒ Object
Methods inherited from Hash
Instance Method Details
#_deep_set_service(hsh, path, object) ⇒ Object
Take a path–a list of key components, and deeply set them into a hash of hashes
40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/bjn_inventory/service_map.rb', line 40 def _deep_set_service(hsh, path, object) car, *cdr = path if cdr.empty? # This is kind of weird, use-case-specific logic object.each do |key, value| hsh[car + '.' + key] = value end else hsh[car] = { } unless hsh.has_key? car _deep_set_service(hsh[car], cdr, object) end end |
#_endpoint(device) ⇒ Object
110 111 112 |
# File 'lib/bjn_inventory/service_map.rb', line 110 def _endpoint(device) @endpoint_fields.map { |field| device[field] }.reject { |e| e.nil? }.first end |
#_field_groups(fields, device, sep = '__') ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/bjn_inventory/bykey.rb', line 9 def _field_groups(fields, device, sep='__') fields = [fields] unless fields.respond_to? :inject value_map = fields.map do |field| values = device[field] values = [values] unless values.respond_to? :map values.map { |val| escape_name(val) } end # # So now we have an array of arrays, eg.: # fields='region' => # [['dc2']] # # fields=['roles', 'region'] => # [['web', ['dc2']] # 'db'], # groups = if fields.length == 1 value_map.first else driving_array, *rest = value_map driving_array.product(*rest).map { |compound_value| compound_value.join(sep) } end groups end |
#_interpolate_path(path, device) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/bjn_inventory/service_map.rb', line 81 def _interpolate_path(path, device) path.map do |component| if component.start_with? '$$' component[1 .. -1] elsif component.start_with? '$' device[component[1 .. -1]] else component end end end |
#_interpolate_pathlist(spec_keys, groups) ⇒ Object
Take uninterpolated paths and expand them with the groups of devices we have
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/bjn_inventory/service_map.rb', line 55 def _interpolate_pathlist(spec_keys, groups) service_keylist = { } # Interpolate based on hosts_field values spec_keys.each do |path, service| if service[@hosts_field] device_names = service[@hosts_field].map { |group| groups[group] || [] }.flatten device_names.each do |device_name| if self[device_name] interpolated_path = _interpolate_path(path, self[device_name]) next if interpolated_path.any? { |el| el.nil? } unless service_keylist.has_key? interpolated_path service_keylist[interpolated_path] = service.merge({ @hosts_field => [] }) end service_keylist[interpolated_path][@hosts_field] << _endpoint(self[device_name]) end if service[@hosts_override] && service_keylist[interpolated_path][@hosts_field] service_keylist[interpolated_path][@hosts_field] = [_interpolate_value(path, self[device_name], service[@hosts_override])] service_keylist[interpolated_path].delete(@hosts_override) end end end end service_keylist end |
#_interpolate_value(path, device, value) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/bjn_inventory/service_map.rb', line 93 def _interpolate_value(path, device, value) replacement_value = value path.each do |component, continued_path| if component.start_with? '$$' replacement_value = replacement_value.gsub(component, component[1 .. -1]) elsif component.start_with? '$' replacement_value = replacement_value.gsub(component, device[component[1 .. -1]]) else replacement_value = replacement_value end if path.is_a?(Hash) replacement_value = _interpolate_value(continued_path, device, replacement_value) end end replacement_value end |
#_join_endpoints(endpoints) ⇒ Object
114 115 116 117 118 119 120 121 |
# File 'lib/bjn_inventory/service_map.rb', line 114 def _join_endpoints(endpoints) case @join when :json endpoints.uniq.sort.to_json else endpoints.uniq.sort.join(@join) end end |
#_pathlist(this_map, prefix = [], cur = {}) ⇒ Object
Create a hash where the keys are paths (arrays of path components) and the values are service specs
125 126 127 128 129 130 131 132 133 134 |
# File 'lib/bjn_inventory/service_map.rb', line 125 def _pathlist(this_map, prefix=[], cur={}) if this_map.any? { |k, v| ! v.respond_to? :keys } cur[prefix] = this_map else this_map.map do |key, value| _pathlist(value, prefix + [key], cur) end end cur end |
#escape_name(value) ⇒ Object
5 6 7 |
# File 'lib/bjn_inventory/bykey.rb', line 5 def escape_name(value) value.gsub(/[^a-zA-Z0-9_-]+/, '_') end |
#to_ansible(*args) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/bjn_inventory/ansible.rb', line 8 def to_ansible(*args) if args[-1].respond_to? :to_hash kwargs = args.pop.stringify_keys else kwargs = { } end group_by = [] if kwargs['group_by'] group_by = kwargs['group_by'] group_by = [group_by] unless group_by.respond_to? :each end group_by.concat(args) logger = kwargs['logger'] || BjnInventory::DefaultLogger.new separator = kwargs['separator'] || '__' ansible_inventory = self.to_groups(group_by: group_by, logger: logger, separator: separator). merge({ '_meta' => { 'hostvars' => self.to_hash } }) # Do my own groups if kwargs['groups'] ansible_inventory.merge! Hash[kwargs['groups'].map do |group, children| [group, { "hosts" => [ ], "children" => children }] end] end ansible_inventory end |
#to_groups(kwargs) ⇒ Object
This basically builds an ansible inventory given a hash of hostvars
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/bjn_inventory/bykey.rb', line 36 def to_groups(kwargs) group_by = kwargs[:group_by] if group_by.empty? raise ArgumentError, "Expected group_by either as keyword or as argument list" end logger = kwargs[:logger] || BjnInventory::DefaultLogger.new # We need at least one field to create groups separator = kwargs[:separator] || '__' groups = { } self.each do |name, device_hash| group_by.each do |group_field_spec| group_field_spec = [group_field_spec] unless group_field_spec.respond_to? :all? if group_field_spec.all? { |field| !device_hash[field].nil? && !device_hash[field].empty? } field_groups = _field_groups(group_field_spec, device_hash, separator) field_groups.each do |group_name| groups[group_name] = [ ] unless groups.has_key? group_name groups[group_name] << name end end end end # I can't really do children, they need to be generators and I'm not # about that right now. Save it for ansible. groups end |
#to_services(kwargs) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/bjn_inventory/service_map.rb', line 8 def to_services(kwargs) @map = kwargs[:map] @group_by = kwargs[:group_by] @logger = kwargs[:logger] || BjnInventory::DefaultLogger.new @hosts_field = kwargs[:hosts] || 'hosts' @hosts_override = kwargs[:hosts_override] || 'hosts_override' @endpoint_fields = kwargs[:endpoint_fields] || ['endpoint', 'ip_address'] @join = kwargs[:join] || ',' separator = kwargs[:separator] || '__' raise ArgumentError, "BjnInventory::ByKey#to_services requires a service map" unless @map raise ArgumentError, "BjnInventory::ByKey#to_services requires a group_by argument" unless @group_by # Build un-interpolated path => service correspondence spec_keys = _pathlist(@map) @logger.debug "paths in map: #{spec_keys.inspect}" groups = self.to_groups(group_by: @group_by, separator: separator) service_keylist = _interpolate_pathlist(spec_keys, groups) services = { } service_keylist.each do |path, service| _deep_set_service(services, path, service.merge({ @hosts_field => _join_endpoints(service[@hosts_field]) })) end services end |