Page MenuHomeVyOS Platform

cloud-init: add strict mode for vyos_config_commands
Open, Requires assessmentPublic

Description

Description

The vyos_userdata cloud-init module currently processes
vyos_config_commands as best effort. A command that does not match the
supported set or delete syntax is skipped. If a ConfigTree operation raises
an exception, the module logs the error and continues with later commands.
The resulting candidate is then written to config.boot.

This behavior is compatible with existing deployments, but it does not provide
a safe contract for automated router provisioning. A typo or one failed
operation can leave a valid-looking, partially generated boot configuration,
while cloud-init reports no module failure to the provisioning system.

Current Behavior

The behavior was reproduced against vyos/vyos-cloud-init rolling commit
83f45e337a4d9393c0baa4aca2b9ade5c05f9bbe.

The focused reproduction submitted four entries:

text
set system host-name 'edge-a'
show version
set system domain-name 'example.test'
set system time-zone 'UTC'

show version represented malformed input, and the ConfigTree test double
raised an error for the domain-name operation. The handler returned without an
exception and wrote both successful operations:

text
exception_propagated=None
commands_submitted=4
operations_persisted=2

BASELINE
set system host-name edge-a
set system time-zone UTC

The existing regression suite also defines malformed-command skipping as the
current behavior:

text
pytest -q tests/unittests/config/test_cc_vyos_userdata.py
9 passed

Proposed Configuration

Add an opt-in strict-mode flag under the existing VyOS cloud-init options:

yaml
#cloud-config
vyos_config_options:
  strict_config_commands: true

vyos_config_commands:
  - set system host-name 'edge-a'
  - set service ssh

When the flag is omitted or false, the module preserves the current
best-effort behavior. When it is true, every command must parse and apply
successfully before config.boot is replaced.

Proposed Behavior

With strict_config_commands: true:

  1. Parse the complete command list before applying any operation.
  2. Reject an unsupported or malformed command with its list index.
  3. Apply the parsed operations to the in-memory ConfigTree candidate.
  4. If any ConfigTree operation fails, raise a cloud-init module error and do not replace the existing config.boot.
  5. After every operation succeeds, replace config.boot atomically while preserving its existing mode when present.
  6. Keep new vyos_userdata logs and errors limited to command indices, actions, and exception types without logging command values.

The cloud-init module runner already records an exception from handle() as a
module failure, so strict-mode errors can be surfaced through the existing
cloud-init status and result files.

With the option omitted or set to false, malformed lines and individual
ConfigTree errors retain their current best-effort semantics for backward
compatibility.

Non-Goals

  • Full semantic verification by VyOS configuration-mode scripts.
  • Committing the candidate to the running configuration.
  • Removing the additional reboot currently used by some provisioning flows.
  • Expanding the supported command language beyond set and delete.
  • Auditing or changing user-data logging in other cloud-init modules.
  • Refactoring unrelated cloud-init modules.

Acceptance Criteria

  • Existing configurations without strict_config_commands retain their current behavior.
  • strict_config_commands: false explicitly selects the current behavior.
  • strict_config_commands: true rejects a malformed command and reports a module failure.
  • Strict mode propagates a ConfigTree application failure as a module failure.
  • A strict-mode failure leaves an existing config.boot byte-for-byte unchanged.
  • A successful command list atomically replaces config.boot.
  • Existing file mode is preserved when replacing config.boot.
  • Logs and exception messages emitted by vyos_userdata do not include command values.
  • Existing ordinary, multi-node, tag-node, value-delete, and path-delete tests continue to pass.
  • New unit tests cover both modes, parse failure, application failure, unchanged-state behavior, successful atomic replacement, and sanitized logging.
  • Behavior is validated on a current rolling image with both a successful and a deliberately rejected NoCloud payload before the implementation PR is opened.
  • The public cloud-init documentation describes the flag, default, failure semantics, and lack of full semantic verification.

Design Question

Is vyos_config_options.strict_config_commands acceptable as the public
interface for this opt-in behavior?

I can implement this in vyos-cloud-init if the proposed interface is
acceptable.

Related Work

  • T2116 introduced vyos_config_commands processing.
  • T9172 and vyos/vyos-cloud-init#116 added direct regression coverage for the existing command parser and ConfigTree operations.

Details

Version
Rolling
Is it a breaking change?
Perfectly compatible
Issue type
Feature (new functionality)

Event Timeline