filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
// Copyright 2016-2023, 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.
|
|
|
|
|
2024-01-30 15:53:10 +00:00
|
|
|
package diy
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-03-28 17:31:35 +00:00
|
|
|
"path/filepath"
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
"testing"
|
|
|
|
|
2023-10-18 10:52:54 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/env"
|
2023-03-28 17:31:35 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/testing/diagtest"
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2023-03-28 17:31:35 +00:00
|
|
|
"gocloud.dev/blob/fileblob"
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
"gocloud.dev/blob/memblob"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestEnsurePulumiMeta(t *testing.T) {
|
2023-03-24 21:24:06 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2023-10-18 10:52:54 +00:00
|
|
|
mkmap := func(value string) env.MapStore {
|
|
|
|
m := make(env.MapStore)
|
2024-01-30 15:53:10 +00:00
|
|
|
m[env.DIYBackendLegacyLayout.Var().Name()] = value
|
2023-10-18 10:52:54 +00:00
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
tests := []struct {
|
|
|
|
desc string
|
|
|
|
give map[string]string // files in the bucket
|
2023-10-18 10:52:54 +00:00
|
|
|
env env.MapStore // environment variables
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
want pulumiMeta
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
// Empty bucket should be initialized to
|
|
|
|
// the current version by default.
|
|
|
|
desc: "empty",
|
2023-02-10 12:24:28 +00:00
|
|
|
want: pulumiMeta{Version: 1},
|
|
|
|
},
|
2023-02-10 12:24:28 +00:00
|
|
|
{
|
|
|
|
// Use legacy mode even for the new bucket
|
|
|
|
// because the environment variable is "1".
|
|
|
|
desc: "empty/legacy",
|
2023-10-18 10:52:54 +00:00
|
|
|
env: mkmap("1"),
|
2023-02-10 12:24:28 +00:00
|
|
|
want: pulumiMeta{Version: 0},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Use legacy mode even for the new bucket
|
|
|
|
// because the environment variable is "true".
|
|
|
|
desc: "empty/legacy/true",
|
2023-10-18 10:52:54 +00:00
|
|
|
env: mkmap("true"),
|
2023-02-10 12:24:28 +00:00
|
|
|
want: pulumiMeta{Version: 0},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Legacy mode is disabled by setting the env var
|
|
|
|
// to "false".
|
|
|
|
// This is also the default behavior.
|
|
|
|
desc: "empty/legacy/false",
|
2023-10-18 10:52:54 +00:00
|
|
|
env: mkmap("false"),
|
2023-02-10 12:24:28 +00:00
|
|
|
want: pulumiMeta{Version: 1},
|
|
|
|
},
|
2023-02-10 12:24:28 +00:00
|
|
|
{
|
|
|
|
// Non-empty bucket without a version file
|
|
|
|
// should get version 0 for legacy mode.
|
|
|
|
desc: "legacy",
|
|
|
|
give: map[string]string{
|
|
|
|
".pulumi/stacks/a.json": `{}`,
|
|
|
|
},
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
want: pulumiMeta{Version: 0},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "version 0",
|
|
|
|
give: map[string]string{
|
2023-03-28 17:52:53 +00:00
|
|
|
".pulumi/meta.yaml": `version: 0`,
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
},
|
|
|
|
want: pulumiMeta{Version: 0},
|
|
|
|
},
|
2023-02-10 12:24:28 +00:00
|
|
|
{
|
2023-02-10 12:24:28 +00:00
|
|
|
// Non-empty bucket with a version file
|
|
|
|
// should get whatever is in the file.
|
2023-02-10 12:24:28 +00:00
|
|
|
desc: "version 1",
|
|
|
|
give: map[string]string{
|
|
|
|
".pulumi/meta.yaml": `version: 1`,
|
|
|
|
},
|
|
|
|
want: pulumiMeta{Version: 1},
|
|
|
|
},
|
2023-03-28 17:31:35 +00:00
|
|
|
{
|
|
|
|
desc: "future version",
|
|
|
|
give: map[string]string{
|
2023-03-28 17:52:53 +00:00
|
|
|
".pulumi/meta.yaml": `version: 42`,
|
2023-03-28 17:31:35 +00:00
|
|
|
},
|
|
|
|
want: pulumiMeta{Version: 42},
|
|
|
|
},
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.desc, func(t *testing.T) {
|
2023-03-24 21:24:06 +00:00
|
|
|
t.Parallel()
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
|
|
|
|
b := memblob.OpenBucket(nil)
|
|
|
|
ctx := context.Background()
|
|
|
|
for name, body := range tt.give {
|
|
|
|
require.NoError(t, b.WriteAll(ctx, name, []byte(body), nil))
|
|
|
|
}
|
|
|
|
|
2023-10-18 10:52:54 +00:00
|
|
|
state, err := ensurePulumiMeta(ctx, b, env.NewEnv(tt.env))
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, &tt.want, state)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEnsurePulumiMeta_corruption(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
desc string
|
2023-03-28 17:52:53 +00:00
|
|
|
give string // contents of meta.yaml
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
wantErr string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "empty",
|
|
|
|
give: ``,
|
2023-03-28 17:52:53 +00:00
|
|
|
wantErr: `corrupt store: missing version in ".pulumi/meta.yaml"`,
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "other fields",
|
|
|
|
give: `foo: bar`,
|
2023-03-28 17:52:53 +00:00
|
|
|
wantErr: `corrupt store: missing version in ".pulumi/meta.yaml"`,
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "corrupt version",
|
|
|
|
give: `version: foo`,
|
2023-03-28 17:52:53 +00:00
|
|
|
wantErr: `corrupt store: unmarshal ".pulumi/meta.yaml"`,
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
b := memblob.OpenBucket(nil)
|
|
|
|
ctx := context.Background()
|
2023-03-28 17:52:53 +00:00
|
|
|
require.NoError(t, b.WriteAll(ctx, ".pulumi/meta.yaml", []byte(tt.give), nil))
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
|
2023-10-18 10:52:54 +00:00
|
|
|
_, err := ensurePulumiMeta(context.Background(), b, env.NewEnv(nil))
|
filestate: Track a state metadata file (.pulumi/Pulumi.yaml)
We want the filestate backend to support project-scoped stacks,
but we can't make the change as-is because it would break old states
with new CLIs.
To differentiate between old and new states,
we've decided to introduce the concept of state metadata.
This is a file under the path .pulumi/Pulumi.yaml
that tracks metadata necessary for the filestate backend to operate.
Initially, this contains just one field: `version`,
with the initial value of 0 representing non-project or "legacy mode".
This changes the filestate layout to track such a file,
creating it if it doesn't exist with the default value of 0.
In a future change, we'll introduce "version 1",
which adds support for project-scoped stacks.
If we ever need to make breaking changes to the layout,
the version in this file will help the CLI decide
whether it's allowed to handle that state bucket
without corrupting it.
Note that this differs slightly
from the initial implementation of this functionality in #12134.
Particularly, this idempotently ensures that a Pulumi.yaml exists,
allowing `version: 0` to indicate legacy mode,
versus the original implementation that treated absence of the file
in a non-empty bucket as legacy mode.
This drops the bucket.IsAccessible check from filestate.New
because accessibility is now verified
when we try to read the metadata file.
Extracted from #12437
2023-03-22 19:14:05 +00:00
|
|
|
assert.ErrorContains(t, err, tt.wantErr)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-03-28 17:31:35 +00:00
|
|
|
|
|
|
|
// Writes a metadata file to the bucket and reads it back.
|
|
|
|
func TestMeta_roundTrip(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
desc string
|
|
|
|
give pulumiMeta
|
|
|
|
}{
|
|
|
|
{desc: "zero", give: pulumiMeta{Version: 0}},
|
2023-02-10 12:24:28 +00:00
|
|
|
{desc: "one", give: pulumiMeta{Version: 1}},
|
2023-03-28 17:31:35 +00:00
|
|
|
{desc: "future", give: pulumiMeta{Version: 42}},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
b := memblob.OpenBucket(nil)
|
2023-02-10 12:24:28 +00:00
|
|
|
// The bucket is always non-empty,
|
|
|
|
// so we won't automatically try to use version 1.
|
|
|
|
require.NoError(t,
|
2023-06-22 12:33:03 +00:00
|
|
|
b.WriteAll(context.Background(), ".pulumi/stacks/dev.json", []byte("bar"), nil))
|
2023-02-10 12:24:28 +00:00
|
|
|
|
2023-03-28 17:31:35 +00:00
|
|
|
ctx := context.Background()
|
|
|
|
require.NoError(t, tt.give.WriteTo(ctx, b))
|
|
|
|
|
2023-10-18 10:52:54 +00:00
|
|
|
got, err := ensurePulumiMeta(ctx, b, env.NewEnv(nil))
|
2023-03-28 17:31:35 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, &tt.give, got)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verifies that we don't write a metadata file with version 0.
|
|
|
|
func TestMeta_WriteTo_zero(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
bucket, err := fileblob.OpenBucket(tmpDir, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
require.NoError(t, (&pulumiMeta{
|
|
|
|
Version: 0,
|
|
|
|
}).WriteTo(ctx, bucket))
|
|
|
|
|
2023-03-28 17:52:53 +00:00
|
|
|
assert.NoFileExists(t, filepath.Join(tmpDir, ".pulumi", "meta.yaml"))
|
2023-03-28 17:31:35 +00:00
|
|
|
}
|
|
|
|
|
2023-02-10 12:24:28 +00:00
|
|
|
// Verify that we don't create a metadata file with version 0 in buckets
|
|
|
|
// that have other files.
|
2023-03-28 17:31:35 +00:00
|
|
|
func TestNew_noMetaOnInit(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
tmpDir := t.TempDir()
|
2023-02-10 12:24:28 +00:00
|
|
|
bucket, err := fileblob.OpenBucket(tmpDir, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t,
|
2023-06-22 12:33:03 +00:00
|
|
|
bucket.WriteAll(context.Background(), ".pulumi/stacks/dev.json", []byte("bar"), nil))
|
2023-02-10 12:24:28 +00:00
|
|
|
|
2023-03-28 17:31:35 +00:00
|
|
|
ctx := context.Background()
|
2023-02-10 12:24:28 +00:00
|
|
|
_, err = New(ctx, diagtest.LogSink(t), "file://"+filepath.ToSlash(tmpDir), nil)
|
2023-03-28 17:31:35 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-03-28 17:52:53 +00:00
|
|
|
assert.NoFileExists(t, filepath.Join(tmpDir, ".pulumi", "meta.yaml"))
|
2023-03-28 17:31:35 +00:00
|
|
|
}
|