# Using ResourceSets for Time-Based Delivery

In highly regulated industries, deploying software changes requires strict adherence to compliance
frameworks and operational policies. These organizations must demonstrate control over when changes
are deployed to production systems, often requiring:

- **Change Advisory Board (CAB) approval windows** - Deployments only during pre-approved time slots
- **Business continuity requirements** - No deployments during peak business hours or critical operations
- **Compliance auditing** - Detailed records of when and why deployments occurred
- **Risk management** - Controlled rollout windows to minimize business impact
- **Operational readiness** - Ensuring sufficient staff coverage during deployment windows

The Flux Operator addresses these requirements through time-based reconciliation schedules, providing
organizations with the governance controls they need while maintaining the benefits of GitOps automation.

## How ResourceSets and Input Providers Work

Before diving into the configuration, it's important to understand how The Flux Operator APIs
work together to enable controlled deployments.

The [ResourceSet](/docs/crd/resourceset/) API allows you to define a set of Flux resources
for deploying an application, while the [ResourceSetInputProvider](/docs/crd/resourcesetinputprovider/) API
is used to provide inputs to the `ResourceSet`, such as Git commit SHA and branch name or tag name,
that determine what version of the application should be deployed.

Instead of using a Flux `GitRepository` and `Kustomization` directly, we'll generate these
resources dynamically with a `ResourceSet`. To control when Flux pulls changes from Git
we'll pin the `GitRepository` to a specific commit SHA, the `ResourceSetInputProvider`
will be responsible for fetching the latest commit SHA from a Git branch or tag,
at the defined reconciliation schedule.

## GitOps Workflow

- **Define a ResourceSetInputProvider**: This provider will scan a Git branch or tag
   for changes and export the commit SHA as an input.
- **Configure schedule**: The provider will have a reconciliation schedule
   that defines when it should check for changes in the Git repository.
- **Define a ResourceSet**: The ResourceSet will use the inputs from the provider
   to create a `GitRepository` and `Kustomization` that deploys the application
   at the specified commit SHA.

### ResourceSetInputProvider Definition

Assuming the Kubernetes deployment manifests for an application are stored in a Git repository,
you can define a input provider that scans a branch for changes
and exports the commit SHA:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
  name: my-app-main
  namespace: apps
  labels:
    app.kubernetes.io/name: my-app
  annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
    fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "Europe/London"
      window: 8h
  type: GitHubBranch # or GitLabBranch / AzureDevOpsBranch
  url: https://github.com/my-org/my-app
  secretRef:
    name: gh-app-auth
  filter:
    includeBranch: "^main$"
  defaultValues:
    env: "production"
```

For when Git tags are used to version the application, you can define an input provider
that scans the Git tags and exports the latest tag according to a semantic versioning:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
  name: my-app-release
  namespace: apps
  labels:
    app.kubernetes.io/name: my-app
  annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
    fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "Europe/London"
      window: 8h
  type: GitHubTag # or GitLabTag / AzureDevOpsTag
  url: https://github.com/my-org/my-app
  secretRef:
    name: gh-auth
  filter:
    semver: ">=1.0.0"
    limit: 1
```

### ResourceSet Definition

The exported inputs can then be used in a `ResourceSet` to deploy the application
using the commit SHA from the input provider:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
  name: my-app
  namespace: apps
spec:
  inputsFrom:
    - kind: ResourceSetInputProvider
      selector:
        matchLabels:
          app.kubernetes.io/name: my-app
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      metadata:
        name: my-app
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 12h
        url: https://github.com/my-org/my-app
        ref:
          commit: << inputs.sha >>
        secretRef:
          name: gh-auth
        sparseCheckout:
          - deploy
    - apiVersion: kustomize.toolkit.fluxcd.io/v1
      kind: Kustomization
      metadata:
        name: my-app
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 30m
        retryInterval: 5m
        prune: true
        wait: true
        timeout: 5m
        sourceRef:
          kind: GitRepository
          name: my-app
        path: deploy/<< inputs.env >>
```

When the `ResourceSetInputProvider` runs according to its schedule, if it finds a new commit,
the `ResourceSet` will be automatically updated with the new commit SHA which will trigger
an application deployment for the new version.

## Helm Release Workflow

For applications packaged with Helm, you can use a similar approach to trigger a Helm release upgrade
in a controlled manner when a new chart version is available.
For this to work, the Helm chart must be stored in a container registry as an OCI artifact.

Example `ResourceSetInputProvider` that scans an OCI repository and exports the latest stable version as an input:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
   name: podinfo-release
   namespace: apps
   labels:
      app.kubernetes.io/name: podinfo
   annotations:
      fluxcd.controlplane.io/reconcileEvery: "10m"
      fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
   schedule:
      - cron: "0 12 * * 1-5"
        timeZone: "UTC"
   type: OCIArtifactTag
   url: oci://ghcr.io/stefanprodan/charts/podinfo
   filter:
      semver: ">=1.0.0"
      limit: 1
```

