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

# VMware vSphere

In Juju, [VMware vSphere](https://www.vmware.com/products/vsphere.html) 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="vsphere-requirements"></a>

## Requirements

In order to add a vSphere cloud you will need an existing vSphere installation which supports, or has access to, the following:

- VMware Hardware Version 8 or greater.
- ESXi 5.0 or greater.
- Internet access.
- DNS and DHCP.

Juju supports both high-availability vSAN deployments and standard deployments.

<a id="vsphere-permissions"></a>

### Minimal vSphere permissions

Juju does not require full administrator privileges. You can create a
dedicated vSphere role with the permissions listed below, scoped to the
datacenter and its children. These permissions allow Juju to import templates,
provision VMs, manage folders, and tear down resources.

Apply the role at the **datacenter level** with propagation to child
objects. For a tighter scope, restrict to the specific datacenter,
cluster, host folder, datastore folder, and network folder that Juju
will use.

**Global**

| VMware UI path   | Privilege ID   |
|------------------|----------------|
| System > Read    | `System.Read`  |

**Datastore**

| VMware UI path                        | Privilege ID               |
|---------------------------------------|----------------------------|
| Datastore > Allocate space            | `Datastore.AllocateSpace`  |
| Datastore > Browse datastore          | `Datastore.Browse`         |
| Datastore > Low level file operations | `Datastore.FileManagement` |

**Folder**

| VMware UI path         | Privilege ID    |
|------------------------|-----------------|
| Folder > Create folder | `Folder.Create` |
| Folder > Delete folder | `Folder.Delete` |
| Folder > Move folder   | `Folder.Move`   |

**Network**

| VMware UI path           | Privilege ID     |
|--------------------------|------------------|
| Network > Assign network | `Network.Assign` |

**Resource**

| VMware UI path                                     | Privilege ID              |
|----------------------------------------------------|---------------------------|
| Resource > Assign virtual machine to resource pool | `Resource.AssignVMToPool` |
| Resource > Import                                  | `Resource.Import`         |

**vApp**

| VMware UI path                        | Privilege ID                 |
|---------------------------------------|------------------------------|
| vApp > Import                         | `vApp.Import`                |
| vApp > vApp application configuration | `vApp.VAppApplicationConfig` |

**Virtual Machine > Configuration**

| VMware UI path                                                          | Privilege ID                                   |
|-------------------------------------------------------------------------|------------------------------------------------|
| Virtual Machine > Configuration > Add or remove device                  | `VirtualMachine.Config.AddRemoveDevice`        |
| Virtual Machine > Configuration > Change CPU count                      | `VirtualMachine.Config.CPUCount`               |
| Virtual Machine > Configuration > Change Memory                         | `VirtualMachine.Config.Memory`                 |
| Virtual Machine > Configuration > Change Settings                       | `VirtualMachine.Config.Settings`               |
| Virtual Machine > Configuration > Extend virtual disk                   | `VirtualMachine.Config.DiskExtend`             |
| Virtual Machine > Configuration > Modify device settings                | `VirtualMachine.Config.EditDevice`             |
| Virtual Machine > Configuration > Advanced                              | `VirtualMachine.Config.AdvancedConfig`         |
| Virtual Machine > Configuration > Upgrade virtual machine compatibility | `VirtualMachine.Config.UpgradeVirtualHardware` |

**Virtual Machine > Interaction**

| VMware UI path                            | Privilege ID                       |
|-------------------------------------------|------------------------------------|
| Virtual Machine > Interaction > Power On  | `VirtualMachine.Interact.PowerOn`  |
| Virtual Machine > Interaction > Power Off | `VirtualMachine.Interact.PowerOff` |

**Virtual Machine > Inventory**

| VMware UI path                                     | Privilege ID                                  |
|----------------------------------------------------|-----------------------------------------------|
| Virtual Machine > Inventory > Create from existing | `VirtualMachine.Inventory.CreateFromExisting` |
| Virtual Machine > Inventory > Move                 | `VirtualMachine.Inventory.Move`               |
| Virtual Machine > Inventory > Remove               | `VirtualMachine.Inventory.Delete`             |

**Virtual Machine > Provisioning**

| VMware UI path                                    | Privilege ID                                 |
|---------------------------------------------------|----------------------------------------------|
| Virtual Machine > Provisioning > Deploy template  | `VirtualMachine.Provisioning.DeployTemplate` |
| Virtual Machine > Provisioning > Mark as template | `VirtualMachine.Provisioning.MarkAsTemplate` |

#### TIP
The `System.Read` privilege provides read access to the entire inventory tree
(datacenters, folders, hosts, clusters, datastores, networks, VMs, resource
pools, and distributed virtual switches). The API session cannot enumerate
objects without it.

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

## Concepts

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

| vSphere                         | Juju                                                                   |
|---------------------------------|------------------------------------------------------------------------|
| Virtual machine                 | [machine](https://documentation.ubuntu.com/juju/3.6/reference/machine.md#machine)         |
| Process inside a VM             | [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) |
| Datastore disk                  | [storage](https://documentation.ubuntu.com/juju/3.6/reference/storage.md#storage)         |
| Port group / network            | Network spaces and placement targets (roughly)                         |
| Cluster/resource pool           | Placement target (`zones`)                                             |

<a id="vsphere-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: vsphere
    auth-types:
      - <auth-type>                # See Authentication types below
    endpoint: <vsphere-vcenter-url>  # vCenter API endpoint
    config:                        # Optional: model config defaults
      <config-key>: <value>        # See Configuration keys below
```

<a id="vsphere-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-vsphere-cloud>        # Cloud name as defined above
    <credential-name>:             # User-defined credential name
      auth-type: <auth-type>       # userpass (the only type)
      <attribute>: <value>         # Auth-type-specific attributes (see below)
```

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

### Authentication types

VMware vSphere supports the following authentication types:

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

#### `userpass`

Attributes:

- `user`: The username to authenticate with (required).
- `password`: The password to authenticate with (required).
- `vmfolder`: The folder to add VMs from the model (optional).

<a id="vsphere-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="vsphere-controller-bootstrap-behavior"></a>

### Bootstrap behavior

Creates a controller VM on vSphere by cloning from a template and waiting for provisioning tasks to complete.

Bootstrap downloads a cloud image to the client, uploads it to the ESX host, and creates a template. This process can be slow depending on network connection. Using pre-created templates speeds up bootstrap and machine deployment.

#### TIP
Bootstrap with cloud-specific model-configuration keys `datastore` and `primary-network` to avoid ambiguity.

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

### Resources created at bootstrap

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

**Compute**

- **VM folder hierarchy**: Creates folder `Juju Controller (<controller-uuid>)` with nested structure `<vm-folder>/Juju Controller (UUID)/Model "name" (UUID)/`. Folders enable cleanup by controller/model.
- **Template cache**: Creates `Juju Controller (<uuid>)/templates/<os>_<track>/` folder. Templates named `juju-template-<sha256>` with architecture tag in extra config.
- **Controller VM**: Created by cloning from a template VM. Disk extended if needed. Hardware upgraded if `force-vm-hardware-version` is specified. Powered on after provisioning.
- **Resource pool placement**: VM placed in resource pool specified by availability zone constraint. Must match compute resource hosting the datastore.

**Networking**

- **Network devices**: Primary network interface (eth0) on `primary-network` (default: “VM Network”) with DHCP. Optional external network interface (eth1) if `external-network` configured.

**Storage**

- **Root disk**: VMDK from template, extended post-clone if constraint specifies larger size. Datastore selected from compute resource’s accessible datastores.

<a id="vsphere-controller-template-management"></a>

### Template management

Templates are created from OVA imports with image integrity verification and stored for reuse. Reusing templates speeds up subsequent bootstrap and machine creation.

See more: [Appendix: Using templates](#vsphere-appendix-using-templates)

<a id="vsphere-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="vsphere-model-configuration-keys"></a>

### Configuration keys

VMware vSphere 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):

**Compute**

<a id="vsphere-model-force-vm-hardware-version"></a>
- **`force-vm-hardware-version`**: The HW compatibility version to use when cloning a VM template to create a VM. The version must be supported by the remote compute resource, and greater than or equal to the template’s version. Type: `int`. Default: `0`.

**Networking**

<a id="vsphere-model-primary-network"></a>
- **`primary-network`**: The primary network that VMs will be connected to. If this is not specified, Juju will look for a network named “VM Network”. Type: `string`. Default: none.

<a id="vsphere-model-external-network"></a>
- **`external-network`**: An external network that VMs will be connected to. The resulting IP address for a VM will be used as its public address. Type: `string`. Default: `""`.

**Storage**

<a id="vsphere-model-datastore"></a>
- **`datastore`**: The datastore in which to create VMs. If this is not specified, the process will abort unless there is only one datastore available. Type: `string`. Default: none.

<a id="vsphere-model-disk-provisioning-type"></a>
- **`disk-provisioning-type`**: Specify how the disk should be provisioned when cloning the VM template. Allowed values: `thin`, `thick` (default), `thick-lazy-zero`. Type: `string`. Default: `"thick"`.

<a id="vsphere-model-enable-disk-uuid"></a>
- **`enable-disk-uuid`**: Expose consistent disk UUIDs to the VM, equivalent to `disk.EnableUUID`. Enables consistent `/dev/disk/by-id/` paths in guest OS. Type: `bool`. Default: `true`.

<a id="vsphere-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="vsphere-machine-constraints"></a>

### Constraints

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

**Compute**

- [arch](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-arch). Valid values: `amd64`.
- [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)
- [cpu-power](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-cpu-power)
- [instance-type](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-instance-type)
- [mem](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-mem)

**Networking**

- [zones](https://documentation.ubuntu.com/juju/3.6/reference/constraint.md#constraint-zones). Specifies resource pools within a host or cluster. Examples: `zones=myhost`, `zones=myfolder/myhost`, `zones=mycluster/mypool`, `zones=mycluster/myparent/mypool`.

**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). Specifies the datastore for the root disk.

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

### Placement directives

VMware vSphere 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): Valid values: `<cluster|host>`.

#### CAUTION
If your topology has a cluster without a host, Juju will see this as an availability zone and may fail silently. To solve this, either ensure the host is within the cluster, or use a placement directive: `juju bootstrap vsphere/<datacenter> <controllername> --to zone=<cluster|host>`.

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

### Resources created per machine

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

**Compute**

- **VM**: Created by cloning from a template. Stored in the controller/model folder hierarchy.
- **Hardware resources**: Memory, CPU cores, CPU power from constraints. Hardware version optionally upgraded via `force-vm-hardware-version` model config.
- **Resource pool placement**: VM placed in resource pool specified by availability zone constraint.
- **Tags & metadata**: Juju writes controller/model metadata to VM extra config to support inventory and cleanup operations.
- **Additional packages**: Cloud-init installs `open-vm-tools` and `iptables-persistent`.

**Networking**

- **Network devices**: Primary interface (eth0) on `primary-network` with DHCP, MAC generated. Optional external interface (eth1) on `external-network` with DHCP, MAC generated. Cloud-init network config added for both interfaces.

**Storage**

- **Root disk**: VMDK from template, extended post-clone if constraint specifies larger size. Provisioning type: `thin`, `thick`, or `thick-lazy-zero` via `disk-provisioning-type` config. Datastore selected from compute resource’s accessible datastores (must be explicit if multiple available).

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

### Networking behavior

- **Network selection**: Primary network from `primary-network` model config (default: “VM Network”). Optional external network from `external-network` config. Port groups referenced by network name string.
- **IP assignment**: DHCP from guest OS. No static IP support in provider. Cloud-init configures interfaces with DHCP.
- **Public/private addressing**: Primary network provides private/internal addressing. External network (if configured) provides public address (used as public address by Juju).
- **Port groups/VLANs**: No explicit VLAN configuration. Relies on vSphere port group mapping.

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

### Storage behavior

- **VMDK only**: All storage operations use VMDK provisioning from templates. Only root disk is supported – no secondary volumes, snapshots, or persistent volume creation.
- **Datastore selection**: Must be specified via `datastore` model config if multiple datastores are available; otherwise bootstrap aborts.
- **Disk provisioning type**: Configurable via `disk-provisioning-type` model config (`thin`, `thick` (default), or `thick-lazy-zero`).

<a id="vsphere-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)

VMware vSphere has no cloud-specific storage providers. All storage operations use VMDK provisioning from templates – see [Storage behavior](#vsphere-machine-storage-behavior).

<a id="vsphere-appendix-using-templates"></a>

## Appendix: Using templates

To speed up bootstrap and deploy, you can use VM templates already created in your vSphere. Templates can be created by hand on your vSphere, or created from an existing VM.

Examples assume that the templates are in directory `$DATA_STORE/templates`.

**Via simplestreams:**

```bash
mkdir -p $HOME/simplestreams
juju-metadata generate-image -d $HOME/simplestreams/ -i "templates/juju-focal-template" --base ubuntu@22.04 -r $DATA_STORE -u $CLOUD_ENDPOINT
juju-metadata generate-image -d $HOME/simplestreams/ -i "templates/juju-noble-template" --base ubuntu@24.04 -r $DATA_STORE -u $CLOUD_ENDPOINT
juju bootstrap --metadata-source $HOME/image-streams vsphere
```

**Bootstrap with specific template:**

```bash
juju bootstrap vsphere --bootstrap-image="templates/focal-test-template" --bootstrap-base ubuntu@22.04 --bootstrap-constraints "arch=amd64"
```

**Using add-image:**

```bash
juju metadata add-image templates/bionic-test-template --base ubuntu@22.04
```

See more: [Discourse | Add custom machine images with the juju metadata command](https://discourse.charmhub.io/t/new-feature-in-juju-2-8-add-custom-machine-images-with-the-juju-metadata-command/3171)
