diff --git a/README.md b/README.md index 293c073..0573ba1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Take you to the land of light, the city of freedom(A unified external service management system for NAS). +## 场景抽象 + 对于公网服务暴露,存在如下场景: 无公网: 1. 本地安装frpc,本地frpc配置/长期运行 @@ -17,11 +19,9 @@ Take you to the land of light, the city of freedom(A unified external service ma 2. 无 3. 域名配置 -对于步骤1,2,3;每个步骤都可以抽象化,定义独立的行为,抽象模型如下: -1. 本地配置 -2. 服务端配置 -3. 域名配置 +从上面可以发现,都是一个一个步骤的抽象,上一个步骤完成,然后执行下一个步骤。所以,本质上是一个工作流的处理,携带着各种参数。 +所以,本质上两种资源:步骤,和网站的服务流,服务类由一个一个步骤抽象组成。定义如下: # demo 步骤1 @@ -81,7 +81,7 @@ full workflow demo: name: exposeLocalService kind: ServiceExpose description: xxx -LocalConfiguration: +configurationSteps: - use: xxx name: frpInstall in: @@ -90,13 +90,11 @@ LocalConfiguration: - use: xxx in: | ip: frpInstall.out.xxx -RemoteConfiguration: - use: xxx name: xxx with: - xxx: xxx.out.xxx -DNSConfiguration: - use: xxx +- use: xxx with: -name: xxx ``` diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..90b147d --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# 1. Start docker service +systemctl start docker + +# 2. Start mysql server +service mysql start + +# 3. Start bifrost diff --git a/pkg/api/types.go b/pkg/api/types.go index 9dc2bc3..b654894 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -16,17 +16,7 @@ limitations under the License. package api -const ( - LocalStepType string = "local" - RemoteStepType string = "remote" - DNSStepType string = "dns" -) - -type LocalConfigDefinition ConfigStepDefinition -type RemoteConfigDefinition ConfigStepDefinition -type DNSConfigDefinition ConfigStepDefinition - -type ConfigStepDefinition struct { +type ConfigurationStepDefinition struct { Name string `json:"name"` Description string `json:"description"` Image string `json:"image"` @@ -54,12 +44,10 @@ type ParameterDefinition struct { } type ConfigurationWorkflow struct { - Name string `json:"name"` - Description string `json:"description"` - LocalConfigurationSteps []ConfigurationStep `json:"localConfigurationSteps"` - RemoteConfigurationSteps []ConfigurationStep `json:"remoteConfigurationSteps"` - DNSConfigurationSteps []ConfigurationStep `json:"dnsConfigurationSteps"` - Status ConfigurationWorkflowStatus `json:"status,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + ConfigurationSteps []ConfigurationStep `json:"configurationSteps"` + Status ConfigurationWorkflowStatus `json:"status,omitempty"` } type ConfigurationStep struct { @@ -81,11 +69,9 @@ const ( ) type ConfigurationWorkflowStatus struct { - State ConfigurationWorkflowState `json:"state"` - Message string `json:"message"` - LocalConfigurationSteps []ConfigurationStepStatus `json:"LocalConfigurationSteps"` - RemoteConfigurationSteps []ConfigurationStepStatus `json:"RemoteConfigurationSteps"` - DNSConfigurationSteps []ConfigurationStepStatus `json:"DNSConfigurationSteps"` + State ConfigurationWorkflowState `json:"state"` + Message string `json:"message"` + ConfigurationSteps []ConfigurationStepStatus `json:"configurationSteps"` } type ConfigurationStepStatus struct { diff --git a/pkg/container/create.go b/pkg/container/create.go index 6502b45..0be26e6 100644 --- a/pkg/container/create.go +++ b/pkg/container/create.go @@ -19,9 +19,15 @@ func CreateContainer(workflowName, stepName, image string) (string, error) { } resp, err := cli.ContainerCreate(context.Background(), &container.Config{ Image: image, - Tty: false}, nil, nil, nil, "") + Tty: false}, nil, nil, nil, "bifrost-"+workflowName+"-"+stepName) if err != nil { return "", err } + err = cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}) + if err != nil { + // Ignore the error, we can't do anything + cli.ContainerRemove(context.Background(), resp.ID, types.ContainerRemoveOptions{Force: true}) + return "", err + } return resp.ID, nil } diff --git a/pkg/controller/workflow.go b/pkg/controller/workflow.go index 721dccd..8354ef6 100644 --- a/pkg/controller/workflow.go +++ b/pkg/controller/workflow.go @@ -55,7 +55,7 @@ func (w *WorkflowQueue) Run() { for { w.mutex.Lock() defer w.mutex.Unlock() - for name, _ := range w.Workflow { + for name := range w.Workflow { requeue, err := w.Reconcile(name) if err == nil && !requeue { delete(w.Workflow, name) @@ -84,8 +84,8 @@ func (w *WorkflowQueue) Reconcile(name string) (requeue bool, err error) { } func (w *WorkflowQueue) DeleteWorkflow(wf *api.ConfigurationWorkflow) (requeue bool, err error) { - for index, step := range wf.DNSConfigurationSteps { - stepState := wf.Status.DNSConfigurationSteps[index] + for index, step := range wf.ConfigurationSteps { + stepState := wf.Status.ConfigurationSteps[index] if stepState.State == api.ConfigurationWorkflowStateRunning || stepState.State == api.ConfigurationWorkflowStateRunningSuccess { err := container.DeleteContainer(stepState.ContainerId) @@ -109,7 +109,7 @@ func (w *WorkflowQueue) DeleteWorkflow(wf *api.ConfigurationWorkflow) (requeue b } } - stepDef := customapi.GetDNSStepDefinition(step.Use) + stepDef := customapi.GetStepDefinition(step.Use) if stepDef == nil { return false, fmt.Errorf("dns step definition %s not found", step.Use) } diff --git a/pkg/customapi/remotesteps/docker_config.go b/pkg/customapi/docker_config.go similarity index 56% rename from pkg/customapi/remotesteps/docker_config.go rename to pkg/customapi/docker_config.go index 1c60a99..3840830 100644 --- a/pkg/customapi/remotesteps/docker_config.go +++ b/pkg/customapi/docker_config.go @@ -1,4 +1,20 @@ -package remotesteps +/* +Copyright 2023 The opennaslab Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicabl e law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package customapi import "fmt" diff --git a/pkg/customapi/localsteps/frpc_config.go b/pkg/customapi/frpc_config.go similarity index 100% rename from pkg/customapi/localsteps/frpc_config.go rename to pkg/customapi/frpc_config.go diff --git a/pkg/customapi/interface.go b/pkg/customapi/interface.go index 1c50395..b219a48 100644 --- a/pkg/customapi/interface.go +++ b/pkg/customapi/interface.go @@ -6,19 +6,14 @@ import ( "reflect" "opennaslab.io/bifrost/pkg/api" - localsteps "opennaslab.io/bifrost/pkg/customapi/localsteps" - remotesteps "opennaslab.io/bifrost/pkg/customapi/remotesteps" ) -var LocalStepsInfoMap = map[string]StepsInfo{ +var StepsInfoMap = map[string]StepsInfo{ "frpc-config": { Name: "frpc-config", Image: "opennaslab/frpc-config:latest", - Description: "install/config frpc in local host", + Description: "install/config frpc in remote host", }, -} - -var RemoteStepsInfoMap = map[string]StepsInfo{ "docker-config": { Name: "docker-config", Image: "opennaslan/docker-config:latest", @@ -26,36 +21,25 @@ var RemoteStepsInfoMap = map[string]StepsInfo{ }, } -var DNSStepsInfoMap = map[string]StepsInfo{} - type TypedInterface interface { Validate() error } -var LocalStepsStruct = map[string]TypedInterface{ - "frpc-config": localsteps.FrpcParameterIn{Service: []localsteps.FrpService{{}}}, +var StepsStruct = map[string]TypedInterface{ + "frpc-config": FrpcParameterIn{Service: []FrpService{{}}}, + "docker-config": DockerConfigParameterIn{}, } -var RemoteStepsStruct = map[string]TypedInterface{ - "docker-config": remotesteps.DockerConfigParameterIn{}, -} - -var DNSStepsStruct = map[string]TypedInterface{} - -func GetTypedConfig(stepType string, step *api.ConfigurationStep) (TypedInterface, error) { - if stepType == api.LocalStepType { - if _, ok := LocalStepsStruct[step.Use]; !ok { - return nil, fmt.Errorf("not found") - } - // TODO: there is currency problem - ret := LocalStepsStruct[step.Use] - if err := json.Unmarshal([]byte(step.In), ret); err != nil { - return nil, err - } - return ret, nil +func GetTypedConfig(step *api.ConfigurationStep) (TypedInterface, error) { + if _, ok := StepsStruct[step.Use]; !ok { + return nil, fmt.Errorf("not found") } - - return nil, fmt.Errorf("not found") + // TODO: there is currency problem + ret := StepsStruct[step.Use] + if err := json.Unmarshal([]byte(step.In), ret); err != nil { + return nil, err + } + return ret, nil } type Documentation struct { @@ -105,50 +89,21 @@ type StepParameter struct { In []Documentation `json:"in"` } -func GetLocalStepDefinition(name string) *StepsInfo { - if _, ok := LocalStepsInfoMap[name]; !ok { - return nil - } - paraInDoc := GenerateDocumentation(LocalStepsStruct[name]) - ret := LocalStepsInfoMap[name] - ret.Parameters.In = paraInDoc - return &ret -} - -func GetRemoteStepDefinition(name string) *StepsInfo { - if _, ok := RemoteStepsInfoMap[name]; !ok { +func GetStepDefinition(name string) *StepsInfo { + if _, ok := StepsInfoMap[name]; !ok { return nil } - paraInDoc := GenerateDocumentation(RemoteStepsStruct[name]) - ret := RemoteStepsInfoMap[name] + paraInDoc := GenerateDocumentation(StepsStruct[name]) + ret := StepsInfoMap[name] ret.Parameters.In = paraInDoc return &ret } -func GetDNSStepDefinition(name string) *StepsInfo { - if _, ok := DNSStepsInfoMap[name]; !ok { - return nil - } - ret := DNSStepsInfoMap[name] - return &ret -} - -func ListLocalStepDefinitions() []StepsInfo { - ret := []StepsInfo{} - for name := range LocalStepsInfoMap { - paraInDoc := GenerateDocumentation(LocalStepsStruct[name]) - ele := LocalStepsInfoMap[name] - ele.Parameters.In = paraInDoc - ret = append(ret, ele) - } - return ret -} - -func ListRemoteStepDefinitions() []StepsInfo { +func ListStepDefinitions() []StepsInfo { ret := []StepsInfo{} - for name := range RemoteStepsInfoMap { - paraInDoc := GenerateDocumentation(RemoteStepsStruct[name]) - ele := RemoteStepsInfoMap[name] + for name := range StepsInfoMap { + paraInDoc := GenerateDocumentation(StepsStruct[name]) + ele := StepsInfoMap[name] ele.Parameters.In = paraInDoc ret = append(ret, ele) } diff --git a/pkg/server/handler.go b/pkg/server/handler.go index 2820503..a554eaf 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -28,52 +28,26 @@ import ( "opennaslab.io/bifrost/pkg/database" ) -func ListLocalStepsHandler(ctx *gin.Context) { - steps := customapi.ListLocalStepDefinitions() +func ListStepsHandler(ctx *gin.Context) { + steps := customapi.ListStepDefinitions() respData, err := json.Marshal(steps) if err != nil { - klog.Errorf("Marshal local steps failed:%v", err) + klog.Errorf("Marshal steps failed:%v", err) ctx.AbortWithError(http.StatusInternalServerError, err) return } ctx.Data(http.StatusOK, "application/json", respData) } -func ListRemoteStepsHandler(ctx *gin.Context) { - steps := customapi.ListRemoteStepDefinitions() - respData, err := json.Marshal(steps) - if err != nil { - klog.Errorf("Marshal remote steps failed:%v", err) - ctx.AbortWithError(http.StatusInternalServerError, err) - return - } - ctx.Data(http.StatusOK, "application/json", respData) -} - -func GetLocalStepHandler(ctx *gin.Context) { - name := ctx.Param("name") - step := customapi.GetLocalStepDefinition(name) - if step == nil { - ctx.AbortWithStatus(http.StatusNotFound) - } - respData, err := json.Marshal(step) - if err != nil { - klog.Errorf("Marshal local steps failed:%v", err) - ctx.AbortWithError(http.StatusInternalServerError, err) - return - } - ctx.Data(http.StatusOK, "application/json", respData) -} - -func GetRemoteStepHandler(ctx *gin.Context) { +func GetStepHandler(ctx *gin.Context) { name := ctx.Param("name") - step := customapi.GetRemoteStepDefinition(name) + step := customapi.GetStepDefinition(name) if step == nil { ctx.AbortWithStatus(http.StatusNotFound) } respData, err := json.Marshal(step) if err != nil { - klog.Errorf("Marshal remote steps failed:%v", err) + klog.Errorf("Marshal steps failed:%v", err) ctx.AbortWithError(http.StatusInternalServerError, err) return } @@ -83,30 +57,18 @@ func GetRemoteStepHandler(ctx *gin.Context) { func CreateOrUpdateWorkflowHandler(ctx *gin.Context) { workflow := &api.ConfigurationWorkflow{} ctx.BindJSON(workflow) - err := validateSteps(api.LocalStepType, workflow.LocalConfigurationSteps) - if err != nil { - klog.Errorf("Validate local steps failed:%v", err) - ctx.AbortWithError(http.StatusBadRequest, err) - return - } - err = validateSteps(api.RemoteStepType, workflow.RemoteConfigurationSteps) - if err != nil { - klog.Errorf("Validate remote steps failed:%v", err) - ctx.AbortWithError(http.StatusBadRequest, err) - return - } - err = validateSteps(api.DNSStepType, workflow.DNSConfigurationSteps) + err := validateSteps(workflow.ConfigurationSteps) if err != nil { - klog.Errorf("Validate dns steps failed:%v", err) + klog.Errorf("Validate steps failed:%v", err) ctx.AbortWithError(http.StatusBadRequest, err) return } ctx.Data(http.StatusOK, "application/json", []byte("OK")) } -func validateSteps(stepType string, steps []api.ConfigurationStep) error { +func validateSteps(steps []api.ConfigurationStep) error { for _, step := range steps { - typedStep, err := customapi.GetTypedConfig(stepType, &step) + typedStep, err := customapi.GetTypedConfig(&step) if err != nil { klog.Errorf("Get local step %s failed:%v", step.Use, err) return err diff --git a/pkg/server/router.go b/pkg/server/router.go index 8044d1f..5d9765f 100644 --- a/pkg/server/router.go +++ b/pkg/server/router.go @@ -36,15 +36,10 @@ func NewServerRouter() *gin.Engine { } func initStepRouter(router *gin.Engine, corsHandler gin.HandlerFunc) { - localStepGroup := router.Group("/api/v1/localsteps") - localStepGroup.GET("", ListLocalStepsHandler) + localStepGroup := router.Group("/api/v1/steps") + localStepGroup.GET("", ListStepsHandler) // Get specific step - localStepGroup.GET("/:name", GetLocalStepHandler) - - remoteStep := router.Group("/api/v1/remotesteps") - remoteStep.GET("", ListRemoteStepsHandler) - // Get specific step - remoteStep.GET("/:name", GetRemoteStepHandler) + localStepGroup.GET("/:name", GetStepHandler) } func initWorkflowRouter(router *gin.Engine, corsHandler gin.HandlerFunc) {