Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage: Per project image and backup storage options #14582

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

boltmark
Copy link
Contributor

@boltmark boltmark commented Dec 4, 2024

This PR adds support for per-project image and backup storage options. We maintain the option to select storage options at the server level, and add a more fine-grained option to select this at the project level.


Overview: We currently support configuration of storage.backups_volume and storage.images_volume on the server level. We would like to make this option more granular by introducing the ability to configure it on a per-project basis. We will continue to support the server-level configuration, but project-level configuration will take priority.

If these options are configured on a given project, then all backup/image tarballs created for resources within said project will be stored in the selected volume. If not, then we will default to the config set at the server level (if any).

Implementation:
We will maintain support for storage.[images,backups]_volume on the server level, and add this config option at the project level. Users may specify storage.images_volume and storage.backups_volume at the project level, which will ensure images or backups for the given project are stored on the specified storage volume. These config keys can be changed, and data will move accordingly.

Images and backups will continue to be stored in the images and backups directory. However, we need some way to be able to store images and backups for a certain projects on a specified storage volume. We will follow the current pattern of using a symlink to the mountpoint of the specified volume. Special directories backups/daemon and images/daemon will be created, and will function exactly as the images and backups directories function now -- to store images and backups that are not project specific. If storage.[images,backups]_volume is set at the server level, then these will be symlinked to the selected volume's mountpoint.

For each project that is created, directories images/project_X and backups/project_X will also be created, which will store images and backups for the given project. If storage.[images,backups]_volume is set at the project level, then the directory will be symlinked to the mountpoint of the selected storage volume. If not set on the project level, then the directory will be symlinked to [images,backups]/daemon/project_X. This follows the current implementation at the server level. When project-level storage.[images,backups]_volume is changed or unset, data is moved accordingly.

@github-actions github-actions bot added Documentation Documentation needs updating API Changes to the REST API labels Dec 4, 2024
// Create images and backups directories, and symlink to the daemon path by default.
imageDaemonPath := shared.VarPath("images", "daemon", fmt.Sprintf("project_%s", project.Name))
imageSymPath := shared.VarPath("images", fmt.Sprintf("project_%s", project.Name))
err = os.MkdirAll(imageDaemonPath, 0700)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
if err != nil {
return response.InternalError(fmt.Errorf("Failed to create directory %q: %w", imageDaemonPath, err))
}
err = os.Symlink(imageDaemonPath, imageSymPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
if err != nil {
return response.InternalError(fmt.Errorf("Failed to create directory %q: %w", imageDaemonPath, err))
}
err = os.Symlink(imageDaemonPath, imageSymPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
backupsSymPath := shared.VarPath("backups", fmt.Sprintf("project_%s", project.Name))
backupsCustomPath := filepath.Join(backupsSymPath, "custom")
backupsInstancesPath := filepath.Join(backupsSymPath, "instances")
err = os.MkdirAll(backupsDaemonPath, 0700)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
if err != nil {
return response.InternalError(fmt.Errorf("Failed to create directory %q: %w", backupsDaemonPath, err))
}
err = os.Symlink(backupsDaemonPath, backupsSymPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
if err != nil {
return response.InternalError(fmt.Errorf("Failed to create directory %q: %w", backupsCustomPath, err))
}
err = os.MkdirAll(backupsInstancesPath, 0700)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
if err != nil {
return fmt.Errorf("Failed to create the new symlink at %q: %w", shared.VarPath(storageType), err)
// Create the new symlink.
err = os.Symlink(destPath, shared.VarPath(storageType, "daemon"))

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
}

// Create the new symlink.
err = os.Symlink(destPath, shared.VarPath(storageType, fmt.Sprintf("project_%s", projectName)))

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if err != nil {
return fmt.Errorf("Failed to create the new symlink at %q: %w", shared.VarPath(storageType), err)
// Create the new symlink.
err = os.Symlink(destPath, shared.VarPath(storageType, "daemon"))

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
}

// Create the new symlink.
err = os.Symlink(destPath, shared.VarPath(storageType, fmt.Sprintf("project_%s", projectName)))

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
@@ -2535,3 +2535,7 @@ Adds a new {config:option}`device-unix-hotplug-device-conf:ownership.inherit` co
## `unix_device_hotplug_subsystem_device_option`

Adds a new {config:option}`device-unix-hotplug-device-conf:subsystem` configuration option for `unix-hotplug` devices. This adds support for detecting `unix-hotplug` devices by subsystem, and can be used in conjunction with {config:option}`device-unix-hotplug-device-conf:productid` and {config:option}`device-unix-hotplug-device-conf:vendorid`.

## `project_daemon_storage`
This introduces two new configuration keys `storage.images_volume` and `storage.backups_volume` to the project level to allow for a storage volume
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This introduces two new configuration keys `storage.images_volume` and `storage.backups_volume` to the project level to allow for a storage volume
This introduces two new configuration keys, `storage.images_volume` and `storage.backups_volume`, to the project level. These keys allow for a storage volume


## `project_daemon_storage`
This introduces two new configuration keys `storage.images_volume` and `storage.backups_volume` to the project level to allow for a storage volume
on an existing pool be used for storing the project-wide images and backups artifacts.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
on an existing pool be used for storing the project-wide images and backups artifacts.
on an existing pool to be used for storing the project-wide images and backups artifacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Changes to the REST API Documentation Documentation needs updating
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants