cmdb

command module
v0.0.0-...-f5108b3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 8, 2024 License: MIT Imports: 11 Imported by: 0

README

CMDB

同步腾讯云的CVM

  • 常见的CMDB设计模式
  • 类云管CMDB设计方案与流程
  • 资源管理模块开发
  • 云商凭证管理模块开发

CMDB需求介绍

prd

常见的CMDB设计模式

model_base

nosql_base

CMDB模块划分与业务流程设计

flow

资源管理模块

  1. 接口的定义
    1. Save
    2. Search
  2. 业务控制器的实现(GRPC)
    1. mongodb insertone
    2. mongodb find
  3. gorestful 的 api接口
    1. search
    2. swagger 文档
  4. 完成模块加载并启动

资源同步器开发

资源同步器接口定义

统一各个云厂商对资源定义的差异

type ResourceProvider interface {
	// 资源同步, 1000 ECS, Stream 接口
	// SyncRequest 请求同步的参数 Region
	// ResourceHandler 处理完一个就交给Handler一个
	Sync(context.Context, *SyncRequest, *ResourceHandler) error
}
腾讯云资源同步器
  1. 准备一个腾讯云账号
  2. 云商API文档与SDK文档的使用
    • API Explorer 使用这个浏览并请求 腾讯云API
package main

import (
        "fmt"

        "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
        "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
        "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
        cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)

func main() {
        // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
        // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
        // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
        credential := common.NewCredential(
                "SecretId",
                "SecretKey",
        )
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        cpf := profile.NewClientProfile()
        cpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com"
        // 实例化要请求产品的client对象,clientProfile是可选的
        client, _ := cvm.NewClient(credential, "", cpf)

        // 实例化一个请求对象,每个接口都会对应一个request对象
        request := cvm.NewDescribeInstancesRequest()
        
        // 返回的resp是一个DescribeInstancesResponse的实例,与请求对象对应
        response, err := client.DescribeInstances(request)
        if _, ok := err.(*errors.TencentCloudSDKError); ok {
                fmt.Printf("An API error has returned: %s", err)
                return
        }
        if err != nil {
                panic(err)
        }
        // 输出json格式的字符串回包
        fmt.Printf("%s", response.ToJsonString())
} 
  1. 腾讯云CVM SDK 测试
  • 需要创建一个CVM
  • 开发腾讯云CVM资源同步器(provider)
  • 云商账号管理模块功能开发(secret)
  • 云商账号资源同步功能开发(secret sync resource)
流式API: websocket使用

服务端实现:

// 使用云商账号凭证 来实现资源同步
// 我们有多个返回, 需要使用 websocket 来 把当前的 http链接 升降成 websocket协议(tcp封装)
func (h *handler) SyncResource(r *restful.Request, w *restful.Response) {
	// w http.ResponseWriter 浏览器处理不了 之定义header
	socket, err := h.Upgrader().Upgrade(w, r.Request, nil)
	if err != nil {
		response.Failed(w, err)
	}
	defer socket.Close()

	req := &secret.SyncResourceRequest{}
	h.controller.SyncResource(r.Request.Context(), req, func(sr *secret.SyncResponse) {
		err := socket.WriteJSON(sr)
		if err != nil {
			h.log.Error().Msgf("websocket write error, %s", err)
		}
	})
}

使用客户端测试(Web)

