Environment Management¶
openvox-code supports two modes for managing Puppet environments: static (explicitly declared) and dynamic (branch-discovered). Both can be used together.
Dynamic Environments¶
Dynamic environments are discovered automatically from Git branches in your control repository. Each branch becomes a Puppet environment.
Branch Selection¶
Branch discovery is controlled by the branchSelector field on each source. It supports glob patterns for flexible matching.
All branches (empty matchPatterns matches everything):
apiVersion: openvox.voxpupuli.org/v1alpha1
kind: CodeConfig
spec:
cachedir: /var/cache/openvox-code
environmentdir: /etc/puppetlabs/code/environments
sources:
- url: https://github.com/example/control-repo.git
branchSelector: {}
Specific branches (exact names, no discovery needed):
sources:
- url: https://github.com/example/control-repo.git
branchSelector:
matchPatterns:
- production
- staging
- development
Glob patterns (branches are discovered and filtered):
sources:
- url: https://github.com/example/control-repo.git
branchSelector:
matchPatterns:
- production
- staging
- "feature_*"
excludePatterns:
- "feature_wip_*"
- "feature_test_*"
The matchPatterns field accepts Go's filepath.Match glob syntax:
| Pattern | Matches |
|---|---|
* |
Any sequence of non-separator characters |
? |
Any single non-separator character |
[abc] |
Character class |
production |
Exact match |
When matchPatterns is empty, all branches are included. The excludePatterns field is always applied after matching -- a branch matching any exclude pattern is skipped even if it also matches an include pattern.
Branch names are sanitized for use as directory names (e.g., feature/login becomes feature_login).
Module Files in Dynamic Environments¶
Each branch can include YAML module files that list the modules for that environment. Module files are specified as an array of {name, required} objects, where name supports glob patterns:
sources:
- url: https://github.com/example/control-repo.git
branchSelector: {}
modulefiles:
- name: modules.yaml
required: true
- name: "modules.d/*.yaml"
required: false
The module files live inside the control repo and are read per-branch after the control repo is checked out. They support both a Kubernetes-style envelope and a flat format:
Kubernetes-style module file:
apiVersion: openvox.voxpupuli.org/v1alpha1
kind: ModuleFile
spec:
modules:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
- name: apache
git: https://github.com/puppetlabs/puppetlabs-apache.git
ref: v12.0.0
exclude:
- obsolete_module
Flat module file:
modules:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
- name: apache
git: https://github.com/puppetlabs/puppetlabs-apache.git
ref: v12.0.0
exclude:
- obsolete_module
The exclude field allows a branch to remove modules that would otherwise be inherited from source-level modulesets or modules.
Source-Level Modules¶
Sources can define modules and module sets that apply to all discovered branches. This avoids duplicating common module definitions in every branch's module file:
apiVersion: openvox.voxpupuli.org/v1alpha1
kind: CodeConfig
spec:
cachedir: /var/cache/openvox-code
environmentdir: /etc/puppetlabs/code/environments
modulesets:
base:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
sources:
- url: https://github.com/example/control-repo.git
branchSelector: {}
modulesets:
- base
modules:
- name: myapp
git: https://github.com/example/puppet-myapp.git
follow_branch: true
Source-level modulesets and modules are combined with per-branch module file modules. Per-branch module file definitions take precedence on name conflicts.
Follow Branch¶
The follow_branch field on a module tells openvox-code to first try the branch matching the environment name. If that branch does not exist in the module repository, it falls back to the ref field (or HEAD if ref is empty):
modules:
- name: myapp
git: https://github.com/example/puppet-myapp.git
follow_branch: true
ref: main # fallback if the environment branch doesn't exist
This is useful for modules where developers work on feature branches that match the control repo branch names.
Static Environments¶
Static environments are explicitly declared in the configuration file. They give you full control over the ref and module list for each environment.
apiVersion: openvox.voxpupuli.org/v1alpha1
kind: CodeConfig
spec:
cachedir: /var/cache/openvox-code
environmentdir: /etc/puppetlabs/code/environments
environments:
production:
ref: v1.5.0
modulesets:
- common
modules:
- name: myapp
git: https://github.com/example/puppet-myapp.git
ref: v2.1.0
staging:
ref: staging
modulesets:
- common
modules:
- name: myapp
git: https://github.com/example/puppet-myapp.git
ref: main
Static environments are useful when you want to:
- Pin an environment to a specific tag or SHA rather than a branch tip
- Use different module versions per environment
- Mix module sets with per-environment module overrides
Module Sets¶
Module sets let you define reusable groups of modules that can be shared across environments and sources:
modulesets:
common:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
- name: concat
git: https://github.com/puppetlabs/puppetlabs-concat.git
ref: v9.0.0
monitoring:
- name: prometheus
git: https://github.com/example/puppet-prometheus.git
ref: v1.2.0
- name: grafana
git: https://github.com/example/puppet-grafana.git
ref: v3.0.0
environments:
production:
ref: production
modulesets:
- common
- monitoring
When an environment references multiple module sets, all modules from all referenced sets are included. If a module appears in multiple sets, the last one wins.
Custom Install Paths¶
Modules support target_dir and install_as fields for controlling where they are installed:
modules:
- name: role
git: https://github.com/example/puppet-role.git
ref: main
target_dir: site # install under site/ instead of modules/
- name: puppetlabs-stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
install_as: stdlib # directory name: modules/stdlib/
The default target_dir is modules and the default install_as is the module name.
Overrides¶
Per-environment modules take precedence over module sets. This lets you pin a specific version of a module in one environment while using the default version everywhere else:
modulesets:
common:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
environments:
production:
ref: production
modulesets:
- common
modules:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v8.6.0 # pinned to older version in production
Precedence¶
When both dynamic and static environments exist with the same name, the static declaration wins. This lets you use branch discovery as a baseline while explicitly controlling specific environments.
Lockfile¶
openvox-code supports a lockfile (openvox-code.lock) that records the exact Git SHA for every module in every environment. This ensures reproducible deploys.
# Generate or update the lockfile
openvox-code lock --config openvox-code.yaml
# Deploy using locked SHAs
openvox-code deploy --lockfile openvox-code.lock
The lockfile is a YAML file with the following structure:
version: 1
generated_at: "2026-01-15T10:30:00Z"
environments:
production:
ref: v1.5.0
control_repo_url: https://github.com/example/control-repo.git
control_repo_sha: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
modules:
- name: stdlib
git: https://github.com/puppetlabs/puppetlabs-stdlib.git
ref: v9.0.0
sha: f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5
- name: apache
git: https://github.com/puppetlabs/puppetlabs-apache.git
ref: v12.0.0
sha: 1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b
This is particularly useful for:
- Reproducible production deploys
- Auditing exactly which code is deployed
- Rolling back to a known-good state