moose-inventory 1.0.9 → 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/ci.yml +15 -1
- data/.github/workflows/release.yml +60 -0
- data/.gitignore +2 -1
- data/.gitleaks.toml +9 -0
- data/.rubocop.yml +49 -0
- data/BACKLOG.md +752 -24
- data/Gemfile +2 -0
- data/Gemfile.lock +36 -1
- data/README.md +340 -44
- 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 +54 -50
- data/docs/release/release-environment-protection.md +70 -0
- data/docs/release/release-readiness.md +37 -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 +75 -0
- data/docs/security-audit-2026-05-26.md +63 -0
- 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 +7 -1
- data/lib/moose_inventory/cli/group_add.rb +91 -73
- data/lib/moose_inventory/cli/group_addchild.rb +41 -66
- data/lib/moose_inventory/cli/group_addhost.rb +33 -71
- 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 +105 -73
- data/lib/moose_inventory/cli/group_rmchild.rb +47 -57
- data/lib/moose_inventory/cli/group_rmhost.rb +34 -61
- 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 +143 -0
- data/lib/moose_inventory/cli/host.rb +8 -2
- data/lib/moose_inventory/cli/host_add.rb +91 -66
- data/lib/moose_inventory/cli/host_addgroup.rb +39 -66
- 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 +39 -55
- 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 +188 -193
- 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 +116 -0
- data/lib/moose_inventory/operations/add_associations.rb +131 -0
- data/lib/moose_inventory/operations/add_groups.rb +123 -0
- data/lib/moose_inventory/operations/add_hosts.rb +123 -0
- 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 +125 -0
- data/lib/moose_inventory/operations/group_cleanup.rb +70 -0
- 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 +113 -0
- data/lib/moose_inventory/operations/remove_groups.rb +79 -0
- 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 +22 -35
- data/scripts/check.sh +3 -0
- data/scripts/ci/check_generated_artifacts.sh +41 -0
- data/scripts/ci/check_permissions.sh +5 -0
- data/scripts/ci/check_rubocop.sh +33 -0
- data/scripts/ci/check_secrets.sh +26 -0
- data/scripts/ci/check_security.sh +18 -0
- data/scripts/ci/install_security_tools.sh +47 -0
- data/scripts/files.rb +5 -4
- data/scripts/install_dependencies.sh +2 -0
- 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 +165 -85
- data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +100 -30
- 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 +551 -29
- 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 +111 -0
- data/spec/lib/moose_inventory/operations/add_groups_spec.rb +80 -0
- data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +82 -0
- data/spec/lib/moose_inventory/operations/add_variables_spec.rb +103 -0
- data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +122 -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 +113 -0
- data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +78 -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 +163 -35
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
|
-
require_relative '
|
|
4
|
+
require_relative 'formatter'
|
|
5
|
+
require_relative '../inventory_context'
|
|
6
|
+
require_relative '../operations/add_groups'
|
|
3
7
|
|
|
4
8
|
module Moose
|
|
5
9
|
module Inventory
|
|
@@ -10,84 +14,98 @@ module Moose
|
|
|
10
14
|
#==========================
|
|
11
15
|
desc 'add NAME', 'Add a group NAME to the inventory'
|
|
12
16
|
option :hosts
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
option :dry_run, type: :boolean
|
|
18
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
19
|
+
def add(*argv)
|
|
20
|
+
abort_if_missing_args(argv, 1, '1 or more')
|
|
21
|
+
validate_machine_plan_request!
|
|
22
|
+
|
|
23
|
+
names = normalize_names(argv)
|
|
24
|
+
hosts = csv_option_names(options[:hosts])
|
|
25
|
+
|
|
26
|
+
abort_if_automatic_group(
|
|
27
|
+
names,
|
|
28
|
+
"ERROR: Cannot manually manipulate the automatic group 'ungrouped'\n"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
result = build_operation(Moose::Inventory::Operations::AddGroups)
|
|
32
|
+
.call(names: names, hosts: hosts, dry_run: options[:dry_run])
|
|
33
|
+
return if machine_plan_output_rendered?(result, command: 'group add')
|
|
34
|
+
|
|
35
|
+
record_audit({ command: 'group add', action: 'add', entity_type: 'group',
|
|
36
|
+
entity_names: names }, result: result, dry_run: options[:dry_run])
|
|
37
|
+
render_add_groups_events(result.events)
|
|
38
|
+
print_warning_summary(result, success_message: 'Succeeded')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def render_add_groups_events(events)
|
|
44
|
+
events.each { |event| render_add_groups_event(event) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def render_add_groups_event(event)
|
|
48
|
+
payload = event.payload
|
|
49
|
+
|
|
50
|
+
return render_add_groups_event_puts(event.type, payload) if puts_event?(event.type)
|
|
51
|
+
return render_add_groups_event_warn(event.type, payload) if warn_event?(event.type)
|
|
52
|
+
return puts 'Dry run complete. No changes applied.' if event.type == :dry_run_summary
|
|
53
|
+
|
|
54
|
+
render_add_groups_event_fmt(event.type, payload)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def puts_event?(type)
|
|
58
|
+
type == :group_started
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def warn_event?(type)
|
|
62
|
+
%i[group_exists host_missing_created association_exists].include?(type)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def render_add_groups_event_puts(type, payload)
|
|
66
|
+
puts "Add group '#{payload[:name]}':" if type == :group_started
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def render_add_groups_event_warn(type, payload)
|
|
70
|
+
case type
|
|
71
|
+
when :group_exists
|
|
72
|
+
fmt.warn "Group '#{payload[:name]}' already exists, skipping creation.\n"
|
|
73
|
+
when :host_missing_created
|
|
74
|
+
fmt.warn "Host '#{payload[:name]}' doesn't exist, but will be created.\n"
|
|
75
|
+
when :association_exists
|
|
76
|
+
fmt.warn(
|
|
77
|
+
"Association {group:#{payload[:group]} <-> host:#{payload[:host]}} " \
|
|
78
|
+
"already exists, skipping creation.\n"
|
|
79
|
+
)
|
|
18
80
|
end
|
|
81
|
+
end
|
|
19
82
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
options[:hosts] = '' if options[:hosts].nil?
|
|
23
|
-
hosts = options[:hosts].downcase.split(',').uniq
|
|
83
|
+
def render_add_groups_event_fmt(type, payload)
|
|
84
|
+
return render_add_groups_event_status(type, payload) if status_event?(type)
|
|
24
85
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
86
|
+
case type
|
|
87
|
+
when :creating_group
|
|
88
|
+
fmt.puts 2, '- create group...'
|
|
89
|
+
when :adding_association
|
|
90
|
+
fmt.puts 2, "- add association {group:#{payload[:group]} <-> host:#{payload[:host]}}..."
|
|
91
|
+
when :host_creating_now
|
|
92
|
+
fmt.puts 4, '- host doesn\'t exist, creating now...'
|
|
93
|
+
when :removing_automatic_group
|
|
94
|
+
fmt.puts 2, "- remove automatic association {group:ungrouped <-> host:#{payload[:host]}}..."
|
|
95
|
+
when :group_complete
|
|
96
|
+
fmt.puts 2, '- all OK'
|
|
28
97
|
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def status_event?(type)
|
|
101
|
+
%i[already_exists_skipping ok].include?(type)
|
|
102
|
+
end
|
|
29
103
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# Transaction
|
|
35
|
-
warn_count = 0
|
|
36
|
-
db.transaction do # Transaction start
|
|
37
|
-
names.each do |name|
|
|
38
|
-
# Add the group
|
|
39
|
-
puts "Add group '#{name}':"
|
|
40
|
-
group = db.models[:group].find(name: name)
|
|
41
|
-
hosts_ds = nil
|
|
42
|
-
fmt.puts 2, '- create group...'
|
|
43
|
-
if group.nil?
|
|
44
|
-
group = db.models[:group].create(name: name)
|
|
45
|
-
fmt.puts 4, '- OK'
|
|
46
|
-
else
|
|
47
|
-
warn_count += 1
|
|
48
|
-
fmt.warn "Group '#{name}' already exists, skipping creation.\n"
|
|
49
|
-
fmt.puts 4, '- already exists, skipping.'
|
|
50
|
-
hosts_ds = group.hosts_dataset
|
|
51
|
-
fmt.puts 4, '- OK'
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Associate with hosts
|
|
55
|
-
hosts.each do |h|
|
|
56
|
-
next if h.nil? || h.empty?
|
|
57
|
-
fmt.puts 2, "- add association {group:#{name} <-> host:#{h}}..."
|
|
58
|
-
host = db.models[:host].find(name: h)
|
|
59
|
-
if host.nil?
|
|
60
|
-
warn_count += 1
|
|
61
|
-
fmt.warn "Host '#{h}' doesn't exist, but will be created.\n"
|
|
62
|
-
fmt.puts 4, "- host doesn't exist, creating now..."
|
|
63
|
-
host = db.models[:host].create(name: h)
|
|
64
|
-
fmt.puts 6, '- OK'
|
|
65
|
-
end
|
|
66
|
-
if !hosts_ds.nil? && !hosts_ds[name: h].nil?
|
|
67
|
-
warn_count += 1
|
|
68
|
-
fmt.warn "Association {group:#{name} <-> host:#{h}}"\
|
|
69
|
-
" already exists, skipping creation.\n"
|
|
70
|
-
fmt.puts 4, '- already exists, skipping.'
|
|
71
|
-
else
|
|
72
|
-
group.add_host(host)
|
|
73
|
-
end
|
|
74
|
-
fmt.puts 4, '- OK'
|
|
75
|
-
|
|
76
|
-
# Handle the host's automatic 'ungrouped' group
|
|
77
|
-
ungrouped = host.groups_dataset[name: 'ungrouped']
|
|
78
|
-
next if ungrouped.nil?
|
|
79
|
-
fmt.puts 2, '- remove automatic association {group:ungrouped'\
|
|
80
|
-
" <-> host:#{h}}..."
|
|
81
|
-
host.remove_group(ungrouped) unless ungrouped.nil?
|
|
82
|
-
fmt.puts 4, '- OK'
|
|
83
|
-
end
|
|
84
|
-
fmt.puts 2, '- all OK'
|
|
85
|
-
end
|
|
86
|
-
end # Transaction end
|
|
87
|
-
if warn_count == 0
|
|
88
|
-
puts 'Succeeded'
|
|
104
|
+
def render_add_groups_event_status(type, payload)
|
|
105
|
+
if type == :already_exists_skipping
|
|
106
|
+
fmt.puts payload[:indent], '- already exists, skipping.'
|
|
89
107
|
else
|
|
90
|
-
puts
|
|
108
|
+
fmt.puts payload[:indent], '- OK'
|
|
91
109
|
end
|
|
92
110
|
end
|
|
93
111
|
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
|
-
require_relative '
|
|
4
|
+
require_relative 'formatter'
|
|
5
|
+
require_relative '../inventory_context'
|
|
6
|
+
require_relative '../operations/group_child_relations'
|
|
3
7
|
|
|
4
8
|
module Moose
|
|
5
9
|
module Inventory
|
|
@@ -10,78 +14,49 @@ module Moose
|
|
|
10
14
|
#==========================
|
|
11
15
|
desc 'addchild PARENTGROUP CHILDGROUP_1 [CHILDGROUP_2 ... ]',
|
|
12
16
|
'Associate one or more child-groups CHILDGROUP_n with PARENTGROUP'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Arguments
|
|
21
|
-
pname = args[0].downcase
|
|
22
|
-
cnames = args.slice(1, args.length - 1).uniq.map(&:downcase)
|
|
23
|
-
|
|
24
|
-
# Sanity
|
|
25
|
-
if pname == 'ungrouped' || cnames.include?('ungrouped')
|
|
26
|
-
abort("ERROR: Cannot manually manipulate the automatic group 'ungrouped'.")
|
|
27
|
-
end
|
|
17
|
+
option :dry_run, type: :boolean
|
|
18
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
19
|
+
def addchild(*argv)
|
|
20
|
+
abort_if_missing_args(argv, 2, '2 or more')
|
|
21
|
+
validate_machine_plan_request!
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
23
|
+
pname = argv[0].downcase
|
|
24
|
+
cnames = normalize_names(argv.slice(1, argv.length - 1))
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
warn_count = 0
|
|
35
|
-
begin
|
|
36
|
-
db.transaction do # Transaction start
|
|
37
|
-
puts "Associate parent group '#{pname}' with child group(s) '#{cnames.join(',')}':"
|
|
38
|
-
# Get the target group
|
|
39
|
-
fmt.puts 2, "- retrieve group '#{pname}'..."
|
|
40
|
-
pgroup = db.models[:group].find(name: pname)
|
|
41
|
-
if pgroup.nil?
|
|
42
|
-
abort("ERROR: The group '#{pname}' does not exist.")
|
|
43
|
-
end
|
|
44
|
-
fmt.puts 4, '- OK'
|
|
26
|
+
abort_if_automatic_group([pname] + cnames)
|
|
45
27
|
|
|
46
|
-
|
|
28
|
+
result = add_children_to_group(pname, cnames)
|
|
29
|
+
return if machine_plan_output_rendered?(result, command: 'group addchild')
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# Check against existing associations
|
|
53
|
-
unless groups_ds[name: cname].nil?
|
|
54
|
-
warn_count += 1
|
|
55
|
-
fmt.warn "Association {group:#{pname} <-> group:#{cname}}}"\
|
|
56
|
-
" already exists, skipping.\n"
|
|
57
|
-
fmt.puts 4, '- already exists, skipping.'
|
|
58
|
-
fmt.puts 4, '- OK'
|
|
59
|
-
next
|
|
60
|
-
end
|
|
31
|
+
record_audit({ command: 'group addchild', action: 'associate_child', entity_type: 'group',
|
|
32
|
+
entity_names: pname }, result: result, dry_run: options[:dry_run])
|
|
33
|
+
print_warning_summary(result)
|
|
34
|
+
end
|
|
61
35
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if warn_count == 0
|
|
80
|
-
puts 'Succeeded.'
|
|
81
|
-
else
|
|
82
|
-
puts 'Succeeded, with warnings.'
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def add_children_to_group(parent_name, child_names)
|
|
39
|
+
operation = build_operation(Moose::Inventory::Operations::GroupChildRelations)
|
|
40
|
+
run_group_relation_transaction(
|
|
41
|
+
heading: "Associate parent group '#{parent_name}' with child group(s) '#{child_names.join(',')}':",
|
|
42
|
+
on_error: method(:exception_to_s)
|
|
43
|
+
) do
|
|
44
|
+
parent_group = fetch_existing_group_or_abort(parent_name)
|
|
45
|
+
result = operation.add_children(
|
|
46
|
+
parent_group: parent_group,
|
|
47
|
+
parent_name: parent_name,
|
|
48
|
+
child_names: child_names,
|
|
49
|
+
dry_run: options[:dry_run]
|
|
50
|
+
)
|
|
51
|
+
render_addchild_events(result.events) unless machine_plan_output_requested?
|
|
52
|
+
result
|
|
83
53
|
end
|
|
84
54
|
end
|
|
55
|
+
|
|
56
|
+
def render_addchild_events(events)
|
|
57
|
+
emitter = addchild_emitter
|
|
58
|
+
events.each { |event| emitter.call(event) }
|
|
59
|
+
end
|
|
85
60
|
end
|
|
86
61
|
end
|
|
87
62
|
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
|
-
require_relative '
|
|
4
|
+
require_relative 'formatter'
|
|
5
|
+
require_relative '../inventory_context'
|
|
6
|
+
require_relative '../operations/add_associations'
|
|
3
7
|
|
|
4
8
|
module Moose
|
|
5
9
|
module Inventory
|
|
@@ -10,84 +14,42 @@ module Moose
|
|
|
10
14
|
#==========================
|
|
11
15
|
desc 'addhost NAME HOSTNAME',
|
|
12
16
|
'Associate a host HOSTNAME with the group NAME'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Arguments
|
|
21
|
-
name = args[0].downcase
|
|
22
|
-
hosts = args.slice(1, args.length - 1).uniq.map(&:downcase)
|
|
23
|
-
|
|
24
|
-
# Sanity
|
|
25
|
-
if name == 'ungrouped'
|
|
26
|
-
abort("ERROR: Cannot manually manipulate the automatic group 'ungrouped'.")
|
|
27
|
-
end
|
|
17
|
+
option :dry_run, type: :boolean
|
|
18
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
19
|
+
def addhost(*args)
|
|
20
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
21
|
+
validate_machine_plan_request!
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
23
|
+
name = args[0].downcase
|
|
24
|
+
hosts = normalize_names(args.slice(1, args.length - 1))
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
warn_count = 0
|
|
35
|
-
begin
|
|
36
|
-
db.transaction do # Transaction start
|
|
37
|
-
puts "Associate group '#{name}' with host(s) '#{hosts.join(',')}':"
|
|
38
|
-
# Get the target group
|
|
39
|
-
fmt.puts 2, "- retrieve group '#{name}'..."
|
|
40
|
-
group = db.models[:group].find(name: name)
|
|
41
|
-
abort("ERROR: The group '#{name}' does not exist.") if group.nil?
|
|
42
|
-
fmt.puts 4, '- OK'
|
|
26
|
+
abort_if_automatic_group([name])
|
|
43
27
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
hosts_ds = group.hosts_dataset
|
|
47
|
-
hosts.each do |h|
|
|
48
|
-
fmt.puts 2, "- add association {group:#{name} <-> host:#{h}}..."
|
|
28
|
+
result = add_hosts_to_group(name, hosts)
|
|
29
|
+
return if machine_plan_output_rendered?(result, command: 'group addhost')
|
|
49
30
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
" exists, skipping.\n"
|
|
55
|
-
fmt.puts 4, '- already exists, skipping.'
|
|
56
|
-
fmt.puts 4, '- OK'
|
|
57
|
-
next
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Add new association
|
|
61
|
-
host = db.models[:host].find(name: h)
|
|
62
|
-
if host.nil?
|
|
63
|
-
warn_count += 1
|
|
64
|
-
fmt.warn "Host '#{h}' does not exist and will be created.\n"
|
|
65
|
-
fmt.puts 4, '- host does not exist, creating now...'
|
|
66
|
-
host = db.models[:host].create(name: h)
|
|
67
|
-
fmt.puts 6, '- OK'
|
|
68
|
-
end
|
|
31
|
+
record_audit({ command: 'group addhost', action: 'associate', entity_type: 'group',
|
|
32
|
+
entity_names: name }, result: result, dry_run: options[:dry_run])
|
|
33
|
+
print_warning_summary(result)
|
|
34
|
+
end
|
|
69
35
|
|
|
70
|
-
|
|
71
|
-
fmt.puts 4, '- OK'
|
|
36
|
+
private
|
|
72
37
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
end # Transaction end
|
|
82
|
-
rescue db.exceptions[:moose] => e
|
|
83
|
-
abort("ERROR: #{e.message}")
|
|
84
|
-
end
|
|
85
|
-
if warn_count == 0
|
|
86
|
-
puts 'Succeeded.'
|
|
87
|
-
else
|
|
88
|
-
puts 'Succeeded, with warnings.'
|
|
38
|
+
def add_hosts_to_group(name, hosts)
|
|
39
|
+
operation = build_operation(Moose::Inventory::Operations::AddAssociations)
|
|
40
|
+
run_group_relation_transaction(heading: "Associate group '#{name}' with host(s) '#{hosts.join(',')}':") do
|
|
41
|
+
group = fetch_existing_group_or_abort(name)
|
|
42
|
+
result = operation.group_to_hosts(group: group, group_name: name, host_names: hosts,
|
|
43
|
+
dry_run: options[:dry_run])
|
|
44
|
+
render_group_addhost_events(result.events) unless machine_plan_output_requested?
|
|
45
|
+
result
|
|
89
46
|
end
|
|
90
47
|
end
|
|
48
|
+
|
|
49
|
+
def render_group_addhost_events(events)
|
|
50
|
+
emitter = host_group_association_addition_emitter(perspective: :group)
|
|
51
|
+
events.each { |event| emitter.call(event) }
|
|
52
|
+
end
|
|
91
53
|
end
|
|
92
54
|
end
|
|
93
55
|
end
|
|
@@ -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
|