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

Fix/query params #12468

Closed
wants to merge 12 commits into from
Closed
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Consider the following aspects to ensure that your LXD installation is secure:
- Keep your operating system up-to-date and install all available security patches.
- Use only supported LXD versions (LTS releases or monthly feature releases).
- Restrict access to the LXD daemon and the remote API.
- Do not use privileged containers unless required. If you use privileged containers, put appropriate security measures in place. See the [LXC security page](https://linuxcontainers.org/lxc/security/) for more information.
- Do not use privileged containers unless required. If you use privileged containers, put appropriate security measures in place. See the [LXD security page](https://documentation.ubuntu.com/lxd/en/latest/explanation/security/) for more information.
- Configure your network interfaces to be secure.
<!-- Include end security -->

Expand Down
8 changes: 7 additions & 1 deletion client/lxd_storage_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,10 @@ func (r *ProtocolLXD) CopyStoragePoolVolume(pool string, source InstanceServer,
return nil, fmt.Errorf("Failed to get destination connection info: %w", err)
}

clusterInternalVolumeCopy := r.CheckExtension("cluster_internal_custom_volume_copy") == nil

// Copy the storage pool volume locally.
if destInfo.URL == sourceInfo.URL && destInfo.SocketPath == sourceInfo.SocketPath && (volume.Location == r.clusterTarget || (volume.Location == "none" && r.clusterTarget == "")) {
if destInfo.URL == sourceInfo.URL && destInfo.SocketPath == sourceInfo.SocketPath && (volume.Location == r.clusterTarget || (volume.Location == "none" && r.clusterTarget == "") || clusterInternalVolumeCopy) {
// Project handling
if destInfo.Project != sourceInfo.Project {
if !r.HasExtension("storage_api_project") {
Expand All @@ -566,6 +568,10 @@ func (r *ProtocolLXD) CopyStoragePoolVolume(pool string, source InstanceServer,
req.Source.Project = sourceInfo.Project
}

if clusterInternalVolumeCopy {
req.Source.Location = sourceInfo.Target
}

// Send the request
op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s", url.PathEscape(pool), url.PathEscape(volume.Type)), req, "", true)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2312,3 +2312,9 @@ no effect on existing devices.
This API extension indicates that the `/1.0/operations/{id}/wait` endpoint exists on the server. This indicates to the client
that the endpoint can be used to wait for an operation to complete rather than waiting for an operation event via the
`/1.0/events` endpoint.

## `cluster_internal_custom_volume_copy`

This extension adds support for copying and moving custom storage volumes within a cluster with a single API call.
Calling `POST /1.0/storage-pools/<pool>/custom?target=<target>` will copy the custom volume specified in the `source` part of the request.
Calling `POST /1.0/storage-pools/<pool>/custom/<volume>?target=<target>` will move the custom volume from the source, specified in the `source` part of the request, to the target.
25 changes: 21 additions & 4 deletions doc/howto/network_bridge_firewalld.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,12 @@ For example:
sudo firewall-cmd --zone=trusted --change-interface=lxdbr0 --permanent
sudo firewall-cmd --reload

<!-- Include start warning -->

```{warning}
<!-- Include start warning -->
The commands given above show a simple example configuration.
Depending on your use case, you might need more advanced rules and the example configuration might inadvertently introduce a security risk.
```

<!-- Include end warning -->
```

### UFW: Add rules for the bridge

Expand All @@ -93,12 +91,31 @@ For example:
sudo ufw route allow in on lxdbr0
sudo ufw route allow out on lxdbr0

````{warning}
% Repeat warning from above
```{include} network_bridge_firewalld.md
:start-after: <!-- Include start warning -->
:end-before: <!-- Include end warning -->
```

Here's an example for more restrictive firewall rules that limit access from the guests to the host to only DHCP and DNS and allow all outbound connections:

```
# allow the guest to get an IP from the LXD host
sudo ufw allow in on lxdbr0 to any port 67 proto udp
sudo ufw allow in on lxdbr0 to any port 547 proto udp

# allow the guest to resolve host names from the LXD host
sudo ufw allow in on lxdbr0 to any port 53

# allow the guest to have access to outbound connections
CIDR4="$(lxc network get lxdbr0 ipv4.address | sed 's|\.[0-9]\+/|.0/|')"
CIDR6="$(lxc network get lxdbr0 ipv6.address | sed 's|:[0-9]\+/|:/|')"
sudo ufw route allow in on lxdbr0 from "${CIDR4}"
sudo ufw route allow in on lxdbr0 from "${CIDR6}"
```
````

(network-lxd-docker)=
## Prevent connectivity issues with LXD and Docker

Expand Down
7 changes: 7 additions & 0 deletions doc/rest-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5827,6 +5827,8 @@ definitions:
example: foo
type: string
x-go-name: Project
source:
$ref: '#/definitions/StorageVolumeSource'
target:
$ref: '#/definitions/StorageVolumePostTarget'
volume_only:
Expand Down Expand Up @@ -5981,6 +5983,11 @@ definitions:
example: X509 PEM certificate
type: string
x-go-name: Certificate
location:
description: What cluster member this record was found on
example: lxd01
type: string
x-go-name: Location
mode:
description: Whether to use pull or push mode (for migration)
example: pull
Expand Down
4 changes: 2 additions & 2 deletions lxd/cluster/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ var ConfigSchema = config.Schema{
// type: bool
// scope: global
// shortdesc: Whether to set `Access-Control-Allow-Credentials`
"core.https_allowed_credentials": {Type: config.Bool},
"core.https_allowed_credentials": {Type: config.Bool, Default: "false"},

// lxdmeta:generate(entity=server, group=core, key=core.https_trusted_proxy)
// Specify a comma-separated list of IP addresses of trusted servers that provide the client's address through the proxy connection header.
Expand Down Expand Up @@ -524,7 +524,7 @@ var ConfigSchema = config.Schema{
// type: bool
// scope: global
// shortdesc: Whether to automatically trust clients signed by the CA
"core.trust_ca_certificates": {Type: config.Bool},
"core.trust_ca_certificates": {Type: config.Bool, Default: "false"},

// lxdmeta:generate(entity=server, group=candid-and-rbac, key=candid.api_key)
//
Expand Down
31 changes: 31 additions & 0 deletions lxd/db/storage_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -953,3 +953,34 @@ func (c *ClusterTx) GetStorageVolumeURIs(ctx context.Context, project string) ([

return uris, nil
}

// UpdateStorageVolumeNode changes the name of a storage volume and the cluster member hosting it.
// It's meant to be used when moving a storage volume backed by ceph from one cluster node to another.
func (c *ClusterTx) UpdateStorageVolumeNode(ctx context.Context, projectName string, oldName string, newName string, newMemberName string, poolID int64, volumeType int) error {
volume, err := c.GetStoragePoolVolume(ctx, poolID, projectName, volumeType, oldName, false)
if err != nil {
return err
}

member, err := c.GetNodeByName(ctx, newMemberName)
if err != nil {
return fmt.Errorf("Failed to get new member %q info: %w", newMemberName, err)
}

stmt := "UPDATE storage_volumes SET node_id=?, name=? WHERE id=?"
result, err := c.tx.Exec(stmt, member.ID, newName, volume.ID)
if err != nil {
return fmt.Errorf("Failed to update volumes's name and member ID: %w", err)
}

n, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("Failed to get rows affected by volume update: %w", err)
}

if n != 1 {
return fmt.Errorf("Unexpected number of updated rows in storage_volumes table: %d", n)
}

return nil
}
Loading