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
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
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
|
+
|
|
14
|
+
module Moose
|
|
15
|
+
module Inventory
|
|
16
|
+
module Cli
|
|
17
|
+
##
|
|
18
|
+
# Shared helpers for Thor command classes.
|
|
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
|
+
|
|
29
|
+
AUTOMATIC_GROUP = 'ungrouped'
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def db
|
|
34
|
+
Moose::Inventory::DB
|
|
35
|
+
end
|
|
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
|
+
|
|
53
|
+
def fmt
|
|
54
|
+
Moose::Inventory::Cli::Formatter
|
|
55
|
+
end
|
|
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
|
+
|
|
69
|
+
def normalize_names(values)
|
|
70
|
+
values.uniq.map(&:downcase)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def csv_option_names(value)
|
|
74
|
+
(value || '').downcase.split(',').uniq
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def abort_if_missing_args(args, minimum, label)
|
|
78
|
+
return unless args.length < minimum
|
|
79
|
+
|
|
80
|
+
abort("ERROR: Wrong number of arguments, #{args.length} for #{label}.")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def abort_if_automatic_group(names, message = nil)
|
|
84
|
+
return unless names.include?(AUTOMATIC_GROUP)
|
|
85
|
+
|
|
86
|
+
abort(message || "ERROR: Cannot manually manipulate the automatic group '#{AUTOMATIC_GROUP}'.")
|
|
87
|
+
end
|
|
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
|
+
|
|
95
|
+
def association_exists?(dataset, name)
|
|
96
|
+
!dataset.nil? && !dataset[name: name].nil?
|
|
97
|
+
end
|
|
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
|
+
|
|
112
|
+
def automatic_group
|
|
113
|
+
inventory_context.automatic_group
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def remove_automatic_group_from_host(host, indent:, message:)
|
|
117
|
+
ungrouped = host.groups_dataset[name: AUTOMATIC_GROUP]
|
|
118
|
+
return if ungrouped.nil?
|
|
119
|
+
|
|
120
|
+
fmt.puts indent, message
|
|
121
|
+
host.remove_group(ungrouped)
|
|
122
|
+
fmt.puts indent + 2, '- OK'
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def add_automatic_group_to_host_if_last_group(host, indent:, message:)
|
|
126
|
+
add_automatic_group_to_host_if_group_count(host, 1, indent: indent, message: message)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def add_automatic_group_to_host_if_no_groups(host, indent:, message:)
|
|
130
|
+
add_automatic_group_to_host_if_group_count(host, 0, indent: indent, message: message)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def add_automatic_group_to_host_if_group_count(host, group_count, indent:, message:)
|
|
134
|
+
return unless host.groups_dataset.count == group_count
|
|
135
|
+
|
|
136
|
+
fmt.puts indent, message
|
|
137
|
+
host.add_group(automatic_group)
|
|
138
|
+
fmt.puts indent + 2, '- OK'
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -1,8 +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 'formatter'
|
|
7
|
+
require_relative 'helpers'
|
|
8
|
+
require_relative '../db/exceptions'
|
|
6
9
|
|
|
7
10
|
module Moose
|
|
8
11
|
module Inventory
|
|
@@ -10,6 +13,8 @@ module Moose
|
|
|
10
13
|
##
|
|
11
14
|
# Class implementing the "host" methods of the CLI
|
|
12
15
|
class Host < Thor
|
|
16
|
+
include Moose::Inventory::Cli::Helpers
|
|
17
|
+
|
|
13
18
|
require_relative 'host_add'
|
|
14
19
|
require_relative 'host_get'
|
|
15
20
|
require_relative 'host_list'
|
|
@@ -19,6 +24,7 @@ module Moose
|
|
|
19
24
|
require_relative 'host_addvar'
|
|
20
25
|
require_relative 'host_listvars'
|
|
21
26
|
require_relative 'host_rmvar'
|
|
27
|
+
require_relative 'host_tags'
|
|
22
28
|
end
|
|
23
29
|
end
|
|
24
30
|
end
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
4
|
require 'json'
|
|
3
5
|
require 'indentation'
|
|
4
6
|
|
|
5
|
-
require_relative '
|
|
6
|
-
require_relative '../db/exceptions
|
|
7
|
+
require_relative 'formatter'
|
|
8
|
+
require_relative '../db/exceptions'
|
|
9
|
+
require_relative '../inventory_context'
|
|
10
|
+
require_relative '../operations/add_hosts'
|
|
7
11
|
|
|
8
12
|
module Moose
|
|
9
13
|
module Inventory
|
|
@@ -11,81 +15,102 @@ module Moose
|
|
|
11
15
|
##
|
|
12
16
|
# Class implementing the "host" methods of the CLI
|
|
13
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
|
+
|
|
14
31
|
#==========================
|
|
15
32
|
desc 'add HOSTNAME_1 [HOSTNAME_2 ...]',
|
|
16
33
|
'Add a hosts HOSTNAME_n to the inventory'
|
|
17
34
|
option :groups
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"#{argv.length} for 1 or more.")
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Convenience
|
|
27
|
-
db = Moose::Inventory::DB
|
|
28
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
35
|
+
option :dry_run, type: :boolean
|
|
36
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
37
|
+
def add(*argv)
|
|
38
|
+
abort_if_missing_args(argv, 1, '1 or more')
|
|
39
|
+
validate_machine_plan_request!
|
|
29
40
|
|
|
30
41
|
# Arguments
|
|
31
|
-
names = argv
|
|
42
|
+
names = normalize_names(argv)
|
|
32
43
|
|
|
33
44
|
# split(/\W+/) splits on hyphens too, which is not what we want
|
|
34
45
|
# groups = options[:groups].downcase.split(/\W+/).uniq
|
|
35
|
-
|
|
36
|
-
groups = options[:groups].downcase.split(',').uniq
|
|
46
|
+
groups = csv_option_names(options[:groups])
|
|
37
47
|
|
|
38
48
|
# Sanity
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
49
|
+
abort_if_automatic_group(groups)
|
|
50
|
+
|
|
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])
|
|
57
|
+
render_add_hosts_events(result.events)
|
|
58
|
+
print_warning_summary(result, success_message: 'Succeeded', warning_message: 'Succeeded')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def render_add_hosts_events(events)
|
|
64
|
+
fmt.reset_indent
|
|
65
|
+
events.each { |event| render_add_hosts_event(event) }
|
|
66
|
+
end
|
|
67
|
+
|
|
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.'
|
|
89
114
|
end
|
|
90
115
|
end
|
|
91
116
|
end
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'thor'
|
|
2
4
|
require 'json'
|
|
3
5
|
|
|
4
|
-
require_relative '
|
|
5
|
-
require_relative '../db/exceptions
|
|
6
|
+
require_relative 'formatter'
|
|
7
|
+
require_relative '../db/exceptions'
|
|
8
|
+
require_relative '../inventory_context'
|
|
9
|
+
require_relative '../operations/add_associations'
|
|
6
10
|
|
|
7
11
|
module Moose
|
|
8
12
|
module Inventory
|
|
@@ -12,75 +16,44 @@ module Moose
|
|
|
12
16
|
class Host
|
|
13
17
|
desc 'addgroup HOSTNAME GROUPNAME [GROUPNAME ...]',
|
|
14
18
|
'Associate the host with a group'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
option :dry_run, type: :boolean
|
|
20
|
+
option :plan_format, type: :string, desc: 'Emit dry-run plan events as yaml|json|pjson'
|
|
21
|
+
def addgroup(*args)
|
|
22
|
+
abort_if_missing_args(args, 2, '2 or more')
|
|
23
|
+
validate_machine_plan_request!
|
|
24
|
+
|
|
25
|
+
name = args[0].downcase
|
|
26
|
+
groups = normalize_names(args.slice(1, args.length - 1))
|
|
27
|
+
|
|
28
|
+
abort_if_automatic_group(groups)
|
|
29
|
+
|
|
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')
|
|
22
38
|
end
|
|
39
|
+
end
|
|
23
40
|
|
|
24
|
-
|
|
25
|
-
db = Moose::Inventory::DB
|
|
26
|
-
fmt = Moose::Inventory::Cli::Formatter
|
|
27
|
-
|
|
28
|
-
# Arguments
|
|
29
|
-
name = args[0].downcase
|
|
30
|
-
groups = args.slice(1, args.length - 1).uniq.map(&:downcase)
|
|
41
|
+
private
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
36
51
|
end
|
|
52
|
+
end
|
|
37
53
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# Get the target host
|
|
42
|
-
fmt.puts 2, "- Retrieve host '#{name}'..."
|
|
43
|
-
host = db.models[:host].find(name: name)
|
|
44
|
-
if host.nil?
|
|
45
|
-
fail db.exceptions[:moose], "The host '#{name}' "\
|
|
46
|
-
'was not found in the database.'
|
|
47
|
-
end
|
|
48
|
-
fmt.puts 4, '- OK'
|
|
49
|
-
|
|
50
|
-
# Associate host with the groups
|
|
51
|
-
groups_ds = host.groups_dataset
|
|
52
|
-
groups.each do |g|
|
|
53
|
-
fmt.puts 2, "- Add association {host:#{name} <-> group:#{g}}..."
|
|
54
|
-
|
|
55
|
-
# Check against existing associations
|
|
56
|
-
if !groups_ds[name: g].nil?
|
|
57
|
-
fmt.warn "Association {host:#{name} <-> group:#{g}} already exists, skipping."
|
|
58
|
-
fmt.puts 4, '- Already exists, skipping.'
|
|
59
|
-
else
|
|
60
|
-
# Add new association
|
|
61
|
-
group = db.models[:group].find(name: g)
|
|
62
|
-
if group.nil?
|
|
63
|
-
fmt.warn "Group '#{g}' does not exist and will be created."
|
|
64
|
-
fmt.puts 4, '- Group does not exist, creating now...'
|
|
65
|
-
group = db.models[:group].create(name: g)
|
|
66
|
-
fmt.puts 6, '- OK'
|
|
67
|
-
end
|
|
68
|
-
host.add_group(group)
|
|
69
|
-
end
|
|
70
|
-
fmt.puts 4, '- OK'
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Handle 'ungrouped' group automation
|
|
74
|
-
unless groups_ds[name: 'ungrouped'].nil?
|
|
75
|
-
fmt.puts 2, '- Remove automatic association '\
|
|
76
|
-
"{host:#{name} <-> group:ungrouped}..."
|
|
77
|
-
ungrouped = db.models[:group].find(name: 'ungrouped')
|
|
78
|
-
host.remove_group(ungrouped) unless ungrouped.nil?
|
|
79
|
-
fmt.puts 4, '- OK'
|
|
80
|
-
end
|
|
81
|
-
fmt.puts 2, '- All OK'
|
|
82
|
-
end # Transaction end
|
|
83
|
-
puts 'Succeeded'
|
|
54
|
+
def render_host_addgroup_events(events)
|
|
55
|
+
emitter = host_group_association_addition_emitter(perspective: :host)
|
|
56
|
+
events.each { |event| emitter.call(event) }
|
|
84
57
|
end
|
|
85
58
|
end
|
|
86
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
|