consistently use stdout and stderr (#502)

* consistently use stdout and stderr
Signed-off-by: Fabian Kammel <fk@edgeless.systems>
This commit is contained in:
Fabian Kammel 2022-11-10 10:27:24 +01:00 committed by GitHub
parent e011c7ef78
commit 81a5907f26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 61 additions and 59 deletions

View File

@ -29,11 +29,11 @@ type Upgrader struct {
measurementsUpdater measurementsUpdater measurementsUpdater measurementsUpdater
imageUpdater imageUpdater imageUpdater imageUpdater
writer io.Writer outWriter io.Writer
} }
// NewUpgrader returns a new Upgrader. // NewUpgrader returns a new Upgrader.
func NewUpgrader(writer io.Writer) (*Upgrader, error) { func NewUpgrader(outWriter io.Writer) (*Upgrader, error) {
kubeConfig, err := clientcmd.BuildConfigFromFlags("", constants.AdminConfFilename) kubeConfig, err := clientcmd.BuildConfigFromFlags("", constants.AdminConfFilename)
if err != nil { if err != nil {
return nil, fmt.Errorf("building kubernetes config: %w", err) return nil, fmt.Errorf("building kubernetes config: %w", err)
@ -53,7 +53,7 @@ func NewUpgrader(writer io.Writer) (*Upgrader, error) {
return &Upgrader{ return &Upgrader{
measurementsUpdater: &kubeMeasurementsUpdater{client: kubeClient}, measurementsUpdater: &kubeMeasurementsUpdater{client: kubeClient},
imageUpdater: &kubeImageUpdater{client: unstructuredClient}, imageUpdater: &kubeImageUpdater{client: unstructuredClient},
writer: writer, outWriter: outWriter,
}, nil }, nil
} }
@ -118,7 +118,7 @@ func (u *Upgrader) updateMeasurements(ctx context.Context, measurements map[uint
} }
if !changed { if !changed {
// measurements are the same, nothing to be done // measurements are the same, nothing to be done
fmt.Fprintln(u.writer, "Cluster is already using the chosen measurements, skipping measurements upgrade") fmt.Fprintln(u.outWriter, "Cluster is already using the chosen measurements, skipping measurements upgrade")
return nil return nil
} }
} }
@ -136,7 +136,7 @@ func (u *Upgrader) updateMeasurements(ctx context.Context, measurements map[uint
return fmt.Errorf("setting new measurements: %w", err) return fmt.Errorf("setting new measurements: %w", err)
} }
fmt.Fprintln(u.writer, "Successfully updated the cluster's expected measurements") fmt.Fprintln(u.outWriter, "Successfully updated the cluster's expected measurements")
return nil return nil
} }
@ -147,7 +147,7 @@ func (u *Upgrader) updateImage(ctx context.Context, image string) error {
} }
if currentImageDefinition == image { if currentImageDefinition == image {
fmt.Fprintln(u.writer, "Cluster is already using the chosen image, skipping image upgrade") fmt.Fprintln(u.outWriter, "Cluster is already using the chosen image, skipping image upgrade")
return nil return nil
} }
@ -156,7 +156,7 @@ func (u *Upgrader) updateImage(ctx context.Context, image string) error {
return fmt.Errorf("setting new image: %w", err) return fmt.Errorf("setting new image: %w", err)
} }
fmt.Fprintln(u.writer, "Successfully updated the cluster's image, upgrades will be applied automatically") fmt.Fprintln(u.outWriter, "Successfully updated the cluster's image, upgrades will be applied automatically")
return nil return nil
} }

View File

