OmniCube Reference Manualomnicube(7)

omnicube(7)

Standards, Environments, and Macros · OmniCube · August 10, 2026

NAME

omnicube - OmniCube clustered zone and VM management suite

DESCRIPTION

OmniCube is a set of shell tools, SMF services and cron jobs that turn a small number of illumos hosts into a cluster on which zones and virtual machines are created, snapshotted, replicated and moved between nodes. Every component is a script under /opt/omnicube that can be read and run by hand, and all cluster state lives in SMF properties, ZFS user properties and ZFS snapshots.

A cluster is the set of nodes named in the SMF property config/nodes of svc:/omnicube/sysadm. All of them run the same package and must reach each other over ssh(1) non-interactively (BatchMode=yes and StrictHostKeyChecking=yes are enforced, so host keys have to be pre-populated). There is no quorum, no leader election and no distributed lock manager: coordination is a per-node lock directory under /var/run/omnicube, the site:is_locked ZFS property on the pool being operated on, and the isolation marker described below.

Storage is per zone. Every node holds one large raw disk image per zone in its own pool, at /node/raw/zone/zone-disk0.raw where node is the short host name, and the zone's zpool is built from those images by create_zone_pool.sh(8): mirrored into a single pool (SYNC) or one independent pool per node (ASYNC). A peer's image is reached over NFSv4, mounted at the same path as on the owning node, or as an iSCSI LUN created by create_iscsi_lun.sh(8) and exported with stmfadm(8); init_backup_zfs.sh(8) prepares the shares an administration zone backs up to. A zone's data is therefore always on at least two nodes, and its pool can be imported on whichever node is to run it.

Four kinds of zone run on that storage: native illumos zones (lipkg and relatives), Linux-branded lx zones, and virtual machines under bhyve or kvm. manage_zone.sh(8) is the single entry point for all of them and dispatches on the brand it reads back from zonecfg(8); VM zones are configured from the templates in vm_tpl.cfg(5).

SYNC and ASYNC zones

A zone is SYNC or ASYNC according to the config/type property of its own SMF instance, svc:/service/omnicube/zone:zone. The distinction is about how the zone's data reaches the other nodes, and it decides which command moves the zone:

sync

The zone's zpool is a mirror whose halves live on different nodes, so the copies are always identical and only one node may import the pool at a time. The zone is relocated with manage_zone.sh -l, which stops it, exports the pool, recreates the SMF instance on the target node and imports it there: seconds of downtime and no data loss, at the cost of writing synchronously across the interconnect.

async

Each node has its own pool for the zone, kept up to date asynchronously by sync_pool.sh(8), which snapshots pool/zones/pool as @SYNCYYYYMMDDHHMMSS and sends the incremental stream to every peer, keeping at most MAX_SNAP=16 of its own snapshots. The peer copy therefore lags by up to one interval. An ASYNC zone is moved with manage_zone.sh -S, which sends it to a named host and parent dataset.

Independently of that, any dataset can be snapshotted on a schedule and replicated to an off-cluster backup host by autosnap(8), autocleansnap(8) and autosync(8), driven by the retention policies documented in default.conf(5).

Monitoring and isolation

The monitors run from cron(8) on every node and report through info(), warning() and error() in oc_log(3), which log to syslogd(8) under the tag sitescript and send throttled mail to the aliases oc-warn and oc-alert. pool_monitor.sh(8) watches zpool health and iSCSI sessions, reconnecting targets and re-attaching disabled bridge links; sys_monitor(8) watches pool capacity, orphaned site:is_locked properties and clock drift; zone_monitor.sh(8) boots zones that should be running; zones_srv_monitor.sh(8) clears failed services inside the zones; and monitor_nvme.sh(8) reports NVMe health.

When a node loses its peer's storage, repairing pools locally is worse than doing nothing — the node would resilver mirrors whose other half is merely unreachable. So pool_monitor.sh(8) calls isolate_node.sh(8), which creates the marker directory /var/run/omnicube/isolate_node.lock and offlines every non-local pool and LUN. Every monitor aborts while that marker exists, so an isolated node makes no further storage decisions. The marker records a mode: auto isolation is cleared automatically by isolate_node.sh reconcile once the peer answers on the iSCSI port again, while manual isolation, and any marker whose mode cannot be read, is cleared only by an explicit isolate_node.sh release.

