Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions website/docs/concepts/core-concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Core Concepts

This page explains what ORC does and how its main features work. For the
reasoning behind these choices, see [Design Principles](design-principles.md). For
the full field-level API documentation, see the
[CRD Reference](../crd-reference.md).

## Management Policies

Every ORC resource has a `managementPolicy` that determines how ORC treats the
underlying OpenStack resource:

| Policy | Description |
|--------|-------------|
| `managed` | ORC creates, updates, and deletes the OpenStack resource. This is the default. |
| `unmanaged` | ORC imports an existing OpenStack resource but will not modify or delete it. |

### When to use `managed`

- The resource should be created and owned by ORC
- You want ORC to update the OpenStack resource when you change the spec
- You want ORC to delete the OpenStack resource when you remove it from
Kubernetes

### When to use `unmanaged`

- The resource is owned by another system (e.g. created by an admin or
another tool)
- You need to reference shared infrastructure that multiple projects use
(external networks, public flavors)

The distinction matters most at deletion time. By default, when you delete a
`managed` ORC object, ORC deletes the corresponding OpenStack resource. When you
delete an `unmanaged` ORC object, the OpenStack resource is always left
untouched. See [Deletion Behavior](#deletion-behavior) for how to change the
default for managed resources.

### Create vs Import

A **managed** resource uses `spec.resource` to describe what should be created:

```yaml
spec:
managementPolicy: managed
resource:
description: My application network
```

An **unmanaged** resource uses `spec.import` to find an existing OpenStack
resource by UUID or by a filter query:

```yaml
spec:
managementPolicy: unmanaged
import:
filter:
name: public
external: true
```

When importing by filter, the filter must match exactly **one** resource:

- **No matches**: ORC keeps retrying (the resource stays `Progressing: True`).
This is useful when you expect another system to create the resource soon.
- **Multiple matches**: ORC reports a terminal error. Make the filter more
specific.

See [Troubleshooting](../troubleshooting.md#common-issues) for debugging
import filter issues. The [Tutorial](../getting-started.md) walks through
importing resources step by step.

## Resource References and Dependencies

ORC resources reference each other using `*Ref` fields (e.g. `networkRef`,
`flavorRef`, `portRef`). These references serve three purposes:

1. **Name resolution**: References are resolved by Kubernetes object name
within the same namespace. References to other OpenStack resources always
go through an ORC object, never by raw OpenStack UUID. (A few spec fields
do accept raw IDs for values that aren't references to other resources,
such as setting a resource's own ID or a port's host ID.)

2. **Automatic ordering**: ORC waits for a referenced resource to exist and
be `Available` before proceeding. You can apply all your resources at once
in any order and ORC will sort out the sequencing.

3. **Deletion protection**: ORC prevents deletion of a resource while other
resources still reference it. If you delete everything at once, ORC
automatically deletes them in the correct reverse order.

See [Design Principles](design-principles.md#orc-objects-only-reference-orc-objects)
for why ORC requires all references to go through ORC objects.

### Cross-namespace references

ORC does not allow cross-namespace references. All `*Ref` fields resolve within
the same namespace. This applies to ORC objects, credential secrets, and any
other referenced objects. See
[Design Principles](design-principles.md#no-cross-namespace-references) for the
rationale behind this choice.

## Deletion Behavior

For managed resources, the `managedOptions.onDelete` field controls what happens
when the Kubernetes object is deleted:

| Value | Description |
|-------|-------------|
| `delete` | Delete the OpenStack resource. This is the default. |
| `detach` | Keep the OpenStack resource; only remove the ORC object. |

```yaml
spec:
managementPolicy: managed
managedOptions:
onDelete: detach # Keep the OpenStack resource on deletion
resource:
# ...
```

Use `detach` when you want to stop managing a resource through ORC without
destroying the underlying infrastructure, for example during a migration.

## Name Reuse

Deleting an ORC object and creating a new one with the same name is safe. ORC's
dependency management ensures that the old resource is fully cleaned up before
the new one takes its place.

## Status and Conditions

Every ORC resource reports its state through two conditions: **Available** (is
the resource ready?) and **Progressing** (is ORC still working on it?). A
resource is healthy when `Available=True` and `Progressing=False`.

When something goes wrong, the condition's `reason` and `message` fields explain
what happened. See [Status Conditions Reference](../reference/conditions.md)
for the full list of condition states, reasons, and recommended actions.

ORC surfaces error messages, including potentially sensitive details from
OpenStack, directly in status conditions.

The `.status.resource` field contains the observed state from OpenStack,
including fields that OpenStack assigns (like `projectID`, `createdAt`, etc.).

## Cloud Credentials

Every ORC resource has its own `cloudCredentialsRef` that points to a Kubernetes
Secret containing OpenStack credentials. The secret holds a standard OpenStack
`clouds.yaml`, and each ORC resource specifies which cloud entry to use.
Because credentials are per-resource, you can manage OpenStack resources across
multiple clouds or projects from the same namespace.

ORC prevents deletion of credential secrets while they are still referenced by
ORC resources, ensuring credentials aren't accidentally removed from under
running infrastructure.

See [Set Up Cloud Credentials](../howto/cloud-credentials.md) for step-by-step
instructions on creating the secret, adding custom CA certificates, and
referencing credentials from ORC resources.

## Resource Naming

By default, ORC creates OpenStack resources with the same name as the Kubernetes
object. You can override this using `spec.resource.name`. See
[Design Principles](design-principles.md#resource-naming) for how ORC handles
duplicate names safely.

## Deterministic Behavior

When OpenStack would create resources behind the scenes or make arbitrary
choices, ORC requires the user to be explicit instead. See
[Design Principles](design-principles.md#deterministic-behavior) for examples.
72 changes: 72 additions & 0 deletions website/docs/concepts/design-principles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Design Principles

This page explains why ORC is designed the way it is. It covers the principles
and trade-offs that guide ORC's behavior. Understanding these principles helps
you predict how ORC will behave in situations the documentation doesn't
explicitly cover. For a practical introduction to ORC's features, see
[Core Concepts](core-concepts.md).

## ORC objects only reference ORC objects

In order to fully manage dependencies, ORC only ever references other ORC
objects in spec fields. You cannot put a raw OpenStack UUID in a `*Ref` field.
Instead, you create an ORC object (even an `unmanaged` import) and reference
that.

This may seem like extra work for simple cases, but it gives ORC a complete
picture of the dependency graph. That's what makes automatic ordering and
deletion protection possible: ORC knows what depends on what because every
relationship goes through a Kubernetes object it can watch.

Status fields *do* contain OpenStack UUIDs. When reporting observed state, ORC
directly reports what OpenStack returned, including resource IDs.

## No implicit resource creation

ORC avoids API options that would cause OpenStack to create resources behind the
scenes. For example, OpenStack's server create API accepts networks by network
ID, port ID, or fixed IP, all inline. Passing a network or IP address inline
would cause OpenStack to create a port implicitly, invisible to ORC. ORC
requires you to create a separate Port object and reference it via `portRef`,
so every resource has a clear owner.

## Deterministic behavior

Given a spec, the resulting OpenStack state should be predictable. ORC honors
OpenStack's default values, but where OpenStack would make an arbitrary choice,
ORC requires the user to be explicit.

For example, creating a port on a network with multiple subnets would let
OpenStack pick a subnet arbitrarily. ORC will not create IP addresses for ports
unless the user specifies them in the spec.

## No cross-namespace references

ORC does not allow cross-namespace references. This applies to all references,
including references to other ORC objects and to non-ORC objects such as
credential secrets and user-data secrets.

This design principle:

- **Reduces security risk**: a bug in the controller cannot accidentally leak
resources from other namespaces
- **Enables namespace-scoped operation**: ORC can run in a single namespace
without any ClusterRoles

## Resource naming

By default, ORC creates OpenStack resources with the same name as the Kubernetes
object. Since Kubernetes enforces unique names within a namespace, OpenStack
resources created by ORC will have distinct names by default.

ORC also allows overriding the OpenStack name via `spec.resource.name`, which
makes it possible to create OpenStack resources with duplicate names. ORC
handles this correctly because it always tracks resources by their OpenStack ID
(stored in `status.id`), not by name.

## Error reporting

ORC considers itself an agent of the user: error messages, including
potentially sensitive details from OpenStack, are surfaced directly in status
conditions because the user would have received the same response calling the
API directly.
87 changes: 87 additions & 0 deletions website/docs/concepts/drift-detection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Drift Detection and External Deletion

This page explains how ORC's periodic resync works, what happens when resources
are changed or deleted outside of ORC, and how dependent resources are affected.
For practical setup steps, see
[How to Enable Drift Detection](../howto/drift-detection.md).

## How periodic resync works

After a resource reaches a stable state (`Progressing=False`), ORC schedules a
reconciliation after the configured `resyncPeriod`. On each resync:

1. ORC fetches the current state of the OpenStack resource.
2. For **managed** resources: if drift is detected, ORC updates the resource to
match the Kubernetes spec.
3. For **unmanaged** resources: ORC refreshes `status.resource` to reflect the
current OpenStack state, but makes no changes.
4. The next resync is scheduled.

A small random jitter ([0%, +20%]) is applied to `resyncPeriod` to spread
reconciliations and avoid thundering-herd effects.

!!! note

Resources in a terminal error state (`Progressing=False` with reason
`InvalidConfiguration` or `UnrecoverableError`) are **not** periodically
resynced. Terminal errors require manual intervention to resolve.

### Restart behavior

ORC persists `status.lastSyncTime` in the Kubernetes status. After a controller
restart, it uses this timestamp to determine when the next resync should occur,
preventing a thundering herd of reconciliations on startup.

## External deletion handling

When a resource is deleted directly from OpenStack (bypassing ORC), the behavior
depends on how ORC originally obtained the resource.

### Managed resources are recreated

If you created the resource through ORC's `spec.resource` field, ORC
**recreates** it automatically:

1. ORC detects the resource is missing from OpenStack (the ID stored in
`status.id` no longer exists).
2. ORC clears `status.id`.
3. On the next reconcile, ORC creates a new OpenStack resource.
4. The new resource ID is stored in `status.id`.

The ORC object continues to exist and becomes `Available=True` again once the
resource is recreated.

!!! warning

Recreation produces a new OpenStack resource with a **new ID**. Any
OpenStack resources (outside ORC) that referenced the old ID will need to be
updated manually.

### Imported resources enter terminal error

If you imported an existing resource using `spec.import`, ORC reports a
**terminal error** when the resource is deleted from OpenStack:

- `Available=False`
- `Progressing=False`
- Condition reason: `UnrecoverableError`
- Message: `resource has been deleted from OpenStack`

ORC does **not** recreate imported resources because it did not create them
originally, and recreating a new empty resource would not restore what was lost.

To recover: delete and recreate the ORC object pointing at a new or restored
OpenStack resource.

## Implications for dependent resources

OpenStack enforces referential integrity for most resource relationships. For
example, a Network cannot be deleted while Subnets exist on it. This means
externally deleting a parent resource is normally prevented by OpenStack itself.

!!! warning

If a parent resource is externally deleted in a way that bypasses
OpenStack's referential integrity (e.g. direct database manipulation),
manual cleanup of both the parent and dependent resources may be required.
This is an unusual operational scenario.
Loading
Loading