@ -76,7 +76,7 @@ func TestUpdateMeasurements(t *testing.T) {
upgrader := &Upgrader{ upgrader := &Upgrader{
measurementsUpdater: tc.updater, measurementsUpdater: tc.updater,
writer: &bytes.Buffer{}, outWriter: &bytes.Buffer{},
} }
err := upgrader.updateMeasurements(context.Background(), tc.newMeasurements) err := upgrader.updateMeasurements(context.Background(), tc.newMeasurements)
@ -203,7 +203,7 @@ func TestUpdateImage(t *testing.T) {
upgrader := &Upgrader{ upgrader := &Upgrader{
imageUpdater: tc.updater, imageUpdater: tc.updater,
writer: &bytes.Buffer{}, outWriter: &bytes.Buffer{},
} }
err := upgrader.updateImage(context.Background(), tc.newImage) err := upgrader.updateImage(context.Background(), tc.newImage)

View File

@ -63,7 +63,7 @@ func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHan
} }
if conf.IsDebugImage() { if conf.IsDebugImage() {
cmd.Println("Configured image doesn't look like a released production image. Double check image before deploying to production.") cmd.PrintErrln("Configured image doesn't look like a released production image. Double check image before deploying to production.")
} }
if err := flags.updateURLs(conf); err != nil { if err := flags.updateURLs(conf); err != nil {
@ -79,8 +79,8 @@ func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHan
} }
if err := verifyWithRekor(cmd.Context(), verifier, hash); err != nil { if err := verifyWithRekor(cmd.Context(), verifier, hash); err != nil {
cmd.Printf("Ignoring Rekor related error: %v\n", err) cmd.PrintErrf("Ignoring Rekor related error: %v\n", err)
cmd.Println("Make sure the downloaded measurements are trustworthy!") cmd.PrintErrln("Make sure the downloaded measurements are trustworthy!")
} }
conf.UpdateMeasurements(fetchedMeasurements) conf.UpdateMeasurements(fetchedMeasurements)

View File

