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,5 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
|
-
require_relative '
|
|
4
|
+
require_relative '../inventory_context'
|
|
5
|
+
require_relative '../operations/add_variables'
|
|
3
6
|
|
|
4
7
|
module Moose
|
|
5
8
|
module Inventory
|
|
@@ -10,61 +13,38 @@ module Moose
|
|
|
10
13
|
#==========================
|
|
11
14
|
desc 'addvar NAME VARNAME=VALUE',
|
|
12
15
|
'Add a variable VARNAME with value VALUE to the group NAME'
|
|
16
|
+
option :dry_run, type: :boolean
|
|
17
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
13
18
|
def addvar(*args)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"#{args.length} for 2 or more.")
|
|
17
|
-
end
|
|
18
|
-
# Convenience
|
|
19
|
-
db = Moose::Inventory::DB
|
|
20
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
19
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
20
|
+
validate_machine_plan_request!
|
|
21
21
|
|
|
22
|
-
# Arguments
|
|
23
22
|
name = args[0].downcase
|
|
24
23
|
vars = args.slice(1, args.length - 1).uniq
|
|
24
|
+
operation = build_operation(Moose::Inventory::Operations::AddVariables,
|
|
25
|
+
entity_type: :group,
|
|
26
|
+
emitter: machine_plan_emitter(group_addvar_emitter(name, vars)))
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
fmt.puts 2, "- retrieve group '#{name}'..."
|
|
30
|
-
group = db.models[:group].find(name: name)
|
|
31
|
-
if group.nil?
|
|
32
|
-
fail db.exceptions[:moose],
|
|
33
|
-
"The group '#{name}' does not exist."
|
|
34
|
-
end
|
|
35
|
-
fmt.puts 4, '- OK'
|
|
28
|
+
result = db.transaction do
|
|
29
|
+
operation.call(name: name, vars: vars, dry_run: options[:dry_run])
|
|
30
|
+
end
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
vars.each do |v|
|
|
39
|
-
fmt.puts 2, "- add variable '#{v}'..."
|
|
40
|
-
vararray = v.split('=')
|
|
32
|
+
return if machine_plan_output_rendered?(result, command: 'group addvar')
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
record_audit({ command: 'group addvar', action: 'add_variable', entity_type: 'group',
|
|
35
|
+
entity_names: name }, result: result, dry_run: options[:dry_run])
|
|
36
|
+
print_success_summary
|
|
37
|
+
end
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
groupvar = groupvars_ds[name: vararray[0]]
|
|
49
|
-
if !groupvar.nil?
|
|
50
|
-
unless groupvar[:value] == vararray[1]
|
|
51
|
-
fmt.puts 4, '- already exists, applying as an update...'
|
|
52
|
-
update = db.models[:groupvar].find(id: groupvar[:id])
|
|
53
|
-
update[:value] = vararray[1]
|
|
54
|
-
update.save
|
|
55
|
-
end
|
|
56
|
-
else
|
|
57
|
-
# groupvar doesn't exist, so create and associate
|
|
58
|
-
groupvar = db.models[:groupvar].create(name: vararray[0],
|
|
59
|
-
value: vararray[1])
|
|
60
|
-
group.add_groupvar(groupvar)
|
|
61
|
-
end
|
|
62
|
-
fmt.puts 4, '- OK'
|
|
63
|
-
end
|
|
64
|
-
fmt.puts 2, '- all OK'
|
|
65
|
-
end # Transaction end
|
|
39
|
+
private
|
|
66
40
|
|
|
67
|
-
|
|
41
|
+
def group_addvar_emitter(name, vars)
|
|
42
|
+
variable_operation_emitter(
|
|
43
|
+
action: :add,
|
|
44
|
+
entity_label: 'group',
|
|
45
|
+
entity_name: name,
|
|
46
|
+
variables_label: vars.join(',')
|
|
47
|
+
)
|
|
68
48
|
end
|
|
69
49
|
end
|
|
70
50
|
end
|
|
@@ -1,54 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
|
-
require_relative '
|
|
4
|
+
require_relative '../inventory_context'
|
|
5
|
+
require_relative '../operations/query_inventory'
|
|
3
6
|
|
|
4
7
|
module Moose
|
|
5
8
|
module Inventory
|
|
6
9
|
module Cli
|
|
7
|
-
##
|
|
8
10
|
# Implementation of the "group get" method of the CLI
|
|
9
11
|
class Group
|
|
10
12
|
desc 'get GROUP_1 [GROUP_2 ...]', 'Get groups GROUP_n from the inventory'
|
|
11
|
-
def get(*argv)
|
|
12
|
-
if argv.empty?
|
|
13
|
-
abort('ERROR: Wrong number of arguments, '\
|
|
14
|
-
"#{argv.length} for 1 or more")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Convenience
|
|
18
|
-
db = Moose::Inventory::DB
|
|
19
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
20
|
-
|
|
21
|
-
# Arguments
|
|
22
|
-
names = argv.uniq.map(&:downcase)
|
|
23
|
-
|
|
24
|
-
# Process
|
|
25
|
-
results = {}
|
|
26
|
-
names.each do |name|
|
|
27
|
-
group = db.models[:group].find(name: name)
|
|
28
|
-
|
|
29
|
-
next if group.nil?
|
|
30
|
-
hosts = group.hosts_dataset.map(:name)
|
|
31
|
-
|
|
32
|
-
children = group.children_dataset.map(:name)
|
|
33
|
-
|
|
34
|
-
groupvars = {}
|
|
35
|
-
group.groupvars_dataset.each do |gv|
|
|
36
|
-
groupvars[gv[:name].to_sym] = gv[:value]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
results[group[:name].to_sym] = {}
|
|
40
|
-
results[group[:name].to_sym][:hosts] = hosts unless hosts.empty?
|
|
41
|
-
|
|
42
|
-
unless children.empty?
|
|
43
|
-
results[group[:name].to_sym][:children] = children
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
unless groupvars.empty?
|
|
47
|
-
results[group[:name].to_sym][:groupvars] = groupvars
|
|
48
|
-
end
|
|
49
|
-
end
|
|
13
|
+
def get(*argv)
|
|
14
|
+
abort("ERROR: Wrong number of arguments, #{argv.length} for 1 or more") if argv.empty?
|
|
50
15
|
|
|
51
|
-
|
|
16
|
+
names = normalize_names(argv)
|
|
17
|
+
fmt.dump(inventory_query.get_groups(names: names), output_format)
|
|
52
18
|
end
|
|
53
19
|
end
|
|
54
20
|
end
|
|
@@ -1,52 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
|
-
require_relative '
|
|
4
|
+
require_relative '../inventory_context'
|
|
5
|
+
require_relative '../operations/query_inventory'
|
|
3
6
|
|
|
4
7
|
module Moose
|
|
5
8
|
module Inventory
|
|
6
9
|
module Cli
|
|
7
|
-
##
|
|
8
10
|
# Implementation of the "group list" method of the CLI
|
|
9
11
|
class Group
|
|
10
|
-
#==========================
|
|
11
12
|
desc 'list',
|
|
12
13
|
'List the groups, together with any associated hosts and groupvars'
|
|
13
|
-
def list
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
confopts = Moose::Inventory::Config._confopts
|
|
17
|
-
|
|
18
|
-
# Process
|
|
19
|
-
results = {}
|
|
20
|
-
db.models[:group].all.each do |group|
|
|
21
|
-
hosts = group.hosts_dataset.map(:name)
|
|
22
|
-
|
|
23
|
-
# Hide the automatic ungrouped group, if it's empty
|
|
24
|
-
next if group[:name] == 'ungrouped' && hosts.empty?
|
|
25
|
-
|
|
26
|
-
children = group.children_dataset.map(:name)
|
|
27
|
-
|
|
28
|
-
groupvars = {}
|
|
29
|
-
group.groupvars_dataset.each do |gv|
|
|
30
|
-
groupvars[gv[:name].to_sym] = gv[:value]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
results[group[:name].to_sym] = {}
|
|
34
|
-
unless hosts.empty? && (confopts[:ansible] != true)
|
|
35
|
-
results[group[:name].to_sym][:hosts] = hosts
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
unless children.empty?
|
|
39
|
-
results[group[:name].to_sym][:children] = children
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
next if groupvars.empty?
|
|
43
|
-
if confopts[:ansible] == true
|
|
44
|
-
results[group[:name].to_sym][:vars] = groupvars
|
|
45
|
-
else
|
|
46
|
-
results[group[:name].to_sym][:groupvars] = groupvars
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
Formatter.out(results)
|
|
14
|
+
def list
|
|
15
|
+
results = inventory_query.list_groups(ansible: ansible_mode?)
|
|
16
|
+
fmt.dump(results, output_format)
|
|
50
17
|
end
|
|
51
18
|
end
|
|
52
19
|
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
4
|
require 'json'
|
|
3
5
|
|
|
4
|
-
require_relative '
|
|
5
|
-
require_relative '../
|
|
6
|
+
require_relative '../inventory_context'
|
|
7
|
+
require_relative '../operations/query_inventory'
|
|
6
8
|
|
|
7
9
|
module Moose
|
|
8
10
|
module Inventory
|
|
@@ -13,61 +15,13 @@ module Moose
|
|
|
13
15
|
#==========================
|
|
14
16
|
desc 'listvar', 'List all variables associated with the group'
|
|
15
17
|
def listvars(*argv)
|
|
16
|
-
|
|
17
|
-
confopts = Moose::Inventory::Config._confopts
|
|
18
|
-
|
|
19
|
-
# Note, the Ansible spects don't call for a "--group GROUPNAME" method.
|
|
20
|
-
# So, strictly, there is no Ansible compatibility for this method.
|
|
21
|
-
# Instead, the Ansible compatibility included herein is for consistency
|
|
22
|
-
# with the "hosts listvars" method, which services the Ansible
|
|
23
|
-
# "--host HOSTNAME" specs.
|
|
24
|
-
|
|
25
|
-
# sanity
|
|
26
|
-
if confopts[:ansible] == true
|
|
27
|
-
if argv.length != 1
|
|
28
|
-
abort('ERROR: Wrong number of arguments for Ansible mode, '\
|
|
29
|
-
"#{args.length} for 1.")
|
|
30
|
-
end
|
|
31
|
-
else
|
|
32
|
-
if argv.empty?
|
|
33
|
-
abort('ERROR: Wrong number of arguments, '\
|
|
34
|
-
"#{args.length} for 1 or more.")
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Convenience
|
|
39
|
-
db = Moose::Inventory::DB
|
|
40
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
41
|
-
|
|
42
|
-
# Arguments
|
|
43
|
-
names = argv.uniq.map(&:downcase)
|
|
18
|
+
validate_listvars_args(argv)
|
|
44
19
|
|
|
45
|
-
|
|
46
|
-
results =
|
|
20
|
+
names = normalize_names(argv)
|
|
21
|
+
results = inventory_query.list_group_vars(names: names, ansible: ansible_mode?)
|
|
22
|
+
warn_if_missing_ansible_listvars_entity(:group, names.first)
|
|
47
23
|
|
|
48
|
-
|
|
49
|
-
# This is the implementation per Ansible specs
|
|
50
|
-
name = names.first
|
|
51
|
-
group = db.models[:group].find(name: name)
|
|
52
|
-
if group.nil?
|
|
53
|
-
fmt.warn "The Group #{name} does not exist."
|
|
54
|
-
else
|
|
55
|
-
group.groupvars_dataset.each do |gv|
|
|
56
|
-
results[gv[:name].to_sym] = gv[:value]
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
else
|
|
60
|
-
# This our more flexible implementation
|
|
61
|
-
names.each do |name|
|
|
62
|
-
group = db.models[:group].find(name: name)
|
|
63
|
-
next if group.nil?
|
|
64
|
-
results[name.to_sym] = {}
|
|
65
|
-
group.groupvars_dataset.each do |gv|
|
|
66
|
-
results[name.to_sym][gv[:name].to_sym] = gv[:value]
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
fmt.dump(results)
|
|
24
|
+
fmt.dump(results, output_format)
|
|
71
25
|
end
|
|
72
26
|
end
|
|
73
27
|
end
|
|
@@ -16,10 +16,14 @@ module Moose
|
|
|
16
16
|
type: :boolean,
|
|
17
17
|
default: false,
|
|
18
18
|
desc: 'Also delete child groups that become orphaned'
|
|
19
|
+
option :dry_run, type: :boolean
|
|
20
|
+
option :yes, type: :boolean, desc: 'Confirm destructive removal without prompting'
|
|
21
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
19
22
|
desc 'rm NAME',
|
|
20
23
|
'Remove a group NAME from the inventory'
|
|
21
24
|
def rm(*argv)
|
|
22
25
|
abort_if_missing_args(argv, 1, '1 or more')
|
|
26
|
+
validate_machine_plan_request!
|
|
23
27
|
|
|
24
28
|
names = normalize_names(argv)
|
|
25
29
|
|
|
@@ -27,25 +31,22 @@ module Moose
|
|
|
27
31
|
names,
|
|
28
32
|
"Cannot manually manipulate the automatic group 'ungrouped'\n"
|
|
29
33
|
)
|
|
34
|
+
confirm_destructive_action!("group rm #{names.join(',')}")
|
|
30
35
|
|
|
31
36
|
result = remove_groups(names)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
else
|
|
36
|
-
puts 'Succeeded, with warnings.'
|
|
37
|
-
end
|
|
37
|
+
record_audit({ command: 'group rm', action: 'remove', entity_type: 'group',
|
|
38
|
+
entity_names: names }, result: result, dry_run: options[:dry_run])
|
|
39
|
+
print_warning_summary(result) unless machine_plan_output_requested?
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
private
|
|
41
43
|
|
|
42
44
|
def remove_groups(names)
|
|
43
|
-
|
|
44
|
-
operation = Moose::Inventory::Operations::RemoveGroups.new(context: context)
|
|
45
|
+
operation = build_operation(Moose::Inventory::Operations::RemoveGroups)
|
|
45
46
|
|
|
46
47
|
db.transaction do
|
|
47
|
-
result = operation.call(names: names, recursive: options[:recursive])
|
|
48
|
-
render_group_rm_events(result.events)
|
|
48
|
+
result = operation.call(names: names, recursive: options[:recursive], dry_run: options[:dry_run])
|
|
49
|
+
machine_plan_output_rendered?(result, command: 'group rm') || render_group_rm_events(result.events)
|
|
49
50
|
return result
|
|
50
51
|
end
|
|
51
52
|
end
|
|
@@ -59,6 +60,7 @@ module Moose
|
|
|
59
60
|
|
|
60
61
|
render_group_rm_warning(payload) if event.type == :group_missing
|
|
61
62
|
return render_group_rm_progress(event.type, payload) if group_rm_progress?(event.type)
|
|
63
|
+
return puts 'Dry run complete. No changes applied.' if event.type == :dry_run_summary
|
|
62
64
|
|
|
63
65
|
render_group_rm_status(event.type, payload)
|
|
64
66
|
end
|
|
@@ -19,107 +19,51 @@ module Moose
|
|
|
19
19
|
desc: 'Delete child groups that become orphaned'
|
|
20
20
|
desc 'rmchild PARENTGROUP CHILDGROUP_1 [CHILDGROUP_2 ... ]',
|
|
21
21
|
'Dissociate one or more child-groups CHILDGROUP_n from PARENTGROUP'
|
|
22
|
+
option :dry_run, type: :boolean
|
|
23
|
+
option :yes, type: :boolean, desc: 'Confirm destructive dissociation without prompting'
|
|
24
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
22
25
|
def rmchild(*argv)
|
|
23
26
|
abort_if_missing_args(argv, 2, '2 or more')
|
|
27
|
+
validate_machine_plan_request!
|
|
24
28
|
|
|
25
29
|
pname = argv[0].downcase
|
|
26
30
|
cnames = normalize_names(argv.slice(1, argv.length - 1))
|
|
27
31
|
|
|
28
32
|
abort_if_automatic_group([pname] + cnames)
|
|
33
|
+
confirm_destructive_action!("group rmchild #{pname} #{cnames.join(',')}")
|
|
29
34
|
|
|
30
35
|
result = remove_children_from_group(pname, cnames)
|
|
36
|
+
return if machine_plan_output_rendered?(result, command: 'group rmchild')
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
puts 'Succeeded, with warnings.'
|
|
36
|
-
end
|
|
38
|
+
record_audit({ command: 'group rmchild', action: 'dissociate_child', entity_type: 'group',
|
|
39
|
+
entity_names: pname }, result: result, dry_run: options[:dry_run])
|
|
40
|
+
print_warning_summary(result)
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
private
|
|
40
44
|
|
|
41
45
|
def remove_children_from_group(parent_name, child_names)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return result
|
|
58
|
-
end
|
|
59
|
-
rescue db.exceptions[:moose] => e
|
|
60
|
-
abort("ERROR: #{e}")
|
|
46
|
+
operation = build_operation(Moose::Inventory::Operations::GroupChildRelations)
|
|
47
|
+
run_group_relation_transaction(
|
|
48
|
+
heading: "Dissociate parent group '#{parent_name}' from child group(s) '#{child_names.join(',')}':",
|
|
49
|
+
on_error: method(:exception_to_s)
|
|
50
|
+
) do
|
|
51
|
+
parent_group = fetch_existing_group_or_abort(parent_name)
|
|
52
|
+
result = operation.remove_children(
|
|
53
|
+
parent_group: parent_group,
|
|
54
|
+
parent_name: parent_name,
|
|
55
|
+
child_names: child_names,
|
|
56
|
+
delete_orphans: options[:delete_orphans],
|
|
57
|
+
dry_run: options[:dry_run]
|
|
58
|
+
)
|
|
59
|
+
render_rmchild_events(result.events) unless machine_plan_output_requested?
|
|
60
|
+
result
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
def fetch_existing_group_for_rmchild(context, name)
|
|
65
|
-
fmt.puts 2, "- retrieve group '#{name}'..."
|
|
66
|
-
group = context.find_group(name)
|
|
67
|
-
abort("ERROR: The group '#{name}' does not exist.") if group.nil?
|
|
68
|
-
|
|
69
|
-
fmt.puts 4, '- OK'
|
|
70
|
-
group
|
|
71
|
-
end
|
|
72
|
-
|
|
73
64
|
def render_rmchild_events(events)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def render_rmchild_event(event)
|
|
78
|
-
payload = event.payload
|
|
79
|
-
|
|
80
|
-
return render_rmchild_warning(payload) if event.type == :child_association_missing
|
|
81
|
-
return render_rmchild_missing(payload) if event.type == :missing_skipping
|
|
82
|
-
return render_rmchild_progress(event.type, payload) if rmchild_progress_event?(event.type)
|
|
83
|
-
|
|
84
|
-
render_rmchild_status(event.type, payload)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def rmchild_progress_event?(type)
|
|
88
|
-
%i[
|
|
89
|
-
removing_child_association
|
|
90
|
-
recursively_delete_orphaned_group
|
|
91
|
-
removing_recursive_child_association
|
|
92
|
-
].include?(type)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def render_rmchild_progress(type, payload)
|
|
96
|
-
case type
|
|
97
|
-
when :removing_child_association
|
|
98
|
-
fmt.puts 2, "- remove association {group:#{payload[:parent]} <-> group:#{payload[:child]}}..."
|
|
99
|
-
when :recursively_delete_orphaned_group
|
|
100
|
-
fmt.puts 2, "- Recursively delete orphaned group '#{payload[:name]}'..."
|
|
101
|
-
when :removing_recursive_child_association
|
|
102
|
-
fmt.puts 4, "- Remove association {group:#{payload[:parent]} <-> group:#{payload[:child]}}..."
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def render_rmchild_status(type, payload)
|
|
107
|
-
case type
|
|
108
|
-
when :adding_automatic_group_to_host
|
|
109
|
-
fmt.puts payload[:indent], "- Adding automatic association {group:ungrouped <-> host:#{payload[:host]}}..."
|
|
110
|
-
when :destroying_group
|
|
111
|
-
fmt.puts payload[:indent], "- Destroy group '#{payload[:name]}'..."
|
|
112
|
-
when :ok
|
|
113
|
-
fmt.puts payload[:indent], '- OK'
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def render_rmchild_warning(payload)
|
|
118
|
-
fmt.warn "Association {group:#{payload[:parent]} <-> group:#{payload[:child]}} does not exist, skipping.\n"
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def render_rmchild_missing(payload)
|
|
122
|
-
fmt.puts payload[:indent], "- doesn't exist, skipping."
|
|
65
|
+
emitter = rmchild_emitter
|
|
66
|
+
events.each { |event| emitter.call(event) }
|
|
123
67
|
end
|
|
124
68
|
end
|
|
125
69
|
end
|
|
@@ -14,78 +14,43 @@ module Moose
|
|
|
14
14
|
#==========================
|
|
15
15
|
desc 'rmhost GROUPNAME HOSTNAME_1 [HOSTNAME_2 ...]',
|
|
16
16
|
'Dissociate the hosts HOSTNAME_n from the group NAME'
|
|
17
|
+
option :dry_run, type: :boolean
|
|
18
|
+
option :yes, type: :boolean, desc: 'Confirm destructive dissociation without prompting'
|
|
19
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
17
20
|
def rmhost(*args)
|
|
18
21
|
abort_if_missing_args(args, 2, '2 or more')
|
|
22
|
+
validate_machine_plan_request!
|
|
19
23
|
|
|
20
24
|
name = args[0].downcase
|
|
21
25
|
hosts = normalize_names(args.slice(1, args.length - 1))
|
|
22
26
|
|
|
23
27
|
abort_if_automatic_group([name])
|
|
28
|
+
confirm_destructive_action!("group rmhost #{name} #{hosts.join(',')}")
|
|
24
29
|
|
|
25
30
|
result = remove_hosts_from_group(name, hosts)
|
|
31
|
+
return if machine_plan_output_rendered?(result, command: 'group rmhost')
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
puts 'Succeeded, with warnings.'
|
|
31
|
-
end
|
|
33
|
+
record_audit({ command: 'group rmhost', action: 'dissociate', entity_type: 'group',
|
|
34
|
+
entity_names: name }, result: result, dry_run: options[:dry_run])
|
|
35
|
+
print_warning_summary(result)
|
|
32
36
|
end
|
|
33
37
|
|
|
34
38
|
private
|
|
35
39
|
|
|
36
40
|
def remove_hosts_from_group(name, hosts)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
result = operation.group_from_hosts(group: group, group_name: name, host_names: hosts)
|
|
45
|
-
render_group_rmhost_events(result.events)
|
|
46
|
-
fmt.puts 2, '- all OK'
|
|
47
|
-
return result
|
|
48
|
-
end
|
|
49
|
-
rescue db.exceptions[:moose] => e
|
|
50
|
-
abort("ERROR: #{e.message}")
|
|
41
|
+
operation = build_operation(Moose::Inventory::Operations::RemoveAssociations)
|
|
42
|
+
run_group_relation_transaction(heading: "Dissociate group '#{name}' from host(s) '#{hosts.join(',')}':") do
|
|
43
|
+
group = fetch_existing_group_or_abort(name)
|
|
44
|
+
result = operation.group_from_hosts(group: group, group_name: name, host_names: hosts,
|
|
45
|
+
dry_run: options[:dry_run])
|
|
46
|
+
render_group_rmhost_events(result.events) unless machine_plan_output_requested?
|
|
47
|
+
result
|
|
51
48
|
end
|
|
52
49
|
end
|
|
53
50
|
|
|
54
|
-
def fetch_existing_group_for_rmhost(context, name)
|
|
55
|
-
fmt.puts 2, "- retrieve group '#{name}'..."
|
|
56
|
-
group = context.find_group(name)
|
|
57
|
-
abort("ERROR: The group '#{name}' does not exist.") if group.nil?
|
|
58
|
-
|
|
59
|
-
fmt.puts 4, '- OK'
|
|
60
|
-
group
|
|
61
|
-
end
|
|
62
|
-
|
|
63
51
|
def render_group_rmhost_events(events)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def render_group_rmhost_event(event)
|
|
68
|
-
payload = event.payload
|
|
69
|
-
|
|
70
|
-
return render_group_rmhost_warning(payload) if event.type == :group_host_association_missing
|
|
71
|
-
return render_group_rmhost_missing(payload) if event.type == :missing_skipping
|
|
72
|
-
|
|
73
|
-
case event.type
|
|
74
|
-
when :removing_group_host_association
|
|
75
|
-
fmt.puts 2, "- remove association {group:#{payload[:group]} <-> host:#{payload[:host]}}..."
|
|
76
|
-
when :adding_automatic_group
|
|
77
|
-
fmt.puts 2, "- add automatic association {group:ungrouped <-> host:#{payload[:host]}}..."
|
|
78
|
-
when :ok
|
|
79
|
-
fmt.puts payload[:indent], '- OK'
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def render_group_rmhost_warning(payload)
|
|
84
|
-
fmt.warn "Association {group:#{payload[:group]} <-> host:#{payload[:host]}} doesn't exist, skipping.\n"
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def render_group_rmhost_missing(payload)
|
|
88
|
-
fmt.puts payload[:indent], "- doesn't exist, skipping."
|
|
52
|
+
emitter = host_group_association_removal_emitter(perspective: :group)
|
|
53
|
+
events.each { |event| emitter.call(event) }
|
|
89
54
|
end
|
|
90
55
|
end
|
|
91
56
|
end
|