JCC-CSScheduler/executor/internal/task/create_ecs/sugoncloud.go

289 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package create_ecs
import (
"fmt"
"io"
"strings"
"sync"
"time"
"gitlink.org.cn/cloudream/common/pkgs/logger"
schsdk "gitlink.org.cn/cloudream/common/sdks/scheduler"
"gitlink.org.cn/cloudream/common/utils/http2"
"gitlink.org.cn/cloudream/common/utils/serder"
exemq "gitlink.org.cn/cloudream/scheduler/common/pkgs/mq/executor"
)
type response[T any] struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data T `json:"data"`
}
type sugonToken struct {
ClusterId string `json:"clusterId"`
ClusterName string `json:"clusterName"`
Token string `json:"token"`
}
type sugonTokenResp struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data []sugonToken `json:"data"`
}
func getToken(authConfigs map[string]interface{}) (string, error) {
header := make(map[string]string)
header["User"] = authConfigs["user"].(string)
header["Password"] = authConfigs["password"].(string)
header["Orgid"] = authConfigs["orgid"].(string)
resp, err := http2.PostJSON(authConfigs["get_token_url"].(string), http2.RequestParam{
Header: header,
})
if err != nil {
return "", err
}
contType := resp.Header.Get("Content-Type")
if strings.Contains(contType, http2.ContentTypeJSON) {
var codeResp sugonTokenResp
if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil {
return "", fmt.Errorf("parsing response: %w", err)
}
for i := 0; i < len(codeResp.Data); i++ {
data := codeResp.Data[i]
if data.ClusterName == authConfigs["clusterName"] {
return data.Token, nil
}
}
}
return "", fmt.Errorf("there is no token")
}
type sugonUrlResp struct {
Name string `json:"name"`
AiUrls []sugonUrl `json:"aiUrls"`
EfileUrls []sugonUrl `json:"efileUrls"`
}
type sugonUrl struct {
Url string `json:"url"`
}
func getUrl(token string, url string) (string, string, error) {
header := make(map[string]string)
header["Token"] = token
resp, err := http2.GetForm(url, http2.RequestParam{
Header: header,
})
if err != nil {
return "", "", err
}
// 读取并打印原始响应
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", "", fmt.Errorf("reading response body: %w", err)
}
contType := resp.Header.Get("Content-Type")
if strings.Contains(contType, http2.ContentTypeJSON) {
var codeResp response[sugonUrlResp]
if err := serder.JSONToObject(bodyBytes, &codeResp); err != nil {
return "", "", fmt.Errorf("parsing response: %w", err)
}
if len(codeResp.Data.AiUrls) == 0 {
return "", "", fmt.Errorf("there is no url")
}
return codeResp.Data.AiUrls[0].Url, codeResp.Data.EfileUrls[0].Url, nil
}
return "", "", fmt.Errorf("there is no token")
}
type SugonCloud struct {
Lock sync.Mutex
}
var ecsConfig map[string]interface{}
var authConfig map[string]interface{}
var instanceKV map[string]string
var sugonClient exemq.HttpClient
var efileClient exemq.HttpClient
func SugonCloudConfig(authConfigs map[string]interface{}, ecsConfigs map[string]interface{}) {
authConfigs["get_token_url"] = "https://ac.sugon.com/ac/openapi/v2/tokens"
authConfig = authConfigs
ecsConfig = ecsConfigs
instanceKV = make(map[string]string)
// 获取token
token, err := getToken(authConfigs)
if err != nil {
logger.Error(err.Error())
return
}
// 获取请求链接
url, efileUrl, err := getUrl(token, "https://ac.sugon.com/ac/openapi/v2/center")
httpPool := exemq.NewHttpPool(&exemq.Config{})
c, err := httpPool.AcquireByUrl(url)
if err != nil {
logger.Error(err.Error())
return
}
sugonClient = *c
ec, err := httpPool.AcquireByUrl(efileUrl)
if err != nil {
logger.Error(err.Error())
return
}
efileClient = *ec
}
func (s *SugonCloud) CreateServer() (string, string, error) {
instanceServiceName := "auto_instance_" + time.Now().Format("20060102150405")
ecsConfig["instanceServiceName"] = instanceServiceName
// 获取token
token, err := getToken(authConfig)
if err != nil {
logger.Error(err.Error())
return "", "", err
}
// 创建实例
_, err = sugonClient.CreateSugonInstance(token, ecsConfig)
if err != nil {
return "", "", err
}
// 获取实例ID4*1000s后还未获取ID则认为实例创建失败
var instanceID string
for i := 0; i <= 1000; i++ {
id, status, err := sugonClient.GetInstanceID(token, instanceServiceName)
if status == schsdk.Failed {
return "", "", fmt.Errorf("create instance failed")
}
if err != nil || status == schsdk.Waiting || status == schsdk.Deploying {
time.Sleep(4 * time.Second)
continue
}
if i == 1000 {
return "", "", fmt.Errorf("get instance id timeout")
}
instanceID = id
break
}
if instanceID == "" {
return "", "", fmt.Errorf("get instance id failed")
}
// 获取实例url
url, err := sugonClient.GetInstanceUrl(token, instanceID)
logger.Info("create ecs success, instanceID: " + instanceID + " url: " + url)
instanceKV[instanceID] = instanceServiceName
return instanceID, url, nil
}
func (s *SugonCloud) RunCommand(commands []string, instanceID string, timeout int) (string, error) {
s.Lock.Lock()
defer s.Lock.Unlock()
// 获取token
token, err := getToken(authConfig)
if err != nil {
logger.Error(err.Error())
return "", err
}
for i := 0; i < len(commands); i++ {
// 曙光集群不支持查看日志,通过预览日志文件返回
if timeout == -1 && i == len(commands)-1 {
// 命令执行完成需要时间,但是接口不会等待完成后才返回,所以这里需要轮询看是否有结果
content := ""
for j := 0; j < 10; j++ {
content, err = efileClient.PreviewFile(token, commands[i])
if err != nil {
return "", err
}
if content == "" {
time.Sleep(3 * time.Second)
continue
}
break
}
return content, err
}
_, err := sugonClient.RunCommand(token, instanceID, commands[i])
if err != nil {
return "", err
}
}
return "", err
}
func (s *SugonCloud) DeleteInstance(instanceID string) (string, error) {
// 获取token
token, err := getToken(authConfig)
if err != nil {
logger.Error(err.Error())
return "", err
}
instance, err := sugonClient.OperateSugonInstance(token, instanceID, schsdk.DestroyECS)
return instance, err
}
func (s *SugonCloud) StopInstance(instanceID string) (string, error) {
// 获取token
token, err := getToken(authConfig)
if err != nil {
logger.Error(err.Error())
return "", err
}
instance, err := sugonClient.OperateSugonInstance(token, instanceID, schsdk.PauseECS)
return instance, err
}
func (s *SugonCloud) RebootInstances(instanceID string) (string, error) {
//TODO implement me
panic("implement me")
}
func (s *SugonCloud) StartInstances(instanceID string) (string, error) {
// 获取token
token, err := getToken(authConfig)
if err != nil {
logger.Error(err.Error())
return "", err
}
instance, err := sugonClient.OperateSugonInstance(token, instanceID, schsdk.RunECS)
return instance, err
}
func (s *SugonCloud) AvailableCheck(instanceID string) bool {
instanceName, ok := instanceKV[instanceID]
if !ok {
return false
}
token, _ := getToken(authConfig)
instanceID, _, err := sugonClient.GetInstanceID(token, instanceName)
if err != nil || instanceID == "" {
logger.Error(err.Error())
return false
}
return true
}