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
|
-
|
|
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
|
|
@@ -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::Group 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
|
-
@group = Moose::Inventory::Cli::Group
|
|
29
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Group, command_ivar: :@group)
|
|
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 = @group.
|
|
21
|
+
result = @group.method_defined?(:addvar, false)
|
|
41
22
|
expect(result).to eq(true)
|
|
42
23
|
end
|
|
43
24
|
|
|
44
25
|
#-----------------
|
|
45
26
|
it '<missing args> ... should abort with an error' do
|
|
46
27
|
actual = runner do
|
|
47
|
-
@app.start(%w
|
|
28
|
+
@app.start(%w[group addvar]) # <- no group given
|
|
48
29
|
end
|
|
49
30
|
# @console.out(actual, 'y')
|
|
50
31
|
|
|
@@ -60,16 +41,16 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
60
41
|
group_var = 'foo=bar'
|
|
61
42
|
|
|
62
43
|
actual = runner do
|
|
63
|
-
@app.start(%W
|
|
44
|
+
@app.start(%W[group addvar #{group_name} #{group_var}])
|
|
64
45
|
end
|
|
65
46
|
|
|
66
47
|
# Check output
|
|
67
48
|
desired = { aborted: true }
|
|
68
49
|
desired[:STDOUT] =
|
|
69
|
-
"Add variables '#{group_var}' to group '#{group_name}':\n"\
|
|
70
|
-
"
|
|
50
|
+
"Add variables '#{group_var}' to group '#{group_name}':\n " \
|
|
51
|
+
"- retrieve group '#{group_name}'...\n"
|
|
71
52
|
desired[:STDERR] =
|
|
72
|
-
"An error occurred during a transaction, any changes have been rolled back.\n"\
|
|
53
|
+
"An error occurred during a transaction, any changes have been rolled back.\n" \
|
|
73
54
|
"ERROR: The group '#{group_name}' does not exist.\n"
|
|
74
55
|
expected(actual, desired)
|
|
75
56
|
end
|
|
@@ -81,32 +62,30 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
81
62
|
|
|
82
63
|
group_name = 'test_group'
|
|
83
64
|
@db.models[:group].create(name: group_name)
|
|
84
|
-
|
|
85
|
-
var = { name: 'var1', value: 'testval' }
|
|
86
|
-
cases = %w(
|
|
65
|
+
cases = %w[
|
|
87
66
|
testvar
|
|
88
67
|
testvar=
|
|
89
68
|
=testval
|
|
90
69
|
testvar=testval=
|
|
91
70
|
=testvar=testval
|
|
92
71
|
testvar=testval=extra
|
|
93
|
-
|
|
72
|
+
]
|
|
94
73
|
|
|
95
74
|
cases.each do |args|
|
|
96
75
|
actual = runner do
|
|
97
|
-
@app.start(%W
|
|
76
|
+
@app.start(%W[group addvar #{group_name} #{args}])
|
|
98
77
|
end
|
|
99
78
|
# @console.out(actual,'p')
|
|
100
79
|
|
|
101
80
|
desired = { aborted: true }
|
|
102
81
|
desired[:STDOUT] =
|
|
103
|
-
"Add variables '#{args}' to group '#{group_name}':\n"\
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
82
|
+
"Add variables '#{args}' to group '#{group_name}':\n " \
|
|
83
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
84
|
+
"- OK\n " \
|
|
85
|
+
"- add variable '#{args}'...\n"
|
|
107
86
|
|
|
108
87
|
desired[:STDERR] =
|
|
109
|
-
"An error occurred during a transaction, any changes have been rolled back.\n"\
|
|
88
|
+
"An error occurred during a transaction, any changes have been rolled back.\n" \
|
|
110
89
|
"ERROR: Incorrect format in '{#{args}}'. Expected 'key=value'.\n"
|
|
111
90
|
|
|
112
91
|
expected(actual, desired)
|
|
@@ -124,18 +103,18 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
124
103
|
@db.models[:group].create(name: group_name)
|
|
125
104
|
|
|
126
105
|
actual = runner do
|
|
127
|
-
@app.start(%W
|
|
106
|
+
@app.start(%W[group addvar #{group_name} #{var[:name]}=#{var[:value]}])
|
|
128
107
|
end
|
|
129
108
|
# @console.out(actual,'p')
|
|
130
109
|
|
|
131
110
|
desired = { aborted: false }
|
|
132
111
|
desired[:STDOUT] =
|
|
133
|
-
"Add variables '#{var[:name]}=#{var[:value]}' to group '#{group_name}':\n"\
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
112
|
+
"Add variables '#{var[:name]}=#{var[:value]}' to group '#{group_name}':\n " \
|
|
113
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
114
|
+
"- OK\n " \
|
|
115
|
+
"- add variable '#{var[:name]}=#{var[:value]}'...\n " \
|
|
116
|
+
"- OK\n " \
|
|
117
|
+
"- all OK\n" \
|
|
139
118
|
"Succeeded.\n"
|
|
140
119
|
expected(actual, desired)
|
|
141
120
|
|
|
@@ -155,43 +134,60 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
155
134
|
group_name = 'test1'
|
|
156
135
|
varsarray = [
|
|
157
136
|
{ name: 'var1', value: 'val1' },
|
|
158
|
-
{ name: 'var2', value: 'val2' }
|
|
137
|
+
{ name: 'var2', value: 'val2' }
|
|
159
138
|
]
|
|
160
139
|
|
|
161
|
-
vars =
|
|
162
|
-
|
|
163
|
-
vars << "#{var[:name]}=#{var[:value]}"
|
|
140
|
+
vars = varsarray.map do |var|
|
|
141
|
+
"#{var[:name]}=#{var[:value]}"
|
|
164
142
|
end
|
|
165
143
|
|
|
166
144
|
@db.models[:group].create(name: group_name)
|
|
167
145
|
|
|
168
146
|
actual = runner do
|
|
169
|
-
@app.start(%W
|
|
147
|
+
@app.start(%W[group addvar #{group_name}] + vars)
|
|
170
148
|
end
|
|
171
149
|
|
|
172
150
|
# @console.out(actual,'y')
|
|
173
151
|
|
|
174
152
|
desired = { aborted: false }
|
|
175
153
|
desired[:STDOUT] =
|
|
176
|
-
"Add variables '#{vars.join(',')}' to group '#{group_name}':\n"\
|
|
177
|
-
"
|
|
178
|
-
"
|
|
154
|
+
"Add variables '#{vars.join(',')}' to group '#{group_name}':\n " \
|
|
155
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
156
|
+
"- OK\n"
|
|
179
157
|
vars.each do |var|
|
|
180
158
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
181
|
-
" - add variable '#{var}'...\n"\
|
|
182
|
-
"
|
|
159
|
+
" - add variable '#{var}'...\n " \
|
|
160
|
+
"- OK\n"
|
|
183
161
|
end
|
|
184
162
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
185
|
-
" - all OK\n"\
|
|
163
|
+
" - all OK\n" \
|
|
186
164
|
"Succeeded.\n"
|
|
187
165
|
expected(actual, desired)
|
|
188
166
|
|
|
189
167
|
# We should have the correct hostvar associations
|
|
190
168
|
group = @db.models[:group].find(name: group_name)
|
|
191
|
-
|
|
169
|
+
group.groupvars_dataset
|
|
192
170
|
expect(vars.count).to eq(vars.length)
|
|
193
171
|
end
|
|
194
172
|
|
|
173
|
+
#------------------------
|
|
174
|
+
it 'GROUP key=value --dry-run should not create or update variables' do
|
|
175
|
+
group_name = 'test1'
|
|
176
|
+
@db.models[:group].create(name: group_name)
|
|
177
|
+
runner { @app.start(%W[group addvar #{group_name} var1=old]) }
|
|
178
|
+
|
|
179
|
+
actual = runner do
|
|
180
|
+
@app.start(%W[group addvar #{group_name} var1=new var2=val2 --dry-run])
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
expect(actual[:unexpected]).to eq(false)
|
|
184
|
+
expect(actual[:aborted]).to eq(false)
|
|
185
|
+
expect(actual[:STDOUT]).to include('Dry run complete. No changes applied.')
|
|
186
|
+
group = @db.models[:group].find(name: group_name)
|
|
187
|
+
expect(group.groupvars_dataset[name: 'var1'][:value]).to eq('old')
|
|
188
|
+
expect(group.groupvars_dataset[name: 'var2']).to be_nil
|
|
189
|
+
end
|
|
190
|
+
|
|
195
191
|
#------------------------
|
|
196
192
|
it 'GROUP key=value ... should update an already existing association' do
|
|
197
193
|
# 1. Should add the var to the db
|
|
@@ -201,23 +197,23 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
201
197
|
var = { name: 'var1', value: 'testval' }
|
|
202
198
|
|
|
203
199
|
@db.models[:group].create(name: group_name)
|
|
204
|
-
runner { @app.start(%W
|
|
200
|
+
runner { @app.start(%W[group addvar #{group_name} #{var[:name]}=#{var[:value]}]) }
|
|
205
201
|
|
|
206
202
|
var[:value] = 'newtestval'
|
|
207
203
|
actual = runner do
|
|
208
|
-
@app.start(%W
|
|
204
|
+
@app.start(%W[group addvar #{group_name} #{var[:name]}=#{var[:value]}])
|
|
209
205
|
end
|
|
210
206
|
# @console.out(actual,'y')
|
|
211
207
|
|
|
212
208
|
desired = { aborted: false }
|
|
213
209
|
desired[:STDOUT] =
|
|
214
|
-
"Add variables '#{var[:name]}=#{var[:value]}' to group '#{group_name}':\n"\
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
210
|
+
"Add variables '#{var[:name]}=#{var[:value]}' to group '#{group_name}':\n " \
|
|
211
|
+
"- retrieve group '#{group_name}'...\n " \
|
|
212
|
+
"- OK\n " \
|
|
213
|
+
"- add variable '#{var[:name]}=#{var[:value]}'...\n " \
|
|
214
|
+
"- already exists, applying as an update...\n " \
|
|
215
|
+
"- OK\n " \
|
|
216
|
+
"- all OK\n" \
|
|
221
217
|
"Succeeded.\n"
|
|
222
218
|
expected(actual, desired)
|
|
223
219
|
|
|
@@ -233,3 +229,4 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
233
229
|
end
|
|
234
230
|
end
|
|
235
231
|
end
|
|
232
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,49 +1,30 @@
|
|
|
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
|
-
@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
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
24
|
-
|
|
25
|
-
@db = Moose::Inventory::DB
|
|
26
|
-
@db.init if @db.db.nil?
|
|
27
|
-
|
|
28
|
-
@group = Moose::Inventory::Cli::Group
|
|
29
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Group, command_ivar: :@group)
|
|
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 'get' do
|
|
38
19
|
#---------------------
|
|
39
20
|
it 'should be responsive' do
|
|
40
|
-
result = @group.
|
|
21
|
+
result = @group.method_defined?(:get, false)
|
|
41
22
|
expect(result).to eq(true)
|
|
42
23
|
end
|
|
43
24
|
|
|
44
25
|
#---------------------
|
|
45
26
|
it '<missing args> ... should abort with an error' do
|
|
46
|
-
actual = runner { @app.start(%w
|
|
27
|
+
actual = runner { @app.start(%w[group get]) }
|
|
47
28
|
|
|
48
29
|
# @console.out(actual,'y')
|
|
49
30
|
|
|
@@ -56,7 +37,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
56
37
|
#---------------------
|
|
57
38
|
it "GROUP ... should return an empty set when GROUP doesn't exist" do
|
|
58
39
|
group_name = 'does-not-exist'
|
|
59
|
-
actual = runner { @app.start(%W
|
|
40
|
+
actual = runner { @app.start(%W[group get #{group_name}]) }
|
|
60
41
|
|
|
61
42
|
# @console.out(actual, 'y')
|
|
62
43
|
|
|
@@ -69,13 +50,15 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
69
50
|
#---------------------
|
|
70
51
|
it 'GROUP ... should get a group from the db' do
|
|
71
52
|
name = 'test_group'
|
|
72
|
-
runner { @app.start(%W
|
|
53
|
+
runner { @app.start(%W[group add #{name}]) }
|
|
73
54
|
|
|
74
|
-
actual = runner { @app.start(%W
|
|
55
|
+
actual = runner { @app.start(%W[group get #{name}]) }
|
|
75
56
|
|
|
76
57
|
mock = {}
|
|
77
58
|
mock[name.to_sym] = {}
|
|
78
|
-
#
|
|
59
|
+
# Contract: `group get` omits empty relationship collections in the default
|
|
60
|
+
# human/data output. `group list --ansible` keeps `hosts: []` because
|
|
61
|
+
# Ansible inventory consumers expect the key to exist.
|
|
79
62
|
|
|
80
63
|
desired = { aborted: false, STDOUT: '', STDERR: '' }
|
|
81
64
|
desired[:STDOUT] = mock.to_yaml
|
|
@@ -87,10 +70,10 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
87
70
|
it 'GROUP ... should display groupvars, if any are set' do
|
|
88
71
|
name = 'test_group'
|
|
89
72
|
var = 'foo=bar'
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
runner { @app.start(%W[group add #{name}]) }
|
|
74
|
+
runner { @app.start(%W[group addvar #{name} #{var}]) }
|
|
92
75
|
|
|
93
|
-
actual = runner { @app.start(%W
|
|
76
|
+
actual = runner { @app.start(%W[group get #{name}]) }
|
|
94
77
|
# @console.out(actual, 'y')
|
|
95
78
|
|
|
96
79
|
mock = {}
|
|
@@ -104,3 +87,4 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
104
87
|
end
|
|
105
88
|
end
|
|
106
89
|
end
|
|
90
|
+
# rubocop:enable Metrics/BlockLength
|