@ -7,7 +7,6 @@ SPDX-License-Identifier: AGPL-3.0-only
package cmd package cmd
import ( import (
"fmt"
"strings" "strings"
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes" "github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
@ -27,7 +26,7 @@ func newConfigInstanceTypesCmd() *cobra.Command {
} }
func printSupportedInstanceTypes(cmd *cobra.Command, args []string) { func printSupportedInstanceTypes(cmd *cobra.Command, args []string) {
fmt.Printf(`AWS instance families: cmd.Printf(`AWS instance families:
%v %v
Azure Confidential VM instance types: Azure Confidential VM instance types:
%v %v

View File

@ -41,7 +41,7 @@ func NewCreateCmd() *cobra.Command {
func runCreate(cmd *cobra.Command, args []string) error { func runCreate(cmd *cobra.Command, args []string) error {
fileHandler := file.NewHandler(afero.NewOsFs()) fileHandler := file.NewHandler(afero.NewOsFs())
spinner := newSpinner(cmd.OutOrStdout()) spinner := newSpinner(cmd.ErrOrStderr())
defer spinner.Stop() defer spinner.Stop()
creator := cloudcmd.NewCreator(spinner) creator := cloudcmd.NewCreator(spinner)
@ -59,34 +59,34 @@ func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler,
return err return err
} }
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath) config, err := readConfig(cmd.ErrOrStderr(), fileHandler, flags.configPath)
if err != nil { if err != nil {
return fmt.Errorf("reading and validating config: %w", err) return fmt.Errorf("reading and validating config: %w", err)
} }
var printedAWarning bool var printedAWarning bool
if config.IsDebugImage() { if config.IsDebugImage() {
cmd.Println("Configured image doesn't look like a released production image. Double check image before deploying to production.") cmd.PrintErrln("Configured image doesn't look like a released production image. Double check image before deploying to production.")
printedAWarning = true printedAWarning = true
} }
if config.IsDebugCluster() { if config.IsDebugCluster() {
cmd.Println("WARNING: Creating a debug cluster. This cluster is not secure and should only be used for debugging purposes.") cmd.PrintErrln("WARNING: Creating a debug cluster. This cluster is not secure and should only be used for debugging purposes.")
cmd.Println("DO NOT USE THIS CLUSTER IN PRODUCTION.") cmd.PrintErrln("DO NOT USE THIS CLUSTER IN PRODUCTION.")
printedAWarning = true printedAWarning = true
} }
if config.IsAzureNonCVM() { if config.IsAzureNonCVM() {
cmd.Println("Disabling Confidential VMs is insecure. Use only for evaluation purposes.") cmd.PrintErrln("Disabling Confidential VMs is insecure. Use only for evaluation purposes.")
printedAWarning = true printedAWarning = true
if config.EnforcesIDKeyDigest() { if config.EnforcesIDKeyDigest() {
cmd.Println("Your config asks for enforcing the idkeydigest. This is only available on Confidential VMs. It will not be enforced.") cmd.PrintErrln("Your config asks for enforcing the idkeydigest. This is only available on Confidential VMs. It will not be enforced.")
} }
} }
// Print an extra new line later to separate warnings from the prompt message of the create command // Print an extra new line later to separate warnings from the prompt message of the create command
if printedAWarning { if printedAWarning {
cmd.Println("") cmd.PrintErrln("")
} }
provider := config.GetProvider() provider := config.GetProvider()

View File

@ -79,7 +79,7 @@ func initialize(cmd *cobra.Command, newDialer func(validator *cloudcmd.Validator
return err return err
} }
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath) config, err := readConfig(cmd.ErrOrStderr(), fileHandler, flags.configPath)
if err != nil { if err != nil {
return fmt.Errorf("reading and validating config: %w", err) return fmt.Errorf("reading and validating config: %w", err)
} }
@ -94,13 +94,13 @@ func initialize(cmd *cobra.Command, newDialer func(validator *cloudcmd.Validator
return fmt.Errorf("validating kubernetes version: %w", err) return fmt.Errorf("validating kubernetes version: %w", err)
} }
if versions.IsPreviewK8sVersion(k8sVersion) { if versions.IsPreviewK8sVersion(k8sVersion) {
cmd.Printf("Warning: Constellation with Kubernetes %v is still in preview. Use only for evaluation purposes.\n", k8sVersion) cmd.PrintErrf("Warning: Constellation with Kubernetes %v is still in preview. Use only for evaluation purposes.\n", k8sVersion)
} }
provider := config.GetProvider() provider := config.GetProvider()
checker := license.NewChecker(quotaChecker, fileHandler) checker := license.NewChecker(quotaChecker, fileHandler)
if err := checker.CheckLicense(cmd.Context(), provider, config.Provider, cmd.Printf); err != nil { if err := checker.CheckLicense(cmd.Context(), provider, config.Provider, cmd.Printf); err != nil {
cmd.Printf("License check failed: %v", err) cmd.PrintErrf("License check failed: %v", err)
} }
var sshUsers []*ssh.UserKey var sshUsers []*ssh.UserKey
@ -290,7 +290,7 @@ type masterSecret struct {
} }
// readOrGenerateMasterSecret reads a base64 encoded master secret from file or generates a new 32 byte secret. // readOrGenerateMasterSecret reads a base64 encoded master secret from file or generates a new 32 byte secret.
func readOrGenerateMasterSecret(writer io.Writer, fileHandler file.Handler, filename string) (masterSecret, error) { func readOrGenerateMasterSecret(outWriter io.Writer, fileHandler file.Handler, filename string) (masterSecret, error) {
if filename != "" { if filename != "" {
var secret masterSecret var secret masterSecret
if err := fileHandler.ReadJSON(filename, &secret); err != nil { if err := fileHandler.ReadJSON(filename, &secret); err != nil {
@ -323,7 +323,7 @@ func readOrGenerateMasterSecret(writer io.Writer, fileHandler file.Handler, file
if err := fileHandler.WriteJSON(constants.MasterSecretFilename, secret, file.OptNone); err != nil { if err := fileHandler.WriteJSON(constants.MasterSecretFilename, secret, file.OptNone); err != nil {
return masterSecret{}, err return masterSecret{}, err
} }
fmt.Fprintf(writer, "Your Constellation master secret was successfully written to ./%s\n", constants.MasterSecretFilename) fmt.Fprintf(outWriter, "Your Constellation master secret was successfully written to ./%s\n", constants.MasterSecretFilename)
return secret, nil return secret, nil
} }

View File

@ -50,7 +50,7 @@ func newMiniUpCmd() *cobra.Command {
} }
func runUp(cmd *cobra.Command, args []string) error { func runUp(cmd *cobra.Command, args []string) error {
spinner := newSpinner(cmd.OutOrStdout()) spinner := newSpinner(cmd.ErrOrStderr())
defer spinner.Stop() defer spinner.Stop()
creator := cloudcmd.NewCreator(spinner) creator := cloudcmd.NewCreator(spinner)
@ -58,7 +58,7 @@ func runUp(cmd *cobra.Command, args []string) error {
} }
func up(cmd *cobra.Command, creator cloudCreator, spinner spinnerInterf) error { func up(cmd *cobra.Command, creator cloudCreator, spinner spinnerInterf) error {
if err := checkSystemRequirements(cmd.OutOrStdout()); err != nil { if err := checkSystemRequirements(cmd.ErrOrStderr()); err != nil {
return fmt.Errorf("system requirements not met: %w", err) return fmt.Errorf("system requirements not met: %w", err)
} }
@ -163,7 +163,7 @@ func prepareConfig(cmd *cobra.Command, fileHandler file.Handler) (*config.Config
// check for existing config // check for existing config
if configPath != "" { if configPath != "" {
config, err := readConfig(cmd.OutOrStdout(), fileHandler, configPath) config, err := readConfig(cmd.ErrOrStderr(), fileHandler, configPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -178,7 +178,7 @@ func prepareConfig(cmd *cobra.Command, fileHandler file.Handler) (*config.Config
_, err = fileHandler.Stat(constants.ConfigFilename) _, err = fileHandler.Stat(constants.ConfigFilename)
if err == nil { if err == nil {
// config already exists, prompt user to overwrite // config already exists, prompt user to overwrite
cmd.Println("A config file already exists in the current workspace.") cmd.PrintErrln("A config file already exists in the current workspace.")
ok, err := askToConfirm(cmd, "Do you want to overwrite it?") ok, err := askToConfirm(cmd, "Do you want to overwrite it?")
if err != nil { if err != nil {
return nil, err return nil, err
@ -194,7 +194,7 @@ func prepareConfig(cmd *cobra.Command, fileHandler file.Handler) (*config.Config
cmd.Printf("Using existing image at %s\n\n", imagePath) cmd.Printf("Using existing image at %s\n\n", imagePath)
} else if errors.Is(err, os.ErrNotExist) { } else if errors.Is(err, os.ErrNotExist) {
cmd.Printf("Downloading image to %s\n", imagePath) cmd.Printf("Downloading image to %s\n", imagePath)
if err := installImage(cmd.Context(), cmd.OutOrStdout(), versions.ConstellationQEMUImageURL, imagePath); err != nil { if err := installImage(cmd.Context(), cmd.ErrOrStderr(), versions.ConstellationQEMUImageURL, imagePath); err != nil {
return nil, fmt.Errorf("downloading image to %s: %w", imagePath, err) return nil, fmt.Errorf("downloading image to %s: %w", imagePath, err)
} }
} else { } else {
@ -226,10 +226,10 @@ func initializeMiniCluster(cmd *cobra.Command, fileHandler file.Handler, spinner
// clean up cluster resources if initialization fails // clean up cluster resources if initialization fails
defer func() { defer func() {
if retErr != nil { if retErr != nil {
cmd.Printf("An error occurred: %s\n", retErr) cmd.PrintErrf("An error occurred: %s\n", retErr)
cmd.Println("Attempting to roll back.") cmd.PrintErrln("Attempting to roll back.")
_ = runDown(cmd, []string{}) _ = runDown(cmd, []string{})
cmd.Printf("Rollback succeeded.\n\n") cmd.PrintErrf("Rollback succeeded.\n\n")
} }
}() }()
newDialer := func(validator *cloudcmd.Validator) *dialer.Dialer { newDialer := func(validator *cloudcmd.Validator) *dialer.Dialer {
@ -247,7 +247,7 @@ func initializeMiniCluster(cmd *cobra.Command, fileHandler file.Handler, spinner
} }
// installImage downloads the image from sourceURL to the destination. // installImage downloads the image from sourceURL to the destination.
func installImage(ctx context.Context, out io.Writer, sourceURL, destination string) error { func installImage(ctx context.Context, errWriter io.Writer, sourceURL, destination string) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL, nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL, nil)
if err != nil { if err != nil {
return fmt.Errorf("creating request: %w", err) return fmt.Errorf("creating request: %w", err)
@ -270,7 +270,7 @@ func installImage(ctx context.Context, out io.Writer, sourceURL, destination str
bar := progressbar.NewOptions64( bar := progressbar.NewOptions64(
resp.ContentLength, resp.ContentLength,
progressbar.OptionSetWriter(out), progressbar.OptionSetWriter(errWriter),
progressbar.OptionShowBytes(true), progressbar.OptionShowBytes(true),
progressbar.OptionSetPredictTime(true), progressbar.OptionSetPredictTime(true),
progressbar.OptionFullWidth(), progressbar.OptionFullWidth(),
@ -282,7 +282,7 @@ func installImage(ctx context.Context, out io.Writer, sourceURL, destination str
BarEnd: "]", BarEnd: "]",
}), }),
progressbar.OptionClearOnFinish(), progressbar.OptionClearOnFinish(),
progressbar.OptionOnCompletion(func() { fmt.Fprintf(out, "Done.\n\n") }), progressbar.OptionOnCompletion(func() { fmt.Fprintf(errWriter, "Done.\n\n") }),
) )
defer bar.Close() defer bar.Close()

View File

@ -15,30 +15,30 @@ import (
"github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/file"
) )
func readConfig(out io.Writer, fileHandler file.Handler, name string) (*config.Config, error) { func readConfig(errWriter io.Writer, fileHandler file.Handler, name string) (*config.Config, error) {
cnf, err := config.FromFile(fileHandler, name) cnf, err := config.FromFile(fileHandler, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := validateConfig(out, cnf); err != nil { if err := validateConfig(errWriter, cnf); err != nil {
return nil, err return nil, err
} }
return cnf, nil return cnf, nil
} }
func validateConfig(out io.Writer, cnf *config.Config) error { func validateConfig(errWriter io.Writer, cnf *config.Config) error {
msgs, err := cnf.Validate() msgs, err := cnf.Validate()
if err != nil { if err != nil {
return fmt.Errorf("performing config validation: %w", err) return fmt.Errorf("performing config validation: %w", err)
} }
if len(msgs) > 0 { if len(msgs) > 0 {
fmt.Fprintln(out, "Invalid fields in config file:") fmt.Fprintln(errWriter, "Invalid fields in config file:")
for _, m := range msgs { for _, m := range msgs {
fmt.Fprintln(out, "\t"+m) fmt.Fprintln(errWriter, "\t"+m)
} }
fmt.Fprintln(out, "Fix the invalid entries or generate a new configuration using `constellation config generate`") fmt.Fprintln(errWriter, "Fix the invalid entries or generate a new configuration using `constellation config generate`")
return errors.New("invalid configuration") return errors.New("invalid configuration")
} }

View File

@ -66,7 +66,7 @@ func recover(
return err return err
} }
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath) config, err := readConfig(cmd.ErrOrStderr(), fileHandler, flags.configPath)
if err != nil { if err != nil {
return fmt.Errorf("reading and validating config: %w", err) return fmt.Errorf("reading and validating config: %w", err)
} }

View File

@ -36,7 +36,7 @@ func NewTerminateCmd() *cobra.Command {
// runTerminate runs the terminate command. // runTerminate runs the terminate command.
func runTerminate(cmd *cobra.Command, args []string) error { func runTerminate(cmd *cobra.Command, args []string) error {
fileHandler := file.NewHandler(afero.NewOsFs()) fileHandler := file.NewHandler(afero.NewOsFs())
spinner := newSpinner(cmd.OutOrStdout()) spinner := newSpinner(cmd.ErrOrStderr())
defer spinner.Stop() defer spinner.Stop()
terminator := cloudcmd.NewTerminator() terminator := cloudcmd.NewTerminator()

View File

@ -93,18 +93,18 @@ func upgradePlan(cmd *cobra.Command, planner upgradePlanner,
} }
compatibleImages := getCompatibleImages(csp, version, images) compatibleImages := getCompatibleImages(csp, version, images)
if len(compatibleImages) == 0 { if len(compatibleImages) == 0 {
cmd.Println("No compatible images found to upgrade to.") cmd.PrintErrln("No compatible images found to upgrade to.")
return nil return nil
} }
// get expected measurements for each image // get expected measurements for each image
if err := getCompatibleImageMeasurements(cmd.Context(), client, rekor, []byte(flags.cosignPubKey), compatibleImages); err != nil { if err := getCompatibleImageMeasurements(cmd.Context(), cmd, client, rekor, []byte(flags.cosignPubKey), compatibleImages); err != nil {
return fmt.Errorf("fetching measurements for compatible images: %w", err) return fmt.Errorf("fetching measurements for compatible images: %w", err)
} }
// interactive mode // interactive mode
if flags.filePath == "" { if flags.filePath == "" {
fmt.Fprintf(cmd.OutOrStdout(), "Current version: %s\n", version) cmd.Printf("Current version: %s\n", version)
return upgradePlanInteractive( return upgradePlanInteractive(
&nopWriteCloser{cmd.OutOrStdout()}, &nopWriteCloser{cmd.OutOrStdout()},
io.NopCloser(cmd.InOrStdin()), io.NopCloser(cmd.InOrStdin()),
@ -179,7 +179,7 @@ func getCompatibleImages(csp cloudprovider.Provider, currentVersion string, imag
} }
// getCompatibleImageMeasurements retrieves the expected measurements for each image. // getCompatibleImageMeasurements retrieves the expected measurements for each image.
func getCompatibleImageMeasurements(ctx context.Context, client *http.Client, rekor rekorVerifier, pubK []byte, images map[string]config.UpgradeConfig) error { func getCompatibleImageMeasurements(ctx context.Context, cmd *cobra.Command, client *http.Client, rekor rekorVerifier, pubK []byte, images map[string]config.UpgradeConfig) error {
for idx, img := range images { for idx, img := range images {
measurementsURL, err := url.Parse(constants.S3PublicBucket + strings.ToLower(img.Image) + "/measurements.yaml") measurementsURL, err := url.Parse(constants.S3PublicBucket + strings.ToLower(img.Image) + "/measurements.yaml")
if err != nil { if err != nil {
@ -197,8 +197,8 @@ func getCompatibleImageMeasurements(ctx context.Context, client *http.Client, re
} }
if err = verifyWithRekor(ctx, rekor, hash); err != nil { if err = verifyWithRekor(ctx, rekor, hash); err != nil {
fmt.Printf("Warning: Unable to verify '%s' in Rekor.\n", hash) cmd.PrintErrf("Warning: Unable to verify '%s' in Rekor.\n", hash)
fmt.Printf("Make sure measurements are correct.\n") cmd.PrintErrf("Make sure measurements are correct.\n")
} }
images[idx] = img images[idx] = img

View File

@ -21,6 +21,7 @@ import (
"github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/file"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
@ -271,7 +272,7 @@ func TestGetCompatibleImageMeasurements(t *testing.T) {
pubK := []byte("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----") pubK := []byte("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----")
err := getCompatibleImageMeasurements(context.Background(), client, singleUUIDVerifier(), pubK, testImages) err := getCompatibleImageMeasurements(context.Background(), &cobra.Command{}, client, singleUUIDVerifier(), pubK, testImages)
assert.NoError(err) assert.NoError(err)
for _, image := range testImages { for _, image := range testImages {
@ -456,8 +457,10 @@ func TestUpgradePlan(t *testing.T) {
cmd := newUpgradePlanCmd() cmd := newUpgradePlanCmd()
cmd.SetContext(context.Background()) cmd.SetContext(context.Background())
var out bytes.Buffer var outTarget bytes.Buffer
cmd.SetOut(&out) cmd.SetOut(&outTarget)
var errTarget bytes.Buffer
cmd.SetErr(&errTarget)
client := newTestClient(func(req *http.Request) *http.Response { client := newTestClient(func(req *http.Request) *http.Response {
if req.URL.String() == imageReleaseURL { if req.URL.String() == imageReleaseURL {
@ -497,13 +500,13 @@ func TestUpgradePlan(t *testing.T) {
assert.NoError(err) assert.NoError(err)
if !tc.wantUpgrade { if !tc.wantUpgrade {
assert.Contains(out.String(), "No compatible images") assert.Contains(errTarget.String(), "No compatible images")
return return
} }
var availableUpgrades map[string]config.UpgradeConfig var availableUpgrades map[string]config.UpgradeConfig
if tc.flags.filePath == "-" { if tc.flags.filePath == "-" {
require.NoError(yaml.Unmarshal(out.Bytes(), &availableUpgrades)) require.NoError(yaml.Unmarshal(outTarget.Bytes(), &availableUpgrades))
} else { } else {
require.NoError(fileHandler.ReadYAMLStrict(tc.flags.filePath, &availableUpgrades)) require.NoError(fileHandler.ReadYAMLStrict(tc.flags.filePath, &availableUpgrades))
} }

View File

@ -59,7 +59,7 @@ func verify(cmd *cobra.Command, fileHandler file.Handler, verifyClient verifyCli
return err return err
} }
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath) config, err := readConfig(cmd.ErrOrStderr(), fileHandler, flags.configPath)
if err != nil { if err != nil {
return fmt.Errorf("reading and validating config: %w", err) return fmt.Errorf("reading and validating config: %w", err)
} }

View File

@ -28,7 +28,7 @@ func NewVersionCmd() *cobra.Command {
func runVersion(cmd *cobra.Command, args []string) { func runVersion(cmd *cobra.Command, args []string) {
buildInfo, ok := debug.ReadBuildInfo() buildInfo, ok := debug.ReadBuildInfo()
if !ok { if !ok {
cmd.Printf("Unable to retrieve build info. Is buildvcs enabled?") cmd.PrintErrf("Unable to retrieve build info. Is buildvcs enabled?")
return return
} }