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: custom deploy addon support cluster addon and can select version #6446

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
9 changes: 8 additions & 1 deletion apistructs/addon.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ const (
// AddonConfigCenterAlias terminus-configcenter alias name
AddonConfigCenterAlias = "configcenter"
// AddonNewConfigCenter configcenter
AddonNewConfigCenter = "configcenter"
AddonNewConfigCenter = "config-center"
//AddonTerminusRoost 注册中心
AddonTerminusRoost = "terminus-roost"
// AddonMicroService micro-service
Expand All @@ -329,6 +329,13 @@ const (
AddonSourcecov = "sourcecov"

OriginalReplicas = "original_replicas"

// registercenter
AddonRegisterCenter = "registercenter"
// mse-nacos
AddonMSENacos = "mse-nacos"
// custom
AddonCustom = "custom"
)

// AddonRes addon信息
Expand Down
2 changes: 2 additions & 0 deletions cmd/orchestrator/conf/i18n/orchestrator-log-trans.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ zh:
AddonPlanIllegal: "Addon %s 规格不合法, Basic 规格 Addon 无法在生产环境使用"
AddonFormatIllegal: "Addon %s 格式不合法, 请检查 dice.yml 中 addon 部分是否正确"
AddonDeprecated: "Addon %s 当前版本:%v 已被废弃,请在dice.yml中重新配置"
ClusterAddonRedeploy: "Addon %s 在集群中存在,请选择部署 %v 版本,来进行关联,您当前部署的版本为:%v"

en:
WaitingForAddonTimeOut: "Waiting for the addon (%s)(%s) to be healthy timeout (%d min)"
Expand All @@ -45,3 +46,4 @@ en:
AddonPlanIllegal: "Addon %s plan is illegal, Basic plan addon cannot be used in production environment"
AddonFormatIllegal: "Addon %s format is illegal, please check the dice.yml addon section"
AddonDeprecated: "Addon %s current version: %v deprecated, please reconfigure in dice.yml"
ClusterAddonRedeploy: "Addon %s is existing, please select version: %v to link, your deploy version is %v"
2 changes: 2 additions & 0 deletions internal/tools/orchestrator/endpoints/addon.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func (e *Endpoints) CreateAddonDirectly(ctx context.Context, r *http.Request, va
// return apierrors.ErrCreateAddon.AccessDenied().ToResp(), nil
// }
// }
e.bindingDeploy(&addonCreateReq)

addonid, err := e.addon.AddonCreate(addonCreateReq)
if err != nil {
return apierrors.ErrCreateAddon.InternalError(err).ToResp(), nil
Expand Down
66 changes: 66 additions & 0 deletions internal/tools/orchestrator/endpoints/addon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
package endpoints

import (
"context"
"math/rand"
"net/http"
"reflect"
"strings"
"sync"
"testing"

Expand Down Expand Up @@ -212,3 +215,66 @@ func TestConcurrentReadWriteProjectInfos(t *testing.T) {
assert.Equal(t, true, ok)
}
}

func TestCreateAddonDirectly(t *testing.T) {
e := Endpoints{}

for _, test := range []struct {
payload string
orgid string
userid string
}{
{
payload: `{
"addons": {
"registercenter": {
"plan": "registercenter:basic",
"options": {
"version": "2.0.0"
}
}
},
"workspace": "TEST",
"shareScope": "PROJECT",
"projectId": 88888,
"clusterName": "test"
}`,
orgid: "666",
userid: "666",
},

{
payload: `{
"addons": {
"config-center": {
"plan": "config-center:basic",
"options": {
"version": "2.0.0"
}
}
},
"workspace": "TEST",
"shareScope": "PROJECT",
"projectId": 88888,
"clusterName": "test"
}`,
orgid: "666",
userid: "666",
},
} {
payload := strings.NewReader(test.payload)
req, err := http.NewRequest("", "", payload)
if err != nil {
t.Fatal(err)
}
req.Header.Add("org-id", test.orgid)
req.Header.Add("USER-ID", test.userid)

monkey.PatchInstanceMethod(reflect.TypeOf(e.addon), "AddonCreate", func(a *addon.Addon, req apistructs.AddonDirectCreateRequest) ([]string, error) {
return []string{"test success!"}, nil
})

_, _ = e.CreateAddonDirectly(context.Background(), req, nil)
}

}
34 changes: 34 additions & 0 deletions internal/tools/orchestrator/endpoints/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ package endpoints

import (
"context"
"fmt"
"net/http"
"strconv"
"strings"
"time"

"github.com/pkg/errors"
Expand All @@ -27,6 +29,7 @@ import (
"golang.org/x/text/message"

"github.com/erda-project/erda-proto-go/core/dicehub/release/pb"
"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/bundle"
"github.com/erda-project/erda/internal/tools/orchestrator/dbclient"
"github.com/erda-project/erda/internal/tools/orchestrator/events"
Expand All @@ -44,6 +47,7 @@ import (
"github.com/erda-project/erda/pkg/crypto/encryption"
"github.com/erda-project/erda/pkg/goroutinepool"
"github.com/erda-project/erda/pkg/http/httpserver"
"github.com/erda-project/erda/pkg/parser/diceyml"
"github.com/erda-project/erda/pkg/strutil"
)

Expand Down Expand Up @@ -507,3 +511,33 @@ func (e *Endpoints) FullGCLoop(ctx context.Context) {
}
}
}

func (e *Endpoints) inspectAddonVersions(addOns diceyml.AddOns) (versions map[string]string) {
versions = make(map[string]string)
for _, addOn := range addOns {
addonInfo := strings.SplitN(addOn.Plan, ":", 2)
versions[addonInfo[0]] = addOn.Options["version"]
}
return
}

func (e *Endpoints) bindingDeploy(req *apistructs.AddonDirectCreateRequest) {
versions := e.inspectAddonVersions(req.Addons)
registerVersion, hasR := versions[apistructs.AddonRegisterCenter]
configVersion, hasC := versions[apistructs.AddonNewConfigCenter]
if hasR && !hasC {
e.appendAddon(req, apistructs.AddonNewConfigCenter, registerVersion)
} else if !hasR && hasC {
e.appendAddon(req, apistructs.AddonRegisterCenter, configVersion)
}
}

func (e *Endpoints) appendAddon(req *apistructs.AddonDirectCreateRequest, addonType string, version string) {
name := addonType + strutil.RandStr(5)
req.Addons[name] = &diceyml.AddOn{
Plan: fmt.Sprintf("%s:%s", addonType, apistructs.AddonBasic),
Options: map[string]string{
"version": version,
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,6 @@ func updatePodAndInstance(dbclient *instanceinfo.Client, podlist *corev1.PodList
}
}
} else {
logrus.Infof("get [currentContainerID] from mainContainer")
currentTerminatedContainer := mainContainer.State.Terminated
if currentTerminatedContainer != nil {
if len(strings.Split(mainContainer.ContainerID, "://")) == 2 {
Expand Down
56 changes: 45 additions & 11 deletions internal/tools/orchestrator/services/addon/addon.go
Original file line number Diff line number Diff line change
Expand Up @@ -2633,13 +2633,32 @@
basic := locale.Get("basicPlan")
professional := locale.Get("professionalPlan")

createableAddons := []string{"api-gateway", "mysql", "canal", "monitor"}
createableAddonVersion := map[string]string{"api-gateway": "3.0.0", "mysql": "5.7.29", "canal": "1.1.0", "monitor": "3.6"}
createableAddons := []string{
apistructs.AddonApiGateway,
apistructs.AddonMySQL,
apistructs.AddonMonitor,
apistructs.AddonRegisterCenter,
apistructs.AddonNewConfigCenter,
}
// if these addon-type is `custom` and they can't be deployed by user, skip it!
unCreateAbleAddons := []string{
apistructs.AddonMSENacos, // mse-nacos only can be deployed by `config-center` or `register-center`
}
createableAddonVersion := map[string]string{
apistructs.AddonApiGateway: "3.0.0",
apistructs.AddonMySQL: "5.7.29",
apistructs.AddonCanal: "1.1.0",
apistructs.AddonMonitor: "3.6",
apistructs.AddonRegisterCenter: "3.0.0",
apistructs.AddonNewConfigCenter: "3.0.0",
}

Check warning on line 2654 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2636-L2654

Added lines #L2636 - L2654 were not covered by tests
createableAddonPlan := map[string][]map[string]string{
"api-gateway": {{"label": basic, "value": "api-gateway:basic"}},
"mysql": {{"label": basic, "value": "mysql:basic"}},
"canal": {{"label": basic, "value": "canal:basic"}},
"monitor": {{"label": professional, "value": "monitor:professional"}},
apistructs.AddonApiGateway: {{"label": basic, "value": "api-gateway:basic"}},
apistructs.AddonMySQL: {{"label": basic, "value": "mysql:basic"}},
apistructs.AddonCanal: {{"label": basic, "value": "canal:basic"}},
apistructs.AddonMonitor: {{"label": professional, "value": "monitor:professional"}},
apistructs.AddonRegisterCenter: {{"label": basic, "value": "registercenter:basic"}},
apistructs.AddonNewConfigCenter: {{"label": basic, "value": "config-center:basic"}},

Check warning on line 2661 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2656-L2661

Added lines #L2656 - L2661 were not covered by tests
}

// 构建请求参数,请求extension
Expand All @@ -2653,7 +2672,7 @@
}
extensionResult := make([]map[string]interface{}, 0, len(extensions))
for _, item := range extensions {
if item.Category != apistructs.AddonCustomCategory && !strutil.Exist(createableAddons, item.Name) {
if (item.Category != apistructs.AddonCustomCategory && !strutil.Exist(createableAddons, item.Name)) || strutil.Exist(unCreateAbleAddons, item.Name) {

Check warning on line 2675 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2675

Added line #L2675 was not covered by tests
continue
}
version := createableAddonVersion[item.Name]
Expand Down Expand Up @@ -2686,18 +2705,17 @@
addonMap["addonName"] = item.Name
addonMap["vars"] = addonSpec.ConfigVars
switch item.Name {
case "mysql", "api-gateway", "monitor":
case apistructs.AddonMySQL, apistructs.AddonApiGateway, apistructs.AddonMonitor, apistructs.AddonRegisterCenter, apistructs.AddonNewConfigCenter:

Check warning on line 2708 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2708

Added line #L2708 was not covered by tests
addonMap["vars"] = nil
case "canal":
case apistructs.AddonCanal:

Check warning on line 2710 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2710

Added line #L2710 was not covered by tests
addonMap["vars"] = []string{
"canal.instance.master.address",
"canal.instance.dbUsername",
"canal.instance.dbPassword",
"mysql"}
case "custom":
case apistructs.AddonCustom:

Check warning on line 2716 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2716

Added line #L2716 was not covered by tests
addonMap["vars"] = []string{}
}
addonMap["version"] = version
addonMap["plan"] = createableAddonPlan[item.Name]
// TODO: disable tenant support, we shall refactor later
//switch item.Name {
Expand All @@ -2707,6 +2725,22 @@
//default:
// addonMap["supportTenant"] = false
//}

versions := make([]string, 0, 1)
exts, err := a.bdl.QueryExtensionVersions(apistructs.ExtensionVersionQueryRequest{
Name: item.Name,
All: true,
})
if err != nil {
logrus.Errorf("query error: %v", err)
versions = append(versions, version)
} else {
for _, e := range exts {
versions = append(versions, e.Version)
}

Check warning on line 2740 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2728-L2740

Added lines #L2728 - L2740 were not covered by tests
}
addonMap["versions"] = versions

Check warning on line 2743 in internal/tools/orchestrator/services/addon/addon.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon.go#L2742-L2743

Added lines #L2742 - L2743 were not covered by tests
extensionResult = append(extensionResult, addonMap)
}
return &extensionResult, nil
Expand Down
76 changes: 48 additions & 28 deletions internal/tools/orchestrator/services/addon/addon_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
AddonDeprecated = "AddonDeprecated"
)

const I18nClusterAddonRedeploy = "ClusterAddonRedeploy"

// AttachAndCreate addon创建,runtime建立关系方法
func (a *Addon) AttachAndCreate(params *apistructs.AddonHandlerCreateItem) (*apistructs.AddonInstanceRes, error) {
// 获取addon extension信息
Expand Down Expand Up @@ -281,15 +283,12 @@
return nil
}

func (a *Addon) AddonCreate(req apistructs.AddonDirectCreateRequest) (string, error) {
if len(req.Addons) != 1 {
return "", fmt.Errorf("len(req.Addons) != 1")
}
baseAddons := []apistructs.AddonCreateItem{}
func (a *Addon) AddonCreate(req apistructs.AddonDirectCreateRequest) ([]string, error) {
var baseAddons []apistructs.AddonCreateItem
for name, a := range req.Addons {
plan := strings.SplitN(a.Plan, ":", 2)
if len(plan) != 2 {
return "", errors.Errorf("addon plan information is not compliant")
return nil, errors.Errorf("addon plan information is not compliant")

Check warning on line 291 in internal/tools/orchestrator/services/addon/addon_handler.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon_handler.go#L291

Added line #L291 was not covered by tests
}
baseAddons = append(baseAddons, apistructs.AddonCreateItem{
Name: name,
Expand All @@ -298,30 +297,42 @@
Options: a.Options,
})
}
addonItem := apistructs.AddonHandlerCreateItem{
InstanceName: baseAddons[0].Name,
AddonName: addonutil.TransAddonName(baseAddons[0].Type),
Plan: baseAddons[0].Plan,
ClusterName: req.ClusterName,
Workspace: strutil.ToUpper(req.Workspace),
OrgID: strconv.FormatUint(req.OrgID, 10),
ProjectID: strconv.FormatUint(req.ProjectID, 10),
ApplicationID: strconv.FormatUint(req.ApplicationID, 10),
OperatorID: req.Operator,
InsideAddon: "N",
ShareScope: req.ShareScope,
Options: baseAddons[0].Options,
}
addonSpec, addonDice, err := a.GetAddonExtention(&addonItem)
if err != nil {
logrus.Errorf("failed to GetAddonExtention err: %v", err)
return "", err
}

if err := a.checkAddonDeployable(addonItem, addonSpec); err != nil {
return "", err
routingIds := make([]string, 0, len(baseAddons))

for i := range baseAddons {
addonItem := apistructs.AddonHandlerCreateItem{
InstanceName: baseAddons[i].Name,
AddonName: addonutil.TransAddonName(baseAddons[i].Type),
Plan: baseAddons[i].Plan,
ClusterName: req.ClusterName,
Workspace: strutil.ToUpper(req.Workspace),
OrgID: strconv.FormatUint(req.OrgID, 10),
ProjectID: strconv.FormatUint(req.ProjectID, 10),
ApplicationID: strconv.FormatUint(req.ApplicationID, 10),
OperatorID: req.Operator,
InsideAddon: "N",
ShareScope: req.ShareScope,
Options: baseAddons[i].Options,
}
addonSpec, addonDice, err := a.GetAddonExtention(&addonItem)
if err != nil {
logrus.Errorf("failed to GetAddonExtention err: %v", err)
return nil, err
}

if err := a.checkAddonDeployable(addonItem, addonSpec); err != nil {
logrus.Errorf("%s", err)
return nil, err
}

Check warning on line 327 in internal/tools/orchestrator/services/addon/addon_handler.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon_handler.go#L324-L327

Added lines #L324 - L327 were not covered by tests

id, err := a.addonCreateAux(addonSpec, addonDice, &addonItem)
if err != nil {
return nil, err
}
routingIds = append(routingIds, id)

Check warning on line 333 in internal/tools/orchestrator/services/addon/addon_handler.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon_handler.go#L329-L333

Added lines #L329 - L333 were not covered by tests
}
return a.addonCreateAux(addonSpec, addonDice, &addonItem)
return routingIds, nil

Check warning on line 335 in internal/tools/orchestrator/services/addon/addon_handler.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon_handler.go#L335

Added line #L335 was not covered by tests
}

// checkAddonDeployable 检查 addon 是否能部署
Expand All @@ -335,6 +346,15 @@
return fmt.Errorf("[project(%s)/workspace(%s)] 已存在 microservice(%s), 无法再新建",
addon.ProjectID, addon.Workspace, addon.AddonName)
}
instance, err := a.db.GetAddonInstanceByNameAndCluster(addon.AddonName, addon.ClusterName)
if err != nil {
logrus.Errorf("%v", err)
return errors.New("failed to get addon instance from database")
}
if instance != nil && (addon.Options == nil || instance.Version != addon.Options["version"]) {
return errors.New(i18n.OrgSprintf(addon.OrgID, I18nClusterAddonRedeploy, addon.AddonName, instance.Version, addon.Options["version"]))
}
logrus.Infof("no deployed %s addon found", addon.AddonName)

Check warning on line 357 in internal/tools/orchestrator/services/addon/addon_handler.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/orchestrator/services/addon/addon_handler.go#L349-L357

Added lines #L349 - L357 were not covered by tests
}

switch strutil.ToLower(addon.AddonName) {
Expand Down
Loading