Skip to content

Environments

Warning

This feature is under license.

Note

Documentation is in progress.

The Environments home

Environments in the user menu opens a matrix: one row per project, one column per environment, and in each cell what that project currently has running in that environment.

  • A cell shows the deployed build, its top promotion and how long it has been there, with an overlay for a deployment still on its way, a red dot when that deployment is held up, and a behind badge when an environment earlier in the chain holds something newer. Clicking a cell opens the slot drawer, which shows what is deployed now, what is in flight, what could go next and the last few deployments.
  • A project deploying more than once into the same environment — a canary, for instance — has one row per qualifier, nested under the project's own row.
  • A column is only drawn for an environment some visible row has a slot in.
  • The toolbar filters by project name, by favourites or all projects, by project label and by environment tag, and can keep only what has a deployment on the way. The filters are part of the address, so a filtered matrix can be bookmarked and shared.
  • The matrix refreshes itself every 30 seconds and says when it last did.

Creating environments and slots is behind the Setup command, out of the way of the operational screens — see Setup — and is usually not done by hand at all, see Configuration.

The slot page

Clicking Open slot in the drawer opens that slot's own page — "production · petclinic [canary]". It is the home of one project's deployments into one environment.

  • The header block is the drawer's own Now / In flight / Next, in full: what is deployed, what is trying to replace it and what could go next, with the one action that would move the deployment in flight. It refreshes itself every 30 seconds and says when it last did.
  • Deployments is the whole history: number, build, status, who, when it started, how long it took, and the error if there was one. It can be filtered by status, by build and by user — user meaning anybody on the deployment's audit trail, not only whoever started it — and the filtering is done by the server, so the answers do not depend on how much of the history is on screen.
  • Eligible builds lists what could go into the slot next, with Deploy on each. By default it lists the deployable builds — the ones the slot's rules already accept. The Show all eligible builds switch widens the list to every eligible one, so that "why can I not deploy this?" has somewhere to be asked.
  • Setup holds the slot's settings — its description, and whether it admits agents — its admission rules and its workflows: adding, editing and deleting them, and deleting the slot itself. The whole tab is hidden from a user who may not configure the slot.

Agents admitted

A registered agent may start a deployment pipeline, start the deployment and finish it — or mark it as failed — only in a slot which admits agents, and only if its owner may. In any other slot, it is refused with a message saying so:

agent claude-code-ci[agent] may not start a pipeline on production/petclinic: the slot does not admit agents (agent policy)

A slot does not admit agents by default. Edit the settings in the slot's Setup tab, set agentsAdmitted: true for the slot's environment in the CI configuration or in the CasC, or call the updateSlot mutation.

Even in a slot which admits agents, an agent never satisfies a manual approval, whoever the rule lists: its approval is refused with "an agent cannot approve; ask owner", and the pipeline stays a candidate. This is how agent asks, human approves works for deployments: the agent starts the pipeline, a person approves it, and the agent — or anybody — then deploys. An agent never overrides an admission rule either.

Admission rules

A slot admits builds through its admission rules, and a build must pass all of them. Each one is configured by its id and a ruleConfig:

Rule Id Admits a build when
Branch pattern branchPattern its branch matches includes and no excludes; with lastBranchOnly, deploying it also needs its branch to be the last of those branches
Promotion promotion its branch has the promotion level; deploying it needs the build to be promoted to it
Environment environment it has been deployed in the slot of environmentName (and qualifier)
Manual approval manual someone approves the deployment, optionally restricted to users or groups
Version pattern versionPattern its version matches includes and no excludes

Version pattern

The version pattern rule reads the build's version: its release label when it has one, its name otherwise. It tells a GA or a beta from an alpha when they all come from the same branch and reach the same promotion, which neither branchPattern nor promotion can.

  • includes — regular expressions, one of which the version must match. None means every version.
  • excludes — regular expressions, none of which the version must match. An exclusion wins over an inclusion.

Every expression must match the whole version, ignoring case: \d+\.\d+\.\d+ admits 6.0.0 but not 6.0.0-alpha.3. The expressions are read both by Yontrack and by its database, so keep to the syntax they share — classes such as \d, groups, alternations and quantifiers. A pattern either of them refuses, like a possessive \d++ or an inline (?i), is refused when the rule is saved.