// websocket链接
const connect = () => {
        // 建立websocket链接
        let socket = new WebSocket(`ws://127.0.0.1:8020/cmdb/api/v1/secret/ws/cllfqm5mjd0ku666k150/sync_resource`);
        socket.onopen = function (e) {
        console.log('socket open')
        console.log(e)
        };
        socket.onmessage = function (event) {
        // server 发送给terminal的数据
        console.log(event)
        term.write(event.data)
        };
        socket.onclose = function (event) {
        if (event.wasClean) {
                term.write(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
        } else {
                // e.g. server process killed or network down
                // event.code is usually 1006 in this case
                term.write('[close] Connection died');
        }
        };
        socket.onerror = function (error) {
        term.write(`[error]`);
        };
}
编写mock模块
// 使用云商凭证同步资源 Stream
func (i *impl) SyncResource(
	ctx context.Context,
	in *secret.SyncResourceRequest,
	hook secret.SyncResourceHandler) error {

	for i := 1; i < 51; i++ {
		hook(&secret.SyncResponse{
			Id:   fmt.Sprintf("cvm%d", i),
			Name: fmt.Sprintf("cvm%d", i),
		})
		time.Sleep(1 * time.Second)
	}

	return nil
}
// _ "gitee.com/go-course/go12/devcloud-mini/cmdb/apps/secret/mock"
_ "gitee.com/go-course/go12/devcloud-mini/cmdb/apps/secret/impl"
关于敏感信息存储加密
// IbkhUeQczqSMgEvQI1avP5e4fG1XMG1FpsOWfvYoF5Y=
// h4TU/S8lMOUyx20ZJEwX8p6w8eD1/03V17l0QsnIKIs=
func TestEncrypt(t *testing.T) {
	s := secret.NewSecret(secret.NewCreateSecretRequest())
	s.Spec.Value = "123456"
	if err := s.Encrypt("test"); err != nil {
		t.Fatal(err)
	}
	t.Log(s)
	if err := s.Decrypt("test"); err != nil {
		t.Fatal(err)
	}
	t.Log(s)
}

脱敏:

GET /cmdb/api/v1/secret/clpu14tmjd0jgd01qnb0 HTTP/1.1
Host: 127.0.0.1:8020
Authorization: Bearer EBB4TpK6dbR5CUsyCSnPFYdD
Content-Type: application/json
Content-Length: 81

{
    "id": "clpu14tmjd0jgd01qnb0",
    "domain": "",
    "namespace": "",
    "spec": {
        "type": 0,
        "key": "AKIDGYjokXBg3F5pOm4BA4oNm14zmR7i7OXX",
        "value": "a0IU*****",
        "regions": [
            "ap-nanjing"
        ],
        "resource_types": [
            0
        ]
    }
}
关于同步任务的执行设计

可以参考: go cron

接入Trace(Opentelemetry)

安装Jaeger服务
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-e COLLECTOR_OTLP_ENABLED=true \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \

UI界面: http://localhost:16686/search

初始化Tracer, 使用Jaeger作为后端
type Config struct {
	Provider TRACE_PROVIDER `toml:"provider" json:"provider" yaml:"provider" env:"TRACE_PROVIDER"`
	Endpoint string         `toml:"endpoint" json:"endpoint" yaml:"endpoint" env:"TRACE_PROVIDER_ENDPOINT"`
	Enabled  bool           `toml:"enabled" json:"enabled" yaml:"enabled" env:"TRACE_ENABLED"`

	ioc.ObjectImpl
}

func (t *Config) Init() error {
	ep := t.Endpoint

	if ep == "" || !t.Enabled {
		return nil
	}

	exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(ep)))
	if err != nil {
		return err
	}

	tp := sdktrace.NewTracerProvider(
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(resource.Default()),
	)
	otel.SetTracerProvider(tp)
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.Baggage{}, propagation.TraceContext{}))
	return nil
}

通过下面的配置开启

[trace]
enabled = true
endpoint = "http://localhost:14268/api/traces"
通过 ioc 开启trace
[app]
name = "cmdb"
key  = "this is your app key"

[app.http]
web_framework = "go-restful"
host = "127.0.0.1"
port = 8020
enable_api_doc = true
api_doc_path="/swagger_docs"
enable_trace=true

[app.grpc]
host = "127.0.0.1"
port = 18020
enable_trace=true

[mongodb]
endpoints = ["127.0.0.1:27017"]
username = "admin"
password = "123456"
database = "cmdb"
enable_trace=true

[mcenter]
address = "127.0.0.1:18010"
client_id = "Z6OB8gLvF62VKEadAks6Gw1s"
client_secret = "jJPW5qeYLr0qS5Wvb3cqzrSeqmWaHmf7"

[log]
level = "debug"

[log.file]
enable = true
file_path = "logs/cmdb.log"

[trace]
enabled = true
endpoint = "http://localhost:14268/api/traces"
启动服务

导入trace配置

_ "github.com/infraboard/mcube/ioc/config/trace"
  • cmdb 开启完Trace
  • mcenter 已要开启trace
GET /cmdb/api/v1/secret/clpu14tmjd0jgd01qnb0 HTTP/1.1
Host: 127.0.0.1:8020
Authorization: Bearer mJRdh9W2DDNs9T7oDpz4OOC4

埋点
// 埋点,添加自定义trace
// 全局providre, ioc SetTracerProvider 已经设置好了 全局provider
p := otel.GetTracerProvider()
_, span := p.Tracer("cmdb").Start(r.Request.Context(), "ListSecret",
    oteltrace.WithAttributes(attribute.String("username", "admin")),
)
defer span.End()

// ctx 需要继续往后传递(这个context里面包含 trace id)
// 因为没有后续逻辑 这里丢弃了context

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL