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: add code runner for configuration code execution #803

Merged
merged 1 commit into from
Feb 21, 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
13 changes: 13 additions & 0 deletions pkg/cmd/generate/run/fake/fake.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fake
healthjyk marked this conversation as resolved.
Show resolved Hide resolved

import "kusionstack.io/kusion/pkg/cmd/generate/run"

var _ run.CodeRunner = &KPMRunner{}

// KPMRunner is a fake code runner for testing purposes.
type KPMRunner struct{}

// Run does nothing.
func (r *KPMRunner) Run(workDir string, arguments map[string]string) ([]byte, error) {
return nil, nil
}
57 changes: 57 additions & 0 deletions pkg/cmd/generate/run/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package run

import (
kcl "kcl-lang.io/kcl-go"
kclpkg "kcl-lang.io/kcl-go/pkg/kcl"
"kcl-lang.io/kpm/pkg/api"
"kcl-lang.io/kpm/pkg/opt"
)

// CodeRunner compiles and runs the target DSL based configuration code
// and returns configuration data in plain format.
type CodeRunner interface {
Run(workingDir string, arguments map[string]string) ([]byte, error)
}

// KPMRunner should implement the CodeRunner interface.
var _ CodeRunner = &KPMRunner{}

// KPMRunner implements the CodeRunner interface.
type KPMRunner struct{}

// Run calls KPM api to compile and run KCL based configuration code.
func (r *KPMRunner) Run(workDir string, arguments map[string]string) ([]byte, error) {
optList := buildKCLOptions(workDir, arguments)
result, err := api.RunWithOpts(
opt.WithKclOption(*kclpkg.NewOption().Merge(optList...)),
opt.WithNoSumCheck(true),
opt.WithLogWriter(nil),
)
if err != nil {
return nil, err
}

return []byte(result.GetRawYamlResult()), nil
}

// buildKCLOptions returns list of KCL options.
func buildKCLOptions(workDir string, arguments map[string]string) []kcl.Option {
optList := make([]kcl.Option, 2)

// build arguments option
for k, v := range arguments {
argStr := k + "=" + v
withOpt := kcl.WithOptions(argStr)
optList = append(optList, withOpt)
}

// build workDir option
withOpt := kcl.WithWorkDir(workDir)
optList = append(optList, withOpt)

// eliminate null values in the result
withOpt = kcl.WithDisableNone(true)
optList = append(optList, withOpt)

return optList
}
23 changes: 23 additions & 0 deletions pkg/cmd/generate/run/run_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package run

import (
"os"
"path/filepath"
"testing"
)

func TestKPMRunnerRun(t *testing.T) {
currentPath, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
workDir := filepath.Join(currentPath, "testdata/prod")
codeRunner := &KPMRunner{}
value, err := codeRunner.Run(workDir, nil)
if err != nil {
t.Fatalf("Failed to run configuration code: %v", err)
}
if len(value) == 0 {
t.Fatalf("Unexpected value output")
}
}
55 changes: 55 additions & 0 deletions pkg/cmd/generate/run/testdata/base/base.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import catalog.models.schema.v1 as ac
import catalog.models.schema.v1.workload as wl
import catalog.models.schema.v1.workload.container as c
import catalog.models.schema.v1.workload.container.probe as p

# base.k declares reusable configurations for all stacks.
helloworld: ac.AppConfiguration {
workload: wl.Service {
containers: {
"nginx": c.Container {
image: "nginx:v1"
# Run the following command as defined
command: ["/bin/sh", "-c", "echo hi"]
# Extra arguments append to command defined above
args: ["/bin/sh", "-c", "echo hi"]
env: {
# An environment variable of name "env1" and value "VALUE" will be set
"env1": "VALUE"
# An environment variable of name "env2" and value of the key "key" in the
# secret named "sec-name" will be set.
"env2": "secret://sec-name/key"
}
# Run the command "/bin/sh -c echo hi", as defined above, in the directory "/tmp"
workingDir: "/tmp"
# Configure a HTTP readiness probe
readinessProbe: p.Probe {
probeHandler: p.Http {
url: "http://localhost:80"
}
initialDelaySeconds: 10
}
}
}
# Set the replicas
replicas: 2
}
}

sampleapp: ac.AppConfiguration {
workload: wl.Service {
containers: {
"nginx": c.Container {
image: "nginx:v1"
# Run the following command as defined
command: ["/bin/sh", "-c", "echo hi"]
# Extra arguments append to command defined above
args: ["/bin/sh", "-c", "echo hi"]
# Run the command "/bin/sh -c echo hi", as defined above, in the directory "/tmp"
workingDir: "/tmp"
}
}
# Set the replicas
replicas: 2
}
}
9 changes: 9 additions & 0 deletions pkg/cmd/generate/run/testdata/prod/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "testdata"
version = "0.1.0"

[dependencies]
catalog = { git = "https://github.com/KusionStack/catalog.git", tag = "0.1.2" }
[profile]
entries = ["../base/base.k", "main.k"]

16 changes: 16 additions & 0 deletions pkg/cmd/generate/run/testdata/prod/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import catalog.models.schema.v1 as ac

# main.k declares customized configurations for prod stack.
helloworld: ac.AppConfiguration {
workload.containers.nginx: {
# prod stack has different image
image = "nginx:v2"
}
}

sampleapp: ac.AppConfiguration {
workload.containers.nginx: {
# prod stack has different image
image = "nginx:v3"
}
}
2 changes: 2 additions & 0 deletions pkg/cmd/generate/run/testdata/prod/stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# The stack basic info
name: prod
2 changes: 2 additions & 0 deletions pkg/cmd/generate/run/testdata/project.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# The project basic info
name: testdata
Loading