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,51 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
1
4
|
require 'spec_helper'
|
|
2
5
|
|
|
3
|
-
# TODO: the usual respond_to? method doesn't seem to work on Thor objects.
|
|
4
6
|
# Why not? For now, we'll check against instance_methods.
|
|
5
7
|
|
|
6
8
|
RSpec.describe Moose::Inventory::Cli::Host do
|
|
7
9
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
@mockarg_parts = {
|
|
10
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
11
|
-
format: 'yaml',
|
|
12
|
-
env: 'test',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
24
|
-
|
|
25
|
-
@db = Moose::Inventory::DB
|
|
26
|
-
@db.init if @db.db.nil?
|
|
27
|
-
|
|
28
|
-
@host = Moose::Inventory::Cli::Host
|
|
29
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host)
|
|
30
11
|
end
|
|
31
12
|
|
|
32
13
|
before(:each) do
|
|
33
|
-
|
|
14
|
+
reset_cli_harness
|
|
34
15
|
end
|
|
35
16
|
|
|
36
17
|
#=======================
|
|
37
18
|
describe 'get' do
|
|
38
19
|
#---------------------
|
|
39
20
|
it 'Host.get() should be responsive' do
|
|
40
|
-
result = @host.
|
|
21
|
+
result = @host.method_defined?(:get, false)
|
|
41
22
|
expect(result).to eq(true)
|
|
42
23
|
end
|
|
43
24
|
|
|
44
25
|
#---------------------
|
|
45
26
|
it 'host get <missing args> ... should abort with an error' do
|
|
46
27
|
# no items in the db
|
|
47
|
-
|
|
48
|
-
actual = runner { @app.start(%w(host get)) }
|
|
28
|
+
actual = runner { @app.start(%w[host get]) }
|
|
49
29
|
|
|
50
30
|
desired = { aborted: true }
|
|
51
31
|
desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more\n"
|
|
@@ -57,7 +37,7 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
57
37
|
it 'host get HOST ... should return an empty set when HOST doesn\'t exist' do
|
|
58
38
|
# no items in the db
|
|
59
39
|
name = 'not-in-db'
|
|
60
|
-
actual = runner { @app.start(%W
|
|
40
|
+
actual = runner { @app.start(%W[host get #{name}]) }
|
|
61
41
|
|
|
62
42
|
desired = {}
|
|
63
43
|
desired[:STDOUT] = {}.to_yaml
|
|
@@ -68,9 +48,9 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
68
48
|
#---------------------
|
|
69
49
|
it 'host get HOST ... should get a host from the db' do
|
|
70
50
|
name = 'test-host-add'
|
|
71
|
-
runner { @app.start(%W
|
|
51
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
72
52
|
|
|
73
|
-
actual = runner { @app.start(%W
|
|
53
|
+
actual = runner { @app.start(%W[host get #{name}]) }
|
|
74
54
|
|
|
75
55
|
mock = {}
|
|
76
56
|
mock[name.to_sym] = {}
|
|
@@ -86,10 +66,10 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
86
66
|
it 'host get HOST ... should display hostvars, if any are set' do
|
|
87
67
|
name = 'test-host-add'
|
|
88
68
|
var = 'foo=bar'
|
|
89
|
-
runner { @app.start(%W
|
|
90
|
-
runner { @app.start(%W
|
|
69
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
70
|
+
runner { @app.start(%W[host addvar #{name} #{var}]) }
|
|
91
71
|
|
|
92
|
-
actual = runner { @app.start(%W
|
|
72
|
+
actual = runner { @app.start(%W[host get #{name}]) }
|
|
93
73
|
|
|
94
74
|
mock = {}
|
|
95
75
|
mock[name.to_sym] = {}
|
|
@@ -103,3 +83,4 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
103
83
|
end
|
|
104
84
|
end
|
|
105
85
|
end
|
|
86
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,51 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
|
1
4
|
require 'spec_helper'
|
|
2
5
|
|
|
3
|
-
# TODO: the usual respond_to? method doesn't seem to work on Thor objects.
|
|
4
6
|
# Why not? For now, we'll check against instance_methods.
|
|
5
7
|
|
|
6
8
|
RSpec.describe Moose::Inventory::Cli::Host do
|
|
7
9
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
@mockarg_parts = {
|
|
10
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
11
|
-
format: 'yaml',
|
|
12
|
-
env: 'test',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
|
|
24
|
-
@db = Moose::Inventory::DB
|
|
25
|
-
@db.init if @db.db.nil?
|
|
26
|
-
|
|
27
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
28
|
-
@host = Moose::Inventory::Cli::Host
|
|
29
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host)
|
|
30
11
|
end
|
|
31
12
|
|
|
32
13
|
before(:each) do
|
|
33
|
-
|
|
14
|
+
reset_cli_harness
|
|
34
15
|
end
|
|
35
16
|
|
|
36
17
|
#====================
|
|
37
18
|
describe 'list' do
|
|
38
19
|
#---------------------
|
|
39
20
|
it 'should be responsive' do
|
|
40
|
-
result = @host.
|
|
21
|
+
result = @host.method_defined?(:list, false)
|
|
41
22
|
expect(result).to eq(true)
|
|
42
23
|
end
|
|
43
24
|
|
|
44
25
|
#---------------------
|
|
45
26
|
it 'should return an empty set when no results' do
|
|
46
27
|
# no items in the db
|
|
47
|
-
|
|
48
|
-
actual = runner { @app.start(%w(host list)) }
|
|
28
|
+
actual = runner { @app.start(%w[host list]) }
|
|
49
29
|
|
|
50
30
|
desired = { aborted: false, STDOUT: '', STDERR: '' }
|
|
51
31
|
desired[:STDOUT] = {}.to_yaml
|
|
@@ -55,25 +35,53 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
55
35
|
|
|
56
36
|
#---------------------
|
|
57
37
|
it 'should get a list of hosts from the db' do
|
|
58
|
-
var = 'foo=bar'
|
|
59
|
-
|
|
60
38
|
mock = {}
|
|
61
|
-
hosts = %w
|
|
39
|
+
hosts = %w[host1 host2 host3]
|
|
62
40
|
hosts.each do |name|
|
|
63
|
-
runner { @app.start(%W
|
|
64
|
-
runner { @app.start(%W
|
|
41
|
+
runner { @app.start(%W[host add #{name}]) }
|
|
42
|
+
runner { @app.start(%W[host addvar #{name} foo=bar]) }
|
|
65
43
|
mock[name.to_sym] = {}
|
|
66
44
|
mock[name.to_sym][:groups] = ['ungrouped']
|
|
67
45
|
mock[name.to_sym][:hostvars] = { foo: 'bar' }
|
|
68
46
|
end
|
|
69
47
|
|
|
70
48
|
# items should now be in the db
|
|
71
|
-
actual = runner { @app.start(%w
|
|
49
|
+
actual = runner { @app.start(%w[host list]) }
|
|
72
50
|
|
|
73
51
|
desired = { aborted: false, STDOUT: '', STDERR: '' }
|
|
74
52
|
desired[:STDOUT] = mock.to_yaml
|
|
75
53
|
|
|
76
54
|
expected(actual, desired)
|
|
77
55
|
end
|
|
56
|
+
|
|
57
|
+
it 'filters hosts by group, tag, and variable' do
|
|
58
|
+
runner { @app.start(%w[group add web]) }
|
|
59
|
+
runner { @app.start(%w[host add web01 --groups web]) }
|
|
60
|
+
runner { @app.start(%w[host add db01]) }
|
|
61
|
+
runner { @app.start(%w[host addtag web01 prod]) }
|
|
62
|
+
runner { @app.start(%w[host addvar web01 os=fedora]) }
|
|
63
|
+
runner { @app.start(%w[host addtag db01 prod]) }
|
|
64
|
+
runner { @app.start(%w[host addvar db01 os=debian]) }
|
|
65
|
+
|
|
66
|
+
actual = runner { @app.start(%w[host list --group web --tag prod --var os=fedora]) }
|
|
67
|
+
|
|
68
|
+
desired = { aborted: false, STDERR: '' }
|
|
69
|
+
desired[:STDOUT] = {
|
|
70
|
+
web01: {
|
|
71
|
+
groups: ['web'],
|
|
72
|
+
tags: ['prod'],
|
|
73
|
+
hostvars: { os: 'fedora' }
|
|
74
|
+
}
|
|
75
|
+
}.to_yaml
|
|
76
|
+
expected(actual, desired)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'aborts on invalid variable filters' do
|
|
80
|
+
actual = runner { @app.start(%w[host list --var broken]) }
|
|
81
|
+
|
|
82
|
+
expect(actual[:aborted]).to eq(true)
|
|
83
|
+
expect(actual[:STDERR]).to include("ERROR: Invalid variable filter 'broken'. Expected key=value.")
|
|
84
|
+
end
|
|
78
85
|
end
|
|
79
86
|
end
|
|
87
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,53 +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::Host do
|
|
7
9
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
@mockarg_parts = {
|
|
10
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
11
|
-
format: 'yaml',
|
|
12
|
-
env: 'test',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
|
|
24
|
-
@db = Moose::Inventory::DB
|
|
25
|
-
@db.init if @db.db.nil?
|
|
26
|
-
|
|
27
|
-
@console = Moose::Inventory::Cli::Formatter
|
|
28
|
-
@host = Moose::Inventory::Cli::Host
|
|
29
|
-
@cli = Moose::Inventory::Cli
|
|
30
|
-
@app = Moose::Inventory::Cli::Application
|
|
10
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host, include_cli: true)
|
|
31
11
|
end
|
|
32
12
|
|
|
33
13
|
before(:each) do
|
|
34
|
-
|
|
35
|
-
# so we must reset config on each pass
|
|
36
|
-
@config.init(@mockargs)
|
|
37
|
-
@db.reset
|
|
14
|
+
reset_cli_harness(reset_config: true)
|
|
38
15
|
end
|
|
39
16
|
|
|
40
17
|
#==================
|
|
41
18
|
describe 'listvar' do
|
|
42
19
|
#-----------------
|
|
43
20
|
it 'should be responsive' do
|
|
44
|
-
result = @host.
|
|
21
|
+
result = @host.method_defined?(:listvars, false)
|
|
45
22
|
expect(result).to eq(true)
|
|
46
23
|
end
|
|
47
24
|
|
|
48
25
|
#-----------------
|
|
49
26
|
it '<missing args> ... should abort with an error' do
|
|
50
|
-
actual = runner { @app.start(%w
|
|
27
|
+
actual = runner { @app.start(%w[host listvars]) }
|
|
51
28
|
|
|
52
29
|
# Check output
|
|
53
30
|
desired = { aborted: true }
|
|
@@ -58,7 +35,7 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
58
35
|
#-----------------
|
|
59
36
|
it '--ansible <missing args> ... should abort with an error' do
|
|
60
37
|
args = @mockargs.clone
|
|
61
|
-
args.
|
|
38
|
+
args.push('--ansible', 'host', 'listvars').flatten
|
|
62
39
|
|
|
63
40
|
actual = runner { @cli.start(args) }
|
|
64
41
|
|
|
@@ -71,13 +48,13 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
71
48
|
#------------------------
|
|
72
49
|
it 'HOST ... should return a list of host variables grouped by host' do
|
|
73
50
|
host_name = 'test_host'
|
|
74
|
-
host_vars = %w
|
|
51
|
+
host_vars = %w[foo=bar cow=chicken]
|
|
75
52
|
|
|
76
|
-
|
|
77
|
-
|
|
53
|
+
runner { @app.start(%W[host add #{host_name}]) }
|
|
54
|
+
runner { @app.start(%W[host addvar #{host_name} #{host_vars[0]} #{host_vars[1]}]) }
|
|
78
55
|
|
|
79
56
|
actual = runner do
|
|
80
|
-
@app.start(%W
|
|
57
|
+
@app.start(%W[host listvars #{host_name}])
|
|
81
58
|
end
|
|
82
59
|
|
|
83
60
|
# @console.out(actual, 'y')
|
|
@@ -98,65 +75,80 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
98
75
|
#------------------------
|
|
99
76
|
it '--ansible HOST ... should return a list of host variables per Ansible specs' do
|
|
100
77
|
host_name = 'test_host'
|
|
101
|
-
host_vars = %w
|
|
78
|
+
host_vars = %w[foo=bar cow=chicken]
|
|
102
79
|
|
|
103
|
-
|
|
104
|
-
|
|
80
|
+
runner { @app.start(%W[host add #{host_name}]) }
|
|
81
|
+
runner { @app.start(%W[host addvar #{host_name} #{host_vars[0]} #{host_vars[1]}]) }
|
|
105
82
|
|
|
106
83
|
actual = runner do
|
|
107
|
-
@cli.start(%W
|
|
84
|
+
@cli.start(%W[--config #{@mockarg_parts[:config]} --ansible host listvars #{host_name}])
|
|
108
85
|
end
|
|
109
86
|
|
|
110
87
|
# @console.out(actual, 'y')
|
|
111
88
|
|
|
112
89
|
# Check output
|
|
113
90
|
meta = {}
|
|
114
|
-
meta[
|
|
115
|
-
meta[
|
|
91
|
+
meta[:hostvars] = {}
|
|
92
|
+
meta[:hostvars][host_name.to_sym] = {}
|
|
116
93
|
|
|
117
94
|
mock = {}
|
|
118
95
|
host_vars.each do |hv|
|
|
119
96
|
hv_array = hv.split('=')
|
|
120
97
|
mock[hv_array[0].to_sym] = hv_array[1]
|
|
121
|
-
meta[
|
|
98
|
+
meta[:hostvars][host_name.to_sym][hv_array[0].to_sym] = hv_array[1]
|
|
99
|
+
end
|
|
100
|
+
mock[:_meta] = meta
|
|
101
|
+
|
|
102
|
+
desired = {}
|
|
103
|
+
desired[:STDOUT] = "#{mock.to_json}\n"
|
|
104
|
+
expected(actual, desired)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
#------------------------
|
|
108
|
+
it '--ansible HOST ... should warn when the host does not exist' do
|
|
109
|
+
host_name = 'missing_host'
|
|
110
|
+
|
|
111
|
+
actual = runner do
|
|
112
|
+
@cli.start(%W[--config #{@mockarg_parts[:config]} --ansible host listvars #{host_name}])
|
|
122
113
|
end
|
|
123
|
-
mock['_meta'.to_sym] = meta
|
|
124
114
|
|
|
125
115
|
desired = {}
|
|
126
|
-
desired[:STDOUT] =
|
|
116
|
+
desired[:STDOUT] = "{\"_meta\":{\"hostvars\":{}}}\n"
|
|
117
|
+
desired[:STDERR] = "WARNING: The host #{host_name} does not exist.\n"
|
|
127
118
|
expected(actual, desired)
|
|
128
119
|
end
|
|
129
120
|
|
|
130
121
|
#------------------------
|
|
131
122
|
it '--ansible HOST ... should be an alias for Ansible\'s --host HOST' do
|
|
132
123
|
host_name = 'test_host'
|
|
133
|
-
host_vars = %w
|
|
124
|
+
host_vars = %w[foo=bar cow=chicken]
|
|
134
125
|
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
runner { @app.start(%W[host add #{host_name}]) }
|
|
127
|
+
runner { @app.start(%W[host addvar #{host_name} #{host_vars[0]} #{host_vars[1]}]) }
|
|
137
128
|
|
|
138
129
|
actual = runner do
|
|
139
|
-
@cli.start(%W
|
|
130
|
+
@cli.start(%W[--config #{@mockarg_parts[:config]} --host #{host_name}])
|
|
140
131
|
end
|
|
141
132
|
|
|
142
133
|
# @console.out(actual, 'y')
|
|
143
134
|
|
|
144
135
|
# Check output
|
|
145
136
|
meta = {}
|
|
146
|
-
meta[
|
|
147
|
-
meta[
|
|
137
|
+
meta[:hostvars] = {}
|
|
138
|
+
meta[:hostvars][host_name.to_sym] = {}
|
|
148
139
|
|
|
149
140
|
mock = {}
|
|
150
141
|
host_vars.each do |hv|
|
|
151
142
|
hv_array = hv.split('=')
|
|
152
143
|
mock[hv_array[0].to_sym] = hv_array[1]
|
|
153
|
-
meta[
|
|
144
|
+
meta[:hostvars][host_name.to_sym][hv_array[0].to_sym] = hv_array[1]
|
|
154
145
|
end
|
|
155
|
-
mock[
|
|
146
|
+
mock[:_meta] = meta
|
|
156
147
|
|
|
157
148
|
desired = {}
|
|
158
|
-
desired[:STDOUT] = mock.to_json
|
|
149
|
+
desired[:STDOUT] = "#{mock.to_json}\n"
|
|
159
150
|
expected(actual, desired)
|
|
160
151
|
end
|
|
161
152
|
end
|
|
162
153
|
end
|
|
154
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -1,48 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
|
-
# TODO: the usual respond_to? method doesn't seem to work on Thor objects.
|
|
4
5
|
# Why not? For now, we'll check against instance_methods.
|
|
5
6
|
|
|
6
7
|
RSpec.describe Moose::Inventory::Cli::Host do
|
|
7
8
|
before(:all) do
|
|
8
|
-
|
|
9
|
-
@mockarg_parts = {
|
|
10
|
-
config: File.join(spec_root, 'config/config.yml'),
|
|
11
|
-
format: 'yaml',
|
|
12
|
-
env: 'test',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@mockargs = []
|
|
16
|
-
@mockarg_parts.each do |key, val|
|
|
17
|
-
@mockargs << "--#{key}"
|
|
18
|
-
@mockargs << val
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
@config = Moose::Inventory::Config
|
|
22
|
-
@config.init(@mockargs)
|
|
23
|
-
|
|
24
|
-
@db = Moose::Inventory::DB
|
|
25
|
-
@db.init if @db.db.nil?
|
|
26
|
-
|
|
27
|
-
@host = Moose::Inventory::Cli::Host
|
|
28
|
-
@app = Moose::Inventory::Cli::Application
|
|
9
|
+
setup_cli_harness(command_class: Moose::Inventory::Cli::Host, command_ivar: :@host)
|
|
29
10
|
end
|
|
30
11
|
|
|
31
12
|
before(:each) do
|
|
32
|
-
|
|
13
|
+
reset_cli_harness
|
|
33
14
|
end
|
|
34
15
|
|
|
35
16
|
#======================
|
|
36
17
|
describe 'rm' do
|
|
37
18
|
#---------------
|
|
38
19
|
it 'Host.rm() should be responsive' do
|
|
39
|
-
result = @host.
|
|
20
|
+
result = @host.method_defined?(:rm, false)
|
|
40
21
|
expect(result).to eq(true)
|
|
41
22
|
end
|
|
42
23
|
|
|
43
24
|
#---------------
|
|
44
25
|
it '<missing argument> ... should abort with an error' do
|
|
45
|
-
actual = runner { @app.start(%w
|
|
26
|
+
actual = runner { @app.start(%w[host rm]) }
|
|
46
27
|
|
|
47
28
|
# Check output
|
|
48
29
|
desired = { aborted: true, STDERR: '', STDOUT: '' }
|
|
@@ -59,15 +40,15 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
59
40
|
|
|
60
41
|
# no items in the db
|
|
61
42
|
name = 'fake'
|
|
62
|
-
actual = runner { @app.start(%W
|
|
43
|
+
actual = runner { @app.start(%W[host rm #{name} --yes]) }
|
|
63
44
|
|
|
64
45
|
desired = {}
|
|
65
46
|
desired[:STDOUT] =
|
|
66
|
-
"Remove host '#{name}':\n"\
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
47
|
+
"Remove host '#{name}':\n " \
|
|
48
|
+
"- Retrieve host '#{name}'...\n " \
|
|
49
|
+
"- No such host, skipping.\n " \
|
|
50
|
+
"- OK\n " \
|
|
51
|
+
"- All OK\n" \
|
|
71
52
|
"Succeeded, with warnings.\n"
|
|
72
53
|
desired[:STDERR] =
|
|
73
54
|
"WARNING: Host '#{name}' does not exist, skipping.\n"
|
|
@@ -75,22 +56,39 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
75
56
|
expected(actual, desired)
|
|
76
57
|
end
|
|
77
58
|
|
|
59
|
+
#---------------
|
|
60
|
+
it 'HOST without --yes or --dry-run should abort before deleting' do
|
|
61
|
+
name = 'test1'
|
|
62
|
+
@db.models[:host].create(name: name)
|
|
63
|
+
|
|
64
|
+
actual = runner { @app.start(%W[host rm #{name}]) }
|
|
65
|
+
|
|
66
|
+
desired = {
|
|
67
|
+
aborted: true,
|
|
68
|
+
STDOUT: '',
|
|
69
|
+
STDERR: "ERROR: host rm #{name} is destructive. Re-run with --yes to confirm, " \
|
|
70
|
+
"or use --dry-run to preview.\n"
|
|
71
|
+
}
|
|
72
|
+
expected(actual, desired)
|
|
73
|
+
expect(@db.models[:host].find(name: name)).not_to be_nil
|
|
74
|
+
end
|
|
75
|
+
|
|
78
76
|
#---------------
|
|
79
77
|
it 'HOST ... should remove a host' do
|
|
80
78
|
name = 'test1'
|
|
81
79
|
@db.models[:host].create(name: name)
|
|
82
80
|
|
|
83
|
-
actual = runner { @app.start(%W
|
|
81
|
+
actual = runner { @app.start(%W[host rm #{name} --yes]) }
|
|
84
82
|
|
|
85
83
|
# Check output
|
|
86
84
|
desired = {}
|
|
87
85
|
desired[:STDOUT] =
|
|
88
|
-
"Remove host '#{name}':\n"\
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
86
|
+
"Remove host '#{name}':\n " \
|
|
87
|
+
"- Retrieve host '#{name}'...\n " \
|
|
88
|
+
"- OK\n " \
|
|
89
|
+
"- Destroy host '#{name}'...\n " \
|
|
90
|
+
"- OK\n " \
|
|
91
|
+
"- All OK\n" \
|
|
94
92
|
"Succeeded.\n"
|
|
95
93
|
|
|
96
94
|
expected(actual, desired)
|
|
@@ -100,28 +98,48 @@ RSpec.describe Moose::Inventory::Cli::Host do
|
|
|
100
98
|
expect(host).to be_nil
|
|
101
99
|
end
|
|
102
100
|
|
|
101
|
+
#---------------
|
|
102
|
+
it 'HOST --dry-run should show planned removal without deleting the host' do
|
|
103
|
+
name = 'test1'
|
|
104
|
+
@db.models[:host].create(name: name)
|
|
105
|
+
|
|
106
|
+
actual = runner { @app.start(%W[host rm #{name} --dry-run]) }
|
|
107
|
+
|
|
108
|
+
desired = {}
|
|
109
|
+
desired[:STDOUT] =
|
|
110
|
+
"Remove host '#{name}':\n " \
|
|
111
|
+
"- Retrieve host '#{name}'...\n " \
|
|
112
|
+
"- OK\n " \
|
|
113
|
+
"- Destroy host '#{name}'...\n " \
|
|
114
|
+
"- OK\n " \
|
|
115
|
+
"- All OK\n" \
|
|
116
|
+
"Dry run complete. No changes applied.\n" \
|
|
117
|
+
"Succeeded.\n"
|
|
118
|
+
|
|
119
|
+
expected(actual, desired)
|
|
120
|
+
expect(@db.models[:host].find(name: name)).not_to be_nil
|
|
121
|
+
end
|
|
103
122
|
#---------------
|
|
104
123
|
it 'HOST1 HOST2 ... should remove multiple hosts' do
|
|
105
|
-
names = %w
|
|
124
|
+
names = %w[host1 host2 host3]
|
|
106
125
|
names.each do |name|
|
|
107
126
|
@db.models[:host].create(name: name)
|
|
108
127
|
end
|
|
109
128
|
|
|
110
|
-
actual = runner { @app.start(%w
|
|
129
|
+
actual = runner { @app.start(%w[host rm --yes] + names) }
|
|
111
130
|
|
|
112
131
|
# Check output
|
|
113
132
|
desired = { aborted: false, STDERR: '', STDOUT: '' }
|
|
114
133
|
names.each do |name|
|
|
115
134
|
desired[:STDOUT] = desired[:STDOUT] +
|
|
116
|
-
"Remove host '#{name}':\n"\
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
135
|
+
"Remove host '#{name}':\n " \
|
|
136
|
+
"- Retrieve host '#{name}'...\n " \
|
|
137
|
+
"- OK\n " \
|
|
138
|
+
"- Destroy host '#{name}'...\n " \
|
|
139
|
+
"- OK\n " \
|
|
140
|
+
"- All OK\n"
|
|
122
141
|
end
|
|
123
|
-
desired[:STDOUT] = desired[:STDOUT]
|
|
124
|
-
"Succeeded.\n"
|
|
142
|
+
desired[:STDOUT] = "#{desired[:STDOUT]}Succeeded.\n"
|
|
125
143
|
expected(actual, desired)
|
|
126
144
|
|
|
127
145
|
# Check db
|