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,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
|
-
@mockargs << '--trace' # extra info for debugging
|
|
21
|
-
|
|
22
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
23
|
-
|
|
24
|
-
@config = Moose::Inventory::Config
|
|
25
|
-
@config.init(@mockargs)
|
|
26
|
-
|
|
27
|
-
@db = Moose::Inventory::DB
|
|
28
|
-
@db.init if @db.db.nil?
|
|
29
|
-
|
|
30
|
-
@host = Moose::Inventory::Cli::Host
|
|
31
|
-
@group = Moose::Inventory::Cli::Group
|
|
32
|
-
@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
|
+
extra_args: ['--trace']
|
|
15
|
+
)
|
|
33
16
|
end
|
|
34
17
|
|
|
35
18
|
before(:each) do
|
|
36
|
-
|
|
19
|
+
reset_cli_harness
|
|
37
20
|
end
|
|
38
21
|
|
|
39
22
|
# ============================
|
|
40
23
|
describe 'add' do
|
|
41
24
|
# --------------------
|
|
42
25
|
it 'Group.add() method should be responsive' do
|
|
43
|
-
result = @group.
|
|
26
|
+
result = @group.method_defined?(:add, false)
|
|
44
27
|
expect(result).to eq(true)
|
|
45
28
|
end
|
|
46
29
|
|
|
47
30
|
# --------------------
|
|
48
31
|
it '<no arguments> ... should bail with an error' do
|
|
49
|
-
actual = runner { @app.start(%w
|
|
32
|
+
actual = runner { @app.start(%w[group add]) }
|
|
50
33
|
|
|
51
34
|
desired = { aborted: true }
|
|
52
35
|
desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more.\n"
|
|
@@ -55,7 +38,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
55
38
|
|
|
56
39
|
# --------------------
|
|
57
40
|
it 'ungrouped ... should abort with an error' do
|
|
58
|
-
actual = runner { @app.start(%w
|
|
41
|
+
actual = runner { @app.start(%w[group add ungrouped]) }
|
|
59
42
|
|
|
60
43
|
# Check output
|
|
61
44
|
desired = { aborted: true }
|
|
@@ -67,17 +50,17 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
67
50
|
# --------------------
|
|
68
51
|
it 'GROUP ... should add a group to the db' do
|
|
69
52
|
name = 'test'
|
|
70
|
-
actual = runner { @app.start(%W
|
|
53
|
+
actual = runner { @app.start(%W[group add #{name}]) }
|
|
71
54
|
|
|
72
55
|
# @console.out(actual)
|
|
73
56
|
|
|
74
57
|
# Check output
|
|
75
58
|
desired = {}
|
|
76
59
|
desired[:STDOUT] =
|
|
77
|
-
"Add group '#{name}':\n"\
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
60
|
+
"Add group '#{name}':\n " \
|
|
61
|
+
"- create group...\n " \
|
|
62
|
+
"- OK\n " \
|
|
63
|
+
"- all OK\n" \
|
|
81
64
|
"Succeeded\n"
|
|
82
65
|
|
|
83
66
|
expected(actual, desired)
|
|
@@ -87,23 +70,68 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
87
70
|
expect(group[:name]).to eq(name)
|
|
88
71
|
end
|
|
89
72
|
|
|
73
|
+
# --------------------
|
|
74
|
+
it 'GROUP --dry-run should show planned group creation without writing to the db' do
|
|
75
|
+
name = 'dry-run-group'
|
|
76
|
+
|
|
77
|
+
actual = runner { @app.start(%W[group add #{name} --dry-run]) }
|
|
78
|
+
|
|
79
|
+
desired = {}
|
|
80
|
+
desired[:STDOUT] =
|
|
81
|
+
"Add group '#{name}':\n " \
|
|
82
|
+
"- create group...\n " \
|
|
83
|
+
"- OK\n " \
|
|
84
|
+
"- all OK\n" \
|
|
85
|
+
"Dry run complete. No changes applied.\n" \
|
|
86
|
+
"Succeeded\n"
|
|
87
|
+
|
|
88
|
+
expected(actual, desired)
|
|
89
|
+
expect(@db.models[:group].find(name: name)).to be_nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# --------------------
|
|
93
|
+
it 'GROUP --hosts HOST --dry-run should not create the group or missing host' do
|
|
94
|
+
group_name = 'dry-run-group'
|
|
95
|
+
host_name = 'dry-run-host'
|
|
96
|
+
|
|
97
|
+
actual = runner { @app.start(%W[group add #{group_name} --hosts #{host_name} --dry-run]) }
|
|
98
|
+
|
|
99
|
+
desired = {}
|
|
100
|
+
desired[:STDOUT] =
|
|
101
|
+
"Add group '#{group_name}':\n " \
|
|
102
|
+
"- create group...\n " \
|
|
103
|
+
"- OK\n " \
|
|
104
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
105
|
+
"- host doesn't exist, creating now...\n " \
|
|
106
|
+
"- OK\n " \
|
|
107
|
+
"- OK\n " \
|
|
108
|
+
"- all OK\n" \
|
|
109
|
+
"Dry run complete. No changes applied.\n" \
|
|
110
|
+
"Succeeded, with warnings.\n"
|
|
111
|
+
desired[:STDERR] =
|
|
112
|
+
"WARNING: Host '#{host_name}' doesn't exist, but will be created.\n"
|
|
113
|
+
|
|
114
|
+
expected(actual, desired)
|
|
115
|
+
expect(@db.models[:group].find(name: group_name)).to be_nil
|
|
116
|
+
expect(@db.models[:host].find(name: host_name)).to be_nil
|
|
117
|
+
end
|
|
90
118
|
# --------------------
|
|
91
119
|
it 'GROUP ... should skip GROUP creation if it already exists' do
|
|
92
120
|
name = 'test-group'
|
|
93
121
|
@db.models[:group].create(name: name)
|
|
94
122
|
|
|
95
|
-
actual = runner { @app.start(%W
|
|
123
|
+
actual = runner { @app.start(%W[group add #{name}]) }
|
|
96
124
|
|
|
97
125
|
# @console.out(actual)
|
|
98
126
|
|
|
99
127
|
# Check output
|
|
100
128
|
desired = {}
|
|
101
129
|
desired[:STDOUT] =
|
|
102
|
-
"Add group '#{name}':\n"\
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
130
|
+
"Add group '#{name}':\n " \
|
|
131
|
+
"- create group...\n " \
|
|
132
|
+
"- already exists, skipping.\n " \
|
|
133
|
+
"- OK\n " \
|
|
134
|
+
"- all OK\n" \
|
|
107
135
|
"Succeeded, with warnings.\n"
|
|
108
136
|
desired[:STDERR] =
|
|
109
137
|
"WARNING: Group '#{name}' already exists, skipping creation.\n"
|
|
@@ -115,9 +143,9 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
115
143
|
|
|
116
144
|
# --------------------
|
|
117
145
|
it 'GROUP1 GROUP2 GROUP3 ... should add multiple groups' do
|
|
118
|
-
names = %w
|
|
146
|
+
names = %w[test1 test2 test3]
|
|
119
147
|
|
|
120
|
-
actual = runner { @app.start(%w
|
|
148
|
+
actual = runner { @app.start(%w[group add] + names) }
|
|
121
149
|
|
|
122
150
|
# @console.out(actual)
|
|
123
151
|
|
|
@@ -125,12 +153,12 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
125
153
|
desired = { STDOUT: '' }
|
|
126
154
|
names.each do |name|
|
|
127
155
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
128
|
-
"Add group '#{name}':\n"\
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
156
|
+
"Add group '#{name}':\n " \
|
|
157
|
+
"- create group...\n " \
|
|
158
|
+
"- OK\n " \
|
|
159
|
+
"- all OK\n" \
|
|
132
160
|
end
|
|
133
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
161
|
+
desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded\n"
|
|
134
162
|
|
|
135
163
|
expected(actual, desired)
|
|
136
164
|
|
|
@@ -142,15 +170,14 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
142
170
|
end
|
|
143
171
|
|
|
144
172
|
# --------------------
|
|
145
|
-
it 'GROUP1 --hosts HOST1 ... should add the '\
|
|
146
|
-
|
|
147
|
-
|
|
173
|
+
it 'GROUP1 --hosts HOST1 ... should add the ' \
|
|
174
|
+
'group and associate it with existing hosts' do
|
|
148
175
|
host_name = 'test-host'
|
|
149
176
|
@db.models[:host].create(name: host_name)
|
|
150
177
|
|
|
151
178
|
group_name = 'test-group'
|
|
152
179
|
actual = runner do
|
|
153
|
-
@app.start(%W
|
|
180
|
+
@app.start(%W[group add #{group_name} --hosts #{host_name}])
|
|
154
181
|
end
|
|
155
182
|
|
|
156
183
|
# @console.out(actual)
|
|
@@ -158,12 +185,12 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
158
185
|
# Check output
|
|
159
186
|
desired = {}
|
|
160
187
|
desired[:STDOUT] =
|
|
161
|
-
"Add group '#{group_name}':\n"\
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
188
|
+
"Add group '#{group_name}':\n " \
|
|
189
|
+
"- create group...\n " \
|
|
190
|
+
"- OK\n " \
|
|
191
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
192
|
+
"- OK\n " \
|
|
193
|
+
"- all OK\n" \
|
|
167
194
|
"Succeeded\n"
|
|
168
195
|
|
|
169
196
|
expected(actual, desired)
|
|
@@ -184,7 +211,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
184
211
|
|
|
185
212
|
group_name = 'test-group'
|
|
186
213
|
actual = runner do
|
|
187
|
-
@app.start(%W
|
|
214
|
+
@app.start(%W[group add #{group_name} --hosts #{host_name}])
|
|
188
215
|
end
|
|
189
216
|
|
|
190
217
|
# @console.out(actual)
|
|
@@ -192,14 +219,14 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
192
219
|
# Check output
|
|
193
220
|
desired = {}
|
|
194
221
|
desired[:STDOUT] =
|
|
195
|
-
"Add group '#{group_name}':\n"\
|
|
196
|
-
"
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"
|
|
201
|
-
"
|
|
202
|
-
"
|
|
222
|
+
"Add group '#{group_name}':\n " \
|
|
223
|
+
"- create group...\n " \
|
|
224
|
+
"- OK\n " \
|
|
225
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
226
|
+
"- host doesn't exist, creating now...\n " \
|
|
227
|
+
"- OK\n " \
|
|
228
|
+
"- OK\n " \
|
|
229
|
+
"- all OK\n" \
|
|
203
230
|
"Succeeded, with warnings.\n"
|
|
204
231
|
desired[:STDERR] =
|
|
205
232
|
"WARNING: Host '#{host_name}' doesn't exist, but will be created.\n"
|
|
@@ -220,11 +247,11 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
220
247
|
group_name = 'test-group'
|
|
221
248
|
|
|
222
249
|
# Create group and association
|
|
223
|
-
runner { @app.start(%W
|
|
250
|
+
runner { @app.start(%W[group add #{group_name} --hosts #{host_name}]) }
|
|
224
251
|
|
|
225
252
|
# Do it again, to prove that we skip
|
|
226
253
|
actual = runner do
|
|
227
|
-
@app.start(%W
|
|
254
|
+
@app.start(%W[group add #{group_name} --hosts #{host_name}])
|
|
228
255
|
end
|
|
229
256
|
|
|
230
257
|
# @console.out(actual, 'y')
|
|
@@ -232,17 +259,17 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
232
259
|
# Check output
|
|
233
260
|
desired = {}
|
|
234
261
|
desired[:STDOUT] =
|
|
235
|
-
"Add group '#{group_name}':\n"\
|
|
236
|
-
"
|
|
237
|
-
"
|
|
238
|
-
"
|
|
239
|
-
"
|
|
240
|
-
"
|
|
241
|
-
"
|
|
242
|
-
"
|
|
262
|
+
"Add group '#{group_name}':\n " \
|
|
263
|
+
"- create group...\n " \
|
|
264
|
+
"- already exists, skipping.\n " \
|
|
265
|
+
"- OK\n " \
|
|
266
|
+
"- add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
267
|
+
"- already exists, skipping.\n " \
|
|
268
|
+
"- OK\n " \
|
|
269
|
+
"- all OK\n" \
|
|
243
270
|
"Succeeded, with warnings.\n"
|
|
244
271
|
desired[:STDERR] =
|
|
245
|
-
"WARNING: Group '#{group_name}' already exists, skipping creation.\n"\
|
|
272
|
+
"WARNING: Group '#{group_name}' already exists, skipping creation.\n" \
|
|
246
273
|
"WARNING: Association {group:#{group_name} <-> host:#{host_name}} already exists, skipping creation.\n"
|
|
247
274
|
|
|
248
275
|
expected(actual, desired)
|
|
@@ -256,26 +283,25 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
256
283
|
end
|
|
257
284
|
|
|
258
285
|
# --------------------
|
|
259
|
-
it 'GROUP --hosts HOST1,HOST2 ... should add the group and '\
|
|
260
|
-
|
|
261
|
-
|
|
286
|
+
it 'GROUP --hosts HOST1,HOST2 ... should add the group and ' \
|
|
287
|
+
'associate it with multiple hosts' do
|
|
262
288
|
# The group should be added
|
|
263
289
|
# Each host should be associated with the group
|
|
264
290
|
# Each host should be removed from the automatic 'ungrouped' group
|
|
265
291
|
|
|
266
292
|
group_name = 'test-group'
|
|
267
|
-
host_names = %w
|
|
293
|
+
host_names = %w[host1 host2 host3]
|
|
268
294
|
|
|
269
295
|
# Add just the first host. This ensure that we cover paths for both
|
|
270
296
|
# and existing host (with an 'ungrouped' association) and for none
|
|
271
297
|
# existing groups.
|
|
272
|
-
|
|
298
|
+
runner { @app.start(%W[host add #{host_names[0]}]) }
|
|
273
299
|
|
|
274
300
|
# @console.out(tmp, 'y')
|
|
275
301
|
|
|
276
302
|
# Now run the actual group addition
|
|
277
303
|
actual = runner do
|
|
278
|
-
@app.start(%W
|
|
304
|
+
@app.start(%W[group add #{group_name} --hosts #{host_names.join(',')}])
|
|
279
305
|
end
|
|
280
306
|
|
|
281
307
|
# @console.out(actual,'y')
|
|
@@ -283,25 +309,25 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
283
309
|
# Check output
|
|
284
310
|
desired = { aborted: false, STDERR: '', STDOUT: '' }
|
|
285
311
|
desired[:STDOUT] =
|
|
286
|
-
"Add group '#{group_name}':\n"\
|
|
287
|
-
"
|
|
288
|
-
"
|
|
289
|
-
"
|
|
290
|
-
"
|
|
291
|
-
"
|
|
292
|
-
"
|
|
312
|
+
"Add group '#{group_name}':\n " \
|
|
313
|
+
"- create group...\n " \
|
|
314
|
+
"- OK\n " \
|
|
315
|
+
"- add association {group:#{group_name} <-> host:#{host_names[0]}}...\n " \
|
|
316
|
+
"- OK\n " \
|
|
317
|
+
"- remove automatic association {group:ungrouped <-> host:#{host_names[0]}}...\n " \
|
|
318
|
+
"- OK\n"
|
|
293
319
|
|
|
294
320
|
host_names.slice(1, host_names.length - 1).each do |host_name|
|
|
295
321
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
296
|
-
" - add association {group:#{group_name} <-> host:#{host_name}}...\n"\
|
|
297
|
-
"
|
|
298
|
-
"
|
|
299
|
-
"
|
|
322
|
+
" - add association {group:#{group_name} <-> host:#{host_name}}...\n " \
|
|
323
|
+
"- host doesn't exist, creating now...\n " \
|
|
324
|
+
"- OK\n " \
|
|
325
|
+
"- OK\n"
|
|
300
326
|
desired[:STDERR] = desired[:STDERR] +
|
|
301
327
|
"WARNING: Host '#{host_name}' doesn't exist, but will be created.\n"
|
|
302
328
|
end
|
|
303
329
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
304
|
-
" - all OK\n"\
|
|
330
|
+
" - all OK\n" \
|
|
305
331
|
"Succeeded, with warnings.\n"
|
|
306
332
|
|
|
307
333
|
expected(actual, desired)
|
|
@@ -318,13 +344,13 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
318
344
|
end
|
|
319
345
|
|
|
320
346
|
# --------------------
|
|
321
|
-
it 'HOST --groups GROUP1,ungrouped ... should bail '\
|
|
322
|
-
|
|
347
|
+
it 'HOST --groups GROUP1,ungrouped ... should bail ' \
|
|
348
|
+
'with an error' do
|
|
323
349
|
name = 'testhost'
|
|
324
|
-
group_names = %w
|
|
350
|
+
group_names = %w[group1 ungrouped]
|
|
325
351
|
|
|
326
352
|
actual = runner do
|
|
327
|
-
@app.start(%W
|
|
353
|
+
@app.start(%W[host add #{name} --groups #{group_names.join(',')}])
|
|
328
354
|
end
|
|
329
355
|
|
|
330
356
|
# Check output
|
|
@@ -336,15 +362,14 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
336
362
|
end
|
|
337
363
|
|
|
338
364
|
# --------------------
|
|
339
|
-
it 'HOST1 HOST2 --groups GROUP1,GROUP2 ... should add multiple '\
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
host_names = %w(host1 host2 host3)
|
|
365
|
+
it 'HOST1 HOST2 --groups GROUP1,GROUP2 ... should add multiple ' \
|
|
366
|
+
'groups, associating each with multiple hosts' do
|
|
367
|
+
host_names = %w[host1 host2 host3]
|
|
343
368
|
# Note, relies on auto-generation of hosts
|
|
344
369
|
|
|
345
|
-
group_names = %w
|
|
370
|
+
group_names = %w[group1 group2 group3]
|
|
346
371
|
actual = runner do
|
|
347
|
-
@app.start(%w
|
|
372
|
+
@app.start(%w[group add] + group_names + %W[--hosts #{host_names.join(',')}])
|
|
348
373
|
end
|
|
349
374
|
|
|
350
375
|
# @console.out(actual,'y')
|
|
@@ -354,27 +379,25 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
354
379
|
first_pass = true
|
|
355
380
|
group_names.each do |group|
|
|
356
381
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
357
|
-
"Add group '#{group}':\n"\
|
|
358
|
-
"
|
|
359
|
-
"
|
|
382
|
+
"Add group '#{group}':\n " \
|
|
383
|
+
"- create group...\n " \
|
|
384
|
+
"- OK\n"
|
|
360
385
|
|
|
361
386
|
host_names.each do |host|
|
|
362
387
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
363
388
|
" - add association {group:#{group} <-> host:#{host}}...\n"
|
|
364
389
|
if first_pass
|
|
365
390
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
366
|
-
" - host doesn't exist, creating now...\n"\
|
|
367
|
-
"
|
|
391
|
+
" - host doesn't exist, creating now...\n " \
|
|
392
|
+
"- OK\n"
|
|
368
393
|
end
|
|
369
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
370
|
-
" - OK\n"
|
|
394
|
+
desired[:STDOUT] = "#{desired[:STDOUT]} - OK\n"
|
|
371
395
|
end
|
|
372
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
373
|
-
" - all OK\n"
|
|
396
|
+
desired[:STDOUT] = "#{desired[:STDOUT]} - all OK\n"
|
|
374
397
|
first_pass = false
|
|
375
398
|
end
|
|
376
399
|
|
|
377
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
400
|
+
desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded, with warnings.\n"
|
|
378
401
|
host_names.each do |host|
|
|
379
402
|
desired[:STDERR] = desired[:STDERR] +
|
|
380
403
|
"WARNING: Host '#{host}' doesn't exist, but will be created.\n"
|
|
@@ -395,3 +418,4 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
395
418
|
end
|
|
396
419
|
end
|
|
397
420
|
end
|
|
421
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -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
|