From 95fc2ad30a856f565e122ffbe3455584439d9bbb Mon Sep 17 00:00:00 2001 From: healthjyk Date: Fri, 8 Mar 2024 17:41:02 +0800 Subject: [PATCH] feat: remove state model to pkg apis/core/v1 and stateStorage interface to pkg state --- pkg/apis/core/v1/state.go | 53 +++++ pkg/engine/state/storage.go | 15 ++ .../states/{state.go => state_deprecated.go} | 30 +-- pkg/engine/states/state_test.go | 199 ------------------ 4 files changed, 83 insertions(+), 214 deletions(-) create mode 100644 pkg/apis/core/v1/state.go create mode 100644 pkg/engine/state/storage.go rename pkg/engine/states/{state.go => state_deprecated.go} (93%) delete mode 100644 pkg/engine/states/state_test.go diff --git a/pkg/apis/core/v1/state.go b/pkg/apis/core/v1/state.go new file mode 100644 index 00000000..23a97ff4 --- /dev/null +++ b/pkg/apis/core/v1/state.go @@ -0,0 +1,53 @@ +package v1 + +import ( + "time" + + "kusionstack.io/kusion/pkg/version" +) + +// State 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. +type State struct { + // State ID + ID int64 `json:"id" yaml:"id"` + + // Project name + Project string `json:"project" yaml:"project"` + + // Stack name + Stack string `json:"stack" yaml:"stack"` + + // Workspace name + Workspace string `json:"workspace" yaml:"workspace"` + + // State version + Version int `json:"version" yaml:"version"` + + // KusionVersion represents the Kusion's version when this State is created + KusionVersion string `json:"kusionVersion" yaml:"kusionVersion"` + + // Serial is an auto-increase number that represents how many times this State is modified + Serial uint64 `json:"serial" yaml:"serial"` + + // Operator represents the person who triggered this operation + Operator string `json:"operator,omitempty" yaml:"operator,omitempty"` + + // Resources records all resources in this operation + Resources Resources `json:"resources" yaml:"resources"` + + // CreateTime is the time State is created + CreateTime time.Time `json:"createTime" yaml:"createTime"` + + // ModifiedTime is the time State is modified each time + ModifiedTime time.Time `json:"modifiedTime,omitempty" yaml:"modifiedTime"` +} + +func NewState() *State { + s := &State{ + KusionVersion: version.ReleaseVersion(), + Version: 1, + Resources: []Resource{}, + } + return s +} diff --git a/pkg/engine/state/storage.go b/pkg/engine/state/storage.go new file mode 100644 index 00000000..173bab38 --- /dev/null +++ b/pkg/engine/state/storage.go @@ -0,0 +1,15 @@ +package state + +import ( + v1 "kusionstack.io/kusion/pkg/apis/core/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.State, error) + + // Apply updates the state if already exists, or create a new state. + Apply(state *v1.State) error +} diff --git a/pkg/engine/states/state.go b/pkg/engine/states/state_deprecated.go similarity index 93% rename from pkg/engine/states/state.go rename to pkg/engine/states/state_deprecated.go index 0656fd58..595ff376 100644 --- a/pkg/engine/states/state.go +++ b/pkg/engine/states/state_deprecated.go @@ -3,22 +3,10 @@ package states import ( "time" - apiv1 "kusionstack.io/kusion/pkg/apis/core/v1" + v1 "kusionstack.io/kusion/pkg/apis/core/v1" "kusionstack.io/kusion/pkg/version" ) -// StateStorage represents the set of methods to manipulate State in a specified storage -type StateStorage interface { - // GetLatestState return nil if state not exists - GetLatestState(query *StateQuery) (*State, error) - - // Apply means update this state if it already exists or create a new one - Apply(state *State) error - - // Delete State by id - Delete(id string) error -} - type StateQuery struct { // Tenant name Tenant string `json:"tenant"` @@ -64,7 +52,7 @@ type State struct { Operator string `json:"operator,omitempty" yaml:"operator,omitempty"` // Resources records all resources in this operation - Resources apiv1.Resources `json:"resources" yaml:"resources"` + Resources v1.Resources `json:"resources" yaml:"resources"` // CreateTime is the time State is created CreateTime time.Time `json:"createTime" yaml:"createTime"` @@ -77,7 +65,19 @@ func NewState() *State { s := &State{ KusionVersion: version.ReleaseVersion(), Version: 1, - Resources: []apiv1.Resource{}, + Resources: []v1.Resource{}, } return s } + +// StateStorage represents the set of methods to manipulate State in a specified storage +type StateStorage interface { + // GetLatestState return nil if state not exists + GetLatestState(query *StateQuery) (*State, error) + + // Apply means update this state if it already exists or create a new one + Apply(state *State) error + + // Delete State by id + Delete(id string) error +} diff --git a/pkg/engine/states/state_test.go b/pkg/engine/states/state_test.go deleted file mode 100644 index 782a8f58..00000000 --- a/pkg/engine/states/state_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package states - -import ( - "reflect" - "testing" - - apiv1 "kusionstack.io/kusion/pkg/apis/core/v1" - "kusionstack.io/kusion/pkg/version" -) - -func TestNewState(t *testing.T) { - tests := []struct { - name string - want *State - }{ - { - name: "t1", - want: &State{ - KusionVersion: version.ReleaseVersion(), - Version: 1, - Resources: []apiv1.Resource{}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := NewState(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("NewState() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestResourceKey(t *testing.T) { - tests := []struct { - name string - want string - resourceState *apiv1.Resource - }{ - { - name: "t1", - want: "kusion_test", - resourceState: &apiv1.Resource{ - ID: "kusion_test", - Attributes: nil, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.resourceState.ResourceKey(); got != tt.want { - t.Errorf("ResourceKey() = %v, want = %v", got, tt.want) - } - }) - } -} - -func TestResources_Index(t *testing.T) { - tests := []struct { - name string - rs apiv1.Resources - want map[string]*apiv1.Resource - }{ - { - name: "t1", - rs: []apiv1.Resource{ - { - ID: "a", - }, - }, - want: map[string]*apiv1.Resource{ - "a": { - ID: "a", - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.rs.Index(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Index() = %v, want = %v", got, tt.want) - } - }) - } -} - -func TestResources_Len(t *testing.T) { - tests := []struct { - name string - rs apiv1.Resources - want int - }{ - { - name: "t1", - rs: []apiv1.Resource{ - { - ID: "c", - }, - }, - want: 1, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.rs.Len(); got != tt.want { - t.Errorf("models.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestResources_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - rs apiv1.Resources - args args - }{ - { - name: "t1", - rs: []apiv1.Resource{ - { - ID: "test", - }, - }, - args: args{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.rs.Swap(tt.args.i, tt.args.j) - }) - } -} - -func TestResources_Less(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - rs apiv1.Resources - args args - want bool - }{ - { - name: "t1", - rs: []apiv1.Resource{ - { - ID: "a", - }, - { - ID: "b", - }, - }, - args: args{0, 1}, - want: true, - }, - { - name: "t2", - rs: []apiv1.Resource{ - { - ID: "a", - }, - { - ID: "b", - }, - }, - args: args{0, 1}, - want: true, - }, - { - name: "t3", - rs: []apiv1.Resource{ - { - ID: "a", - }, - { - ID: "a", - }, - }, - args: args{0, 1}, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.rs.Less(tt.args.i, tt.args.j); got != tt.want { - t.Errorf("models.Less() = %v, want %v", got, tt.want) - } - }) - } -}