From 272ee0d76f8287a8c103921a2e165135be7d39a6 Mon Sep 17 00:00:00 2001 From: KK <68334452+healthjyk@users.noreply.github.com> Date: Mon, 27 May 2024 10:49:36 +0800 Subject: [PATCH] feat: clean the usage of deprecated state and its storage (#1133) --- .gitignore | 2 - pkg/apis/api.kusion.io/v1/types.go | 51 +------- pkg/backend/backend.go | 4 - pkg/backend/storages/local.go | 6 - pkg/backend/storages/local_test.go | 31 ----- pkg/backend/storages/oss.go | 6 - pkg/backend/storages/oss_test.go | 32 ----- pkg/backend/storages/s3.go | 6 - pkg/backend/storages/s3_test.go | 34 ----- pkg/cmd/preview/preview_test.go | 6 +- pkg/engine/api/apply.go | 16 --- pkg/engine/doc.go | 2 +- pkg/engine/runtime/terraform/tfops/state.go | 4 +- .../runtime/terraform/tfops/workspace.go | 4 +- pkg/engine/state/storage.go | 15 --- pkg/engine/state/storages/local.go | 52 -------- pkg/engine/state/storages/local_test.go | 120 ------------------ pkg/engine/state/storages/oss.go | 69 ---------- pkg/engine/state/storages/oss_test.go | 73 ----------- pkg/engine/state/storages/s3.go | 79 ------------ pkg/engine/state/storages/s3_test.go | 75 ----------- pkg/engine/state/storages/util.go | 26 ---- 22 files changed, 7 insertions(+), 706 deletions(-) delete mode 100644 pkg/engine/state/storage.go delete mode 100644 pkg/engine/state/storages/local.go delete mode 100644 pkg/engine/state/storages/local_test.go delete mode 100644 pkg/engine/state/storages/oss.go delete mode 100644 pkg/engine/state/storages/oss_test.go delete mode 100644 pkg/engine/state/storages/s3.go delete mode 100644 pkg/engine/state/storages/s3_test.go delete mode 100644 pkg/engine/state/storages/util.go diff --git a/.gitignore b/.gitignore index 7766a095..f11c7fe6 100644 --- a/.gitignore +++ b/.gitignore @@ -43,8 +43,6 @@ _python37_home_/ /VERSION /kclopenapi .kclvm/ -kusion_state*.json -kusion_state*.yaml # Vscode __debug_bin diff --git a/pkg/apis/api.kusion.io/v1/types.go b/pkg/apis/api.kusion.io/v1/types.go index a08d32b8..0f345ee6 100644 --- a/pkg/apis/api.kusion.io/v1/types.go +++ b/pkg/apis/api.kusion.io/v1/types.go @@ -19,8 +19,6 @@ import ( "gopkg.in/yaml.v2" v1 "k8s.io/api/core/v1" - - "kusionstack.io/kusion/pkg/version" ) // Project is a definition of Kusion project resource. @@ -820,7 +818,7 @@ type Resources []Resource // Resource is the representation of a resource in the state. type Resource struct { - // ID is the unique key of this resource in the whole DeprecatedState. + // ID is the unique key of this resource. // ApiVersion:Kind:Namespace:Name is an idiomatic way for Kubernetes resources. // providerNamespace:providerName:resourceType:resourceName for Terraform resources ID string `yaml:"id" json:"id"` @@ -908,50 +906,3 @@ type Release struct { // ModifiedTime is the time that the Release is modified. ModifiedTime time.Time `yaml:"modifiedTime" json:"modifiedTime"` } - -// DeprecatedState is a record of an operation's result. It is a mapping between resources in KCL and the actual infra -// resource and often used as a datasource for 3-way merge/diff in operations like Apply or Preview. -// Deprecated: DeprecatedState will not in use in time -type DeprecatedState struct { - // DeprecatedState ID - ID int64 `yaml:"id" json:"id"` - - // Project name - Project string `yaml:"project" json:"project"` - - // Stack name - Stack string `yaml:"stack" json:"stack"` - - // Workspace name - Workspace string `yaml:"workspace" json:"workspace"` - - // DeprecatedState version - Version int `yaml:"version" json:"version"` - - // KusionVersion represents the Kusion version when this DeprecatedState is created - KusionVersion string `yaml:"kusionVersion" json:"kusionVersion"` - - // Serial is an auto-increase number that represents how many times this DeprecatedState is modified - Serial uint64 `yaml:"serial" json:"serial"` - - // Operator represents the person who triggered this operation - Operator string `yaml:"operator,omitempty" json:"operator,omitempty"` - - // Resources records all resources in this operation - Resources Resources `yaml:"resources" json:"resources"` - - // CreateTime is the time DeprecatedState is created - CreateTime time.Time `yaml:"createTime" json:"createTime"` - - // ModifiedTime is the time DeprecatedState is modified each time - ModifiedTime time.Time `yaml:"modifiedTime,omitempty" json:"modifiedTime,omitempty"` -} - -func NewState() *DeprecatedState { - s := &DeprecatedState{ - KusionVersion: version.ReleaseVersion(), - Version: 1, - Resources: []Resource{}, - } - return s -} diff --git a/pkg/backend/backend.go b/pkg/backend/backend.go index 710b6691..ecaef579 100644 --- a/pkg/backend/backend.go +++ b/pkg/backend/backend.go @@ -7,7 +7,6 @@ import ( "kusionstack.io/kusion/pkg/backend/storages" "kusionstack.io/kusion/pkg/config" "kusionstack.io/kusion/pkg/engine/release" - "kusionstack.io/kusion/pkg/engine/state" "kusionstack.io/kusion/pkg/workspace" ) @@ -16,9 +15,6 @@ type Backend interface { // WorkspaceStorage returns the workspace storage and init default workspace. WorkspaceStorage() (workspace.Storage, error) - // StateStorage returns the state storage. - StateStorage(project, workspace string) state.Storage - // ReleaseStorage returns the release storage. ReleaseStorage(project, workspace string) (release.Storage, error) } diff --git a/pkg/backend/storages/local.go b/pkg/backend/storages/local.go index 6a22df51..40407b17 100644 --- a/pkg/backend/storages/local.go +++ b/pkg/backend/storages/local.go @@ -4,8 +4,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" "kusionstack.io/kusion/pkg/engine/release" releasestorages "kusionstack.io/kusion/pkg/engine/release/storages" - "kusionstack.io/kusion/pkg/engine/state" - statestorages "kusionstack.io/kusion/pkg/engine/state/storages" "kusionstack.io/kusion/pkg/workspace" workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) @@ -21,10 +19,6 @@ func NewLocalStorage(config *v1.BackendLocalConfig) *LocalStorage { return &LocalStorage{path: config.Path} } -func (s *LocalStorage) StateStorage(project, workspace string) state.Storage { - return statestorages.NewLocalStorage(statestorages.GenStateFilePath(s.path, project, workspace)) -} - func (s *LocalStorage) WorkspaceStorage() (workspace.Storage, error) { return workspacestorages.NewLocalStorage(workspacestorages.GenWorkspaceDirPath(s.path)) } diff --git a/pkg/backend/storages/local_test.go b/pkg/backend/storages/local_test.go index b6ba0f30..f80525d7 100644 --- a/pkg/backend/storages/local_test.go +++ b/pkg/backend/storages/local_test.go @@ -1,7 +1,6 @@ package storages import ( - "path/filepath" "testing" "github.com/bytedance/mockey" @@ -9,8 +8,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" releasestorages "kusionstack.io/kusion/pkg/engine/release/storages" - "kusionstack.io/kusion/pkg/engine/state" - statestorages "kusionstack.io/kusion/pkg/engine/state/storages" workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) @@ -35,34 +32,6 @@ func TestNewLocalStorage(t *testing.T) { } } -func TestLocalStorage_StateStorage(t *testing.T) { - testcases := []struct { - name string - localStorage *LocalStorage - project, workspace string - stateStorage state.Storage - }{ - { - name: "state storage from local backend", - localStorage: &LocalStorage{ - path: "kusion", - }, - project: "wordpress", - workspace: "dev", - stateStorage: statestorages.NewLocalStorage( - filepath.Join("kusion", "states", "wordpress", "dev", "state.yaml"), - ), - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - stateStorage := tc.localStorage.StateStorage(tc.project, tc.workspace) - assert.Equal(t, tc.stateStorage, stateStorage) - }) - } -} - func TestLocalStorage_WorkspaceStorage(t *testing.T) { testcases := []struct { name string diff --git a/pkg/backend/storages/oss.go b/pkg/backend/storages/oss.go index 8c856870..90607cc3 100644 --- a/pkg/backend/storages/oss.go +++ b/pkg/backend/storages/oss.go @@ -6,8 +6,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" "kusionstack.io/kusion/pkg/engine/release" releasestorages "kusionstack.io/kusion/pkg/engine/release/storages" - "kusionstack.io/kusion/pkg/engine/state" - statestorages "kusionstack.io/kusion/pkg/engine/state/storages" "kusionstack.io/kusion/pkg/workspace" workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) @@ -33,10 +31,6 @@ func NewOssStorage(config *v1.BackendOssConfig) (*OssStorage, error) { return &OssStorage{bucket: bucket, prefix: config.Prefix}, nil } -func (s *OssStorage) StateStorage(project, workspace string) state.Storage { - return statestorages.NewOssStorage(s.bucket, statestorages.GenGenericOssStateFileKey(s.prefix, project, workspace)) -} - func (s *OssStorage) WorkspaceStorage() (workspace.Storage, error) { return workspacestorages.NewOssStorage(s.bucket, workspacestorages.GenGenericOssWorkspacePrefixKey(s.prefix)) } diff --git a/pkg/backend/storages/oss_test.go b/pkg/backend/storages/oss_test.go index dac4c9ff..5f2f62ef 100644 --- a/pkg/backend/storages/oss_test.go +++ b/pkg/backend/storages/oss_test.go @@ -9,8 +9,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" releasestorages "kusionstack.io/kusion/pkg/engine/release/storages" - "kusionstack.io/kusion/pkg/engine/state" - statestorages "kusionstack.io/kusion/pkg/engine/state/storages" workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) @@ -45,36 +43,6 @@ func TestNewOssStorage(t *testing.T) { } } -func TestOssStorage_StateStorage(t *testing.T) { - testcases := []struct { - name string - ossStorage *OssStorage - project, workspace string - stateStorage state.Storage - }{ - { - name: "state storage from oss backend", - ossStorage: &OssStorage{ - bucket: &oss.Bucket{}, - prefix: "kusion", - }, - project: "wordpress", - workspace: "dev", - stateStorage: statestorages.NewOssStorage( - &oss.Bucket{}, - "kusion/states/wordpress/dev/state.yaml", - ), - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - stateStorage := tc.ossStorage.StateStorage(tc.project, tc.workspace) - assert.Equal(t, tc.stateStorage, stateStorage) - }) - } -} - func TestOssStorage_WorkspaceStorage(t *testing.T) { testcases := []struct { name string diff --git a/pkg/backend/storages/s3.go b/pkg/backend/storages/s3.go index f8081c51..396b4b1f 100644 --- a/pkg/backend/storages/s3.go +++ b/pkg/backend/storages/s3.go @@ -9,8 +9,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" "kusionstack.io/kusion/pkg/engine/release" releasestorages "kusionstack.io/kusion/pkg/engine/release/storages" - "kusionstack.io/kusion/pkg/engine/state" - statestorages "kusionstack.io/kusion/pkg/engine/state/storages" "kusionstack.io/kusion/pkg/workspace" workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) @@ -46,10 +44,6 @@ func NewS3Storage(config *v1.BackendS3Config) (*S3Storage, error) { }, nil } -func (s *S3Storage) StateStorage(project, workspace string) state.Storage { - return statestorages.NewS3Storage(s.s3, s.bucket, statestorages.GenGenericOssStateFileKey(s.prefix, project, workspace)) -} - func (s *S3Storage) WorkspaceStorage() (workspace.Storage, error) { return workspacestorages.NewS3Storage(s.s3, s.bucket, workspacestorages.GenGenericOssWorkspacePrefixKey(s.prefix)) } diff --git a/pkg/backend/storages/s3_test.go b/pkg/backend/storages/s3_test.go index 3bd91a5b..073d7c3f 100644 --- a/pkg/backend/storages/s3_test.go +++ b/pkg/backend/storages/s3_test.go @@ -10,8 +10,6 @@ import ( v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" releasestorages "kusionstack.io/kusion/pkg/engine/release/storages" - "kusionstack.io/kusion/pkg/engine/state" - statestorages "kusionstack.io/kusion/pkg/engine/state/storages" workspacestorages "kusionstack.io/kusion/pkg/workspace/storages" ) @@ -47,38 +45,6 @@ func TestNewS3Storage(t *testing.T) { } } -func TestS3Storage_StateStorage(t *testing.T) { - testcases := []struct { - name string - s3Storage *S3Storage - project, workspace string - stateStorage state.Storage - }{ - { - name: "state storage from s3 backend", - s3Storage: &S3Storage{ - s3: &s3.S3{}, - bucket: "infra", - prefix: "kusion", - }, - project: "wordpress", - workspace: "dev", - stateStorage: statestorages.NewS3Storage( - &s3.S3{}, - "infra", - "kusion/states/wordpress/dev/state.yaml", - ), - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - stateStorage := tc.s3Storage.StateStorage(tc.project, tc.workspace) - assert.Equal(t, tc.stateStorage, stateStorage) - }) - } -} - func TestS3Storage_WorkspaceStorage(t *testing.T) { testcases := []struct { name string diff --git a/pkg/cmd/preview/preview_test.go b/pkg/cmd/preview/preview_test.go index d503f953..9f39c7e7 100644 --- a/pkg/cmd/preview/preview_test.go +++ b/pkg/cmd/preview/preview_test.go @@ -16,7 +16,6 @@ package preview import ( "context" - "path/filepath" "testing" "github.com/bytedance/mockey" @@ -93,15 +92,12 @@ var ( ) func newPreviewOptions() *PreviewOptions { - storageBackend := storages.NewLocalStorage(&apiv1.BackendLocalConfig{ - Path: filepath.Join("", "state.yaml"), - }) return &PreviewOptions{ MetaOptions: &meta.MetaOptions{ RefProject: proj, RefStack: stack, RefWorkspace: workspace, - Backend: storageBackend, + Backend: &storages.LocalStorage{}, }, } } diff --git a/pkg/engine/api/apply.go b/pkg/engine/api/apply.go index dc3dcd16..1c776aa4 100644 --- a/pkg/engine/api/apply.go +++ b/pkg/engine/api/apply.go @@ -22,22 +22,6 @@ import ( // // You can customize the runtime of engine and the state // storage through `runtime` and `storage` parameters. -// -// Example: -// -// o := NewApplyOptions() -// stateStorage := &states.FileSystemState{ -// Path: filepath.Join(o.WorkDir, states.KusionState) -// } -// kubernetesRuntime, err := runtime.NewKubernetesRuntime() -// if err != nil { -// return err -// } -// -// err = Apply(o, kubernetesRuntime, stateStorage, planResources, changes, os.Stdout) -// if err != nil { -// return err -// } func Apply( o *APIOptions, storage release.Storage, diff --git a/pkg/engine/doc.go b/pkg/engine/doc.go index 0c928e3e..b1e614d6 100644 --- a/pkg/engine/doc.go +++ b/pkg/engine/doc.go @@ -37,7 +37,7 @@ // // 2. Walk this DAG: // 1. Get the latest `State` from the actual infra by the `Runtime` -// 2. Get the last operation `State` from the `State` storage medium +// 2. Get the last operation `State` from the `Release` storage medium // // 3. Merge/Diff three states: desired state described in Intent, live state from `Runtime` and prior state from `State` storage medium, and return the diff result to the console package engine diff --git a/pkg/engine/runtime/terraform/tfops/state.go b/pkg/engine/runtime/terraform/tfops/state.go index f66ea92d..d80a9e92 100644 --- a/pkg/engine/runtime/terraform/tfops/state.go +++ b/pkg/engine/runtime/terraform/tfops/state.go @@ -5,7 +5,7 @@ import ( "github.com/zclconf/go-cty/cty" - "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" + v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" ) // StateRepresentation is the top-level representation of the json format of a terraform @@ -107,7 +107,7 @@ type resource struct { // resource, whose structure depends on the resource type schema. type attributeValues map[string]interface{} -// ConvertTFState convert Terraform DeprecatedState to kusion DeprecatedState +// ConvertTFState convert Terraform State to kusion State func ConvertTFState(tfState *StateRepresentation, providerAddr string) v1.Resource { if tfState == nil || tfState.Values == nil { return v1.Resource{} diff --git a/pkg/engine/runtime/terraform/tfops/workspace.go b/pkg/engine/runtime/terraform/tfops/workspace.go index b0eb8774..8718115b 100644 --- a/pkg/engine/runtime/terraform/tfops/workspace.go +++ b/pkg/engine/runtime/terraform/tfops/workspace.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/hcl/v2/hclparse" "github.com/spf13/afero" - "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" + v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" "kusionstack.io/kusion/pkg/log" "kusionstack.io/kusion/pkg/util/io" jsonutil "kusionstack.io/kusion/pkg/util/json" @@ -294,7 +294,7 @@ func (w *WorkSpace) show(ctx context.Context, fileName string) ([]byte, error) { return out, nil } -// RefreshOnly refresh Terraform DeprecatedState +// RefreshOnly refresh Terraform State func (w *WorkSpace) RefreshOnly(ctx context.Context) (*StateRepresentation, error) { chdir := fmt.Sprintf("-chdir=%s", w.tfCacheDir) err := w.CleanAndInitWorkspace(ctx) diff --git a/pkg/engine/state/storage.go b/pkg/engine/state/storage.go deleted file mode 100644 index 87d201c4..00000000 --- a/pkg/engine/state/storage.go +++ /dev/null @@ -1,15 +0,0 @@ -package state - -import ( - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -// Storage is used to provide the state storage for a set of real resources belonging to a specified stack, -// which is determined by the combination of project name, stack name and workspace name. -type Storage interface { - // Get returns the state, if the state does not exist, return nil. - Get() (*v1.DeprecatedState, error) - - // Apply updates the state if already exists, or create a new state. - Apply(state *v1.DeprecatedState) error -} diff --git a/pkg/engine/state/storages/local.go b/pkg/engine/state/storages/local.go deleted file mode 100644 index 3b5e58d3..00000000 --- a/pkg/engine/state/storages/local.go +++ /dev/null @@ -1,52 +0,0 @@ -package storages - -import ( - "fmt" - "io/fs" - "os" - "path/filepath" - - "gopkg.in/yaml.v3" - - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -// LocalStorage is an implementation of state.Storage which uses local filesystem as storage. -type LocalStorage struct { - // The path of state file. - path string -} - -func NewLocalStorage(path string) *LocalStorage { - return &LocalStorage{path: path} -} - -func (s *LocalStorage) Get() (*v1.DeprecatedState, error) { - content, err := os.ReadFile(s.path) - if err != nil && !os.IsNotExist(err) { - return nil, err - } - - if len(content) != 0 { - state := &v1.DeprecatedState{} - err = yaml.Unmarshal(content, state) - if err != nil { - return nil, err - } - return state, nil - } else { - return nil, nil - } -} - -func (s *LocalStorage) Apply(state *v1.DeprecatedState) error { - if err := os.MkdirAll(filepath.Dir(s.path), os.ModePerm); err != nil { - fmt.Println(err) - } - - content, err := yaml.Marshal(state) - if err != nil { - return err - } - return os.WriteFile(s.path, content, fs.ModePerm) -} diff --git a/pkg/engine/state/storages/local_test.go b/pkg/engine/state/storages/local_test.go deleted file mode 100644 index a7fa3491..00000000 --- a/pkg/engine/state/storages/local_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package storages - -import ( - "os" - "testing" - - "github.com/bytedance/mockey" - "github.com/stretchr/testify/assert" - - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -func mockState() *v1.DeprecatedState { - return &v1.DeprecatedState{ - ID: 1, - Project: "wordpress", - Stack: "dev", - Workspace: "dev", - Version: 1, - KusionVersion: "0.11.0", - Serial: 1, - Operator: "kk-confused", - Resources: v1.Resources{ - v1.Resource{ - ID: "v1:ServiceAccount:wordpress:wordpress", - Type: "Kubernetes", - Attributes: map[string]interface{}{ - "apiVersion": "v1", - "kind": "ServiceAccount", - "metadata": map[string]interface{}{ - "name": "wordpress", - "namespace": "wordpress", - }, - }, - }, - }, - } -} - -func mockStateContent() string { - return ` -id: 1 -project: wordpress -stack: dev -workspace: dev -version: 1 -kusionVersion: 0.11.0 -serial: 1 -operator: kk-confused -resources: - - id: v1:ServiceAccount:wordpress:wordpress - type: Kubernetes - attributes: - apiVersion: v1 - kind: ServiceAccount - metadata: - name: wordpress - namespace: wordpress -createTime: 0001-01-01T00:00:00Z -` -} - -func mockLocalStorage() *LocalStorage { - return &LocalStorage{} -} - -func TestLocalStorage_Get(t *testing.T) { - testcases := []struct { - name string - success bool - content []byte - state *v1.DeprecatedState - }{ - { - name: "get local state successfully", - success: true, - content: []byte(mockStateContent()), - state: mockState(), - }, - { - name: "get empty local state successfully", - success: true, - content: nil, - state: nil, - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - mockey.PatchConvey("mock read state file", t, func() { - mockey.Mock(os.ReadFile).Return(tc.content, nil).Build() - state, err := mockLocalStorage().Get() - assert.Equal(t, tc.success, err == nil) - assert.Equal(t, tc.state, state) - }) - }) - } -} - -func TestLocalStorage_Apply(t *testing.T) { - testcases := []struct { - name string - success bool - state *v1.DeprecatedState - }{ - { - name: "apply local state successfully", - success: true, - state: mockState(), - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - mockey.PatchConvey("mock write state file", t, func() { - mockey.Mock(os.WriteFile).Return(nil).Build() - err := mockLocalStorage().Apply(tc.state) - assert.Equal(t, tc.success, err == nil) - }) - }) - } -} diff --git a/pkg/engine/state/storages/oss.go b/pkg/engine/state/storages/oss.go deleted file mode 100644 index 3b708395..00000000 --- a/pkg/engine/state/storages/oss.go +++ /dev/null @@ -1,69 +0,0 @@ -package storages - -import ( - "bytes" - "io" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - "gopkg.in/yaml.v3" - - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -// OssStorage is an implementation of state.Backend which uses oss as storage. -type OssStorage struct { - bucket *oss.Bucket - - // The oss key to store the state file. - key string -} - -func NewOssStorage(bucket *oss.Bucket, key string) *OssStorage { - return &OssStorage{ - bucket: bucket, - key: key, - } -} - -func (s *OssStorage) Get() (*v1.DeprecatedState, error) { - var exist bool - body, err := s.bucket.GetObject(s.key) - if err != nil { - ossErr, ok := err.(oss.ServiceError) - // error code ref: github.com/aliyun/aliyun-oss-go-sdk@v2.1.8+incompatible/oss/bucket.go:553 - if ok && ossErr.StatusCode == 404 { - exist = true - } - if exist { - return nil, nil - } - return nil, err - } - defer func() { - _ = body.Close() - }() - - content, err := io.ReadAll(body) - if err != nil { - return nil, err - } - if len(content) == 0 { - return nil, nil - } - - state := &v1.DeprecatedState{} - err = yaml.Unmarshal(content, state) - if err != nil { - return nil, err - } - return state, nil -} - -func (s *OssStorage) Apply(state *v1.DeprecatedState) error { - content, err := yaml.Marshal(state) - if err != nil { - return err - } - - return s.bucket.PutObject(s.key, bytes.NewReader(content)) -} diff --git a/pkg/engine/state/storages/oss_test.go b/pkg/engine/state/storages/oss_test.go deleted file mode 100644 index b3cf5d77..00000000 --- a/pkg/engine/state/storages/oss_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package storages - -import ( - "bytes" - "io" - "testing" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - "github.com/bytedance/mockey" - "github.com/stretchr/testify/assert" - - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -func mockOssStorage() *OssStorage { - return &OssStorage{bucket: &oss.Bucket{}} -} - -func TestOssStorage_Get(t *testing.T) { - testcases := []struct { - name string - success bool - content []byte - state *v1.DeprecatedState - }{ - { - name: "get oss state successfully", - success: true, - content: []byte(mockStateContent()), - state: mockState(), - }, - { - name: "get empty oss state successfully", - success: true, - content: nil, - state: nil, - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - mockey.PatchConvey("mock oss get", t, func() { - mockey.Mock(oss.Bucket.GetObject).Return(io.NopCloser(bytes.NewReader([]byte(""))), nil).Build() - mockey.Mock(io.ReadAll).Return(tc.content, nil).Build() - state, err := mockOssStorage().Get() - assert.Equal(t, tc.success, err == nil) - assert.Equal(t, tc.state, state) - }) - }) - } -} - -func TestOssStorage_Apply(t *testing.T) { - testcases := []struct { - name string - success bool - state *v1.DeprecatedState - }{ - { - name: "apply oss state successfully", - success: true, - state: mockState(), - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - mockey.PatchConvey("mock oss put", t, func() { - mockey.Mock(oss.Bucket.PutObject).Return(nil).Build() - err := mockOssStorage().Apply(tc.state) - assert.Equal(t, tc.success, err == nil) - }) - }) - } -} diff --git a/pkg/engine/state/storages/s3.go b/pkg/engine/state/storages/s3.go deleted file mode 100644 index ef583fc3..00000000 --- a/pkg/engine/state/storages/s3.go +++ /dev/null @@ -1,79 +0,0 @@ -package storages - -import ( - "bytes" - "io" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/s3" - "gopkg.in/yaml.v3" - - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -// S3Storage is an implementation of state.Storage which uses s3 as storage. -type S3Storage struct { - s3 *s3.S3 - bucket string - - // The s3 key to store the state file. - key string -} - -func NewS3Storage(s3 *s3.S3, bucket, key string) *S3Storage { - return &S3Storage{ - s3: s3, - bucket: bucket, - key: key, - } -} - -func (s *S3Storage) Get() (*v1.DeprecatedState, error) { - input := &s3.GetObjectInput{ - Bucket: aws.String(s.bucket), - Key: &s.key, - } - output, err := s.s3.GetObject(input) - if err != nil { - awsErr, ok := err.(awserr.Error) - // if no kusion state file, return nil state - if ok && awsErr.Code() == s3.ErrCodeNoSuchKey { - return nil, nil - } - return nil, err - } - defer func() { - _ = output.Body.Close() - }() - - content, err := io.ReadAll(output.Body) - if err != nil { - return nil, err - } - if len(content) == 0 { - return nil, nil - } - - state := &v1.DeprecatedState{} - err = yaml.Unmarshal(content, state) - if err != nil { - return nil, err - } - return state, nil -} - -func (s *S3Storage) Apply(state *v1.DeprecatedState) error { - content, err := yaml.Marshal(state) - if err != nil { - return err - } - - input := &s3.PutObjectInput{ - Bucket: aws.String(s.bucket), - Key: aws.String(s.key), - Body: bytes.NewReader(content), - } - _, err = s.s3.PutObject(input) - return err -} diff --git a/pkg/engine/state/storages/s3_test.go b/pkg/engine/state/storages/s3_test.go deleted file mode 100644 index 2575231a..00000000 --- a/pkg/engine/state/storages/s3_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package storages - -import ( - "bytes" - "io" - "testing" - - "github.com/aws/aws-sdk-go/service/s3" - "github.com/bytedance/mockey" - "github.com/stretchr/testify/assert" - - v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1" -) - -func mockS3Storage() *S3Storage { - return &S3Storage{s3: &s3.S3{}} -} - -func TestS3Storage_Get(t *testing.T) { - testcases := []struct { - name string - success bool - content []byte - state *v1.DeprecatedState - }{ - { - name: "get s3 state successfully", - success: true, - content: []byte(mockStateContent()), - state: mockState(), - }, - { - name: "get empty s3 state successfully", - success: true, - content: nil, - state: nil, - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - mockey.PatchConvey("mock s3 get", t, func() { - mockey.Mock((*s3.S3).GetObject).Return(&s3.GetObjectOutput{ - Body: io.NopCloser(bytes.NewReader([]byte(""))), - }, nil).Build() - mockey.Mock(io.ReadAll).Return(tc.content, nil).Build() - state, err := mockS3Storage().Get() - assert.Equal(t, tc.success, err == nil) - assert.Equal(t, tc.state, state) - }) - }) - } -} - -func TestS3Storage_Apply(t *testing.T) { - testcases := []struct { - name string - success bool - state *v1.DeprecatedState - }{ - { - name: "apply s3 state successfully", - success: true, - state: mockState(), - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - mockey.PatchConvey("mock s3 put", t, func() { - mockey.Mock((*s3.S3).PutObject).Return(nil, nil).Build() - err := mockS3Storage().Apply(tc.state) - assert.Equal(t, tc.success, err == nil) - }) - }) - } -} diff --git a/pkg/engine/state/storages/util.go b/pkg/engine/state/storages/util.go deleted file mode 100644 index ba3a7081..00000000 --- a/pkg/engine/state/storages/util.go +++ /dev/null @@ -1,26 +0,0 @@ -package storages - -import ( - "fmt" - "path/filepath" - "strings" -) - -const ( - stateFile = "state.yaml" - statesPrefix = "states" -) - -// GenStateFilePath generates the state file path, which is used for LocalStorage. -func GenStateFilePath(dir, project, workspace string) string { - return filepath.Join(dir, statesPrefix, project, workspace, stateFile) -} - -// GenGenericOssStateFileKey generates generic oss state file key, which is use for OssStorage and S3Storage. -func GenGenericOssStateFileKey(prefix, project, workspace string) string { - prefix = strings.TrimPrefix(prefix, "/") - if prefix != "" { - prefix += "/" - } - return fmt.Sprintf("%s%s/%s/%s/%s", prefix, statesPrefix, project, workspace, stateFile) -}