The version is a fact of the build, so a build the rule admits is both eligible and deployable.

For example, GA and beta releases, but no alpha nor release candidate:

admissionRules:
  - ruleId: versionPattern
    ruleConfig:
      includes:
        - "\\d+\\.\\d+\\.\\d+(-beta\\.\\d+)?"

Eligible and deployable builds

Every admission rule of a slot answers two questions about a build:

  • Eligible — the build could go to this slot. A deployment can be started for it, and waits as a candidate. For the promotion rule, the build's branch has the promotion level.
  • Deployable — the build can go now: its candidate would run at once. For the promotion rule, the build itself is promoted to that level.

A build can be eligible and not yet deployable — not promoted yet, not deployed in the previous environment yet, or not on the last branch when the branchPattern rule has lastBranchOnly. Starting a deployment for it is allowed: the candidate becomes runnable once the rules accept it. The deploy dialog opened from a build, and its mobile counterpart, say so beside the slot — Not deployable yet: Build not promoted — and still offer the action.

A manual approval is given on the deployment itself, so it can never be satisfied before the deployment exists. It is not counted against deployability; the deploy dialog only notes Needs approval once started.

In the GraphQL API:

  • Slot.eligibleBuilds and Slot.eligibleBuild return the deployable builds by default. Pass deployable: false to get every eligible build.
  • eligibleSlotsForBuild gives, for each slot of the build's project, eligible and nonEligibleRules, and also deployable, nonDeployableRules (each with the rule and its reason) and pipelineOnlyRules (the rules decided on the deployment only, like manual).
  • startSlotPipeline creates a candidate for any eligible build. Whether it can run is on the returned pipeline, in runAction { ok } and admissionRules { check { ok reason } }.
  • Build.readiness(slotId) lists, in one read, everything the build still lacks for one slot: the rules which make it not eligible or not deployable, and a manual approval not given yet. See Readiness.

The deployment page

Clicking a deployment — from the matrix cell's drawer, from a slot, or from a build — opens that one deployment. It answers three questions, in three places:

  • The header names the build, its branch and its top promotion, says when the deployment started and who started it, and draws where it has got to: Candidate → Running → Deployed, or → Cancelled, or → Failed. Beside the bar is the one action that would move it — Start the deployment on a candidate, Finish the deployment on a running one — with Cancel as a secondary action, and Mark as failed on a running one (see Failed deployments). The action is disabled while something is blocking, and is not shown at all to a user without the right, or on a deployment which is over.
  • What's blocking lists the checks of the phase the deployment is in, failing ones first, with the fix on the failing row itself: Answer a rule waiting on somebody, Override a rule or a workflow which refuses. Checks which passed are folded behind "N of M checks passed". The phases already over are below, collapsed and read-only; a finished deployment has no current phase and shows all of them, expanded.
  • A check which is only pending — a workflow still running or not started yet, a manual approval nobody has answered — blocks the deployment like a failed one, but is not drawn as an error: it shows a spinner or an hourglass, reads Running or Waiting, and the header says what the deployment is waiting for in a blue notice rather than a red one. A failed check stays red.
  • The timeline down the side is the audit trail, newest first: every status change, every answer given to a rule, and every override — with the justification its author wrote.

The page refreshes itself every 30 seconds and says when it last did. Force deployment and Delete deployment remain header commands, and are hidden from a user without the right.

Failed deployments

A deployment goes through CANDIDATE and RUNNING, and ends as one of:

Status Meaning
DONE The build is deployed: it is now what the slot runs.
FAILED The deployment ran and did not make it.
CANCELLED The deployment was stopped — by hand, or because a more recent deployment replaced it.

A failed deployment is not a cancelled one: it was attempted, and its failure is a fact worth keeping — the delivery scorecard counts it in the success rate and the time to restore of the slot, where a cancelled deployment is left out.

  • Only a RUNNING deployment can be marked as failed; a candidate which never started is cancelled instead. It needs the same right as finishing a deployment, and takes an optional message saying why it failed.
  • FAILED is final: a failed deployment cannot be finished, even by forcing it, nor cancelled. Deploying the build again means starting a new deployment.
  • A failure does not change what the slot runs: the last DONE deployment stays the deployed one.
  • On the deployment page, Mark as failed sits beside Finish the deployment, and the timeline shows the failure with its message. The matrix, the slot drawer and the slot page show the Failed status. The mobile UI shows it too, without offering to mark a deployment as failed: a failure is reported by the CI which ran the deployment.
  • Marking a deployment as failed sends the slot-pipeline-failed event, and runs the slot workflows whose trigger is FAILED (On deployment failed).

