moose-inventory 2.0 → 2.1
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 +4 -4
- data/.github/workflows/release.yml +2 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +21 -0
- data/BACKLOG.md +630 -8
- data/Gemfile +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +315 -39
- data/Rakefile +2 -0
- data/bin/moose-inventory +2 -1
- data/docs/architecture/architecture-and-trust-boundaries.md +444 -0
- data/docs/compatibility/cli-output-compatibility.md +76 -0
- data/docs/governance/approval-register.md +37 -0
- data/docs/maintenance/database-backup-restore-guidance.md +162 -0
- data/docs/maintenance/package-maintenance-and-agent-boundaries.md +260 -0
- data/docs/process/conformance-gap-analysis-2026-05-28.md +192 -0
- data/docs/product/product-brief.md +161 -0
- data/docs/product/requirements-baseline.md +477 -0
- data/docs/qa/qa-documentation-and-release-gates.md +283 -0
- data/docs/release/package-provenance-hardening.md +126 -0
- data/docs/release/publishing.md +11 -3
- data/docs/release/release-environment-protection.md +70 -0
- data/docs/release/release-readiness.md +23 -4
- data/docs/security/accepted-risk-register.md +84 -0
- data/docs/security/security-privacy-process.md +287 -0
- data/docs/security-audit-2026-05-26-rerun.md +2 -2
- data/docs/ux/cli-workflow-notes.md +287 -0
- data/examples/ansible/ansible.cfg +3 -0
- data/examples/ansible/inventory/moose_inventory.yml +5 -0
- data/examples/ansible/inventory_plugins/moose_inventory.py +100 -0
- data/examples/ci/README.md +16 -0
- data/examples/ci/github-actions/inventory-review.yml +38 -0
- data/examples/ci/inventory/example-snapshot.yml +19 -0
- data/examples/ci/scripts/validate-inventory-snapshot.sh +30 -0
- data/lib/moose_inventory/cli/application.rb +133 -5
- data/lib/moose_inventory/cli/association_rendering.rb +74 -0
- data/lib/moose_inventory/cli/association_rendering_support.rb +89 -0
- data/lib/moose_inventory/cli/audit.rb +62 -0
- data/lib/moose_inventory/cli/audit_recording.rb +40 -0
- data/lib/moose_inventory/cli/child_relation_rendering.rb +110 -0
- data/lib/moose_inventory/cli/console.rb +135 -0
- data/lib/moose_inventory/cli/db.rb +64 -0
- data/lib/moose_inventory/cli/factory.rb +28 -0
- data/lib/moose_inventory/cli/formatter.rb +8 -12
- data/lib/moose_inventory/cli/group.rb +5 -2
- data/lib/moose_inventory/cli/group_add.rb +11 -9
- data/lib/moose_inventory/cli/group_addchild.rb +23 -65
- data/lib/moose_inventory/cli/group_addhost.rb +16 -67
- data/lib/moose_inventory/cli/group_addvar.rb +27 -47
- data/lib/moose_inventory/cli/group_get.rb +8 -42
- data/lib/moose_inventory/cli/group_list.rb +7 -40
- data/lib/moose_inventory/cli/group_listvars.rb +9 -55
- data/lib/moose_inventory/cli/group_rm.rb +12 -10
- data/lib/moose_inventory/cli/group_rmchild.rb +26 -82
- data/lib/moose_inventory/cli/group_rmhost.rb +18 -53
- data/lib/moose_inventory/cli/group_rmvar.rb +30 -41
- data/lib/moose_inventory/cli/group_tags.rb +33 -0
- data/lib/moose_inventory/cli/helpers.rb +68 -1
- data/lib/moose_inventory/cli/host.rb +6 -3
- data/lib/moose_inventory/cli/host_add.rb +69 -29
- data/lib/moose_inventory/cli/host_addgroup.rb +22 -58
- data/lib/moose_inventory/cli/host_addvar.rb +28 -52
- data/lib/moose_inventory/cli/host_get.rb +9 -37
- data/lib/moose_inventory/cli/host_list.rb +24 -21
- data/lib/moose_inventory/cli/host_listvars.rb +9 -62
- data/lib/moose_inventory/cli/host_rm.rb +60 -42
- data/lib/moose_inventory/cli/host_rmgroup.rb +25 -44
- data/lib/moose_inventory/cli/host_rmvar.rb +31 -45
- data/lib/moose_inventory/cli/host_tags.rb +33 -0
- data/lib/moose_inventory/cli/listvars_support.rb +55 -0
- data/lib/moose_inventory/cli/plan_rendering.rb +50 -0
- data/lib/moose_inventory/cli/relation_transaction_support.rb +51 -0
- data/lib/moose_inventory/cli/tag_support.rb +97 -0
- data/lib/moose_inventory/cli/variable_rendering.rb +67 -0
- data/lib/moose_inventory/config/config.rb +185 -108
- data/lib/moose_inventory/db/db.rb +170 -195
- data/lib/moose_inventory/db/exceptions.rb +6 -3
- data/lib/moose_inventory/db/models.rb +16 -0
- data/lib/moose_inventory/db/schema_migrations.rb +248 -0
- data/lib/moose_inventory/inventory_context.rb +68 -2
- data/lib/moose_inventory/operations/add_associations.rb +20 -16
- data/lib/moose_inventory/operations/add_groups.rb +21 -13
- data/lib/moose_inventory/operations/add_hosts.rb +30 -17
- data/lib/moose_inventory/operations/add_variables.rb +77 -0
- data/lib/moose_inventory/operations/entity_variable_operation_support.rb +46 -0
- data/lib/moose_inventory/operations/group_child_relations.rb +23 -16
- data/lib/moose_inventory/operations/group_cleanup.rb +23 -8
- data/lib/moose_inventory/operations/import_inventory_snapshot.rb +41 -0
- data/lib/moose_inventory/operations/inventory_doctor.rb +172 -0
- data/lib/moose_inventory/operations/inventory_snapshot.rb +60 -0
- data/lib/moose_inventory/operations/inventory_snapshot_applier.rb +112 -0
- data/lib/moose_inventory/operations/inventory_snapshot_preview.rb +174 -0
- data/lib/moose_inventory/operations/inventory_snapshot_validator.rb +134 -0
- data/lib/moose_inventory/operations/operation_event_support.rb +27 -0
- data/lib/moose_inventory/operations/query_inventory/base_query.rb +24 -0
- data/lib/moose_inventory/operations/query_inventory/group_queries.rb +86 -0
- data/lib/moose_inventory/operations/query_inventory/host_queries.rb +106 -0
- data/lib/moose_inventory/operations/query_inventory.rb +47 -0
- data/lib/moose_inventory/operations/remove_associations.rb +30 -18
- data/lib/moose_inventory/operations/remove_groups.rb +12 -12
- data/lib/moose_inventory/operations/remove_hosts.rb +68 -0
- data/lib/moose_inventory/operations/remove_variables.rb +67 -0
- data/lib/moose_inventory/runtime_options.rb +31 -0
- data/lib/moose_inventory/version.rb +3 -1
- data/lib/moose_inventory.rb +10 -7
- data/moose-inventory.gemspec +19 -35
- data/scripts/check.sh +1 -0
- data/scripts/ci/check_generated_artifacts.sh +41 -0
- data/scripts/ci/check_permissions.sh +2 -0
- data/scripts/ci/check_rubocop.sh +30 -25
- data/scripts/files.rb +5 -4
- data/spec/examples/ci_examples_spec.rb +37 -0
- data/spec/lib/moose_inventory/ansible_plugin_examples_spec.rb +29 -0
- data/spec/lib/moose_inventory/cli/application_doctor_spec.rb +50 -0
- data/spec/lib/moose_inventory/cli/application_import_export_spec.rb +100 -0
- data/spec/lib/moose_inventory/cli/application_spec.rb +25 -15
- data/spec/lib/moose_inventory/cli/audit_spec.rb +56 -0
- data/spec/lib/moose_inventory/cli/cli_spec.rb +15 -19
- data/spec/lib/moose_inventory/cli/console_spec.rb +98 -0
- data/spec/lib/moose_inventory/cli/factory_spec.rb +27 -0
- data/spec/lib/moose_inventory/cli/formatter_spec.rb +95 -3
- data/spec/lib/moose_inventory/cli/group_add_spec.rb +140 -116
- data/spec/lib/moose_inventory/cli/group_addchild_spec.rb +89 -35
- data/spec/lib/moose_inventory/cli/group_addhost_spec.rb +81 -84
- data/spec/lib/moose_inventory/cli/group_addvar_spec.rb +65 -68
- data/spec/lib/moose_inventory/cli/group_get_spec.rb +17 -33
- data/spec/lib/moose_inventory/cli/group_list_spec.rb +16 -38
- data/spec/lib/moose_inventory/cli/group_listvar_spec.rb +33 -40
- data/spec/lib/moose_inventory/cli/group_rm_spec.rb +136 -96
- data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +66 -41
- data/spec/lib/moose_inventory/cli/group_rmhost_spec.rb +76 -78
- data/spec/lib/moose_inventory/cli/group_rmvar_spec.rb +57 -63
- data/spec/lib/moose_inventory/cli/group_spec.rb +2 -0
- data/spec/lib/moose_inventory/cli/helpers_spec.rb +146 -0
- data/spec/lib/moose_inventory/cli/host_add_spec.rb +170 -116
- data/spec/lib/moose_inventory/cli/host_addgroup_spec.rb +100 -83
- data/spec/lib/moose_inventory/cli/host_addvar_spec.rb +92 -74
- data/spec/lib/moose_inventory/cli/host_get_spec.rb +14 -33
- data/spec/lib/moose_inventory/cli/host_list_spec.rb +41 -33
- data/spec/lib/moose_inventory/cli/host_listvar_spec.rb +45 -53
- data/spec/lib/moose_inventory/cli/host_rm_spec.rb +66 -48
- data/spec/lib/moose_inventory/cli/host_rmgroup_spec.rb +73 -83
- data/spec/lib/moose_inventory/cli/host_rmvar_spec.rb +56 -63
- data/spec/lib/moose_inventory/cli/host_spec.rb +2 -0
- data/spec/lib/moose_inventory/cli/tags_spec.rb +81 -0
- data/spec/lib/moose_inventory/config/config_spec.rb +41 -3
- data/spec/lib/moose_inventory/db/db_spec.rb +396 -36
- data/spec/lib/moose_inventory/db/exceptions_spec.rb +18 -0
- data/spec/lib/moose_inventory/db/models_spec.rb +7 -3
- data/spec/lib/moose_inventory/db_lifecycle_spec.rb +73 -0
- data/spec/lib/moose_inventory/inventory_context_spec.rb +10 -0
- data/spec/lib/moose_inventory/operations/add_associations_spec.rb +34 -0
- data/spec/lib/moose_inventory/operations/add_groups_spec.rb +15 -0
- data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +13 -0
- data/spec/lib/moose_inventory/operations/add_variables_spec.rb +103 -0
- data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +46 -0
- data/spec/lib/moose_inventory/operations/import_inventory_snapshot_spec.rb +226 -0
- data/spec/lib/moose_inventory/operations/inventory_doctor_spec.rb +77 -0
- data/spec/lib/moose_inventory/operations/inventory_snapshot_spec.rb +50 -0
- data/spec/lib/moose_inventory/operations/operation_event_support_spec.rb +78 -0
- data/spec/lib/moose_inventory/operations/query_inventory_spec.rb +146 -0
- data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +35 -0
- data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +21 -0
- data/spec/lib/moose_inventory/operations/remove_hosts_spec.rb +55 -0
- data/spec/lib/moose_inventory/operations/remove_variables_spec.rb +83 -0
- data/spec/shared/shared_config_setup.rb +4 -3
- data/spec/spec_helper.rb +50 -40
- data/spec/support/cli_harness.rb +33 -0
- metadata +80 -41
|
@@ -1,49 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
1
4
|
require 'spec_helper'
|
|
2
5
|
|
|
3
|
-
# TODO: the usual respond_to? method doesn't seem to work on Thor objects.
|
|
4
6
|
# Why not? For now, we'll check against instance_methods.
|
|
5
7
|
|
|
6
8
|
RSpec.describe Moose::Inventory::Cli::Host do
|
|
7
9
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
@mockarg_parts = {
|
|
10
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
11
|
-
format: 'yaml',
|
|
12
|
-
env: 'test',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
|
|
24
|
-
@db = Moose::Inventory::DB
|
|
25
|
-
@db.init if @db.db.nil?
|
|
26
|
-
|
|
27
|
-
@host = Moose::Inventory::Cli::Host
|
|
28
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host)
|
|
29
11
|
end
|
|
30
12
|
|
|
31
13
|
before(:each) do
|
|
32
|
-
|
|
14
|
+
reset_cli_harness
|
|
33
15
|
end
|
|
34
16
|
|
|
35
17
|
#=======================
|
|
36
18
|
describe 'addgroup' do
|
|
37
19
|
#------------------------
|
|
38
20
|
it 'Host.addgroup() should be responsive' do
|
|
39
|
-
result = @host.
|
|
21
|
+
result = @host.method_defined?(:addgroup, false)
|
|
40
22
|
expect(result).to eq(true)
|
|
41
23
|
end
|
|
42
24
|
|
|
43
25
|
#------------------------
|
|
44
26
|
it 'host addgroup <missing args> ... should abort with an error' do
|
|
45
27
|
actual = runner do
|
|
46
|
-
@app.start(%w
|
|
28
|
+
@app.start(%w[host addgroup]) # <- no group given
|
|
47
29
|
end
|
|
48
30
|
|
|
49
31
|
# Check output
|
|
@@ -55,16 +37,16 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
55
37
|
#------------------------
|
|
56
38
|
it 'host addgroup HOST GROUP ... should abort if the host does not exist' do
|
|
57
39
|
actual = runner do
|
|
58
|
-
@app.start(%w
|
|
40
|
+
@app.start(%w[host addgroup not-a-host example])
|
|
59
41
|
end
|
|
60
42
|
|
|
61
43
|
# Check output
|
|
62
44
|
desired = { aborted: true }
|
|
63
45
|
desired[:STDOUT] =
|
|
64
|
-
"Associate host 'not-a-host' with groups 'example':\n"\
|
|
65
|
-
"
|
|
46
|
+
"Associate host 'not-a-host' with groups 'example':\n " \
|
|
47
|
+
"- Retrieve host 'not-a-host'...\n"
|
|
66
48
|
desired[:STDERR] =
|
|
67
|
-
"An error occurred during a transaction, any changes have been rolled back.\n"\
|
|
49
|
+
"An error occurred during a transaction, any changes have been rolled back.\n" \
|
|
68
50
|
"ERROR: The host 'not-a-host' was not found in the database.\n"
|
|
69
51
|
expected(actual, desired)
|
|
70
52
|
end
|
|
@@ -77,26 +59,23 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
77
59
|
name = 'test1'
|
|
78
60
|
group_name = 'testgroup1'
|
|
79
61
|
|
|
80
|
-
runner { @app.start(%W
|
|
62
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
81
63
|
@db.models[:group].create(name: group_name)
|
|
82
64
|
|
|
83
|
-
actual = runner { @app.start(%W
|
|
65
|
+
actual = runner { @app.start(%W[host addgroup #{name} #{group_name}]) }
|
|
84
66
|
|
|
85
|
-
# rubocop:disable Metrics/LineLength
|
|
86
67
|
desired = { aborted: false }
|
|
87
68
|
desired[:STDOUT] =
|
|
88
|
-
"Associate host '#{name}' with groups '#{group_name}':\n"\
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
69
|
+
"Associate host '#{name}' with groups '#{group_name}':\n " \
|
|
70
|
+
"- Retrieve host '#{name}'...\n " \
|
|
71
|
+
"- OK\n " \
|
|
72
|
+
"- Add association {host:#{name} <-> group:#{group_name}}...\n " \
|
|
73
|
+
"- OK\n " \
|
|
74
|
+
"- Remove automatic association {host:#{name} <-> group:ungrouped}...\n " \
|
|
75
|
+
"- OK\n " \
|
|
76
|
+
"- All OK\n" \
|
|
96
77
|
"Succeeded\n"
|
|
97
78
|
expected(actual, desired)
|
|
98
|
-
# rubocop:enable Metrics/LineLength
|
|
99
|
-
|
|
100
79
|
# We should have the correct group associations
|
|
101
80
|
host = @db.models[:host].find(name: name)
|
|
102
81
|
groups = host.groups_dataset
|
|
@@ -105,14 +84,51 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
105
84
|
expect(groups[name: 'ungrouped']).to be_nil # redundant, but for clarity!
|
|
106
85
|
end
|
|
107
86
|
|
|
87
|
+
#------------------------
|
|
88
|
+
it 'host addgroup HOST GROUP --dry-run should not create the group or change membership' do
|
|
89
|
+
name = 'test1'
|
|
90
|
+
group_name = 'drygroup'
|
|
91
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
92
|
+
|
|
93
|
+
actual = runner { @app.start(%W[host addgroup #{name} #{group_name} --dry-run]) }
|
|
94
|
+
|
|
95
|
+
expect(actual[:unexpected]).to eq(false)
|
|
96
|
+
expect(actual[:aborted]).to eq(false)
|
|
97
|
+
expect(actual[:STDOUT]).to include('Dry run complete. No changes applied.')
|
|
98
|
+
expect(@db.models[:group].find(name: group_name)).to be_nil
|
|
99
|
+
host = @db.models[:host].find(name: name)
|
|
100
|
+
expect(host.groups_dataset[name: 'ungrouped']).not_to be_nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
#------------------------
|
|
104
|
+
it 'host addgroup HOST GROUP --dry-run --plan-format json should emit a pure relation plan' do
|
|
105
|
+
name = 'test1'
|
|
106
|
+
group_name = 'drygroup'
|
|
107
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
108
|
+
|
|
109
|
+
actual = runner { @app.start(%W[host addgroup #{name} #{group_name} --dry-run --plan-format json]) }
|
|
110
|
+
|
|
111
|
+
expect(actual[:unexpected]).to eq(false)
|
|
112
|
+
expect(actual[:aborted]).to eq(false)
|
|
113
|
+
expect(actual[:STDOUT]).not_to include('Associate host')
|
|
114
|
+
plan = JSON.parse(actual[:STDOUT])
|
|
115
|
+
expect(plan['command']).to eq('host addgroup')
|
|
116
|
+
expect(plan['events'].map do |event|
|
|
117
|
+
event['type']
|
|
118
|
+
end).to include('adding_host_group_association', 'dry_run_summary')
|
|
119
|
+
expect(@db.models[:group].find(name: group_name)).to be_nil
|
|
120
|
+
host = @db.models[:host].find(name: name)
|
|
121
|
+
expect(host.groups_dataset[name: 'ungrouped']).not_to be_nil
|
|
122
|
+
end
|
|
123
|
+
|
|
108
124
|
#------------------------
|
|
109
125
|
it 'HOST \'ungrouped\' ... should abort with an error' do
|
|
110
126
|
name = 'test1'
|
|
111
127
|
group_name = 'ungrouped'
|
|
112
128
|
|
|
113
|
-
runner { @app.start(%W
|
|
129
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
114
130
|
|
|
115
|
-
actual = runner { @app.start(%W
|
|
131
|
+
actual = runner { @app.start(%W[host addgroup #{name} #{group_name}]) }
|
|
116
132
|
|
|
117
133
|
desired = { aborted: true }
|
|
118
134
|
desired[:STDERR] =
|
|
@@ -125,25 +141,25 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
125
141
|
name = 'test1'
|
|
126
142
|
group_name = 'testgroup1'
|
|
127
143
|
|
|
128
|
-
runner { @app.start(%W
|
|
144
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
129
145
|
|
|
130
146
|
# DON'T CREATE THE GROUP! That's the point of the test. ;o)
|
|
131
147
|
|
|
132
|
-
actual = runner { @app.start(%W
|
|
148
|
+
actual = runner { @app.start(%W[host addgroup #{name} #{group_name}]) }
|
|
133
149
|
|
|
134
150
|
# Check output
|
|
135
151
|
desired = { aborted: false }
|
|
136
152
|
desired[:STDOUT] =
|
|
137
|
-
"Associate host '#{name}' with groups '#{group_name}':\n"\
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"
|
|
153
|
+
"Associate host '#{name}' with groups '#{group_name}':\n " \
|
|
154
|
+
"- Retrieve host '#{name}'...\n " \
|
|
155
|
+
"- OK\n " \
|
|
156
|
+
"- Add association {host:#{name} <-> group:#{group_name}}...\n " \
|
|
157
|
+
"- Group does not exist, creating now...\n " \
|
|
158
|
+
"- OK\n " \
|
|
159
|
+
"- OK\n " \
|
|
160
|
+
"- Remove automatic association {host:#{name} <-> group:ungrouped}...\n " \
|
|
161
|
+
"- OK\n " \
|
|
162
|
+
"- All OK\n" \
|
|
147
163
|
"Succeeded\n"
|
|
148
164
|
desired[:STDERR] =
|
|
149
165
|
"WARNING: Group '#{group_name}' does not exist and will be created."
|
|
@@ -158,33 +174,33 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
158
174
|
end
|
|
159
175
|
|
|
160
176
|
#------------------------
|
|
161
|
-
it 'HOST GROUP ... should skip associations that already
|
|
162
|
-
|
|
177
|
+
it 'HOST GROUP ... should skip associations that already ' \
|
|
178
|
+
'exist, but raise a warning.' do
|
|
163
179
|
name = 'test1'
|
|
164
180
|
group_name = 'testgroup1'
|
|
165
181
|
|
|
166
|
-
runner { @app.start(%W
|
|
182
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
167
183
|
|
|
168
184
|
# DON'T CREATE THE GROUP! That's the point of the test. ;o)
|
|
169
185
|
|
|
170
186
|
# Run once to make the association
|
|
171
|
-
runner { @app.start(%W
|
|
187
|
+
runner { @app.start(%W[host addgroup #{name} #{group_name}]) }
|
|
172
188
|
|
|
173
189
|
# Run again, to prove expected result
|
|
174
|
-
actual = runner { @app.start(%W
|
|
190
|
+
actual = runner { @app.start(%W[host addgroup #{name} #{group_name}]) }
|
|
175
191
|
|
|
176
192
|
# Check output
|
|
177
193
|
# Note: This time, we don't expect to see any messages about
|
|
178
194
|
# dissociation from 'ungrouped'
|
|
179
195
|
desired = { aborted: false }
|
|
180
196
|
desired[:STDOUT] =
|
|
181
|
-
"Associate host '#{name}' with groups '#{group_name}':\n"\
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
197
|
+
"Associate host '#{name}' with groups '#{group_name}':\n " \
|
|
198
|
+
"- Retrieve host '#{name}'...\n " \
|
|
199
|
+
"- OK\n " \
|
|
200
|
+
"- Add association {host:#{name} <-> group:#{group_name}}...\n " \
|
|
201
|
+
"- Already exists, skipping.\n " \
|
|
202
|
+
"- OK\n " \
|
|
203
|
+
"- All OK\n" \
|
|
188
204
|
"Succeeded\n"
|
|
189
205
|
desired[:STDERR] = "WARNING: Association {host:#{name} <-> group:#{group_name}} already exists, skipping."
|
|
190
206
|
expected(actual, desired)
|
|
@@ -198,35 +214,35 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
198
214
|
end
|
|
199
215
|
|
|
200
216
|
#------------------------
|
|
201
|
-
it 'host addgroup GROUP1 GROUP1 ... should add the host to'\
|
|
202
|
-
|
|
217
|
+
it 'host addgroup GROUP1 GROUP1 ... should add the host to ' \
|
|
218
|
+
'multiple groups at once' do
|
|
203
219
|
name = 'test1'
|
|
204
|
-
group_names = %w
|
|
220
|
+
group_names = %w[group1 group2 group3]
|
|
205
221
|
|
|
206
|
-
runner { @app.start(%W
|
|
222
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
207
223
|
|
|
208
|
-
actual = runner { @app.start(%W
|
|
224
|
+
actual = runner { @app.start(%W[host addgroup #{name}] + group_names) }
|
|
209
225
|
|
|
210
226
|
# Check output
|
|
211
227
|
desired = { aborted: false, STDERR: '' }
|
|
212
228
|
desired[:STDOUT] =
|
|
213
|
-
"Associate host '#{name}' with groups '#{group_names.join(',')}':\n"\
|
|
214
|
-
"
|
|
215
|
-
"
|
|
229
|
+
"Associate host '#{name}' with groups '#{group_names.join(',')}':\n " \
|
|
230
|
+
"- Retrieve host '#{name}'...\n " \
|
|
231
|
+
"- OK\n"
|
|
216
232
|
group_names.each do |group|
|
|
217
233
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
218
|
-
" - Add association {host:#{name} <-> group:#{group}}...\n"\
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
234
|
+
" - Add association {host:#{name} <-> group:#{group}}...\n " \
|
|
235
|
+
"- Group does not exist, creating now...\n " \
|
|
236
|
+
"- OK\n " \
|
|
237
|
+
"- OK\n"
|
|
222
238
|
|
|
223
239
|
desired[:STDERR] = desired[:STDERR] +
|
|
224
240
|
"WARNING: Group '#{group}' does not exist and will be created."
|
|
225
241
|
end
|
|
226
242
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
227
|
-
" - Remove automatic association {host:#{name} <-> group:ungrouped}...\n"\
|
|
228
|
-
"
|
|
229
|
-
"
|
|
243
|
+
" - Remove automatic association {host:#{name} <-> group:ungrouped}...\n " \
|
|
244
|
+
"- OK\n " \
|
|
245
|
+
"- All OK\n" \
|
|
230
246
|
"Succeeded\n"
|
|
231
247
|
expected(actual, desired)
|
|
232
248
|
|
|
@@ -244,3 +260,4 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
244
260
|
end
|
|
245
261
|
end
|
|
246
262
|
end
|
|
263
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,50 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
1
4
|
require 'spec_helper'
|
|
2
5
|
|
|
3
|
-
# TODO: the usual respond_to? method doesn't seem to work on Thor objects.
|
|
4
6
|
# Why not? For now, we'll check against instance_methods.
|
|
5
7
|
|
|
6
8
|
RSpec.describe Moose::Inventory::Cli::Host do
|
|
7
9
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
@mockarg_parts = {
|
|
10
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
11
|
-
format: 'yaml',
|
|
12
|
-
env: 'test',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
|
|
24
|
-
@db = Moose::Inventory::DB
|
|
25
|
-
@db.init if @db.db.nil?
|
|
26
|
-
|
|
27
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
28
|
-
@host = Moose::Inventory::Cli::Host
|
|
29
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host)
|
|
30
11
|
end
|
|
31
12
|
|
|
32
13
|
before(:each) do
|
|
33
|
-
|
|
14
|
+
reset_cli_harness
|
|
34
15
|
end
|
|
35
16
|
|
|
36
17
|
#==================
|
|
37
18
|
describe 'addvar' do
|
|
38
19
|
#-----------------
|
|
39
20
|
it 'should be responsive' do
|
|
40
|
-
result = @host.
|
|
21
|
+
result = @host.method_defined?(:addvar, false)
|
|
41
22
|
expect(result).to eq(true)
|
|
42
23
|
end
|
|
43
24
|
|
|
44
25
|
#-----------------
|
|
45
26
|
it 'host addvar <missing args> ... should abort with an error' do
|
|
46
27
|
actual = runner do
|
|
47
|
-
@app.start(%w
|
|
28
|
+
@app.start(%w[host addvar]) # <- no group given
|
|
48
29
|
end
|
|
49
30
|
|
|
50
31
|
# Check output
|
|
@@ -59,16 +40,16 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
59
40
|
host_var = 'foo=bar'
|
|
60
41
|
|
|
61
42
|
actual = runner do
|
|
62
|
-
@app.start(%W
|
|
43
|
+
@app.start(%W[host addvar #{host_name} #{host_var}])
|
|
63
44
|
end
|
|
64
45
|
|
|
65
46
|
# Check output
|
|
66
47
|
desired = { aborted: true }
|
|
67
48
|
desired[:STDOUT] =
|
|
68
|
-
"Add variables '#{host_var}' to host '#{host_name}':\n"\
|
|
69
|
-
"
|
|
49
|
+
"Add variables '#{host_var}' to host '#{host_name}':\n " \
|
|
50
|
+
"- retrieve host '#{host_name}'...\n"
|
|
70
51
|
desired[:STDERR] =
|
|
71
|
-
"An error occurred during a transaction, any changes have been rolled back.\n"\
|
|
52
|
+
"An error occurred during a transaction, any changes have been rolled back.\n" \
|
|
72
53
|
"ERROR: The host '#{host_name}' does not exist.\n"
|
|
73
54
|
expected(actual, desired)
|
|
74
55
|
end
|
|
@@ -80,32 +61,30 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
80
61
|
|
|
81
62
|
host_name = 'test1'
|
|
82
63
|
@db.models[:host].create(name: host_name)
|
|
83
|
-
|
|
84
|
-
var = { name: 'var1', value: 'testval' }
|
|
85
|
-
cases = %w(
|
|
64
|
+
cases = %w[
|
|
86
65
|
testvar
|
|
87
66
|
testvar=
|
|
88
67
|
=testval
|
|
89
68
|
testvar=testval=
|
|
90
69
|
=testvar=testval
|
|
91
70
|
testvar=testval=extra
|
|
92
|
-
|
|
71
|
+
]
|
|
93
72
|
|
|
94
73
|
cases.each do |args|
|
|
95
74
|
actual = runner do
|
|
96
|
-
@app.start(%W
|
|
75
|
+
@app.start(%W[host addvar #{host_name} #{args}])
|
|
97
76
|
end
|
|
98
77
|
# @console.out(actual,'p')
|
|
99
78
|
|
|
100
79
|
desired = { aborted: true }
|
|
101
80
|
desired[:STDOUT] =
|
|
102
|
-
"Add variables '#{args}' to host '#{host_name}':\n"\
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
81
|
+
"Add variables '#{args}' to host '#{host_name}':\n " \
|
|
82
|
+
"- retrieve host '#{host_name}'...\n " \
|
|
83
|
+
"- OK\n " \
|
|
84
|
+
"- add variable '#{args}'...\n"
|
|
106
85
|
|
|
107
86
|
desired[:STDERR] =
|
|
108
|
-
"An error occurred during a transaction, any changes have been rolled back.\n"\
|
|
87
|
+
"An error occurred during a transaction, any changes have been rolled back.\n" \
|
|
109
88
|
"ERROR: Incorrect format in '{#{args}}'. Expected 'key=value'.\n"
|
|
110
89
|
|
|
111
90
|
expected(actual, desired)
|
|
@@ -123,18 +102,18 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
123
102
|
@db.models[:host].create(name: host_name)
|
|
124
103
|
|
|
125
104
|
actual = runner do
|
|
126
|
-
@app.start(%W
|
|
105
|
+
@app.start(%W[host addvar #{host_name} #{var[:name]}=#{var[:value]}])
|
|
127
106
|
end
|
|
128
107
|
# @console.out(actual,'p')
|
|
129
108
|
|
|
130
109
|
desired = { aborted: false }
|
|
131
110
|
desired[:STDOUT] =
|
|
132
|
-
"Add variables '#{var[:name]}=#{var[:value]}' to host '#{host_name}':\n"\
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
111
|
+
"Add variables '#{var[:name]}=#{var[:value]}' to host '#{host_name}':\n " \
|
|
112
|
+
"- retrieve host '#{host_name}'...\n " \
|
|
113
|
+
"- OK\n " \
|
|
114
|
+
"- add variable '#{var[:name]}=#{var[:value]}'...\n " \
|
|
115
|
+
"- OK\n " \
|
|
116
|
+
"- all OK\n" \
|
|
138
117
|
"Succeeded.\n"
|
|
139
118
|
expected(actual, desired)
|
|
140
119
|
|
|
@@ -157,18 +136,18 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
157
136
|
@db.models[:host].create(name: host_name)
|
|
158
137
|
|
|
159
138
|
actual = runner do
|
|
160
|
-
@app.start(%W
|
|
139
|
+
@app.start(%W[host addvar #{host_name} #{var[:name]}=#{var[:value]}])
|
|
161
140
|
end
|
|
162
141
|
# @console.out(actual,'p')
|
|
163
142
|
|
|
164
143
|
desired = { aborted: false }
|
|
165
144
|
desired[:STDOUT] =
|
|
166
|
-
"Add variables '#{var[:name]}=#{var[:value]}' to host '#{host_name}':\n"\
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
145
|
+
"Add variables '#{var[:name]}=#{var[:value]}' to host '#{host_name}':\n " \
|
|
146
|
+
"- retrieve host '#{host_name}'...\n " \
|
|
147
|
+
"- OK\n " \
|
|
148
|
+
"- add variable '#{var[:name]}=#{var[:value]}'...\n " \
|
|
149
|
+
"- OK\n " \
|
|
150
|
+
"- all OK\n" \
|
|
172
151
|
"Succeeded.\n"
|
|
173
152
|
expected(actual, desired)
|
|
174
153
|
|
|
@@ -188,33 +167,32 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
188
167
|
host_name = 'test1'
|
|
189
168
|
varsarray = [
|
|
190
169
|
{ name: 'var1', value: 'val1' },
|
|
191
|
-
{ name: 'var2', value: 'val2' }
|
|
170
|
+
{ name: 'var2', value: 'val2' }
|
|
192
171
|
]
|
|
193
172
|
|
|
194
|
-
vars =
|
|
195
|
-
|
|
196
|
-
vars << "#{var[:name]}=#{var[:value]}"
|
|
173
|
+
vars = varsarray.map do |var|
|
|
174
|
+
"#{var[:name]}=#{var[:value]}"
|
|
197
175
|
end
|
|
198
176
|
|
|
199
177
|
@db.models[:host].create(name: host_name)
|
|
200
178
|
|
|
201
179
|
actual = runner do
|
|
202
|
-
@app.start(%W
|
|
180
|
+
@app.start(%W[host addvar #{host_name}] + vars)
|
|
203
181
|
end
|
|
204
182
|
# @console.out(actual,'p')
|
|
205
183
|
|
|
206
184
|
desired = { aborted: false }
|
|
207
185
|
desired[:STDOUT] =
|
|
208
|
-
"Add variables '#{vars.join(',')}' to host '#{host_name}':\n"\
|
|
209
|
-
"
|
|
210
|
-
"
|
|
186
|
+
"Add variables '#{vars.join(',')}' to host '#{host_name}':\n " \
|
|
187
|
+
"- retrieve host '#{host_name}'...\n " \
|
|
188
|
+
"- OK\n"
|
|
211
189
|
vars.each do |var|
|
|
212
190
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
213
|
-
" - add variable '#{var}'...\n"\
|
|
214
|
-
"
|
|
191
|
+
" - add variable '#{var}'...\n " \
|
|
192
|
+
"- OK\n"
|
|
215
193
|
end
|
|
216
194
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
217
|
-
" - all OK\n"\
|
|
195
|
+
" - all OK\n" \
|
|
218
196
|
"Succeeded.\n"
|
|
219
197
|
expected(actual, desired)
|
|
220
198
|
|
|
@@ -224,6 +202,45 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
224
202
|
expect(hostvars.count).to eq(vars.length)
|
|
225
203
|
end
|
|
226
204
|
|
|
205
|
+
#------------------------
|
|
206
|
+
it 'host addvar HOST key=value --dry-run should not create or update variables' do
|
|
207
|
+
host_name = 'test1'
|
|
208
|
+
@db.models[:host].create(name: host_name)
|
|
209
|
+
runner { @app.start(%W[host addvar #{host_name} var1=old]) }
|
|
210
|
+
|
|
211
|
+
actual = runner do
|
|
212
|
+
@app.start(%W[host addvar #{host_name} var1=new var2=val2 --dry-run])
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
expect(actual[:unexpected]).to eq(false)
|
|
216
|
+
expect(actual[:aborted]).to eq(false)
|
|
217
|
+
expect(actual[:STDOUT]).to include('Dry run complete. No changes applied.')
|
|
218
|
+
host = @db.models[:host].find(name: host_name)
|
|
219
|
+
expect(host.hostvars_dataset[name: 'var1'][:value]).to eq('old')
|
|
220
|
+
expect(host.hostvars_dataset[name: 'var2']).to be_nil
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
#------------------------
|
|
224
|
+
it 'host addvar HOST key=value --dry-run --plan-format json should emit a plan without writing' do
|
|
225
|
+
host_name = 'test1'
|
|
226
|
+
@db.models[:host].create(name: host_name)
|
|
227
|
+
runner { @app.start(%W[host addvar #{host_name} var1=old]) }
|
|
228
|
+
|
|
229
|
+
actual = runner do
|
|
230
|
+
@app.start(%W[host addvar #{host_name} var1=new var2=val2 --dry-run --plan-format json])
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
expect(actual[:unexpected]).to eq(false)
|
|
234
|
+
expect(actual[:aborted]).to eq(false)
|
|
235
|
+
expect(actual[:STDOUT]).not_to include('Add variables')
|
|
236
|
+
plan = JSON.parse(actual[:STDOUT])
|
|
237
|
+
expect(plan['command']).to eq('host addvar')
|
|
238
|
+
expect(plan['events'].map { |event| event['type'] }).to include('adding_variable', 'dry_run_summary')
|
|
239
|
+
host = @db.models[:host].find(name: host_name)
|
|
240
|
+
expect(host.hostvars_dataset[name: 'var1'][:value]).to eq('old')
|
|
241
|
+
expect(host.hostvars_dataset[name: 'var2']).to be_nil
|
|
242
|
+
end
|
|
243
|
+
|
|
227
244
|
#------------------------
|
|
228
245
|
it 'host addvar HOST key=value ... should update an already existing association' do
|
|
229
246
|
# 1. Should add the var to the db
|
|
@@ -233,23 +250,23 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
233
250
|
var = { name: 'var1', value: 'testval' }
|
|
234
251
|
|
|
235
252
|
@db.models[:host].create(name: host_name)
|
|
236
|
-
runner { @app.start(%W
|
|
253
|
+
runner { @app.start(%W[host addvar #{host_name} #{var[:name]}=#{var[:value]}]) }
|
|
237
254
|
|
|
238
255
|
var[:value] = 'newtestval'
|
|
239
256
|
actual = runner do
|
|
240
|
-
@app.start(%W
|
|
257
|
+
@app.start(%W[host addvar #{host_name} #{var[:name]}=#{var[:value]}])
|
|
241
258
|
end
|
|
242
259
|
# @console.out(actual,'p')
|
|
243
260
|
|
|
244
261
|
desired = { aborted: false }
|
|
245
262
|
desired[:STDOUT] =
|
|
246
|
-
"Add variables '#{var[:name]}=#{var[:value]}' to host '#{host_name}':\n"\
|
|
247
|
-
"
|
|
248
|
-
"
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"
|
|
252
|
-
"
|
|
263
|
+
"Add variables '#{var[:name]}=#{var[:value]}' to host '#{host_name}':\n " \
|
|
264
|
+
"- retrieve host '#{host_name}'...\n " \
|
|
265
|
+
"- OK\n " \
|
|
266
|
+
"- add variable '#{var[:name]}=#{var[:value]}'...\n " \
|
|
267
|
+
"- already exists, applying as an update...\n " \
|
|
268
|
+
"- OK\n " \
|
|
269
|
+
"- all OK\n" \
|
|
253
270
|
"Succeeded.\n"
|
|
254
271
|
expected(actual, desired)
|
|
255
272
|
|
|
@@ -265,3 +282,4 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
265
282
|
end
|
|
266
283
|
end
|
|
267
284
|
end
|
|
285
|
+
# rubocop:enable Metrics/BlockLength
|