Two guards apply to nearly every command. The run-level guard makes a script exit 0 silently at run level 0, 1, 5, 6, S or s, or when /etc/nologin exists, so no job can race a shutdown; OC_IGNORE_RUNLEVEL bypasses it. The lock guard gives each job an atomically created single-instance lock directory under /var/run/omnicube and an EXIT trap that releases it. See oc_runlevel(3) and oc_lock(3).

Directory layout

/opt/omnicube/sbin

Administrative commands, section 8. Zone and pool management, the monitors, the isolation tool and the restricted-shell helpers.

/opt/omnicube/bin

Commands intended for operators and for use inside zones, section 1.

/opt/omnicube/backup

The snapshot and replication jobs (autosnap, autocleansnap, autosync) and, in policies/, the packaged retention policies.

/opt/omnicube/lib/common/utils.sh

The shared shell library, sourced by nearly every script. It reads the SMF configuration, sets up logging, locking, validation and ssh, and defines PFEXEC and the run-level guard. Documented in omnicube_utils(3).

/opt/omnicube/share

Data files: the VM zone templates (vm_tpl.cfg(5)), a README with the reference crontab, and man/ with these manual pages.

/var/opt/omnicube/backup/policies

Site-local retention policies, which shadow the packaged ones.

/var/run/omnicube

Runtime state on tmpfs: job locks, the isolation marker, the mail-throttle markers and the sys_monitor(8) streak counters. Mode 1775, group config/lock_group, so root and RBAC operators can both create locks.

SMF configuration

Cluster-wide configuration lives in the config property group of svc:/omnicube/sysadm, by default the default instance. Several instances may coexist, each with its own config/site prefix, so one host can serve more than one site or backup destination; OC_SMF_INSTANCE and autosync -i select one, and autocleansnap(8) deliberately iterates over all of them. Read a property with svcprop(1), set one with svccfg(8) followed by svcadm refresh.

config/site

Prefix for every ZFS user property the suite reads or writes, and for the syslog tag. No default: it is mandatory, and a script whose instance does not define it exits 78 with PROPPREFIX not initialized.

config/nodes

Space-separated list of the full host names of the cluster nodes, used as ssh targets. Pool, dataset and raw-image paths are derived from the short name (everything before the first hyphen). Default: empty, which reduces every multi-node operation to a local one.

config/storage_nodes

The nodes that export iSCSI storage, when these are not the same as config/nodes. Read by pool_monitor.sh(8) only, to compute the expected session count. Default: unset, in which case config/nodes is used.

config/lock_group

Group that owns /var/run/omnicube and its subdirectories, which are created mode 1775 so that root jobs and pfexec operators can share them. Must match ^[a-zA-Z0-9_-]+$. Default sysadmin.

config/iscsi_num_sessions

Number of iSCSI sessions expected per storage node. pool_monitor.sh(8) multiplies it by the number of nodes and treats a smaller total as degraded (below half the expected total it escalates). Default 2.

config/mail_domain

Domain used in the envelope sender of alert mail, hostname@mail_domain. No default; without it mailx(1) is invoked with an incomplete sender and mail may be rejected.

config/mail_throttle_window

Seconds during which the same (severity, message) pair is mailed at most once. Markers live in a per-user 0700 directory under /var/run/omnicube/mail_throttle, so throttling is per uid and cannot be suppressed by another user. A non-numeric value is ignored. Default 3600.

config/monitor_pool_min_level

Capacity percentage below which sys_monitor(8) says nothing about a pool. A non-numeric value is ignored. Default 70. The warning and error thresholds above it, 80 and 90 percent, are not tunable.

config/monitor_exclude_pools

List of zpool names sys_monitor(8) skips entirely. Matched literally, not as patterns. Default: empty.

config/monitor_exclude_zones

List of zones whose failed services zones_srv_monitor.sh(8) must not clear — zones in maintenance, or zones that orchestrate their own restarts. Matched literally. Default: empty.

config/ntp_servers