Example `ResourceSet` that deploys a Flux HelmRelease using
the artifact tag exported by the input provider as the latest chart version:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
  name: podinfo
  namespace: apps
spec:
  inputsFrom:
    - kind: ResourceSetInputProvider
      selector:
        matchLabels:
          app.kubernetes.io/name: podinfo
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: OCIRepository
      metadata:
        name: podinfo
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 10m
        url: oci://ghcr.io/stefanprodan/charts/podinfo
        ref:
          tag: << inputs.tag >>
    - apiVersion: helm.toolkit.fluxcd.io/v2
      kind: HelmRelease
      metadata:
        name: podinfo
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 30m
        releaseName: podinfo
        chartRef:
          kind: OCIRepository
          name: podinfo
        values:
          replicaCount: 2
```

<div class="callout callout-tip">
<div class="callout-title">OCI Artifacts Support</div>
<div class="callout-content">

Note that Flux Operator supports OIDC-based authentication for container registries such as Amazon ECR, Azure ACR and Google GAR.
For more details, see the [ResourceSetInputProvider API reference](/docs/crd/resourcesetinputprovider/#secret-less).

</div>
</div>

## Scheduling Configuration

The `.spec.schedule` field in the `ResourceSetInputProvider` allows you to define when the input provider
should run to check for changes in source repositories.

### Schedule Definition

The schedule is defined as a list of cron expressions, each with an optional time zone and window.

Example:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
spec:
  schedule:
    # Every day-of-week from Monday through Thursday
    # between 10:00 to 16:00
    - cron: "0 10 * * 1-4"
      timeZone: "America/New_York"
      window: "6h"
```

The `cron` field accepts standard cron expressions with five fields:

```
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
* * * * *
```

Use <a href="https://crontab.guru/" target="_blank" rel="noopener noreferrer">crontab.guru</a> to help generate and validate cron expressions.

The `timeZone` field specifies the time zone for interpreting the cron schedule
using <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones" target="_blank" rel="noopener noreferrer">IANA time zone names</a>.
If not specified, the time zone defaults to `UTC`.

The `window` field defines the duration during which reconciliations are allowed to run after the scheduled time.
The format is a Go duration string, e.g. `30m`, `1h`, `2h30m`.
Must be either `0s` (no window) or at least twice the reconciliation timeout `4m`.

### Schedule Window

When a non-zero window is specified, reconciliation is allowed throughout the entire window duration:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
   annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "UTC"
      window: "8h"
```

In this case:

- At creation time, the input provider will not execute immediately, but will wait for the next scheduled time.
- The input provider will start reconciling at 08:00 UTC every weekday (Monday to Friday).
- The reconciliation will continue until 16:00 UTC, every 10 minutes, as specified by the `reconcileEvery` annotation.
- Any changes to the input provider object during this window will be reconciled immediately.

### Zero-Duration Window

When the window is omitted or set to `0s`, flux-operator makes the best effort to reconcile
at the exact scheduled time:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
   annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "UTC"
      window: "0s"
```

In this case:

- At creation time, the input provider will execute immediately ignoring the schedule.
- The input provider will reconcile at 08:00 UTC every weekday (Monday to Friday).
- Any changes to the input provider object will be reconciled immediately, even outside the scheduled time.

### Multiple Schedules

The schedule can contain multiple cron expressions, allowing for complex scheduling scenarios:

```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
spec:
  schedule:
    # Every day-of-week from Monday through Thursday
    # between 10:00 to 16:00 NY time
    - cron: "0 10 * * 1-4"
      timeZone: "America/New_York"
      window: "6h"
    # Every Friday from 10:00 to 13:00 UK time
    - cron: "0 10 * * 5"
      timeZone: "Europe/London"
      window: "3h"
```

In this case:

- The input provider reconciles if **any** schedule matches the current time.
- The next scheduled time is determined by the **earliest** upcoming schedule.
- Each schedule operates independently with its own time zone and window.

## Command-Line Operations

The `flux-operator` CLI can be used to perform manual operations
such as forcing a reconciliation, checking the status of the input provider or disabling it.

To force a reconciliation outside the defined schedule:

```sh
flux-operator reconcile rsip my-app-main --namespace apps --force
```

To check the status of input providers including their next schedule time:

```sh
flux-operator get rsip --all-namespaces
```

To suspend an input provider and prevent it from reconciling:

```sh
flux-operator suspend rsip my-app-main --namespace apps
```

To resume a suspended input provider:

```sh
flux-operator resume rsip my-app-main --namespace apps
```

See the [Flux Operator CLI documentation](cli.md) for more details on how to use the CLI.

## Further reading

To learn more about ResourceSets and the various configuration options, see the following docs:

- [ResourceSet API reference](/docs/crd/resourceset/)
- [ResourceSetInputProvider API reference](/docs/crd/resourcesetinputprovider/)