diff --git a/pkg/module/generator/ordered_resources_test.go b/pkg/module/generator/ordered_resources_test.go index c6504ac..697ba55 100644 --- a/pkg/module/generator/ordered_resources_test.go +++ b/pkg/module/generator/ordered_resources_test.go @@ -17,10 +17,10 @@ var ( "namespace": "foo", "name": "bar", }, - "Spec": map[string]interface{}{ + "spec": map[string]interface{}{ "replica": 1, "template": map[string]interface{}{ - "Spec": map[string]interface{}{ + "spec": map[string]interface{}{ "containers": []map[string]interface{}{ { "image": "foo.bar.com:v1", diff --git a/pkg/module/interfaces.go b/pkg/module/interfaces.go index a5b1783..fa0e319 100644 --- a/pkg/module/interfaces.go +++ b/pkg/module/interfaces.go @@ -7,27 +7,16 @@ import ( "github.com/pkg/errors" "google.golang.org/grpc" - v1 "kusionstack.io/kusion-api-go/api.kusion.io/v1" "kusionstack.io/kusion-module-framework/pkg/module/proto" ) const PluginKey = "module-default" -// Generator is an interface for things that can generate Intent from input configurations. -// todo it's for built-in generators and we should consider to convert it to a general Module interface -type Generator interface { - // Generate performs the intent generate operation. - Generate(intent *v1.Spec) error -} - // Module is the interface that we're exposing as a kusion module plugin. type Module interface { Generate(ctx context.Context, req *proto.GeneratorRequest) (*proto.GeneratorResponse, error) } -// NewGeneratorFunc is a function that returns a Generator. -type NewGeneratorFunc func() (Generator, error) - type GRPCClient struct { client proto.ModuleClient } diff --git a/pkg/module/util.go b/pkg/module/util.go index 074f5b7..fa44bd4 100644 --- a/pkg/module/util.go +++ b/pkg/module/util.go @@ -40,7 +40,8 @@ func WrapK8sResourceToKusionResource(id string, resource runtime.Object) (*v1.Re }, nil } -// KubernetesResourceID returns the ID of a Kubernetes resource based on its type and metadata. Resource ID should be unique in one Spec. +// KubernetesResourceID returns the ID of a Kubernetes resource based on its type and metadata. +// Resource ID usually should be unique in one resource list. func KubernetesResourceID(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectMeta) string { // resource id example: apps/v1:Deployment:nginx:nginx-deployment id := typeMeta.APIVersion + ":" + typeMeta.Kind + ":" @@ -99,7 +100,8 @@ type ProviderConfig struct { ProviderMeta v1.GenericConfig `yaml:"providerMeta" json:"providerMeta"` } -// TerraformResourceID returns the Kusion resource ID of the Terraform resource. Resource ID should be unique in one Spec. +// TerraformResourceID returns the Kusion resource ID of the Terraform resource. +// Resource ID usually should be unique in one resource list. func TerraformResourceID(providerCfg ProviderConfig, resType, resName string) (string, error) { if providerCfg.Version == "" { return "", ErrEmptyTFProviderVersion @@ -168,7 +170,7 @@ func TerraformProviderRegion(providerCfg ProviderConfig) string { return region.(string) } -// PatchHealthPolicyToExtension patch the health policy to the `extensions` field of the resource in the Spec. +// PatchHealthPolicyToExtension patch the health policy to the `extensions` field of the Kusion resource. // Support Kubernetes resource only. func PatchHealthPolicyToExtension(resource *v1.Resource, healthPolicy string) error { if resource == nil { @@ -192,7 +194,7 @@ func PatchHealthPolicyToExtension(resource *v1.Resource, healthPolicy string) er return nil } -// PatchImportResourcesToExtension patch the imported resource to the `extensions` field of the resource in the Spec. +// PatchImportResourcesToExtension patch the imported resource to the `extensions` field of the Kusion resource. // Support TF resource only. func PatchImportResourcesToExtension(resource *v1.Resource, importedResource string) error { if resource == nil { @@ -215,7 +217,7 @@ func PatchImportResourcesToExtension(resource *v1.Resource, importedResource str return nil } -// PatchKubeConfigPathToExtension patch the kubeConfig path to the `extensions` field of the resource in the Spec. +// PatchKubeConfigPathToExtension patch the kubeConfig path to the `extensions` field of the Kusion resource. // 1. If $KUBECONFIG environment variable is set, then it is used. // 2. If not, and the `kubeConfig` in resource extensions is set, then it is used. // 3. Otherwise, ${HOME}/.kube/config is used. @@ -238,35 +240,6 @@ var IgnoreModules = map[string]bool{ "job": true, } -// CallGeneratorFuncs calls each NewGeneratorFunc in the given slice -// and returns a slice of Generator instances. -func CallGeneratorFuncs(newGenerators ...NewGeneratorFunc) ([]Generator, error) { - gs := make([]Generator, 0, len(newGenerators)) - for _, newGenerator := range newGenerators { - if g, err := newGenerator(); err != nil { - return nil, err - } else { - gs = append(gs, g) - } - } - return gs, nil -} - -// CallGenerators calls the Generate method of each Generator instance -// returned by the given NewGeneratorFuncs. -func CallGenerators(i *v1.Spec, newGenerators ...NewGeneratorFunc) error { - gs, err := CallGeneratorFuncs(newGenerators...) - if err != nil { - return err - } - for _, g := range gs { - if err := g.Generate(i); err != nil { - return err - } - } - return nil -} - // ForeachOrdered executes the given function on each // item in the map in order of their keys. func ForeachOrdered[T any](m map[string]T, f func(key string, value T) error) error { @@ -321,32 +294,6 @@ func KusionPathDependency(id, name string) string { return "$kusion_path." + id + "." + name } -// AppendToSpec adds a Kubernetes resource to the Spec resources slice. -func AppendToSpec(resourceType v1.Type, resourceID string, i *v1.Spec, resource any) error { - // this function is only used for Kubernetes resources - if resourceType != v1.Kubernetes { - return errors.New("AppendToSpec is only used for Kubernetes resources") - } - - gvk := resource.(runtime.Object).GetObjectKind().GroupVersionKind().String() - // fixme: this function converts int to int64 by default - unstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(resource) - if err != nil { - return err - } - r := v1.Resource{ - ID: resourceID, - Type: resourceType, - Attributes: unstructured, - DependsOn: nil, - Extensions: map[string]any{ - v1.ResourceExtensionGVK: gvk, - }, - } - i.Resources = append(i.Resources, r) - return nil -} - // PatchResource patches the resource with the given patch. func PatchResource[T any](resources map[string][]*v1.Resource, gvk string, patchFunc func(*T) error) error { var obj T diff --git a/pkg/module/util_test.go b/pkg/module/util_test.go index 258d07c..9deaee7 100644 --- a/pkg/module/util_test.go +++ b/pkg/module/util_test.go @@ -10,55 +10,6 @@ import ( v1 "kusionstack.io/kusion-api-go/api.kusion.io/v1" ) -type mockGenerator struct { - GenerateFunc func(Spec *v1.Spec) error -} - -func (m *mockGenerator) Generate(i *v1.Spec) error { - return m.GenerateFunc(i) -} - -func TestCallGenerators(t *testing.T) { - i := &v1.Spec{} - - var ( - generator1 Generator = &mockGenerator{ - GenerateFunc: func(Spec *v1.Spec) error { - return nil - }, - } - generator2 Generator = &mockGenerator{ - GenerateFunc: func(Spec *v1.Spec) error { - return assert.AnError - }, - } - gf1 = func() (Generator, error) { return generator1, nil } - gf2 = func() (Generator, error) { return generator2, nil } - ) - - err := CallGenerators(i, gf1, gf2) - assert.Error(t, err) - assert.EqualError(t, err, assert.AnError.Error()) -} - -func TestCallGeneratorFuncs(t *testing.T) { - generatorFunc1 := func() (Generator, error) { - return &mockGenerator{}, nil - } - - generatorFunc2 := func() (Generator, error) { - return nil, assert.AnError - } - - generators, err := CallGeneratorFuncs(generatorFunc1) - assert.NoError(t, err) - assert.Len(t, generators, 1) - assert.IsType(t, &mockGenerator{}, generators[0]) - - _, err = CallGeneratorFuncs(generatorFunc2) - assert.ErrorIs(t, err, assert.AnError) -} - func TestForeachOrdered(t *testing.T) { m := map[string]int{ "b": 2, @@ -120,43 +71,6 @@ func TestKubernetesResourceID(t *testing.T) { assert.Equal(t, "apps/v1:Deployment:example:my-deployment", id) } -func TestAppendToSpec(t *testing.T) { - i := &v1.Spec{} - resource := &v1.Resource{ - ID: "v1:Namespace:fake-project", - Type: "Kubernetes", - Attributes: map[string]interface{}{ - "apiVersion": "v1", - "kind": "Namespace", - "metadata": map[string]interface{}{ - "creationTimestamp": nil, - "name": "fake-project", - }, - "spec": make(map[string]interface{}), - "status": make(map[string]interface{}), - }, - } - - ns := &corev1.Namespace{ - TypeMeta: metav1.TypeMeta{ - Kind: "Namespace", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "fake-project", - }, - } - - err := AppendToSpec(v1.Kubernetes, resource.ID, i, ns) - - assert.NoError(t, err) - assert.Len(t, i.Resources, 1) - assert.Equal(t, resource.ID, i.Resources[0].ID) - assert.Equal(t, resource.Type, i.Resources[0].Type) - assert.Equal(t, resource.Attributes, i.Resources[0].Attributes) - assert.Equal(t, ns.GroupVersionKind().String(), i.Resources[0].Extensions[v1.ResourceExtensionGVK]) -} - func TestUniqueAppName(t *testing.T) { projectName := "my-project" stackName := "my-stack" @@ -218,77 +132,3 @@ func TestPatchResource(t *testing.T) { resources["/v1, Kind=Namespace"][0].Attributes["metadata"].(map[string]interface{})["labels"].(map[string]interface{}), ) } - -func TestAddKubeConfigIf(t *testing.T) { - testcases := []struct { - name string - ws *v1.Workspace - i *v1.Spec - expectedSpec *v1.Spec - }{ - { - name: "empty workspace runtime config", - ws: &v1.Workspace{Name: "dev"}, - i: &v1.Spec{ - Resources: v1.Resources{ - { - ID: "mock-id-1", - Type: "Kubernetes", - Attributes: map[string]any{ - "mock-key": "mock-value", - }, - Extensions: nil, - }, - }, - }, - expectedSpec: &v1.Spec{ - Resources: v1.Resources{ - { - ID: "mock-id-1", - Type: "Kubernetes", - Attributes: map[string]any{ - "mock-key": "mock-value", - }, - Extensions: nil, - }, - }, - }, - }, - { - name: "empty kubeConfig in workspace", - ws: &v1.Workspace{ - Name: "dev", - }, - i: &v1.Spec{ - Resources: v1.Resources{ - { - ID: "mock-id-1", - Type: "Kubernetes", - Attributes: map[string]any{ - "mock-key": "mock-value", - }, - Extensions: nil, - }, - }, - }, - expectedSpec: &v1.Spec{ - Resources: v1.Resources{ - { - ID: "mock-id-1", - Type: "Kubernetes", - Attributes: map[string]any{ - "mock-key": "mock-value", - }, - Extensions: nil, - }, - }, - }, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, *tc.expectedSpec, *tc.i) - }) - } -}