Servers sys_monitor(8) queries with ntpdate -bsq. Default: unset, in which case the default route's gateway is queried.

config/vnc_bind

Address activate_zone_vnc.sh(1) binds the VNC relay to. Unset or * means all interfaces, which is logged as a warning because the relay carries no RFB authentication; a value that is not a bare address or host name is a fatal error. Recommended 127.0.0.1, with access through an ssh tunnel. Default: unset.

config/vnc_tls

Boolean. When true, activate_zone_vnc.sh(1) starts the VNC relay as a socat OPENSSL-LISTEN listener instead of a plain TCP-LISTEN, presenting the node's server certificate. Overridden per run by the -s and -S options. Default: unset, i.e. false.

config/vnc_cert

Path to the server certificate used when config/vnc_tls is on, together with config/vnc_key when the private key lives in a separate file. Default: unset, in which case /etc/opt/omnicube/certs/server.pem is used if present, otherwise server.crt plus server.key in the same directory.

config/vnc_cafile

Path to the CA certificate that client certificates are verified against. When set, the relay listens with verify=1, so only clients presenting a certificate signed by that CA are accepted; when unset the relay uses verify=0, which encrypts the session without authenticating the peer and is logged as a warning. Default: unset.

config/vnc_verify_client

Boolean. When true, mutual TLS is node policy: activate_zone_vnc.sh(1) refuses -S, treats config/vnc_tls as true regardless of its value, and exits 1 without starting a relay if config/vnc_cafile is unset or names a missing file. Default: unset, i.e. false.

config/vnc_log_level

How much activate_zone_vnc.sh(1) asks socat to log to <zonepath>/log/vnc.log: error (no -d), warning (-d, the shipped default), notice (-d -d, one block per accepted connection: source address, peer certificate check, TLS version), info or debug. (warn is accepted as a synonym for warning.) Any other value is fatal. Default: warning, from the manifest.

config/vnc_tls_opts

Extra socat OPENSSL address options, appended verbatim to the listen address and constrained to ^[a-zA-Z0-9._,=:+!@-]+$. Empty by default because the option spellings are release-dependent - openssl-min-proto-version= exists only from socat 1.7.4 and an unknown option is fatal. Default: unset.

Each managed zone additionally has its own instance, svc:/service/omnicube/zone:zone, with three properties: config/type (sync or async, see above), config/adm_status (started or stopped, the administrative intent that zone_monitor.sh(8) enforces and that manage_zone.sh(8) sets with -b and -s) and config/zpools (the list of zpools belonging to the zone, locked and handed over as a unit by a relocation). A zone with no SMF instance is an ASYNC zone managed entirely by hand; zone_monitor.sh(8) then falls back to the zone's autoboot property.

Command index

Zone and VM lifecycle:

manage_zone.sh(8) — start, stop, relocate, send, resize and reconfigure any zone.
create_zone_pool.sh(8) — create the zpool and datasets of a new SYNC or ASYNC zone.
create_zone_config.sh(8) — create a zpool over an existing raw image and its zone datasets.
zone_save.sh(8) — export every local zone's configuration next to its zonepath.
get_vm_disk_info.sh(8) — report record size and virtual and actual size of a VM disk image.
activate_zone_vnc.sh(1) — attach a VNC console to a bhyve or kvm zone.
generate_mac_address_vm(1) — generate a MAC address inside the site's IEEE MA-M block.

Storage:

create_iscsi_lun.sh(8) — create a zone's raw LUN, its slog LUN and the STMF views.
init_backup_zfs.sh(8) — prepare and share the datasets an administration zone backs up to.
sync_pool.sh(8) — snapshot and send ASYNC zone pools to the peer nodes.

Snapshots and off-cluster replication:

autosnap(8) — create the scheduled snapshots a policy asks for.
autocleansnap(8) — enforce retention locally and on the backup host.
autosync(8) — replicate snapshots to the backup host.

Monitoring and isolation:

