Skip to content

Commit

Permalink
Merge pull request #1415 from presztak/initial_owner_custom_volume
Browse files Browse the repository at this point in the history
Add ability to set the initial owner of a custom volume
  • Loading branch information
stgraber authored Nov 25, 2024
2 parents 2101720 + b65d99e commit c29c1f0
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 2 deletions.
10 changes: 10 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2646,3 +2646,13 @@ As part of this, the following configuration options have been added:
## `custom_volume_refresh_exclude_older_snapshots`

This adds support for excluding source snapshots earlier than latest target snapshot.

## `storage_initial_owner`

This adds ability to set the initial owner of a custom volume.

The following configuration options have been added:

* `initial.gid`
* `initial.mode`
* `initial.uid`
3 changes: 3 additions & 0 deletions doc/reference/storage_btrfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ Key | Type | Default | Descr

Key | Type | Condition | Default | Description
:-- | :--- | :-------- | :------ | :----------
`initial.gid` | int | custom volume with content type `filesystem` | same as `volume.initial.uid` or `0` | GID of the volume owner in the instance
`initial.mode` | int | custom volume with content type `filesystem` | same as `volume.initial.mode` or `711` | Mode of the volume in the instance
`initial.uid` | int | custom volume with content type `filesystem` | same as `volume.initial.gid` or `0` | UID of the volume owner in the instance
`security.shared` | bool | custom block volume | same as `volume.security.shared` or `false` | Enable sharing the volume across multiple instances
`security.shifted` | bool | custom volume | same as `volume.security.shifted` or `false` | {{enable_ID_shifting}}
`security.unmapped` | bool | custom volume | same as `volume.security.unmapped` or `false` | Disable ID mapping for the volume
Expand Down
3 changes: 3 additions & 0 deletions doc/reference/storage_ceph.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ Key | Type | Condition | Default
:-- | :--- | :-------- | :------ | :----------
`block.filesystem` | string | block-based volume with content type `filesystem` | same as `volume.block.filesystem` | {{block_filesystem}}
`block.mount_options` | string | block-based volume with content type `filesystem` | same as `volume.block.mount_options` | Mount options for block-backed file system volumes
`initial.gid` | int | custom volume with content type `filesystem` | same as `volume.initial.uid` or `0` | GID of the volume owner in the instance
`initial.mode` | int | custom volume with content type `filesystem` | same as `volume.initial.mode` or `711` | Mode of the volume in the instance
`initial.uid` | int | custom volume with content type `filesystem` | same as `volume.initial.gid` or `0` | UID of the volume owner in the instance
`security.shared` | bool | custom block volume | same as `volume.security.shared` or `false` | Enable sharing the volume across multiple instances
`security.shifted` | bool | custom volume | same as `volume.security.shifted` or `false` | {{enable_ID_shifting}}
`security.unmapped` | bool | custom volume | same as `volume.security.unmapped` or `false` | Disable ID mapping for the volume
Expand Down
3 changes: 3 additions & 0 deletions doc/reference/storage_cephfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ Key | Type | Default

Key | Type | Condition | Default | Description
:-- | :--- | :-------- | :------ | :----------
`initial.gid` | int | custom volume with content type `filesystem` | same as `volume.initial.uid` or `0` | GID of the volume owner in the instance
`initial.mode` | int | custom volume with content type `filesystem` | same as `volume.initial.mode` or `711` | Mode of the volume in the instance
`initial.uid` | int | custom volume with content type `filesystem` | same as `volume.initial.gid` or `0` | UID of the volume owner in the instance
`security.shared` | bool | custom block volume | same as `volume.security.shared` or `false` | Enable sharing the volume across multiple instances
`security.shifted` | bool | custom volume | same as `volume.security.shifted` or `false` | {{enable_ID_shifting}}
`security.unmapped` | bool | custom volume | same as `volume.security.unmapped` or `false` | Disable ID mapping for the volume
Expand Down
3 changes: 3 additions & 0 deletions doc/reference/storage_dir.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ Key | Type | Default

