<a id="cloud-openstack"></a>

# OpenStack

In Juju, [OpenStack](https://www.openstack.org/software/) is a [machine cloud](https://documentation.ubuntu.com/juju/3.6/reference/cloud.md#machine-cloud) and works as described below.

#### NOTE
This reference assumes basic familiarity with Juju. If you are new to Juju, start with the [Tutorial](https://documentation.ubuntu.com/juju/3.6/tutorial.md#tutorial), then use this page together with the generic materials it links to.

<a id="openstack-requirements"></a>

## Requirements

An OpenStack version that supports:

- Compute v2 (Nova).
- Network v2 (Neutron) (optional, but required for Queens or newer).
- Volume v2 (Cinder) (optional).
- Identity v2 or v3 (Keystone).

<a id="openstack-concepts"></a>

## Concepts

The following table shows how OpenStack abstractions map to Juju concepts:

| OpenStack                                                                                        | Juju                                                                             |
|--------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
| [Project/Tenant](https://docs.openstack.org/keystone/latest/admin/projects-users-and-roles.html) | Scope for a [model](https://documentation.ubuntu.com/juju/3.6/reference/model.md#model) (roughly) |
| [Nova instance](https://docs.openstack.org/nova/latest/)                                         | [machine](https://documentation.ubuntu.com/juju/3.6/reference/machine.md#machine)                   |
| Process on an instance                                                                           | [unit](https://documentation.ubuntu.com/juju/3.6/reference/unit.md#unit)                         |
| Group of units for one workload                                                                  | [application](https://documentation.ubuntu.com/juju/3.6/reference/application.md#application)           |
| [Cinder volume](https://docs.openstack.org/cinder/latest/)                                       | [storage](https://documentation.ubuntu.com/juju/3.6/reference/storage.md#storage)                   |
| [Neutron network/subnet](https://docs.openstack.org/neutron/latest/)                             | Network spaces and placement targets (roughly)                                   |

<a id="openstack-cloud"></a>

## The cloud

See also: [Cloud](https://documentation.ubuntu.com/juju/3.6/reference/cloud.md#cloud), [Juju | Manage clouds](https://documentation.ubuntu.com/juju/3.6/howto/manage-clouds.md#manage-clouds), [Terraform Provider for Juju | Manage clouds](https://canonical.com/juju/docs/terraform-provider-juju/latest/howto/manage-clouds/#manage-clouds)

As for all machine clouds, the cloud is registered in Juju via a cloud definition, stored in `clouds.yaml` on the client (on Linux: `~/.local/share/juju/clouds.yaml`) and following this schema:

```yaml
clouds:
  <cloud-name>:  # User-defined name
    type: openstack
    auth-types:
      - <auth-type>                # See Authentication types below
    endpoint: <keystone-api-url>  # Keystone API endpoint
    regions:
      <region-name>:
        endpoint: <endpoint>       # Region-specific endpoint (if different)
    config:                        # Optional: model config defaults
      <config-key>: <value>        # See Configuration keys below
```

#### TIP
Source the OpenStack RC file (`source <path to file>`) before running `juju add-cloud` in interactive mode – Juju will detect values from preset OpenStack environment variables and suggest them as defaults.

<a id="openstack-credential"></a>

## Credentials

See also: [Credential](https://documentation.ubuntu.com/juju/3.6/reference/credential.md#credential), [Juju | Manage credentials](https://documentation.ubuntu.com/juju/3.6/howto/manage-credentials.md#manage-credentials), [Terraform Provider for Juju | Manage credentials](https://canonical.com/juju/docs/terraform-provider-juju/latest/howto/manage-credentials/#manage-credentials)

As for all machine clouds, credentials are stored in `credentials.yaml` on the client and follow this schema:

```yaml
credentials:
  <your-openstack-cloud>  # Cloud name as defined above
    <credential-name>:             # User-defined credential name
      auth-type: <auth-type>       # userpass (see Authentication types below)
      <attribute>: <value>         # Auth-type-specific attributes (see below)
```

#### IMPORTANT
**If you want to use environment variables (recommended):** Source the OpenStack RC file. Run `juju add-credential` and accept the suggested defaults.

<a id="openstack-credential-authentication-types"></a>

### Authentication types

OpenStack supports the following authentication types:

<a id="openstack-credential-userpass"></a>

#### `userpass`

Attributes:

- `username`: The username to authenticate with (required).
- `password`: The password for the specified username (required).
- `tenant-name`: The OpenStack tenant name (optional).
- `tenant-id`: The OpenStack tenant ID (optional).
- `version`: The OpenStack identity version (optional).
- `domain-name`: The OpenStack domain name (optional).
- `project-domain-name`: The OpenStack project domain name (optional).
- `user-domain-name`: The OpenStack user domain name (optional).

<a id="openstack-credential-access-key"></a>

#### `access-key`

For OpenStack deployments that expose an EC2-compatible endpoint.

Attributes:

- `access-key`: The access key to authenticate with (required).
- `secret-key`: The secret key to authenticate with (required).
- `tenant-name`: The OpenStack tenant name (optional).
- `tenant-id`: The OpenStack tenant ID (optional).
- `version`: The OpenStack identity version (optional).

<a id="openstack-controller"></a>

## Controllers

See also: [Controller](https://documentation.ubuntu.com/juju/3.6/reference/controller.md#controller), [Juju | Manage controllers](https://documentation.ubuntu.com/juju/3.6/howto/manage-controllers.md#manage-controllers), [Terraform Provider for Juju | Manage controllers](https://canonical.com/juju/docs/terraform-provider-juju/latest/howto/manage-controllers/#manage-controllers)

<a id="openstack-controller-bootstrap-behavior"></a>

### Bootstrap behavior

Creates a controller instance on OpenStack. Requires simplestreams metadata to locate appropriate machine images. If metadata is available locally, pass it via `juju bootstrap ... --metadata-source <path to metadata simplestreams>`.

See more: [How to manage Simplestreams metadata](https://documentation.ubuntu.com/juju/3.6/howto/manage-metadata.md#manage-metadata)

**Special bootstrap considerations:**

- **Multiple private networks**: Specify the network for instances to boot from via `juju bootstrap ... --model-default network=<network uuid or name>`.
- **Floating IP access**: If instances must be accessed via floating IPs, pass `allocate-public-ip=true` as a bootstrap constraint.

<a id="openstack-controller-resources-created-at-bootstrap"></a>

### Resources created at bootstrap

The controller runs on a Nova instance provisioned using the same mechanisms as workload machines – see [Resources created per machine](#openstack-machine-resources-created-per-machine) for the full per-machine resource model. Controller-specific differences are noted below.

**Compute**

- **Nova instance**: Ubuntu LTS compute instance. Flavor selected based on hardware constraints.
- **Instance metadata**: Tagged with `juju-is-controller: true`, `juju-controller-uuid`, and `juju-model-uuid`.

**Networking**

- **Security groups**:
  - Model-wide group: `juju-<controller-uuid>-<model-uuid>`. Ingress rules (self-referencing):
    - TCP ports 1–65535 (IPv4 and IPv6)
    - UDP ports 1–65535 (IPv4 and IPv6)
    - ICMP (IPv4 and IPv6)
  - Machine or global group (no initial rules; added via `open-ports`):
    - `firewall-mode=instance` (default): `juju-<controller-uuid>-<model-uuid>-<machine-id>`
    - `firewall-mode=global`: `juju-<controller-uuid>-<model-uuid>-global`
  - Optionally the OpenStack `default` security group if `use-default-secgroup=true`.
  - All groups tagged with `juju-controller=<controller-uuid>` and `juju-model=<model-uuid>`.
- **Network attachments**: Connected to configured internal networks from model config.
- **Neutron ports** (if space-aware networking): Pre-created with fixed IPs before instance boot.
- **Floating IP** (optional): Allocated from external network if `allocate-public-ip=true`.

**Storage**

- **Root disk**: Local ephemeral disk or Cinder boot volume based on `root-disk-source` constraint. Configurable volume type, tag, and disk bus.

<a id="openstack-model"></a>

## Models

See also: [Model](https://documentation.ubuntu.com/juju/3.6/reference/model.md#model), [Juju | Manage models](https://documentation.ubuntu.com/juju/3.6/howto/manage-models.md#manage-models), [Terraform Provider for Juju | Manage models](https://canonical.com/juju/docs/terraform-provider-juju/latest/howto/manage-models/#manage-models)

<a id="openstack-model-configuration-keys"></a>

### Configuration keys

OpenStack supports the following [cloud-specific model configuration keys](https://documentation.ubuntu.com/juju/3.6/reference/configuration/list-of-model-configuration-keys.md#model-config-cloud-specific-key):

**Networking**

<a id="openstack-model-external-network"></a>
- **`external-network`**: The network label or UUID to create floating IP addresses on when multiple external networks exist. Type: `string`. Default: `""`.

<a id="openstack-model-use-openstack-gbp"></a>
- **`use-openstack-gbp`**: Whether to use Neutron’s Group-Based Policy. Type: `bool`. Default: `false`.

<a id="openstack-model-policy-target-group"></a>
- **`policy-target-group`**: The UUID of Policy Target Group to use for Policy Targets created. Type: `string`. Default: `""`.

<a id="openstack-model-use-default-secgroup"></a>
- **`use-default-secgroup`**: Whether new machine instances should have the “default” OpenStack security group assigned in addition to Juju-defined security groups. Type: `bool`. Default: `false`.

<a id="openstack-model-network"></a>
- **`network`**: The network label or UUID to bring machines up on when multiple networks exist. Type: `string`. Default: `""`.

<a id="openstack-machine"></a>

## Machines

See also: [Machine](https://documentation.ubuntu.com/juju/3.6/reference/machine.md#machine), [Juju | Manage machines](https://documentation.ubuntu.com/juju/3.6/howto/manage-machines.md#manage-machines), [Terraform Provider for Juju | Manage machines](https://canonical.com/juju/docs/terraform-provider-juju/latest/howto/manage-machines/#manage-machines)

<a id="openstack-machine-constraints"></a>

### Constraints

OpenStack supports the following [constraints](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint):

#### NOTE
The constraints `instance-type` and `[mem, root-disk, cores]` are mutually exclusive.

**Compute**

- [arch](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-arch)
- [container](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-container)
- [cores](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-cores)
- [image-id](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-image-id). Starting with Juju 3.3. Valid values: An OpenStack image ID.
- [instance-type](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-instance-type). Valid values: Any user-defined OpenStack flavor.
- [mem](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-mem)
- [virt-type](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-virt-type). Valid values: `kvm`, `lxd`.

**Networking**

- [allocate-public-ip](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-allocate-public-ip)
- [zones](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-zones)

**Storage**

- [root-disk](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-root-disk)
- [root-disk-source](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-root-disk-source). Values: `local` (ephemeral disk, default) or `volume` (Cinder boot volume) or `<storage-pool name>` (Cinder boot volume with additional configuration for volume type, tag, and disk bus).

<a id="openstack-machine-placement-directives"></a>

### Placement directives

OpenStack supports the following [placement directives](https://documentation.ubuntu.com/juju/3.6/reference/placement-directive.md#placement-directive):

- [<machine>](https://documentation.ubuntu.com/juju/3.6/reference/placement-directive.md#placement-directive-machine)
- [zone=<zone>](https://documentation.ubuntu.com/juju/3.6/reference/placement-directive.md#placement-directive-zone)

<a id="openstack-machine-resources-created-per-machine"></a>

### Resources created per machine

Applies to all machines, including controller machines. Controller-specific differences are documented in [Resources created at bootstrap](#openstack-controller-resources-created-at-bootstrap).

**Compute**

- **Nova instance**: Compute instance with name `juju-<model-uuid>-<machine-id>`. Flavor selected based on constraints.
- **Root disk**: Local ephemeral disk (default) or Cinder boot volume if `root-disk-source=volume`.
- **Additional Cinder volumes** (optional): Created when storage specified via storage constraints.

**Networking**

- **Security groups**:
  - Model-wide group: `juju-<controller-uuid>-<model-uuid>`
  - Machine-specific group (`firewall-mode=instance`, default): `juju-<controller-uuid>-<model-uuid>-<machine-id>`
  - Global group (`firewall-mode=global`): `juju-<controller-uuid>-<model-uuid>-global`
- **Network attachments**: Connected to configured internal networks. Multiple NICs if multiple networks configured.
- **Neutron ports** (if space-aware networking): Pre-created ports with fixed IPs for each subnet/space.
- **Floating IP** (optional): Allocated from external network if `allocate-public-ip=true` constraint.

**Metadata tags:** `juju-model-uuid`, `juju-controller-uuid`, `juju-machine-id`, `juju-units-deployed`.

<a id="openstack-machine-networking-behavior"></a>

### Networking behavior

- **Network selection**: Uses networks configured via `network` model config. If not specified, attaches to all available internal networks.
- **Spaces**: OpenStack supports multiple network devices. Supplying multiple space constraints or endpoint bindings will provision machines with NICs in subnets representing the union of specified spaces. Creates dedicated Neutron ports per subnet/space. Ports pre-allocated with fixed IPs before boot.
- **Security groups**: Per-model group allows internal traffic. Machine or global group allows user-defined port rules via `open-ports`.
- **Floating IPs**: Allocated from external network specified in `external-network` config. Attempts to place in same availability zone as instance. Reuses unassigned IPs when available.
- **Port security**: Respects `port_security_enabled` network attribute. Skips security group creation if port security disabled.

<a id="openstack-machine-storage-behavior"></a>

### Storage behavior

See also: [cinder](#storage-provider-cinder) for the Cinder storage provider configuration options.

- **Root disk**: Local ephemeral disk by default. Use `root-disk-source=volume` constraint to boot from a generic Cinder volume instead, or specify a storage pool. Volume type, tag and disk bus are configurable via the pool.
- **Additional volumes**: Cinder block volumes created on demand when storage is specified via storage constraints.
- **AZ constraint**: Availability zone is matched to the instance’s AZ when possible.
- **Device path**: Auto-assigned by OpenStack.

<a id="openstack-storage"></a>

## Storage

See also: [Storage](https://documentation.ubuntu.com/juju/3.6/reference/storage.md#storage), [Juju | Manage storage](https://documentation.ubuntu.com/juju/3.6/howto/manage-storage.md#manage-storage)

<a id="openstack-storage-providers"></a>

### Storage providers

In addition to generic storage providers, OpenStack provides the following [cloud-specific storage providers](https://documentation.ubuntu.com/juju/3.6/reference/storage.md#storage-provider-cloud-specific):

<a id="storage-provider-cinder"></a>

#### `cinder`

**Type:** Cinder block volumes

**Tagging:** Volumes tagged with `juju-model-uuid`, `juju-controller-uuid`, `juju-storage-instance`, `juju-storage-owner`. Volume names follow the pattern `juju-<model-uuid>-<volume-tag>`.

**Configuration options:**

- `volume-type`: The volume type. Value is the name of any volume type registered with Cinder.