pool_monitor.sh(8) — repair degraded pools, iSCSI sessions and bridge links.
sys_monitor(8) — pool capacity, orphaned locks and time synchronisation.
zone_monitor.sh(8) — boot zones that should be running.
zones_srv_monitor.sh(8) — clear failed services inside the zones.
monitor_nvme.sh(8) — report NVMe device health.
isolate_node.sh(8) — enter, reconcile, release and report isolation mode.
logadm(8) — rotate the suite's logs from cron.

Guest control and console access:

shutdown_windows_server(8), restart_windows_server(8) — drive a Windows guest's SAC console.
qemu-monitor-command(8) — talk to a kvm guest's monitor and guest agent.
restrict-shell(8), restrict-shell-cmd(8) — give a user the console of the one zone named after their login.
sshpass(1) — supply a password to ssh non-interactively.

Library and file formats:

omnicube_utils(3) — the shared library as a whole, and oc_log(3), oc_lock(3), oc_runlevel(3), oc_validate(3), oc_ssh(3), oc_policy(3) for its individual groups of functions.
vm_tpl.cfg(5) — the kvm and bhyve zone templates.
default.conf(5) — the snapshot retention policies.

ZFS properties

State that must travel with the data is kept in ZFS user properties prefixed with config/site. With config/site set to efit they are, on datasets, efit:snapshotting and efit:remotebackup (opt in to snapshotting and to replication), efit:snappolicy (the policy name) and efit:is_locked (pool busy, skip it), and on snapshots efit:insync and efit:bckcandel (replication progress, which is what stops autocleansnap(8) destroying a snapshot another job still needs). See autosnap(8), autosync(8), autocleansnap(8) and default.conf(5).

Viewing these manual pages

The pages are installed in /opt/omnicube/share/man, which is not on the default man(1) search path. Either name the tree explicitly:

man -M /opt/omnicube/share/man manage_zone.sh

or add it to MANPATH once, for instance in /etc/profile:

MANPATH=/opt/omnicube/share/man:$(manpath 2>/dev/null)
export MANPATH
man 5 default.conf

Page names are the command file names, including the .sh suffix where the script has one, so the page for /opt/omnicube/sbin/manage_zone.sh is manage_zone.sh(8); there is no manage_zone page.

ENVIRONMENT

OC_SMF_INSTANCE

Name of the svc:/omnicube/sysadm instance to read the configuration from. It must be set before utils.sh is sourced, since the instance name is baked into the property prefix, the syslog tag and the lock paths at that point. autosync(8) and manage_zone.sh(8) accept -i NAME instead, which overrides the variable. Unset means the default instance.

OC_IGNORE_RUNLEVEL

When non-empty, bypass the run-level guard so a command can be run deliberately from single-user mode or during a shutdown. For interactive maintenance only: cron and SMF invocations never set it, so automated jobs still stand down. Every command honours it, including those that implement the guard standalone rather than through utils.sh.

FILES

/opt/omnicube

Install root; see Directory layout above.

/opt/omnicube/share/README

Reference crontab and the recipe for adding a zone's SMF instance.

/opt/omnicube/share/man

The manual pages of the suite.

/opt/omnicube/backup/policies/default.conf

Packaged snapshot retention policy; default.conf(5).

/opt/omnicube/share/vm_tpl.cfg

VM zone template, a link to the kvm or bhyve variant; vm_tpl.cfg(5).

/var/run/omnicube

Lock directories, the isolation marker, mail-throttle markers and monitor counters.

/etc/security/exec_attr.d/omnicube

The commands the profiles grant, and the uid or euid each is granted with.

/etc/security/prof_attr.d/omnicube

The two RBAC profiles themselves.

/etc/logadm.d/omnicube.conf

Rotation of the logs below: eight generations, weekly or at 10 MB, mode 640, group sys, followed by a restart of rsyslogd(8).

/etc/rsyslog.d/omnicube.conf

Routes auth and authpriv to /var/log/auth.log and everything else to /var/log/misc.log, where the suite's own log lines land.

SECURITY

Nothing in the suite is installed setuid. Privileged operations go through pfexec(1) and the two RBAC profiles in /etc/security/prof_attr.d/omnicube, assigned with usermod -P. Note that on illumos that option replaces the profiles= list in user_attr(5); there is no + modifier (that is a Solaris 11 extension), so to add a profile to an account that already has one, read the current list back from /etc/user_attr and pass all of them in a single comma-separated argument. Profiles handed out system-wide through PROFS_GRANTED in policy.conf(5) do not live in user_attr and are unaffected. Check the result with profiles -l.

