Skip to content

Commit

Permalink
incus/init: Add support for storage volumes in preseed init
Browse files Browse the repository at this point in the history
Add support for configuring storage volumes in preseed init.
  • Loading branch information
megheaiulian committed Jan 21, 2025
1 parent 737cb4d commit 38cb660
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 0 deletions.
64 changes: 64 additions & 0 deletions client/incus_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/gorilla/websocket"

"github.com/lxc/incus/v6/shared/api"
"github.com/lxc/incus/v6/shared/util"

localtls "github.com/lxc/incus/v6/shared/tls"
)

Expand Down Expand Up @@ -405,6 +407,68 @@ func (r *ProtocolIncus) ApplyServerPreseed(config api.InitPreseed) error {
}
}

// Apply storage volumes configuration.
applyStorageVolume := func(storageVolume api.InitStorageVolumesProjectPost) error {
// Get the current storageVolume.
currentStorageVolume, etag, err := r.UseProject(storageVolume.Project).GetStoragePoolVolume(storageVolume.Pool, storageVolume.Type, storageVolume.Name)

if err != nil {
// Create the storage volume if it doesn't exist.
err := r.UseProject(storageVolume.Project).CreateStoragePoolVolume(storageVolume.Pool, storageVolume.StorageVolumesPost)
if err != nil {
return fmt.Errorf("Failed to create storage volume %q in project %q on pool %q: %w", storageVolume.Name, storageVolume.Project, storageVolume.Pool, err)
}
} else {
// Quick check.
if currentStorageVolume.Type != storageVolume.Type {
return fmt.Errorf("Storage volume %q in project %q is of type %q instead of %q", currentStorageVolume.Name, storageVolume.Project, currentStorageVolume.Type, storageVolume.Type)
}

// Prepare the update.
newStorageVolume := api.StorageVolumePut{}
err = util.DeepCopy(currentStorageVolume.Writable(), &newStorageVolume)
if err != nil {
return fmt.Errorf("Failed to copy configuration of storage volume %q in project %q: %w", storageVolume.Name, storageVolume.Project, err)
}

// Description override.
if storageVolume.Description != "" {
newStorageVolume.Description = storageVolume.Description
}

// Config overrides.
for k, v := range storageVolume.Config {
newStorageVolume.Config[k] = fmt.Sprintf("%v", v)
}

// Apply it.
err = r.UseProject(storageVolume.Project).UpdateStoragePoolVolume(storageVolume.Pool, storageVolume.Type, currentStorageVolume.Name, newStorageVolume, etag)
if err != nil {
return fmt.Errorf("Failed to update storage volume %q in project %q: %w", storageVolume.Name, storageVolume.Project, err)
}
}

return nil
}

// Apply storage volumes in the default project before other projects config.
for i := range config.Server.StorageVolumes {
// Populate default project if not specified.
if config.Server.StorageVolumes[i].Project == "" {
config.Server.StorageVolumes[i].Project = api.ProjectDefaultName
}
// Populate default type if not specified.
if config.Server.StorageVolumes[i].Type == "" {
config.Server.StorageVolumes[i].Type = "custom"
}

err := applyStorageVolume(config.Server.StorageVolumes[i])
if err != nil {
return err
}

}

// Apply profile configuration.
if config.Server.Profiles != nil && len(config.Server.Profiles) > 0 {
// Get the list of profiles.
Expand Down
3 changes: 3 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2689,3 +2689,6 @@ This extends the QEMU scriptlet feature by allowing to modify QEMU configuration
## `network_bridge_acl_devices`

This adds support for device ACLs when attached to a bridged network.

## `init_preseed_storage_volumes`
This API extension provides the ability to configure storage volumes in preseed init.
5 changes: 5 additions & 0 deletions doc/howto/initialize.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ storage_pools:
config:
source: my-zfs-pool/my-zfs-dataset

# Storage volumes
storage_volumes:
- name: my-vol
pool: data

# Network devices
networks:
- name: incus-my-bridge
Expand Down
1 change: 1 addition & 0 deletions internal/version/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ var APIExtensions = []string{
"console_force",
"network_ovn_state_addresses",
"network_bridge_acl_devices",
"init_preseed_storage_volumes",
}

// APIExtensionsCount returns the number of available API extensions.
Expand Down
19 changes: 19 additions & 0 deletions shared/api/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ type InitLocalPreseed struct {
// Example: local dir storage pool
StoragePools []StoragePoolsPost `json:"storage_pools" yaml:"storage_pools"`

// Storage Volumes to add
// Example: local dir storage volume
StorageVolumes []InitStorageVolumesProjectPost `json:"storage_volumes" yaml:"storage_volumes"`

// Profiles to add
// Example: "default" profile with a root disk device
Profiles []ProfilesPost `json:"profiles" yaml:"profiles"`
Expand All @@ -48,6 +52,21 @@ type InitNetworksProjectPost struct {
Project string
}

// InitStorageVolumesProjectPost represents the fields of a new storage volume along with its associated pool.
//
// swagger:model
//
// API extension: init_preseed_storage_volumes.
type InitStorageVolumesProjectPost struct {
StorageVolumesPost `yaml:",inline"`
// Storage pool in which the volume will reside
// Example: "default"
Pool string
// Project in which the volume will reside
// Example: "default"
Project string
}

// InitClusterPreseed represents initialization configuration for the cluster.
//
// swagger:model
Expand Down
6 changes: 6 additions & 0 deletions test/suites/init_preseed.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ test_init_preseed() {
INCUS_DIR=${INCUS_INIT_DIR}

storage_pool="incustest-$(basename "${INCUS_DIR}")-data"
storage_volume="${storage_pool}-volume"
# In case we're running against the ZFS backend, let's test
# creating a zfs storage pool, otherwise just use dir.
if [ "$incus_backend" = "zfs" ]; then
Expand All @@ -36,6 +37,9 @@ storage_pools:
driver: $driver
config:
source: $source
storage_volumes:
- name: ${storage_volume}
pool: ${storage_pool}
networks:
- name: inct$$
type: bridge
Expand Down Expand Up @@ -66,6 +70,7 @@ EOF
incus network list | grep -q "inct$$"
incus storage list | grep -q "${storage_pool}"
incus storage show "${storage_pool}" | grep -q "$source"
incus storage volume list "${storage_pool}" | grep -q "${storage_volume}"
incus profile list | grep -q "test-profile"
incus profile show default | grep -q "pool: ${storage_pool}"
incus profile show test-profile | grep -q "limits.memory: 2GiB"
Expand All @@ -74,6 +79,7 @@ EOF
printf 'config: {}\ndevices: {}' | incus profile edit default
incus profile delete test-profile
incus network delete inct$$
incus storage volume delete "${storage_pool}" "${storage_volume}"
incus storage delete "${storage_pool}"

if [ "$incus_backend" = "zfs" ]; then
Expand Down

0 comments on commit 38cb660

Please sign in to comment.