pulumi/cmd/preview.go

178 lines
6 KiB
Go
Raw Normal View History

2018-05-22 21:43:36 +02:00
// Copyright 2016-2018, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/backend"
"github.com/pulumi/pulumi/pkg/backend/display"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/util/cmdutil"
"github.com/pulumi/pulumi/pkg/util/result"
)
func newPreviewCmd() *cobra.Command {
var debug bool
var expectNop bool
var message string
var stack string
// Flags for engine.UpdateOptions.
var analyzers []string
var diffDisplay bool
var jsonDisplay bool
var parallel int
var showConfig bool
var showReplacementSteps bool
var showSames bool
var suppressOutputs bool
var cmd = &cobra.Command{
Use: "preview",
Aliases: []string{"pre"},
SuggestFor: []string{"build", "plan"},
Short: "Show a preview of updates to a stack's resources",
Long: "Show a preview of updates a stack's resources.\n" +
"\n" +
"This command displays a preview of the updates to an existing stack whose state is\n" +
2019-03-02 20:04:09 +01:00
"represented by an existing state file. The new desired state is computed by running\n" +
"a Pulumi program, and extracting all resource allocations from its resulting object graph.\n" +
"These allocations are then compared against the existing state to determine what\n" +
"operations must take place to achieve the desired state. No changes to the stack will\n" +
"actually take place.\n" +
"\n" +
"The program to run is loaded from the project in the current directory. Use the `-C` or\n" +
"`--cwd` flag to use a different directory.",
Args: cmdutil.NoArgs,
Run: cmdutil.RunResultFunc(func(cmd *cobra.Command, args []string) result.Result {
var displayType = display.DisplayProgress
if diffDisplay {
displayType = display.DisplayDiff
}
opts := backend.UpdateOptions{
Engine: engine.UpdateOptions{
Defer all diffs to resource providers. (#2849) Thse changes make a subtle but critical adjustment to the process the Pulumi engine uses to determine whether or not a difference exists between a resource's actual and desired states, and adjusts the way this difference is calculated and displayed accordingly. Today, the Pulumi engine get the first chance to decide whether or not there is a difference between a resource's actual and desired states. It does this by comparing the current set of inputs for a resource (i.e. the inputs from the running Pulumi program) with the last set of inputs used to update the resource. If there is no difference between the old and new inputs, the engine decides that no change is necessary without consulting the resource's provider. Only if there are changes does the engine consult the resource's provider for more information about the difference. This can be problematic for a number of reasons: - Not all providers do input-input comparison; some do input-state comparison - Not all providers are able to update the last deployed set of inputs when performing a refresh - Some providers--either intentionally or due to bugs--may see changes in resources whose inputs have not changed All of these situations are confusing at the very least, and the first is problematic with respect to correctness. Furthermore, the display code only renders diffs it observes rather than rendering the diffs observed by the provider, which can obscure the actual changes detected at runtime. These changes address both of these issues: - Rather than comparing the current inputs against the last inputs before calling a resource provider's Diff function, the engine calls the Diff function in all cases. - Providers may now return a list of properties that differ between the requested and actual state and the way in which they differ. This information will then be used by the CLI to render the diff appropriately. A provider may also indicate that a particular diff is between old and new inputs rather than old state and new inputs. Fixes #2453.
2019-07-01 21:34:19 +02:00
Analyzers: analyzers,
Parallel: parallel,
Debug: debug,
UseLegacyDiff: useLegacyDiff(),
},
Display: display.Options{
Color: cmdutil.GetGlobalColorization(),
ShowConfig: showConfig,
ShowReplacementSteps: showReplacementSteps,
ShowSameResources: showSames,
SuppressOutputs: suppressOutputs,
IsInteractive: cmdutil.Interactive(),
Type: displayType,
JSONDisplay: jsonDisplay,
Debug: debug,
},
}
Initial support for passing URLs to `new` and `up` (#1727) * Initial support for passing URLs to `new` and `up` This PR adds initial support for `pulumi new` using Git under the covers to manage Pulumi templates, providing the same experience as before. You can now also optionally pass a URL to a Git repository, e.g. `pulumi new [<url>]`, including subdirectories within the repository, and arbitrary branches, tags, or commits. The following commands result in the same behavior from the user's perspective: - `pulumi new javascript` - `pulumi new https://github.com/pulumi/templates/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/master/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates/javascript` To specify an arbitrary branch, tag, or commit: - `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates/javascript` - `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates/javascript` Branches and tags can include '/' separators, and `pulumi` will still find the right subdirectory. URLs to Gists are also supported, e.g.: `pulumi new https://gist.github.com/justinvp/6673959ceb9d2ac5a14c6d536cb871a6` If the specified subdirectory in the repository does not contain a `Pulumi.yaml`, it will look for subdirectories within containing `Pulumi.yaml` files, and prompt the user to choose a template, along the lines of how `pulumi new` behaves when no template is specified. The following commands result in the CLI prompting to choose a template: - `pulumi new` - `pulumi new https://github.com/pulumi/templates/templates` - `pulumi new https://github.com/pulumi/templates/tree/master/templates` - `pulumi new https://github.com/pulumi/templates/tree/HEAD/templates` Of course, arbitrary branches, tags, or commits can be specified as well: - `pulumi new https://github.com/pulumi/templates/tree/<branch>/templates` - `pulumi new https://github.com/pulumi/templates/tree/<tag>/templates` - `pulumi new https://github.com/pulumi/templates/tree/<commit>/templates` This PR also includes initial support for passing URLs to `pulumi up`, providing a streamlined way to deploy installable cloud applications with Pulumi, without having to manage source code locally before doing a deployment. For example, `pulumi up https://github.com/justinvp/aws` can be used to deploy a sample AWS app. The stack can be updated with different versions, e.g. `pulumi up https://github.com/justinvp/aws/tree/v2 -s <stack-to-update>` Config values can optionally be passed via command line flags, e.g. `pulumi up https://github.com/justinvp/aws -c aws:region=us-west-2 -c foo:bar=blah` Gists can also be used, e.g. `pulumi up https://gist.github.com/justinvp/62fde0463f243fcb49f5a7222e51bc76` * Fix panic when hitting ^C from "choose template" prompt * Add description to templates When running `pulumi new` without specifying a template, include the template description along with the name in the "choose template" display. ``` $ pulumi new Please choose a template: aws-go A minimal AWS Go program aws-javascript A minimal AWS JavaScript program aws-python A minimal AWS Python program aws-typescript A minimal AWS TypeScript program > go A minimal Go program hello-aws-javascript A simple AWS serverless JavaScript program javascript A minimal JavaScript program python A minimal Python program typescript A minimal TypeScript program ``` * React to changes to the pulumi/templates repo. We restructured the `pulumi/templates` repo to have all the templates in the root instead of in a `templates` subdirectory, so make the change here to no longer look for templates in `templates`. This also fixes an issue around using `Depth: 1` that I found while testing this. When a named template is used, we attempt to clone or pull from the `pulumi/templates` repo to `~/.pulumi/templates`. Having it go in this well-known directory allows us to maintain previous behavior around allowing offline use of templates. If we use `Depth: 1` for the initial clone, it will fail when attempting to pull when there are updates to the remote repository. Unfortunately, there's no built-in `--unshallow` support in `go-git` and setting a larger `Depth` doesn't appear to help. There may be a workaround, but for now, if we're cloning the pulumi templates directory to `~/.pulumi/templates`, we won't use `Depth: 1`. For template URLs, we will continue to use `Depth: 1` as we clone those to a temp directory (which gets deleted) that we'll never try to update. * List available templates in help text * Address PR Feedback * Don't show "Installing dependencies" message for `up` * Fix secrets handling When prompting for config, if the existing stack value is a secret, keep it a secret and mask the prompt. If the template says it should be secret, make it a secret. * Fix ${PROJECT} and ${DESCRIPTION} handling for `up` Templates used with `up` should already have a filled-in project name and description, but if it's a `new`-style template, that has `${PROJECT}` and/or `${DESCRIPTION}`, be helpful and just replace these with better values. * Fix stack handling Add a bool `setCurrent` param to `requireStack` to control whether the current stack should be saved in workspace settings. For the `up <url>` case, we don't want to save. Also, split the `up` code into two separate functions: one for the `up <url>` case and another for the normal `up` case where you have workspace in your current directory. While we may be able to combine them back into a single function, right now it's a bit cleaner being separate, even with some small amount of duplication. * Fix panic due to nil crypter Lazily get the crypter only if needed inside `promptForConfig`. * Embellish comment * Harden isPreconfiguredEmptyStack check Fix the code to check to make sure the URL specified on the command line matches the URL stored in the `pulumi:template` config value, and that the rest of the config from the stack satisfies the config requirements of the template.
2018-08-11 03:08:16 +02:00
s, err := requireStack(stack, true, opts.Display, true /*setCurrent*/)
if err != nil {
return result.FromError(err)
}
proj, root, err := readProject()
if err != nil {
return result.FromError(err)
}
m, err := getUpdateMetadata("", root)
if err != nil {
return result.FromError(errors.Wrap(err, "gathering environment metadata"))
}
sm, err := getStackSecretsManager(s)
if err != nil {
return result.FromError(errors.Wrap(err, "getting secrets manager"))
}
cfg, err := getStackConfiguration(s, sm)
if err != nil {
return result.FromError(errors.Wrap(err, "getting stack configuration"))
}
changes, res := s.Preview(commandContext(), backend.UpdateOperation{
Proj: proj,
Root: root,
M: m,
Opts: opts,
StackConfiguration: cfg,
SecretsManager: sm,
Scopes: cancellationScopes,
})
switch {
case res != nil:
return PrintEngineResult(res)
2018-05-16 19:22:09 +02:00
case expectNop && changes != nil && changes.HasChanges():
return result.FromError(errors.New("error: no changes were expected but changes were proposed"))
default:
return nil
}
}),
}
cmd.PersistentFlags().BoolVarP(
&debug, "debug", "d", false,
"Print detailed debugging output during resource operations")
cmd.PersistentFlags().BoolVar(
&expectNop, "expect-no-changes", false,
"Return an error if any changes are proposed by this preview")
cmd.PersistentFlags().StringVarP(
&stack, "stack", "s", "",
"The name of the stack to operate on. Defaults to the current stack")
cmd.PersistentFlags().StringVar(
&stackConfigFile, "config-file", "",
"Use the configuration values in the specified file rather than detecting the file name")
cmd.PersistentFlags().StringVarP(
&message, "message", "m", "",
"Optional message to associate with the preview operation")
// Flags for engine.UpdateOptions.
cmd.PersistentFlags().StringSliceVar(
&analyzers, "analyzer", []string{},
"Run one or more analyzers as part of this update")
cmd.PersistentFlags().BoolVar(
&diffDisplay, "diff", false,
"Display operation as a rich diff showing the overall change")
cmd.Flags().BoolVarP(
&jsonDisplay, "json", "j", false,
"Serialize the preview diffs, operations, and overall output as JSON")
cmd.PersistentFlags().IntVarP(
&parallel, "parallel", "p", defaultParallel,
"Allow P resource operations to run in parallel at once (1 for no parallelism). Defaults to unbounded.")
cmd.PersistentFlags().BoolVar(
&showConfig, "show-config", false,
"Show configuration keys and variables")
Implement `get` functions on all resources This change implements the `get` function for resources. Per pulumi/lumi#83, this allows Lumi scripts to actually read from the target environment. For example, we can now look up a SecurityGroup from its ARN: let group = aws.ec2.SecurityGroup.get( "arn:aws:ec2:us-west-2:153052954103:security-group:sg-02150d79"); The returned object is a fully functional resource object. So, we can then link it up with an EC2 instance, for example, in the usual ways: let instance = new aws.ec2.Instance(..., { securityGroups: [ group ], }); This didn't require any changes to the RPC or provider model, since we already implement the Get function. There are a few loose ends; two are short term: 1) URNs are not rehydrated. 2) Query is not yet implemented. One is mid-term: 3) We probably want a URN-based lookup function. But we will likely wait until we tackle pulumi/lumi#109 before adding this. And one is long term (and subtle): 4) These amount to I/O and are not repeatable! A change in the target environment may cause a script to generate a different plan intermittently. Most likely we want to apply a different kind of deployment "policy" for such scripts. These are inching towards the scripting model of pulumi/lumi#121, which is an entirely different beast than the repeatable immutable infrastructure deployments. Finally, it is worth noting that with this, we have some of the fundamental underpinnings required to finally tackle "inference" (pulumi/lumi#142).
2017-06-20 02:24:00 +02:00
cmd.PersistentFlags().BoolVar(
&showReplacementSteps, "show-replacement-steps", false,
"Show detailed resource replacement creates and deletes instead of a single step")
cmd.PersistentFlags().BoolVar(
&showSames, "show-sames", false,
"Show resources that needn't be updated because they haven't changed, alongside those that do")
cmd.PersistentFlags().BoolVar(
&suppressOutputs, "suppress-outputs", false,
"Suppress display of stack outputs (in case they contain sensitive values)")
return cmd
}