For historical reasons, we used to need to require to load an existing checkpoint to copy some data from it into the snapshot when saving a new snapshot. The need for this was removed as part of the general work in #2678, but we continued to load the checkpoint and then just disregard the data that was returned (unless there was an error and that error was not FileNotFound, in which case we would fail). Our logic for checking if something was FileNotFound was correct when we wrote it, but when we adopted go-cloud in order to have our filestate backend also write to blob storage backends like S3, we forgot that we had checks like `os.IsNotExists()` floating around which were now incorrect. That meant if the file did not exist for some reason, instead of going along as planned, we'd error out now with an error saying something wasn't found. When we write a checkpoint, we first "backed up" the initial version by renaming it to include a `.bak` suffix, then we write the new file in place. However, this can run afoul of eventual consistency models like S3, since there will be a period of time in which a caller may observe that the object is missing, even after a new version is written (based on my understanding of [S3's consistency model](https://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#ConsistencyModel) Since we no longer need to actually copy any information from the previous checkpoint, we can simply remove the call entirely to load it. As a follow up, we need to audit places inside the filebased backend that assume `os.*` functions are going to do what we want them to do, since in general they will not. Fixes #2714
43 lines
1.4 KiB
Go
43 lines
1.4 KiB
Go
// 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 filestate
|
|
|
|
import (
|
|
"github.com/pulumi/pulumi/pkg/resource/deploy"
|
|
"github.com/pulumi/pulumi/pkg/secrets"
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
)
|
|
|
|
// localSnapshotManager is a simple SnapshotManager implementation that persists snapshots
|
|
// to disk on the local machine.
|
|
type localSnapshotPersister struct {
|
|
name tokens.QName
|
|
backend *localBackend
|
|
sm secrets.Manager
|
|
}
|
|
|
|
func (sp *localSnapshotPersister) SecretsManager() secrets.Manager {
|
|
return sp.sm
|
|
}
|
|
|
|
func (sp *localSnapshotPersister) Save(snapshot *deploy.Snapshot) error {
|
|
_, err := sp.backend.saveStack(sp.name, snapshot, sp.sm)
|
|
return err
|
|
|
|
}
|
|
|
|
func (b *localBackend) newSnapshotPersister(stackName tokens.QName, sm secrets.Manager) *localSnapshotPersister {
|
|
return &localSnapshotPersister{name: stackName, backend: b, sm: sm}
|
|
}
|