The two profiles are:

OmniCube Administration

The operator profile. It grants the solaris.smf.manage and solaris.smf.modify authorisations, plus uid=0 execution of:

zfs zpool zoneadm zonecfg zlogin svcadm svccfg stmfadm iscsiadm
nvmeadm dladm logadm mount format truncate tee mkdir cp rmdir kill
gsed socat expect sqlite3 qemu-img

It is root-equivalent and is documented as such: several of those commands reach a root shell through a documented feature (format's !, sqlite3's .shell, expect's exec, socat's EXEC:, GNU sed's s///e) and tee, cp, truncate and mkdir give arbitrary root-owned writes. The profile buys auditing, not containment; grant it only to accounts you would trust with the root password.

OmniCube Restricted Shell

The profile for zone console users. It grants exactly one command, restrict-shell-cmd(8), and with euid=0 rather than uid=0 so the real uid still identifies the caller. That helper lets a user open, or hang up, only the console of the zone whose name equals their login name.

pfexec matches exec_attr(5) entries on the resolved path of the binary, which is why the scripts export an explicit PATH and why relocating a tool means editing both the script and /etc/security/exec_attr.d/omnicube. In the scripts the prefix is ${PFEXEC}, which utils.sh sets to pfexec for an unprivileged caller and to the empty string when the effective uid is already 0; it must always be used unquoted.

Zone, node, user, host and dataset names are validated with validate_name and validate_dataset before they reach a command line; see oc_validate(3). Policy files and zone templates, by contrast, are sourced or applied as code, so their ownership and mode are the only boundary: both must be root-owned and not group or world writable.

SEE ALSO

The Command index above lists every page in the suite. The starting points are omnicube_utils(3), default.conf(5), vm_tpl.cfg(5), autosnap(8), autosync(8), autocleansnap(8), isolate_node.sh(8), manage_zone.sh(8), pool_monitor.sh(8), sys_monitor(8).

NOTES

The snapshot, replication and save jobs are driven from cron(8), not from SMF. The reference crontab shipped in /opt/omnicube/share/README is:

6  * * * * /opt/omnicube/backup/autosnap >/dev/null
26,46  * * * * /opt/omnicube/backup/autosync >/dev/null
20 3 * * * /opt/omnicube/sbin/zone_save.sh
36 * * * * /opt/omnicube/backup/autocleansnap >/dev/null

Registering a zone with the suite means creating its SMF instance; the README gives the sequence:

ZONE=myzone
svccfg -s svc:/service/omnicube/zone add ${ZONE}
SMF=svc:/service/omnicube/zone:${ZONE}
svccfg -s ${SMF} addpg config application
svccfg -s ${SMF} setprop config/type = astring: sync
svccfg -s ${SMF} setprop config/adm_status = astring: started
svcadm refresh ${SMF}
svcadm enable ${SMF}

Several operations are cluster-wide and have no automatic rollback: a relocation stops the zone, exports its pool and rebuilds it on the target, and a target that becomes unreachable half way through leaves the zone unconfigured, to be recovered by hand. This is why the entry points pre-flight ssh to every peer before changing anything, and why config/nodes must not name a decommissioned node.

Changing a zone's configuration on one node only is a latent failure: the peer copies still carry the old configuration and a relocation will silently revert the change. Follow every configuration change with manage_zone.sh -z zone -r.

A stuck site:is_locked property wedges every snapshot and replication job for the dataset it is set on, because those jobs skip a locked pool by design. The jobs release it from an EXIT trap, but a SIGKILL or a pool exported mid-relocation can leave it behind; sys_monitor(8) reports it after three consecutive observations, and it is cleared with zfs inherit -r site:is_locked pool.

The cluster nodes are illumos systems running the same package. Only the backup host of a replication policy may be Linux, which is why that one path avoids pfexec, ggrep and bash built-ins on the remote side.

man7/omnicube.7generated 2026-09-02 05:17 CEST