Add --version flag to 'pulumi stack export' (#3906)
* Add --version flag to 'pulumi stack export' * Update CHANGELOG * Update/rebase with latest * Fix lint warning
This commit is contained in:
parent
54d344f7c1
commit
ba046b063b
|
@ -17,6 +17,9 @@ CHANGELOG
|
||||||
- Move .NET SDK attributes to the root namespace.
|
- Move .NET SDK attributes to the root namespace.
|
||||||
[#3902](https://github.com/pulumi/pulumi/pull/3902)
|
[#3902](https://github.com/pulumi/pulumi/pull/3902)
|
||||||
|
|
||||||
|
- Support exporting older stack versions.
|
||||||
|
[#3906](https://github.com/pulumi/pulumi/pull/3906)
|
||||||
|
|
||||||
## 1.10.1 (2020-02-06)
|
## 1.10.1 (2020-02-06)
|
||||||
- Support stack references in the Go SDK.
|
- Support stack references in the Go SDK.
|
||||||
[#3829](https://github.com/pulumi/pulumi/pull/3829)
|
[#3829](https://github.com/pulumi/pulumi/pull/3829)
|
||||||
|
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/pkg/apitype"
|
||||||
|
"github.com/pulumi/pulumi/pkg/backend"
|
||||||
"github.com/pulumi/pulumi/pkg/backend/display"
|
"github.com/pulumi/pulumi/pkg/backend/display"
|
||||||
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
||||||
)
|
)
|
||||||
|
@ -28,6 +30,7 @@ import (
|
||||||
func newStackExportCmd() *cobra.Command {
|
func newStackExportCmd() *cobra.Command {
|
||||||
var file string
|
var file string
|
||||||
var stackName string
|
var stackName string
|
||||||
|
var version string
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "export",
|
Use: "export",
|
||||||
|
@ -40,6 +43,7 @@ func newStackExportCmd() *cobra.Command {
|
||||||
"in a stack's state due to failed deployments, manual changes to cloud\n" +
|
"in a stack's state due to failed deployments, manual changes to cloud\n" +
|
||||||
"resources, etc.",
|
"resources, etc.",
|
||||||
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := commandContext()
|
||||||
opts := display.Options{
|
opts := display.Options{
|
||||||
Color: cmdutil.GetGlobalColorization(),
|
Color: cmdutil.GetGlobalColorization(),
|
||||||
}
|
}
|
||||||
|
@ -50,9 +54,28 @@ func newStackExportCmd() *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
deployment, err := s.ExportDeployment(commandContext())
|
var deployment *apitype.UntypedDeployment
|
||||||
if err != nil {
|
// Export the latest version of the checkpoint by default. Otherwise, we require that
|
||||||
return err
|
// the backend/stack implements the ability the export previous checkpoints.
|
||||||
|
if version == "" {
|
||||||
|
deployment, err = s.ExportDeployment(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check that the stack and its backend supports the ability to do this.
|
||||||
|
be := s.Backend()
|
||||||
|
specificExpBE, ok := be.(backend.SpecificDeploymentExporter)
|
||||||
|
if !ok {
|
||||||
|
return errors.Errorf(
|
||||||
|
"the current backend (%s) does not provide the ability to export previous deployments",
|
||||||
|
be.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
deployment, err = specificExpBE.ExportDeploymentForVersion(ctx, s, version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from stdin or a specified file.
|
// Read from stdin or a specified file.
|
||||||
|
@ -77,5 +100,7 @@ func newStackExportCmd() *cobra.Command {
|
||||||
&stackName, "stack", "s", "", "The name of the stack to operate on. Defaults to the current stack")
|
&stackName, "stack", "s", "", "The name of the stack to operate on. Defaults to the current stack")
|
||||||
cmd.PersistentFlags().StringVarP(
|
cmd.PersistentFlags().StringVarP(
|
||||||
&file, "file", "", "", "A filename to write stack output to")
|
&file, "file", "", "", "A filename to write stack output to")
|
||||||
|
cmd.PersistentFlags().StringVarP(
|
||||||
|
&version, "version", "", "", "Previous stack version to export. (If unset, will export the latest.)")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,17 @@ type Backend interface {
|
||||||
CurrentUser() (string, error)
|
CurrentUser() (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SpecificDeploymentExporter is an interface defining an additional capability of a Backend, specifically the
|
||||||
|
// ability to export a specific versions of a stack's deployment. This isn't a requirement for all backends and
|
||||||
|
// should be checked for dynamically.
|
||||||
|
type SpecificDeploymentExporter interface {
|
||||||
|
// ExportDeploymentForVersion exports a specific deployment from the history of a stack. The meaning of
|
||||||
|
// version is backend-specific. For the Pulumi Console, it is the numeric version. (The first update
|
||||||
|
// being version "1", the second "2", and so on.) Though this might change in the future to use some
|
||||||
|
// other type of identifier or commitish .
|
||||||
|
ExportDeploymentForVersion(ctx context.Context, stack Stack, version string) (*apitype.UntypedDeployment, error)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateOperation is a complete stack update operation (preview, update, refresh, or destroy).
|
// UpdateOperation is a complete stack update operation (preview, update, refresh, or destroy).
|
||||||
type UpdateOperation struct {
|
type UpdateOperation struct {
|
||||||
Proj *workspace.Project
|
Proj *workspace.Project
|
||||||
|
|
|
@ -125,6 +125,9 @@ type cloudBackend struct {
|
||||||
currentProject *workspace.Project
|
currentProject *workspace.Project
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assert we implement the backend.Backend and backend.SpecificDeploymentExporter interfaces.
|
||||||
|
var _ backend.SpecificDeploymentExporter = &cloudBackend{}
|
||||||
|
|
||||||
// New creates a new Pulumi backend for the given cloud API URL and token.
|
// New creates a new Pulumi backend for the given cloud API URL and token.
|
||||||
func New(d diag.Sink, cloudURL string) (Backend, error) {
|
func New(d diag.Sink, cloudURL string) (Backend, error) {
|
||||||
cloudURL = ValueOrDefaultURL(cloudURL)
|
cloudURL = ValueOrDefaultURL(cloudURL)
|
||||||
|
@ -1160,17 +1163,32 @@ func (b *cloudBackend) GetLogs(ctx context.Context, stack backend.Stack, cfg bac
|
||||||
|
|
||||||
func (b *cloudBackend) ExportDeployment(ctx context.Context,
|
func (b *cloudBackend) ExportDeployment(ctx context.Context,
|
||||||
stack backend.Stack) (*apitype.UntypedDeployment, error) {
|
stack backend.Stack) (*apitype.UntypedDeployment, error) {
|
||||||
return b.exportDeployment(ctx, stack.Ref())
|
return b.exportDeployment(ctx, stack.Ref(), nil /* latest */)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *cloudBackend) exportDeployment(ctx context.Context,
|
func (b *cloudBackend) ExportDeploymentForVersion(
|
||||||
stackRef backend.StackReference) (*apitype.UntypedDeployment, error) {
|
ctx context.Context, stack backend.Stack, version string) (*apitype.UntypedDeployment, error) {
|
||||||
|
// The Pulumi Console defines versions as a positive integer. Parse the provided version string and
|
||||||
|
// ensure it is valid.
|
||||||
|
//
|
||||||
|
// The first stack update version is 1, and monotonically increasing from there.
|
||||||
|
versionNumber, err := strconv.Atoi(version)
|
||||||
|
if err != nil || versionNumber <= 0 {
|
||||||
|
return nil, errors.Errorf("%q is not a valid stack version. It should be a positive integer.", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.exportDeployment(ctx, stack.Ref(), &versionNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// exportDeployment exports the checkpoint file for a stack, optionally getting a previous version.
|
||||||
|
func (b *cloudBackend) exportDeployment(
|
||||||
|
ctx context.Context, stackRef backend.StackReference, version *int) (*apitype.UntypedDeployment, error) {
|
||||||
stack, err := b.getCloudStackIdentifier(stackRef)
|
stack, err := b.getCloudStackIdentifier(stackRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
deployment, err := b.client.ExportStackDeployment(ctx, stack)
|
deployment, err := b.client.ExportStackDeployment(ctx, stack, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,11 +376,19 @@ func (pc *Client) GetStackUpdates(ctx context.Context, stack StackIdentifier) ([
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportStackDeployment exports the indicated stack's deployment as a raw JSON message.
|
// ExportStackDeployment exports the indicated stack's deployment as a raw JSON message.
|
||||||
func (pc *Client) ExportStackDeployment(ctx context.Context,
|
// If version is nil, will export the latest version of the stack.
|
||||||
stack StackIdentifier) (apitype.UntypedDeployment, error) {
|
func (pc *Client) ExportStackDeployment(
|
||||||
|
ctx context.Context, stack StackIdentifier, version *int) (apitype.UntypedDeployment, error) {
|
||||||
|
|
||||||
|
path := getStackPath(stack, "export")
|
||||||
|
|
||||||
|
// Tack on a specific version as desired.
|
||||||
|
if version != nil {
|
||||||
|
path += fmt.Sprintf("/%d", *version)
|
||||||
|
}
|
||||||
|
|
||||||
var resp apitype.ExportStackResponse
|
var resp apitype.ExportStackResponse
|
||||||
if err := pc.restCall(ctx, "GET", getStackPath(stack, "export"), nil, nil, &resp); err != nil {
|
if err := pc.restCall(ctx, "GET", path, nil, nil, &resp); err != nil {
|
||||||
return apitype.UntypedDeployment{}, err
|
return apitype.UntypedDeployment{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ func (b *cloudBackend) newUpdate(ctx context.Context, stackRef backend.StackRefe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *cloudBackend) getSnapshot(ctx context.Context, stackRef backend.StackReference) (*deploy.Snapshot, error) {
|
func (b *cloudBackend) getSnapshot(ctx context.Context, stackRef backend.StackReference) (*deploy.Snapshot, error) {
|
||||||
untypedDeployment, err := b.exportDeployment(ctx, stackRef)
|
untypedDeployment, err := b.exportDeployment(ctx, stackRef, nil /* get latest */)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue