Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement workload(Service/Job) generation #83

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

Kusion is an Intent-Driven Platform Orchestrator that enables developers to specify their desired intent in a declarative way and then use a consistent workflow to drive continuous delivery through the entire application lifecycle.

To achieve that, we've introduced the concept of [Kusion Modules](https://www.kusionstack.io/docs/concepts/kusion-module/overview) for users to prescribe their intent in a structured way. Kusion Modules are modular building blocks that represent common and re-usable capabilities required during an application delivery.
To achieve that, we've introduced the concept of [Kusion Modules](https://www.kusionstack.io/docs/concepts/module/overview) for users to prescribe their intent in a structured way. Kusion Modules are modular building blocks that represent common and re-usable capabilities required during an application delivery.

One of the core goals of Kusion is to build an open, inclusive and prosperous open-source community focused on solving real-world application delivery and management problems, in the meantime sharing the reusable building blocks and best practices.

This repository contains the source code for all Kusion Modules that can be used publicly. If your module is open to the public, we **welcome and highly encourage** you to contribute it to this repository, so that more people can benefit from the module. Submit a pull request to this repository, once it is merged, it will be published to the [KusionStack GitHub container registry](https://github.com/orgs/KusionStack/packages).

We also provide a module [developer guide](https://www.kusionstack.io/docs/concepts/kusion-module/develop-guide) on our website, if you have any questions, please don't hesitate to contact us directly.
We also provide a module [developer guide](https://www.kusionstack.io/docs/concepts/module/develop-guide) on our website, if you have any questions, please don't hesitate to contact us directly.

Some of the modules in this repository are maintained by the KusionStack team, representing our understanding of a "golden path" and are designed to be used out-of-the-box. All examples can be found in the [User Guide](https://www.kusionstack.io/docs/user-guides/working-with-k8s/deploy-application) on our website.

Expand Down Expand Up @@ -43,7 +43,7 @@ The modules defined in the `catalog` repository are published to the [KusionStac
1. Please visit [module references](https://www.kusionstack.io/docs/reference/modules/) on the website or example/readme.md in each module directory to understand the capabilities and usage of each module.
2. Register this module in your workspace and set default values to standardize the module's behavior

Please visit the [platform engineer development guide](https://www.kusionstack.io/docs/concepts/kusion-module/develop-guide) for more details.
Please visit the [platform engineer development guide](https://www.kusionstack.io/docs/concepts/module/develop-guide) for more details.

### App Developers

Expand All @@ -54,4 +54,4 @@ As an application developer, the workflow of using a Kusion module looks like th
3. Initialize modules
4. Apply the AppConfiguration

Please visit the [application developer user guide](https://www.kusionstack.io/docs/concepts/kusion-module/app-dev-guide) for more details.
Please visit the [application developer user guide](https://www.kusionstack.io/docs/concepts/module/app-dev-guide) for more details.
36 changes: 36 additions & 0 deletions modules/workload/job/src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
TEST?=$$(go list ./... | grep -v 'vendor')
###### chang variables below according to your own modules ###
NAMESPACE=kusionstack
NAME=job
VERSION=0.1.0
BINARY=../bin/kusion-module-${NAME}_${VERSION}

LOCAL_ARCH := $(shell uname -m)
ifeq ($(LOCAL_ARCH),x86_64)
GOARCH_LOCAL := amd64
else
GOARCH_LOCAL := $(LOCAL_ARCH)
endif
export GOOS_LOCAL := $(shell uname|tr 'A-Z' 'a-z')
export OS_ARCH ?= $(GOARCH_LOCAL)

default: install

build-darwin:
GOOS=darwin GOARCH=arm64 go build -o ${BINARY}

install: build-darwin
# copy module binary to $KUSION_HOME. e.g. ~/.kusion/modules/kusionstack/job/v0.1.0/darwin/arm64/kusion-module-service_0.1.0
mkdir -p ${KUSION_HOME}/modules/${NAMESPACE}/${NAME}/${VERSION}/${GOOS_LOCAL}/${OS_ARCH}
cp ${BINARY} ${KUSION_HOME}/modules/${NAMESPACE}/${NAME}/${VERSION}/${GOOS_LOCAL}/${OS_ARCH}

release:
GOOS=darwin GOARCH=arm64 go build -o ${BINARY}_darwin_arm64 ./${NAME}
GOOS=darwin GOARCH=amd64 go build -o ${BINARY}_darwin_amd64 ./${NAME}
GOOS=linux GOARCH=arm64 go build -o ${BINARY}_linux_arm64 ./${NAME}
GOOS=linux GOARCH=amd64 go build -o ${BINARY}_linux_amd64 ./${NAME}
GOOS=windows GOARCH=amd64 go build -o ${BINARY}_windows_amd64 ./${NAME}
GOOS=windows GOARCH=386 go build -o ${BINARY}_windows_386 ./${NAME}

test:
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 5m
50 changes: 50 additions & 0 deletions modules/workload/job/src/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module job

go 1.22.1

require (
github.com/imdario/mergo v0.3.16
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.30.0
k8s.io/apimachinery v0.30.0
kusionstack.io/kusion v0.12.0
kusionstack.io/kusion-module-framework v0.2.2
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-plugin v1.6.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
135 changes: 135 additions & 0 deletions modules/workload/job/src/job.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package main

import (
"context"
"fmt"

"gopkg.in/yaml.v2"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kusionstack.io/kusion-module-framework/pkg/module"
"kusionstack.io/kusion-module-framework/pkg/server"
v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
"kusionstack.io/kusion/pkg/log"
"kusionstack.io/kusion/pkg/modules"
)

func (j *Job) Generate(_ context.Context, request *module.GeneratorRequest) (*module.GeneratorResponse, error) {
defer func() {
if r := recover(); r != nil {
log.Debugf("failed to generate Job module: %v", r)
}
}()

if request.DevConfig == nil {
log.Info("Job does not exist in AppConfig config")
return nil, nil
}
out, err := yaml.Marshal(request.DevConfig)
if err != nil {
return nil, err
}

if err = yaml.Unmarshal(out, j); err != nil {
return nil, fmt.Errorf("complete Job by dev config failed, %w", err)
}

if err = completeBaseWorkload(&j.Base, request.PlatformConfig); err != nil {
return nil, fmt.Errorf("complete Job by platform config failed, %w", err)
}

uniqueAppName := modules.UniqueAppName(request.Project, request.Stack, request.App)

meta := metav1.ObjectMeta{
Namespace: request.Project,
Name: uniqueAppName,
Labels: modules.MergeMaps(
modules.UniqueAppLabels(request.Project, request.App),
j.Labels,
),
Annotations: modules.MergeMaps(
j.Annotations,
),
}

containers, volumes, configMaps, err := toOrderedContainers(j.Containers, uniqueAppName)
if err != nil {
return nil, err
}

res := make([]v1.Resource, 0)
for _, cm := range configMaps {
cm.Namespace = request.Project
resourceID := module.KubernetesResourceID(cm.TypeMeta, cm.ObjectMeta)
resource, err := module.WrapK8sResourceToKusionResource(resourceID, &cm)
if err != nil {
return nil, err
}
res = append(res, *resource)
}

jobSpec := batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: modules.MergeMaps(modules.UniqueAppLabels(request.Project, request.App), j.Labels),
Annotations: modules.MergeMaps(j.Annotations),
},
Spec: corev1.PodSpec{
Containers: containers,
RestartPolicy: corev1.RestartPolicyNever,
Volumes: volumes,
},
},
}

if j.Schedule == "" {
k8sJob := &batchv1.Job{
ObjectMeta: meta,
TypeMeta: metav1.TypeMeta{
Kind: "Job",
APIVersion: batchv1.SchemeGroupVersion.String(),
},
Spec: jobSpec,
}

resourceID := module.KubernetesResourceID(k8sJob.TypeMeta, k8sJob.ObjectMeta)
resource, err := module.WrapK8sResourceToKusionResource(resourceID, k8sJob)
if err != nil {
return nil, err
}
res = append(res, *resource)

return &module.GeneratorResponse{
Resources: res,
}, nil
}

cronJob := &batchv1.CronJob{
ObjectMeta: meta,
TypeMeta: metav1.TypeMeta{
Kind: "CronJob",
APIVersion: batchv1.SchemeGroupVersion.String(),
},
Spec: batchv1.CronJobSpec{
JobTemplate: batchv1.JobTemplateSpec{
Spec: jobSpec,
},
Schedule: j.Schedule,
},
}

resourceID := module.KubernetesResourceID(cronJob.TypeMeta, cronJob.ObjectMeta)
resource, err := module.WrapK8sResourceToKusionResource(resourceID, cronJob)
if err != nil {
return nil, err
}
res = append(res, *resource)
return &module.GeneratorResponse{
Resources: res,
}, nil
}

func main() {
server.Start(&Job{})
}
Loading
Loading