Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(GH-2475) Allow entire inventory to be a plugin reference #2503

Merged
merged 1 commit into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/bolt/inventory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def self.schema
schema = {
type: Hash,
properties: OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
definitions: DEFINITIONS
definitions: DEFINITIONS,
_plugin: true
}

schema[:definitions]['config'][:properties] = Bolt::Config.transport_definitions
Expand Down
10 changes: 9 additions & 1 deletion lib/bolt/inventory/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,20 @@ class Group
GROUP_KEYS = DATA_KEYS + %w[name groups targets]
CONFIG_KEYS = Bolt::Config::INVENTORY_OPTIONS.keys

def initialize(input, plugins)
def initialize(input, plugins, all_group: false)
@logger = Bolt::Logger.logger(self)
@plugins = plugins

input = @plugins.resolve_top_level_references(input) if @plugins.reference?(input)

if all_group
if input.key?('name') && input['name'] != 'all'
@logger.warn("Top-level group '#{input['name']}' cannot specify a name, using 'all' instead.")
end

input = input.merge('name' => 'all')
end

raise ValidationError.new("Group does not have a name", nil) unless input.key?('name')

@name = @plugins.resolve_references(input['name'])
Expand Down
2 changes: 1 addition & 1 deletion lib/bolt/inventory/inventory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def initialize(data, transport, transports, plugins)
@transport = transport
@config = transports
@plugins = plugins
@groups = Group.new(@data.merge('name' => 'all'), plugins)
@groups = Group.new(@data, plugins, all_group: true)
@group_lookup = {}
@targets = {}

Expand Down
2 changes: 1 addition & 1 deletion rakelib/schemas.rake
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ end

def add_plugin_reference(definition)
definition, data = definition.partition do |k, _|
k == :description
%i[definitions description].include?(k)
end.map(&:to_h)

definition[:oneOf] = [
Expand Down
87 changes: 68 additions & 19 deletions schemas/bolt-inventory.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1353,25 +1353,74 @@
]
}
},
"type": "object",
"properties": {
"config": {
"$ref": "#/definitions/config"
},
"facts": {
"$ref": "#/definitions/facts"
},
"features": {
"$ref": "#/definitions/features"
},
"groups": {
"$ref": "#/definitions/groups"
},
"targets": {
"$ref": "#/definitions/targets"
"oneOf": [
{
"type": "object",
"properties": {
"config": {
"oneOf": [
{
"$ref": "#/definitions/config"
},
{
"$ref": "#/definitions/_plugin"
}
]
},
"facts": {
"oneOf": [
{
"$ref": "#/definitions/facts"
},
{
"$ref": "#/definitions/_plugin"
}
]
},
"features": {
"oneOf": [
{
"$ref": "#/definitions/features"
},
{
"$ref": "#/definitions/_plugin"
}
]
},
"groups": {
"oneOf": [
{
"$ref": "#/definitions/groups"
},
{
"$ref": "#/definitions/_plugin"
}
]
},
"targets": {
"oneOf": [
{
"$ref": "#/definitions/targets"
},
{
"$ref": "#/definitions/_plugin"
}
]
},
"vars": {
"oneOf": [
{
"$ref": "#/definitions/vars"
},
{
"$ref": "#/definitions/_plugin"
}
]
}
}
},
"vars": {
"$ref": "#/definitions/vars"
{
"$ref": "#/definitions/_plugin"
}
}
]
}
2 changes: 0 additions & 2 deletions spec/bolt/inventory/inventory_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ def get_target(inventory, name, alia = nil)
context 'with targets at the top level' do
let(:data) {
{
'name' => 'group1',
'targets' => [
'target1',
{ 'uri' => 'target2' },
Expand Down Expand Up @@ -791,7 +790,6 @@ def common_data(transport)
context 'with targets at the top level' do
let(:data) {
{
'name' => 'group1',
'targets' => [
'target1',
{ 'uri' => 'target2' },
Expand Down
6 changes: 2 additions & 4 deletions spec/bolt/transport/local_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ def get_target(inventory, name, alia = nil)

context 'with group-level config' do
let(:data) {
{ 'name' => 'locomoco',
'targets' => [uri],
{ 'targets' => [uri],
'config' => {
'transport' => 'ssh',
'local' => {
Expand Down Expand Up @@ -100,8 +99,7 @@ def get_target(inventory, name, alia = nil)

context 'with group-level config' do
let(:data) {
{ 'name' => 'locomoco',
'targets' => [uri],
{ 'targets' => [uri],
'config' => {
'local' => {
'bundled-ruby' => true,
Expand Down
72 changes: 72 additions & 0 deletions spec/integration/inventory_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

require 'spec_helper'
require 'bolt_spec/conn'
require 'bolt_spec/env_var'
require 'bolt_spec/files'
require 'bolt_spec/integration'
require 'bolt_spec/project'
require 'bolt_spec/puppetdb'

describe 'running with an inventory file', reset_puppet_settings: true do
include BoltSpec::Conn
include BoltSpec::EnvVar
include BoltSpec::Files
include BoltSpec::Integration
include BoltSpec::Project
Expand Down Expand Up @@ -692,4 +694,74 @@ def fact_plan(name = 'facts_test')
expect(result['targets'].empty?).to be(true)
end
end

context 'top-level plugin' do
let(:command) { %W[inventory show --targets all --project #{@project.path}] }
let(:env_var) { 'BOLT_INVENTORY_PARTIAL' }
let(:partial_path) { 'partial.yaml' }

let(:inventory) do
{
'_plugin' => 'yaml',
'filepath' => partial_path
}
end

let(:partial) do
{
'targets' => %w[foo bar baz]
}
end

around(:each) do |example|
with_env_vars(env_var => partial_path) do
with_project(inventory: inventory) do |project|
@project = project
File.write(project.path + partial_path, partial.to_yaml)
example.run
end
end
end

context 'with valid resolved data' do
it 'does not error' do
result = run_cli_json(command)
expect(result['targets']).to include(*partial['targets'])
end
end

context 'with resolved data with a name' do
let(:partial) do
{
'name' => 'badname',
'targets' => %w[foo bar baz]
}
end

it 'warns' do
run_cli_json(command)

expect(@log_output.readlines).to include(
/WARN.*Top-level group 'badname' cannot specify a name, using 'all' instead/
)
end
end

context 'with nested plugins' do
let(:inventory) do
{
'_plugin' => 'yaml',
'filepath' => {
'_plugin' => 'env_var',
'var' => env_var
}
}
end

it 'resolves and does not error' do
result = run_cli_json(command)
expect(result['targets']).to include(*partial['targets'])
end
end
end
end
17 changes: 17 additions & 0 deletions spec/lib/bolt_spec/env_var.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module BoltSpec
module EnvVar
def with_env_vars(new_vars)
new_vars.transform_keys!(&:to_s)

begin
old_vars = new_vars.keys.collect { |var| [var, ENV[var]] }.to_h
ENV.update(new_vars)
yield
ensure
ENV.update(old_vars) if old_vars
end
end
end
end