Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Added

- **Work orders can be made, changed and deleted:** `workorder.show`, `workorder.create`, `workorder.set` and
`workorder.delete`, light writes, audited. A new work order is `pending` and done once unless told otherwise;
`--due now` sets the do-it-now flag and no due date; times are taken as generalized time or ISO 8601; the repeat
interval is in minutes; a status a person sets is `pending` or `onhold`.
- **`template.list` and `template.show`:** the notification templates the vault holds now, read-only: subject, body,
`$TOKEN$` markers, and whether DirXMLDev can read the body.
- `Operate.Engine` has `add` and `delete` (default: refused), implemented for a vault.

### Fixed

- **`workorder.list` finds work orders where the Work Order driver keeps them.** It searched under the driver set,
but work orders live in the container the `idv.workorder.container` GCV names (a slash DN, now resolved a level at a
time, from the driver's own values, the GCV objects linked to it as NOVLWOBASE installs them, or the set's), or the Work
Order driver object, NetIQ's suggestion. `--base` still overrides.
- A body or document that does not parse no longer prints `[Fatal Error]` to stderr; the failure is still reported
to the caller.

## [0.65.0] - 2026-11-03

### Fixed
Expand Down
131 changes: 129 additions & 2 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2006,7 +2006,7 @@ More: [console-gaps.md](console-gaps.md#13-as-built-l1-the-low-set).

### `workorder.list`

The Work Order driver's `DirXML-WorkOrder` objects: status, due date, description, newest due date first. Read-only.
The Work Order driver's `DirXML-WorkOrder` objects: status, due date ("now" when it is to be done at once), description, newest due date first. Read-only. Without `--base`, the container each Work Order driver uses: the `idv.workorder.container` GCV (the driver's own, a GCV object linked to it as NOVLWOBASE installs it, or the set's; a slash DN, found a level at a time), else the Work Order driver object itself, NetIQ's suggested container; with no Work Order driver, the driver set.

```
bin/idm workorder.list --env <name> [--base <dn>] [--limit <n>] [--json]
Expand All @@ -2015,7 +2015,7 @@ bin/idm workorder.list --env <name> [--base <dn>] [--limit <n>] [--json]
| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--base` | no | the search base; default: the driver set |
| `--base` | no | the search base; default: the Work Order container (above) |
| `--limit` | no | the most objects listed; default: 200 |
| `--json` | no | the result as JSON |

Expand All @@ -2025,6 +2025,133 @@ bin/idm workorder.list --env test

More: [console-gaps.md](console-gaps.md#13-as-built-l1-the-low-set).

### `workorder.show`

One work order: every field, whether it is to be done now, and the driver's processing log. Read-only.

```
bin/idm workorder.show --env <name> --dn <work order> [--json]
```

| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--dn` | yes | the work order |
| `--json` | no | the result as JSON |

```bash
bin/idm workorder.show --env test --dn "cn=New hire jdoe,cn=Work Orders,cn=driverset1,o=system"
```

### `workorder.create`

A new work order in the Work Order container (or `--container`), `pending` and done once unless the options say otherwise, as Identity Console makes one. Writes to the vault, as `vault.email-server set` does: `--confirm <env>` or `IDM_AGENT_ALLOW_WRITE=1`, `--yes` on a `stg` or `prd` tier, `--confirm <env>` on a `prd` tier. Audited.

```
bin/idm workorder.create --env <name> --name <name> [--container <dn>] [fields] [--yes] [--confirm <env>] [--json]
```

| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--name` | yes | the work order's name |
| `--container` | no | where it goes; default: the Work Order container, refused when there are several |
| `--status` | no | `pending` (a new one's default) or `onhold`; the driver sets `configured` or `error` |
| `--due` | no | when it is done: `now` (the do-it-now flag, no due date), or a time as `20261231235900Z`, `2026-12-31T23:59:00Z` or `2026-12-31` |
| `--repeat-minutes` | no | repeat it every this many minutes; `0`, a new one's default, for once |
| `--delete-date` | no | when the driver deletes it, a time as for `--due` |
| `--delete-on-error` | no | `true` to delete it on the delete date even after an error |
| `--dependent` | no | a work order it waits for; repeat for several |
| `--type`, `--number`, `--contact`, `--description` | no | the work order's type (passed to the WorkToDo object), number, contact and description |
| `--content`, `--content-file` | no | what the work order does, as text or from a file |

```bash
bin/idm workorder.create --env test --name "New hire jdoe" --due 2026-12-01T08:00:00Z --content-file jdoe.xml --confirm test
```

The Work Order driver polls its container and runs a work order when it is due: it adds a `DirXML-WorkToDo` object with
the content, description, type and the work order's DN (NOVLWOBASE names it `DO-<work order>`, in the same container),
then sets the status to `configured` (or `error`), adds a line to the log and writes the time it ran as the due date. One
that repeats gets its next due date and stays `pending`. Under NOVLWOBASE a work order runs again only once whatever
consumes its WorkToDo has removed it; until then the add fails (-606) and the status becomes `error`.

### `workorder.set`

A work order's fields changed; an empty value (`--description=`) clears one. Takes the fields of `workorder.create`. Writes to the vault, gated as `workorder.create`. Audited.

```
bin/idm workorder.set --env <name> --dn <work order> [fields] [--yes] [--confirm <env>] [--json]
```

| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--dn` | yes | the work order |
| `--status` | no | `pending` (a new one's default) or `onhold`; the driver sets `configured` or `error` |
| `--due` | no | when it is done: `now` (the do-it-now flag, no due date), or a time as `20261231235900Z`, `2026-12-31T23:59:00Z` or `2026-12-31` |
| `--repeat-minutes` | no | repeat it every this many minutes; `0`, a new one's default, for once |
| `--delete-date` | no | when the driver deletes it, a time as for `--due` |
| `--delete-on-error` | no | `true` to delete it on the delete date even after an error |
| `--dependent` | no | a work order it waits for; repeat for several |
| `--type`, `--number`, `--contact`, `--description` | no | the work order's type (passed to the WorkToDo object), number, contact and description |
| `--content`, `--content-file` | no | what the work order does, as text or from a file |

```bash
bin/idm workorder.set --env test --dn "cn=New hire jdoe,cn=Work Orders,cn=driverset1,o=system" --status onhold --confirm test
```

### `workorder.delete`

A work order deleted. Writes to the vault, gated as `workorder.create`. Audited.

```
bin/idm workorder.delete --env <name> --dn <work order> [--yes] [--confirm <env>] [--json]
```

| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--dn` | yes | the work order |

```bash
bin/idm workorder.delete --env test --dn "cn=New hire jdoe,cn=Work Orders,cn=driverset1,o=system" --confirm test
```

### `template.list`

The notification templates the vault holds now (`notfMergeTemplate` in the collection under `cn=Security`): name, subject, and whether a package installed it. Read-only: templates are tree content (`templates/`), changed by `vault.deploy`.

```
bin/idm template.list --env <name> [--json]
```

| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--json` | no | the result as JSON |

```bash
bin/idm template.list --env test
```

### `template.show`

One template as the vault holds it: the subject, the body, the `$TOKEN$` markers the two use, and whether the body is XML DirXMLDev can read (one it cannot would be read as no body, and a deploy would not keep it). Read-only.

```
bin/idm template.show --env <name> --name <template> [--json]
```

| Argument | Required | Values |
|---|---|---|
| `--env` | yes | an environment in `environments.properties` |
| `--name` | yes | the template's name |
| `--json` | no | the result as JSON |

```bash
bin/idm template.show --env test --name "Password Expiration Notification"
```

### `vault.email-server`

The notification collection's SMTP settings; the password is reported as set or not, never shown. `set` writes the settings given (an empty value, `--host=` or `--host ""`, clears that setting) and the password from the environment's secrets file (`--password-key`) or one line on stdin (`--stdin`). Show is read-only. `set` writes to the vault: needs `--confirm <env>` or `IDM_AGENT_ALLOW_WRITE=1`, `--yes` on a `stg` or `prd` tier, and `--confirm <env>` on a `prd` tier. Audited.
Expand Down
20 changes: 19 additions & 1 deletion docs/console-gaps.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,4 +332,22 @@ projects with policies, read locally only; lab projects with templates):
date and description. Listed, not modelled: they are the Work Order driver's runtime records, not
configuration, so the note's "tree objects" idea was dropped. **Excluded objects**: this schema has no
attribute for them and the console's route could not be grounded on a lab object; left out.

**Written too (2026-11-02):** `workorder.show`, `workorder.create`, `workorder.set`, `workorder.delete`. Grounded on the
class's schema (status, repeat interval and count, number, contact and type are strings; the due, delete and creation
dates generalized time; do it now, delete on error and send to publisher booleans; dependents DNs), Identity
Console 26.1.2's work order page (a new one is `pending` with repeat interval `0`; the interval is in minutes; "do it
now" is the flag with no due date; a person sets `pending` or `onhold`) and NOVLWOBASE 2.1.1 (the container is the
set GCV `idv.workorder.container`, `type="dn" dn-space="dirxml" dn-type="slash"`, which the driver's placement
policy joins with `\` and the name; NetIQ suggests the driver object itself). `workorder.list` now looks there by
default: under the driver set it found none where the container was elsewhere. `template.list` and `template.show`
read the live templates; the canonical form a deploy writes was checked against a lab's 351 templates: every body
parses, and only whitespace between elements changes, never the text inside one.
**Shown live (idm-ig4, 2026-11-02),** with a Work Order driver built like Designer's WorkOrder configuration and
NOVLWOBASE 2.1.1: `workorder.list` found the container from the driver's slash GCV, the value the shim read too. The
filter ignores `DirXML-WorkOrder` on the subscriber channel (so the package's create policy, which names
`DirXML-nwoType`, not in the schema, never applies); the shim polls the container on the publisher channel. A work
order made by `workorder.create --due now` ran on the first poll: a `DirXML-WorkToDo` `DO-<name>` in the container with
its content, description, type and DN, then status `configured`, a log line, and the processing time as due date (the
do-it-now flag stays). Run again by `workorder.set`, it failed with -606: the WorkToDo of the last run was still there,
and the driver set `error`. With that removed, `--repeat-minutes 1` moved the due date on by a minute and kept it
`pending`. `workorder.show` and `workorder.delete` worked as documented.
4 changes: 3 additions & 1 deletion docs/operate.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ Remote Loader lifecycle (the RL process is outside the vault), `--delete-driver`
| `driverset.servers [add\|remove]` | `DirXML-ServerList` on the set and, through `GetDriverSet`, the driver set the connected server reports running; `add`/`remove --server DN` go to that server (its URL from the environment's `servers=` mapping) and call `SetDriverSet` / `ClearDriverSet` | show is read-only; add/remove are heavy writes, audited, refused when the server runs another set; never clear a set's only server |
| `engine.metrics` | the console's user and driver metrics: users, users with an association, of those the enabled ones (the licensing count, `(&(objectClass=User)(DirXML-Associations=*)(!(loginDisabled=true)))`), and each driver's associations by state — counts only, nothing read beyond the DNs; `--base` narrows the search | read-only; `getUserDriverMetrics`, `computeDriverDistribution` |
| `driver.rights` | eDirectory's effective privileges of the driver object (the identity the engine's policies act as, through its security equivalences) on an object: `[Entry Rights]`, `[All Attributes Rights]` and the attributes named (LDAP names) | read-only; the console's `privileges` |
| `workorder.list` | the Work Order driver's `DirXML-WorkOrder` objects under a base (the driver set by default): status, due date, description, the content in the JSON | read-only; runtime data, so listed rather than modelled in the tree |
| `workorder.list` / `workorder.show` | the Work Order driver's `DirXML-WorkOrder` objects in its container (the `idv.workorder.container` GCV, a slash DN resolved a level at a time; else the driver object; or `--base`): status, due date or "now", every field and the driver's log | read-only; runtime data, so listed rather than modelled in the tree |
| `workorder.create` / `workorder.set` / `workorder.delete` | a work order made (`pending`, repeat 0, as Identity Console makes one), changed (an empty value clears a field; `--due now` is the do-it-now flag and no due date) or deleted | light write, audited; the fields are checked: a status a person sets (`pending`, `onhold`), generalized times, whole minutes, dependents that exist |
| `template.list` / `template.show` | the notification templates the vault holds now: name, subject, package; one's body, `$TOKEN$` markers, and whether DirXMLDev can read the body | read-only; templates are tree content, changed by `vault.deploy` |
| `vault.email-server [set]` | the notification collection's SMTP settings (`notfSMTPEmailHost`, `notfSMTPPort`, `notfSMTPEmailFrom`, `notfSMTPEmailUserName`, `notfSMTPUseTLS`, `notfSMTPTimeout`, `notfSMTPMailProtocol`, `notfSMTPAuthMechanisms`); the password (`notfSMTPMailPassword`) is reported as set or not, never shown, and written from the secrets file (`--password-key`) or stdin | show is read-only; set is a light write, audited; the console's `emailServerOptions` (its test send has no engine operation behind it and is not offered) |
| `driver.migrate --direction vault` | the console's `migrateFromNDS`: an LDAP search (`--base`, `--filter`, `--class`, `--max`) finds the vault objects, then each goes down the running driver's subscriber channel as a `<sync class-name src-dn>` command, which makes the engine read the object and send its add or modify to the shim; `--dry-run` lists them | heavy write, audited; `--direction app` (the default with `--xds`) is the old `MigrateApp` |
| `driver.log-level [set]` | Designer's log level page: `DirXML-DriverTraceLevel` holds the choice (0 errors, 1 errors and warnings, 2 last log time only, 3 off, 5 specific events), `DirXML-LogEvents` the event ids the engine logs (set through `SetLogEvents`, since the attribute is engine-written: 0 → 4 5 38, 1 → 3 4 5 35 38 39, 2 → -1, 3 cleared), `DirXML-LogLimit` the most entries kept, `DirXML-LogEventsType`; a driver without its own values uses the driver set's, `--inherit` puts a driver back to that | show is read-only; set is a light write, audited; the console's `logLevelPage` |
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/pointblue/dirxml/dev/Cli.java
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public static void main(String[] args) {
if (args.length >= 1 && args[0].startsWith("viewer.")) {
System.exit(com.pointblue.dirxml.dev.operate.ViewerCli.run(args));
}
if (args.length >= 1 && (args[0].startsWith("driver.") || args[0].startsWith("driverset.") || args[0].startsWith("engine.") || args[0].startsWith("job.") || args[0].startsWith("rbe.") || args[0].startsWith("workorder.") || args[0].equals("object.inspect") || args[0].equals("vault.email-server") || args[0].equals("trace.view"))) {
if (args.length >= 1 && (args[0].startsWith("driver.") || args[0].startsWith("driverset.") || args[0].startsWith("engine.") || args[0].startsWith("job.") || args[0].startsWith("rbe.") || args[0].startsWith("workorder.") || args[0].startsWith("template.") || args[0].equals("object.inspect") || args[0].equals("vault.email-server") || args[0].equals("trace.view"))) {
System.exit(com.pointblue.dirxml.dev.operate.OperateCli.run(args));
}
if (args.length >= 1 && com.pointblue.dirxml.dev.promote.PromoteCli.handles(args[0])) {
Expand Down Expand Up @@ -636,6 +636,8 @@ static String usageText() {
sb.append(" driver.health [clear] --env E --driver D [--yes] the Driver Health job's last state per server, the health configuration, the set's health jobs; clear removes the recorded status\n");
sb.append(" job.list --env E [--driver D] | job.status --env E --job J [--driver D] | job.start|abort --env E --job J [--driver D] [--yes] the set's jobs with the engine's state; start or abort one\n");
sb.append(" driverset.activation --env E [apply --file F --yes] | driverset.servers --env E [add|remove --server DN --yes] | engine.metrics --env E | driver.rights --env E --driver D --dn O | workorder.list --env E the low console gaps (docs/console-gaps.md §13)\n");
sb.append(" workorder.show --env E --dn DN | workorder.create --env E --name N [fields] | workorder.set --env E --dn DN [fields] | workorder.delete --env E --dn DN work orders (docs/commands.md)\n");
sb.append(" template.list --env E | template.show --env E --name N the notification templates the vault holds now, read-only\n");
sb.append(" vault.email-server [set] --env E [--host H] [--port N] [--from A] [--user U] [--tls true|false] [--timeout N] [--protocol P] [--auth M] [--password-key K|--stdin] the notification collection's SMTP settings (the password never shown); set writes them\n");
sb.append(" rbe.list --env E | rbe.members --env E --policy P the entitlement policies of the set: priority, members, grants; one policy's computed members\n");
sb.append(" engine.version --env E\n");
Expand Down
Loading
Loading