diff --git a/pkg/apis/core/v1/patcher.go b/pkg/apis/core/v1/patcher.go new file mode 100644 index 00000000..1a03ff7d --- /dev/null +++ b/pkg/apis/core/v1/patcher.go @@ -0,0 +1,13 @@ +package v1 + +import v1 "k8s.io/api/core/v1" + +// Patcher contains fields should be patched into the workload corresponding fields +type Patcher struct { + // Environments represent the environment variables patched to all containers in the workload. + Environments []v1.EnvVar `json:"environments" yaml:"environments"` + // Labels represent the labels patched to both the workload and pod. + Labels map[string]string `json:"labels" yaml:"labels"` + // Annotations represent the annotations patched to both the workload and pod. + Annotations map[string]string `json:"annotations" yaml:"annotations"` +} diff --git a/pkg/apis/core/v1/resource.go b/pkg/apis/core/v1/resource.go index 44a2d733..a7582650 100644 --- a/pkg/apis/core/v1/resource.go +++ b/pkg/apis/core/v1/resource.go @@ -2,8 +2,6 @@ package v1 import ( "encoding/json" - - v1 "k8s.io/api/core/v1" ) type Resources []Resource @@ -24,22 +22,10 @@ type Resource struct { // DependsOn contains all resources this resource depends on DependsOn []string `json:"dependsOn,omitempty" yaml:"dependsOn,omitempty"` - // Patcher contains fields should be patched into the workload corresponding fields - Patcher *Patcher `json:"patcher,omitempty" yaml:"patcher,omitempty"` - // Extensions specifies arbitrary metadata of this resource Extensions map[string]interface{} `json:"extensions,omitempty" yaml:"extensions,omitempty"` } -type Patcher struct { - // Environments represent the environment variables patched to all containers in the workload. - Environments []v1.EnvVar `json:"environments" yaml:"environments"` - // Labels represent the labels patched to both the workload and pod. - Labels map[string]string `json:"labels" yaml:"labels"` - // Annotations represent the annotations patched to both the workload and pod. - Annotations map[string]string `json:"annotations" yaml:"annotations"` -} - func (r *Resource) ResourceKey() string { return r.ID } diff --git a/pkg/cmd/mod/mod_init.go b/pkg/cmd/mod/mod_init.go index 717511d7..db59c748 100644 --- a/pkg/cmd/mod/mod_init.go +++ b/pkg/cmd/mod/mod_init.go @@ -21,13 +21,13 @@ type InitOptions struct { } var example = i18n.T(`# Create a kusion module template in the current directory - kusion mod init my-app + kusion mod init my-module # Init a kusion module at the specified Path - kusion mod init my-app ./modules + kusion mod init my-module ./modules # Init a module from a remote git template repository - kusion mod init my-app --template https://github.com//`) + kusion mod init my-module --template https://github.com//`) var short = i18n.T("Create a kusion module along with common files and directories in the current directory") const ( diff --git a/pkg/modules/generators/app_configurations_generator.go b/pkg/modules/generators/app_configurations_generator.go index 2b6e7402..af9a08da 100644 --- a/pkg/modules/generators/app_configurations_generator.go +++ b/pkg/modules/generators/app_configurations_generator.go @@ -116,24 +116,22 @@ func (g *appConfigurationGenerator) Generate(spec *v1.Intent) error { if spec.Resources == nil || len(spec.Resources) < 2 { return fmt.Errorf("workload is not generated") } - workload := spec.Resources[1] + wl := spec.Resources[1] // call modules to generate customized resources - resources, err := g.callModules(projectModuleConfigs) + resources, patchers, err := g.callModules(projectModuleConfigs) if err != nil { return err } // patch workload with resource patchers - for i, r := range resources { - if r.Patcher != nil { - if err = patchWorkload(&workload, r.Patcher); err != nil { - return err - } - resources[i] = r + for _, p := range patchers { + if err = patchWorkload(&wl, &p); err != nil { + return err } } + // append the generated resources to the spec spec.Resources = append(spec.Resources, resources...) // The OrderedResourcesGenerator should be executed after all resources are generated. @@ -245,9 +243,7 @@ func patchWorkload(workload *v1.Resource, patcher *v1.Patcher) error { return nil } -func (g *appConfigurationGenerator) callModules(projectModuleConfigs map[string]v1.GenericConfig) ([]v1.Resource, error) { - var resources []v1.Resource - +func (g *appConfigurationGenerator) callModules(projectModuleConfigs map[string]v1.GenericConfig) (resources []v1.Resource, patchers []v1.Patcher, err error) { pluginMap := make(map[string]*modules.Plugin) defer func() { for _, plugin := range pluginMap { @@ -266,10 +262,10 @@ func (g *appConfigurationGenerator) callModules(projectModuleConfigs map[string] if pluginMap[t] == nil { plugin, err := modules.NewPlugin(t) if err != nil { - return nil, err + return nil, nil, err } if plugin == nil { - return nil, fmt.Errorf("init plugin for module %s failed", t) + return nil, nil, fmt.Errorf("init plugin for module %s failed", t) } pluginMap[t] = plugin } @@ -278,17 +274,17 @@ func (g *appConfigurationGenerator) callModules(projectModuleConfigs map[string] // prepare the request protoRequest, err := g.initModuleRequest(t, config) if err != nil { - return nil, err + return nil, nil, err } // invoke the plugin log.Infof("invoke module:%s with request:%s", t, protoRequest.String()) response, err := plugin.Module.Generate(context.Background(), protoRequest) if err != nil { - return nil, fmt.Errorf("invoke kusion module: %s failed. %w", t, err) + return nil, nil, fmt.Errorf("invoke kusion module: %s failed. %w", t, err) } if response == nil { - return nil, fmt.Errorf("empty response from module %s", t) + return nil, nil, fmt.Errorf("empty response from module %s", t) } // parse module result @@ -296,13 +292,22 @@ func (g *appConfigurationGenerator) callModules(projectModuleConfigs map[string] temp := &v1.Resource{} err = yaml.Unmarshal(res, temp) if err != nil { - return nil, err + return nil, nil, err } resources = append(resources, *temp) } + // parse patcher + for _, patcher := range response.Patchers { + temp := &v1.Patcher{} + err = yaml.Unmarshal(patcher, temp) + if err != nil { + return nil, nil, err + } + patchers = append(patchers, *temp) + } } - return resources, nil + return resources, patchers, nil } func (g *appConfigurationGenerator) initModuleRequest(key string, platformModuleConfig v1.GenericConfig) (*proto.GeneratorRequest, error) { diff --git a/pkg/modules/generators/app_configurations_generator_test.go b/pkg/modules/generators/app_configurations_generator_test.go index 0b17ba76..5fcbd0f5 100644 --- a/pkg/modules/generators/app_configurations_generator_test.go +++ b/pkg/modules/generators/app_configurations_generator_test.go @@ -66,7 +66,7 @@ func mockPlugin() { mockey.Mock(modules.NewPlugin).To(func(key string) (*modules.Plugin, error) { return &modules.Plugin{Module: &fakeModule{}}, nil }).Build() - mockey.Mock((*modules.Plugin).KillPluginClient).To(func() {}).Build() + mockey.Mock((*modules.Plugin).KillPluginClient).Return().Build() } func TestAppConfigurationGenerator_Generate_CustomNamespace(t *testing.T) { diff --git a/pkg/modules/proto/module.pb.go b/pkg/modules/proto/module.pb.go index 29b0d00a..d9fba671 100644 --- a/pkg/modules/proto/module.pb.go +++ b/pkg/modules/proto/module.pb.go @@ -131,6 +131,7 @@ type GeneratorResponse struct { // Resources is a v1.Resource array, which represents the generated resources by this module. Resources [][]byte `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` + Patchers [][]byte `protobuf:"bytes,2,rep,name=patchers,proto3" json:"patchers,omitempty"` } func (x *GeneratorResponse) Reset() { @@ -172,6 +173,13 @@ func (x *GeneratorResponse) GetResources() [][]byte { return nil } +func (x *GeneratorResponse) GetPatchers() [][]byte { + if x != nil { + return x.Patchers + } + return nil +} + var File_module_proto protoreflect.FileDescriptor var file_module_proto_rawDesc = []byte{ @@ -191,15 +199,17 @@ var file_module_proto_rawDesc = []byte{ 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x31, 0x0a, 0x11, 0x47, 0x65, + 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x4d, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x32, 0x3b, 0x0a, - 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2e, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x0c, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x08, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x32, 0x3b, 0x0a, 0x06, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, + 0x11, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2e, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -220,8 +230,8 @@ var file_module_proto_goTypes = []interface{}{ (*GeneratorResponse)(nil), // 1: GeneratorResponse } var file_module_proto_depIdxs = []int32{ - 0, // 0: ModulePath.Generate:input_type -> GeneratorRequest - 1, // 1: ModulePath.Generate:output_type -> GeneratorResponse + 0, // 0: Module.Generate:input_type -> GeneratorRequest + 1, // 1: Module.Generate:output_type -> GeneratorResponse 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name diff --git a/pkg/modules/proto/module.proto b/pkg/modules/proto/module.proto index 01b4ba97..c4b78232 100644 --- a/pkg/modules/proto/module.proto +++ b/pkg/modules/proto/module.proto @@ -23,6 +23,7 @@ message GeneratorRequest { message GeneratorResponse { // Resources is a v1.Resource array, which represents the generated resources by this module. repeated bytes resources = 1; + repeated bytes patchers = 2; } service Module { diff --git a/pkg/modules/proto/module_grpc.pb.go b/pkg/modules/proto/module_grpc.pb.go index 12ac311d..d5a684ab 100644 --- a/pkg/modules/proto/module_grpc.pb.go +++ b/pkg/modules/proto/module_grpc.pb.go @@ -18,7 +18,7 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 -// ModuleClient is the client API for ModulePath service. +// ModuleClient is the client API for Module service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ModuleClient interface { @@ -35,14 +35,14 @@ func NewModuleClient(cc grpc.ClientConnInterface) ModuleClient { func (c *moduleClient) Generate(ctx context.Context, in *GeneratorRequest, opts ...grpc.CallOption) (*GeneratorResponse, error) { out := new(GeneratorResponse) - err := c.cc.Invoke(ctx, "/ModulePath/Generate", in, out, opts...) + err := c.cc.Invoke(ctx, "/Module/Generate", in, out, opts...) if err != nil { return nil, err } return out, nil } -// ModuleServer is the server API for ModulePath service. +// ModuleServer is the server API for Module service. // All implementations must embed UnimplementedModuleServer // for forward compatibility type ModuleServer interface { @@ -80,7 +80,7 @@ func _Module_Generate_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/ModulePath/Generate", + FullMethod: "/Module/Generate", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ModuleServer).Generate(ctx, req.(*GeneratorRequest)) @@ -88,11 +88,11 @@ func _Module_Generate_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } -// Module_ServiceDesc is the grpc.ServiceDesc for ModulePath service. +// Module_ServiceDesc is the grpc.ServiceDesc for Module service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var Module_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "ModulePath", + ServiceName: "Module", HandlerType: (*ModuleServer)(nil), Methods: []grpc.MethodDesc{ {