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,48 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
1
4
|
require 'spec_helper'
|
|
2
5
|
|
|
3
6
|
RSpec.describe Moose::Inventory::Cli::Group do
|
|
4
7
|
before(:all) do
|
|
5
|
-
|
|
6
|
-
@mockarg_parts = {
|
|
7
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
8
|
-
format: 'yaml',
|
|
9
|
-
env: 'test',
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@mockargs = []
|
|
13
|
-
@mockarg_parts.each do |key, val|
|
|
14
|
-
@mockargs << "--#{key}"
|
|
15
|
-
@mockargs << val
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
@config = Moose::Inventory::Config
|
|
19
|
-
@config.init(@mockargs)
|
|
20
|
-
|
|
21
|
-
@db = Moose::Inventory::DB
|
|
22
|
-
@db.init if @db.db.nil?
|
|
23
|
-
|
|
24
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
25
|
-
@group = Moose::Inventory::Cli::Group
|
|
26
|
-
@cli = Moose::Inventory::Cli
|
|
27
|
-
@app = Moose::Inventory::Cli::Application
|
|
8
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Group, command_ivar: :@group, include_cli: true)
|
|
28
9
|
end
|
|
29
10
|
|
|
30
11
|
before(:each) do
|
|
31
|
-
|
|
12
|
+
reset_cli_harness
|
|
32
13
|
end
|
|
33
14
|
|
|
34
15
|
#====================
|
|
35
16
|
describe 'list' do
|
|
36
17
|
#---------------------
|
|
37
18
|
it 'should be responsive' do
|
|
38
|
-
result = @group.
|
|
19
|
+
result = @group.method_defined?(:list, false)
|
|
39
20
|
expect(result).to eq(true)
|
|
40
21
|
end
|
|
41
22
|
|
|
42
23
|
#---------------------
|
|
43
24
|
it 'should return an empty set when no results' do
|
|
44
25
|
# no items in the db
|
|
45
|
-
actual = runner { @app.start(%w
|
|
26
|
+
actual = runner { @app.start(%w[group list]) }
|
|
46
27
|
|
|
47
28
|
desired = { aborted: false, STDOUT: '', STDERR: '' }
|
|
48
29
|
desired[:STDOUT] = {}.to_yaml
|
|
@@ -53,19 +34,18 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
53
34
|
#---------------------
|
|
54
35
|
it 'should get a list of group from the db' do
|
|
55
36
|
var = 'foo=bar'
|
|
56
|
-
host_name = 'test_host'
|
|
57
37
|
|
|
58
38
|
mock = {}
|
|
59
|
-
groups = %w
|
|
39
|
+
groups = %w[group1 group2 group3]
|
|
60
40
|
groups.each do |name|
|
|
61
|
-
runner { @app.start(%W
|
|
62
|
-
runner { @app.start(%W
|
|
41
|
+
runner { @app.start(%W[group add #{name}]) }
|
|
42
|
+
runner { @app.start(%W[group addvar #{name} #{var}]) }
|
|
63
43
|
mock[name.to_sym] = {}
|
|
64
44
|
mock[name.to_sym][:groupvars] = { foo: 'bar' }
|
|
65
45
|
end
|
|
66
46
|
|
|
67
47
|
# items should now be in the db
|
|
68
|
-
actual = runner { @app.start(%w
|
|
48
|
+
actual = runner { @app.start(%w[group list]) }
|
|
69
49
|
|
|
70
50
|
desired = { aborted: false, STDOUT: '', STDERR: '' }
|
|
71
51
|
desired[:STDOUT] = mock.to_yaml
|
|
@@ -75,12 +55,10 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
75
55
|
|
|
76
56
|
#---------------------
|
|
77
57
|
it 'should be an alias of --list (i.e. Ansible parameter)' do
|
|
78
|
-
host_name = 'test_host'
|
|
79
|
-
|
|
80
58
|
mock = {}
|
|
81
|
-
groups = %w
|
|
59
|
+
groups = %w[group1 group2 group3]
|
|
82
60
|
groups.each do |name|
|
|
83
|
-
runner { @app.start(%W
|
|
61
|
+
runner { @app.start(%W[group add #{name}]) }
|
|
84
62
|
mock[name.to_sym] = { hosts: [] }
|
|
85
63
|
end
|
|
86
64
|
|
|
@@ -92,10 +70,10 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
92
70
|
# @console.out(actual, 'y')
|
|
93
71
|
|
|
94
72
|
desired = { aborted: false, STDOUT: '', STDERR: '' }
|
|
95
|
-
desired[:STDOUT] = mock.to_json
|
|
73
|
+
desired[:STDOUT] = "#{mock.to_json}\n"
|
|
96
74
|
|
|
97
75
|
expected(actual, desired)
|
|
98
76
|
end
|
|
99
|
-
end
|
|
100
77
|
end
|
|
101
|
-
|
|
78
|
+
end
|
|
79
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,50 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
1
4
|
require 'spec_helper'
|
|
2
5
|
|
|
3
6
|
RSpec.describe Moose::Inventory::Cli::Group do
|
|
4
7
|
before(:all) do
|
|
5
|
-
|
|
6
|
-
@mockarg_parts = {
|
|
7
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
8
|
-
format: 'yaml',
|
|
9
|
-
env: 'test',
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@mockargs = []
|
|
13
|
-
@mockarg_parts.each do |key, val|
|
|
14
|
-
@mockargs << "--#{key}"
|
|
15
|
-
@mockargs << val
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
@config = Moose::Inventory::Config
|
|
19
|
-
@config.init(@mockargs)
|
|
20
|
-
|
|
21
|
-
@db = Moose::Inventory::DB
|
|
22
|
-
@db.init if @db.db.nil?
|
|
23
|
-
|
|
24
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
25
|
-
@group = Moose::Inventory::Cli::Group
|
|
26
|
-
@cli = Moose::Inventory::Cli
|
|
27
|
-
@app = Moose::Inventory::Cli::Application
|
|
8
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Group, command_ivar: :@group, include_cli: true)
|
|
28
9
|
end
|
|
29
10
|
|
|
30
11
|
before(:each) do
|
|
31
|
-
|
|
32
|
-
# so we must reset config on each pass
|
|
33
|
-
@config.init(@mockargs)
|
|
34
|
-
@db.reset
|
|
12
|
+
reset_cli_harness(reset_config: true)
|
|
35
13
|
end
|
|
36
14
|
|
|
37
15
|
#==================
|
|
38
16
|
describe 'listvar' do
|
|
39
17
|
#-----------------
|
|
40
18
|
it 'should be responsive' do
|
|
41
|
-
result = @group.
|
|
19
|
+
result = @group.method_defined?(:listvars, false)
|
|
42
20
|
expect(result).to eq(true)
|
|
43
21
|
end
|
|
44
22
|
|
|
45
23
|
#-----------------
|
|
46
24
|
it '<missing args> ... should abort with an error' do
|
|
47
|
-
actual = runner { @app.start(%w
|
|
25
|
+
actual = runner { @app.start(%w[group listvars]) }
|
|
48
26
|
|
|
49
27
|
# Check output
|
|
50
28
|
desired = { aborted: true }
|
|
@@ -55,7 +33,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
55
33
|
#-----------------
|
|
56
34
|
it '--ansible <missing args> ... should abort with an error' do
|
|
57
35
|
args = @mockargs.clone
|
|
58
|
-
args.
|
|
36
|
+
args.push('--ansible', 'group', 'listvars').flatten
|
|
59
37
|
|
|
60
38
|
actual = runner { @cli.start(args) }
|
|
61
39
|
|
|
@@ -68,13 +46,13 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
68
46
|
#------------------------
|
|
69
47
|
it 'GROUP ... should return a list of group variables grouped by group' do
|
|
70
48
|
group_name = 'test_group'
|
|
71
|
-
group_vars = %w
|
|
49
|
+
group_vars = %w[foo=bar cow=chicken]
|
|
72
50
|
|
|
73
|
-
|
|
74
|
-
|
|
51
|
+
runner { @app.start(%W[group add #{group_name}]) }
|
|
52
|
+
runner { @app.start(%W[group addvar #{group_name} #{group_vars[0]} #{group_vars[1]}]) }
|
|
75
53
|
|
|
76
54
|
actual = runner do
|
|
77
|
-
@app.start(%W
|
|
55
|
+
@app.start(%W[group listvars #{group_name}])
|
|
78
56
|
end
|
|
79
57
|
|
|
80
58
|
# @console.out(actual, 'y')
|
|
@@ -93,15 +71,15 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
93
71
|
end
|
|
94
72
|
|
|
95
73
|
#------------------------
|
|
96
|
-
it '
|
|
74
|
+
it 'returns group variables in an Ansible-style hostvars payload' do
|
|
97
75
|
group_name = 'test_group'
|
|
98
|
-
group_vars = %w
|
|
76
|
+
group_vars = %w[foo=bar cow=chicken]
|
|
99
77
|
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
runner { @app.start(%W[group add #{group_name}]) }
|
|
79
|
+
runner { @app.start(%W[group addvar #{group_name} #{group_vars[0]} #{group_vars[1]}]) }
|
|
102
80
|
|
|
103
81
|
actual = runner do
|
|
104
|
-
@cli.start(%W
|
|
82
|
+
@cli.start(%W[--config #{@mockarg_parts[:config]} --ansible group listvars #{group_name}])
|
|
105
83
|
end
|
|
106
84
|
|
|
107
85
|
# @console.out(actual, 'y')
|
|
@@ -114,8 +92,23 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
114
92
|
end
|
|
115
93
|
|
|
116
94
|
desired = {}
|
|
117
|
-
desired[:STDOUT] = mock.to_json
|
|
95
|
+
desired[:STDOUT] = "#{mock.to_json}\n"
|
|
96
|
+
expected(actual, desired)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#------------------------
|
|
100
|
+
it 'warns when an Ansible-mode group does not exist' do
|
|
101
|
+
group_name = 'missing_group'
|
|
102
|
+
|
|
103
|
+
actual = runner do
|
|
104
|
+
@cli.start(%W[--config #{@mockarg_parts[:config]} --ansible group listvars #{group_name}])
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
desired = {}
|
|
108
|
+
desired[:STDOUT] = "{}\n"
|
|
109
|
+
desired[:STDERR] = "WARNING: The Group #{group_name} does not exist."
|
|
118
110
|
expected(actual, desired)
|
|
119
111
|
end
|
|
120
112
|
end
|
|
121
113
|
end
|
|
114
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,51 +1,34 @@
|
|
|
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
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
|
|
24
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
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 'rm' do
|
|
40
23
|
#---------------
|
|
41
24
|
it 'Group.rm() should be responsive' do
|
|
42
|
-
result = @group.
|
|
25
|
+
result = @group.method_defined?(:rm, false)
|
|
43
26
|
expect(result).to eq(true)
|
|
44
27
|
end
|
|
45
28
|
|
|
46
29
|
#---------------
|
|
47
30
|
it '<missing argument> ... should abort with an error' do
|
|
48
|
-
actual = runner { @app.start(%w
|
|
31
|
+
actual = runner { @app.start(%w[host rm]) }
|
|
49
32
|
|
|
50
33
|
# Check output
|
|
51
34
|
desired = { aborted: true, STDERR: '', STDOUT: '' }
|
|
@@ -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 rm ungrouped]) }
|
|
59
42
|
|
|
60
43
|
# Check output
|
|
61
44
|
desired = { aborted: true }
|
|
@@ -73,16 +56,16 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
73
56
|
|
|
74
57
|
# no items in the db
|
|
75
58
|
group_name = 'fake'
|
|
76
|
-
actual = runner { @app.start(%W
|
|
59
|
+
actual = runner { @app.start(%W[group rm #{group_name} --yes]) }
|
|
77
60
|
|
|
78
61
|
# @console.out(actual,'y')
|
|
79
62
|
desired = {}
|
|
80
63
|
desired[:STDOUT] =
|
|
81
|
-
"Remove group '#{group_name}':\n"\
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
64
|
+
"Remove group '#{group_name}':\n " \
|
|
65
|
+
"- Retrieve group '#{group_name}'...\n " \
|
|
66
|
+
"- No such group, skipping.\n " \
|
|
67
|
+
"- OK\n " \
|
|
68
|
+
"- All OK\n" \
|
|
86
69
|
"Succeeded, with warnings.\n"
|
|
87
70
|
desired[:STDERR] =
|
|
88
71
|
"WARNING: Group '#{group_name}' does not exist, skipping.\n"
|
|
@@ -95,17 +78,17 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
95
78
|
group_name = 'test1'
|
|
96
79
|
@db.models[:group].create(name: group_name)
|
|
97
80
|
|
|
98
|
-
actual = runner { @app.start(%W
|
|
81
|
+
actual = runner { @app.start(%W[group rm #{group_name} --yes]) }
|
|
99
82
|
|
|
100
83
|
# Check output
|
|
101
84
|
desired = {}
|
|
102
85
|
desired[:STDOUT] =
|
|
103
|
-
"Remove group '#{group_name}':\n"\
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
86
|
+
"Remove group '#{group_name}':\n " \
|
|
87
|
+
"- Retrieve group '#{group_name}'...\n " \
|
|
88
|
+
"- OK\n " \
|
|
89
|
+
"- Destroy group '#{group_name}'...\n " \
|
|
90
|
+
"- OK\n " \
|
|
91
|
+
"- All OK\n" \
|
|
109
92
|
"Succeeded.\n"
|
|
110
93
|
expected(actual, desired)
|
|
111
94
|
|
|
@@ -114,12 +97,68 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
114
97
|
expect(group).to be_nil
|
|
115
98
|
end
|
|
116
99
|
|
|
100
|
+
#---------------
|
|
101
|
+
it 'GROUP without --yes or --dry-run should abort before deleting' do
|
|
102
|
+
group_name = 'group1'
|
|
103
|
+
@db.models[:group].create(name: group_name)
|
|
104
|
+
|
|
105
|
+
actual = runner { @app.start(%W[group rm #{group_name}]) }
|
|
106
|
+
|
|
107
|
+
desired = {
|
|
108
|
+
aborted: true,
|
|
109
|
+
STDOUT: '',
|
|
110
|
+
STDERR: "ERROR: group rm #{group_name} is destructive. Re-run with --yes to confirm, " \
|
|
111
|
+
"or use --dry-run to preview.\n"
|
|
112
|
+
}
|
|
113
|
+
expected(actual, desired)
|
|
114
|
+
expect(@db.models[:group].find(name: group_name)).not_to be_nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
#---------------
|
|
118
|
+
it 'GROUP --dry-run should show planned removal without deleting the group' do
|
|
119
|
+
group_name = 'test1'
|
|
120
|
+
@db.models[:group].create(name: group_name)
|
|
121
|
+
|
|
122
|
+
actual = runner { @app.start(%W[group rm #{group_name} --dry-run]) }
|
|
123
|
+
|
|
124
|
+
desired = {}
|
|
125
|
+
desired[:STDOUT] =
|
|
126
|
+
"Remove group '#{group_name}':\n " \
|
|
127
|
+
"- Retrieve group '#{group_name}'...\n " \
|
|
128
|
+
"- OK\n " \
|
|
129
|
+
"- Destroy group '#{group_name}'...\n " \
|
|
130
|
+
"- OK\n " \
|
|
131
|
+
"- All OK\n" \
|
|
132
|
+
"Dry run complete. No changes applied.\n" \
|
|
133
|
+
"Succeeded.\n"
|
|
134
|
+
|
|
135
|
+
expected(actual, desired)
|
|
136
|
+
expect(@db.models[:group].find(name: group_name)).not_to be_nil
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
#---------------
|
|
140
|
+
it 'GROUP --recursive --dry-run should show recursive cleanup without deleting groups' do
|
|
141
|
+
runner { @app.start(%w[group add parent]) }
|
|
142
|
+
runner { @app.start(%w[group add child --hosts child-host]) }
|
|
143
|
+
runner { @app.start(%w[group addchild parent child]) }
|
|
144
|
+
|
|
145
|
+
actual = runner { @app.start(%w[group rm --recursive parent --dry-run]) }
|
|
146
|
+
|
|
147
|
+
expect(actual[:unexpected]).to eq(false)
|
|
148
|
+
expect(actual[:aborted]).to eq(false)
|
|
149
|
+
expect(actual[:STDOUT]).to include("- Recursively delete orphaned group 'child'...\n")
|
|
150
|
+
expect(actual[:STDOUT]).to include('Dry run complete. No changes applied.')
|
|
151
|
+
expect(@db.models[:group].find(name: 'parent')).not_to be_nil
|
|
152
|
+
expect(@db.models[:group].find(name: 'child')).not_to be_nil
|
|
153
|
+
host = @db.models[:host].find(name: 'child-host')
|
|
154
|
+
expect(host.groups_dataset[name: 'ungrouped']).to be_nil
|
|
155
|
+
end
|
|
117
156
|
#---------------
|
|
118
157
|
it "GROUP ... should handle the automatic 'ungrouped' group for associated hosts" do
|
|
119
158
|
host_name = 'test-host1'
|
|
120
159
|
group_name = 'test-group1'
|
|
121
160
|
|
|
122
|
-
tmp = runner { @app.start(%W
|
|
161
|
+
tmp = runner { @app.start(%W[group add #{group_name} --hosts #{host_name}]) }
|
|
123
162
|
expect(tmp[:unexpected]).to eq(false)
|
|
124
163
|
expect(tmp[:aborted]).to eq(false)
|
|
125
164
|
host = @db.models[:host].find(name: host_name)
|
|
@@ -128,21 +167,21 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
128
167
|
expect(groups_ds[name: 'ungrouped']).to be_nil # Shouldn't be ungrouped
|
|
129
168
|
|
|
130
169
|
# Now do the rm
|
|
131
|
-
actual = runner { @app.start(%W
|
|
170
|
+
actual = runner { @app.start(%W[group rm #{group_name} --yes]) }
|
|
132
171
|
|
|
133
172
|
# @console.out(actual)
|
|
134
173
|
|
|
135
174
|
# Check output
|
|
136
175
|
desired = {}
|
|
137
176
|
desired[:STDOUT] =
|
|
138
|
-
"Remove group '#{group_name}':\n"\
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
177
|
+
"Remove group '#{group_name}':\n " \
|
|
178
|
+
"- Retrieve group '#{group_name}'...\n " \
|
|
179
|
+
"- OK\n " \
|
|
180
|
+
"- Adding automatic association {group:ungrouped <-> host:#{host_name}}...\n " \
|
|
181
|
+
"- OK\n " \
|
|
182
|
+
"- Destroy group '#{group_name}'...\n " \
|
|
183
|
+
"- OK\n " \
|
|
184
|
+
"- All OK\n" \
|
|
146
185
|
"Succeeded.\n"
|
|
147
186
|
expected(actual, desired)
|
|
148
187
|
|
|
@@ -159,26 +198,26 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
159
198
|
|
|
160
199
|
#---------------
|
|
161
200
|
it 'GROUP1 GROUP2 ... should remove multiple groups' do
|
|
162
|
-
names = %w
|
|
201
|
+
names = %w[group1 group2 group3]
|
|
163
202
|
names.each do |name|
|
|
164
203
|
@db.models[:group].create(name: name)
|
|
165
204
|
end
|
|
166
205
|
|
|
167
|
-
actual = runner { @app.start(%w
|
|
206
|
+
actual = runner { @app.start(%w[group rm --yes] + names) }
|
|
168
207
|
|
|
169
208
|
# Check output
|
|
170
209
|
desired = { STDOUT: '' }
|
|
171
210
|
names.each do |name|
|
|
172
211
|
# Check output
|
|
173
212
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
174
|
-
"Remove group '#{name}':\n"\
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
213
|
+
"Remove group '#{name}':\n " \
|
|
214
|
+
"- Retrieve group '#{name}'...\n " \
|
|
215
|
+
"- OK\n " \
|
|
216
|
+
"- Destroy group '#{name}'...\n " \
|
|
217
|
+
"- OK\n " \
|
|
218
|
+
"- All OK\n"
|
|
180
219
|
end
|
|
181
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
220
|
+
desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded.\n"
|
|
182
221
|
expected(actual, desired)
|
|
183
222
|
|
|
184
223
|
# Check db
|
|
@@ -189,24 +228,24 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
189
228
|
#---------------
|
|
190
229
|
it 'GROUP ... should remove GROUP, where GROUP has an associated parent.' do
|
|
191
230
|
@db.models[:group].create(name: 'parent')
|
|
192
|
-
runner { @app.start(%w
|
|
231
|
+
runner { @app.start(%w[group addchild parent child]) }
|
|
193
232
|
|
|
194
|
-
actual = runner { @app.start(%w
|
|
233
|
+
actual = runner { @app.start(%w[group rm child --yes]) }
|
|
195
234
|
|
|
196
235
|
# Check output
|
|
197
236
|
desired = { STDOUT: '' }
|
|
198
237
|
# Check output
|
|
199
238
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
200
|
-
"Remove group 'child':\n"\
|
|
201
|
-
"
|
|
202
|
-
"
|
|
203
|
-
"
|
|
204
|
-
"
|
|
205
|
-
"
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
|
|
209
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
239
|
+
"Remove group 'child':\n " \
|
|
240
|
+
"- Retrieve group 'child'...\n " \
|
|
241
|
+
"- OK\n " \
|
|
242
|
+
"- Remove association {group:child <-> group:parent}...\n " \
|
|
243
|
+
"- OK\n " \
|
|
244
|
+
"- Destroy group 'child'...\n " \
|
|
245
|
+
"- OK\n " \
|
|
246
|
+
"- All OK\n"
|
|
247
|
+
|
|
248
|
+
desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded.\n"
|
|
210
249
|
expected(actual, desired)
|
|
211
250
|
|
|
212
251
|
# Check db
|
|
@@ -217,24 +256,24 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
217
256
|
#---------------
|
|
218
257
|
it 'GROUP ... should remove GROUP, where GROUP has an associated child.' do
|
|
219
258
|
@db.models[:group].create(name: 'parent')
|
|
220
|
-
runner { @app.start(%w
|
|
259
|
+
runner { @app.start(%w[group addchild parent child]) }
|
|
221
260
|
|
|
222
|
-
actual = runner { @app.start(%w
|
|
261
|
+
actual = runner { @app.start(%w[group rm parent --yes]) }
|
|
223
262
|
|
|
224
263
|
# Check output
|
|
225
264
|
desired = { STDOUT: '' }
|
|
226
265
|
# Check output
|
|
227
266
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
228
|
-
"Remove group 'parent':\n"\
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
|
|
237
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
267
|
+
"Remove group 'parent':\n " \
|
|
268
|
+
"- Retrieve group 'parent'...\n " \
|
|
269
|
+
"- OK\n " \
|
|
270
|
+
"- Remove association {group:parent <-> group:child}...\n " \
|
|
271
|
+
"- OK\n " \
|
|
272
|
+
"- Destroy group 'parent'...\n " \
|
|
273
|
+
"- OK\n " \
|
|
274
|
+
"- All OK\n"
|
|
275
|
+
|
|
276
|
+
desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded.\n"
|
|
238
277
|
expected(actual, desired)
|
|
239
278
|
|
|
240
279
|
# Check db
|
|
@@ -244,20 +283,20 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
244
283
|
|
|
245
284
|
#---------------
|
|
246
285
|
it 'GROUP --recursive ... should remove orphaned child groups recursively' do
|
|
247
|
-
runner { @app.start(%w
|
|
248
|
-
runner { @app.start(%w
|
|
249
|
-
runner { @app.start(%w
|
|
250
|
-
runner { @app.start(%w
|
|
251
|
-
runner { @app.start(%w
|
|
286
|
+
runner { @app.start(%w[group add parent]) }
|
|
287
|
+
runner { @app.start(%w[group add child --hosts child-host]) }
|
|
288
|
+
runner { @app.start(%w[group add grandchild]) }
|
|
289
|
+
runner { @app.start(%w[group addchild parent child]) }
|
|
290
|
+
runner { @app.start(%w[group addchild child grandchild]) }
|
|
252
291
|
|
|
253
|
-
actual = runner { @app.start(%w
|
|
292
|
+
actual = runner { @app.start(%w[group rm --recursive parent --yes]) }
|
|
254
293
|
|
|
255
294
|
expect(actual[:unexpected]).to eq(false)
|
|
256
295
|
expect(actual[:aborted]).to eq(false)
|
|
257
296
|
expect(actual[:STDOUT]).to include("- Recursively delete orphaned group 'child'...\n")
|
|
258
297
|
expect(actual[:STDOUT]).to include("- Recursively delete orphaned group 'grandchild'...\n")
|
|
259
298
|
|
|
260
|
-
%w
|
|
299
|
+
%w[parent child grandchild].each do |name|
|
|
261
300
|
expect(@db.models[:group].find(name: name)).to be_nil
|
|
262
301
|
end
|
|
263
302
|
|
|
@@ -267,11 +306,11 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
267
306
|
|
|
268
307
|
#---------------
|
|
269
308
|
it 'GROUP --recursive ... should not remove child groups with another parent' do
|
|
270
|
-
runner { @app.start(%w
|
|
271
|
-
runner { @app.start(%w
|
|
272
|
-
runner { @app.start(%w
|
|
309
|
+
runner { @app.start(%w[group add parent other-parent]) }
|
|
310
|
+
runner { @app.start(%w[group addchild parent child]) }
|
|
311
|
+
runner { @app.start(%w[group addchild other-parent child]) }
|
|
273
312
|
|
|
274
|
-
actual = runner { @app.start(%w
|
|
313
|
+
actual = runner { @app.start(%w[group rm --recursive parent --yes]) }
|
|
275
314
|
|
|
276
315
|
expect(actual[:unexpected]).to eq(false)
|
|
277
316
|
expect(actual[:aborted]).to eq(false)
|
|
@@ -283,3 +322,4 @@ RSpec.describe Moose::Inventory::Cli::Group do
|
|
|
283
322
|
end
|
|
284
323
|
end
|
|
285
324
|
end
|
|
325
|
+
# rubocop:enable Metrics/BlockLength
|