moose-inventory 1.0.9 → 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/ci.yml +15 -1
- data/.github/workflows/release.yml +60 -0
- data/.gitignore +2 -1
- data/.gitleaks.toml +9 -0
- data/.rubocop.yml +49 -0
- data/BACKLOG.md +752 -24
- data/Gemfile +2 -0
- data/Gemfile.lock +36 -1
- data/README.md +340 -44
- 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 +54 -50
- data/docs/release/release-environment-protection.md +70 -0
- data/docs/release/release-readiness.md +37 -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 +75 -0
- data/docs/security-audit-2026-05-26.md +63 -0
- 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 +7 -1
- data/lib/moose_inventory/cli/group_add.rb +91 -73
- data/lib/moose_inventory/cli/group_addchild.rb +41 -66
- data/lib/moose_inventory/cli/group_addhost.rb +33 -71
- 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 +105 -73
- data/lib/moose_inventory/cli/group_rmchild.rb +47 -57
- data/lib/moose_inventory/cli/group_rmhost.rb +34 -61
- 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 +143 -0
- data/lib/moose_inventory/cli/host.rb +8 -2
- data/lib/moose_inventory/cli/host_add.rb +91 -66
- data/lib/moose_inventory/cli/host_addgroup.rb +39 -66
- 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 +39 -55
- 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 +188 -193
- 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 +116 -0
- data/lib/moose_inventory/operations/add_associations.rb +131 -0
- data/lib/moose_inventory/operations/add_groups.rb +123 -0
- data/lib/moose_inventory/operations/add_hosts.rb +123 -0
- 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 +125 -0
- data/lib/moose_inventory/operations/group_cleanup.rb +70 -0
- 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 +113 -0
- data/lib/moose_inventory/operations/remove_groups.rb +79 -0
- 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 +22 -35
- data/scripts/check.sh +3 -0
- data/scripts/ci/check_generated_artifacts.sh +41 -0
- data/scripts/ci/check_permissions.sh +5 -0
- data/scripts/ci/check_rubocop.sh +33 -0
- data/scripts/ci/check_secrets.sh +26 -0
- data/scripts/ci/check_security.sh +18 -0
- data/scripts/ci/install_security_tools.sh +47 -0
- data/scripts/files.rb +5 -4
- data/scripts/install_dependencies.sh +2 -0
- 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 +165 -85
- data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +100 -30
- 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 +551 -29
- 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 +111 -0
- data/spec/lib/moose_inventory/operations/add_groups_spec.rb +80 -0
- data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +82 -0
- data/spec/lib/moose_inventory/operations/add_variables_spec.rb +103 -0
- data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +122 -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 +113 -0
- data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +78 -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 +163 -35
|
@@ -1,15 +1,17 @@
|
|
|
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::Group do
|
|
7
9
|
before(:all) do
|
|
8
10
|
# Set up the configuration object
|
|
9
11
|
@mockarg_parts = {
|
|
10
|
-
config:
|
|
11
|
-
format:
|
|
12
|
-
env:
|
|
12
|
+
config: File.join(spec_root, 'config/config.yml'),
|
|
13
|
+
format: 'yaml',
|
|
14
|
+
env: 'test'
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
@mockargs = []
|
|
@@ -39,14 +41,14 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
39
41
|
describe 'addchild' do
|
|
40
42
|
#------------------------
|
|
41
43
|
it 'Group.addchild() should be responsive' do
|
|
42
|
-
result = @group.
|
|
44
|
+
result = @group.method_defined?(:addchild, false)
|
|
43
45
|
expect(result).to eq(true)
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
#------------------------
|
|
47
49
|
it '<missing args> ... should abort with an error' do
|
|
48
50
|
actual = runner do
|
|
49
|
-
@app.start(%w
|
|
51
|
+
@app.start(%w[group addchild])
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
# @console.out(actual, 'y')
|
|
@@ -63,7 +65,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
63
65
|
child_name = 'fake'
|
|
64
66
|
|
|
65
67
|
actual = runner do
|
|
66
|
-
@app.start(%W
|
|
68
|
+
@app.start(%W[group addchild #{parent_name} #{child_name}])
|
|
67
69
|
end
|
|
68
70
|
|
|
69
71
|
# @console.out(actual, 'y')
|
|
@@ -79,7 +81,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
79
81
|
child_name = 'ungrouped'
|
|
80
82
|
|
|
81
83
|
actual = runner do
|
|
82
|
-
@app.start(%W
|
|
84
|
+
@app.start(%W[group addchild #{parent_name} #{child_name}])
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
# @console.out(actual, 'y')
|
|
@@ -92,25 +94,28 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
92
94
|
|
|
93
95
|
#------------------------
|
|
94
96
|
it 'GROUP CHILDGROUP ... should abort if GROUP does not exist' do
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
+
# Contract: addchild attaches children to an existing parent. Missing child
|
|
98
|
+
# groups may be created, but the parent must already exist so typos do not
|
|
99
|
+
# silently create a new tree root.
|
|
97
100
|
pname = 'parent_group'
|
|
98
101
|
cname = 'child group'
|
|
99
102
|
|
|
100
103
|
actual = runner do
|
|
101
|
-
@app.start(%W
|
|
104
|
+
@app.start(%W[group addchild #{pname} #{cname}])
|
|
102
105
|
end
|
|
103
106
|
|
|
104
107
|
# @console.out(actual, 'y')
|
|
105
108
|
# Check output
|
|
106
109
|
desired = { aborted: true }
|
|
107
110
|
desired[:STDOUT] =
|
|
108
|
-
"Associate parent group '#{pname}' with child group(s) '#{cname}':\n"\
|
|
109
|
-
"
|
|
111
|
+
"Associate parent group '#{pname}' with child group(s) '#{cname}':\n " \
|
|
112
|
+
"- retrieve group '#{pname}'...\n"
|
|
110
113
|
desired[:STDERR] =
|
|
111
|
-
"ERROR: The group '#{pname}' does not exist.\n"\
|
|
114
|
+
"ERROR: The group '#{pname}' does not exist.\n" \
|
|
112
115
|
"An error occurred during a transaction, any changes have been rolled back.\n"
|
|
113
116
|
expected(actual, desired)
|
|
117
|
+
expect(@db.models[:group].find(name: pname)).to be_nil
|
|
118
|
+
expect(@db.models[:group].find(name: cname)).to be_nil
|
|
114
119
|
end
|
|
115
120
|
|
|
116
121
|
#------------------------
|
|
@@ -118,20 +123,20 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
118
123
|
pname = 'parent_group'
|
|
119
124
|
cname = 'child_group'
|
|
120
125
|
|
|
121
|
-
runner { @app.start(%W
|
|
126
|
+
runner { @app.start(%W[group add #{pname} #{cname}]) }
|
|
122
127
|
|
|
123
|
-
actual = runner { @app.start(%W
|
|
128
|
+
actual = runner { @app.start(%W[group addchild #{pname} #{cname}]) }
|
|
124
129
|
|
|
125
130
|
# @console.out(actual, 'y')
|
|
126
131
|
|
|
127
132
|
desired = { aborted: false }
|
|
128
133
|
desired[:STDOUT] =
|
|
129
|
-
"Associate parent group '#{pname}' with child group(s) '#{cname}':\n"\
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
134
|
+
"Associate parent group '#{pname}' with child group(s) '#{cname}':\n " \
|
|
135
|
+
"- retrieve group '#{pname}'...\n " \
|
|
136
|
+
"- OK\n " \
|
|
137
|
+
"- add association {group:#{pname} <-> group:#{cname}}...\n " \
|
|
138
|
+
"- OK\n " \
|
|
139
|
+
"- all OK\n" \
|
|
135
140
|
"Succeeded.\n"
|
|
136
141
|
expected(actual, desired)
|
|
137
142
|
|
|
@@ -143,28 +148,76 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
143
148
|
end
|
|
144
149
|
|
|
145
150
|
#------------------------
|
|
146
|
-
it 'GROUP CHILDGROUP
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
it 'GROUP CHILDGROUP --dry-run should not create the child or association' do
|
|
152
|
+
pname = 'parent_group'
|
|
153
|
+
cname = 'dry_child'
|
|
154
|
+
|
|
155
|
+
runner { @app.start(%W[group add #{pname}]) }
|
|
156
|
+
|
|
157
|
+
actual = runner { @app.start(%W[group addchild #{pname} #{cname} --dry-run]) }
|
|
158
|
+
|
|
159
|
+
expect(actual[:unexpected]).to eq(false)
|
|
160
|
+
expect(actual[:aborted]).to eq(false)
|
|
161
|
+
expect(actual[:STDOUT]).to include('Dry run complete. No changes applied.')
|
|
162
|
+
expect(@db.models[:group].find(name: cname)).to be_nil
|
|
163
|
+
pgroup = @db.models[:group].find(name: pname)
|
|
164
|
+
expect(pgroup.children_dataset[name: cname]).to be_nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
#------------------------
|
|
168
|
+
|
|
169
|
+
it 'GROUP CHILDGROUP... should warn and skip when the association already exists' do
|
|
170
|
+
pname = 'parent_group'
|
|
171
|
+
cname = 'child_group'
|
|
172
|
+
|
|
173
|
+
runner { @app.start(%W[group add #{pname} #{cname}]) }
|
|
174
|
+
runner { @app.start(%W[group addchild #{pname} #{cname}]) }
|
|
175
|
+
|
|
176
|
+
actual = runner { @app.start(%W[group addchild #{pname} #{cname}]) }
|
|
177
|
+
|
|
178
|
+
desired = { aborted: false }
|
|
179
|
+
desired[:STDOUT] = <<~OUTPUT
|
|
180
|
+
Associate parent group '#{pname}' with child group(s) '#{cname}':
|
|
181
|
+
- retrieve group '#{pname}'...
|
|
182
|
+
- OK
|
|
183
|
+
- add association {group:#{pname} <-> group:#{cname}}...
|
|
184
|
+
- already exists, skipping.
|
|
185
|
+
- OK
|
|
186
|
+
- all OK
|
|
187
|
+
Succeeded, with warnings.
|
|
188
|
+
OUTPUT
|
|
189
|
+
desired[:STDERR] = <<~ERROR
|
|
190
|
+
WARNING: Association {group:#{pname} <-> group:#{cname}} already exists, skipping.
|
|
191
|
+
ERROR
|
|
192
|
+
expected(actual, desired)
|
|
193
|
+
|
|
194
|
+
pgroup = @db.models[:group].find(name: pname)
|
|
195
|
+
cgroups = pgroup.children_dataset
|
|
196
|
+
expect(cgroups.count).to eq(1)
|
|
197
|
+
expect(cgroups[name: cname]).not_to be_nil
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
it 'GROUP CHILDGROUP... should associate GROUP with a CHILDGROUP ' \
|
|
201
|
+
'creating it if necessary' do
|
|
149
202
|
pname = 'parent_group'
|
|
150
203
|
cname = 'child_group'
|
|
151
204
|
|
|
152
|
-
runner { @app.start(%W
|
|
205
|
+
runner { @app.start(%W[group add #{pname}]) } # <- don't pre-create the child
|
|
153
206
|
|
|
154
|
-
actual = runner { @app.start(%W
|
|
207
|
+
actual = runner { @app.start(%W[group addchild #{pname} #{cname}]) }
|
|
155
208
|
|
|
156
209
|
# @console.out(actual, 'y')
|
|
157
210
|
|
|
158
211
|
desired = { aborted: false }
|
|
159
212
|
desired[:STDOUT] =
|
|
160
|
-
"Associate parent group '#{pname}' with child group(s) '#{cname}':\n"\
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
213
|
+
"Associate parent group '#{pname}' with child group(s) '#{cname}':\n " \
|
|
214
|
+
"- retrieve group '#{pname}'...\n " \
|
|
215
|
+
"- OK\n " \
|
|
216
|
+
"- add association {group:#{pname} <-> group:#{cname}}...\n " \
|
|
217
|
+
"- child group does not exist, creating now...\n " \
|
|
218
|
+
"- OK\n " \
|
|
219
|
+
"- OK\n " \
|
|
220
|
+
"- all OK\n" \
|
|
168
221
|
"Succeeded, with warnings.\n"
|
|
169
222
|
desired[:STDERR] = "WARNING: Group '#{cname}' does not exist and will be created.\n"
|
|
170
223
|
expected(actual, desired)
|
|
@@ -177,3 +230,4 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
177
230
|
end
|
|
178
231
|
end
|
|
179
232
|
end
|
|
233
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,52 +1,35 @@
|
|
|
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::Group do
|
|
7
9
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
22
|
-
|
|
23
|
-
@config = Moose::Inventory::Config
|
|
24
|
-
@config.init(@mockargs)
|
|
25
|
-
|
|
26
|
-
@db = Moose::Inventory::DB
|
|
27
|
-
@db.init if @db.db.nil?
|
|
28
|
-
|
|
29
|
-
@group = Moose::Inventory::Cli::Group
|
|
30
|
-
@host = Moose::Inventory::Cli::Host
|
|
31
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(
|
|
11
|
+
command_class: Moose::Inventory::Cli::Group,
|
|
12
|
+
command_ivar: :@group,
|
|
13
|
+
extra_commands: { :@host => Moose::Inventory::Cli::Host }
|
|
14
|
+
)
|
|
32
15
|
end
|
|
33
16
|
|
|
34
17
|
before(:each) do
|
|
35
|
-
|
|
18
|
+
reset_cli_harness
|
|
36
19
|
end
|
|
37
20
|
|
|
38
21
|
#=======================
|
|
39
22
|
describe 'addhost' do
|
|
40
23
|
#------------------------
|
|
41
24
|
it 'Group.addhost() should be responsive' do
|
|
42
|
-
result = @group.
|
|
25
|
+
result = @group.method_defined?(:addhost, false)
|
|
43
26
|
expect(result).to eq(true)
|
|
44
27
|
end
|
|
45
28
|
|
|
46
29
|
#------------------------
|
|
47
30
|
it 'addhost <missing args> ... should abort with an error' do
|
|
48
31
|
actual = runner do
|
|
49
|
-
@app.start(%w
|
|
32
|
+
@app.start(%w[group addhost]) # <- no group given
|
|
50
33
|
end
|
|
51
34
|
|
|
52
35
|
# @console.out(actual, 'y')
|
|
@@ -63,17 +46,17 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
63
46
|
group_name = 'not-a-group'
|
|
64
47
|
|
|
65
48
|
actual = runner do
|
|
66
|
-
@app.start(%W
|
|
49
|
+
@app.start(%W[group addhost #{group_name} #{host_name}])
|
|
67
50
|
end
|
|
68
51
|
|
|
69
52
|
# @console.out(actual, 'y')
|
|
70
53
|
# Check output
|
|
71
54
|
desired = { aborted: true }
|
|
72
55
|
desired[:STDOUT] =
|
|
73
|
-
"Associate group '#{group_name}' with host(s) '#{host_name}':\n"\
|
|
74
|
-
"
|
|
56
|
+
"Associate group '#{group_name}' with host(s) '#{host_name}':\n " \
|
|
57
|
+
"- retrieve group '#{group_name}'...\n"
|
|
75
58
|
desired[:STDERR] =
|
|
76
|
-
"ERROR: The group '#{group_name}' does not exist.\n"\
|
|
59
|
+
"ERROR: The group '#{group_name}' does not exist.\n" \
|
|
77
60
|
"An error occurred during a transaction, any changes have been rolled back.\n"
|
|
78
61
|
expected(actual, desired)
|
|
79
62
|
end
|
|
@@ -86,26 +69,23 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
86
69
|
host_name = 'test1'
|
|
87
70
|
group_name = 'testgroup1'
|
|
88
71
|
|
|
89
|
-
runner { @app.start(%W
|
|
72
|
+
runner { @app.start(%W[host add #{host_name}]) }
|
|
90
73
|
@db.models[:group].create(name: group_name)
|
|
91
74
|
|
|
92
|
-
actual = runner { @app.start(%W
|
|
75
|
+
actual = runner { @app.start(%W[group addhost #{group_name} #{host_name}]) }
|
|
93
76
|
|
|
94
|
-
# rubocop:disable Metrics/LineLength
|
|
95
77
|
desired = { aborted: false }
|
|
96
78
|
desired[:STDOUT] =
|
|
97
|
-
"Associate group '#{group_name}' with host(s) '#{host_name}':\n"\
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
79
|
+
"Associate group '#{group_name}' with host(s) '#{host_name}':\n " \
|
|
80
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
81
|
+
"- OK\n " \
|
|
82
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
83
|
+
"- OK\n " \
|
|
84
|
+
"- remove automatic association {group:ungrouped <-> host:#{host_name}}...\n " \
|
|
85
|
+
"- OK\n " \
|
|
86
|
+
"- all OK\n" \
|
|
105
87
|
"Succeeded.\n"
|
|
106
88
|
expected(actual, desired)
|
|
107
|
-
# rubocop:enable Metrics/LineLength
|
|
108
|
-
|
|
109
89
|
# We should have the correct group associations
|
|
110
90
|
host = @db.models[:host].find(name: host_name)
|
|
111
91
|
groups = host.groups_dataset
|
|
@@ -114,14 +94,30 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
114
94
|
expect(groups[name: 'ungrouped']).to be_nil # redundant, but for clarity!
|
|
115
95
|
end
|
|
116
96
|
|
|
97
|
+
#------------------------
|
|
98
|
+
it 'group addhost GROUP HOST --dry-run should not create the host or association' do
|
|
99
|
+
host_name = 'dry-host'
|
|
100
|
+
group_name = 'testgroup1'
|
|
101
|
+
runner { @app.start(%W[group add #{group_name}]) }
|
|
102
|
+
|
|
103
|
+
actual = runner { @app.start(%W[group addhost #{group_name} #{host_name} --dry-run]) }
|
|
104
|
+
|
|
105
|
+
expect(actual[:unexpected]).to eq(false)
|
|
106
|
+
expect(actual[:aborted]).to eq(false)
|
|
107
|
+
expect(actual[:STDOUT]).to include('Dry run complete. No changes applied.')
|
|
108
|
+
expect(@db.models[:host].find(name: host_name)).to be_nil
|
|
109
|
+
group = @db.models[:group].find(name: group_name)
|
|
110
|
+
expect(group.hosts_dataset[name: host_name]).to be_nil
|
|
111
|
+
end
|
|
112
|
+
|
|
117
113
|
#------------------------
|
|
118
114
|
it '\'ungrouped\' HOST... should abort with an error' do
|
|
119
115
|
host_name = 'test1'
|
|
120
116
|
group_name = 'ungrouped'
|
|
121
117
|
|
|
122
|
-
runner { @app.start(%W
|
|
118
|
+
runner { @app.start(%W[host add #{host_name}]) }
|
|
123
119
|
|
|
124
|
-
actual = runner { @app.start(%W
|
|
120
|
+
actual = runner { @app.start(%W[group addhost #{group_name} #{host_name}]) }
|
|
125
121
|
|
|
126
122
|
desired = { aborted: true }
|
|
127
123
|
desired[:STDERR] =
|
|
@@ -134,23 +130,23 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
134
130
|
host_name = 'test1'
|
|
135
131
|
group_name = 'testgroup1'
|
|
136
132
|
|
|
137
|
-
runner { @app.start(%W
|
|
133
|
+
runner { @app.start(%W[group add #{group_name}]) }
|
|
138
134
|
|
|
139
135
|
# DON'T CREATE THE HOST! That's the point of the test. ;o)
|
|
140
136
|
|
|
141
|
-
actual = runner { @app.start(%W
|
|
137
|
+
actual = runner { @app.start(%W[group addhost #{group_name} #{host_name}]) }
|
|
142
138
|
|
|
143
139
|
# Check output
|
|
144
140
|
desired = {}
|
|
145
141
|
desired[:STDOUT] =
|
|
146
|
-
"Associate group '#{group_name}' with host(s) '#{host_name}':\n"\
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
142
|
+
"Associate group '#{group_name}' with host(s) '#{host_name}':\n " \
|
|
143
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
144
|
+
"- OK\n " \
|
|
145
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
146
|
+
"- host does not exist, creating now...\n " \
|
|
147
|
+
"- OK\n " \
|
|
148
|
+
"- OK\n " \
|
|
149
|
+
"- all OK\n" \
|
|
154
150
|
"Succeeded, with warnings.\n"
|
|
155
151
|
desired[:STDERR] =
|
|
156
152
|
"WARNING: Host '#{host_name}' does not exist and will be created.\n"
|
|
@@ -164,32 +160,32 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
164
160
|
end
|
|
165
161
|
|
|
166
162
|
#------------------------
|
|
167
|
-
it 'GROUP HOST... should skip associations that already
|
|
168
|
-
'
|
|
163
|
+
it 'GROUP HOST... should skip associations that already ' \
|
|
164
|
+
'exist, but raise a warning.' do
|
|
169
165
|
host_name = 'test1'
|
|
170
166
|
group_name = 'testgroup1'
|
|
171
167
|
|
|
172
|
-
runner { @app.start(%W
|
|
173
|
-
runner { @app.start(%W
|
|
168
|
+
runner { @app.start(%W[group add #{group_name}]) }
|
|
169
|
+
runner { @app.start(%W[host add #{host_name}]) }
|
|
174
170
|
|
|
175
171
|
# Run once to make the initial association
|
|
176
|
-
runner { @app.start(%W
|
|
172
|
+
runner { @app.start(%W[group addhost #{group_name} #{host_name}]) }
|
|
177
173
|
|
|
178
174
|
# Run again, to prove expected result
|
|
179
|
-
actual = runner { @app.start(%W
|
|
175
|
+
actual = runner { @app.start(%W[group addhost #{group_name} #{host_name}]) }
|
|
180
176
|
|
|
181
177
|
# @console.out(actual,'y')
|
|
182
178
|
|
|
183
179
|
# Check output
|
|
184
180
|
desired = {}
|
|
185
181
|
desired[:STDOUT] =
|
|
186
|
-
"Associate group '#{group_name}' with host(s) '#{host_name}':\n"\
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
182
|
+
"Associate group '#{group_name}' with host(s) '#{host_name}':\n " \
|
|
183
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
184
|
+
"- OK\n " \
|
|
185
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
186
|
+
"- already exists, skipping.\n " \
|
|
187
|
+
"- OK\n " \
|
|
188
|
+
"- all OK\n" \
|
|
193
189
|
"Succeeded, with warnings.\n"
|
|
194
190
|
desired[:STDERR] =
|
|
195
191
|
"WARNING: Association {group:#{group_name} <-> host:#{host_name}} already exists, skipping.\n"
|
|
@@ -203,38 +199,38 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
203
199
|
end
|
|
204
200
|
|
|
205
201
|
#------------------------
|
|
206
|
-
it 'GROUP HOST1 HOST2 ... should associate the group with
|
|
207
|
-
|
|
202
|
+
it 'GROUP HOST1 HOST2 ... should associate the group with ' \
|
|
203
|
+
'multiple hosts at once' do
|
|
208
204
|
group_name = 'test1'
|
|
209
|
-
host_names = %w
|
|
205
|
+
host_names = %w[host1 host2 host3]
|
|
210
206
|
|
|
211
|
-
runner { @app.start(%W
|
|
207
|
+
runner { @app.start(%W[group add #{group_name}]) }
|
|
212
208
|
host_names.each do |host|
|
|
213
|
-
runner { @app.start(%W
|
|
209
|
+
runner { @app.start(%W[host add #{host}]) }
|
|
214
210
|
end
|
|
215
211
|
|
|
216
|
-
actual = runner { @app.start(%W
|
|
212
|
+
actual = runner { @app.start(%W[group addhost #{group_name}] + host_names) }
|
|
217
213
|
|
|
218
214
|
# @console.out(actual, 'y')
|
|
219
215
|
|
|
220
216
|
# Check output
|
|
221
217
|
desired = { aborted: false, STDERR: '' }
|
|
222
218
|
desired[:STDOUT] =
|
|
223
|
-
"Associate group '#{group_name}' with host(s) '#{host_names.join(',')}':\n"\
|
|
224
|
-
"
|
|
225
|
-
"
|
|
219
|
+
"Associate group '#{group_name}' with host(s) '#{host_names.join(',')}':\n " \
|
|
220
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
221
|
+
"- OK\n"
|
|
226
222
|
host_names.each do |host|
|
|
227
223
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
228
|
-
" - add association {group:#{group_name} <-> host:#{host}}...\n"\
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
224
|
+
" - add association {group:#{group_name} <-> host:#{host}}...\n " \
|
|
225
|
+
"- OK\n " \
|
|
226
|
+
"- remove automatic association {group:ungrouped <-> host:#{host}}...\n " \
|
|
227
|
+
"- OK\n" \
|
|
232
228
|
|
|
233
229
|
# desired[:STDERR] = desired[:STDERR] +
|
|
234
230
|
# "WARNING: Host '#{host}' does not exist and will be created.\n"
|
|
235
231
|
end
|
|
236
232
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
237
|
-
" - all OK\n"\
|
|
233
|
+
" - all OK\n" \
|
|
238
234
|
"Succeeded.\n"
|
|
239
235
|
expected(actual, desired)
|
|
240
236
|
|
|
@@ -246,3 +242,4 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
246
242
|
end
|
|
247
243
|
end
|
|
248
244
|
end
|
|
245
|
+
# rubocop:enable Metrics/BlockLength
|