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.
- #_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
39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/bjn_inventory/service_map.rb', line 39 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
88 89 90 |
# File 'lib/bjn_inventory/service_map.rb', line 88 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
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/bjn_inventory/service_map.rb', line 76 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
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/bjn_inventory/service_map.rb', line 54 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 end end end service_keylist end |
#_join_endpoints(endpoints) ⇒ Object
92 93 94 95 96 97 98 99 |
# File 'lib/bjn_inventory/service_map.rb', line 92 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
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/bjn_inventory/service_map.rb', line 103 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 |
# 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' @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 |