From CI, or any automation, through GraphQL:

mutation {
  failSlotPipeline(input: {pipelineId: "...", message: "Helm upgrade timed out"}) {
    failStatus { ok }
    errors { message }
  }
}

or with the KDSL, pipeline.fail(message = "Helm upgrade timed out").

Backdating deployments

A deployment can be recorded after the fact — when importing a deployment history, for example, or when the CI reports late. The GraphQL mutations moving a deployment accept an optional dateTime, which is then used instead of the current time:

Mutation dateTime is
startSlotPipeline the start of the deployment
startSlotPipelineDeployment the time it started running
finishSlotPipelineDeployment its end, as DONE
failSlotPipeline its end, as FAILED
cancelSlotPipeline its end, as CANCELLED

The time is stored on the deployment — its start and end — and in its history. It must be:

  • not in the future;
  • not before the creation of the build;
  • not before the previous change of the deployment;
  • for a start, not before the start of the slot's latest deployment.

A time breaking one of these rules is refused, and nothing changes. So, a slot's history is recorded in order: deployment by deployment, oldest first.

Starting a deployment cancels the slot's deployment still in progress, if any, and that cancellation takes the start time of the new deployment. Without a dateTime, nothing is checked and the current time is used, as before.

Backdating needs no other right than the action's own. The events are sent, and the slot workflows run, as for any other deployment — at the time they are recorded, not at the backdated one.

In the KDSL:

build.startPipeline(slot, dateTime = start)
    .startDeploying(dateTime = start.plusMinutes(1))
    .finishDeployment(dateTime = start.plusMinutes(10))
// or .fail(message = "...", dateTime = ...), or .cancel(reason = "...", dateTime = ...)

Setup

The Setup command on the Environments home opens the one page where environments and slots are created, edited and deleted. It is deliberately out of the operational screens: configuring is not what somebody opens the Environments home to do, and in practice it is done as code — see Configuration.

  • Environments lists every environment in order, with its icon (editable in place), its tags and how many slots it has. New environment lives here, and so does deleting one.
  • Slots lists every slot grouped by project, with its qualifier, its environment, how many admission rules and workflows it carries, and a link to that slot's own Setup tab. New slot lives here.

Every control is hidden from a user without the matching right, and the Setup command itself is hidden from a user who has none of them.

Configuration

While environments and their slots can be configured through the UI, it's recommenced to use either:

CI configuration

Using the CI config feature, one can define the environments and slots linked to a project directly from its Yontrack CI config file.

For example:

version: v1
configuration:
  defaults:
    project:
      environments:
        environments:
          - name: self.yontrack.com
            description: Production environment for Yontrack itself
            order: 200
            tags:
              - yontrack
              - release
        slots:
          - project: yontrack
            environments:
              - name: self.yontrack.com
                agentsAdmitted: true
                admissionRules:
                  - ruleId: promotion
                    ruleConfig:
                      promotion: GOLD
                  - ruleId: branchPattern
                    ruleConfig:
                      includes:
                        - main
                workflows:
                  - name: Creation
                    trigger: CANDIDATE
                    nodes:
                      - id: start
                        executorId: mock
                        data:
                          text: Start
                      - id: end
                        parents:
                          - id: start
                        executorId: mock
                        data:
                          text: End

In this case, unless in the CasC setup where this behavior is configurable, the environments are not authoritative. Only the slots are for the configured project.

A typical use case for this CI config of environments would be done at the level where the actual environment is actually deployed, like in a GitOps repository.

CasC

The environments section of the CasC takes the same environments and slots as the CI configuration, agentsAdmitted included.

Removed setting: settings.environments

The environments extension used to contribute a buildDisplayOption setting, which chose how a build's environments were drawn on the promotion dots of the build page. Those dots are gone — a build's environments are now the journey strip on the build page, which always shows every slot of the project — and the setting went with them.

A casc.ontrack.config.settings.environments block left in a configuration-as-code file is rejected as an unknown settings section, so remove it when upgrading.