deps: replace multierr with native errors.Join

Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
This commit is contained in:
Paul Meyer 2023-02-07 12:56:25 +01:00
parent 955316c661
commit 12c866bcb9
32 changed files with 173 additions and 159 deletions

View File

@ -8,10 +8,9 @@ package cloudcmd
import (
"context"
"errors"
"fmt"
"io"
"go.uber.org/multierr"
)
// rollbacker does a rollback.
@ -28,7 +27,7 @@ func rollbackOnError(ctx context.Context, w io.Writer, onErr *error, roll rollba
fmt.Fprintf(w, "An error occurred: %s\n", *onErr)
fmt.Fprintln(w, "Attempting to roll back.")
if err := roll.rollback(ctx); err != nil {
*onErr = multierr.Append(*onErr, fmt.Errorf("on rollback: %w", err)) // TODO: print the error, or return it?
*onErr = errors.Join(*onErr, fmt.Errorf("on rollback: %w", err)) // TODO: print the error, or return it?
return
}
fmt.Fprintln(w, "Rollback succeeded.")
@ -40,9 +39,9 @@ type rollbackerTerraform struct {
func (r *rollbackerTerraform) rollback(ctx context.Context) error {
var err error
err = multierr.Append(err, r.client.Destroy(ctx))
err = errors.Join(err, r.client.Destroy(ctx))
if err == nil {
err = multierr.Append(err, r.client.CleanUpWorkspace())
err = errors.Join(err, r.client.CleanUpWorkspace())
}
return err
}
@ -56,9 +55,9 @@ type rollbackerQEMU struct {
func (r *rollbackerQEMU) rollback(ctx context.Context) error {
var err error
if r.createdWorkspace {
err = multierr.Append(err, r.client.Destroy(ctx))
err = errors.Join(err, r.client.Destroy(ctx))
}
err = multierr.Append(err, r.libvirt.Stop(ctx))
err = errors.Join(err, r.libvirt.Stop(ctx))
if err == nil {
err = r.client.CleanUpWorkspace()
}

View File

@ -24,7 +24,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config"
"github.com/spf13/cobra"
"go.uber.org/multierr"
)
// Validator validates Platform Configuration Registers (PCRs).
@ -84,10 +83,7 @@ func (v *Validator) updatePCR(pcrIndex uint32, encoded string) error {
hexErr := err
decoded, err = base64.StdEncoding.DecodeString(encoded)
if err != nil {
return multierr.Append(
fmt.Errorf("input [%s] is not hex encoded: %w", encoded, hexErr),
fmt.Errorf("input [%s] is not base64 encoded: %w", encoded, err),
)
return fmt.Errorf("input [%s] could neither be hex decoded (%w) nor base64 decoded (%w)", encoded, hexErr, err)
}
}
// new_pcr_value := hash(old_pcr_value || data_to_extend)

View File

@ -8,6 +8,7 @@ package cmd
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
@ -80,8 +81,12 @@ func (cfm *configFetchMeasurementsCmd) configFetchMeasurements(
cfm.log.Debugf("Loading configuration file from %q", flags.configPath)
conf, err := config.New(fileHandler, flags.configPath, flags.force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
if !conf.IsReleaseImage() {

View File

@ -73,8 +73,12 @@ func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler
c.log.Debugf("Loading configuration file from %q", flags.configPath)
conf, err := config.New(fileHandler, flags.configPath, flags.force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
c.log.Debugf("Checking configuration for warnings")

View File

@ -104,8 +104,12 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud
i.log.Debugf("Using flags: %+v", flags)
i.log.Debugf("Loading configuration file from %q", flags.configPath)
conf, err := config.New(fileHandler, flags.configPath, flags.force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
i.log.Debugf("Checking cluster ID file")

View File

@ -17,7 +17,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"go.uber.org/multierr"
)
func newMiniDownCmd() *cobra.Command {
@ -39,7 +38,7 @@ func runDown(cmd *cobra.Command, args []string) error {
err := runTerminate(cmd, args)
if removeErr := os.Remove(constants.MasterSecretFilename); removeErr != nil && !os.IsNotExist(removeErr) {
err = multierr.Append(err, removeErr)
err = errors.Join(err, removeErr)
}
return err
}

View File

@ -187,8 +187,12 @@ func (m *miniUpCmd) prepareConfig(cmd *cobra.Command, fileHandler file.Handler)
// check for existing config
if configPath != "" {
conf, err := config.New(fileHandler, configPath, force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return nil, config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return nil, err
}
if conf.GetProvider() != cloudprovider.QEMU {
return nil, errors.New("invalid provider for MiniConstellation cluster")

View File

@ -8,6 +8,7 @@ package cmd
import (
"context"
"errors"
"fmt"
"io"
"net"
@ -80,9 +81,14 @@ func (r *recoverCmd) recover(
r.log.Debugf("Loading configuration file from %q", flags.configPath)
conf, err := config.New(fileHandler, flags.configPath, flags.force)
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return err
}
provider := conf.GetProvider()
r.log.Debugf("Got provider %s", provider.String())
if provider == cloudprovider.Azure {

View File

@ -13,7 +13,6 @@ import (
"github.com/spf13/afero"
"github.com/spf13/cobra"
"go.uber.org/multierr"
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/v2/internal/constants"
@ -79,11 +78,11 @@ func terminate(cmd *cobra.Command, terminator cloudTerminator, fileHandler file.
var retErr error
if err := fileHandler.Remove(constants.AdminConfFilename); err != nil && !errors.Is(err, fs.ErrNotExist) {
retErr = multierr.Append(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", constants.AdminConfFilename))
retErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", constants.AdminConfFilename))
}
if err := fileHandler.Remove(constants.ClusterIDsFileName); err != nil && !errors.Is(err, fs.ErrNotExist) {
retErr = multierr.Append(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", constants.ClusterIDsFileName))
retErr = errors.Join(err, fmt.Errorf("failed to remove file: '%s', please remove it manually", constants.ClusterIDsFileName))
}
return retErr

View File

@ -74,8 +74,12 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, imageFetcher imageFet
return fmt.Errorf("parsing flags: %w", err)
}
conf, err := config.New(fileHandler, flags.configPath, flags.force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
if err := u.handleServiceUpgrade(cmd, conf, flags); err != nil {

View File

@ -127,8 +127,12 @@ type upgradeCheckCmd struct {
// upgradePlan plans an upgrade of a Constellation cluster.
func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Handler, flags upgradeCheckFlags) error {
conf, err := config.New(fileHandler, flags.configPath, flags.force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
u.log.Debugf("Read configuration from %q", flags.configPath)
// get current image version of the cluster

View File

@ -76,8 +76,12 @@ func (v *verifyCmd) verify(cmd *cobra.Command, fileHandler file.Handler, verifyC
v.log.Debugf("Loading configuration file from %q", flags.configPath)
conf, err := config.New(fileHandler, flags.configPath, flags.force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
provider := conf.GetProvider()

View File

@ -23,7 +23,6 @@ import (
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/multierr"
)
func TestPrepareCluster(t *testing.T) {
@ -682,10 +681,13 @@ func TestCleanupWorkspace(t *testing.T) {
"files are cleaned up": {
provider: cloudprovider.QEMU,
prepareFS: func(f file.Handler) error {
var err error
err = multierr.Append(err, f.Write("terraform.tfvars", someContent))
err = multierr.Append(err, f.Write("terraform.tfstate", someContent))
return multierr.Append(err, f.Write("terraform.tfstate.backup", someContent))
if err := f.Write("terraform.tfvars", someContent); err != nil {
return err
}
if err := f.Write("terraform.tfstate", someContent); err != nil {
return err
}
return f.Write("terraform.tfstate.backup", someContent)
},
},
"no error if files do not exist": {

View File

@ -8,6 +8,7 @@ package cmd
import (
"context"
"errors"
"fmt"
"io"
"net"
@ -68,8 +69,12 @@ func runDeploy(cmd *cobra.Command, args []string) error {
streamer := streamer.New(fs)
transfer := filetransfer.New(log, streamer, filetransfer.ShowProgress)
constellationConfig, err := config.New(fileHandler, configName, force)
var configValidationErr *config.ValidationError
if errors.As(err, &configValidationErr) {
cmd.PrintErrln(configValidationErr.LongMessage())
}
if err != nil {
return config.DisplayValidationErrors(cmd.ErrOrStderr(), err)
return err
}
return deploy(cmd, fileHandler, constellationConfig, transfer, log)

View File

@ -21,7 +21,6 @@ import (
pb "github.com/edgelesssys/constellation/v2/debugd/service"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/logger"
"go.uber.org/multierr"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
@ -116,14 +115,9 @@ func (s *debugdServer) UploadFiles(stream pb.Debugd_UploadFilesServer) error {
continue
}
// continue on error to allow other units to be overridden
// TODO: switch to native go multierror once 1.20 is released
// err = s.serviceManager.OverrideServiceUnitExecStart(stream.Context(), file.OverrideServiceUnit, file.TargetPath)
// if err != nil {
// overrideUnitErr = errors.Join(overrideUnitErr, err)
// }
err = s.serviceManager.OverrideServiceUnitExecStart(stream.Context(), file.OverrideServiceUnit, file.TargetPath)
if err != nil {
overrideUnitErr = multierr.Append(overrideUnitErr, err)
overrideUnitErr = errors.Join(overrideUnitErr, err)
}
}

2
go.mod
View File

@ -91,7 +91,6 @@ require (
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
go.uber.org/goleak v1.2.1
go.uber.org/multierr v1.9.0
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.6.0
golang.org/x/mod v0.8.0
@ -298,6 +297,7 @@ require (
go.opencensus.io v0.24.0 // indirect
go.starlark.net v0.0.0-20220223235035-243c74974e97 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20220823124025-807a23277127 // indirect
golang.org/x/net v0.6.0 // indirect
golang.org/x/oauth2 v0.4.0 // indirect

View File

@ -44,7 +44,6 @@ require (
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
go.uber.org/goleak v1.2.1
go.uber.org/multierr v1.9.0
go.uber.org/zap v1.24.0
golang.org/x/mod v0.8.0
google.golang.org/grpc v1.51.0
@ -268,6 +267,7 @@ require (
go.opencensus.io v0.24.0 // indirect
go.starlark.net v0.0.0-20220223235035-243c74974e97 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/exp v0.0.0-20220823124025-807a23277127 // indirect
golang.org/x/net v0.6.0 // indirect

View File

@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
package main
import (
"errors"
"flag"
"fmt"
"io"
@ -18,7 +19,6 @@ import (
"github.com/edgelesssys/constellation/v2/hack/image-measurement/server"
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
"github.com/edgelesssys/constellation/v2/internal/logger"
"go.uber.org/multierr"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/yaml.v3"
@ -46,7 +46,7 @@ func (l *libvirtInstance) uploadBaseImage(baseVolume *libvirt.StorageVol) (err e
return fmt.Errorf("error while opening %s: %s", l.imagePath, err)
}
defer func() {
err = multierr.Append(err, file.Close())
err = errors.Join(err, file.Close())
}()
fi, err := file.Stat()
@ -276,9 +276,9 @@ func (l *libvirtInstance) deletePool() error {
func (l *libvirtInstance) deleteLibvirtInstance() error {
var err error
err = multierr.Append(err, l.deleteNetwork())
err = multierr.Append(err, l.deleteDomain())
err = multierr.Append(err, l.deletePool())
err = errors.Join(err, l.deleteNetwork())
err = errors.Join(err, l.deleteDomain())
err = errors.Join(err, l.deletePool())
return err
}
@ -295,7 +295,7 @@ func (l *libvirtInstance) obtainMeasurements() (measurements measurements.M, err
}
}()
defer func() {
err = multierr.Append(err, l.deleteLibvirtInstance())
err = errors.Join(err, l.deleteLibvirtInstance())
}()
if err := l.createLibvirtInstance(); err != nil {
return nil, err

View File

@ -9,10 +9,10 @@ package idkeydigest
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"go.uber.org/multierr"
)
// IDKeyDigests is a list of trusted digest values for the ID key.
@ -60,7 +60,7 @@ func (d *IDKeyDigests) UnmarshalYAML(unmarshal func(any) error) error {
// Unmarshalling failed, IDKeyDigests might be a simple string instead of IDKeyDigests struct.
var unmarshalledString string
if legacyErr := unmarshal(&unmarshalledString); legacyErr != nil {
return multierr.Append(
return errors.Join(
err,
fmt.Errorf("trying legacy format: %w", legacyErr),
)
@ -89,7 +89,7 @@ func (d *IDKeyDigests) UnmarshalJSON(b []byte) error {
// Unmarshalling failed, IDKeyDigests might be a simple string instead of IDKeyDigests struct.
var unmarshalledString string
if legacyErr := json.Unmarshal(b, &unmarshalledString); legacyErr != nil {
return multierr.Append(
return errors.Join(
err,
fmt.Errorf("trying legacy format: %w", legacyErr),
)

View File

@ -20,6 +20,7 @@ import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -31,7 +32,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/sigstore"
"github.com/google/go-tpm/tpmutil"
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
"go.uber.org/multierr"
"gopkg.in/yaml.v3"
)
@ -91,7 +91,7 @@ func (m *M) FetchAndVerify(
var mWithMetadata WithMetadata
if err := json.Unmarshal(measurements, &mWithMetadata); err != nil {
if yamlErr := yaml.Unmarshal(measurements, &mWithMetadata); yamlErr != nil {
return "", multierr.Append(
return "", errors.Join(
err,
fmt.Errorf("trying yaml format: %w", yamlErr),
)
@ -193,7 +193,7 @@ func (m *Measurement) UnmarshalJSON(b []byte) error {
// Unmarshalling failed, Measurement might be a simple string instead of Measurement struct.
// These values will always be enforced.
if legacyErr := json.Unmarshal(b, &eM.Expected); legacyErr != nil {
return multierr.Append(
return errors.Join(
err,
fmt.Errorf("trying legacy format: %w", legacyErr),
)
@ -222,7 +222,7 @@ func (m *Measurement) UnmarshalYAML(unmarshal func(any) error) error {
// Unmarshalling failed, Measurement might be a simple string instead of Measurement struct.
// These values will always be enforced.
if legacyErr := unmarshal(&eM.Expected); legacyErr != nil {
return multierr.Append(
return errors.Join(
err,
fmt.Errorf("trying legacy format: %w", legacyErr),
)
@ -252,7 +252,7 @@ func (m *Measurement) unmarshal(eM encodedMeasurement) error {
hexErr := err
expected, err = base64.StdEncoding.DecodeString(eM.Expected)
if err != nil {
return multierr.Append(
return errors.Join(
fmt.Errorf("invalid measurement: not a hex string %w", hexErr),
fmt.Errorf("not a base64 string: %w", err),
)

View File

@ -36,7 +36,6 @@ import (
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
"go.uber.org/multierr"
)
// Measurements is a required alias since docgen is not able to work with
@ -586,12 +585,10 @@ func (c *Config) Validate(force bool) error {
return err
}
var validationErrors error
var validationErrMsgs []string
for _, e := range errs {
validationErrors = multierr.Append(
validationErrors,
errors.New(e.Translate(trans)),
)
validationErrMsgs = append(validationErrMsgs, e.Translate(trans))
}
return validationErrors
return &ValidationError{validationErrMsgs: validationErrMsgs}
}

View File

@ -23,7 +23,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"go.uber.org/multierr"
)
func TestMain(m *testing.M) {
@ -185,19 +184,13 @@ func TestNewWithDefaultOptions(t *testing.T) {
}
func TestValidate(t *testing.T) {
const defaultErrCount = 21 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default
const azErrCount = 9
const gcpErrCount = 6
testCases := map[string]struct {
cnf *Config
wantErr bool
wantErrCount int
cnf *Config
wantErr bool
}{
"default config is not valid": {
cnf: Default(),
wantErr: true,
wantErrCount: defaultErrCount,
cnf: Default(),
wantErr: true,
},
"v0 is one error": {
cnf: func() *Config {
@ -205,8 +198,7 @@ func TestValidate(t *testing.T) {
cnf.Version = "v0"
return cnf
}(),
wantErr: true,
wantErrCount: defaultErrCount + 1,
wantErr: true,
},
"v0 and negative state disk are two errors": {
cnf: func() *Config {
@ -215,8 +207,7 @@ func TestValidate(t *testing.T) {
cnf.StateDiskSizeGB = -1
return cnf
}(),
wantErr: true,
wantErrCount: defaultErrCount + 2,
wantErr: true,
},
"default Azure config is not valid": {
cnf: func() *Config {
@ -226,8 +217,7 @@ func TestValidate(t *testing.T) {
cnf.Provider.Azure = az
return cnf
}(),
wantErr: true,
wantErrCount: azErrCount,
wantErr: true,
},
"Azure config with all required fields is valid": {
cnf: func() *Config {
@ -255,8 +245,7 @@ func TestValidate(t *testing.T) {
cnf.Provider.GCP = gcp
return cnf
}(),
wantErr: true,
wantErrCount: gcpErrCount,
wantErr: true,
},
"GCP config with all required fields is valid": {
cnf: func() *Config {
@ -302,7 +291,6 @@ func TestValidate(t *testing.T) {
err := tc.cnf.Validate(false)
if tc.wantErr {
assert.Error(err)
assert.Len(multierr.Errors(err), tc.wantErrCount)
return
}
assert.NoError(err)

View File

@ -10,7 +10,6 @@ import (
"bytes"
"errors"
"fmt"
"io"
"os"
"sort"
"strconv"
@ -25,22 +24,27 @@ import (
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
"go.uber.org/multierr"
"golang.org/x/mod/semver"
)
// DisplayValidationErrors shows all validation errors inside configError as one formatted string.
func DisplayValidationErrors(errWriter io.Writer, configError error) error {
errs := multierr.Errors(configError)
if errs != nil {
fmt.Fprintln(errWriter, "Problems validating config file:")
for _, err := range errs {
fmt.Fprintln(errWriter, "\t"+err.Error())
}
fmt.Fprintln(errWriter, "Fix the invalid entries or generate a new configuration using `constellation config generate`")
return errors.New("invalid configuration")
// ValidationError occurs when the validation of a config fails.
// It contains a list of errors that occurred during validation.
type ValidationError struct {
validationErrMsgs []string
}
func (e *ValidationError) Error() string {
return "invalid configuration"
}
// LongMessage prints the errors that occurred during validation in a verbose and user friendly way.
func (e *ValidationError) LongMessage() string {
msg := "Problems validating config file:\n"
for _, ve := range e.validationErrMsgs {
msg += fmt.Sprintf("\t%s\n", ve)
}
return nil
msg += "Fix the invalid entries or generate a new configuration using `constellation config generate`"
return msg
}
func registerInvalidK8sVersionError(ut ut.Translator) error {

View File

@ -12,6 +12,7 @@ import (
"bytes"
"compress/gzip"
"context"
"errors"
"io"
"io/fs"
"net"
@ -26,7 +27,6 @@ import (
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/multierr"
"google.golang.org/grpc/test/bufconn"
testclock "k8s.io/utils/clock/testing"
)
@ -737,10 +737,10 @@ func (w *tarGzWriter) Bytes() []byte {
func (w *tarGzWriter) Close() (result error) {
if err := w.tarWriter.Close(); err != nil {
result = multierr.Append(result, err)
result = errors.Join(result, err)
}
if err := w.gzWriter.Close(); err != nil {
result = multierr.Append(result, err)
result = errors.Join(result, err)
}
return result
}

View File

@ -29,7 +29,6 @@ import (
verclient "github.com/edgelesssys/constellation/v2/internal/versionsapi/client"
gaxv2 "github.com/googleapis/gax-go/v2"
"github.com/spf13/cobra"
"go.uber.org/multierr"
"go.uber.org/zap/zapcore"
)
@ -141,12 +140,12 @@ func deleteSingleVersion(ctx context.Context, clients rmImageClients, ver versio
log.Debugf("Deleting images for %s", ver.Version)
if err := deleteImage(ctx, clients, ver, dryrun, log); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting images: %w", err))
retErr = errors.Join(retErr, fmt.Errorf("deleting images: %w", err))
}
log.Debugf("Deleting version %s from versions API", ver.Version)
if err := clients.version.DeleteVersion(ctx, ver); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting version from versions API: %w", err))
retErr = errors.Join(retErr, fmt.Errorf("deleting version from versions API: %w", err))
}
return retErr
@ -182,13 +181,13 @@ func deleteRef(ctx context.Context, clients rmImageClients, ref string, dryrun b
for _, ver := range vers {
if err := deleteImage(ctx, clients, ver, dryrun, log); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting images for version %s: %w", ver.Version, err))
retErr = errors.Join(retErr, fmt.Errorf("deleting images for version %s: %w", ver.Version, err))
}
}
log.Infof("Deleting ref %s from versions API", ref)
if err := clients.version.DeleteRef(ctx, ref); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting ref from versions API: %w", err))
retErr = errors.Join(retErr, fmt.Errorf("deleting ref from versions API: %w", err))
}
return retErr
@ -215,21 +214,21 @@ func deleteImage(ctx context.Context, clients rmImageClients, ver versionsapi.Ve
log.Infof("Deleting AWS images from %s", imageInfo.JSONPath())
for awsRegion, awsImage := range imageInfo.AWS {
if err := clients.aws.deleteImage(ctx, awsImage, awsRegion, dryrun, log); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting AWS image %s: %w", awsImage, err))
retErr = errors.Join(retErr, fmt.Errorf("deleting AWS image %s: %w", awsImage, err))
}
}
log.Infof("Deleting GCP images from %s", imageInfo.JSONPath())
for _, gcpImage := range imageInfo.GCP {
if err := clients.gcp.deleteImage(ctx, gcpImage, dryrun, log); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting GCP image %s: %w", gcpImage, err))
retErr = errors.Join(retErr, fmt.Errorf("deleting GCP image %s: %w", gcpImage, err))
}
}
log.Infof("Deleting Azure images from %s", imageInfo.JSONPath())
for _, azImage := range imageInfo.Azure {
if err := clients.az.deleteImage(ctx, azImage, dryrun, log); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting Azure image %s: %w", azImage, err))
retErr = errors.Join(retErr, fmt.Errorf("deleting Azure image %s: %w", azImage, err))
}
}

View File

@ -43,7 +43,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
"go.uber.org/multierr"
"golang.org/x/mod/semver"
)
@ -167,17 +166,17 @@ func (c *Client) DeleteVersion(ctx context.Context, ver versionsapi.Version) err
c.log.Debugf("Deleting version %s from minor version list", ver.Version)
possibleNewLatest, err := c.deleteVersionFromMinorVersionList(ctx, ver)
if err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("removing from minor version list: %w", err))
retErr = errors.Join(retErr, fmt.Errorf("removing from minor version list: %w", err))
}
c.log.Debugf("Checking latest version for %s", ver.Version)
if err := c.deleteVersionFromLatest(ctx, ver, possibleNewLatest); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("updating latest version: %w", err))
retErr = errors.Join(retErr, fmt.Errorf("updating latest version: %w", err))
}
c.log.Debugf("Deleting artifact path %s for %s", ver.ArtifactPath(), ver.Version)
if err := c.deletePath(ctx, ver.ArtifactPath()); err != nil {
retErr = multierr.Append(retErr, fmt.Errorf("deleting artifact path: %w", err))
retErr = errors.Join(retErr, fmt.Errorf("deleting artifact path: %w", err))
}
return retErr

View File

@ -13,7 +13,6 @@ import (
"path"
"github.com/edgelesssys/constellation/v2/internal/constants"
"go.uber.org/multierr"
"golang.org/x/mod/semver"
)
@ -62,25 +61,25 @@ func (i ImageInfo) URL() (string, error) {
func (i ImageInfo) ValidateRequest() error {
var retErr error
if err := ValidateRef(i.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(i.Ref, i.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if !semver.IsValid(i.Version) {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not a valid semver", i.Version))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", i.Version))
}
if len(i.AWS) != 0 {
retErr = multierr.Append(retErr, errors.New("AWS map must be empty for request"))
retErr = errors.Join(retErr, errors.New("AWS map must be empty for request"))
}
if len(i.Azure) != 0 {
retErr = multierr.Append(retErr, errors.New("Azure map must be empty for request"))
retErr = errors.Join(retErr, errors.New("Azure map must be empty for request"))
}
if len(i.GCP) != 0 {
retErr = multierr.Append(retErr, errors.New("GCP map must be empty for request"))
retErr = errors.Join(retErr, errors.New("GCP map must be empty for request"))
}
if len(i.QEMU) != 0 {
retErr = multierr.Append(retErr, errors.New("QEMU map must be empty for request"))
retErr = errors.Join(retErr, errors.New("QEMU map must be empty for request"))
}
return retErr
@ -90,25 +89,25 @@ func (i ImageInfo) ValidateRequest() error {
func (i ImageInfo) Validate() error {
var retErr error
if err := ValidateRef(i.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(i.Ref, i.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if !semver.IsValid(i.Version) {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not a valid semver", i.Version))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", i.Version))
}
if len(i.AWS) == 0 {
retErr = multierr.Append(retErr, errors.New("AWS map must not be empty"))
retErr = errors.Join(retErr, errors.New("AWS map must not be empty"))
}
if len(i.Azure) == 0 {
retErr = multierr.Append(retErr, errors.New("Azure map must not be empty"))
retErr = errors.Join(retErr, errors.New("Azure map must not be empty"))
}
if len(i.GCP) == 0 {
retErr = multierr.Append(retErr, errors.New("GCP map must not be empty"))
retErr = errors.Join(retErr, errors.New("GCP map must not be empty"))
}
if len(i.QEMU) == 0 {
retErr = multierr.Append(retErr, errors.New("QEMU map must not be empty"))
retErr = errors.Join(retErr, errors.New("QEMU map must not be empty"))
}
return retErr

View File

@ -7,12 +7,12 @@ SPDX-License-Identifier: AGPL-3.0-only
package versionsapi
import (
"errors"
"fmt"
"net/url"
"path"
"github.com/edgelesssys/constellation/v2/internal/constants"
"go.uber.org/multierr"
"golang.org/x/mod/semver"
)
@ -54,16 +54,16 @@ func (l Latest) URL() (string, error) {
func (l Latest) Validate() error {
var retErr error
if err := ValidateRef(l.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(l.Ref, l.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if l.Kind == VersionKindUnknown {
retErr = multierr.Append(retErr, fmt.Errorf("version of kind %q is not supported", l.Kind))
retErr = errors.Join(retErr, fmt.Errorf("version of kind %q is not supported", l.Kind))
}
if !semver.IsValid(l.Version) {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not a valid semver", l.Version))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", l.Version))
}
return retErr
@ -73,16 +73,16 @@ func (l Latest) Validate() error {
func (l Latest) ValidateRequest() error {
var retErr error
if err := ValidateRef(l.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(l.Ref, l.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if l.Kind == VersionKindUnknown {
retErr = multierr.Append(retErr, fmt.Errorf("version of kind %q is not supported", l.Kind))
retErr = errors.Join(retErr, fmt.Errorf("version of kind %q is not supported", l.Kind))
}
if l.Version != "" {
retErr = multierr.Append(retErr, fmt.Errorf("version %q must be empty for request", l.Version))
retErr = errors.Join(retErr, fmt.Errorf("version %q must be empty for request", l.Version))
}
return retErr
}

View File

@ -7,12 +7,12 @@ SPDX-License-Identifier: AGPL-3.0-only
package versionsapi
import (
"errors"
"fmt"
"net/url"
"path"
"github.com/edgelesssys/constellation/v2/internal/constants"
"go.uber.org/multierr"
"golang.org/x/mod/semver"
)
@ -66,19 +66,19 @@ func (l List) URL() (string, error) {
func (l List) ValidateRequest() error {
var retErr error
if err := ValidateRef(l.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(l.Ref, l.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if l.Granularity != GranularityMajor && l.Granularity != GranularityMinor {
retErr = multierr.Append(retErr, fmt.Errorf("granularity %q is not supported", l.Granularity))
retErr = errors.Join(retErr, fmt.Errorf("granularity %q is not supported", l.Granularity))
}
if l.Kind != VersionKindImage {
retErr = multierr.Append(retErr, fmt.Errorf("kind %q is not supported", l.Kind))
retErr = errors.Join(retErr, fmt.Errorf("kind %q is not supported", l.Kind))
}
if !semver.IsValid(l.Base) {
retErr = multierr.Append(retErr, fmt.Errorf("base version %q is not a valid semantic version", l.Base))
retErr = errors.Join(retErr, fmt.Errorf("base version %q is not a valid semantic version", l.Base))
}
var normalizeFunc func(string) string
switch l.Granularity {
@ -90,10 +90,10 @@ func (l List) ValidateRequest() error {
normalizeFunc = func(s string) string { return s }
}
if normalizeFunc(l.Base) != l.Base {
retErr = multierr.Append(retErr, fmt.Errorf("base version %q does not match granularity %q", l.Base, l.Granularity))
retErr = errors.Join(retErr, fmt.Errorf("base version %q does not match granularity %q", l.Base, l.Granularity))
}
if len(l.Versions) != 0 {
retErr = multierr.Append(retErr, fmt.Errorf("versions must be empty for request"))
retErr = errors.Join(retErr, fmt.Errorf("versions must be empty for request"))
}
return retErr
}
@ -109,19 +109,19 @@ func (l List) ValidateRequest() error {
func (l List) Validate() error {
var retErr error
if err := ValidateRef(l.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(l.Ref, l.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if l.Granularity != GranularityMajor && l.Granularity != GranularityMinor {
retErr = multierr.Append(retErr, fmt.Errorf("granularity %q is not supported", l.Granularity))
retErr = errors.Join(retErr, fmt.Errorf("granularity %q is not supported", l.Granularity))
}
if l.Kind != VersionKindImage {
retErr = multierr.Append(retErr, fmt.Errorf("kind %q is not supported", l.Kind))
retErr = errors.Join(retErr, fmt.Errorf("kind %q is not supported", l.Kind))
}
if !semver.IsValid(l.Base) {
retErr = multierr.Append(retErr, fmt.Errorf("base version %q is not a valid semantic version", l.Base))
retErr = errors.Join(retErr, fmt.Errorf("base version %q is not a valid semantic version", l.Base))
}
var normalizeFunc func(string) string
switch l.Granularity {
@ -133,14 +133,14 @@ func (l List) Validate() error {
normalizeFunc = func(s string) string { return s }
}
if normalizeFunc(l.Base) != l.Base {
retErr = multierr.Append(retErr, fmt.Errorf("base version %q does not match granularity %q", l.Base, l.Granularity))
retErr = errors.Join(retErr, fmt.Errorf("base version %q does not match granularity %q", l.Base, l.Granularity))
}
for _, ver := range l.Versions {
if !semver.IsValid(ver) {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not a valid semantic version", ver))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semantic version", ver))
}
if normalizeFunc(ver) != l.Base || normalizeFunc(ver) == ver {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not finer-grained than base version %q", ver, l.Base))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not finer-grained than base version %q", ver, l.Base))
}
}

View File

@ -15,7 +15,6 @@ import (
"strings"
"github.com/edgelesssys/constellation/v2/internal/constants"
"go.uber.org/multierr"
"golang.org/x/mod/semver"
)
@ -64,19 +63,19 @@ func (v Version) ShortPath() string {
func (v Version) Validate() error {
var retErr error
if err := ValidateRef(v.Ref); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if err := ValidateStream(v.Ref, v.Stream); err != nil {
retErr = multierr.Append(retErr, err)
retErr = errors.Join(retErr, err)
}
if !semver.IsValid(v.Version) {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not a valid semantic version", v.Version))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semantic version", v.Version))
}
if semver.Canonical(v.Version) != v.Version {
retErr = multierr.Append(retErr, fmt.Errorf("version %q is not a canonical semantic version", v.Version))
retErr = errors.Join(retErr, fmt.Errorf("version %q is not a canonical semantic version", v.Version))
}
if v.Kind == VersionKindUnknown {
retErr = multierr.Append(retErr, errors.New("version kind is unknown"))
retErr = errors.Join(retErr, errors.New("version kind is unknown"))
}
return retErr
}

View File

@ -24,7 +24,6 @@ require (
go.etcd.io/etcd/api/v3 v3.5.7
go.etcd.io/etcd/client/pkg/v3 v3.5.7
go.etcd.io/etcd/client/v3 v3.5.7
go.uber.org/multierr v1.9.0
golang.org/x/mod v0.8.0
google.golang.org/api v0.107.0
google.golang.org/protobuf v1.28.1
@ -83,6 +82,7 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/net v0.6.0 // indirect

View File

@ -8,12 +8,12 @@ package client
import (
"context"
"errors"
"math/rand"
"time"
compute "cloud.google.com/go/compute/apiv1"
"github.com/spf13/afero"
"go.uber.org/multierr"
)
// Client is a client for the Google Compute Engine.
@ -100,7 +100,7 @@ func closeAll(closers []closer) error {
// close operations, even if a previous operation failed.
var errs error
for _, closer := range closers {
errs = multierr.Append(errs, closer.Close())
errs = errors.Join(errs, closer.Close())
}
return errs
}