[cli] Disable permalinks to the update details page when using elf-managed backends (S3, Azure, GCS) (#6251)

Fixes: #4029
Fixes: #3537

Should the user want to get permalinks when using a self-managed backend, they can pass a flag:
```
$ pulumi up --suppress-permalink false
```

Permalinks for these self-managed backends will be suppressed on `update`, `preview`, `destroy`,
`import` and `refresh` operations.
This commit is contained in:
Paul Stack 2021-02-19 23:55:35 +00:00 committed by GitHub
parent f7397bb798
commit 1731053b18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 156 additions and 42 deletions

View file

@ -11,6 +11,13 @@ CHANGELOG
- [sdk/dotnet] F# API to specify stack options.
[#5077](https://github.com/pulumi/pulumi/pull/5077)
- [cli] Disable permalinks to the update details page when using self-managed backends (S3, Azure, GCS). Should the user
want to get permalinks when using a self backend, they can pass a flag:
`pulumi up --suppress-permalink false`.
Permalinks for these self-managed backends will be suppressed on `update`, `preview`, `destroy`, `import` and `refresh`
operations.
[#6251](https://github.com/pulumi/pulumi/pull/6251)
### Bug Fixes
- [sdk/nodejs] Don't error when loading multiple copies of the same version of a Node.js
@ -65,7 +72,7 @@ CHANGELOG
- [sdk/python] Fixed a bug in `contains_unknowns` where outputs with a property named "values" failed with a TypeError.
[#6264](https://github.com/pulumi/pulumi/pull/6264)
- [sdk/python] Allowed keyword args in Output.all() to create a dict.
[#6269](https://github.com/pulumi/pulumi/pull/6269)
@ -75,7 +82,6 @@ CHANGELOG
- [automation/python] Fixed a bug in nested configuration parsing.
[#6349](https://github.com/pulumi/pulumi/pull/6349)
## 2.20.0 (2021-02-03)
- [sdk/python] Fix `Output.from_input` to unwrap nested output values in input types (args classes), which addresses

View file

@ -599,18 +599,25 @@ func (b *localBackend) apply(
} else {
link, err = b.bucket.SignedURL(context.TODO(), b.stackPath(stackName), nil)
if err != nil {
// set link to be empty to when there is an error to hide use of Permalinks
link = ""
// we log a warning here rather then returning an error to avoid exiting
// pulumi with an error code.
// printing a statefile perma link happens after all the providers have finished
// deploying the infrastructure, failing the pulumi update because there was a
// problem printing a statefile perma link can be missleading in automated CI environments.
cmdutil.Diag().Warningf(diag.Message("", "Could not get signed url for stack location: %v"), err)
cmdutil.Diag().Warningf(diag.Message("", "Unable to create signed url for current backend to "+
"create a Permalink. Please visit https://www.pulumi.com/docs/troubleshooting/ "+
"for more information\n"))
}
}
fmt.Printf(op.Opts.Display.Color.Colorize(
colors.SpecHeadline+"Permalink: "+
colors.Underline+colors.BrightBlue+"%s"+colors.Reset+"\n"), link)
if link != "" {
fmt.Printf(op.Opts.Display.Color.Colorize(
colors.SpecHeadline+"Permalink: "+
colors.Underline+colors.BrightBlue+"%s"+colors.Reset+"\n"), link)
}
}
return changes, nil

View file

@ -5,9 +5,6 @@ import (
"encoding/json"
"os"
"github.com/pulumi/pulumi/sdk/v2/go/common/diag"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/cmdutil"
"golang.org/x/oauth2/google"
"gocloud.dev/blob/gcsblob"
@ -68,11 +65,6 @@ func GoogleCredentialsMux(ctx context.Context) (*blob.URLMux, error) {
if err == nil && account.ClientEmail != "" && account.PrivateKey != "" {
options.GoogleAccessID = account.ClientEmail
options.PrivateKey = []byte(account.PrivateKey)
} else {
cmdutil.Diag().Warningf(diag.Message("",
"Pulumi will not be able to print a statefile permalink using these credentials. "+
"Neither a GoogleAccessID or PrivateKey are available. "+
"Try using a GCP Service Account."))
}
blobmux := &blob.URLMux{}

View file

@ -46,7 +46,7 @@ func newDestroyCmd() *cobra.Command {
var showSames bool
var skipPreview bool
var suppressOutputs bool
var suppressPermaLink bool
var suppressPermaLink string
var yes bool
var targets *[]string
var targetDependents bool
@ -86,13 +86,33 @@ func newDestroyCmd() *cobra.Command {
ShowReplacementSteps: showReplacementSteps,
ShowSameResources: showSames,
SuppressOutputs: suppressOutputs,
SuppressPermaLink: suppressPermaLink,
IsInteractive: interactive,
Type: displayType,
EventLogPath: eventLogPath,
Debug: debug,
}
// we only suppress permalinks if the user passes true. the default is an empty string
// which we pass as 'false'
//nolint:goconst
if suppressPermaLink == "true" {
opts.Display.SuppressPermaLink = true
} else {
opts.Display.SuppressPermaLink = false
}
filestateBackend, err := isFilestateBackend(opts.Display)
if err != nil {
return result.FromError(err)
}
// by default, we are going to suppress the permalink when using self-managed backends
// this can be re-enabled by explicitly passing "false" to the `supppress-permalink` flag
//nolint:goconst
if suppressPermaLink != "false" && filestateBackend {
opts.Display.SuppressPermaLink = true
}
s, err := requireStack(stack, false, opts.Display, true /*setCurrent*/)
if err != nil {
return result.FromError(err)
@ -200,9 +220,10 @@ func newDestroyCmd() *cobra.Command {
cmd.PersistentFlags().BoolVar(
&suppressOutputs, "suppress-outputs", false,
"Suppress display of stack outputs (in case they contain sensitive values)")
cmd.PersistentFlags().BoolVar(
&suppressPermaLink, "suppress-permalink", false,
cmd.PersistentFlags().StringVar(
&suppressPermaLink, "suppress-permalink", "",
"Suppress display of the state permalink")
cmd.Flag("suppress-permalink").NoOptDefVal = "false"
cmd.PersistentFlags().BoolVarP(
&yes, "yes", "y", false,

View file

@ -270,7 +270,7 @@ func newImportCmd() *cobra.Command {
var showConfig bool
var skipPreview bool
var suppressOutputs bool
var suppressPermaLink bool
var suppressPermaLink string
var yes bool
var protectResources bool
@ -383,14 +383,32 @@ func newImportCmd() *cobra.Command {
}
opts.Display = display.Options{
Color: cmdutil.GetGlobalColorization(),
ShowConfig: showConfig,
SuppressOutputs: suppressOutputs,
SuppressPermaLink: suppressPermaLink,
IsInteractive: interactive,
Type: displayType,
EventLogPath: eventLogPath,
Debug: debug,
Color: cmdutil.GetGlobalColorization(),
ShowConfig: showConfig,
SuppressOutputs: suppressOutputs,
IsInteractive: interactive,
Type: displayType,
EventLogPath: eventLogPath,
Debug: debug,
}
// we only suppress permalinks if the user passes true. the default is an empty string
// which we pass as 'false'
if suppressPermaLink == "true" {
opts.Display.SuppressPermaLink = true
} else {
opts.Display.SuppressPermaLink = false
}
filestateBackend, err := isFilestateBackend(opts.Display)
if err != nil {
return result.FromError(err)
}
// by default, we are going to suppress the permalink when using self-managed backends
// this can be re-enabled by explicitly passing "false" to the `supppress-permalink` flag
if suppressPermaLink != "false" && filestateBackend {
opts.Display.SuppressPermaLink = true
}
// Fetch the project.
@ -541,9 +559,10 @@ func newImportCmd() *cobra.Command {
cmd.PersistentFlags().BoolVar(
&suppressOutputs, "suppress-outputs", false,
"Suppress display of stack outputs (in case they contain sensitive values)")
cmd.PersistentFlags().BoolVar(
&suppressPermaLink, "suppress-permalink", false,
cmd.PersistentFlags().StringVar(
&suppressPermaLink, "suppress-permalink", "",
"Suppress display of the state permalink")
cmd.Flag("suppress-permalink").NoOptDefVal = "false"
cmd.PersistentFlags().BoolVarP(
&yes, "yes", "y", false,
"Automatically approve and perform the refresh after previewing it")

View file

@ -49,7 +49,7 @@ func newPreviewCmd() *cobra.Command {
var showSames bool
var showReads bool
var suppressOutputs bool
var suppressPermaLink bool
var suppressPermaLink string
var targets []string
var replaces []string
var targetReplaces []string
@ -85,7 +85,6 @@ func newPreviewCmd() *cobra.Command {
ShowSameResources: showSames,
ShowReads: showReads,
SuppressOutputs: suppressOutputs,
SuppressPermaLink: suppressPermaLink,
IsInteractive: cmdutil.Interactive(),
Type: displayType,
JSONDisplay: jsonDisplay,
@ -93,6 +92,24 @@ func newPreviewCmd() *cobra.Command {
Debug: debug,
}
// we only suppress permalinks if the user passes true. the default is an empty string
// which we pass as 'false'
if suppressPermaLink == "true" {
displayOpts.SuppressPermaLink = true
} else {
displayOpts.SuppressPermaLink = false
}
filestateBackend, err := isFilestateBackend(displayOpts)
if err != nil {
return result.FromError(err)
}
// by default, we are going to suppress the permalink when using self-managed backends
// this can be re-enabled by explicitly passing "false" to the `supppress-permalink` flag
if suppressPermaLink != "false" && filestateBackend {
displayOpts.SuppressPermaLink = true
}
if err := validatePolicyPackConfig(policyPackPaths, policyPackConfigPaths); err != nil {
return result.FromError(err)
}
@ -253,13 +270,14 @@ func newPreviewCmd() *cobra.Command {
cmd.PersistentFlags().BoolVar(
&showReads, "show-reads", false,
"Show resources that are being read in, alongside those being managed directly in the stack")
cmd.PersistentFlags().BoolVar(
&suppressOutputs, "suppress-outputs", false,
"Suppress display of stack outputs (in case they contain sensitive values)")
cmd.PersistentFlags().BoolVar(
&suppressPermaLink, "suppress-permalink", false,
cmd.PersistentFlags().StringVar(
&suppressPermaLink, "suppress-permalink", "",
"Suppress display of the state permalink")
cmd.Flag("suppress-permalink").NoOptDefVal = "false"
if hasDebugCommands() {
cmd.PersistentFlags().StringVar(

View file

@ -44,7 +44,7 @@ func newRefreshCmd() *cobra.Command {
var showSames bool
var skipPreview bool
var suppressOutputs bool
var suppressPermaLink bool
var suppressPermaLink string
var yes bool
var targets *[]string
@ -84,13 +84,31 @@ func newRefreshCmd() *cobra.Command {
ShowReplacementSteps: showReplacementSteps,
ShowSameResources: showSames,
SuppressOutputs: suppressOutputs,
SuppressPermaLink: suppressPermaLink,
IsInteractive: interactive,
Type: displayType,
EventLogPath: eventLogPath,
Debug: debug,
}
// we only suppress permalinks if the user passes true. the default is an empty string
// which we pass as 'false'
if suppressPermaLink == "true" {
opts.Display.SuppressPermaLink = true
} else {
opts.Display.SuppressPermaLink = false
}
filestateBackend, err := isFilestateBackend(opts.Display)
if err != nil {
return result.FromError(err)
}
// by default, we are going to suppress the permalink when using self-managed backends
// this can be re-enabled by explicitly passing "false" to the `supppress-permalink` flag
if suppressPermaLink != "false" && filestateBackend {
opts.Display.SuppressPermaLink = true
}
s, err := requireStack(stack, true, opts.Display, true /*setCurrent*/)
if err != nil {
return result.FromError(err)
@ -193,9 +211,10 @@ func newRefreshCmd() *cobra.Command {
cmd.PersistentFlags().BoolVar(
&suppressOutputs, "suppress-outputs", false,
"Suppress display of stack outputs (in case they contain sensitive values)")
cmd.PersistentFlags().BoolVar(
&suppressPermaLink, "suppress-permalink", false,
cmd.PersistentFlags().StringVar(
&suppressPermaLink, "suppress-permalink", "",
"Suppress display of the state permalink")
cmd.Flag("suppress-permalink").NoOptDefVal = "false"
cmd.PersistentFlags().BoolVarP(
&yes, "yes", "y", false,
"Automatically approve and perform the refresh after previewing it")

View file

@ -66,7 +66,7 @@ func newUpCmd() *cobra.Command {
var showReads bool
var skipPreview bool
var suppressOutputs bool
var suppressPermaLink bool
var suppressPermaLink string
var yes bool
var secretsProvider string
var targets []string
@ -364,13 +364,31 @@ func newUpCmd() *cobra.Command {
ShowSameResources: showSames,
ShowReads: showReads,
SuppressOutputs: suppressOutputs,
SuppressPermaLink: suppressPermaLink,
IsInteractive: interactive,
Type: displayType,
EventLogPath: eventLogPath,
Debug: debug,
}
// we only suppress permalinks if the user passes true. the default is an empty string
// which we pass as 'false'
if suppressPermaLink == "true" {
opts.Display.SuppressPermaLink = true
} else {
opts.Display.SuppressPermaLink = false
}
filestateBackend, err := isFilestateBackend(opts.Display)
if err != nil {
return result.FromError(err)
}
// by default, we are going to suppress the permalink when using self-managed backends
// this can be re-enabled by explicitly passing "false" to the `supppress-permalink` flag
if suppressPermaLink != "false" && filestateBackend {
opts.Display.SuppressPermaLink = true
}
if len(args) > 0 {
return upTemplateNameOrURL(args[0], opts)
}
@ -461,9 +479,10 @@ func newUpCmd() *cobra.Command {
cmd.PersistentFlags().BoolVar(
&suppressOutputs, "suppress-outputs", false,
"Suppress display of stack outputs (in case they contain sensitive values)")
cmd.PersistentFlags().BoolVar(
&suppressPermaLink, "suppress-permalink", false,
cmd.PersistentFlags().StringVar(
&suppressPermaLink, "suppress-permalink", "",
"Suppress display of the state permalink")
cmd.Flag("suppress-permalink").NoOptDefVal = "false"
cmd.PersistentFlags().BoolVarP(
&yes, "yes", "y", false,
"Automatically approve and perform the update after previewing it")

View file

@ -88,6 +88,19 @@ func skipConfirmations() bool {
// backendInstance is used to inject a backend mock from tests.
var backendInstance backend.Backend
func isFilestateBackend(opts display.Options) (bool, error) {
if backendInstance != nil {
return false, nil
}
url, err := workspace.GetCurrentCloudURL()
if err != nil {
return false, errors.Wrapf(err, "could not get cloud url")
}
return filestate.IsFileStateBackendURL(url), nil
}
func currentBackend(opts display.Options) (backend.Backend, error) {
if backendInstance != nil {
return backendInstance, nil