require 'bjn_inventory' require 'bjn_inventory/default_logger' module BjnInventory class ByKey def _ansible_name(value) value.gsub(/[^a-zA-Z0-9_-]+/, '_') end 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| _ansible_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 # This basically builds an ansible inventory given a hash of hostvars def to_ansible(*ansible_spec) if ansible_spec[-1].respond_to? :to_hash kwargs = ansible_spec.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(ansible_spec) if group_by.empty? raise ArgumentError, "Expected group_by either as keyword or as argument list" end logger ||= BjnInventory::DefaultLogger.new # We need at least one field to create groups separator = kwargs['separator'] || '__' ansible_inventory = { '_meta' => {'hostvars' => self.to_hash } } 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| ansible_inventory[group_name] = [ ] unless ansible_inventory.has_key? group_name ansible_inventory[group_name] << name end end end end if kwargs['groups'] ansible_inventory.merge! Hash[kwargs['groups'].map do |group, children| [group, { "hosts" => [ ], "children" => children }] end] end ansible_inventory end end end