2024-01-30 15:53:10 +00:00
|
|
|
package diy
|
2023-03-15 00:43:18 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/backend"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/stack"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/secrets/b64"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/encoding"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/testing/diagtest"
|
|
|
|
)
|
|
|
|
|
|
|
|
// This file contains copies of old backend tests
|
|
|
|
// that were upgraded to run with project support.
|
|
|
|
// This duplicates those tests to run with legacy, non-project state,
|
|
|
|
// validating that the legacy behavior is preserved.
|
|
|
|
|
|
|
|
//nolint:paralleltest // mutates environment variables
|
|
|
|
func TestListStacksWithMultiplePassphrases_legacy(t *testing.T) {
|
2024-01-30 15:53:10 +00:00
|
|
|
// Login to a temp dir diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
|
|
|
ctx := context.Background()
|
|
|
|
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Create stack "a" and import a checkpoint with a secret
|
|
|
|
aStackRef, err := b.ParseStackReference("a")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
aStack, err := b.CreateStack(ctx, aStackRef, "", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, aStack)
|
|
|
|
defer func() {
|
|
|
|
t.Setenv("PULUMI_CONFIG_PASSPHRASE", "abc123")
|
|
|
|
_, err := b.RemoveStack(ctx, aStack, true)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}()
|
|
|
|
deployment, err := makeUntypedDeployment("a", "abc123",
|
|
|
|
"v1:4iF78gb0nF0=:v1:Co6IbTWYs/UdrjgY:FSrAWOFZnj9ealCUDdJL7LrUKXX9BA==")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
t.Setenv("PULUMI_CONFIG_PASSPHRASE", "abc123")
|
|
|
|
err = b.ImportDeployment(ctx, aStack, deployment)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Create stack "b" and import a checkpoint with a secret
|
|
|
|
bStackRef, err := b.ParseStackReference("b")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
bStack, err := b.CreateStack(ctx, bStackRef, "", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, bStack)
|
|
|
|
defer func() {
|
|
|
|
t.Setenv("PULUMI_CONFIG_PASSPHRASE", "123abc")
|
|
|
|
_, err := b.RemoveStack(ctx, bStack, true)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}()
|
|
|
|
deployment, err = makeUntypedDeployment("b", "123abc",
|
|
|
|
"v1:C7H2a7/Ietk=:v1:yfAd1zOi6iY9DRIB:dumdsr+H89VpHIQWdB01XEFqYaYjAg==")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
t.Setenv("PULUMI_CONFIG_PASSPHRASE", "123abc")
|
|
|
|
err = b.ImportDeployment(ctx, bStack, deployment)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Remove the config passphrase so that we can no longer deserialize the checkpoints
|
|
|
|
err = os.Unsetenv("PULUMI_CONFIG_PASSPHRASE")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Ensure that we can list the stacks we created even without a passphrase
|
|
|
|
stacks, outContToken, err := b.ListStacks(ctx, backend.ListStacksFilter{}, nil /* inContToken */)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Nil(t, outContToken)
|
|
|
|
assert.Len(t, stacks, 2)
|
|
|
|
for _, stack := range stacks {
|
|
|
|
assert.NotNil(t, stack.ResourceCount())
|
|
|
|
assert.Equal(t, 1, *stack.ResourceCount())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDrillError_legacy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// Login to a temp dir diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
|
|
|
ctx := context.Background()
|
|
|
|
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Get a non-existent stack and expect a nil error because it won't be found.
|
|
|
|
stackRef, err := b.ParseStackReference("dev")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %v when parsing stack reference", err)
|
|
|
|
}
|
|
|
|
_, err = b.GetStack(ctx, stackRef)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2023-03-15 00:43:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCancel_legacy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// Login to a temp dir diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
|
|
|
ctx := context.Background()
|
|
|
|
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Check that trying to cancel a stack that isn't created yet doesn't error
|
|
|
|
aStackRef, err := b.ParseStackReference("a")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
err = b.CancelCurrentUpdate(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Check that trying to cancel a stack that isn't locked doesn't error
|
|
|
|
aStack, err := b.CreateStack(ctx, aStackRef, "", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, aStack)
|
|
|
|
err = b.CancelCurrentUpdate(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Locking and lock checks are only part of the internal interface
|
2024-01-30 15:53:10 +00:00
|
|
|
lb, ok := b.(*diyBackend)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.True(t, ok)
|
|
|
|
assert.NotNil(t, lb)
|
|
|
|
|
|
|
|
// Lock the stack and check CancelCurrentUpdate deletes the lock file
|
|
|
|
err = lb.Lock(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
// check the lock file exists
|
|
|
|
lockExists, err := lb.bucket.Exists(ctx, lb.lockPath(aStackRef))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, lockExists)
|
|
|
|
// Call CancelCurrentUpdate
|
|
|
|
err = lb.CancelCurrentUpdate(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
// Now check the lock file no longer exists
|
|
|
|
lockExists, err = lb.bucket.Exists(ctx, lb.lockPath(aStackRef))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, lockExists)
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// Make another diy backend which will have a different lockId
|
2023-03-15 00:43:18 +00:00
|
|
|
ob, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
2024-01-30 15:53:10 +00:00
|
|
|
otherBackend, ok := ob.(*diyBackend)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.True(t, ok)
|
|
|
|
assert.NotNil(t, lb)
|
|
|
|
|
|
|
|
// Lock the stack with this new backend, then check that checkForLocks on the first backend now errors
|
|
|
|
err = otherBackend.Lock(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
err = lb.checkForLock(ctx, aStackRef)
|
|
|
|
assert.Error(t, err)
|
|
|
|
// Now call CancelCurrentUpdate and check that checkForLocks no longer errors
|
|
|
|
err = lb.CancelCurrentUpdate(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
err = lb.checkForLock(ctx, aStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRemoveMakesBackups_legacy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// Login to a temp dir diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
|
|
|
ctx := context.Background()
|
|
|
|
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Grab the bucket interface to test with
|
2024-01-30 15:53:10 +00:00
|
|
|
lb, ok := b.(*diyBackend)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.True(t, ok)
|
|
|
|
assert.NotNil(t, lb)
|
|
|
|
|
|
|
|
// Check that creating a new stack doesn't make a backup file
|
|
|
|
aStackRef, err := lb.parseStackReference("a")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
aStack, err := b.CreateStack(ctx, aStackRef, "", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, aStack)
|
|
|
|
|
|
|
|
// Check the stack file now exists, but the backup file doesn't
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err := lb.bucket.Exists(ctx, lb.stackPath(ctx, aStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, stackFileExists)
|
2023-04-03 21:36:44 +00:00
|
|
|
backupFileExists, err := lb.bucket.Exists(ctx, lb.stackPath(ctx, aStackRef)+".bak")
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, backupFileExists)
|
|
|
|
|
|
|
|
// Now remove the stack
|
|
|
|
removed, err := b.RemoveStack(ctx, aStack, false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, removed)
|
|
|
|
|
|
|
|
// Check the stack file is now gone, but the backup file exists
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err = lb.bucket.Exists(ctx, lb.stackPath(ctx, aStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, stackFileExists)
|
2023-04-03 21:36:44 +00:00
|
|
|
backupFileExists, err = lb.bucket.Exists(ctx, lb.stackPath(ctx, aStackRef)+".bak")
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, backupFileExists)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRenameWorks_legacy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// Login to a temp dir diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
|
|
|
ctx := context.Background()
|
|
|
|
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Grab the bucket interface to test with
|
2024-01-30 15:53:10 +00:00
|
|
|
lb, ok := b.(*diyBackend)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.True(t, ok)
|
|
|
|
assert.NotNil(t, lb)
|
|
|
|
|
|
|
|
// Create a new stack
|
|
|
|
aStackRef, err := lb.parseStackReference("a")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
aStack, err := b.CreateStack(ctx, aStackRef, "", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, aStack)
|
|
|
|
|
|
|
|
// Check the stack file now exists
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err := lb.bucket.Exists(ctx, lb.stackPath(ctx, aStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, stackFileExists)
|
|
|
|
|
|
|
|
// Fake up some history
|
2023-04-03 21:36:44 +00:00
|
|
|
err = lb.addToHistory(ctx, aStackRef, backend.UpdateInfo{Kind: apitype.DestroyUpdate})
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
// And pollute the history folder
|
|
|
|
err = lb.bucket.WriteAll(ctx, path.Join(aStackRef.HistoryDir(), "randomfile.txt"), []byte{0, 13}, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Rename the stack
|
|
|
|
bStackRefI, err := b.RenameStack(ctx, aStack, "b")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "b", bStackRefI.String())
|
2024-01-30 15:53:10 +00:00
|
|
|
bStackRef := bStackRefI.(*diyBackendReference)
|
2023-03-15 00:43:18 +00:00
|
|
|
|
|
|
|
// Check the new stack file now exists and the old one is gone
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err = lb.bucket.Exists(ctx, lb.stackPath(ctx, bStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, stackFileExists)
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err = lb.bucket.Exists(ctx, lb.stackPath(ctx, aStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, stackFileExists)
|
|
|
|
|
|
|
|
// Rename again
|
|
|
|
bStack, err := b.GetStack(ctx, bStackRef)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
cStackRefI, err := b.RenameStack(ctx, bStack, "c")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "c", cStackRefI.String())
|
2024-01-30 15:53:10 +00:00
|
|
|
cStackRef := cStackRefI.(*diyBackendReference)
|
2023-03-15 00:43:18 +00:00
|
|
|
|
|
|
|
// Check the new stack file now exists and the old one is gone
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err = lb.bucket.Exists(ctx, lb.stackPath(ctx, cStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, stackFileExists)
|
2023-04-03 21:36:44 +00:00
|
|
|
stackFileExists, err = lb.bucket.Exists(ctx, lb.stackPath(ctx, bStackRef))
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, stackFileExists)
|
|
|
|
|
|
|
|
// Check we can still get the history
|
|
|
|
history, err := b.GetHistory(ctx, cStackRef, 10, 0)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, history, 1)
|
|
|
|
assert.Equal(t, apitype.DestroyUpdate, history[0].Kind)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regression test for https://github.com/pulumi/pulumi/issues/10439
|
|
|
|
func TestHtmlEscaping_legacy(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
sm := b64.NewBase64SecretsManager()
|
|
|
|
resources := []*resource.State{
|
|
|
|
{
|
|
|
|
URN: resource.NewURN("a", "proj", "d:e:f", "a:b:c", "name"),
|
|
|
|
Type: "a:b:c",
|
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
resource.PropertyKey("html"): resource.NewStringProperty("<html@tags>"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
snap := deploy.NewSnapshot(deploy.Manifest{}, sm, resources, nil)
|
Lift context parameter to SerializeDeployment/Resource/Operations/Properties (#15929)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
SerializePropertyValue needed a `context.Context` object to pass to the
`config.Encrypter`. It was using `context.TODO()`, this change instead
accepts a context on the parameters and lifts that up to
SerializeProperties, SerializeResource, SerializeOperation, and
SerializeDeployment.
There were a few call sites for those methods that already had a context
on hand, and they now pass that context. The other calls sites now use
`context.TODO()`, we should continue to iterate in this area to ensure
everywhere that needs a context has one passed in.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-04-15 07:45:46 +00:00
|
|
|
ctx := context.Background()
|
2023-03-15 00:43:18 +00:00
|
|
|
|
Lift context parameter to SerializeDeployment/Resource/Operations/Properties (#15929)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
SerializePropertyValue needed a `context.Context` object to pass to the
`config.Encrypter`. It was using `context.TODO()`, this change instead
accepts a context on the parameters and lifts that up to
SerializeProperties, SerializeResource, SerializeOperation, and
SerializeDeployment.
There were a few call sites for those methods that already had a context
on hand, and they now pass that context. The other calls sites now use
`context.TODO()`, we should continue to iterate in this area to ensure
everywhere that needs a context has one passed in.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-04-15 07:45:46 +00:00
|
|
|
sdep, err := stack.SerializeDeployment(ctx, snap, false /* showSecrets */)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
data, err := encoding.JSON.Marshal(sdep)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Ensure data has the string contents "<html@tags>"", not "\u003chtml\u0026tags\u003e"
|
|
|
|
// ImportDeployment below should not modify the data
|
|
|
|
assert.Contains(t, string(data), "<html@tags>")
|
|
|
|
|
|
|
|
udep := &apitype.UntypedDeployment{
|
|
|
|
Version: 3,
|
|
|
|
Deployment: json.RawMessage(data),
|
|
|
|
}
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// Login to a temp dir diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
|
|
|
b, err := New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Create stack "a" and import a checkpoint with a secret
|
|
|
|
aStackRef, err := b.ParseStackReference("a")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
aStack, err := b.CreateStack(ctx, aStackRef, "", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, aStack)
|
|
|
|
err = b.ImportDeployment(ctx, aStack, udep)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Ensure the file has the string contents "<html@tags>"", not "\u003chtml\u0026tags\u003e"
|
|
|
|
|
|
|
|
// Grab the bucket interface to read the file with
|
2024-01-30 15:53:10 +00:00
|
|
|
lb, ok := b.(*diyBackend)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.True(t, ok)
|
|
|
|
assert.NotNil(t, lb)
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
chkpath := lb.stackPath(ctx, aStackRef.(*diyBackendReference))
|
2023-03-15 00:43:18 +00:00
|
|
|
bytes, err := lb.bucket.ReadAll(context.Background(), chkpath)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
state := string(bytes)
|
|
|
|
assert.Contains(t, state, "<html@tags>")
|
|
|
|
}
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
func TestDIYBackendRejectsStackInitOptions_legacy(t *testing.T) {
|
2023-03-15 00:43:18 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// Here, we provide options that illegally specify a team on a
|
|
|
|
// backend that does not support teams. We expect this to create
|
|
|
|
// an error later when we call CreateStack.
|
|
|
|
illegalOptions := &backend.CreateStackOptions{Teams: []string{"red-team"}}
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
// • Create a mock diy backend
|
2023-03-15 00:43:18 +00:00
|
|
|
tmpDir := markLegacyStore(t, t.TempDir())
|
2023-12-12 12:19:42 +00:00
|
|
|
dirURI := "file://" + filepath.ToSlash(tmpDir)
|
2024-01-30 15:53:10 +00:00
|
|
|
diy, err := New(context.Background(), diagtest.LogSink(t), dirURI, nil)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
// • Simulate `pulumi stack init`, passing non-nil init options
|
2024-01-30 15:53:10 +00:00
|
|
|
fakeStackRef, err := diy.ParseStackReference("foobar")
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.NoError(t, err)
|
2024-01-30 15:53:10 +00:00
|
|
|
_, err = diy.CreateStack(ctx, fakeStackRef, "", illegalOptions)
|
2023-03-15 00:43:18 +00:00
|
|
|
assert.ErrorIs(t, err, backend.ErrTeamsNotSupported)
|
|
|
|
}
|
|
|
|
|
|
|
|
// markLegacyStore marks the given directory as a legacy store.
|
|
|
|
// This is done by dropping a single file into the bookkeeping directory.
|
|
|
|
// ensurePulumiMeta will treat this as a legacy store if the directory exists.
|
|
|
|
//
|
|
|
|
// Returns the directory that was marked.
|
|
|
|
func markLegacyStore(t *testing.T, dir string) string {
|
|
|
|
metaPath := filepath.Join(dir, pulumiMetaPath)
|
|
|
|
require.NoError(t, os.MkdirAll(filepath.Dir(metaPath), 0o755))
|
|
|
|
require.NoError(t, os.WriteFile(metaPath, []byte(`version: 0`), 0o600))
|
|
|
|
return dir
|
|
|
|
}
|