Key | Type | Condition | Default | Description
:-- | :--- | :-------- | :------ | :----------
`initial.gid` | int | custom volume with content type `filesystem` | same as `volume.initial.uid` or `0` | GID of the volume owner in the instance
`initial.mode` | int | custom volume with content type `filesystem` | same as `volume.initial.mode` or `711` | Mode of the volume in the instance
`initial.uid` | int | custom volume with content type `filesystem` | same as `volume.initial.gid` or `0` | UID of the volume owner in the instance
`security.shared` | bool | custom block volume | same as `volume.security.shared` or `false` | Enable sharing the volume across multiple instances
`security.shifted` | bool | custom volume | same as `volume.security.shifted` or `false` | {{enable_ID_shifting}}
`security.unmapped` | bool | custom volume | same as `volume.security.unmapped` or `false` | Disable ID mapping for the volume
Expand Down
3 changes: 3 additions & 0 deletions doc/reference/storage_lvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ Key | Type | Condition
:-- | :--- | :------ | :------ | :----------
`block.filesystem` | string | block-based volume with content type `filesystem` | same as `volume.block.filesystem` | {{block_filesystem}}
`block.mount_options` | string | block-based volume with content type `filesystem` | same as `volume.block.mount_options` | Mount options for block-backed file system volumes
`initial.gid` | int | custom volume with content type `filesystem` | same as `volume.initial.uid` or `0` | GID of the volume owner in the instance
`initial.mode` | int | custom volume with content type `filesystem` | same as `volume.initial.mode` or `711` | Mode of the volume in the instance
`initial.uid` | int | custom volume with content type `filesystem` | same as `volume.initial.gid` or `0` | UID of the volume owner in the instance
`lvm.stripes` | string | | same as `volume.lvm.stripes` | Number of stripes to use for new volumes (or thin pool volume)
`lvm.stripes.size` | string | | same as `volume.lvm.stripes.size` | Size of stripes to use (at least 4096 bytes and multiple of 512 bytes)
`security.shifted` | bool | custom volume | same as `volume.security.shifted` or `false` | {{enable_ID_shifting}}
Expand Down
3 changes: 3 additions & 0 deletions doc/reference/storage_zfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ Key | Type | Condition | Default
:-- | :--- | :-------- | :------ | :----------
`block.filesystem` | string | block-based volume with content type `filesystem` (`zfs.block_mode` enabled) | same as `volume.block.filesystem` | {{block_filesystem}}
`block.mount_options` | string | block-based volume with content type `filesystem` (`zfs.block_mode` enabled) | same as `volume.block.mount_options` | Mount options for block-backed file system volumes
`initial.gid` | int | custom volume with content type `filesystem` | same as `volume.initial.uid` or `0` | GID of the volume owner in the instance
`initial.mode` | int | custom volume with content type `filesystem` | same as `volume.initial.mode` or `711` | Mode of the volume in the instance
`initial.uid` | int | custom volume with content type `filesystem` | same as `volume.initial.gid` or `0` | UID of the volume owner in the instance
`security.shared` | bool | custom block volume | same as `volume.security.shared` or `false` | Enable sharing the volume across multiple instances
`security.shifted` | bool | custom volume | same as `volume.security.shifted` or `false` | {{enable_ID_shifting}}
`security.unmapped` | bool | custom volume | same as `volume.security.unmapped` or `false` | Disable ID mapping for the volume
Expand Down
41 changes: 40 additions & 1 deletion internal/server/storage/drivers/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"slices"
"strconv"
"strings"

internalInstance "github.com/lxc/incus/v6/internal/instance"
Expand Down Expand Up @@ -233,8 +234,46 @@ func (v Volume) EnsureMountPath() error {
revert.Add(func() { _ = os.Remove(volPath) })
}

// Set very restrictive mode 0100 for non-custom, non-bucket and non-image volumes.
mode := os.FileMode(0711)
if v.volType == VolumeTypeCustom && v.contentType == ContentTypeFS {
initialMode := v.ExpandedConfig("initial.mode")
if initialMode != "" {
m, err := strconv.ParseInt(initialMode, 8, 0)
if err != nil {
return err
}

mode = os.FileMode(m)
}

uid, gid := 0, 0
var err error
initialUID := v.ExpandedConfig("initial.uid")
if initialUID != "" {
uid, err = strconv.Atoi(initialUID)
if err != nil {
return err
}
}

initialGID := v.ExpandedConfig("initial.gid")
if initialGID != "" {
gid, err = strconv.Atoi(initialGID)
if err != nil {
return err
}
}

// Set the owner of a custom volume if uid or gid have been set.
if uid != 0 || gid != 0 {
err = os.Chown(volPath, uid, gid)
if err != nil {
return err
}
}
}

// Set very restrictive mode 0100 for non-custom, non-bucket and non-image volumes.
if v.volType != VolumeTypeCustom && v.volType != VolumeTypeImage && v.volType != VolumeTypeBucket {
mode = os.FileMode(0100)
}
Expand Down
5 changes: 4 additions & 1 deletion internal/server/storage/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,10 +491,13 @@ func poolAndVolumeCommonRules(vol *drivers.Volume) map[string]func(string) error
"snapshots.pattern": validate.IsAny,
}

// security.shifted and security.unmapped are only relevant for custom filesystem volumes.
// Options relevant for custom filesystem volumes.
if (vol == nil) || (vol != nil && vol.Type() == drivers.VolumeTypeCustom && vol.ContentType() == drivers.ContentTypeFS) {
rules["security.shifted"] = validate.Optional(validate.IsBool)
rules["security.unmapped"] = validate.Optional(validate.IsBool)
rules["initial.uid"] = validate.Optional(validate.IsInt64)
rules["initial.gid"] = validate.Optional(validate.IsInt64)
rules["initial.mode"] = validate.Optional(validate.IsInt64)
}

// security.shared is only relevant for custom block volumes.
Expand Down
1 change: 1 addition & 0 deletions internal/version/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ var APIExtensions = []string{
"instances_scriptlet_get_instances_count",
"cluster_rebalance",
"custom_volume_refresh_exclude_older_snapshots",
"storage_initial_owner",
}

// APIExtensionsCount returns the number of available API extensions.
Expand Down
22 changes: 22 additions & 0 deletions test/suites/storage_volume_initial_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ test_storage_volume_initial_config() {
incus delete c --force
fi

# Test initial owner of a custom volume configuration options.
incus storage volume create "${pool}" testvolume1
incus storage volume create "${pool}" testvolume2 initial.uid=101 initial.gid=101 initial.mode=0700

incus launch testimage c

incus storage volume attach "${pool}" testvolume1 c /testvolume1
incus storage volume attach "${pool}" testvolume2 c /testvolume2

[ "$(incus exec c -- stat -c %u:%g /testvolume1 )" = "0:0" ]
[ "$(incus exec c -- stat -c %a /testvolume1 )" = "711" ]
[ "$(incus exec c -- stat -c %u:%g /testvolume2 )" = "101:101" ]
[ "$(incus exec c -- stat -c %a /testvolume2 )" = "700" ]

incus storage volume detach "${pool}" testvolume1 c
incus storage volume detach "${pool}" testvolume2 c

incus delete c --force

incus storage volume delete "${pool}" testvolume1
incus storage volume delete "${pool}" testvolume2

# Cleanup
incus profile delete "${profile}"

Expand Down

0 comments on commit c29c1f0

Please sign in to comment.