Skip to content

Commit

Permalink
feat: use workspace config when build service and job (#717)
Browse files Browse the repository at this point in the history
  • Loading branch information
healthjyk committed Dec 22, 2023
1 parent 207ebeb commit 1ef33b8
Show file tree
Hide file tree
Showing 11 changed files with 590 additions and 65 deletions.
8 changes: 7 additions & 1 deletion pkg/modules/generators/app_configurations_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,17 @@ func (g *appConfigurationGenerator) Generate(i *intent.Intent) error {
i.Resources = make(intent.Resources, 0)
}

// retrieve the module configs of the specified project
moduleConfigs, err := workspace.GetProjectModuleConfigs(g.ws.Modules, g.project.Name)
if err != nil {
return err
}

// Generate resources
gfs := []modules.NewGeneratorFunc{
NewNamespaceGeneratorFunc(g.project.Name, g.ws),
accessories.NewDatabaseGeneratorFunc(g.project, g.stack, g.appName, g.app.Workload, g.app.Database),
workload.NewWorkloadGeneratorFunc(g.project, g.stack, g.appName, g.app.Workload),
workload.NewWorkloadGeneratorFunc(g.project, g.stack, g.appName, g.app.Workload, moduleConfigs),
trait.NewOpsRuleGeneratorFunc(g.project, g.stack, g.appName, g.app),
monitoring.NewMonitoringGeneratorFunc(g.project, g.app.Monitoring, g.appName),
// The OrderedResourcesGenerator should be executed after all resources are generated.
Expand Down
28 changes: 19 additions & 9 deletions pkg/modules/generators/workload/job_generator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package workload

import (
"fmt"

batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -12,23 +14,26 @@ import (
)

type jobGenerator struct {
project *apiv1.Project
stack *apiv1.Stack
appName string
job *workload.Job
project *apiv1.Project
stack *apiv1.Stack
appName string
job *workload.Job
jobConfig apiv1.GenericConfig
}

func NewJobGenerator(
project *apiv1.Project,
stack *apiv1.Stack,
appName string,
job *workload.Job,
jobConfig apiv1.GenericConfig,
) (modules.Generator, error) {
return &jobGenerator{
project: project,
stack: stack,
appName: appName,
job: job,
project: project,
stack: stack,
appName: appName,
job: job,
jobConfig: jobConfig,
}, nil
}

Expand All @@ -37,9 +42,10 @@ func NewJobGeneratorFunc(
stack *apiv1.Stack,
appName string,
job *workload.Job,
jobConfig apiv1.GenericConfig,
) modules.NewGeneratorFunc {
return func() (modules.Generator, error) {
return NewJobGenerator(project, stack, appName, job)
return NewJobGenerator(project, stack, appName, job, jobConfig)
}
}

Expand All @@ -53,6 +59,10 @@ func (g *jobGenerator) Generate(spec *intent.Intent) error {
spec.Resources = make(intent.Resources, 0)
}

if err := completeBaseWorkload(&g.job.Base, g.jobConfig); err != nil {
return fmt.Errorf("complete job input by workspace config failed, %w", err)
}

uniqueAppName := modules.UniqueAppName(g.project.Name, g.stack.Name, g.appName)

meta := metav1.ObjectMeta{
Expand Down
43 changes: 35 additions & 8 deletions pkg/modules/generators/workload/job_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@ func TestNewJobGenerator(t *testing.T) {
expectedStack := &apiv1.Stack{}
expectedAppName := "test"
expectedJob := &workload.Job{}
actual, err := NewJobGenerator(expectedProject, expectedStack, expectedAppName, expectedJob)
expectedJobConfig := apiv1.GenericConfig{
"labels": map[string]any{
"workload-type": "Job",
},
"annotations": map[string]any{
"workload-type": "Job",
},
}
actual, err := NewJobGenerator(expectedProject, expectedStack, expectedAppName, expectedJob, expectedJobConfig)

assert.NoError(t, err, "Error should be nil")
assert.NotNil(t, actual, "Generator should not be nil")
assert.Equal(t, expectedProject, actual.(*jobGenerator).project, "Project mismatch")
assert.Equal(t, expectedStack, actual.(*jobGenerator).stack, "Stack mismatch")
assert.Equal(t, expectedAppName, actual.(*jobGenerator).appName, "AppName mismatch")
assert.Equal(t, expectedJob, actual.(*jobGenerator).job, "Job mismatch")
assert.Equal(t, expectedJobConfig, actual.(*jobGenerator).jobConfig, "JobConfig mismatch")
}

func TestNewJobGeneratorFunc(t *testing.T) {
Expand All @@ -36,7 +45,15 @@ func TestNewJobGeneratorFunc(t *testing.T) {
expectedStack := &apiv1.Stack{}
expectedAppName := "test"
expectedJob := &workload.Job{}
generatorFunc := NewJobGeneratorFunc(expectedProject, expectedStack, expectedAppName, expectedJob)
expectedJobConfig := apiv1.GenericConfig{
"labels": map[string]any{
"workload-type": "Job",
},
"annotations": map[string]any{
"workload-type": "Job",
},
}
generatorFunc := NewJobGeneratorFunc(expectedProject, expectedStack, expectedAppName, expectedJob, expectedJobConfig)
actualGenerator, err := generatorFunc()

assert.NoError(t, err, "Error should be nil")
Expand All @@ -45,15 +62,17 @@ func TestNewJobGeneratorFunc(t *testing.T) {
assert.Equal(t, expectedStack, actualGenerator.(*jobGenerator).stack, "Stack mismatch")
assert.Equal(t, expectedAppName, actualGenerator.(*jobGenerator).appName, "AppName mismatch")
assert.Equal(t, expectedJob, actualGenerator.(*jobGenerator).job, "Job mismatch")
assert.Equal(t, expectedJobConfig, actualGenerator.(*jobGenerator).jobConfig, "JobConfig mismatch")
}

func TestJobGenerator_Generate(t *testing.T) {
testCases := []struct {
name string
expectedProject *apiv1.Project
expectedStack *apiv1.Stack
expectedAppName string
expectedJob *workload.Job
name string
expectedProject *apiv1.Project
expectedStack *apiv1.Stack
expectedAppName string
expectedJob *workload.Job
expectedJobConfig apiv1.GenericConfig
}{
{
name: "test generate",
Expand All @@ -63,12 +82,20 @@ func TestJobGenerator_Generate(t *testing.T) {
expectedStack: &apiv1.Stack{},
expectedAppName: "test",
expectedJob: &workload.Job{},
expectedJobConfig: apiv1.GenericConfig{
"labels": map[string]any{
"workload-type": "Job",
},
"annotations": map[string]any{
"workload-type": "Job",
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
generator, _ := NewJobGenerator(tc.expectedProject, tc.expectedStack, tc.expectedAppName, tc.expectedJob)
generator, _ := NewJobGenerator(tc.expectedProject, tc.expectedStack, tc.expectedAppName, tc.expectedJob, tc.expectedJobConfig)
spec := &intent.Intent{}
err := generator.Generate(spec)

Expand Down
55 changes: 43 additions & 12 deletions pkg/modules/generators/workload/service_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ import (
apiv1 "kusionstack.io/kusion/pkg/apis/core/v1"
"kusionstack.io/kusion/pkg/apis/intent"
"kusionstack.io/kusion/pkg/modules"
"kusionstack.io/kusion/pkg/modules/generators/workload/network"
"kusionstack.io/kusion/pkg/modules/inputs/workload"
"kusionstack.io/kusion/pkg/workspace"

"kusionstack.io/kusion/pkg/modules/generators/workload/network"
)

// workloadServiceGenerator is a struct for generating service workload resources.
type workloadServiceGenerator struct {
project *apiv1.Project
stack *apiv1.Stack
appName string
service *workload.Service
project *apiv1.Project
stack *apiv1.Stack
appName string
service *workload.Service
serviceConfig apiv1.GenericConfig
}

// NewWorkloadServiceGenerator returns a new workloadServiceGenerator instance.
Expand All @@ -30,6 +33,7 @@ func NewWorkloadServiceGenerator(
stack *apiv1.Stack,
appName string,
service *workload.Service,
serviceConfig apiv1.GenericConfig,
) (modules.Generator, error) {
if len(project.Name) == 0 {
return nil, fmt.Errorf("project name must not be empty")
Expand All @@ -44,10 +48,11 @@ func NewWorkloadServiceGenerator(
}

return &workloadServiceGenerator{
project: project,
stack: stack,
appName: appName,
service: service,
project: project,
stack: stack,
appName: appName,
service: service,
serviceConfig: serviceConfig,
}, nil
}

Expand All @@ -57,9 +62,10 @@ func NewWorkloadServiceGeneratorFunc(
stack *apiv1.Stack,
appName string,
service *workload.Service,
serviceConfig apiv1.GenericConfig,
) modules.NewGeneratorFunc {
return func() (modules.Generator, error) {
return NewWorkloadServiceGenerator(project, stack, appName, service)
return NewWorkloadServiceGenerator(project, stack, appName, service, serviceConfig)
}
}

Expand All @@ -75,6 +81,10 @@ func (g *workloadServiceGenerator) Generate(spec *intent.Intent) error {
spec.Resources = make(intent.Resources, 0)
}

if err := completeServiceInput(g.service, g.serviceConfig); err != nil {
return fmt.Errorf("complete service input by workspace config failed, %w", err)
}

uniqueAppName := modules.UniqueAppName(g.project.Name, g.stack.Name, g.appName)

// Create a slice of containers based on the app's
Expand Down Expand Up @@ -125,10 +135,10 @@ func (g *workloadServiceGenerator) Generate(spec *intent.Intent) error {
typeMeta := metav1.TypeMeta{}

switch service.Type {
case workload.TypeDeploy:
case workload.TypeDeployment:
typeMeta = metav1.TypeMeta{
APIVersion: appsv1.SchemeGroupVersion.String(),
Kind: workload.TypeDeploy,
Kind: workload.TypeDeployment,
}
spec := appsv1.DeploymentSpec{
Replicas: modules.GenericPtr(int32(service.Replicas)),
Expand Down Expand Up @@ -171,3 +181,24 @@ func (g *workloadServiceGenerator) Generate(spec *intent.Intent) error {

return nil
}

func completeServiceInput(service *workload.Service, config apiv1.GenericConfig) error {
if err := completeBaseWorkload(&service.Base, config); err != nil {
return err
}
serviceType, err := workspace.GetStringFromGenericConfig(config, workload.FieldType)
if err != nil {
return err
}
// if not set in workspace, use Deployment as default type
if serviceType == "" {
serviceType = workload.TypeDeployment
}
if serviceType != workload.TypeDeployment && serviceType != workload.TypeCollaset {
return fmt.Errorf("unsupported service type %s", serviceType)
}
if service.Type == "" {
service.Type = serviceType
}
return nil
}
Loading

0 comments on commit 1ef33b8

Please sign in to comment.