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/remove_variables'
|
|
3
6
|
|
|
4
7
|
module Moose
|
|
5
8
|
module Inventory
|
|
@@ -10,54 +13,40 @@ module Moose
|
|
|
10
13
|
#==========================
|
|
11
14
|
desc 'rmvar NAME VARNAME',
|
|
12
15
|
'Remove a variable VARNAME from the group NAME'
|
|
16
|
+
option :dry_run, type: :boolean
|
|
17
|
+
option :yes, type: :boolean, desc: 'Confirm destructive removal without prompting'
|
|
18
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
13
19
|
def rmvar(*args)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"#{args.length} for 2 or more.")
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Convenience
|
|
20
|
-
db = Moose::Inventory::DB
|
|
21
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
20
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
21
|
+
validate_machine_plan_request!
|
|
22
22
|
|
|
23
|
-
# Arguments
|
|
24
23
|
name = args[0].downcase
|
|
25
24
|
vars = args.slice(1, args.length - 1).uniq
|
|
25
|
+
confirm_destructive_action!("group rmvar #{name} #{vars.join(',')}")
|
|
26
|
+
operation = build_operation(Moose::Inventory::Operations::RemoveVariables,
|
|
27
|
+
entity_type: :group,
|
|
28
|
+
emitter: machine_plan_emitter(group_rmvar_emitter(name, vars)))
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
result = db.transaction do
|
|
31
|
+
operation.call(name: name, vars: vars, dry_run: options[:dry_run])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
return if machine_plan_output_rendered?(result, command: 'group rmvar')
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"The group '#{name}' does not exist."
|
|
36
|
-
end
|
|
37
|
-
fmt.puts 4, '- OK'
|
|
36
|
+
record_audit({ command: 'group rmvar', action: 'remove_variable', entity_type: 'group',
|
|
37
|
+
entity_names: name }, result: result, dry_run: options[:dry_run])
|
|
38
|
+
print_success_summary
|
|
39
|
+
end
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
vars.each do |v|
|
|
41
|
-
fmt.puts 2, "- remove variable '#{v}'..."
|
|
42
|
-
vararray = v.split('=')
|
|
43
|
-
if v.start_with?('=') || v.scan('=').count > 1
|
|
44
|
-
fail db.exceptions[:moose],
|
|
45
|
-
"Incorrect format in {#{v}}. " \
|
|
46
|
-
'Expected \'key\' or \'key=value\'.'
|
|
47
|
-
end
|
|
41
|
+
private
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
fmt.puts 4, '- OK'
|
|
57
|
-
end
|
|
58
|
-
fmt.puts 2, '- all OK'
|
|
59
|
-
end # Transaction end
|
|
60
|
-
puts 'Succeeded.'
|
|
43
|
+
def group_rmvar_emitter(name, vars)
|
|
44
|
+
variable_operation_emitter(
|
|
45
|
+
action: :remove,
|
|
46
|
+
entity_label: 'group',
|
|
47
|
+
entity_name: name,
|
|
48
|
+
variables_label: vars.join(',')
|
|
49
|
+
)
|
|
61
50
|
end
|
|
62
51
|
end
|
|
63
52
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moose
|
|
4
|
+
module Inventory
|
|
5
|
+
module Cli
|
|
6
|
+
class Group
|
|
7
|
+
desc 'addtag GROUP TAG_1 [TAG_2 ...]', 'Add metadata tags to a group'
|
|
8
|
+
def addtag(*args)
|
|
9
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
10
|
+
|
|
11
|
+
add_tags('group', args[0].downcase, args.slice(1, args.length - 1))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc 'rmtag GROUP TAG_1 [TAG_2 ...]', 'Remove metadata tags from a group'
|
|
15
|
+
option :yes, type: :boolean, desc: 'Confirm destructive tag removal without prompting'
|
|
16
|
+
def rmtag(*args)
|
|
17
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
18
|
+
confirm_destructive_action!("group rmtag #{args[0].downcase} #{args.slice(1, args.length - 1).join(',')}")
|
|
19
|
+
|
|
20
|
+
remove_tags('group', args[0].downcase, args.slice(1, args.length - 1))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc 'listtags GROUP', 'List metadata tags for a group'
|
|
24
|
+
option :format, type: :string, desc: 'Emit tags as yaml|json|pjson'
|
|
25
|
+
def listtags(*args)
|
|
26
|
+
abort_if_missing_args(args, 1, '1')
|
|
27
|
+
|
|
28
|
+
list_tags('group', args[0].downcase)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -1,11 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../inventory_context'
|
|
4
|
+
require_relative 'audit_recording'
|
|
5
|
+
require_relative 'association_rendering'
|
|
6
|
+
require_relative 'child_relation_rendering'
|
|
7
|
+
require_relative 'factory'
|
|
8
|
+
require_relative 'listvars_support'
|
|
9
|
+
require_relative 'plan_rendering'
|
|
10
|
+
require_relative 'relation_transaction_support'
|
|
11
|
+
require_relative 'tag_support'
|
|
12
|
+
require_relative 'variable_rendering'
|
|
13
|
+
|
|
3
14
|
module Moose
|
|
4
15
|
module Inventory
|
|
5
16
|
module Cli
|
|
6
17
|
##
|
|
7
18
|
# Shared helpers for Thor command classes.
|
|
8
19
|
module Helpers
|
|
20
|
+
include Moose::Inventory::Cli::AssociationRendering
|
|
21
|
+
include Moose::Inventory::Cli::AuditRecording
|
|
22
|
+
include Moose::Inventory::Cli::ChildRelationRendering
|
|
23
|
+
include Moose::Inventory::Cli::ListvarsSupport
|
|
24
|
+
include Moose::Inventory::Cli::PlanRendering
|
|
25
|
+
include Moose::Inventory::Cli::RelationTransactionSupport
|
|
26
|
+
include Moose::Inventory::Cli::TagSupport
|
|
27
|
+
include Moose::Inventory::Cli::VariableRendering
|
|
28
|
+
|
|
9
29
|
AUTOMATIC_GROUP = 'ungrouped'
|
|
10
30
|
|
|
11
31
|
private
|
|
@@ -14,10 +34,38 @@ module Moose
|
|
|
14
34
|
Moose::Inventory::DB
|
|
15
35
|
end
|
|
16
36
|
|
|
37
|
+
def inventory_context
|
|
38
|
+
@inventory_context ||= Moose::Inventory::InventoryContext.new(db: db)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def cli_factory
|
|
42
|
+
@cli_factory ||= Moose::Inventory::Cli::Factory.new(context: inventory_context)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def build_operation(operation_class, **)
|
|
46
|
+
cli_factory.operation(operation_class, **)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def inventory_query
|
|
50
|
+
cli_factory.query_inventory
|
|
51
|
+
end
|
|
52
|
+
|
|
17
53
|
def fmt
|
|
18
54
|
Moose::Inventory::Cli::Formatter
|
|
19
55
|
end
|
|
20
56
|
|
|
57
|
+
def runtime_options
|
|
58
|
+
Moose::Inventory::Config.runtime_options
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def output_format
|
|
62
|
+
runtime_options.output_format
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def ansible_mode?
|
|
66
|
+
runtime_options.ansible?
|
|
67
|
+
end
|
|
68
|
+
|
|
21
69
|
def normalize_names(values)
|
|
22
70
|
values.uniq.map(&:downcase)
|
|
23
71
|
end
|
|
@@ -38,12 +86,31 @@ module Moose
|
|
|
38
86
|
abort(message || "ERROR: Cannot manually manipulate the automatic group '#{AUTOMATIC_GROUP}'.")
|
|
39
87
|
end
|
|
40
88
|
|
|
89
|
+
def confirm_destructive_action!(description)
|
|
90
|
+
return if options[:dry_run] || options[:yes]
|
|
91
|
+
|
|
92
|
+
abort("ERROR: #{description} is destructive. Re-run with --yes to confirm, or use --dry-run to preview.")
|
|
93
|
+
end
|
|
94
|
+
|
|
41
95
|
def association_exists?(dataset, name)
|
|
42
96
|
!dataset.nil? && !dataset[name: name].nil?
|
|
43
97
|
end
|
|
44
98
|
|
|
99
|
+
def exception_to_s(error)
|
|
100
|
+
error.to_s
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def print_warning_summary(result, success_message: 'Succeeded.', warning_message: 'Succeeded, with warnings.')
|
|
104
|
+
warning_count = result.respond_to?(:warning_count) ? result.warning_count : 0
|
|
105
|
+
print_success_summary(warning_count.zero? ? success_message : warning_message)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def print_success_summary(message = 'Succeeded.')
|
|
109
|
+
puts message
|
|
110
|
+
end
|
|
111
|
+
|
|
45
112
|
def automatic_group
|
|
46
|
-
|
|
113
|
+
inventory_context.automatic_group
|
|
47
114
|
end
|
|
48
115
|
|
|
49
116
|
def remove_automatic_group_from_host(host, indent:, message:)
|
|
@@ -1,9 +1,11 @@
|
|
|
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 '../db/exceptions
|
|
6
|
+
require_relative 'formatter'
|
|
7
|
+
require_relative 'helpers'
|
|
8
|
+
require_relative '../db/exceptions'
|
|
7
9
|
|
|
8
10
|
module Moose
|
|
9
11
|
module Inventory
|
|
@@ -22,6 +24,7 @@ module Moose
|
|
|
22
24
|
require_relative 'host_addvar'
|
|
23
25
|
require_relative 'host_listvars'
|
|
24
26
|
require_relative 'host_rmvar'
|
|
27
|
+
require_relative 'host_tags'
|
|
25
28
|
end
|
|
26
29
|
end
|
|
27
30
|
end
|
|
@@ -15,12 +15,28 @@ module Moose
|
|
|
15
15
|
##
|
|
16
16
|
# Class implementing the "host" methods of the CLI
|
|
17
17
|
class Host
|
|
18
|
+
ADD_HOST_EVENT_RENDERERS = {
|
|
19
|
+
host_started: :render_add_host_started,
|
|
20
|
+
creating_host: :render_add_host_creation,
|
|
21
|
+
host_exists: :render_add_host_exists_warning,
|
|
22
|
+
ok: :render_add_host_ok,
|
|
23
|
+
adding_association: :render_add_host_association,
|
|
24
|
+
group_missing_created: :render_add_host_missing_group_warning,
|
|
25
|
+
association_exists: :render_add_host_association_exists_warning,
|
|
26
|
+
adding_automatic_group: :render_add_host_automatic_group,
|
|
27
|
+
host_complete: :render_add_host_complete,
|
|
28
|
+
dry_run_summary: :render_dry_run_summary
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
18
31
|
#==========================
|
|
19
32
|
desc 'add HOSTNAME_1 [HOSTNAME_2 ...]',
|
|
20
33
|
'Add a hosts HOSTNAME_n to the inventory'
|
|
21
34
|
option :groups
|
|
35
|
+
option :dry_run, type: :boolean
|
|
36
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
22
37
|
def add(*argv)
|
|
23
38
|
abort_if_missing_args(argv, 1, '1 or more')
|
|
39
|
+
validate_machine_plan_request!
|
|
24
40
|
|
|
25
41
|
# Arguments
|
|
26
42
|
names = normalize_names(argv)
|
|
@@ -32,11 +48,14 @@ module Moose
|
|
|
32
48
|
# Sanity
|
|
33
49
|
abort_if_automatic_group(groups)
|
|
34
50
|
|
|
35
|
-
result = Moose::Inventory::Operations::AddHosts
|
|
36
|
-
.
|
|
37
|
-
|
|
51
|
+
result = build_operation(Moose::Inventory::Operations::AddHosts)
|
|
52
|
+
.call(names: names, groups: groups, dry_run: options[:dry_run])
|
|
53
|
+
return if machine_plan_output_rendered?(result, command: 'host add')
|
|
54
|
+
|
|
55
|
+
record_audit({ command: 'host add', action: 'add', entity_type: 'host',
|
|
56
|
+
entity_names: names }, result: result, dry_run: options[:dry_run])
|
|
38
57
|
render_add_hosts_events(result.events)
|
|
39
|
-
|
|
58
|
+
print_warning_summary(result, success_message: 'Succeeded', warning_message: 'Succeeded')
|
|
40
59
|
end
|
|
41
60
|
|
|
42
61
|
private
|
|
@@ -46,31 +65,52 @@ module Moose
|
|
|
46
65
|
events.each { |event| render_add_hosts_event(event) }
|
|
47
66
|
end
|
|
48
67
|
|
|
49
|
-
def render_add_hosts_event(event)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
def render_add_hosts_event(event)
|
|
69
|
+
renderer = ADD_HOST_EVENT_RENDERERS[event.type]
|
|
70
|
+
send(renderer, event.payload) unless renderer.nil?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def render_add_host_started(payload)
|
|
74
|
+
puts "Add host '#{payload[:name]}':"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def render_add_host_creation(payload)
|
|
78
|
+
fmt.puts 2, "- Creating host '#{payload[:name]}'..."
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def render_add_host_exists_warning(payload)
|
|
82
|
+
fmt.warn "The host '#{payload[:name]}' already exists, skipping creation.\n"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def render_add_host_ok(payload)
|
|
86
|
+
fmt.puts payload[:indent], '- OK'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def render_add_host_association(payload)
|
|
90
|
+
fmt.puts 2, "- Adding association {host:#{payload[:host]} <-> group:#{payload[:group]}}..."
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def render_add_host_missing_group_warning(payload)
|
|
94
|
+
fmt.warn "The group '#{payload[:name]}' doesn't exist, but will be created.\n"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def render_add_host_association_exists_warning(payload)
|
|
98
|
+
fmt.warn(
|
|
99
|
+
"Association {host:#{payload[:host]} <-> group:#{payload[:group]}} " \
|
|
100
|
+
"already exists, skipping creation.\n"
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def render_add_host_automatic_group(payload)
|
|
105
|
+
fmt.puts 2, "- Adding automatic association {host:#{payload[:host]} <-> group:#{payload[:group]}}..."
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def render_add_host_complete(_payload)
|
|
109
|
+
fmt.puts 2, '- All OK'
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def render_dry_run_summary(_payload)
|
|
113
|
+
puts 'Dry run complete. No changes applied.'
|
|
74
114
|
end
|
|
75
115
|
end
|
|
76
116
|
end
|
|
@@ -16,80 +16,44 @@ module Moose
|
|
|
16
16
|
class Host
|
|
17
17
|
desc 'addgroup HOSTNAME GROUPNAME [GROUPNAME ...]',
|
|
18
18
|
'Associate the host with a group'
|
|
19
|
+
option :dry_run, type: :boolean
|
|
20
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
19
21
|
def addgroup(*args)
|
|
20
22
|
abort_if_missing_args(args, 2, '2 or more')
|
|
23
|
+
validate_machine_plan_request!
|
|
21
24
|
|
|
22
25
|
name = args[0].downcase
|
|
23
26
|
groups = normalize_names(args.slice(1, args.length - 1))
|
|
24
27
|
|
|
25
28
|
abort_if_automatic_group(groups)
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
36
|
-
fmt.puts 2, '- All OK'
|
|
30
|
+
result = add_groups_to_host(name, groups)
|
|
31
|
+
unless machine_plan_output_rendered?(
|
|
32
|
+
result, command: 'host addgroup'
|
|
33
|
+
)
|
|
34
|
+
record_audit({ command: 'host addgroup', action: 'associate', entity_type: 'host',
|
|
35
|
+
entity_names: name }, result: result, dry_run: options[:dry_run])
|
|
36
|
+
print_warning_summary(result, success_message: 'Succeeded',
|
|
37
|
+
warning_message: 'Succeeded')
|
|
37
38
|
end
|
|
38
|
-
|
|
39
|
-
puts 'Succeeded'
|
|
40
39
|
end
|
|
41
40
|
|
|
42
41
|
private
|
|
43
42
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
host
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def render_host_addgroup_events(events)
|
|
54
|
-
events.each { |event| render_host_addgroup_event(event) }
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def render_host_addgroup_event(event)
|
|
58
|
-
payload = event.payload
|
|
59
|
-
|
|
60
|
-
return render_host_addgroup_warning(event.type, payload) if host_addgroup_warning?(event.type)
|
|
61
|
-
return render_host_addgroup_status(payload) if event.type == :already_exists_skipping
|
|
62
|
-
|
|
63
|
-
render_host_addgroup_output(event.type, payload)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def host_addgroup_warning?(type)
|
|
67
|
-
%i[host_group_association_exists group_missing_created].include?(type)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def render_host_addgroup_warning(type, payload)
|
|
71
|
-
if type == :host_group_association_exists
|
|
72
|
-
fmt.warn "Association {host:#{payload[:host]} <-> group:#{payload[:group]}} already exists, skipping."
|
|
73
|
-
else
|
|
74
|
-
fmt.warn "Group '#{payload[:name]}' does not exist and will be created."
|
|
43
|
+
def add_groups_to_host(name, groups)
|
|
44
|
+
operation = build_operation(Moose::Inventory::Operations::AddAssociations)
|
|
45
|
+
run_host_relation_transaction(heading: "Associate host '#{name}' with groups '#{groups.join(',')}':") do
|
|
46
|
+
host = fetch_existing_host_or_raise(name)
|
|
47
|
+
result = operation.host_to_groups(host: host, host_name: name, group_names: groups,
|
|
48
|
+
dry_run: options[:dry_run])
|
|
49
|
+
render_host_addgroup_events(result.events) unless machine_plan_output_requested?
|
|
50
|
+
result
|
|
75
51
|
end
|
|
76
52
|
end
|
|
77
53
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def render_host_addgroup_output(type, payload)
|
|
83
|
-
case type
|
|
84
|
-
when :adding_host_group_association
|
|
85
|
-
fmt.puts 2, "- Add association {host:#{payload[:host]} <-> group:#{payload[:group]}}..."
|
|
86
|
-
when :group_creating_now
|
|
87
|
-
fmt.puts 4, '- Group does not exist, creating now...'
|
|
88
|
-
when :removing_automatic_group
|
|
89
|
-
fmt.puts 2, "- Remove automatic association {host:#{payload[:host]} <-> group:ungrouped}..."
|
|
90
|
-
when :ok
|
|
91
|
-
fmt.puts payload[:indent], '- OK'
|
|
92
|
-
end
|
|
54
|
+
def render_host_addgroup_events(events)
|
|
55
|
+
emitter = host_group_association_addition_emitter(perspective: :host)
|
|
56
|
+
events.each { |event| emitter.call(event) }
|
|
93
57
|
end
|
|
94
58
|
end
|
|
95
59
|
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/add_variables'
|
|
6
8
|
|
|
7
9
|
module Moose
|
|
8
10
|
module Inventory
|
|
@@ -12,64 +14,38 @@ module Moose
|
|
|
12
14
|
class Host
|
|
13
15
|
#==========================
|
|
14
16
|
desc 'addvar', 'Add a variable to the host'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"#{args.length} for 2 or more.")
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Convenience
|
|
24
|
-
db = Moose::Inventory::DB
|
|
25
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
17
|
+
option :dry_run, type: :boolean
|
|
18
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
19
|
+
def addvar(*args)
|
|
20
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
21
|
+
validate_machine_plan_request!
|
|
26
22
|
|
|
27
|
-
# Arguments
|
|
28
23
|
name = args[0].downcase
|
|
29
24
|
vars = args.slice(1, args.length - 1).uniq
|
|
25
|
+
operation = build_operation(Moose::Inventory::Operations::AddVariables,
|
|
26
|
+
entity_type: :host,
|
|
27
|
+
emitter: machine_plan_emitter(host_addvar_emitter(name, vars)))
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
result = db.transaction do
|
|
30
|
+
operation.call(name: name, vars: vars, dry_run: options[:dry_run])
|
|
31
|
+
end
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
host = db.models[:host].find(name: name)
|
|
37
|
-
if host.nil?
|
|
38
|
-
fail db.exceptions[:moose],
|
|
39
|
-
"The host '#{name}' does not exist."
|
|
40
|
-
end
|
|
41
|
-
fmt.puts 4, '- OK'
|
|
33
|
+
return if machine_plan_output_rendered?(result, command: 'host addvar')
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if v.start_with?('=') || v.end_with?('=') || vararray.length != 2
|
|
48
|
-
fail db.exceptions[:moose],
|
|
49
|
-
"Incorrect format in '{#{v}}'. Expected 'key=value'."
|
|
50
|
-
end
|
|
35
|
+
record_audit({ command: 'host addvar', action: 'add_variable', entity_type: 'host',
|
|
36
|
+
entity_names: name }, result: result, dry_run: options[:dry_run])
|
|
37
|
+
print_success_summary
|
|
38
|
+
end
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
hostvar = hostvars_ds[name: vararray[0]]
|
|
54
|
-
if !hostvar.nil?
|
|
55
|
-
unless hostvar[:value] == vararray[1]
|
|
56
|
-
fmt.puts 4, '- already exists, applying as an update...'
|
|
57
|
-
update = db.models[:hostvar].find(id: hostvar[:id])
|
|
58
|
-
update[:value] = vararray[1]
|
|
59
|
-
update.save
|
|
60
|
-
end
|
|
61
|
-
else
|
|
62
|
-
# hostvar doesn't exist, so create and associate
|
|
63
|
-
hostvar = db.models[:hostvar].create(name: vararray[0],
|
|
64
|
-
value: vararray[1])
|
|
65
|
-
host.add_hostvar(hostvar)
|
|
66
|
-
end
|
|
67
|
-
fmt.puts 4, '- OK'
|
|
68
|
-
end
|
|
69
|
-
fmt.puts 2, '- all OK'
|
|
70
|
-
end # Transaction end
|
|
40
|
+
private
|
|
71
41
|
|
|
72
|
-
|
|
42
|
+
def host_addvar_emitter(name, vars)
|
|
43
|
+
variable_operation_emitter(
|
|
44
|
+
action: :add,
|
|
45
|
+
entity_label: 'host',
|
|
46
|
+
entity_name: name,
|
|
47
|
+
variables_label: vars.join(',')
|
|
48
|
+
)
|
|
73
49
|
end
|
|
74
50
|
end
|
|
75
51
|
end
|
|
@@ -1,54 +1,26 @@
|
|
|
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
|
|
9
11
|
module Cli
|
|
10
|
-
##
|
|
11
12
|
# Class implementing the "host get" method of the CLI
|
|
12
13
|
class Host
|
|
13
14
|
require_relative 'host_add'
|
|
14
15
|
|
|
15
|
-
#==========================
|
|
16
16
|
desc 'get HOST_1 [HOST_2 ...]',
|
|
17
17
|
'Get hosts HOST_n from the inventory'
|
|
18
|
-
def get(*argv)
|
|
19
|
-
if argv.empty?
|
|
20
|
-
abort('ERROR: Wrong number of arguments, '\
|
|
21
|
-
"#{argv.length} for 1 or more")
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Convenience
|
|
25
|
-
db = Moose::Inventory::DB
|
|
26
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
27
|
-
|
|
28
|
-
# Arguments
|
|
29
|
-
names = argv.uniq.map(&:downcase)
|
|
30
|
-
|
|
31
|
-
# Process
|
|
32
|
-
results = {}
|
|
33
|
-
names.each do |name|
|
|
34
|
-
host = db.models[:host].find(name: name)
|
|
35
|
-
|
|
36
|
-
next if host.nil?
|
|
37
|
-
groups = host.groups_dataset.map(:name)
|
|
38
|
-
|
|
39
|
-
hostvars = {}
|
|
40
|
-
host.hostvars_dataset.each do |hv|
|
|
41
|
-
hostvars[hv[:name].to_sym] = hv[:value]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
results[host[:name].to_sym] = {}
|
|
45
|
-
results[host[:name].to_sym][:groups] = groups unless groups.empty?
|
|
46
|
-
unless hostvars.empty?
|
|
47
|
-
results[host[:name].to_sym][:hostvars] = hostvars
|
|
48
|
-
end
|
|
49
|
-
end
|
|
18
|
+
def get(*argv)
|
|
19
|
+
abort("ERROR: Wrong number of arguments, #{argv.length} for 1 or more") if argv.empty?
|
|
50
20
|
|
|
51
|
-
|
|
21
|
+
names = normalize_names(argv)
|
|
22
|
+
results = inventory_query.get_hosts(names: names)
|
|
23
|
+
fmt.dump(results, output_format)
|
|
52
24
|
end
|
|
53
25
|
end
|
|
54
26
|
end
|