Merge pull request #4177 from stgraber/more-fixes

Various bugfixes
This commit is contained in:
Stéphane Graber
2026-10-11 12:14:50 -04:00
committed by GitHub
8 changed files with 101 additions and 57 deletions
+28 -47
View File
@@ -163,10 +163,10 @@ func backupCreate(s *state.State, args db.InstanceBackup, sourceInst instance.In
tarWriter := instancewriter.NewInstanceTarWriter(tarPipeWriter, idmapSet)
// Setup tar writer go routine, with optional compression.
tarWriterRes := make(chan error)
var compressErr error
tarWriterRes := make(chan error, 1)
backupProgressWriter := &ioprogress.ProgressWriter{
WriteCloser: tarFileWriter,
Tracker: &ioprogress.ProgressTracker{
Handler: func(value, speed int64) {
_ = op.ExtendMetadata(map[string]any{"create_backup_progress": fmt.Sprintf("%s (%s/s)", units.GetByteSizeString(value, 2), units.GetByteSizeString(speed, 2))})
@@ -177,32 +177,25 @@ func backupCreate(s *state.State, args db.InstanceBackup, sourceInst instance.In
go func(resCh chan<- error) {
l.Debug("Started backup tarball writer")
defer l.Debug("Finished backup tarball writer")
if compress != "none" {
backupProgressWriter.WriteCloser = tarFileWriter
compressErr = compressFile(compress, tarPipeReader, backupProgressWriter)
// If a compression error occurred, close the tarPipeWriter to end the export.
if compressErr != nil {
_ = tarPipeWriter.Close()
}
var err error
if compress != "none" {
err = compressFile(compress, tarPipeReader, backupProgressWriter)
} else {
backupProgressWriter.WriteCloser = tarFileWriter
_, err = util.SafeCopy(backupProgressWriter, tarPipeReader)
}
// On failure, fail any further tarball writes to end the export.
if err != nil {
_ = tarPipeReader.CloseWithError(err)
}
resCh <- err
}(tarWriterRes)
// Write index file.
l.Debug("Adding backup index file")
err = backupWriteIndex(sourceInst, pool, b.OptimizedStorage(), !b.InstanceOnly(), !b.RootOnly(), tarWriter)
// Check compression errors.
if compressErr != nil {
return compressErr
}
// Check backupWriteIndex for errors.
if err != nil {
return fmt.Errorf("Error writing backup index file: %w", err)
}
@@ -522,36 +515,30 @@ func volumeBackupCreate(s *state.State, args db.StoragePoolVolumeBackup, project
tarWriter := instancewriter.NewInstanceTarWriter(tarPipeWriter, nil)
// Setup tar writer go routine, with optional compression.
tarWriterRes := make(chan error)
var compressErr error
tarWriterRes := make(chan error, 1)
go func(resCh chan<- error) {
l.Debug("Started backup tarball writer")
defer l.Debug("Finished backup tarball writer")
if compress != "none" {
compressErr = compressFile(compress, tarPipeReader, fileWriter)
// If a compression error occurred, close the tarPipeWriter to end the export.
if compressErr != nil {
_ = tarPipeWriter.Close()
}
var err error
if compress != "none" {
err = compressFile(compress, tarPipeReader, fileWriter)
} else {
_, err = util.SafeCopy(fileWriter, tarPipeReader)
}
// On failure, fail any further tarball writes to end the export.
if err != nil {
_ = tarPipeReader.CloseWithError(err)
}
resCh <- err
}(tarWriterRes)
// Write index file.
l.Debug("Adding backup index file")
err = volumeBackupWriteIndex(projectName, volumeName, pool, backupRow.OptimizedStorage, !backupRow.VolumeOnly, tarWriter)
// Check compression errors.
if compressErr != nil {
return compressErr
}
// Check backupWriteIndex for errors.
if err != nil {
return fmt.Errorf("Error writing backup index file: %w", err)
}
@@ -781,36 +768,30 @@ func bucketBackupCreate(s *state.State, args db.StoragePoolBucketBackup, project
tarWriter := instancewriter.NewInstanceTarWriter(tarPipeWriter, nil)
// Setup tar writer go routine, with optional compression.
tarWriterRes := make(chan error)
var compressErr error
tarWriterRes := make(chan error, 1)
go func(resCh chan<- error) {
l.Debug("Started backup tarball writer")
defer l.Debug("Finished backup tarball writer")
if compress != "none" {
compressErr = compressFile(compress, tarPipeReader, tarFileWriter)
// If a compression error occurred, close the tarPipeWriter to end the export.
if compressErr != nil {
_ = tarPipeWriter.Close()
}
var err error
if compress != "none" {
err = compressFile(compress, tarPipeReader, tarFileWriter)
} else {
_, err = util.SafeCopy(tarFileWriter, tarPipeReader)
}
// On failure, fail any further tarball writes to end the export.
if err != nil {
_ = tarPipeReader.CloseWithError(err)
}
resCh <- err
}(tarWriterRes)
// Write index file.
l.Debug("Adding backup index file")
err = bucketBackupWriteIndex(projectName, bucketName, pool, tarWriter)
// Check compression errors.
if compressErr != nil {
return compressErr
}
// Check backupWriteIndex for errors.
if err != nil {
return fmt.Errorf("Error writing backup index file: %w", err)
}
@@ -11097,8 +11097,19 @@ func (d *qemu) DeviceEventHandler(runConf *deviceConfig.RunConfig) error {
}
if mount.Size > 0 {
// Resize the active node, which is the top overlay when the disk has snapshots.
nodeName := d.blockNodeName(linux.PathNameEncode(mount.DevName))
blockDevs, err := d.fetchBlockDeviceChain(m, nodeName)
if err != nil {
return err
}
if len(blockDevs) > 0 {
nodeName = blockDevs[len(blockDevs)-1]
}
// Update the size.
err = m.UpdateBlockSize(d.blockNodeName(linux.PathNameEncode(mount.DevName)), mount.Size)
err = m.UpdateBlockSize(nodeName, mount.Size)
if err != nil {
return fmt.Errorf("Failed updating disk size %q: %w", mount.DevName, err)
}
+4
View File
@@ -498,6 +498,10 @@ func ovnAddReferencedACLs(info *api.NetworkACL, referencedACLNames map[string]st
continue // Skip if the subject is an IP address, IP CIDR or IP range.
}
if strings.HasPrefix(subject, "$") {
continue // Skip address set references.
}
// Anything else must be a referenced ACL name.
// Record newly seen referenced ACL into authoritative list.
referencedACLNames[subject] = struct{}{}
+18 -4
View File
@@ -8185,11 +8185,25 @@ func (n *ovn) LoadBalancerUpdate(listenAddress string, req api.NetworkLoadBalanc
reverter.Add(func() {
// Apply old settings to OVN on failure.
portMaps, err := n.loadBalancerValidate(net.ParseIP(curLoadBalancer.ListenAddress), &curLoadBalancer.NetworkLoadBalancerPut)
if err == nil {
vips := n.loadBalancerFlattenVIPs(net.ParseIP(curLoadBalancer.ListenAddress), portMaps)
_ = n.ovnnb.CreateLoadBalancer(context.TODO(), n.getLoadBalancerName(curLoadBalancer.ListenAddress), n.getRouterName(), n.getIntSwitchName(), vips...)
_ = n.forwardBGPSetupPrefixes()
if err != nil {
return
}
vips := n.loadBalancerFlattenVIPs(net.ParseIP(curLoadBalancer.ListenAddress), portMaps)
healthCheck, err := n.getHealthCheck(curLoadBalancer.NetworkLoadBalancerPut)
if err != nil {
return
}
if healthCheck != nil {
for i := range vips {
vips[i].HealthCheck = healthCheck
}
}
_ = n.ovnnb.CreateLoadBalancer(context.TODO(), n.getLoadBalancerName(curLoadBalancer.ListenAddress), n.getRouterName(), n.getIntSwitchName(), vips...)
_ = n.forwardBGPSetupPrefixes()
})
err = n.state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
+17
View File
@@ -9261,6 +9261,23 @@ func (b *backend) qcow2Resize(inst instance.Instance, vol drivers.Volume, size s
return err
}
// Move the GPT alt header to the end of the guest disk.
if vol.IsVMBlock() {
nbdPath, err := drivers.ConnectQemuNbd(volDiskPath, "qcow2", "", false)
if err != nil {
return err
}
defer func() {
_ = drivers.DisconnectQemuNbdWait(nbdPath)
}()
err = drivers.MoveGPTAltHeader(b.logger, nbdPath)
if err != nil {
return err
}
}
return nil
}
@@ -293,9 +293,14 @@ func (d *common) ApplyPatch(name string) error {
// header where possible so that the backup header is where it is expected in case of any corruption with the
// primary header.
func (d *common) moveGPTAltHeader(devPath string) error {
return MoveGPTAltHeader(d.logger, devPath)
}
// MoveGPTAltHeader moves the GPT alternative header to the end of the disk device supplied.
func MoveGPTAltHeader(l logger.Logger, devPath string) error {
path, err := exec.LookPath("sgdisk")
if err != nil {
d.logger.Warn("Skipped moving GPT alternative header to end of disk as sgdisk command not found", logger.Ctx{"dev": devPath})
l.Warn("Skipped moving GPT alternative header to end of disk as sgdisk command not found", logger.Ctx{"dev": devPath})
return nil
}
@@ -321,7 +326,7 @@ func (d *common) moveGPTAltHeader(devPath string) error {
_, err = subprocess.RunCommand(path, "--move-second-header", devPath)
if err == nil {
d.logger.Debug("Moved GPT alternative header to end of disk", logger.Ctx{"dev": devPath})
l.Debug("Moved GPT alternative header to end of disk", logger.Ctx{"dev": devPath})
return nil
}
@@ -131,8 +131,8 @@ func (d *lvm) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Oper
}
}
// Move the GPT alt header to end of disk if needed.
if vol.IsVMBlock() {
// Move the GPT alt header to end of disk if needed (the device holds a qcow2 container when qcow2).
if vol.IsVMBlock() && !IsQcow2Block(vol) {
err = d.moveGPTAltHeader(devPath)
if err != nil {
return err
@@ -919,7 +919,8 @@ func (d *lvm) SetVolumeQuota(vol Volume, size string, allowUnsafeResize bool, op
// Move the VM GPT alt header to end of disk if needed (not needed in unsafe resize mode as it is
// expected the caller will do all necessary post resize actions themselves).
if vol.IsVMBlock() && !allowUnsafeResize {
// The device holds a qcow2 container when qcow2, not the guest disk.
if vol.IsVMBlock() && !allowUnsafeResize && !IsQcow2Block(vol) {
// Activate the volume for resizing.
activated, err := d.activateVolume(vol)
if err != nil {
+11
View File
@@ -2073,6 +2073,17 @@ test_network_ovn_acl() {
incus network acl rule add ingress-ping ingress action=allow protocol=icmp4 destination=10.10.10.1-10.10.11.1
! incus exec c2 -- ping -c1 -w5 -4 10.10.11.2 || false
# Test address set subjects aren't treated as referenced ACLs.
incus network address-set create pingset
incus network address-set add pingset 10.10.11.2
# shellcheck disable=2016
incus network acl rule add ingress-ping ingress action=allow protocol=icmp4 destination='\$pingset'
incus exec c2 -- ping -c1 -w5 -4 10.10.11.2
! ovn-nbctl --bare --column=name --format=csv find port_group | grep -q incus_acl0_ || false
# shellcheck disable=2016
incus network acl rule remove ingress-ping ingress action=allow protocol=icmp4 destination='\$pingset'
incus network address-set delete pingset
# Test ACL rule referencing our own ACL name as source in rule.
incus network acl rule remove ingress-ping ingress action=allow protocol=icmp4 destination=10.10.10.1-10.10.11.1
incus network acl rule add ingress-ping ingress action=allow protocol=icmp4 source=ingress-ping