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
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# moose-inventory
|
|
2
2
|
|
|
3
|
-
The [moose-inventory](https://github.com/RusDavies/moose-inventory) software is a tool for managing dynamic inventories, intended for use with [Ansible](http://www.ansible.com/home).
|
|
3
|
+
The [moose-inventory](https://github.com/RusDavies/moose-inventory) software is a tool for managing dynamic inventories, intended for use with [Ansible](http://www.ansible.com/home).
|
|
4
4
|
|
|
5
5
|
Note 1: For many, the really interesting part of this tool will be it's ability to write to the inventory database from within Ansible, as described at the end of this document. If that's what tickles your fancy, then I encourage you to get a sense of the capability by [jumping to that section first](https://github.com/RusDavies/moose-inventory#writing-to-the-dynamic-inventory-from-ansible). ;o)
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
Note 2: This software is intended for use on UNIX/Linux systems. It will likely not work on Windows, due to some hard-wired search paths - I may fix that in the future but, for now, sorry.
|
|
8
|
+
Note 2: This software is intended for use on UNIX/Linux systems. It will likely not work on Windows, due to some hard-wired search paths - I may fix that in the future but, for now, sorry.
|
|
9
9
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
@@ -25,11 +25,11 @@ gem 'moose-inventory'
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
## Configuration
|
|
28
|
-
The [moose-inventory](https://github.com/RusDavies/moose-inventory) tool makes use of a simple YAML configuration file.
|
|
28
|
+
The [moose-inventory](https://github.com/RusDavies/moose-inventory) tool makes use of a simple YAML configuration file.
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
###File Location
|
|
32
|
-
|
|
31
|
+
### File Location
|
|
32
|
+
|
|
33
33
|
The following locations, in descending order of precedence, are searched for a configuration file:
|
|
34
34
|
|
|
35
35
|
1. location passed via the `--config` option
|
|
@@ -38,14 +38,14 @@ The following locations, in descending order of precedence, are searched for a
|
|
|
38
38
|
5. ~/local/etc/moose-tools/inventory/config
|
|
39
39
|
6. /etc/moose-tools/inventory/config
|
|
40
40
|
|
|
41
|
-
###Format
|
|
42
|
-
The file consists of a mandatory *general* section, and at least one *environment* section. For example:
|
|
41
|
+
### Format
|
|
42
|
+
The file consists of a mandatory *general* section, and at least one *environment* section. For example:
|
|
43
43
|
```yaml
|
|
44
44
|
---
|
|
45
45
|
general:
|
|
46
46
|
defaultenv: moose_dev
|
|
47
47
|
|
|
48
|
-
moose_dev:
|
|
48
|
+
moose_dev:
|
|
49
49
|
db:
|
|
50
50
|
adapter: "sqlite3"
|
|
51
51
|
file: "~/.moose/db/dev.db"
|
|
@@ -68,13 +68,13 @@ another_example_section:
|
|
|
68
68
|
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
###The *general* section
|
|
72
|
-
The general section is mandatory, and contains a single parameter **defaultenv**, which points to the name of the default environment section.
|
|
71
|
+
### The *general* section
|
|
72
|
+
The general section is mandatory, and contains a single parameter **defaultenv**, which points to the name of the default environment section.
|
|
73
73
|
|
|
74
|
-
###Environment sections
|
|
74
|
+
### Environment sections
|
|
75
75
|
You may add as many environment sections as you desire. The intention is to enable the user to easily manage multiple environments, such as development, staging, production, etc., via a single configuration file. The name of each environment section must be unique, but can otherwise be any valid YAML tag.
|
|
76
76
|
|
|
77
|
-
At present, each environment section contains only a **db** subsection, describing database connection parameters. Additional subsections may be added in the future, as functionality increases.
|
|
77
|
+
At present, each environment section contains only a **db** subsection, describing database connection parameters. Additional subsections may be added in the future, as functionality increases.
|
|
78
78
|
|
|
79
79
|
Each **db** section must include an **adapter** parameter. Currently supported adapter types are *sqlite3*, *mysql*, and *postgresql*. The test suite exercises SQLite with a local database file and includes adapter dispatch/error-path smoke coverage for MySQL and PostgreSQL without requiring live database servers.
|
|
80
80
|
|
|
@@ -98,19 +98,19 @@ The tool itself provides a convenient help feature. For example, try each of th
|
|
|
98
98
|
$ moose-inventory help group
|
|
99
99
|
$ moose-inventory group help add
|
|
100
100
|
|
|
101
|
-
###Global switches
|
|
101
|
+
### Global switches
|
|
102
102
|
|
|
103
103
|
#### Option `--config <FILE>`
|
|
104
104
|
The `--config` flag sets the configuration file to be used. If specified, then the file must exist. This takes precedence over all other config files in other locations. If not provided, then the default is to search the locations previously mentioned.
|
|
105
105
|
|
|
106
|
-
For example,
|
|
106
|
+
For example,
|
|
107
107
|
|
|
108
108
|
$ moose-inventory --config ./mystuff.conf host list
|
|
109
109
|
|
|
110
110
|
#### Option `--env <SECTION>`
|
|
111
|
-
The *--env* flag sets the section in the configuration file to be used as the environment configuration. If set, then the section must exist. If not set, then what ever default is provided by the **defaultenv** parameter will be used.
|
|
111
|
+
The *--env* flag sets the section in the configuration file to be used as the environment configuration. If set, then the section must exist. If not set, then what ever default is provided by the **defaultenv** parameter will be used.
|
|
112
112
|
|
|
113
|
-
For example,
|
|
113
|
+
For example,
|
|
114
114
|
|
|
115
115
|
$ moose-inventory --env my_section host list
|
|
116
116
|
|
|
@@ -125,13 +125,216 @@ For example,
|
|
|
125
125
|
:groups:
|
|
126
126
|
- ungrouped
|
|
127
127
|
|
|
128
|
-
###Transactional Behaviour
|
|
129
|
-
The *moose-inventory* tool performs database operations in a transactional manner. That is to say, either all operations of a command succeed, or they are all rolled back.
|
|
128
|
+
### Transactional Behaviour
|
|
129
|
+
The *moose-inventory* tool performs database operations in a transactional manner. That is to say, either all operations of a command succeed, or they are all rolled back.
|
|
130
|
+
|
|
131
|
+
### Dry-run and plan output
|
|
132
|
+
Mutating commands support a `--dry-run` option. This renders the same kind of progress output as the real command, but does not write anything to the database. This is useful when checking inventory surgery before applying it, particularly for operations that affect automatic `ungrouped` associations or child-group cleanup.
|
|
133
|
+
|
|
134
|
+
Examples:
|
|
135
|
+
|
|
136
|
+
$ moose-inventory host add web01 --groups web --dry-run
|
|
137
|
+
Add host 'web01':
|
|
138
|
+
- Creating host 'web01'...
|
|
139
|
+
- OK
|
|
140
|
+
- Adding association {host:web01 <-> group:web}...
|
|
141
|
+
- OK
|
|
142
|
+
- All OK
|
|
143
|
+
Dry run complete. No changes applied.
|
|
144
|
+
Succeeded
|
|
145
|
+
|
|
146
|
+
$ moose-inventory group rm --recursive old_parent_group --dry-run
|
|
147
|
+
$ moose-inventory host addvar web01 owner=russ env=prod --dry-run
|
|
148
|
+
$ moose-inventory group addhost web web01 web02 --dry-run
|
|
149
|
+
$ moose-inventory group rmchild --delete-orphans parent_group child_group --dry-run
|
|
150
|
+
|
|
151
|
+
The following mutating command families support `--dry-run`:
|
|
152
|
+
|
|
153
|
+
1. `host add` and `host rm`
|
|
154
|
+
2. `group add` and `group rm`
|
|
155
|
+
3. `host addvar`, `host rmvar`, `group addvar`, and `group rmvar`
|
|
156
|
+
4. `host addgroup`, `host rmgroup`, `group addhost`, and `group rmhost`
|
|
157
|
+
5. `group addchild` and `group rmchild`
|
|
158
|
+
|
|
159
|
+
For automation and review workflows, dry-run events can also be emitted as YAML, JSON, or pretty JSON with `--plan-format`. This option requires `--dry-run`; without it, the command aborts before making changes.
|
|
160
|
+
|
|
161
|
+
Destructive removal commands require an explicit acknowledgement before they write. Use `--dry-run` to preview, or add `--yes` when you intentionally want to apply a removal non-interactively. This applies to host/group deletion, variable removal, association removal, child-group dissociation, and metadata tag removal commands.
|
|
162
|
+
|
|
163
|
+
$ moose-inventory host rm old-web01 --dry-run
|
|
164
|
+
$ moose-inventory host rm old-web01 --yes
|
|
165
|
+
$ moose-inventory group rm --recursive old_parent_group --yes
|
|
166
|
+
|
|
167
|
+
$ moose-inventory host add web01 --groups web --dry-run --plan-format pjson
|
|
168
|
+
{
|
|
169
|
+
"command": "host add",
|
|
170
|
+
"dry_run": true,
|
|
171
|
+
"changes_applied": false,
|
|
172
|
+
"events": [
|
|
173
|
+
{
|
|
174
|
+
"type": "host_started",
|
|
175
|
+
"payload": {
|
|
176
|
+
"name": "web01"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
The actual `events` array includes the full ordered plan for the command. Each event has a `type` and a `payload`, so scripts can inspect planned host, group, variable, association, automatic `ungrouped`, and child-group cleanup actions without scraping human-readable output.
|
|
183
|
+
|
|
184
|
+
CLI output compatibility is governed by `CLI-OUTPUT-v1` in `docs/compatibility/cli-output-compatibility.md`. Machine-readable JSON/YAML/pjson structures are the supported automation interface. Documented human-readable output is also compatibility-protected when tests, README examples, or release notes rely on it, but scripts should prefer machine-readable formats.
|
|
185
|
+
|
|
186
|
+
### Import and export snapshots
|
|
187
|
+
The full inventory can be exported as a portable snapshot. The snapshot contains a version number, hosts, host variables, host-to-group memberships, host/group tags, groups, group variables, and child-group relationships. It is intended for review, backup, migration, and automation workflows.
|
|
188
|
+
|
|
189
|
+
$ moose-inventory --format yaml export inventory.yml
|
|
190
|
+
Exported inventory snapshot to inventory.yml.
|
|
191
|
+
|
|
192
|
+
$ moose-inventory --format pjson export
|
|
193
|
+
{
|
|
194
|
+
"version": 1,
|
|
195
|
+
"hosts": {
|
|
196
|
+
"web01": {
|
|
197
|
+
"groups": [
|
|
198
|
+
"web"
|
|
199
|
+
],
|
|
200
|
+
"tags": [
|
|
201
|
+
"prod"
|
|
202
|
+
],
|
|
203
|
+
"vars": {
|
|
204
|
+
"env": "prod"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"groups": {
|
|
209
|
+
"web": {
|
|
210
|
+
"children": [],
|
|
211
|
+
"tags": [
|
|
212
|
+
"frontend"
|
|
213
|
+
],
|
|
214
|
+
"vars": {
|
|
215
|
+
"role": "frontend"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
Snapshots can be imported from YAML or JSON. Import validates the file before writing anything. It rejects malformed snapshots, unknown host/group references, unsupported fields, invalid variable shapes, and circular child-group hierarchies.
|
|
222
|
+
|
|
223
|
+
Use `--preview` to validate a snapshot and review its additive import diff without writing to the database. For automation/review gates, add `--preview-format yaml|json|pjson`; the preview uses `snapshot-import-preview-v1`, reports creates, variable updates, association additions, unchanged items, existing records that are absent from the snapshot and therefore ignored, and confirms that destructive changes are not part of normal import.
|
|
224
|
+
|
|
225
|
+
$ moose-inventory import inventory.yml
|
|
226
|
+
Imported inventory snapshot from inventory.yml.
|
|
227
|
+
Created hosts: 1
|
|
228
|
+
Created groups: 1
|
|
229
|
+
Variables changed: 2
|
|
230
|
+
Associations added: 1
|
|
231
|
+
|
|
232
|
+
$ moose-inventory import inventory.yml --preview --preview-format pjson
|
|
233
|
+
|
|
234
|
+
Import is additive and update-oriented: it creates missing hosts and groups, adds missing associations and tags, and creates or updates variables found in the snapshot. It does not delete existing inventory records that are absent from the file. Use a fresh database when you want the imported snapshot to be the whole world, because databases are notoriously bad at guessing intent.
|
|
235
|
+
|
|
236
|
+
### Inventory doctor
|
|
237
|
+
The `doctor` command runs read-only inventory health checks and exits with a non-zero status if it finds issues. This makes it suitable for CI checks, release gates, and pre-change reviews.
|
|
238
|
+
|
|
239
|
+
$ moose-inventory doctor
|
|
240
|
+
Inventory doctor found no issues.
|
|
241
|
+
|
|
242
|
+
When findings are present, the human-readable output lists each issue with a severity and check id:
|
|
243
|
+
|
|
244
|
+
$ moose-inventory doctor
|
|
245
|
+
Inventory doctor found 2 issue(s):
|
|
246
|
+
- [warning] host_only_in_ungrouped: Host 'web01' is only in automatic group 'ungrouped'.
|
|
247
|
+
- [warning] orphaned_group: Group 'old_web' has no parents and no hosts.
|
|
248
|
+
|
|
249
|
+
For automation, use `--format yaml`, `--format json`, or `--format pjson` on the doctor command itself:
|
|
250
|
+
|
|
251
|
+
$ moose-inventory doctor --format pjson
|
|
252
|
+
{
|
|
253
|
+
"ok": false,
|
|
254
|
+
"issue_count": 1,
|
|
255
|
+
"issues": [
|
|
256
|
+
{
|
|
257
|
+
"id": "host_only_in_ungrouped",
|
|
258
|
+
"severity": "warning",
|
|
259
|
+
"message": "Host 'web01' is only in automatic group 'ungrouped'.",
|
|
260
|
+
"subject": "web01"
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
Current doctor checks include missing database configuration, plaintext database passwords, hosts only in `ungrouped`, orphaned groups, empty groups, duplicate-ish names, invalid variable records, and circular child-group relationships.
|
|
266
|
+
|
|
267
|
+
### Metadata tags
|
|
268
|
+
Hosts and groups can carry metadata tags that are separate from Ansible variables. Use tags for operational labels such as environment, owner, lifecycle, location, role, or criticality when you want metadata without exposing it as inventory variables.
|
|
269
|
+
|
|
270
|
+
$ moose-inventory host addtag web01 prod critical owner-platform
|
|
271
|
+
Added host tag(s) to 'web01': prod, critical, owner-platform.
|
|
272
|
+
|
|
273
|
+
$ moose-inventory host listtags web01
|
|
274
|
+
Host 'web01' tags: critical, owner-platform, prod
|
|
275
|
+
|
|
276
|
+
$ moose-inventory host rmtag web01 critical
|
|
277
|
+
Removed host tag(s) from 'web01': critical.
|
|
278
|
+
|
|
279
|
+
Groups support the same tag commands:
|
|
280
|
+
|
|
281
|
+
$ moose-inventory group addtag web frontend public-edge
|
|
282
|
+
$ moose-inventory group listtags web --format json
|
|
283
|
+
|
|
284
|
+
Tag names are case-insensitive operational metadata: CLI tag commands and snapshot imports normalize them to lowercase, strip surrounding whitespace, deduplicate repeated values, and store them in portable join tables. Tag add/remove operations are audited when they change state.
|
|
130
285
|
|
|
131
|
-
###
|
|
132
|
-
|
|
286
|
+
### Audit log / change history
|
|
287
|
+
Moose Inventory records append-only audit events for successful mutating CLI commands. Dry-run commands are intentionally excluded, because planned changes are already available through `--plan-format` and did not actually mutate inventory state.
|
|
133
288
|
|
|
134
|
-
|
|
289
|
+
Audit events record when the change happened, the local actor from `USER`, the command/action, the entity type/name, and structured operation details. The audit log is deliberately small: it is for debugging and accountability, not yet a full rollback system.
|
|
290
|
+
|
|
291
|
+
List recent events in a human-readable form:
|
|
292
|
+
|
|
293
|
+
$ moose-inventory audit list
|
|
294
|
+
12 2026-05-28T17:01:02Z host add host=app01 action=add
|
|
295
|
+
|
|
296
|
+
Machine-readable output is available for scripts and support bundles:
|
|
297
|
+
|
|
298
|
+
$ moose-inventory audit list --format yaml
|
|
299
|
+
$ moose-inventory audit list --format json
|
|
300
|
+
$ moose-inventory audit list --format pjson
|
|
301
|
+
|
|
302
|
+
The default limit is 20 events; use `--limit` to inspect more history:
|
|
303
|
+
|
|
304
|
+
$ moose-inventory audit list --limit 100
|
|
305
|
+
|
|
306
|
+
### Database lifecycle commands
|
|
307
|
+
Moose Inventory records a small schema metadata table and exposes database lifecycle commands under `db`. These commands are intentionally conservative: they inspect, create missing schema metadata, and back up SQLite databases, but they do not silently rewrite production databases into a modern art installation.
|
|
308
|
+
|
|
309
|
+
$ moose-inventory db status
|
|
310
|
+
Adapter: sqlite3
|
|
311
|
+
Schema version: 4
|
|
312
|
+
Expected schema version: 4
|
|
313
|
+
SQLite file: /home/russ/.moose/db/dev.db
|
|
314
|
+
Tables:
|
|
315
|
+
- hosts: present
|
|
316
|
+
- hostvars: present
|
|
317
|
+
- groups: present
|
|
318
|
+
|
|
319
|
+
$ moose-inventory db doctor
|
|
320
|
+
Database doctor found no issues.
|
|
321
|
+
|
|
322
|
+
$ moose-inventory db migrate
|
|
323
|
+
Database schema is at version 4.
|
|
324
|
+
|
|
325
|
+
`db migrate` runs explicit ordered schema migrations up to the current schema version. The current migration chain is `1 -> 2 -> 3 -> 4`: version 1 creates the core inventory tables and schema metadata, version 2 adds audit history, version 3 adds tag metadata, and version 4 adds DB-level uniqueness and lookup indexes for variables, host/group relationships, group-child relationships, and tag joins. Moose Inventory refuses to open or migrate a database whose recorded schema version is newer than the tool supports; upgrade the tool instead of letting old code write to a future schema. `db doctor` reports missing known tables in a dirty or partially migrated database.
|
|
326
|
+
|
|
327
|
+
SQLite users can create a direct database-file backup:
|
|
328
|
+
|
|
329
|
+
$ moose-inventory db backup ./backup/moose-inventory.sqlite3
|
|
330
|
+
Backed up database to /absolute/path/backup/moose-inventory.sqlite3.
|
|
331
|
+
|
|
332
|
+
`db backup` is currently supported for SQLite only. For MySQL/MariaDB and PostgreSQL, use native database tools such as `mysqldump`, `mariadb-dump`, `pg_dump`, managed-service snapshots, or equivalent backup systems, because those engines already have adult supervision built in. Moose Inventory does not run server-backed restore commands, manage database users/grants, or implement destructive snapshot sync/restore behavior. See `docs/maintenance/database-backup-restore-guidance.md` for adapter-specific backup and restore boundaries.
|
|
333
|
+
|
|
334
|
+
### Walk-through example
|
|
335
|
+
This walk-through goes through the process of creating three hosts and three groups, assigning variables to some of each, and then associating hosts with groups. Once done, each association, variable, group, and host are removed.
|
|
336
|
+
|
|
337
|
+
We start by creating three hosts, in this case named *host1*, *host2*, and *host3*. Note, we can add as many hosts as we desire via this single command. Also, although we have used short names here, we could equally have used fully qualified names.
|
|
135
338
|
|
|
136
339
|
$ moose-inventory add host host1 host2 host3
|
|
137
340
|
Add host 'host1':
|
|
@@ -154,7 +357,7 @@ We start by creating three hosts, in this case named *host1*, *host2*, and *hos
|
|
|
154
357
|
- all OK
|
|
155
358
|
Succeeded.
|
|
156
359
|
|
|
157
|
-
Notice that each host is initially associated with an automatic group, *ungrouped*.
|
|
360
|
+
Notice that each host is initially associated with an automatic group, *ungrouped*.
|
|
158
361
|
|
|
159
362
|
Now we can list our hosts, to see that they are stored as expected. In this example, we will request the output be formatted as YAML. If we didn't specify a format, then it would default to regular JSON.
|
|
160
363
|
|
|
@@ -177,7 +380,7 @@ Now we can list our hosts, to see that they are stored as expected. In this exa
|
|
|
177
380
|
}
|
|
178
381
|
}
|
|
179
382
|
|
|
180
|
-
The *host list* command simply lists all hosts, in the order that they were entered into the database. We can also get a specific host, or hosts, by name. In this example, we'll get only *host3* and *host1*, outputting the result in YAML.
|
|
383
|
+
The *host list* command simply lists all hosts, in the order that they were entered into the database. We can also get a specific host, or hosts, by name. In this example, we'll get only *host3* and *host1*, outputting the result in YAML.
|
|
181
384
|
|
|
182
385
|
$ moose-inventory host get host3 host1 --format yaml
|
|
183
386
|
---
|
|
@@ -200,7 +403,7 @@ Now we'll add some host variables. Again, we can add as many variables to a hos
|
|
|
200
403
|
- OK
|
|
201
404
|
- all OK
|
|
202
405
|
Succeeded.
|
|
203
|
-
|
|
406
|
+
|
|
204
407
|
$ moose-inventory host addvar host2 owner=caroline id=54321
|
|
205
408
|
Add variables 'owner=caroline,id=54321' to host 'host2':
|
|
206
409
|
- retrieve host 'host2'...
|
|
@@ -234,7 +437,13 @@ Let's list our hosts again, to see what that looks like.
|
|
|
234
437
|
|
|
235
438
|
As you can see, the hosts with variables each have a new section, hostvars, in which those variables are listed. Try also with *--format pjson*.
|
|
236
439
|
|
|
237
|
-
|
|
440
|
+
Host listing can also be filtered by group, metadata tag, and host variable. Multiple comma-separated values are treated as an AND filter: the host must match all requested groups, all requested tags, and all requested variable key/value pairs.
|
|
441
|
+
|
|
442
|
+
$ moose-inventory host list --group web --tag prod --var os=fedora --format yaml
|
|
443
|
+
|
|
444
|
+
Variable filters use `key=value` syntax. Metadata tags appear under a `tags` section when present; hosts without tags keep the older compact output. Group-side listing filters are still part of the remaining query/filter backlog, because one haunted query surface per slice is plenty.
|
|
445
|
+
|
|
446
|
+
We can do the same with groups. In the following example, the output has been omitted for compactness. Nevertheless, you will see that the form of the commands is as for hosts. Of note, when listing the groups, you will see that the *ungrouped* group is shown. This is an automatic group which cannot be manipulated manually.
|
|
238
447
|
|
|
239
448
|
$ moose-inventory group add group1 group2 group3
|
|
240
449
|
$ moose-inventory group list --format yaml
|
|
@@ -244,7 +453,7 @@ We can do the same with groups. In the following example, the output has been o
|
|
|
244
453
|
|
|
245
454
|
At this point, we have three hosts and three groups, some of each with variables. Let's now associate hosts with groups. We can either associate one or more hosts with a group,
|
|
246
455
|
|
|
247
|
-
$ moose-inventory group addhost group1 host1 host2
|
|
456
|
+
$ moose-inventory group addhost group1 host1 host2
|
|
248
457
|
Associate group 'group1' with host(s) 'host1,host2':
|
|
249
458
|
- retrieve group 'group1'...
|
|
250
459
|
- OK
|
|
@@ -261,7 +470,7 @@ At this point, we have three hosts and three groups, some of each with variables
|
|
|
261
470
|
|
|
262
471
|
or one or more groups with a host,
|
|
263
472
|
|
|
264
|
-
$ moose-inventory host addgroup host3 group2 group3
|
|
473
|
+
$ moose-inventory host addgroup host3 group2 group3
|
|
265
474
|
Associate host 'host3' with groups 'group2,group3':
|
|
266
475
|
- Retrieve host 'host3'...
|
|
267
476
|
- OK
|
|
@@ -312,6 +521,31 @@ We can also list hosts, to get the host-centric view.
|
|
|
312
521
|
- group2
|
|
313
522
|
- group3
|
|
314
523
|
|
|
524
|
+
### Read-only console
|
|
525
|
+
For human browsing, Moose Inventory includes a small read-only console. It is intentionally conservative: the first console slice lets operators inspect inventory state, tags, and recent audit events, but does not mutate records.
|
|
526
|
+
|
|
527
|
+
$ moose-inventory console
|
|
528
|
+
Moose Inventory console (read-only). Type help or quit.
|
|
529
|
+
|
|
530
|
+
Useful console commands include:
|
|
531
|
+
|
|
532
|
+
help
|
|
533
|
+
hosts
|
|
534
|
+
groups
|
|
535
|
+
host web01
|
|
536
|
+
group web
|
|
537
|
+
tags host web01
|
|
538
|
+
tags group web
|
|
539
|
+
audit 10
|
|
540
|
+
quit
|
|
541
|
+
|
|
542
|
+
Console parsing uses shell-style quoting for read-only lookups, so names containing spaces can be inspected without turning the prompt into confetti:
|
|
543
|
+
|
|
544
|
+
host "web 01"
|
|
545
|
+
tags group 'production web'
|
|
546
|
+
|
|
547
|
+
The console reports command-specific usage for extra arguments, invalid tag targets, invalid audit limits, and malformed quotes. Use the normal CLI commands for edits. Future interactive mutation can be added with confirmation, dry-run, and audit semantics instead of improvising a tiny foot-gun in a prompt loop.
|
|
548
|
+
|
|
315
549
|
Removing variables, groups, and hosts is just as easy. In the following examples, the output is again omitted for compactness; the reader is encouraged to work along to experience the tool. Note, that although we show how to remove the variables, it is not strictly necessary to do so in this example, since deleting hosts and groups would delete all associated variables anyway.
|
|
316
550
|
|
|
317
551
|
By default, deleting a group preserves its child groups as root groups. Use `group rm --recursive` when child groups that become orphaned should also be deleted. Similarly, `group rmchild --delete-orphans` removes a parent-child association and deletes the child subtree only when it becomes orphaned by that removal. Hosts whose last group is deleted are automatically moved to `ungrouped`.
|
|
@@ -324,12 +558,56 @@ By default, deleting a group preserves its child groups as root groups. Use `gro
|
|
|
324
558
|
$ moose-inventory host rmvar host1 owner id
|
|
325
559
|
$ moose-inventory host rm host1 host2 host3
|
|
326
560
|
|
|
561
|
+
### CI/CD integration examples
|
|
562
|
+
The `examples/ci/` directory contains a pull-request review pattern for inventory changes that does not require production database credentials. It imports a proposed snapshot into a temporary SQLite database, runs `doctor`, exports a canonical snapshot, lists hosts, and writes an Ansible-compatible inventory artifact.
|
|
563
|
+
|
|
564
|
+
Run the example locally with:
|
|
565
|
+
|
|
566
|
+
$ MOOSE_INVENTORY_CMD="bundle exec ruby -Ilib bin/moose-inventory" \
|
|
567
|
+
examples/ci/scripts/validate-inventory-snapshot.sh \
|
|
568
|
+
examples/ci/inventory/example-snapshot.yml \
|
|
569
|
+
tmp/inventory-ci-artifacts
|
|
570
|
+
|
|
571
|
+
The script writes:
|
|
572
|
+
|
|
573
|
+
tmp/inventory-ci-artifacts/doctor.txt
|
|
574
|
+
tmp/inventory-ci-artifacts/inventory.yml
|
|
575
|
+
tmp/inventory-ci-artifacts/hosts.json
|
|
576
|
+
tmp/inventory-ci-artifacts/ansible-inventory.json
|
|
577
|
+
|
|
578
|
+
`examples/ci/github-actions/inventory-review.yml` shows the same pattern as a GitHub Actions workflow. It is stored under `examples/` rather than `.github/workflows/` so teams can adapt paths, snapshot locations, artifact names, and deployment rules before enabling it. Use this as a review gate before applying inventory changes to a shared or production Moose Inventory database; CI should validate proposals, not casually scribble on prod like a bored intern.
|
|
579
|
+
|
|
327
580
|
### Using moose-inventory with Ansible
|
|
328
581
|
|
|
329
582
|
|
|
330
583
|
The *moose-inventory* tool is compliant with the Ansible specifications for [dynamic inventory sources](http://docs.ansible.com/developing_inventory.html).
|
|
331
584
|
|
|
332
|
-
|
|
585
|
+
The preferred modern integration is the example inventory plugin shipped in `examples/ansible/inventory_plugins/moose_inventory.py`. Copy or vendor that plugin into your Ansible project, then point `ansible.cfg` at the plugin directory and inventory source file:
|
|
586
|
+
|
|
587
|
+
```ini
|
|
588
|
+
[defaults]
|
|
589
|
+
inventory = inventory/moose_inventory.yml
|
|
590
|
+
inventory_plugins = inventory_plugins
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
The inventory source file is plain YAML:
|
|
594
|
+
|
|
595
|
+
```yaml
|
|
596
|
+
---
|
|
597
|
+
plugin: moose_inventory
|
|
598
|
+
executable: moose-inventory
|
|
599
|
+
config: ./example.conf
|
|
600
|
+
env: dev
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
With those files in place, Ansible can use Moose Inventory directly:
|
|
604
|
+
|
|
605
|
+
$ ansible-inventory -i inventory/moose_inventory.yml --list
|
|
606
|
+
$ ansible -i inventory/moose_inventory.yml -u ubuntu us-east-1d -m ping
|
|
607
|
+
|
|
608
|
+
The plugin calls `moose-inventory` for group and host data, preserving Moose Inventory's own configuration file and environment selection instead of hiding them in a shell wrapper. The shipped `examples/ansible/` directory contains a complete minimal `ansible.cfg`, inventory source, and plugin file.
|
|
609
|
+
|
|
610
|
+
A legacy external-inventory shim still works, and remains useful on older Ansible installs or when you want the simplest possible integration. To make use of *moose-inventory's* multiple environment and configuration file options with the shim approach, use a script as the target for the [external inventory script](http://docs.ansible.com/intro_dynamic_inventory.html). A trivial example may look something like the following.
|
|
333
611
|
|
|
334
612
|
```shell
|
|
335
613
|
#!/bin/bash
|
|
@@ -346,16 +624,16 @@ exit $?
|
|
|
346
624
|
|
|
347
625
|
$ ./shim.sh host add example
|
|
348
626
|
$ ./shim.sh host addvar example "my var"="hello world"
|
|
349
|
-
|
|
350
627
|
|
|
351
|
-
|
|
628
|
+
|
|
629
|
+
When Ansible calls the external inventory script, it passes certain parameters, which *moose-inventory* automatically recognises and responds to. The Ansible parameters, and their equivalent *moose-inventory* parameters are shown below.
|
|
352
630
|
|
|
353
631
|
Ansible | moose-inventory
|
|
354
632
|
---------------- |-------------
|
|
355
|
-
`--list` | `--ansible group list`
|
|
633
|
+
`--list` | `--ansible group list`
|
|
356
634
|
`--host HOSTNAME` | `--ansible host listvars HOSTNAME`
|
|
357
635
|
|
|
358
|
-
Note, the above conversions are performed automatically within *moose-inventory*.
|
|
636
|
+
Note, the above conversions are performed automatically within *moose-inventory*.
|
|
359
637
|
|
|
360
638
|
With *moose-inventory* installed and configured, and a shim script (e.g. *shim.sh*) in place, then integration with Ansible can be acheived via Ansible's `-i <file>` option.
|
|
361
639
|
|
|
@@ -364,18 +642,18 @@ With *moose-inventory* installed and configured, and a shim script (e.g. *shim.s
|
|
|
364
642
|
Alternatively, if using an [Ansible configuration file](http://docs.ansible.com/intro_configuration.html), then one may set the [inventory](http://docs.ansible.com/intro_configuration.html#inventory) option,
|
|
365
643
|
|
|
366
644
|
inventory = ./shim.sh
|
|
367
|
-
|
|
368
|
-
Yet another option is to copy the shim script to */etc/ansible/hosts* and `chmod +x` it. However, since this would essentially fix the config file and environment used, doing so would defeat the flexibility intended for *moose-inventory*.
|
|
645
|
+
|
|
646
|
+
Yet another option is to copy the shim script to */etc/ansible/hosts* and `chmod +x` it. However, since this would essentially fix the config file and environment used, doing so would defeat the flexibility intended for *moose-inventory*.
|
|
369
647
|
|
|
370
648
|
#### Writing to the dynamic inventory from Ansible
|
|
371
649
|
A useful aspect of dynamic inventories is the possibility of writing data to the inventory. To persist data from Ansible to the inventory, simply call the shim script via a local_action command, for example:
|
|
372
650
|
|
|
373
651
|
```shell
|
|
374
652
|
- set_fact: mydata="Hello world"
|
|
375
|
-
- local_action: command shim.sh host addvar {{ inventory_hostname }} mydata="{{ mydata }}"
|
|
653
|
+
- local_action: command shim.sh host addvar {{ inventory_hostname }} mydata="{{ mydata }}"
|
|
376
654
|
```
|
|
377
655
|
|
|
378
|
-
|
|
656
|
+
|
|
379
657
|
## Development checks
|
|
380
658
|
|
|
381
659
|
Run the local verification gate before committing changes:
|
|
@@ -384,7 +662,7 @@ Run the local verification gate before committing changes:
|
|
|
384
662
|
./scripts/check.sh
|
|
385
663
|
```
|
|
386
664
|
|
|
387
|
-
The check script runs the RSpec suite, enforces the SimpleCov coverage minimum, checks file permissions, queries OSV for locked RubyGems advisories, runs `bundler-audit`, runs `gitleaks` when available, and builds/smoke-tests the packaged gem.
|
|
665
|
+
The check script runs the RSpec suite, enforces the SimpleCov coverage minimum, checks file permissions, verifies generated/local artifact paths remain ignored and untracked, queries OSV for locked RubyGems advisories, runs `bundler-audit`, runs `gitleaks` when available, and builds/smoke-tests the packaged gem.
|
|
388
666
|
|
|
389
667
|
Optional Go-based security tools used by CI can be installed locally with:
|
|
390
668
|
|
|
@@ -402,8 +680,6 @@ That installs `gitleaks` and `osv-scanner` into `tmp/security-tools/bin` unless
|
|
|
402
680
|
5. Create a new Pull Request
|
|
403
681
|
|
|
404
682
|
|
|
405
|
-
|
|
406
|
-
|
|
407
683
|
|
|
408
684
|
|
|
409
685
|
|
data/Rakefile
CHANGED