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 }