Skip to content

Commit

Permalink
feat: addon support influxdb (#6468)
Browse files Browse the repository at this point in the history
* feat: addon support influxdb

Signed-off-by: Ash <root@viper.run>

* add influxdb unit test

Signed-off-by: Ash <root@viper.run>

* re go mod tidy

Signed-off-by: Ash <root@viper.run>

* ugprade agiledragon/gomonkey to v2

Signed-off-by: Ash <root@viper.run>

* remove unuse unit test

Signed-off-by: Ash <root@viper.run>

---------

Signed-off-by: Ash <root@viper.run>
  • Loading branch information
iutx authored Nov 20, 2024
1 parent ea8bf7e commit 12c9840
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 79 deletions.
2 changes: 2 additions & 0 deletions apistructs/addon.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ const (
AddonCloudGateway = "alicloud-gateway"
// sourcecov code coverage agent
AddonSourcecov = "sourcecov"
// influxdb
AddonInfluxDB = "influxdb"

OriginalReplicas = "original_replicas"

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/IBM/sarama v1.43.2
github.com/Masterminds/semver v1.5.0
github.com/WeiZhang555/tabwriter v0.0.0-20200115015932-e5c45f4da38d
github.com/agiledragon/gomonkey/v2 v2.12.0
github.com/ahmetb/go-linq/v3 v3.2.0
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38
github.com/alibabacloud-go/bailian-20230601 v1.0.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,8 @@ github.com/actgardner/gogen-avro/v10 v10.1.0/go.mod h1:o+ybmVjEa27AAr35FRqU98DJu
github.com/actgardner/gogen-avro/v10 v10.2.1/go.mod h1:QUhjeHPchheYmMDni/Nx7VB0RsT/ee8YIgGY/xpEQgQ=
github.com/actgardner/gogen-avro/v9 v9.1.0/go.mod h1:nyTj6wPqDJoxM3qdnjcLv+EnMDSDFqE0qDpva2QRmKc=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/agiledragon/gomonkey/v2 v2.12.0 h1:ek0dYu9K1rSV+TgkW5LvNNPRWyDZVIxGMCFI6Pz9o38=
github.com/agiledragon/gomonkey/v2 v2.12.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
github.com/agrison/go-tablib v0.0.0-20160310143025-4930582c22ee h1:0RklYSvekYaIFI9JUx7TFPQvo++TdILmZiV17QI4nXk=
github.com/agrison/go-tablib v0.0.0-20160310143025-4930582c22ee/go.mod h1:M9nmO4lBRWR/bBv7UCOmDJ1MB2DVoqz19B4JchDA+K0=
github.com/agrison/mxj v0.0.0-20160310142625-1269f8afb3b4 h1:XBNSe5eibe5Fh131ah+xnO6s4A97U1T3tKZKLQQvqu0=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,6 @@ func (k *Kubernetes) createStatefulSet(ctx context.Context, info types.Statefuls
}
//setEnv(container, info.envs, info.sg, info.namespace)

if info.Namespace == "fake-test" {
return nil
}

SetPodAnnotationsBaseContainerEnvs(set.Spec.Template.Spec.Containers[0], set.Spec.Template.Annotations)

return k.sts.Create(set)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ import (
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/k8sservice"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/namespace"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/persistentvolumeclaim"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/secret"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/statefulset"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/toleration"
"github.com/erda-project/erda/internal/tools/orchestrator/scheduler/executor/plugins/k8s/types"
"github.com/erda-project/erda/pkg/http/httpclient"
"github.com/erda-project/erda/pkg/parser/diceyml"
"github.com/erda-project/erda/pkg/strutil"
Expand Down Expand Up @@ -295,79 +293,6 @@ func TestParseJobSpecTemplate(t *testing.T) {
assert.Equal(t, clusterInfo["MOUNTPOINT_PATH"], newPath)
}

func TestCreateStatefulSet(t *testing.T) {
kubernetes := &Kubernetes{
secret: &secret.Secret{},
}

defer monkey.UnpatchAll()

monkey.PatchInstanceMethod(reflect.TypeOf(kubernetes.secret), "Get", func(sec *secret.Secret, namespace, name string) (*apiv1.Secret, error) {
b := []byte{}
return &apiv1.Secret{Data: map[string][]byte{".dockerconfigjson": b}}, nil
})

info := types.StatefulsetInfo{
Sg: &apistructs.ServiceGroup{
Dice: apistructs.Dice{
ID: "fake-test-dice",
Type: "addon",
Labels: nil,
Services: []apistructs.Service{
{
Name: "fake-test-service",
Namespace: "fake-test",
Image: "",
ImageUsername: "",
ImagePassword: "",
Cmd: "",
Ports: nil,
ProxyPorts: nil,
Vip: "",
ShortVIP: "",
ProxyIp: "",
PublicIp: "",
Scale: 0,
Resources: apistructs.Resources{
Cpu: 100,
Mem: 200,
Disk: 0,
},
Depends: nil,
Env: nil,
Labels: map[string]string{"ADDON_GROUP_ID": "11111111"},
DeploymentLabels: nil,
Selectors: nil,
Binds: nil,
Volumes: nil,
Hosts: nil,
HealthCheck: nil,
NewHealthCheck: nil,
SideCars: nil,
InitContainer: nil,
InstanceInfos: nil,
MeshEnable: nil,
TrafficSecurity: diceyml.TrafficSecurity{},
WorkLoad: "",
ProjectServiceName: "",
K8SSnippet: nil,
StatusDesc: apistructs.StatusDesc{},
},
},
ServiceDiscoveryKind: "",
ServiceDiscoveryMode: "",
ProjectNamespace: "",
},
},
Namespace: "fake-test",
Envs: map[string]string{},
Annotations: map[string]string{},
}

err := kubernetes.createStatefulSet(context.Background(), info)
assert.Nil(t, err)
}

func Test_scaleStatefulSet(t *testing.T) {
k := &Kubernetes{
sts: &statefulset.StatefulSet{},
Expand Down
4 changes: 4 additions & 0 deletions internal/tools/orchestrator/services/addon/addon_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ func (a *Addon) GetAddonResourceStatus(addonIns *dbclient.AddonInstance,
case apistructs.AddonSourcecov:
asm := &SourcecovAddonManagement{bdl: a.bdl, org: a.org}
configMap, err = asm.DeployStatus(addonIns, &serviceGroup)
case apistructs.AddonInfluxDB:
configMap, err = a.InfluxDBDeployStatus(addonIns, &serviceGroup)
default:
// 非基础addon,走通用的处理逻辑
configMap, err = a.CommonDeployStatus(addonIns, &serviceGroup, addonDice, addonSpec)
Expand Down Expand Up @@ -638,6 +640,8 @@ func (a *Addon) BuildAddonRequestGroup(params *apistructs.AddonHandlerCreateItem
}
sam := &SourcecovAddonManagement{bdl: a.bdl, org: a.org}
buildErr = sam.BuildSourceCovServiceItem(params, addonIns, addonSpec, addonDice, &clusterInfo)
case apistructs.AddonInfluxDB:
buildErr = a.BuildInfluxDBServiceItem(params, addonIns, addonSpec, addonDice)
default: //default case
buildErr = a.BuildCommonServiceItem(params, addonIns, addonSpec, addonDice, &clusterInfo)
}
Expand Down
176 changes: 176 additions & 0 deletions internal/tools/orchestrator/services/addon/addon_influxdb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright (c) 2021 Terminus, Inc.
//
// 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 applicable 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 addon

import (
"crypto/md5"
"fmt"
"strconv"
"strings"
"time"

"github.com/pkg/errors"

"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/internal/tools/orchestrator/dbclient"
"github.com/erda-project/erda/pkg/parser/diceyml"
)

const (
InfluxDBDataPath = "/var/lib/influxdb2"
InfluxDBConfHost = "INFLUX_HOST"
InfluxDBConfUser = "INFLUX_USERNAME"
InfluxDBConfPassword = "INFLUX_PASSWORD"
InfluxDBConfORG = "INFLUX_ORG"
InfluxDBServicePort = "8086"
)

const (
InfluxDBKMSPasswordKey = "influxdb-password"
)

const (
InfluxDBInitPrefix = "DOCKER_INFLUXDB_INIT_"

InfluxDBInitUserNameKey = InfluxDBInitPrefix + "USERNAME"
InfluxDBInitUserName = "influxdb"
InfluxDBInitPasswordKey = InfluxDBInitPrefix + "PASSWORD"

// InfluxDBInitModeKey default init mode: setup
InfluxDBInitModeKey = InfluxDBInitPrefix + "MODE"
InfluxDBInitMode = "setup"

// InfluxDBInitOrgKey erda project name -> influxdb org
InfluxDBInitOrgKey = InfluxDBInitPrefix + "ORG"

// InfluxDBInitBucketKey erda application name -> influxdb bucket
InfluxDBInitBucketKey = InfluxDBInitPrefix + "BUCKET"
InfluxDBInitBucket = "erda"

// InfluxDBInitRetentionKey default 1w
InfluxDBInitRetentionKey = InfluxDBInitPrefix + "RETENTION"
InfluxDBInitRetention = "1w"
)

const (
InfluxDBParamsOrg = "org"
InfluxDBParamsBucket = "bucket"
InfluxDBParamsRetention = "retention"
)

// BuildInfluxDBServiceItem build influxdb service item
func (a *Addon) BuildInfluxDBServiceItem(params *apistructs.AddonHandlerCreateItem, addonIns *dbclient.AddonInstance,
addonSpec *apistructs.AddonExtension, addonDice *diceyml.Object) error {
addonDeployPlan := addonSpec.Plan[params.Plan]
serviceMap := diceyml.Services{}

// InfluxDB support 1 node only now.
serviceItem := *addonDice.Services[addonSpec.Name]
serviceItem.Resources = diceyml.Resources{
CPU: addonDeployPlan.CPU,
MaxCPU: addonDeployPlan.MaxCPU,
Mem: addonDeployPlan.Mem,
MaxMem: addonDeployPlan.MaxMem,
}

// init config render
if err := a.influxDBInitRender(params, addonIns, serviceItem.Envs); err != nil {
return err
}

// label
if len(serviceItem.Labels) == 0 {
serviceItem.Labels = map[string]string{}
}
serviceItem.Labels["ADDON_GROUP_ID"] = addonSpec.Name
SetlabelsFromOptions(params.Options, serviceItem.Labels)
// binding data
vol := SetAddonVolumes(params.Options, InfluxDBDataPath, false)
serviceItem.Volumes = diceyml.Volumes{vol}

serviceMap[strings.Join([]string{addonSpec.Name, strconv.Itoa(0)}, "-")] = &serviceItem
addonDice.Services = serviceMap

return nil
}

func (a *Addon) InfluxDBDeployStatus(addonIns *dbclient.AddonInstance, serviceGroup *apistructs.ServiceGroup) (map[string]string, error) {
password, err := a.db.GetByInstanceIDAndField(addonIns.ID, InfluxDBKMSPasswordKey)
if err != nil {
return nil, err
}

configMap := map[string]string{}
if len(serviceGroup.Services) == 0 {
return nil, errors.New("service group is empty")
}
influxDBService := serviceGroup.Services[0]
configMap[InfluxDBConfHost] = fmt.Sprintf("http://%s:%s", influxDBService.Vip, InfluxDBServicePort)
configMap[InfluxDBConfUser] = InfluxDBInitUserName
configMap[InfluxDBConfORG] = genInfluxDBOrg(addonIns)
configMap[InfluxDBConfPassword] = password.Value

return configMap, nil
}

func (a *Addon) influxDBInitRender(params *apistructs.AddonHandlerCreateItem,
addonIns *dbclient.AddonInstance, serviceEnv diceyml.EnvMap) error {
// Init mode
serviceEnv[InfluxDBInitModeKey] = InfluxDBInitMode

// Username
serviceEnv[InfluxDBInitUserNameKey] = InfluxDBInitUserName

// Password
password, err := a.savePassword(addonIns, InfluxDBKMSPasswordKey)
if err != nil {
return err
}
serviceEnv[InfluxDBInitPasswordKey] = password

// Org
org := params.Options[InfluxDBParamsOrg]
if org == "" {
org = genInfluxDBOrg(addonIns)
}
serviceEnv[InfluxDBInitOrgKey] = org

// Bucket
bucket := params.Options[InfluxDBParamsBucket]
if bucket == "" {
bucket = InfluxDBInitBucket
}
serviceEnv[InfluxDBInitBucketKey] = bucket

// Retention
retention := params.Options[InfluxDBParamsRetention]
if retention == "" {
retention = InfluxDBInitRetention
} else {
_, err := time.ParseDuration(retention)
if err != nil {
return errors.Wrapf(err, "failed to parse retention time %s", retention)
}
}
serviceEnv[InfluxDBInitRetentionKey] = retention

return nil
}

func genInfluxDBOrg(addonIns *dbclient.AddonInstance) string {
// ORG_PROJECT_WORKSPACE
influxDBOrgSource := fmt.Sprintf("%s_%s_%s", addonIns.OrgID, addonIns.ProjectID, addonIns.Workspace)
return fmt.Sprintf("%x", md5.Sum([]byte(influxDBOrgSource)))
}
Loading

0 comments on commit 12c9840

Please sign in to comment.