alicloud/service_alicloud_edas.go (925 lines of code) (raw):
package alicloud
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/PaesslerAG/jsonpath"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/aliyun/alibaba-cloud-sdk-go/services/edas"
"github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)
type EdasService struct {
client *connectivity.AliyunClient
}
type Hook struct {
Exec *Exec `json:"exec,omitempty"`
HttpGet *HttpGet `json:"httpGet,omitempty"`
TcpSocket *TcpSocket `json:"tcpSocket,omitempty"`
}
type Exec struct {
Command []string `json:"command"`
}
type HttpGet struct {
Path string `json:"path"`
Port int `json:"port"`
Scheme string `json:"scheme"`
HttpHeaders []HttpHeader `json:"httpHeaders"`
}
type HttpHeader struct {
Name string `json:"name"`
Value string `json:"value"`
}
type TcpSocket struct {
Host string `json:"host"`
Port int `json:"port"`
}
type Prober struct {
FailureThreshold int `json:"failureThreshold"`
InitialDelaySeconds int `json:"initialDelaySeconds"`
SuccessThreshold int `json:"successThreshold"`
TimeoutSeconds int `json:"timeoutSeconds"`
Hook `json:",inline"`
}
const (
ChangeOrderStatusReady = "0"
ChangeOrderStatusRunning = "1"
ChangeOrderStatusSuccess = "2"
ChangeOrderStatusFailed = "3"
ChangeOrderStatusAbort = "6"
ChangeOrderStatusWaitBatchConfirm = "8"
ChangeOrderStatusAutoBatchWait = "9"
ChangeOrderStatusSystemFail = "10"
)
const (
ChangeOrderStatusReadyStr = "Ready"
ChangeOrderStatusRunningStr = "Running"
ChangeOrderStatusSuccessStr = "Success"
ChangeOrderStatusFailedStr = "Failed"
ChangeOrderStatusAbortStr = "Abort"
ChangeOrderStatusWaitBatchConfirmStr = "WaitBatchConfirm"
ChangeOrderStatusAutoBatchWaitStr = "AutoBatchWait"
ChangeOrderStatusSystemFailStr = "SystemFail"
)
var ChangeOrderStatusMap = map[int]string{
0: ChangeOrderStatusReadyStr,
1: ChangeOrderStatusRunningStr,
2: ChangeOrderStatusSuccessStr,
3: ChangeOrderStatusFailedStr,
6: ChangeOrderStatusAbortStr,
8: ChangeOrderStatusWaitBatchConfirmStr,
9: ChangeOrderStatusAutoBatchWaitStr,
10: ChangeOrderStatusSystemFailStr,
}
func (e *EdasService) GetChangeOrderStatus(id string) (info *edas.ChangeOrderInfo, err error) {
request := edas.CreateGetChangeOrderInfoRequest()
request.RegionId = e.client.RegionId
request.ChangeOrderId = id
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.GetChangeOrderInfo(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"OperationDenied.InvalidDBClusterIdNotFound", "OperationDenied.InvalidDBClusterNameNotFound"}) {
return info, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return info, WrapErrorf(err, DefaultErrorMsg, id, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
rsp := raw.(*edas.GetChangeOrderInfoResponse)
return &rsp.ChangeOrderInfo, nil
}
func (e *EdasService) GetChangeOrderStatusV2(id string) (int, error) {
if response, err := e.doPopRequest(map[string]string{
"action": "/pop/v5/changeorder/change_order_info",
"httpMethod": "POST",
"id": id,
}, map[string]string{
"ChangeOrderId": id,
}); err != nil {
return -1, err
} else {
if v, err := jsonpath.Get("$.changeOrderInfo.Status", response); err != nil {
return -1, err
} else {
return parseInt(v)
}
}
}
func (e *EdasService) GetDeployGroup(appId, groupId string) (groupInfo *edas.DeployGroup, err error) {
request := edas.CreateListDeployGroupRequest()
request.RegionId = e.client.RegionId
request.AppId = appId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.ListDeployGroup(request)
})
if err != nil {
return groupInfo, WrapErrorf(err, DefaultErrorMsg, appId, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
rsp := raw.(*edas.ListDeployGroupResponse)
if rsp.Code != 200 {
return groupInfo, Error("get deploy group failed for %s", rsp.Message)
}
for _, group := range rsp.DeployGroupList.DeployGroup {
if group.GroupId == groupId {
return &group, nil
}
}
return groupInfo, nil
}
func (e *EdasService) EdasChangeOrderStatusRefreshFunc(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
object, err := e.GetChangeOrderStatus(id)
if err != nil {
if NotFoundError(err) {
// Set this to nil as if we didn't find anything.
return nil, "", nil
}
return nil, "", WrapError(err)
}
for _, failState := range failStates {
if strconv.Itoa(object.Status) == failState {
return object, strconv.Itoa(object.Status), WrapError(Error(FailedToReachTargetStatus, strconv.Itoa(object.Status)))
}
}
return object, strconv.Itoa(object.Status), nil
}
}
func (e *EdasService) EdasChangeOrderStatusRefreshFuncV2(id string, failStates []string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
status, err := e.GetChangeOrderStatusV2(id)
if err != nil {
if NotFoundError(err) {
// Set this to nil as if we didn't find anything.
return nil, "", nil
}
return nil, "", WrapError(err)
}
statusStr := "not found"
if v, ok := ChangeOrderStatusMap[status]; ok {
statusStr = v
}
for _, failState := range failStates {
if statusStr == failState {
return nil, statusStr, WrapError(Error(FailedToReachTargetStatus, statusStr))
}
}
return status, statusStr, nil
}
}
func (e *EdasService) WaitForChangeOrderFinished(resourceId string, changeOrderId string, timeout time.Duration) error {
if len(changeOrderId) > 0 {
stateConf := BuildStateConf(
[]string{ChangeOrderStatusReadyStr, ChangeOrderStatusRunningStr},
[]string{ChangeOrderStatusSuccessStr},
timeout,
5*time.Second,
e.EdasChangeOrderStatusRefreshFuncV2(changeOrderId,
[]string{
ChangeOrderStatusFailedStr,
ChangeOrderStatusAbortStr,
ChangeOrderStatusSystemFailStr}))
if _, err := stateConf.WaitForState(); err != nil {
return WrapErrorf(err, IdMsg, resourceId)
}
}
return nil
}
func (e *EdasService) WaitForChangeOrderFinishedNonRetryable(resourceId string, changeOrderId string, timeout time.Duration) *resource.RetryError {
if len(changeOrderId) > 0 {
stateConf := BuildStateConf(
[]string{ChangeOrderStatusReadyStr, ChangeOrderStatusRunningStr},
[]string{ChangeOrderStatusSuccessStr},
timeout,
5*time.Second,
e.EdasChangeOrderStatusRefreshFuncV2(changeOrderId,
[]string{
ChangeOrderStatusFailedStr,
ChangeOrderStatusAbortStr,
ChangeOrderStatusSystemFailStr}))
if _, err := stateConf.WaitForState(); err != nil {
return resource.NonRetryableError(WrapErrorf(err, "change order failed, app id %s", resourceId))
}
}
return nil
}
func parseInt(obj interface{}) (int, error) {
if obj == nil {
return -1, fmt.Errorf("try to parse int, but got nil")
}
switch obj.(type) {
case string:
return strconv.Atoi(obj.(string))
case int:
return obj.(int), nil
case int32:
return int(obj.(int32)), nil
case int64:
return int(obj.(int64)), nil
case json.Number:
return strconv.Atoi(obj.(json.Number).String())
default:
return -1, fmt.Errorf("unknown type of object: %v", reflect.TypeOf(obj))
}
}
// HasOngoingTasks check if there is an ongoing task, ignore all api error, just return false
func (e *EdasService) HasOngoingTasks(appId string) bool {
if response, err := e.doPopRequest(map[string]string{
"action": "/pop/v5/changeorder/change_order_list",
"httpMethod": "POST",
"id": appId,
}, map[string]string{
"AppId": appId,
}); err != nil {
return false
} else if v, err := jsonpath.Get("$.ChangeOrderList.ChangeOrder", response); err != nil {
return false
} else {
if len(v.([]interface{})) < 1 {
return false
}
for _, co := range v.([]interface{}) {
changeOrder := co.(map[string]interface{})
status := changeOrder["Status"]
if v, err := parseInt(status); err != nil {
return false
} else if statusStr, exist := ChangeOrderStatusMap[v]; exist {
if statusStr == ChangeOrderStatusReadyStr ||
statusStr == ChangeOrderStatusRunningStr ||
statusStr == ChangeOrderStatusAutoBatchWaitStr ||
statusStr == ChangeOrderStatusWaitBatchConfirmStr {
return true
}
} else {
return false
}
}
}
return false
}
func (e *EdasService) SyncResource(resourceType string) error {
request := edas.CreateSynchronizeResourceRequest()
request.RegionId = e.client.RegionId
request.Type = resourceType
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.SynchronizeResource(request)
})
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, "sync resource", request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
rsp := raw.(*edas.SynchronizeResourceResponse)
if rsp.Code != 200 || !rsp.Success {
return WrapError(Error("sync resource failed for %s", rsp.Message))
}
return nil
}
func (e *EdasService) CheckEcsStatus(instanceIds string, count int) error {
request := ecs.CreateDescribeInstancesRequest()
request.RegionId = e.client.RegionId
request.Status = "Running"
request.PageSize = requests.NewInteger(100)
request.InstanceIds = instanceIds
raw, err := e.client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) {
return ecsClient.DescribeInstances(request)
})
if err != nil {
if IsExpectedErrors(err, []string{"OperationDenied.InvalidDBClusterIdNotFound", "OperationDenied.InvalidDBClusterNameNotFound"}) {
return WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return WrapErrorf(err, DefaultErrorMsg, instanceIds, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
rsp := raw.(*ecs.DescribeInstancesResponse)
if len(rsp.Instances.Instance) != count {
return WrapErrorf(Error("not enough instances"), DefaultErrorMsg, instanceIds, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
return nil
}
func (e *EdasService) GetLastPackgeVersion(appId, groupId string) (string, error) {
var versionId string
request := edas.CreateQueryApplicationStatusRequest()
request.AppId = appId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.QueryApplicationStatus(request)
})
if err != nil {
return "", WrapErrorf(err, DefaultErrorMsg, "alicloud_edas_application_package_version", request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
response, _ := raw.(*edas.QueryApplicationStatusResponse)
if response.Code != 200 {
return "", WrapError(Error("QueryApplicationStatus failed for %s", response.Message))
}
for _, group := range response.AppInfo.GroupList.Group {
if group.GroupId == groupId {
versionId = group.PackageVersionId
}
}
rq := edas.CreateListHistoryDeployVersionRequest()
rq.AppId = appId
raw, err = e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.ListHistoryDeployVersion(rq)
})
if err != nil {
return "", WrapErrorf(err, DefaultErrorMsg, "alicloud_edas_application_package_version_list", request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
rsp, _ := raw.(*edas.ListHistoryDeployVersionResponse)
if rsp.Code != 200 {
return "", WrapError(Error("QueryApplicationStatus failed for %s", response.Message))
}
for _, version := range rsp.PackageVersionList.PackageVersion {
if version.Id == versionId {
return version.PackageVersion, nil
}
}
return "", nil
}
func (e *EdasService) DescribeEdasApplication(appId string) (*edas.Applcation, error) {
application := &edas.Applcation{}
regionId := e.client.RegionId
request := edas.CreateGetApplicationRequest()
request.RegionId = regionId
request.AppId = appId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.GetApplication(request)
})
if err != nil {
return application, WrapError(err)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
response, _ := raw.(*edas.GetApplicationResponse)
if response.Code != 200 {
return application, WrapError(Error("get application error :%s", response.Message))
}
v := response.Applcation
return &v, nil
}
func (e *EdasService) DescribeEdasApplicationV2(appId string) (object map[string]interface{}, err error) {
if response, err := e.doPopRequest(map[string]string{
"action": "/pop/v5/app/app_info",
"httpMethod": "POST",
}, map[string]string{
"id": appId,
"AppId": appId,
}); err != nil {
return nil, err
} else if application, exist := response["Application"].(map[string]interface{}); exist {
return application, nil
} else {
return nil, fmt.Errorf("%s: Edas K8s Applicatio, AppId: %s", ResourceNotfound, appId)
}
}
func (e *EdasService) doPopRequest(requestConfig map[string]string, params map[string]string) (map[string]interface{}, error) {
var response map[string]interface{}
client := e.client
request := map[string]*string{}
for k := range params {
v := params[k]
request[k] = &v
}
action := requestConfig["action"]
httpMethod := requestConfig["httpMethod"]
id := requestConfig["id"]
var err error
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
switch httpMethod {
case "POST":
response, err = client.RoaPost("Edas", "2017-08-01", action, request, nil, nil, false)
case "PUT":
response, err = client.RoaPut("Edas", "2017-08-01", action, request, nil, nil, false)
case "DELETE":
response, err = client.RoaDelete("Edas", "2017-08-01", action, request, nil, nil, false)
case "GET":
response, err = client.RoaGet("Edas", "2017-08-01", action, request, nil, nil)
default:
response, err = nil, fmt.Errorf("httpMethod %s is not support", httpMethod)
}
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
return nil, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR)
}
return response, nil
}
func (e *EdasService) DescribeEdasCluster(clusterId string) (*edas.Cluster, error) {
cluster := &edas.Cluster{}
regionId := e.client.RegionId
request := edas.CreateGetClusterRequest()
request.RegionId = regionId
request.ClusterId = clusterId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.GetCluster(request)
})
if err != nil {
return cluster, WrapErrorf(err, DefaultErrorMsg, "alicloud_edas_cluster", request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
response, _ := raw.(*edas.GetClusterResponse)
if response.Code != 200 {
return cluster, WrapError(Error("create cluster failed for %s", response.Message))
}
v := response.Cluster
return &v, nil
}
func (e *EdasService) DescribeEdasDeployGroup(id string) (*edas.DeployGroup, error) {
group := &edas.DeployGroup{}
regionId := e.client.RegionId
strs := strings.Split(id, ":")
request := edas.CreateListDeployGroupRequest()
request.RegionId = regionId
request.AppId = strs[0]
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.ListDeployGroup(request)
})
if err != nil {
return group, WrapErrorf(err, DefaultErrorMsg, "alicloud_edas_deploy_group", request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
response, _ := raw.(*edas.ListDeployGroupResponse)
if response.Code != 200 {
return group, WrapError(Error("create cluster failed for %s", response.Message))
}
for _, v := range response.DeployGroupList.DeployGroup {
if v.ClusterName == strs[1] {
return &v, nil
}
}
return group, nil
}
func (e *EdasService) DescribeEdasInstanceClusterAttachment(id string) (*edas.Cluster, error) {
cluster := &edas.Cluster{}
v := strings.Split(id, ":")
o, err := e.DescribeEdasCluster(v[0])
if err != nil {
return cluster, WrapError(err)
}
return o, nil
}
func (e *EdasService) DescribeEdasApplicationDeployment(id string) (*edas.Applcation, error) {
application := &edas.Applcation{}
v := strings.Split(id, ":")
o, err := e.DescribeEdasApplication(v[0])
if err != nil {
return application, WrapError(err)
}
return o, nil
}
func (e *EdasService) DescribeEdasApplicationScale(id string) (*edas.Applcation, error) {
application := &edas.Applcation{}
v := strings.Split(id, ":")
o, err := e.DescribeEdasApplication(v[0])
if err != nil {
return application, WrapError(err)
}
return o, nil
}
func (e *EdasService) DescribeEdasSlbAttachment(id string) (*edas.Applcation, error) {
application := &edas.Applcation{}
v := strings.Split(id, ":")
o, err := e.DescribeEdasApplication(v[0])
if err != nil {
return application, WrapError(err)
}
return o, nil
}
type CommandArg struct {
Argument string `json:"argument" xml:"argument"`
}
func (e *EdasService) GetK8sCommandArgs(args []interface{}) (string, error) {
aString := make([]CommandArg, 0)
for _, v := range args {
aString = append(aString, CommandArg{Argument: v.(string)})
}
b, err := json.Marshal(aString)
if err != nil {
return "", WrapError(err)
}
return string(b), nil
}
func (e *EdasService) GetK8sCommandArgsForDeploy(args []interface{}) (string, error) {
b, err := json.Marshal(args)
if err != nil {
return "", WrapError(err)
}
return string(b), nil
}
type K8sEnv struct {
Name string `json:"name" xml:"name"`
Value string `json:"value" xml:"value"`
}
func (e *EdasService) GetK8sEnvs(envs map[string]interface{}) (string, error) {
k8sEnvs := make([]K8sEnv, 0)
for n, v := range envs {
k8sEnvs = append(k8sEnvs, K8sEnv{Name: n, Value: v.(string)})
}
b, err := json.Marshal(k8sEnvs)
if err != nil {
return "", WrapError(err)
}
return string(b), nil
}
func (e *EdasService) QueryK8sAppPackageType(appId string) (string, error) {
request := edas.CreateGetApplicationRequest()
request.RegionId = e.client.RegionId
request.AppId = appId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.GetApplication(request)
})
if err != nil {
return "", WrapError(err)
}
response, _ := raw.(*edas.GetApplicationResponse)
if response.Code != 200 {
return "", WrapError(Error("get application for appId:"+appId+" failed:", response.Message))
}
if len(response.Applcation.ApplicationType) > 0 {
return response.Applcation.ApplicationType, nil
}
return "", WrapError(Error("not package type for appId: %s", appId))
}
func (e *EdasService) DescribeEdasK8sCluster(clusterId string) (*edas.Cluster, error) {
cluster := &edas.Cluster{}
regionId := e.client.RegionId
request := edas.CreateGetClusterRequest()
request.RegionId = regionId
request.ClusterId = clusterId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.GetCluster(request)
})
if err != nil {
return cluster, WrapErrorf(err, DefaultErrorMsg, clusterId, request.GetActionName(), AlibabaCloudSdkGoERROR)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
response, _ := raw.(*edas.GetClusterResponse)
if response.Code != 200 {
if strings.Contains(response.Message, "does not exist") {
return cluster, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return cluster, WrapError(Error("create k8s cluster failed for %s", response.Message))
}
v := response.Cluster
return &v, nil
}
func (e *EdasService) DescribeEdasK8sApplication(appId string) (*edas.Applcation, error) {
application := &edas.Applcation{}
regionId := e.client.RegionId
request := edas.CreateGetK8sApplicationRequest()
request.RegionId = regionId
request.AppId = appId
raw, err := e.client.WithEdasClient(func(edasClient *edas.Client) (interface{}, error) {
return edasClient.GetK8sApplication(request)
})
if err != nil {
return application, WrapError(err)
}
addDebug(request.GetActionName(), raw, request.RoaRequest, request)
response, _ := raw.(*edas.GetK8sApplicationResponse)
if response.Code != 200 {
if strings.Contains(response.Message, "does not exist") {
return application, WrapErrorf(err, NotFoundMsg, AlibabaCloudSdkGoERROR)
}
return application, WrapError(Error("get k8s application error : %s", response.Message))
}
v := response.Applcation
return &v, nil
}
func (e *EdasService) PreStopEqual(old, new interface{}) bool {
oldStr := old.(string)
newStr := new.(string)
var oldHook Hook
err := json.Unmarshal([]byte(oldStr), &oldHook)
if err != nil {
return false
}
var newHook Hook
err = json.Unmarshal([]byte(newStr), &newHook)
if err != nil {
return false
}
return reflect.DeepEqual(oldHook, newHook)
}
func (e *EdasService) PostStartEqual(old, new interface{}) bool {
oldStr := old.(string)
newStr := new.(string)
var oldHook Hook
err := json.Unmarshal([]byte(oldStr), &oldHook)
if err != nil {
return false
}
var newHook Hook
err = json.Unmarshal([]byte(newStr), &newHook)
if err != nil {
return false
}
return reflect.DeepEqual(oldHook, newHook)
}
func (e *EdasService) LivenessEqual(old, new interface{}) bool {
oldStr := old.(string)
newStr := new.(string)
var oldProber Prober
err := json.Unmarshal([]byte(oldStr), &oldProber)
if err != nil {
return false
}
var newProber Prober
err = json.Unmarshal([]byte(newStr), &newProber)
if err != nil {
return false
}
return reflect.DeepEqual(oldProber, newProber)
}
func (e *EdasService) ReadinessEqual(old, new interface{}) bool {
oldStr := old.(string)
newStr := new.(string)
var oldProber Prober
err := json.Unmarshal([]byte(oldStr), &oldProber)
if err != nil {
return false
}
var newProber Prober
err = json.Unmarshal([]byte(newStr), &newProber)
if err != nil {
return false
}
return reflect.DeepEqual(oldProber, newProber)
}
func (e *EdasService) IsJsonEqual(v1, v2 interface{}) bool {
s1 := v1.(string)
s2 := v2.(string)
var i1 interface{}
err := json.Unmarshal([]byte(s1), &i1)
if err != nil {
return false
}
var i2 interface{}
err = json.Unmarshal([]byte(s2), &i2)
if err != nil {
return false
}
return reflect.DeepEqual(&i1, &i2)
}
func (e *EdasService) IsJsonArrayEqual(v1, v2 interface{}) bool {
s1 := v1.(string)
s2 := v2.(string)
var i1 []interface{}
err := json.Unmarshal([]byte(s1), &i1)
if err != nil {
return false
}
var i2 []interface{}
err = json.Unmarshal([]byte(s2), &i2)
if err != nil {
return false
}
if len(i1) != len(i2) {
return false
}
for _, obj := range i1 {
found := false
for _, obj2 := range i2 {
if reflect.DeepEqual(obj, obj2) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
func (s *EdasService) DescribeEdasNamespace(id string) (object map[string]interface{}, err error) {
var response map[string]interface{}
client := s.client
action := "/pop/v5/user_region_defs"
request := map[string]*string{}
idExist := false
wait := incrementalWait(3*time.Second, 3*time.Second)
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
response, err = client.RoaPost("Edas", "2017-08-01", action, request, nil, nil, false)
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR)
}
v, err := jsonpath.Get("$.UserDefineRegionList.UserDefineRegionEntity", response)
if err != nil {
return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.UserDefineRegionList.UserDefineRegionEntity", response)
}
if len(v.([]interface{})) < 1 {
return object, WrapErrorf(NotFoundErr("EDAS", id), NotFoundWithResponse, response)
}
for _, v := range v.([]interface{}) {
if fmt.Sprint(v.(map[string]interface{})["Id"]) == id {
idExist = true
return v.(map[string]interface{}), nil
}
}
if !idExist {
return object, WrapErrorf(NotFoundErr("EDAS", id), NotFoundWithResponse, response)
}
return object, nil
}
func (e *EdasService) BindK8sSlb(appId string, slbConfig *map[string]interface{}, timeout time.Duration) *resource.RetryError {
if e.HasOngoingTasks(appId) {
return resource.RetryableError(Error("there is an ongoing task"))
}
portMappings := (*slbConfig)["port_mappings"].(*schema.Set).List()
var requestServicePortInfos []map[string]interface{}
if len(portMappings) > 0 {
for _, pmInterface := range portMappings {
pm := pmInterface.(map[string]interface{})
if v, ok := pm["service_port"]; ok {
spSlice := v.(*schema.Set).List()
sp := spSlice[0].(map[string]interface{})
info := map[string]interface{}{
"certId": pm["cert_id"],
"loadBalancerProtocol": pm["loadbalancer_protocol"],
"targetPort": sp["target_port"],
"port": sp["port"],
}
requestServicePortInfos = append(requestServicePortInfos, info)
}
}
}
portInfoBytes, err := json.Marshal(requestServicePortInfos)
if err != nil {
return resource.NonRetryableError(WrapErrorf(err, "marshal port mappings failed, value %v", requestServicePortInfos))
}
params := map[string]string{
"AppId": appId,
"Type": (*slbConfig)["type"].(string),
"SlbId": (*slbConfig)["slb_id"].(string),
"Scheduler": (*slbConfig)["scheduler"].(string),
"Specification": (*slbConfig)["specification"].(string),
"ServicePortInfos": string(portInfoBytes),
}
if response, err := e.doPopRequest(map[string]string{
"action": "/pop/v5/k8s/acs/k8s_slb_binding",
"httpMethod": "POST",
"id": appId,
}, params); err != nil {
return resource.NonRetryableError(err)
} else {
return e.WaitForChangeOrderFinishedNonRetryable(appId, response["ChangeOrderId"].(string), timeout)
}
}
func (e *EdasService) UpdateK8sAppSlbInfos(appId string, oldInfos, newInfos *[]interface{}, timeout time.Duration) *resource.RetryError {
buildMap := func(infos *[]interface{}) *map[string]interface{} {
m := map[string]interface{}{}
if len(*infos) > 0 {
for _, v := range *infos {
info := v.(map[string]interface{})
m[info["name"].(string)] = info
}
}
return &m
}
// build a map with key: slbName, value: slbInfo
oldInfosMap := buildMap(oldInfos)
newInfosMap := buildMap(newInfos)
// find removed slb configs and unbind them
for _, v := range *oldInfos {
oInfo := v.(map[string]interface{})
slbName := oInfo["name"].(string)
slbType := oInfo["type"].(string)
if _, ok := (*newInfosMap)[slbName]; !ok {
if err := e.UnbindK8sSlb(appId, slbType, slbName, timeout); err != nil {
return err
}
}
}
// find new or modified slb configs
for _, v := range *newInfos {
nInfo := v.(map[string]interface{})
slbName := nInfo["name"].(string)
if ov, ok := (*oldInfosMap)[slbName]; ok {
oInfo := ov.(map[string]interface{})
if pm, ok := nInfo["port_mappings"].([]interface{}); !ok || len(pm) == 0 {
// in this case, the port_mappings were cleared, so unbind this slb
// type is required to unbind slb, but it is cleared in nInfo
slbType := oInfo["type"].(string)
if err := e.UnbindK8sSlb(appId, slbType, slbName, timeout); err != nil {
return err
}
continue
}
if !reflect.DeepEqual(oInfo, nInfo) {
// modified
if err := e.updateK8sSlb(appId, &nInfo, timeout); err != nil {
return err
}
}
} else {
// new one
if err := e.BindK8sSlb(appId, &nInfo, timeout); err != nil {
return err
}
}
}
return nil
}
func (e *EdasService) updateK8sSlb(appId string, slbConfig *map[string]interface{}, timeout time.Duration) *resource.RetryError {
if e.HasOngoingTasks(appId) {
return resource.RetryableError(Error("there is an ongoing task"))
}
portMappings := (*slbConfig)["port_mappings"].(*schema.Set).List()
var requestServicePortInfos []map[string]interface{}
if len(portMappings) > 0 {
for _, pmInterface := range portMappings {
pm := pmInterface.(map[string]interface{})
if v, ok := pm["service_port"]; ok {
spSlice := v.(*schema.Set).List()
sp := spSlice[0].(map[string]interface{})
info := map[string]interface{}{
"certId": pm["cert_id"],
"loadBalancerProtocol": pm["loadbalancer_protocol"],
"targetPort": sp["target_port"],
"port": sp["port"],
}
requestServicePortInfos = append(requestServicePortInfos, info)
}
}
}
portInfoBytes, err := json.Marshal(requestServicePortInfos)
if err != nil {
return resource.NonRetryableError(WrapErrorf(err, "marshal port mappings failed, value %v", requestServicePortInfos))
}
params := map[string]string{
"AppId": appId,
"SlbName": (*slbConfig)["name"].(string),
"Type": (*slbConfig)["type"].(string),
"Scheduler": (*slbConfig)["scheduler"].(string),
"Specification": (*slbConfig)["specification"].(string),
"ClusterId": "ClusterId",
"ServicePortInfos": string(portInfoBytes),
}
if response, err := e.doPopRequest(map[string]string{
"action": "/pop/v5/k8s/acs/k8s_slb_binding",
"httpMethod": "PUT",
"id": appId,
}, params); err != nil {
return resource.NonRetryableError(err)
} else {
return e.WaitForChangeOrderFinishedNonRetryable(appId, response["ChangeOrderId"].(string), timeout)
}
}
func (e *EdasService) UnbindK8sSlb(appId, slbType, slbName string, timeout time.Duration) *resource.RetryError {
if e.HasOngoingTasks(appId) {
return resource.RetryableError(Error("there is an ongoing task"))
}
if response, err := e.doPopRequest(map[string]string{
"action": "/pop/v5/k8s/acs/k8s_slb_binding",
"httpMethod": "DELETE",
"id": appId,
}, map[string]string{
"AppId": appId,
"Type": slbType,
"SlbName": slbName,
}); err != nil {
return resource.NonRetryableError(err)
} else {
return e.WaitForChangeOrderFinishedNonRetryable(appId, response["ChangeOrderId"].(string), timeout)
}
}
func (e *EdasService) DescribeEdasK8sSlbAttachment(appId string) ([]map[string]interface{}, error) {
application, err := e.DescribeEdasApplicationV2(appId)
if err != nil {
return nil, err
}
slbInfo := ""
if v, ok := application["SlbInfo"]; ok {
slbInfo = v.(string)
}
var slbConfigs []map[string]interface{}
if !jsonEmpty(slbInfo) {
filteredSlbInfo, err := filterSlbInfo(slbInfo)
if err != nil {
return nil, err
}
if len(*filteredSlbInfo) > 0 {
for _, slbInfo := range *filteredSlbInfo {
slbConfig, err := parseSlbConfig(&slbInfo)
if err != nil {
return nil, err
}
slbConfigs = append(slbConfigs, *slbConfig)
}
}
}
return slbConfigs, nil
}