Add Alibaba Cloud Provider support with no vendor (#1309)

* Add Alibaba Cloud Provider

* Add Alibaba Cloud Provider Documents

* Add Alibaba Cloud Provider Examples

* Remove sdk test cases

* fix conflicts in cloud-provider builder

* remove LICENSE in cloudprovider
This commit is contained in:
ringtail 2018-10-23 20:23:34 +08:00 committed by Marcin Wielgus
parent 609e9e44a6
commit 962826e46a
69 changed files with 8699 additions and 3 deletions

View File

@ -17,7 +17,7 @@ FROM $BASEIMAGE
LABEL maintainer="Marcin Wielgus <mwielgus@google.com>"
ENV DEBIAN_FRONTEND noninteractive
RUN clean-install ca-certificates
RUN clean-install ca-certificates tzdata
ADD cluster-autoscaler cluster-autoscaler
ADD run.sh run.sh

View File

@ -0,0 +1,186 @@
# Cluster Autoscaler on AliCloud
The cluster autoscaler on AliCloud scales worker nodes within any specified autoscaling group. It will run as a `Deployment` in your cluster. This README will go over some of the necessary steps required to get the cluster autoscaler up and running.
## Kubernetes Version
Cluster autoscaler must run on v1.9.3 or greater.
## Instance Type Support
- **Standard Instance**x86-Architecture,suitable for common scenes such as websites or api services.
- **GPU/FPGA Instance**Heterogeneous Computing,suitable for high performance computing.
- **Bare Metal Instance**Both the elasticity of a virtual server and the high-performance and comprehensive features of a physical server.
- **Spot Instance**Spot instance are on-demand instances. They are designed to reduce your ECS costs in some cases.
## ACS Console Deployment
doc: https://www.alibabacloud.com/help/doc-detail/89733.html
## Custom Deployment
### 1.Prepare Identity authentication
#### Use access-key-id and access-key-secret
```yaml
apiVersion: v1
kind: Secret
metadata:
name: cloud-config
namespace: kube-system
data:
# insert your base64 encoded Alicloud access id and key here, ensure there's no trailing newline:
# such as: echo -n "your_access_key_id" | base64
access-key-id: "<BASE64_ACCESS_KEY_ID>"
access-key-secret: "<BASE64_ACCESS_KEY_SECRET>"
region-id: "<BASE64_REGION_ID>"
```
#### Use STS with RAM Role
```yaml
{
"Version": "1",
"Statement": [
{
"Action": [
"ess:Describe*",
"ess:CreateScalingRule",
"ess:ModifyScalingGroup",
"ess:RemoveInstances",
"ess:ExecuteScalingRule",
"ess:ModifyScalingRule",
"ess:DeleteScalingRule",
"ess:DetachInstances",
"ecs:DescribeInstanceTypes"
],
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}
```
### 2.ASG Setup
* create a Scaling Group in ESS(https://essnew.console.aliyun.com) with valid configurations.
* create a Scaling Configuration for this Scaling Group with valid instanceType and User Data.In User Data,you can specific the script to initialize the environment and join this node to kubernetes cluster.If your Kubernetes cluster is hosted by ACS.you can use the attach script like this.
```shell
#!/bin/sh
# The token is generated by ACS console. https://www.alibabacloud.com/help/doc-detail/64983.htm?spm=a2c63.l28256.b99.33.46395ad54ozJFq
curl http://aliacs-k8s-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/public/pkg/run/attach/[kubernetes_cluster_version]/attach_node.sh | bash -s -- --openapi-token [token] --ess true
```
### 3.cluster-autoscaler deployment
#### Use access-key-id and access-key-secret
```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
app: cluster-autoscaler
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
spec:
serviceAccountName: admin
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/autoscaler:v1.3.1.2
name: cluster-autoscaler
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=alicloud
- --nodes=[min]:[max]:[ASG_ID]
imagePullPolicy: "Always"
env:
- name: ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: cloud-config
key: access-key-id
- name: ACCESS_KEY_SECRET
valueFrom:
secretKeyRef:
name: cloud-config
key: access-key-secret
- name: REGION_ID
valueFrom:
secretKeyRef:
name: cloud-config
key: region-id
volumeMounts:
- name: ssl-certs
mountPath: /etc/ssl/certs/ca-certificates.crt
readOnly: true
imagePullPolicy: "Always"
volumes:
- name: ssl-certs
hostPath:
path: "/etc/ssl/certs/ca-certificates.crt"
```
#### Use STS with RAM Role
```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
app: cluster-autoscaler
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
spec:
serviceAccountName: admin
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/autoscaler:v1.3.1.2
name: cluster-autoscaler
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=alicloud
- --nodes=[min]:[max]:[ASG_ID]
imagePullPolicy: "Always"
```
### Auto-Discovery Setup
Auto Discovery is not supported in AliCloud currently.
## Common Notes and Gotchas:
- The `/etc/ssl/certs/ca-certificates.crt` should exist by default on your ecs instance.
- By default, cluster autoscaler will not terminate nodes running pods in the kube-system namespace. You can override this default behaviour by passing in the `--skip-nodes-with-system-pods=false` flag.
- By default, cluster autoscaler will wait 10 minutes between scale down operations, you can adjust this using the `--scale-down-delay` flag. E.g. `--scale-down-delay=5m` to decrease the scale down delay to 5 minutes.
- If you're running multiple ASGs, the `--expander` flag supports three options: `random`, `most-pods` and `least-waste`. `random` will expand a random ASG on scale up. `most-pods` will scale up the ASG that will scheduable the most amount of pods. `least-waste` will expand the ASG that will waste the least amount of CPU/MEM resources. In the event of a tie, cluster-autoscaler will fall back to `random`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,20 @@
/*
Copyright 2018 The Kubernetes Authors.
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 auth
// Credential doesn't implement
type Credential interface{}

View File

@ -0,0 +1,53 @@
/*
Copyright 2018 The Kubernetes Authors.
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 credentials
// BaseCredential is deprecated: Use AccessKeyCredential in this package instead.
type BaseCredential struct {
AccessKeyId string
AccessKeySecret string
}
// AccessKeyCredential is kind of credential
type AccessKeyCredential struct {
AccessKeyId string
AccessKeySecret string
}
// NewBaseCredential is deprecated: Use NewAccessKeyCredential in this package instead.
func NewBaseCredential(accessKeyId, accessKeySecret string) *BaseCredential {
return &BaseCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
}
}
// ToAccessKeyCredential returns AccessKeyCredential
func (baseCred *BaseCredential) ToAccessKeyCredential() *AccessKeyCredential {
return &AccessKeyCredential{
AccessKeyId: baseCred.AccessKeyId,
AccessKeySecret: baseCred.AccessKeySecret,
}
}
// NewAccessKeyCredential returns AccessKeyCredential
func NewAccessKeyCredential(accessKeyId, accessKeySecret string) *AccessKeyCredential {
return &AccessKeyCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
}
}

View File

@ -0,0 +1,48 @@
/*
Copyright 2018 The Kubernetes Authors.
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 credentials
// StsRoleNameOnEcsCredential is deprecated: Use EcsRamRoleCredential in this package instead.
type StsRoleNameOnEcsCredential struct {
RoleName string
}
// NewStsRoleNameOnEcsCredential is deprecated: Use NewEcsRamRoleCredential in this package instead.
func NewStsRoleNameOnEcsCredential(roleName string) *StsRoleNameOnEcsCredential {
return &StsRoleNameOnEcsCredential{
RoleName: roleName,
}
}
// ToEcsRamRoleCredential is deprecated
func (oldCred *StsRoleNameOnEcsCredential) ToEcsRamRoleCredential() *EcsRamRoleCredential {
return &EcsRamRoleCredential{
RoleName: oldCred.RoleName,
}
}
// EcsRamRoleCredential is kind of credential on ECS
type EcsRamRoleCredential struct {
RoleName string
}
// NewEcsRamRoleCredential returns EcsRamRoleCredential
func NewEcsRamRoleCredential(roleName string) *EcsRamRoleCredential {
return &EcsRamRoleCredential{
RoleName: roleName,
}
}

View File

@ -0,0 +1,33 @@
/*
Copyright 2018 The Kubernetes Authors.
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 credentials
// RsaKeyPairCredential is kind of credential
type RsaKeyPairCredential struct {
PrivateKey string
PublicKeyId string
SessionExpiration int
}
// NewRsaKeyPairCredential returns RsaKeyPairCredential
func NewRsaKeyPairCredential(privateKey, publicKeyId string, sessionExpiration int) *RsaKeyPairCredential {
return &RsaKeyPairCredential{
PrivateKey: privateKey,
PublicKeyId: publicKeyId,
SessionExpiration: sessionExpiration,
}
}

View File

@ -0,0 +1,33 @@
/*
Copyright 2018 The Kubernetes Authors.
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 credentials
// StsTokenCredential is kind of credential
type StsTokenCredential struct {
AccessKeyId string
AccessKeySecret string
AccessKeyStsToken string
}
// NewStsTokenCredential returns StsTokenCredential
func NewStsTokenCredential(accessKeyId, accessKeySecret, accessKeyStsToken string) *StsTokenCredential {
return &StsTokenCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
AccessKeyStsToken: accessKeyStsToken,
}
}

View File

@ -0,0 +1,68 @@
/*
Copyright 2018 The Kubernetes Authors.
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 credentials
// StsRoleArnCredential is deprecated: Use RamRoleArnCredential in this package instead.
type StsRoleArnCredential struct {
AccessKeyId string
AccessKeySecret string
RoleArn string
RoleSessionName string
RoleSessionExpiration int
}
// RamRoleArnCredential is going to replace StsRoleArnCredential
type RamRoleArnCredential struct {
AccessKeyId string
AccessKeySecret string
RoleArn string
RoleSessionName string
RoleSessionExpiration int
}
// NewStsRoleArnCredential is deprecated: Use RamRoleArnCredential in this package instead.
func NewStsRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName string, roleSessionExpiration int) *StsRoleArnCredential {
return &StsRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
RoleSessionExpiration: roleSessionExpiration,
}
}
// ToRamRoleArnCredential returns RamRoleArnCredential
func (oldCred *StsRoleArnCredential) ToRamRoleArnCredential() *RamRoleArnCredential {
return &RamRoleArnCredential{
AccessKeyId: oldCred.AccessKeyId,
AccessKeySecret: oldCred.AccessKeySecret,
RoleArn: oldCred.RoleArn,
RoleSessionName: oldCred.RoleSessionName,
RoleSessionExpiration: oldCred.RoleSessionExpiration,
}
}
// NewRamRoleArnCredential returns RamRoleArnCredential
func NewRamRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName string, roleSessionExpiration int) *RamRoleArnCredential {
return &RamRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
RoleSessionExpiration: roleSessionExpiration,
}
}

View File

@ -0,0 +1,123 @@
/*
Copyright 2018 The Kubernetes Authors.
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 auth
import (
"bytes"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/utils"
"sort"
"strings"
)
func signRoaRequest(request requests.AcsRequest, signer Signer, regionId string) (err error) {
completeROASignParams(request, signer, regionId)
stringToSign := buildRoaStringToSign(request)
request.SetStringToSign(stringToSign)
signature := signer.Sign(stringToSign, "")
accessKeyId, err := signer.GetAccessKeyId()
if err != nil {
return nil
}
request.GetHeaders()["Authorization"] = "acs " + accessKeyId + ":" + signature
return
}
func completeROASignParams(request requests.AcsRequest, signer Signer, regionId string) {
headerParams := request.GetHeaders()
// complete query params
queryParams := request.GetQueryParams()
//if _, ok := queryParams["RegionId"]; !ok {
// queryParams["RegionId"] = regionId
//}
if extraParam := signer.GetExtraParam(); extraParam != nil {
for key, value := range extraParam {
if key == "SecurityToken" {
headerParams["x-acs-security-token"] = value
continue
}
queryParams[key] = value
}
}
// complete header params
headerParams["Date"] = utils.GetTimeInFormatRFC2616()
headerParams["x-acs-signature-method"] = signer.GetName()
headerParams["x-acs-signature-version"] = signer.GetVersion()
if request.GetFormParams() != nil && len(request.GetFormParams()) > 0 {
formString := utils.GetUrlFormedMap(request.GetFormParams())
request.SetContent([]byte(formString))
headerParams["Content-Type"] = requests.Form
}
contentMD5 := utils.GetMD5Base64(request.GetContent())
headerParams["Content-MD5"] = contentMD5
if _, contains := headerParams["Content-Type"]; !contains {
headerParams["Content-Type"] = requests.Raw
}
switch format := request.GetAcceptFormat(); format {
case "JSON":
headerParams["Accept"] = requests.Json
case "XML":
headerParams["Accept"] = requests.Xml
default:
headerParams["Accept"] = requests.Raw
}
}
func buildRoaStringToSign(request requests.AcsRequest) (stringToSign string) {
headers := request.GetHeaders()
stringToSignBuilder := bytes.Buffer{}
stringToSignBuilder.WriteString(request.GetMethod())
stringToSignBuilder.WriteString(requests.HeaderSeparator)
// append header keys for sign
appendIfContain(headers, &stringToSignBuilder, "Accept", requests.HeaderSeparator)
appendIfContain(headers, &stringToSignBuilder, "Content-MD5", requests.HeaderSeparator)
appendIfContain(headers, &stringToSignBuilder, "Content-Type", requests.HeaderSeparator)
appendIfContain(headers, &stringToSignBuilder, "Date", requests.HeaderSeparator)
// sort and append headers witch starts with 'x-acs-'
var acsHeaders []string
for key := range headers {
if strings.HasPrefix(key, "x-acs-") {
acsHeaders = append(acsHeaders, key)
}
}
sort.Strings(acsHeaders)
for _, key := range acsHeaders {
stringToSignBuilder.WriteString(key + ":" + headers[key])
stringToSignBuilder.WriteString(requests.HeaderSeparator)
}
// append query params
stringToSignBuilder.WriteString(request.BuildQueries())
stringToSign = stringToSignBuilder.String()
return
}
func appendIfContain(sourceMap map[string]string, target *bytes.Buffer, key, separator string) {
if value, contain := sourceMap[key]; contain && len(value) > 0 {
target.WriteString(sourceMap[key])
target.WriteString(separator)
}
}

View File

@ -0,0 +1,98 @@
/*
Copyright 2018 The Kubernetes Authors.
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 auth
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/utils"
"net/url"
"sort"
"strings"
)
func signRpcRequest(request requests.AcsRequest, signer Signer, regionId string) (err error) {
err = completeRpcSignParams(request, signer, regionId)
if err != nil {
return
}
// remove while retry
if _, containsSign := request.GetQueryParams()["Signature"]; containsSign {
delete(request.GetQueryParams(), "Signature")
}
stringToSign := buildRpcStringToSign(request)
request.SetStringToSign(stringToSign)
signature := signer.Sign(stringToSign, "&")
request.GetQueryParams()["Signature"] = signature
return
}
func completeRpcSignParams(request requests.AcsRequest, signer Signer, regionId string) (err error) {
queryParams := request.GetQueryParams()
queryParams["Version"] = request.GetVersion()
queryParams["Action"] = request.GetActionName()
queryParams["Format"] = request.GetAcceptFormat()
queryParams["Timestamp"] = utils.GetTimeInFormatISO8601()
queryParams["SignatureMethod"] = signer.GetName()
queryParams["SignatureType"] = signer.GetType()
queryParams["SignatureVersion"] = signer.GetVersion()
queryParams["SignatureNonce"] = utils.GetUUIDV4()
queryParams["AccessKeyId"], err = signer.GetAccessKeyId()
if err != nil {
return
}
if _, contains := queryParams["RegionId"]; !contains {
queryParams["RegionId"] = regionId
}
if extraParam := signer.GetExtraParam(); extraParam != nil {
for key, value := range extraParam {
queryParams[key] = value
}
}
request.GetHeaders()["Content-Type"] = requests.Form
formString := utils.GetUrlFormedMap(request.GetFormParams())
request.SetContent([]byte(formString))
return
}
func buildRpcStringToSign(request requests.AcsRequest) (stringToSign string) {
signParams := make(map[string]string)
for key, value := range request.GetQueryParams() {
signParams[key] = value
}
for key, value := range request.GetFormParams() {
signParams[key] = value
}
// sort params by key
var paramKeySlice []string
for key := range signParams {
paramKeySlice = append(paramKeySlice, key)
}
sort.Strings(paramKeySlice)
stringToSign = utils.GetUrlFormedMap(signParams)
stringToSign = strings.Replace(stringToSign, "+", "%20", -1)
stringToSign = strings.Replace(stringToSign, "*", "%2A", -1)
stringToSign = strings.Replace(stringToSign, "%7E", "~", -1)
stringToSign = url.QueryEscape(stringToSign)
stringToSign = request.GetMethod() + "&%2F&" + stringToSign
return
}

View File

@ -0,0 +1,100 @@
/*
Copyright 2018 The Kubernetes Authors.
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 auth
import (
"fmt"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/signers"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"reflect"
)
// Signer sign client token
type Signer interface {
GetName() string
GetType() string
GetVersion() string
GetAccessKeyId() (string, error)
GetExtraParam() map[string]string
Sign(stringToSign, secretSuffix string) string
Shutdown()
}
// NewSignerWithCredential create signer with credential
func NewSignerWithCredential(credential Credential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer Signer, err error) {
switch instance := credential.(type) {
case *credentials.AccessKeyCredential:
{
signer, err = signers.NewAccessKeySigner(instance)
}
case *credentials.StsTokenCredential:
{
signer, err = signers.NewStsTokenSigner(instance)
}
case *credentials.RamRoleArnCredential:
{
signer, err = signers.NewRamRoleArnSigner(instance, commonApi)
}
case *credentials.RsaKeyPairCredential:
{
signer, err = signers.NewSignerKeyPair(instance, commonApi)
}
case *credentials.EcsRamRoleCredential:
{
signer, err = signers.NewEcsRamRoleSigner(instance, commonApi)
}
case *credentials.BaseCredential: // deprecated user interface
{
signer, err = signers.NewAccessKeySigner(instance.ToAccessKeyCredential())
}
case *credentials.StsRoleArnCredential: // deprecated user interface
{
signer, err = signers.NewRamRoleArnSigner(instance.ToRamRoleArnCredential(), commonApi)
}
case *credentials.StsRoleNameOnEcsCredential: // deprecated user interface
{
signer, err = signers.NewEcsRamRoleSigner(instance.ToEcsRamRoleCredential(), commonApi)
}
default:
message := fmt.Sprintf(errors.UnsupportedCredentialErrorMessage, reflect.TypeOf(credential))
err = errors.NewClientError(errors.UnsupportedCredentialErrorCode, message, nil)
}
return
}
// Sign will generate signer token
func Sign(request requests.AcsRequest, signer Signer, regionId string) (err error) {
switch request.GetStyle() {
case requests.ROA:
{
signRoaRequest(request, signer, regionId)
}
case requests.RPC:
{
err = signRpcRequest(request, signer, regionId)
}
default:
message := fmt.Sprintf(errors.UnknownRequestTypeErrorMessage, reflect.TypeOf(request))
err = errors.NewClientError(errors.UnknownRequestTypeErrorCode, message, nil)
}
return
}

View File

@ -0,0 +1,64 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"crypto"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"fmt"
)
// ShaHmac1 returns sha-hmac1 secret
func ShaHmac1(source, secret string) string {
key := []byte(secret)
hmac := hmac.New(sha1.New, key)
hmac.Write([]byte(source))
signedBytes := hmac.Sum(nil)
signedString := base64.StdEncoding.EncodeToString(signedBytes)
return signedString
}
// Sha256WithRsa returns sh256 secret
func Sha256WithRsa(source, secret string) string {
decodeString, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
fmt.Println("DecodeString err", err)
}
private, err := x509.ParsePKCS8PrivateKey(decodeString)
if err != nil {
fmt.Println("ParsePKCS8PrivateKey err", err)
}
h := crypto.Hash.New(crypto.SHA256)
h.Write([]byte(source))
hashed := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey),
crypto.SHA256, hashed)
if err != nil {
fmt.Println("Error from signing:", err)
return ""
}
signedString := base64.StdEncoding.EncodeToString(signature)
//fmt.Printf("Encoded: %v\n", signedString)
return signedString
}

View File

@ -0,0 +1,55 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"time"
)
const defaultInAdvanceScale = 0.8
type credentialUpdater struct {
credentialExpiration int
lastUpdateTimestamp int64
inAdvanceScale float64
buildRequestMethod func() (*requests.CommonRequest, error)
responseCallBack func(response *responses.CommonResponse) error
refreshApi func(request *requests.CommonRequest) (response *responses.CommonResponse, err error)
}
func (updater *credentialUpdater) needUpdateCredential() (result bool) {
if updater.inAdvanceScale == 0 {
updater.inAdvanceScale = defaultInAdvanceScale
}
return time.Now().Unix()-updater.lastUpdateTimestamp >= int64(float64(updater.credentialExpiration)*updater.inAdvanceScale)
}
func (updater *credentialUpdater) updateCredential() (err error) {
request, err := updater.buildRequestMethod()
if err != nil {
return
}
response, err := updater.refreshApi(request)
if err != nil {
return
}
updater.lastUpdateTimestamp = time.Now().Unix()
err = updater.responseCallBack(response)
return
}

View File

@ -0,0 +1,24 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
// SessionCredential is kind of credential
type SessionCredential struct {
AccessKeyId string
AccessKeySecret string
StsToken string
}

View File

@ -0,0 +1,67 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
// AccessKeySigner is wrapper of AccessKeyCredential
type AccessKeySigner struct {
credential *credentials.AccessKeyCredential
}
// GetExtraParam doesn't implement
func (signer *AccessKeySigner) GetExtraParam() map[string]string {
return nil
}
// NewAccessKeySigner returns AccessKeySigner
func NewAccessKeySigner(credential *credentials.AccessKeyCredential) (*AccessKeySigner, error) {
return &AccessKeySigner{
credential: credential,
}, nil
}
// GetName returns "HMAC-SHA1"
func (*AccessKeySigner) GetName() string {
return "HMAC-SHA1"
}
// GetType returns ""
func (*AccessKeySigner) GetType() string {
return ""
}
// GetVersion returns "1.0"
func (*AccessKeySigner) GetVersion() string {
return "1.0"
}
// GetAccessKeyId returns accessKeyId
func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) {
return signer.credential.AccessKeyId, nil
}
// Sign returns a signer
func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
// Shutdown doesn't implement
func (signer *AccessKeySigner) Shutdown() {}

View File

@ -0,0 +1,185 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"encoding/json"
"fmt"
"github.com/jmespath/go-jmespath"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"net/http"
"strings"
"time"
)
// EcsRamRoleSigner is kind of signer
type EcsRamRoleSigner struct {
*credentialUpdater
sessionCredential *SessionCredential
credential *credentials.EcsRamRoleCredential
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
// NewEcsRamRoleSigner returns EcsRamRoleSigner
func NewEcsRamRoleSigner(credential *credentials.EcsRamRoleCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *EcsRamRoleSigner, err error) {
signer = &EcsRamRoleSigner{
credential: credential,
commonApi: commonApi,
}
signer.credentialUpdater = &credentialUpdater{
credentialExpiration: defaultDurationSeconds / 60,
buildRequestMethod: signer.buildCommonRequest,
responseCallBack: signer.refreshCredential,
refreshApi: signer.refreshApi,
}
return
}
// GetName returns "HMAC-SHA1"
func (*EcsRamRoleSigner) GetName() string {
return "HMAC-SHA1"
}
// GetType returns ""
func (*EcsRamRoleSigner) GetType() string {
return ""
}
// GetVersion returns "1.0"
func (*EcsRamRoleSigner) GetVersion() string {
return "1.0"
}
// GetAccessKeyId returns accessKeyId
func (signer *EcsRamRoleSigner) GetAccessKeyId() (accessKeyId string, err error) {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
}
return signer.sessionCredential.AccessKeyId, nil
}
// GetExtraParam returns params in map
func (signer *EcsRamRoleSigner) GetExtraParam() map[string]string {
if signer.sessionCredential == nil {
return make(map[string]string)
}
if len(signer.sessionCredential.StsToken) <= 0 {
return make(map[string]string)
}
return map[string]string{"SecurityToken": signer.sessionCredential.StsToken}
}
// Sign creates a signer
func (signer *EcsRamRoleSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeyId + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *EcsRamRoleSigner) buildCommonRequest() (request *requests.CommonRequest, err error) {
request = requests.NewCommonRequest()
return
}
func (signer *EcsRamRoleSigner) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
requestUrl := "http://100.100.100.200/latest/meta-data/ram/security-credentials/" + signer.credential.RoleName
httpRequest, err := http.NewRequest(requests.GET, requestUrl, strings.NewReader(""))
if err != nil {
fmt.Println("refresh Ecs sts token err", err)
return
}
httpClient := &http.Client{}
httpResponse, err := httpClient.Do(httpRequest)
if err != nil {
fmt.Println("refresh Ecs sts token err", err)
return
}
response = responses.NewCommonResponse()
err = responses.Unmarshal(response, httpResponse, "")
return
}
func (signer *EcsRamRoleSigner) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
fmt.Println("refresh Ecs sts token err, httpStatus: " + string(response.GetHttpStatus()) + ", message = " + response.GetHttpContentString())
return
}
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
fmt.Println("refresh Ecs sts token err, json.Unmarshal fail", err)
return
}
code, err := jmespath.Search("Code", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get Code", err)
return
}
if code.(string) != "Success" {
fmt.Println("refresh Ecs sts token err, Code is not Success", err)
return
}
accessKeyId, err := jmespath.Search("AccessKeyId", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get AccessKeyId", err)
return
}
accessKeySecret, err := jmespath.Search("AccessKeySecret", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get AccessKeySecret", err)
return
}
securityToken, err := jmespath.Search("SecurityToken", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get SecurityToken", err)
return
}
expiration, err := jmespath.Search("Expiration", data)
if err != nil {
fmt.Println("refresh Ecs sts token err, fail to get Expiration", err)
return
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
return
}
expirationTime, err := time.Parse("2006-01-02T15:04:05Z", expiration.(string))
signer.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix())
signer.sessionCredential = &SessionCredential{
AccessKeyId: accessKeyId.(string),
AccessKeySecret: accessKeySecret.(string),
StsToken: securityToken.(string),
}
return
}
// GetSessionCredential returns SessionCredential
func (signer *EcsRamRoleSigner) GetSessionCredential() *SessionCredential {
return signer.sessionCredential
}
// Shutdown doesn't implement
func (signer *EcsRamRoleSigner) Shutdown() {}

View File

@ -0,0 +1,157 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"encoding/json"
"fmt"
"github.com/jmespath/go-jmespath"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"net/http"
"strconv"
)
// SignerKeyPair is kind of signer
type SignerKeyPair struct {
*credentialUpdater
sessionCredential *SessionCredential
credential *credentials.RsaKeyPairCredential
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
// NewSignerKeyPair returns SignerKeyPair
func NewSignerKeyPair(credential *credentials.RsaKeyPairCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *SignerKeyPair, err error) {
signer = &SignerKeyPair{
credential: credential,
commonApi: commonApi,
}
signer.credentialUpdater = &credentialUpdater{
credentialExpiration: credential.SessionExpiration,
buildRequestMethod: signer.buildCommonRequest,
responseCallBack: signer.refreshCredential,
refreshApi: signer.refreshApi,
}
if credential.SessionExpiration > 0 {
if credential.SessionExpiration >= 900 && credential.SessionExpiration <= 3600 {
signer.credentialExpiration = credential.SessionExpiration
} else {
err = errors.NewClientError(errors.InvalidParamErrorCode, "Key Pair session duration should be in the range of 15min - 1Hr", nil)
}
} else {
signer.credentialExpiration = defaultDurationSeconds
}
return
}
// GetName returns "HMAC-SHA1"
func (*SignerKeyPair) GetName() string {
return "HMAC-SHA1"
}
// GetType returns ""
func (*SignerKeyPair) GetType() string {
return ""
}
// GetVersion returns "1.0"
func (*SignerKeyPair) GetVersion() string {
return "1.0"
}
// GetAccessKeyId returns accessKeyId
func (signer *SignerKeyPair) GetAccessKeyId() (accessKeyId string, err error) {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
}
return signer.sessionCredential.AccessKeyId, err
}
// GetExtraParam returns params
func (signer *SignerKeyPair) GetExtraParam() map[string]string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
signer.updateCredential()
}
if signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0 {
return make(map[string]string)
}
return make(map[string]string)
}
// Sign create signer
func (signer *SignerKeyPair) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeyId + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *SignerKeyPair) buildCommonRequest() (request *requests.CommonRequest, err error) {
request = requests.NewCommonRequest()
request.Product = "Sts"
request.Version = "2015-04-01"
request.ApiName = "GenerateSessionAccessKey"
request.Scheme = requests.HTTPS
request.QueryParams["PublicKeyId"] = signer.credential.PublicKeyId
request.QueryParams["DurationSeconds"] = strconv.Itoa(signer.credentialExpiration)
return
}
func (signer *SignerKeyPair) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
signerV2, err := NewSignerV2(signer.credential)
return signer.commonApi(request, signerV2)
}
func (signer *SignerKeyPair) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
message := "refresh session AccessKey failed"
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), message)
return
}
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
fmt.Println("refresh KeyPair err, json.Unmarshal fail", err)
return
}
accessKeyId, err := jmespath.Search("SessionAccessKey.SessionAccessKeyId", data)
if err != nil {
fmt.Println("refresh KeyPair err, fail to get SessionAccessKeyId", err)
return
}
accessKeySecret, err := jmespath.Search("SessionAccessKey.SessionAccessKeySecret", data)
if err != nil {
fmt.Println("refresh KeyPair err, fail to get SessionAccessKeySecret", err)
return
}
if accessKeyId == nil || accessKeySecret == nil {
return
}
signer.sessionCredential = &SessionCredential{
AccessKeyId: accessKeyId.(string),
AccessKeySecret: accessKeySecret.(string),
}
return
}
// Shutdown doesn't implement
func (signer *SignerKeyPair) Shutdown() {}

View File

@ -0,0 +1,184 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"encoding/json"
"fmt"
"github.com/jmespath/go-jmespath"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"net/http"
"strconv"
"time"
)
const (
defaultDurationSeconds = 3600
)
// RamRoleArnSigner is kind of signer
type RamRoleArnSigner struct {
*credentialUpdater
roleSessionName string
sessionCredential *SessionCredential
credential *credentials.RamRoleArnCredential
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
// NewRamRoleArnSigner returns RamRoleArnSigner
func NewRamRoleArnSigner(credential *credentials.RamRoleArnCredential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer *RamRoleArnSigner, err error) {
signer = &RamRoleArnSigner{
credential: credential,
commonApi: commonApi,
}
signer.credentialUpdater = &credentialUpdater{
credentialExpiration: credential.RoleSessionExpiration,
buildRequestMethod: signer.buildCommonRequest,
responseCallBack: signer.refreshCredential,
refreshApi: signer.refreshApi,
}
if len(credential.RoleSessionName) > 0 {
signer.roleSessionName = credential.RoleSessionName
} else {
signer.roleSessionName = "aliyun-go-sdk-" + strconv.FormatInt(time.Now().UnixNano()/1000, 10)
}
if credential.RoleSessionExpiration > 0 {
if credential.RoleSessionExpiration >= 900 && credential.RoleSessionExpiration <= 3600 {
signer.credentialExpiration = credential.RoleSessionExpiration
} else {
err = errors.NewClientError(errors.InvalidParamErrorCode, "Assume Role session duration should be in the range of 15min - 1Hr", nil)
}
} else {
signer.credentialExpiration = defaultDurationSeconds
}
return
}
// GetName returns "HMAC-SHA1"
func (*RamRoleArnSigner) GetName() string {
return "HMAC-SHA1"
}
// GetType returns ""
func (*RamRoleArnSigner) GetType() string {
return ""
}
// GetVersion returns "1.0"
func (*RamRoleArnSigner) GetVersion() string {
return "1.0"
}
// GetAccessKeyId returns accessKeyId
func (signer *RamRoleArnSigner) GetAccessKeyId() (accessKeyId string, err error) {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
}
return signer.sessionCredential.AccessKeyId, nil
}
// GetExtraParam returns params
func (signer *RamRoleArnSigner) GetExtraParam() map[string]string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
signer.updateCredential()
}
if signer.sessionCredential == nil || len(signer.sessionCredential.StsToken) <= 0 {
return make(map[string]string)
}
return map[string]string{"SecurityToken": signer.sessionCredential.StsToken}
}
// Sign create signer
func (signer *RamRoleArnSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *RamRoleArnSigner) buildCommonRequest() (request *requests.CommonRequest, err error) {
request = requests.NewCommonRequest()
request.Product = "Sts"
request.Version = "2015-04-01"
request.ApiName = "AssumeRole"
request.Scheme = requests.HTTPS
request.QueryParams["RoleArn"] = signer.credential.RoleArn
request.QueryParams["RoleSessionName"] = signer.credential.RoleSessionName
request.QueryParams["DurationSeconds"] = strconv.Itoa(signer.credentialExpiration)
return
}
func (signer *RamRoleArnSigner) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
credential := &credentials.AccessKeyCredential{
AccessKeyId: signer.credential.AccessKeyId,
AccessKeySecret: signer.credential.AccessKeySecret,
}
signerV1, err := NewAccessKeySigner(credential)
return signer.commonApi(request, signerV1)
}
func (signer *RamRoleArnSigner) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
message := "refresh session token failed"
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), message)
return
}
var data interface{}
err = json.Unmarshal(response.GetHttpContentBytes(), &data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, json.Unmarshal fail", err)
return
}
accessKeyId, err := jmespath.Search("Credentials.AccessKeyId", data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, fail to get AccessKeyId", err)
return
}
accessKeySecret, err := jmespath.Search("Credentials.AccessKeySecret", data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, fail to get AccessKeySecret", err)
return
}
securityToken, err := jmespath.Search("Credentials.SecurityToken", data)
if err != nil {
fmt.Println("refresh RoleArn sts token err, fail to get SecurityToken", err)
return
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
return
}
signer.sessionCredential = &SessionCredential{
AccessKeyId: accessKeyId.(string),
AccessKeySecret: accessKeySecret.(string),
StsToken: securityToken.(string),
}
return
}
// GetSessionCredential returns SessionCredential
func (signer *RamRoleArnSigner) GetSessionCredential() *SessionCredential {
return signer.sessionCredential
}
// Shutdown doesn't implement
func (signer *RamRoleArnSigner) Shutdown() {}

View File

@ -0,0 +1,67 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
// StsTokenSigner is kind of Signer
type StsTokenSigner struct {
credential *credentials.StsTokenCredential
}
// NewStsTokenSigner returns StsTokenSigner
func NewStsTokenSigner(credential *credentials.StsTokenCredential) (*StsTokenSigner, error) {
return &StsTokenSigner{
credential: credential,
}, nil
}
// GetName returns "HMAC-SHA1"
func (*StsTokenSigner) GetName() string {
return "HMAC-SHA1"
}
// GetType returns ""
func (*StsTokenSigner) GetType() string {
return ""
}
// GetVersion returns ""
func (*StsTokenSigner) GetVersion() string {
return "1.0"
}
// GetAccessKeyId returns accessKeyId
func (signer *StsTokenSigner) GetAccessKeyId() (accessKeyId string, err error) {
return signer.credential.AccessKeyId, nil
}
// GetExtraParam returns params
func (signer *StsTokenSigner) GetExtraParam() map[string]string {
return map[string]string{"SecurityToken": signer.credential.AccessKeyStsToken}
}
// Sign creates signer
func (signer *StsTokenSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
// Shutdown doesn't implement
func (signer *StsTokenSigner) Shutdown() {}

View File

@ -0,0 +1,67 @@
/*
Copyright 2018 The Kubernetes Authors.
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 signers
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
// SignerV2 is wrapper of credential
type SignerV2 struct {
credential *credentials.RsaKeyPairCredential
}
// GetExtraParam returns params
func (signer *SignerV2) GetExtraParam() map[string]string {
return nil
}
// NewSignerV2 returns SignerV2
func NewSignerV2(credential *credentials.RsaKeyPairCredential) (*SignerV2, error) {
return &SignerV2{
credential: credential,
}, nil
}
// GetName returns "SHA256withRSA"
func (*SignerV2) GetName() string {
return "SHA256withRSA"
}
// GetType returns "PRIVATEKEY"
func (*SignerV2) GetType() string {
return "PRIVATEKEY"
}
// GetVersion returns "1.0"
func (*SignerV2) GetVersion() string {
return "1.0"
}
// GetAccessKeyId returns accessKeyId
func (signer *SignerV2) GetAccessKeyId() (accessKeyId string, err error) {
return signer.credential.PublicKeyId, err
}
// Sign create signer
func (signer *SignerV2) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.PrivateKey
return Sha256WithRsa(stringToSign, secret)
}
// Shutdown doesn't implement
func (signer *SignerV2) Shutdown() {}

View File

@ -0,0 +1,442 @@
/*
Copyright 2018 The Kubernetes Authors.
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 sdk
import (
"fmt"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth/credentials"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/endpoints"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"net"
"net/http"
"strconv"
"sync"
)
// Version value will be replaced while build: -ldflags="-X sdk.version=x.x.x"
var Version = "0.0.1"
// Client is common SDK client
type Client struct {
regionId string
config *Config
signer auth.Signer
httpClient *http.Client
asyncTaskQueue chan func()
debug bool
isRunning bool
// void "panic(write to close channel)" cause of addAsync() after Shutdown()
asyncChanLock *sync.RWMutex
}
// Init not support yet
func (client *Client) Init() (err error) {
panic("not support yet")
}
// InitWithOptions provide options such as regionId and auth
func (client *Client) InitWithOptions(regionId string, config *Config, credential auth.Credential) (err error) {
client.isRunning = true
client.asyncChanLock = new(sync.RWMutex)
client.regionId = regionId
client.config = config
if err != nil {
return
}
client.httpClient = &http.Client{}
if config.HttpTransport != nil {
client.httpClient.Transport = config.HttpTransport
}
if config.Timeout > 0 {
client.httpClient.Timeout = config.Timeout
}
if config.EnableAsync {
client.EnableAsync(config.GoRoutinePoolSize, config.MaxTaskQueueSize)
}
client.signer, err = auth.NewSignerWithCredential(credential, client.ProcessCommonRequestWithSigner)
return
}
// EnableAsync enable async task queue
func (client *Client) EnableAsync(routinePoolSize, maxTaskQueueSize int) {
client.asyncTaskQueue = make(chan func(), maxTaskQueueSize)
for i := 0; i < routinePoolSize; i++ {
go func() {
for client.isRunning {
select {
case task, notClosed := <-client.asyncTaskQueue:
if notClosed {
task()
}
}
}
}()
}
}
// InitWithAccessKey need accessKeyId and accessKeySecret
func (client *Client) InitWithAccessKey(regionId, accessKeyId, accessKeySecret string) (err error) {
config := client.InitClientConfig()
credential := &credentials.BaseCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
}
return client.InitWithOptions(regionId, config, credential)
}
// InitWithStsToken need regionId,accessKeyId,accessKeySecret and securityToken
func (client *Client) InitWithStsToken(regionId, accessKeyId, accessKeySecret, securityToken string) (err error) {
config := client.InitClientConfig()
credential := &credentials.StsTokenCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
AccessKeyStsToken: securityToken,
}
return client.InitWithOptions(regionId, config, credential)
}
// InitWithRamRoleArn need regionId,accessKeyId,accessKeySecret,roleArn and roleSessionName
func (client *Client) InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (err error) {
config := client.InitClientConfig()
credential := &credentials.RamRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
}
return client.InitWithOptions(regionId, config, credential)
}
// InitWithRsaKeyPair need key pair
func (client *Client) InitWithRsaKeyPair(regionId, publicKeyId, privateKey string, sessionExpiration int) (err error) {
config := client.InitClientConfig()
credential := &credentials.RsaKeyPairCredential{
PrivateKey: privateKey,
PublicKeyId: publicKeyId,
SessionExpiration: sessionExpiration,
}
return client.InitWithOptions(regionId, config, credential)
}
// InitWithEcsRamRole need regionId and roleName
func (client *Client) InitWithEcsRamRole(regionId, roleName string) (err error) {
config := client.InitClientConfig()
credential := &credentials.EcsRamRoleCredential{
RoleName: roleName,
}
return client.InitWithOptions(regionId, config, credential)
}
// InitClientConfig init client config
func (client *Client) InitClientConfig() (config *Config) {
if client.config != nil {
return client.config
}
return NewConfig()
}
// DoAction do request to open api
func (client *Client) DoAction(request requests.AcsRequest, response responses.AcsResponse) (err error) {
return client.DoActionWithSigner(request, response, nil)
}
// BuildRequestWithSigner build request signer
func (client *Client) BuildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (err error) {
// add clientVersion
request.GetHeaders()["x-sdk-core-version"] = Version
regionId := client.regionId
if len(request.GetRegionId()) > 0 {
regionId = request.GetRegionId()
}
// resolve endpoint
resolveParam := &endpoints.ResolveParam{
Domain: request.GetDomain(),
Product: request.GetProduct(),
RegionId: regionId,
LocationProduct: request.GetLocationServiceCode(),
LocationEndpointType: request.GetLocationEndpointType(),
CommonApi: client.ProcessCommonRequest,
}
endpoint, err := endpoints.Resolve(resolveParam)
if err != nil {
return
}
request.SetDomain(endpoint)
// init request params
err = requests.InitParams(request)
if err != nil {
return
}
// signature
var finalSigner auth.Signer
if signer != nil {
finalSigner = signer
} else {
finalSigner = client.signer
}
httpRequest, err := buildHttpRequest(request, finalSigner, regionId)
if client.config.UserAgent != "" {
httpRequest.Header.Set("User-Agent", client.config.UserAgent)
}
return err
}
// DoActionWithSigner do action with signer
func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
// add clientVersion
request.GetHeaders()["x-sdk-core-version"] = Version
regionId := client.regionId
if len(request.GetRegionId()) > 0 {
regionId = request.GetRegionId()
}
// resolve endpoint
resolveParam := &endpoints.ResolveParam{
Domain: request.GetDomain(),
Product: request.GetProduct(),
RegionId: regionId,
LocationProduct: request.GetLocationServiceCode(),
LocationEndpointType: request.GetLocationEndpointType(),
CommonApi: client.ProcessCommonRequest,
}
endpoint, err := endpoints.Resolve(resolveParam)
if err != nil {
return
}
request.SetDomain(endpoint)
if request.GetScheme() == "" {
request.SetScheme(client.config.Scheme)
}
// init request params
err = requests.InitParams(request)
if err != nil {
return
}
// signature
var finalSigner auth.Signer
if signer != nil {
finalSigner = signer
} else {
finalSigner = client.signer
}
httpRequest, err := buildHttpRequest(request, finalSigner, regionId)
if client.config.UserAgent != "" {
httpRequest.Header.Set("User-Agent", client.config.UserAgent)
}
if err != nil {
return
}
var httpResponse *http.Response
for retryTimes := 0; retryTimes <= client.config.MaxRetryTime; retryTimes++ {
httpResponse, err = client.httpClient.Do(httpRequest)
var timeout bool
// receive error
if err != nil {
if !client.config.AutoRetry {
return
} else if timeout = isTimeout(err); !timeout {
// if not timeout error, return
return
} else if retryTimes >= client.config.MaxRetryTime {
// timeout but reached the max retry times, return
timeoutErrorMsg := fmt.Sprintf(errors.TimeoutErrorMessage, strconv.Itoa(retryTimes+1), strconv.Itoa(retryTimes+1))
err = errors.NewClientError(errors.TimeoutErrorCode, timeoutErrorMsg, err)
return
}
}
// if status code >= 500 or timeout, will trigger retry
if client.config.AutoRetry && (timeout || isServerError(httpResponse)) {
// rewrite signatureNonce and signature
httpRequest, err = buildHttpRequest(request, finalSigner, regionId)
if err != nil {
return
}
continue
}
break
}
err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
// wrap server errors
if serverErr, ok := err.(*errors.ServerError); ok {
var wrapInfo = map[string]string{}
wrapInfo["StringToSign"] = request.GetStringToSign()
err = errors.WrapServerError(serverErr, wrapInfo)
}
return
}
func buildHttpRequest(request requests.AcsRequest, singer auth.Signer, regionId string) (httpRequest *http.Request, err error) {
err = auth.Sign(request, singer, regionId)
if err != nil {
return
}
requestMethod := request.GetMethod()
requestUrl := request.BuildUrl()
body := request.GetBodyReader()
httpRequest, err = http.NewRequest(requestMethod, requestUrl, body)
if err != nil {
return
}
for key, value := range request.GetHeaders() {
httpRequest.Header[key] = []string{value}
}
// host is a special case
if host, containsHost := request.GetHeaders()["Host"]; containsHost {
httpRequest.Host = host
}
return
}
func isTimeout(err error) bool {
if err == nil {
return false
}
netErr, isNetError := err.(net.Error)
return isNetError && netErr.Timeout()
}
func isServerError(httpResponse *http.Response) bool {
return httpResponse.StatusCode >= http.StatusInternalServerError
}
// AddAsyncTask create async task
// only block when any one of the following occurs:
// 1. the asyncTaskQueue is full, increase the queue size to avoid this
// 2. Shutdown() in progressing, the client is being closed
func (client *Client) AddAsyncTask(task func()) (err error) {
if client.asyncTaskQueue != nil {
client.asyncChanLock.RLock()
defer client.asyncChanLock.RUnlock()
if client.isRunning {
client.asyncTaskQueue <- task
}
} else {
err = errors.NewClientError(errors.AsyncFunctionNotEnabledCode, errors.AsyncFunctionNotEnabledMessage, nil)
}
return
}
// GetConfig return client config
func (client *Client) GetConfig() *Config {
return client.config
}
// NewClient return SDK client
func NewClient() (client *Client, err error) {
client = &Client{}
err = client.Init()
return
}
// NewClientWithOptions create client with options
func NewClientWithOptions(regionId string, config *Config, credential auth.Credential) (client *Client, err error) {
client = &Client{}
err = client.InitWithOptions(regionId, config, credential)
return
}
// NewClientWithAccessKey create client with accessKeyId and accessKeySecret
func NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret string) (client *Client, err error) {
client = &Client{}
err = client.InitWithAccessKey(regionId, accessKeyId, accessKeySecret)
return
}
// NewClientWithStsToken create client with stsToken
func NewClientWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken string) (client *Client, err error) {
client = &Client{}
err = client.InitWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken)
return
}
// NewClientWithRamRoleArn create client with ramRoleArn
func NewClientWithRamRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
return
}
// NewClientWithEcsRamRole create client with ramRole on ECS
func NewClientWithEcsRamRole(regionId string, roleName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithEcsRamRole(regionId, roleName)
return
}
// NewClientWithRsaKeyPair create client with key-pair
func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, sessionExpiration int) (client *Client, err error) {
client = &Client{}
err = client.InitWithRsaKeyPair(regionId, publicKeyId, privateKey, sessionExpiration)
return
}
// NewClientWithStsRoleArn is deprecated: Use NewClientWithRamRoleArn in this package instead.
func NewClientWithStsRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
return NewClientWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
}
// NewClientWithStsRoleNameOnEcs is deprecated: Use NewClientWithEcsRamRole in this package instead.
func NewClientWithStsRoleNameOnEcs(regionId string, roleName string) (client *Client, err error) {
return NewClientWithEcsRamRole(regionId, roleName)
}
// ProcessCommonRequest do action with common request
func (client *Client) ProcessCommonRequest(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
request.TransToAcsRequest()
response = responses.NewCommonResponse()
err = client.DoAction(request, response)
return
}
// ProcessCommonRequestWithSigner do action with common request and singer
func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonRequest, signerInterface interface{}) (response *responses.CommonResponse, err error) {
if signer, isSigner := signerInterface.(auth.Signer); isSigner {
request.TransToAcsRequest()
response = responses.NewCommonResponse()
err = client.DoActionWithSigner(request, response, signer)
return
}
panic("should not be here")
}
// Shutdown destruction of client
func (client *Client) Shutdown() {
client.signer.Shutdown()
// lock the addAsync()
client.asyncChanLock.Lock()
defer client.asyncChanLock.Unlock()
client.isRunning = false
close(client.asyncTaskQueue)
}

View File

@ -0,0 +1,98 @@
/*
Copyright 2018 The Kubernetes Authors.
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 sdk
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/utils"
"net/http"
"time"
)
// Config is SDK client options
type Config struct {
AutoRetry bool `default:"true"`
MaxRetryTime int `default:"3"`
UserAgent string `default:""`
Debug bool `default:"false"`
Timeout time.Duration `default:"10000000000"`
HttpTransport *http.Transport `default:""`
EnableAsync bool `default:"false"`
MaxTaskQueueSize int `default:"1000"`
GoRoutinePoolSize int `default:"5"`
Scheme string `default:"HTTP"`
}
// NewConfig returns client config
func NewConfig() (config *Config) {
config = &Config{}
utils.InitStructWithDefaultTag(config)
return
}
// WithTimeout set client timeout
func (c *Config) WithTimeout(timeout time.Duration) *Config {
c.Timeout = timeout
return c
}
// WithAutoRetry set client with retry
func (c *Config) WithAutoRetry(isAutoRetry bool) *Config {
c.AutoRetry = isAutoRetry
return c
}
// WithMaxRetryTime set client with max retry times
func (c *Config) WithMaxRetryTime(maxRetryTime int) *Config {
c.MaxRetryTime = maxRetryTime
return c
}
// WithUserAgent set client user agent
func (c *Config) WithUserAgent(userAgent string) *Config {
c.UserAgent = userAgent
return c
}
// WithHttpTransport set client custom http transport
func (c *Config) WithHttpTransport(httpTransport *http.Transport) *Config {
c.HttpTransport = httpTransport
return c
}
// WithEnableAsync enable client async option
func (c *Config) WithEnableAsync(isEnableAsync bool) *Config {
c.EnableAsync = isEnableAsync
return c
}
// WithMaxTaskQueueSize set client max task queue size
func (c *Config) WithMaxTaskQueueSize(maxTaskQueueSize int) *Config {
c.MaxTaskQueueSize = maxTaskQueueSize
return c
}
// WithGoRoutinePoolSize set client go routine pool size
func (c *Config) WithGoRoutinePoolSize(goRoutinePoolSize int) *Config {
c.GoRoutinePoolSize = goRoutinePoolSize
return c
}
// WithDebug set client debug mode
func (c *Config) WithDebug(isDebug bool) *Config {
c.Debug = isDebug
return c
}

View File

@ -0,0 +1,521 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
import (
"encoding/json"
"fmt"
"sync"
)
const endpointsJson = "{" +
" \"products\":[" +
" {" +
" \"code\": \"aegis\"," +
" \"document_id\": \"28449\"," +
" \"location_service_code\": \"vipaegis\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"aegis.cn-hangzhou.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"alidns\"," +
" \"document_id\": \"29739\"," +
" \"location_service_code\": \"alidns\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"alidns.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"arms\"," +
" \"document_id\": \"42924\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-southeast-1\"," +
" \"endpoint\": \"arms.ap-southeast-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"arms.cn-beijing.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"arms.cn-hangzhou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hongkong\"," +
" \"endpoint\": \"arms.cn-hongkong.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-qingdao\"," +
" \"endpoint\": \"arms.cn-qingdao.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"arms.cn-shanghai.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shenzhen\"," +
" \"endpoint\": \"arms.cn-shenzhen.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"arms.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"batchcompute\"," +
" \"document_id\": \"44717\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-southeast-1\"," +
" \"endpoint\": \"batchcompute.ap-southeast-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"batchcompute.cn-beijing.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"batchcompute.cn-hangzhou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-huhehaote\"," +
" \"endpoint\": \"batchcompute.cn-huhehaote.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-qingdao\"," +
" \"endpoint\": \"batchcompute.cn-qingdao.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"batchcompute.cn-shanghai.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shenzhen\"," +
" \"endpoint\": \"batchcompute.cn-shenzhen.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-zhangjiakou\"," +
" \"endpoint\": \"batchcompute.cn-zhangjiakou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-west-1\"," +
" \"endpoint\": \"batchcompute.us-west-1.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"batchcompute.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"ccc\"," +
" \"document_id\": \"63027\"," +
" \"location_service_code\": \"ccc\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"ccc.cn-hangzhou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"ccc.cn-shanghai.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"ccc.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cdn\"," +
" \"document_id\": \"27148\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cdn.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cds\"," +
" \"document_id\": \"62887\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cds.cn-beijing.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"chatbot\"," +
" \"document_id\": \"60760\"," +
" \"location_service_code\": \"beebot\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"chatbot.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cloudapi\"," +
" \"document_id\": \"43590\"," +
" \"location_service_code\": \"apigateway\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-northeast-1\"," +
" \"endpoint\": \"apigateway.ap-northeast-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-west-1\"," +
" \"endpoint\": \"apigateway.us-west-1.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"apigateway.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cloudauth\"," +
" \"document_id\": \"60687\"," +
" \"location_service_code\": \"cloudauth\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cloudauth.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cloudphoto\"," +
" \"document_id\": \"59902\"," +
" \"location_service_code\": \"cloudphoto\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"cloudphoto.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cloudwf\"," +
" \"document_id\": \"58111\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cloudwf.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cms\"," +
" \"document_id\": \"28615\"," +
" \"location_service_code\": \"cms\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cr\"," +
" \"document_id\": \"60716\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cr.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cs\"," +
" \"document_id\": \"26043\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cs.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"csb\"," +
" \"document_id\": \"64837\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"csb.cn-beijing.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"csb.cn-hangzhou.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"csb.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"dds\"," +
" \"document_id\": \"61715\"," +
" \"location_service_code\": \"dds\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"mongodb.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"mongodb.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"dm\"," +
" \"document_id\": \"29434\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-southeast-1\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"ap-southeast-2\"," +
" \"endpoint\": \"dm.ap-southeast-2.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hongkong\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-qingdao\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shenzhen\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-east-1\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-west-1\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"dm.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"dm.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"domain\"," +
" \"document_id\": \"42875\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"domain.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"domain.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"domain-intl\"," +
" \"document_id\": \"\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"domain-intl.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"domain-intl.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"drds\"," +
" \"document_id\": \"51111\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"drds.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"drds.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"ecs\"," +
" \"document_id\": \"25484\"," +
" \"location_service_code\": \"ecs\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"emr\"," +
" \"document_id\": \"28140\"," +
" \"location_service_code\": \"emr\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"emr.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"ess\"," +
" \"document_id\": \"25925\"," +
" \"location_service_code\": \"ess\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"ess.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"green\"," +
" \"document_id\": \"28427\"," +
" \"location_service_code\": \"green\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"green.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"hpc\"," +
" \"document_id\": \"35201\"," +
" \"location_service_code\": \"hpc\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"hpc.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"httpdns\"," +
" \"document_id\": \"52679\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"httpdns-api.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"iot\"," +
" \"document_id\": \"30557\"," +
" \"location_service_code\": \"iot\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"iot.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"itaas\"," +
" \"document_id\": \"55759\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"itaas.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"jaq\"," +
" \"document_id\": \"35037\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"jaq.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"live\"," +
" \"document_id\": \"48207\"," +
" \"location_service_code\": \"live\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"live.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"mts\"," +
" \"document_id\": \"29212\"," +
" \"location_service_code\": \"mts\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"nas\"," +
" \"document_id\": \"62598\"," +
" \"location_service_code\": \"nas\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"ons\"," +
" \"document_id\": \"44416\"," +
" \"location_service_code\": \"ons\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"polardb\"," +
" \"document_id\": \"58764\"," +
" \"location_service_code\": \"polardb\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-south-1\"," +
" \"endpoint\": \"polardb.ap-south-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"ap-southeast-5\"," +
" \"endpoint\": \"polardb.ap-southeast-5.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"polardb.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"push\"," +
" \"document_id\": \"30074\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cloudpush.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"qualitycheck\"," +
" \"document_id\": \"50807\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"qualitycheck.cn-hangzhou.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"r-kvstore\"," +
" \"document_id\": \"60831\"," +
" \"location_service_code\": \"redisa\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"ram\"," +
" \"document_id\": \"28672\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"ram.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"rds\"," +
" \"document_id\": \"26223\"," +
" \"location_service_code\": \"rds\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"ros\"," +
" \"document_id\": \"28899\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"ros.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"sas-api\"," +
" \"document_id\": \"28498\"," +
" \"location_service_code\": \"sas\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"slb\"," +
" \"document_id\": \"27565\"," +
" \"location_service_code\": \"slb\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"sts\"," +
" \"document_id\": \"28756\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"sts.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"vod\"," +
" \"document_id\": \"60574\"," +
" \"location_service_code\": \"vod\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"vpc\"," +
" \"document_id\": \"34962\"," +
" \"location_service_code\": \"vpc\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"waf\"," +
" \"document_id\": \"62847\"," +
" \"location_service_code\": \"waf\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }]" +
"}"
var initOnce sync.Once
var data interface{}
func getEndpointConfigData() interface{} {
initOnce.Do(func() {
err := json.Unmarshal([]byte(endpointsJson), &data)
if err != nil {
fmt.Println("init endpoint config data failed.", err)
}
})
return data
}

View File

@ -0,0 +1,40 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
import (
"fmt"
"github.com/jmespath/go-jmespath"
"strings"
)
// LocalGlobalResolver is global resolver
type LocalGlobalResolver struct{}
// TryResolve returns endpoint
func (resolver *LocalGlobalResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
// get the global endpoints configs
endpointExpression := fmt.Sprintf("products[?code=='%s'].global_endpoint", strings.ToLower(param.Product))
endpointData, err := jmespath.Search(endpointExpression, getEndpointConfigData())
if err == nil && endpointData != nil && len(endpointData.([]interface{})) > 0 {
endpoint = endpointData.([]interface{})[0].(string)
support = len(endpoint) > 0
return endpoint, support, nil
}
support = false
return
}

View File

@ -0,0 +1,44 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
import (
"fmt"
"github.com/jmespath/go-jmespath"
"strings"
)
// LocalRegionalResolver is regional resolver
type LocalRegionalResolver struct{}
// TryResolve returns endpoint
func (resolver *LocalRegionalResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
// get the regional endpoints configs
regionalExpression := fmt.Sprintf("products[?code=='%s'].regional_endpoints", strings.ToLower(param.Product))
regionalData, err := jmespath.Search(regionalExpression, getEndpointConfigData())
if err == nil && regionalData != nil && len(regionalData.([]interface{})) > 0 {
endpointExpression := fmt.Sprintf("[0][?region=='%s'].endpoint", strings.ToLower(param.RegionId))
endpointData, err := jmespath.Search(endpointExpression, regionalData)
if err == nil && endpointData != nil && len(endpointData.([]interface{})) > 0 {
endpoint = endpointData.([]interface{})[0].(string)
support = len(endpoint) > 0
return endpoint, support, nil
}
}
support = false
return
}

View File

@ -0,0 +1,148 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
import (
"encoding/json"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"sync"
"time"
)
const (
// EndpointCacheExpireTime in seconds
EndpointCacheExpireTime = 3600
)
var lastClearTimePerProduct = struct {
sync.RWMutex
cache map[string]int64
}{cache: make(map[string]int64)}
var endpointCache = struct {
sync.RWMutex
cache map[string]string
}{cache: make(map[string]string)}
// LocationResolver is kind of resolver
type LocationResolver struct{}
// TryResolve return endpoint
func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
if len(param.LocationProduct) <= 0 {
support = false
return
}
//get from cache
cacheKey := param.Product + "#" + param.RegionId
if endpointCache.cache != nil && len(endpointCache.cache[cacheKey]) > 0 && !CheckCacheIsExpire(cacheKey) {
endpoint = endpointCache.cache[cacheKey]
support = true
return
}
//get from remote
getEndpointRequest := requests.NewCommonRequest()
getEndpointRequest.Product = "Location"
getEndpointRequest.Version = "2015-06-12"
getEndpointRequest.ApiName = "DescribeEndpoints"
getEndpointRequest.Domain = "location.aliyuncs.com"
getEndpointRequest.Method = "GET"
getEndpointRequest.Scheme = requests.HTTPS
getEndpointRequest.QueryParams["Id"] = param.RegionId
getEndpointRequest.QueryParams["ServiceCode"] = param.LocationProduct
if len(param.LocationEndpointType) > 0 {
getEndpointRequest.QueryParams["Type"] = param.LocationEndpointType
} else {
getEndpointRequest.QueryParams["Type"] = "openAPI"
}
response, err := param.CommonApi(getEndpointRequest)
var getEndpointResponse GetEndpointResponse
if !response.IsSuccess() {
support = false
return
}
json.Unmarshal([]byte(response.GetHttpContentString()), &getEndpointResponse)
if !getEndpointResponse.Success || getEndpointResponse.Endpoints == nil {
support = false
return
}
if len(getEndpointResponse.Endpoints.Endpoint) <= 0 {
support = false
return
}
if len(getEndpointResponse.Endpoints.Endpoint[0].Endpoint) > 0 {
endpoint = getEndpointResponse.Endpoints.Endpoint[0].Endpoint
endpointCache.Lock()
endpointCache.cache[cacheKey] = endpoint
endpointCache.Unlock()
lastClearTimePerProduct.Lock()
lastClearTimePerProduct.cache[cacheKey] = time.Now().Unix()
lastClearTimePerProduct.Unlock()
support = true
return
}
support = false
return
}
// CheckCacheIsExpire valid the cacheKey
func CheckCacheIsExpire(cacheKey string) bool {
lastClearTime := lastClearTimePerProduct.cache[cacheKey]
if lastClearTime <= 0 {
lastClearTime = time.Now().Unix()
lastClearTimePerProduct.Lock()
lastClearTimePerProduct.cache[cacheKey] = lastClearTime
lastClearTimePerProduct.Unlock()
}
now := time.Now().Unix()
elapsedTime := now - lastClearTime
if elapsedTime > EndpointCacheExpireTime {
return true
}
return false
}
// GetEndpointResponse returns Endpoints
type GetEndpointResponse struct {
Endpoints *EndpointsObj
RequestId string
Success bool
}
// EndpointsObj wrapper Endpoint array
type EndpointsObj struct {
Endpoint []EndpointObj
}
// EndpointObj wrapper endpoint
type EndpointObj struct {
Protocols map[string]string
Type string
Namespace string
Id string
SerivceCode string
Endpoint string
}

View File

@ -0,0 +1,43 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
import (
"fmt"
"strings"
)
const keyFormatter = "%s::%s"
var endpointMapping = make(map[string]string)
// AddEndpointMapping adds endpoint to cache
func AddEndpointMapping(regionId, productId, endpoint string) (err error) {
key := fmt.Sprintf(keyFormatter, strings.ToLower(regionId), strings.ToLower(productId))
endpointMapping[key] = endpoint
return nil
}
// MappingResolver is kind of resolver
type MappingResolver struct{}
// TryResolve returns endpoint
func (resolver *MappingResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
key := fmt.Sprintf(keyFormatter, strings.ToLower(param.RegionId), strings.ToLower(param.Product))
endpoint, contains := endpointMapping[key]
return endpoint, contains, nil
}

View File

@ -0,0 +1,87 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
import (
"encoding/json"
"fmt"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
"sync"
)
const (
// ResolveEndpointUserGuideLink returns guide link
ResolveEndpointUserGuideLink = ""
)
var once sync.Once
var resolvers []Resolver
// Resolver interface
type Resolver interface {
TryResolve(param *ResolveParam) (endpoint string, support bool, err error)
}
// Resolve returns endpoint
func Resolve(param *ResolveParam) (endpoint string, err error) {
supportedResolvers := getAllResolvers()
for _, resolver := range supportedResolvers {
endpoint, supported, err := resolver.TryResolve(param)
if supported {
return endpoint, err
}
}
// not support
errorMsg := fmt.Sprintf(errors.CanNotResolveEndpointErrorMessage, param, ResolveEndpointUserGuideLink)
err = errors.NewClientError(errors.CanNotResolveEndpointErrorCode, errorMsg, nil)
return
}
func getAllResolvers() []Resolver {
once.Do(func() {
resolvers = []Resolver{
&SimpleHostResolver{},
&MappingResolver{},
&LocationResolver{},
&LocalRegionalResolver{},
&LocalGlobalResolver{},
}
})
return resolvers
}
// ResolveParam params to resolve endpoint
type ResolveParam struct {
Domain string
Product string
RegionId string
LocationProduct string
LocationEndpointType string
CommonApi func(request *requests.CommonRequest) (response *responses.CommonResponse, err error) `json:"-"`
}
// String returns json string
func (param *ResolveParam) String() string {
jsonBytes, err := json.Marshal(param)
if err != nil {
return fmt.Sprint("ResolveParam.String() process error:", err)
}
return string(jsonBytes)
}

View File

@ -0,0 +1,28 @@
/*
Copyright 2018 The Kubernetes Authors.
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 endpoints
// SimpleHostResolver is kind of resolver
type SimpleHostResolver struct{}
// TryResolve returns endpoint
func (resolver *SimpleHostResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
if support = len(param.Domain) > 0; support {
endpoint = param.Domain
}
return
}

View File

@ -0,0 +1,102 @@
/*
Copyright 2018 The Kubernetes Authors.
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 errors
import "fmt"
/* const code and msg */
const (
DefaultClientErrorStatus = 400
DefaultClientErrorCode = "SDK.ClientError"
UnsupportedCredentialErrorCode = "SDK.UnsupportedCredential"
UnsupportedCredentialErrorMessage = "Specified credential (type = %s) is not supported, please check"
CanNotResolveEndpointErrorCode = "SDK.CanNotResolveEndpoint"
CanNotResolveEndpointErrorMessage = "Can not resolve endpoint(param = %s), please check your accessKey with secret, and read the user guide\n %s"
UnsupportedParamPositionErrorCode = "SDK.UnsupportedParamPosition"
UnsupportedParamPositionErrorMessage = "Specified param position (%s) is not supported, please upgrade sdk and retry"
AsyncFunctionNotEnabledCode = "SDK.AsyncFunctionNotEnabled"
AsyncFunctionNotEnabledMessage = "Async function is not enabled in client, please invoke 'client.EnableAsync' function"
UnknownRequestTypeErrorCode = "SDK.UnknownRequestType"
UnknownRequestTypeErrorMessage = "Unknown Request Type: %s"
MissingParamErrorCode = "SDK.MissingParam"
InvalidParamErrorCode = "SDK.InvalidParam"
JsonUnmarshalErrorCode = "SDK.JsonUnmarshalError"
JsonUnmarshalErrorMessage = "Failed to unmarshal response, but you can get the data via response.GetHttpStatusCode() and response.GetHttpContentString()"
TimeoutErrorCode = "SDK.TimeoutError"
TimeoutErrorMessage = "The request timed out %s times(%s for retry), perhaps we should have the threshold raised a little?"
)
// ClientError wrap error
type ClientError struct {
errorCode string
message string
originError error
}
// NewClientError returns Error
func NewClientError(errorCode, message string, originErr error) Error {
return &ClientError{
errorCode: errorCode,
message: message,
originError: originErr,
}
}
// Error returns clientErrMsg
func (err *ClientError) Error() string {
clientErrMsg := fmt.Sprintf("[%s] %s", err.errorCode, err.message)
if err.originError != nil {
return clientErrMsg + "\ncaused by:\n" + err.originError.Error()
}
return clientErrMsg
}
// OriginError returns originError
func (err *ClientError) OriginError() error {
return err.originError
}
// HttpStatus returns DefaultClientErrorStatus
func (*ClientError) HttpStatus() int {
return DefaultClientErrorStatus
}
// ErrorCode returns error code
func (err *ClientError) ErrorCode() string {
if err.errorCode == "" {
return DefaultClientErrorCode
}
return err.errorCode
}
// Message returns error message
func (err *ClientError) Message() string {
return err.message
}
// String returns error string
func (err *ClientError) String() string {
return err.Error()
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2018 The Kubernetes Authors.
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 errors
// Error wrap error interface
type Error interface {
error
HttpStatus() int
ErrorCode() string
Message() string
OriginError() error
}

View File

@ -0,0 +1,137 @@
/*
Copyright 2018 The Kubernetes Authors.
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 errors
import (
"encoding/json"
"fmt"
"github.com/jmespath/go-jmespath"
)
var wrapperList = []ServerErrorWrapper{
&SignatureDostNotMatchWrapper{},
}
// ServerError wrap error
type ServerError struct {
httpStatus int
requestId string
hostId string
errorCode string
recommend string
message string
comment string
}
// ServerErrorWrapper provides tryWrap func
type ServerErrorWrapper interface {
tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError)
}
// Error returns error msg
func (err *ServerError) Error() string {
return fmt.Sprintf("SDK.ServerError\nErrorCode: %s\nRecommend: %s\nRequestId: %s\nMessage: %s",
err.errorCode, err.comment+err.recommend, err.requestId, err.message)
}
// NewServerError returns server error
func NewServerError(httpStatus int, responseContent, comment string) Error {
result := &ServerError{
httpStatus: httpStatus,
message: responseContent,
comment: comment,
}
var data interface{}
err := json.Unmarshal([]byte(responseContent), &data)
if err == nil {
requestId, _ := jmespath.Search("RequestId", data)
hostId, _ := jmespath.Search("HostId", data)
errorCode, _ := jmespath.Search("Code", data)
recommend, _ := jmespath.Search("Recommend", data)
message, _ := jmespath.Search("Message", data)
if requestId != nil {
result.requestId = requestId.(string)
}
if hostId != nil {
result.hostId = hostId.(string)
}
if errorCode != nil {
result.errorCode = errorCode.(string)
}
if recommend != nil {
result.recommend = recommend.(string)
}
if message != nil {
result.message = message.(string)
}
}
return result
}
// WrapServerError returns ServerError
func WrapServerError(originError *ServerError, wrapInfo map[string]string) *ServerError {
for _, wrapper := range wrapperList {
ok, newError := wrapper.tryWrap(originError, wrapInfo)
if ok {
return newError
}
}
return originError
}
// HttpStatus returns http status
func (err *ServerError) HttpStatus() int {
return err.httpStatus
}
// ErrorCode returns error code
func (err *ServerError) ErrorCode() string {
return err.errorCode
}
// Message returns message
func (err *ServerError) Message() string {
return err.message
}
// OriginError returns nil
func (err *ServerError) OriginError() error {
return nil
}
// HostId returns host id
func (err *ServerError) HostId() string {
return err.hostId
}
// RequestId returns request id
func (err *ServerError) RequestId() string {
return err.requestId
}
// Recommend returns error's recommend
func (err *ServerError) Recommend() string {
return err.recommend
}
// Comment returns error's comment
func (err *ServerError) Comment() string {
return err.comment
}

View File

@ -0,0 +1,47 @@
/*
Copyright 2018 The Kubernetes Authors.
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 errors
import "strings"
/* const code and msg prefix */
const (
SignatureDostNotMatchErrorCode = "SignatureDoesNotMatch"
MessagePrefix = "Specified signature is not matched with our calculation. server string to sign is:"
)
// SignatureDostNotMatchWrapper implements tryWrap interface
type SignatureDostNotMatchWrapper struct{}
func (*SignatureDostNotMatchWrapper) tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError) {
clientStringToSign := wrapInfo["StringToSign"]
if error.errorCode == SignatureDostNotMatchErrorCode && clientStringToSign != "" {
message := error.message
if strings.HasPrefix(message, MessagePrefix) {
serverStringToSign := message[len(MessagePrefix):]
if clientStringToSign == serverStringToSign {
// user secret is error
error.recommend = "Please check you AccessKeySecret"
} else {
error.recommend = "This may be a bug with the SDK and we hope you can submit this question in the " +
"github issue(https://github.com/aliyun/alibaba-cloud-sdk-go/issues), thanks very much"
}
}
return true, error
}
return false, nil
}

View File

@ -0,0 +1,335 @@
/*
Copyright 2018 The Kubernetes Authors.
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 requests
import (
"fmt"
"io"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"reflect"
"strconv"
)
/* const vars */
const (
RPC = "RPC"
ROA = "ROA"
HTTP = "HTTP"
HTTPS = "HTTPS"
DefaultHttpPort = "80"
GET = "GET"
PUT = "PUT"
POST = "POST"
DELETE = "DELETE"
HEAD = "HEAD"
OPTIONS = "OPTIONS"
Json = "application/json"
Xml = "application/xml"
Raw = "application/octet-stream"
Form = "application/x-www-form-urlencoded"
Header = "Header"
Query = "Query"
Body = "Body"
Path = "Path"
HeaderSeparator = "\n"
)
// AcsRequest interface
type AcsRequest interface {
GetScheme() string
GetMethod() string
GetDomain() string
GetPort() string
GetRegionId() string
GetUrl() string
GetQueries() string
GetHeaders() map[string]string
GetQueryParams() map[string]string
GetFormParams() map[string]string
GetContent() []byte
GetBodyReader() io.Reader
GetStyle() string
GetProduct() string
GetVersion() string
GetActionName() string
GetAcceptFormat() string
GetLocationServiceCode() string
GetLocationEndpointType() string
SetStringToSign(stringToSign string)
GetStringToSign() string
SetDomain(domain string)
SetContent(content []byte)
SetScheme(scheme string)
BuildUrl() string
BuildQueries() string
addHeaderParam(key, value string)
addQueryParam(key, value string)
addFormParam(key, value string)
addPathParam(key, value string)
}
// base class
type baseRequest struct {
Scheme string
Method string
Domain string
Port string
RegionId string
product string
version string
actionName string
AcceptFormat string
QueryParams map[string]string
Headers map[string]string
FormParams map[string]string
Content []byte
locationServiceCode string
locationEndpointType string
queries string
stringToSign string
}
// GetQueryParams returns QueryParams
func (request *baseRequest) GetQueryParams() map[string]string {
return request.QueryParams
}
// GetFormParams returns FormParams
func (request *baseRequest) GetFormParams() map[string]string {
return request.FormParams
}
// GetContent returns Content
func (request *baseRequest) GetContent() []byte {
return request.Content
}
// GetVersion returns version
func (request *baseRequest) GetVersion() string {
return request.version
}
// GetActionName returns actionName
func (request *baseRequest) GetActionName() string {
return request.actionName
}
// SetContent returns content
func (request *baseRequest) SetContent(content []byte) {
request.Content = content
}
func (request *baseRequest) addHeaderParam(key, value string) {
request.Headers[key] = value
}
func (request *baseRequest) addQueryParam(key, value string) {
request.QueryParams[key] = value
}
func (request *baseRequest) addFormParam(key, value string) {
request.FormParams[key] = value
}
// GetAcceptFormat returns AcceptFormat
func (request *baseRequest) GetAcceptFormat() string {
return request.AcceptFormat
}
// GetLocationServiceCode returns locationServiceCode
func (request *baseRequest) GetLocationServiceCode() string {
return request.locationServiceCode
}
// GetLocationEndpointType returns locationEndpointType
func (request *baseRequest) GetLocationEndpointType() string {
return request.locationEndpointType
}
// GetProduct returns product
func (request *baseRequest) GetProduct() string {
return request.product
}
// GetScheme returns scheme
func (request *baseRequest) GetScheme() string {
return request.Scheme
}
// SetScheme sets scheme
func (request *baseRequest) SetScheme(scheme string) {
request.Scheme = scheme
}
// GetMethod returns Method
func (request *baseRequest) GetMethod() string {
return request.Method
}
// GetDomain returns Domain
func (request *baseRequest) GetDomain() string {
return request.Domain
}
// SetDomain sets host
func (request *baseRequest) SetDomain(host string) {
request.Domain = host
}
// GetPort returns port
func (request *baseRequest) GetPort() string {
return request.Port
}
// GetRegionId returns regionId
func (request *baseRequest) GetRegionId() string {
return request.RegionId
}
// GetHeaders returns headers
func (request *baseRequest) GetHeaders() map[string]string {
return request.Headers
}
// SetContentType sets content type
func (request *baseRequest) SetContentType(contentType string) {
request.Headers["Content-Type"] = contentType
}
// GetContentType returns content type
func (request *baseRequest) GetContentType() (contentType string, contains bool) {
contentType, contains = request.Headers["Content-Type"]
return
}
// SetStringToSign sets stringToSign
func (request *baseRequest) SetStringToSign(stringToSign string) {
request.stringToSign = stringToSign
}
// GetStringToSign returns stringToSign
func (request *baseRequest) GetStringToSign() string {
return request.stringToSign
}
func defaultBaseRequest() (request *baseRequest) {
request = &baseRequest{
Scheme: "",
AcceptFormat: "JSON",
Method: GET,
QueryParams: make(map[string]string),
Headers: map[string]string{
"x-sdk-client": "golang/1.0.0",
"x-sdk-invoke-type": "normal",
"Accept-Encoding": "identity",
},
FormParams: make(map[string]string),
}
return
}
// InitParams returns params
func InitParams(request AcsRequest) (err error) {
requestValue := reflect.ValueOf(request).Elem()
err = flatRepeatedList(requestValue, request, "", "")
return
}
func flatRepeatedList(dataValue reflect.Value, request AcsRequest, position, prefix string) (err error) {
dataType := dataValue.Type()
for i := 0; i < dataType.NumField(); i++ {
field := dataType.Field(i)
name, containsNameTag := field.Tag.Lookup("name")
fieldPosition := position
if fieldPosition == "" {
fieldPosition, _ = field.Tag.Lookup("position")
}
typeTag, containsTypeTag := field.Tag.Lookup("type")
if containsNameTag {
if !containsTypeTag {
// simple param
key := prefix + name
value := dataValue.Field(i).String()
err = addParam(request, fieldPosition, key, value)
if err != nil {
return
}
} else if typeTag == "Repeated" {
// repeated param
repeatedFieldValue := dataValue.Field(i)
if repeatedFieldValue.Kind() != reflect.Slice {
// possible value: {"[]string", "*[]struct"}, we must call Elem() in the last condition
repeatedFieldValue = repeatedFieldValue.Elem()
}
if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() {
for m := 0; m < repeatedFieldValue.Len(); m++ {
elementValue := repeatedFieldValue.Index(m)
key := prefix + name + "." + strconv.Itoa(m+1)
if elementValue.Type().String() == "string" {
value := elementValue.String()
err = addParam(request, fieldPosition, key, value)
if err != nil {
return
}
} else {
err = flatRepeatedList(elementValue, request, fieldPosition, key+".")
if err != nil {
return
}
}
}
}
}
}
}
return
}
func addParam(request AcsRequest, position, name, value string) (err error) {
if len(value) > 0 {
switch position {
case Header:
request.addHeaderParam(name, value)
case Query:
request.addQueryParam(name, value)
case Path:
request.addPathParam(name, value)
case Body:
request.addFormParam(name, value)
default:
errMsg := fmt.Sprintf(errors.UnsupportedParamPositionErrorMessage, position)
err = errors.NewClientError(errors.UnsupportedParamPositionErrorCode, errMsg, nil)
}
}
return
}

View File

@ -0,0 +1,154 @@
/*
Copyright 2018 The Kubernetes Authors.
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 requests
import (
"bytes"
"fmt"
"io"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"strings"
)
// CommonRequest wrap base request
type CommonRequest struct {
*baseRequest
Version string
ApiName string
Product string
// roa params
PathPattern string
PathParams map[string]string
Ontology AcsRequest
}
// NewCommonRequest returns CommonRequest
func NewCommonRequest() (request *CommonRequest) {
request = &CommonRequest{
baseRequest: defaultBaseRequest(),
}
request.Headers["x-sdk-invoke-type"] = "common"
request.PathParams = make(map[string]string)
return
}
// String returns CommonRequest
func (request *CommonRequest) String() string {
request.TransToAcsRequest()
request.BuildQueries()
request.BuildUrl()
resultBuilder := bytes.Buffer{}
mapOutput := func(m map[string]string) {
if len(m) > 0 {
for key, value := range m {
resultBuilder.WriteString(key + ": " + value + "\n")
}
}
}
// Request Line
resultBuilder.WriteString("\n")
resultBuilder.WriteString(fmt.Sprintf("%s %s %s/1.1\n", request.Method, request.GetQueries(), strings.ToUpper(request.Scheme)))
// Headers
resultBuilder.WriteString("Host" + ": " + request.Domain + "\n")
mapOutput(request.Headers)
resultBuilder.WriteString("\n")
// Body
if len(request.Content) > 0 {
resultBuilder.WriteString(string(request.Content) + "\n")
} else {
mapOutput(request.FormParams)
}
return resultBuilder.String()
}
// TransToAcsRequest convert common request
func (request *CommonRequest) TransToAcsRequest() {
if len(request.Version) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "Common request [version] is required", nil)
}
if len(request.ApiName) == 0 && len(request.PathPattern) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "At least one of [ApiName] and [PathPattern] should has a value", nil)
}
if len(request.Domain) == 0 && len(request.Product) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "At least one of [Domain] and [Product] should has a value", nil)
}
if len(request.PathPattern) > 0 {
roaRequest := &RoaRequest{}
roaRequest.initWithCommonRequest(request)
request.Ontology = roaRequest
} else {
rpcRequest := &RpcRequest{}
rpcRequest.baseRequest = request.baseRequest
rpcRequest.product = request.Product
rpcRequest.version = request.Version
rpcRequest.actionName = request.ApiName
request.Ontology = rpcRequest
}
}
// BuildUrl returns request url
func (request *CommonRequest) BuildUrl() string {
if len(request.Port) > 0 {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
}
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.BuildQueries()
}
// BuildQueries returns queries
func (request *CommonRequest) BuildQueries() string {
return request.Ontology.BuildQueries()
}
// GetUrl returns url
func (request *CommonRequest) GetUrl() string {
if len(request.Port) > 0 {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
}
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.GetQueries()
}
// GetQueries returns queries
func (request *CommonRequest) GetQueries() string {
return request.Ontology.GetQueries()
}
// GetBodyReader returns body
func (request *CommonRequest) GetBodyReader() io.Reader {
return request.Ontology.GetBodyReader()
}
// GetStyle returns style
func (request *CommonRequest) GetStyle() string {
return request.Ontology.GetStyle()
}
func (request *CommonRequest) addPathParam(key, value string) {
request.PathParams[key] = value
}

View File

@ -0,0 +1,155 @@
/*
Copyright 2018 The Kubernetes Authors.
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 requests
import (
"bytes"
"io"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/utils"
"net/url"
"sort"
"strings"
)
// RoaRequest wrap base request
type RoaRequest struct {
*baseRequest
pathPattern string
PathParams map[string]string
}
// GetStyle returns ROA
func (*RoaRequest) GetStyle() string {
return ROA
}
// GetBodyReader returns body
func (request *RoaRequest) GetBodyReader() io.Reader {
if request.FormParams != nil && len(request.FormParams) > 0 {
formString := utils.GetUrlFormedMap(request.FormParams)
return strings.NewReader(formString)
} else if len(request.Content) > 0 {
return bytes.NewReader(request.Content)
} else {
return nil
}
}
// GetQueries returns queries
func (request *RoaRequest) GetQueries() string {
return request.queries
}
// BuildQueries for sign method, need not url encoded
func (request *RoaRequest) BuildQueries() string {
return request.buildQueries(false)
}
func (request *RoaRequest) buildQueries(needParamEncode bool) string {
// replace path params with value
path := request.pathPattern
for key, value := range request.PathParams {
path = strings.Replace(path, "["+key+"]", value, 1)
}
queryParams := request.QueryParams
// check if path contains params
splitArray := strings.Split(path, "?")
path = splitArray[0]
if len(splitArray) > 1 && len(splitArray[1]) > 0 {
queryParams[splitArray[1]] = ""
}
// sort QueryParams by key
var queryKeys []string
for key := range queryParams {
queryKeys = append(queryKeys, key)
}
sort.Strings(queryKeys)
// append urlBuilder
urlBuilder := bytes.Buffer{}
urlBuilder.WriteString(path)
if len(queryKeys) > 0 {
urlBuilder.WriteString("?")
}
for i := 0; i < len(queryKeys); i++ {
queryKey := queryKeys[i]
urlBuilder.WriteString(queryKey)
if value := queryParams[queryKey]; len(value) > 0 {
urlBuilder.WriteString("=")
if needParamEncode {
urlBuilder.WriteString(url.QueryEscape(value))
} else {
urlBuilder.WriteString(value)
}
}
if i < len(queryKeys)-1 {
urlBuilder.WriteString("&")
}
}
result := urlBuilder.String()
result = popStandardUrlencode(result)
request.queries = result
return request.queries
}
func popStandardUrlencode(stringToSign string) (result string) {
result = strings.Replace(stringToSign, "+", "%20", -1)
result = strings.Replace(result, "*", "%2A", -1)
result = strings.Replace(result, "%7E", "~", -1)
return
}
// GetUrl returns url
func (request *RoaRequest) GetUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
}
// BuildUrl creates url
func (request *RoaRequest) BuildUrl() string {
// for network trans, need url encoded
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.buildQueries(true)
}
func (request *RoaRequest) addPathParam(key, value string) {
request.PathParams[key] = value
}
// InitWithApiInfo creates api info
func (request *RoaRequest) InitWithApiInfo(product, version, action, uriPattern, serviceCode, endpointType string) {
request.baseRequest = defaultBaseRequest()
request.PathParams = make(map[string]string)
request.Headers["x-acs-version"] = version
request.pathPattern = uriPattern
request.locationServiceCode = serviceCode
request.locationEndpointType = endpointType
//request.product = product
//request.version = version
//request.actionName = action
}
func (request *RoaRequest) initWithCommonRequest(commonRequest *CommonRequest) {
request.baseRequest = commonRequest.baseRequest
request.PathParams = commonRequest.PathParams
//request.product = commonRequest.Product
//request.version = commonRequest.Version
request.Headers["x-acs-version"] = commonRequest.Version
//request.actionName = commonRequest.ApiName
request.pathPattern = commonRequest.PathPattern
request.locationServiceCode = ""
request.locationEndpointType = ""
}

View File

@ -0,0 +1,92 @@
/*
Copyright 2018 The Kubernetes Authors.
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 requests
import (
"io"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/utils"
"strings"
)
// RpcRequest wrap base request
type RpcRequest struct {
*baseRequest
}
func (request *RpcRequest) init() {
request.baseRequest = defaultBaseRequest()
request.Method = POST
}
// GetStyle returns RPC
func (*RpcRequest) GetStyle() string {
return RPC
}
// GetBodyReader return body
func (request *RpcRequest) GetBodyReader() io.Reader {
if request.FormParams != nil && len(request.FormParams) > 0 {
formString := utils.GetUrlFormedMap(request.FormParams)
return strings.NewReader(formString)
}
return strings.NewReader("")
}
// BuildQueries builds queries
func (request *RpcRequest) BuildQueries() string {
request.queries = "/?" + utils.GetUrlFormedMap(request.QueryParams)
return request.queries
}
// GetQueries returns queries
func (request *RpcRequest) GetQueries() string {
return request.queries
}
// BuildUrl creates url
func (request *RpcRequest) BuildUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
}
// GetUrl returns url
func (request *RpcRequest) GetUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.GetQueries()
}
// GetVersion returns version
func (request *RpcRequest) GetVersion() string {
return request.version
}
// GetActionName returns action name
func (request *RpcRequest) GetActionName() string {
return request.actionName
}
func (request *RpcRequest) addPathParam(key, value string) {
panic("not support")
}
// InitWithApiInfo init api info
func (request *RpcRequest) InitWithApiInfo(product, version, action, serviceCode, endpointType string) {
request.init()
request.product = product
request.version = version
request.actionName = action
request.locationServiceCode = serviceCode
request.locationEndpointType = endpointType
}

View File

@ -0,0 +1,83 @@
/*
Copyright 2018 The Kubernetes Authors.
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 requests
import "strconv"
// Integer wrap string
type Integer string
// NewInteger returns Integer format
func NewInteger(integer int) Integer {
return Integer(strconv.Itoa(integer))
}
// HasValue returns true if integer is not null
func (integer Integer) HasValue() bool {
return integer != ""
}
// GetValue returns int value
func (integer Integer) GetValue() (int, error) {
return strconv.Atoi(string(integer))
}
// NewInteger64 returns Integer format
func NewInteger64(integer int64) Integer {
return Integer(strconv.FormatInt(integer, 10))
}
// GetValue64 returns int64 value
func (integer Integer) GetValue64() (int64, error) {
return strconv.ParseInt(string(integer), 10, 0)
}
// Boolean wrap string
type Boolean string
// NewBoolean returns Boolean format
func NewBoolean(bool bool) Boolean {
return Boolean(strconv.FormatBool(bool))
}
// HasValue returns true if boolean is not null
func (boolean Boolean) HasValue() bool {
return boolean != ""
}
// GetValue returns bool format
func (boolean Boolean) GetValue() (bool, error) {
return strconv.ParseBool(string(boolean))
}
// Float wrap string
type Float string
// NewFloat returns Float format
func NewFloat(f float64) Float {
return Float(strconv.FormatFloat(f, 'f', 6, 64))
}
// HasValue returns true if float is not null
func (float Float) HasValue() bool {
return float != ""
}
// GetValue returns float64 format
func (float Float) GetValue() (float64, error) {
return strconv.ParseFloat(string(float), 64)
}

View File

@ -0,0 +1,357 @@
/*
Copyright 2018 The Kubernetes Authors.
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 responses
import (
"encoding/json"
"github.com/json-iterator/go"
"io"
"math"
"strconv"
"strings"
"sync"
"unsafe"
)
const maxUint = ^uint(0)
const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1
var jsonParser jsoniter.API
var initJson = &sync.Once{}
func initJsonParserOnce() {
initJson.Do(func() {
registerBetterFuzzyDecoder()
jsonParser = jsoniter.ConfigCompatibleWithStandardLibrary
})
}
func registerBetterFuzzyDecoder() {
jsoniter.RegisterTypeDecoder("string", &nullableFuzzyStringDecoder{})
jsoniter.RegisterTypeDecoder("bool", &fuzzyBoolDecoder{})
jsoniter.RegisterTypeDecoder("float32", &nullableFuzzyFloat32Decoder{})
jsoniter.RegisterTypeDecoder("float64", &nullableFuzzyFloat64Decoder{})
jsoniter.RegisterTypeDecoder("int", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(maxInt) || val < float64(minInt) {
iter.ReportError("fuzzy decode int", "exceed range")
return
}
*((*int)(ptr)) = int(val)
} else {
*((*int)(ptr)) = iter.ReadInt()
}
}})
jsoniter.RegisterTypeDecoder("uint", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(maxUint) || val < 0 {
iter.ReportError("fuzzy decode uint", "exceed range")
return
}
*((*uint)(ptr)) = uint(val)
} else {
*((*uint)(ptr)) = iter.ReadUint()
}
}})
jsoniter.RegisterTypeDecoder("int8", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt8) || val < float64(math.MinInt8) {
iter.ReportError("fuzzy decode int8", "exceed range")
return
}
*((*int8)(ptr)) = int8(val)
} else {
*((*int8)(ptr)) = iter.ReadInt8()
}
}})
jsoniter.RegisterTypeDecoder("uint8", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint8) || val < 0 {
iter.ReportError("fuzzy decode uint8", "exceed range")
return
}
*((*uint8)(ptr)) = uint8(val)
} else {
*((*uint8)(ptr)) = iter.ReadUint8()
}
}})
jsoniter.RegisterTypeDecoder("int16", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt16) || val < float64(math.MinInt16) {
iter.ReportError("fuzzy decode int16", "exceed range")
return
}
*((*int16)(ptr)) = int16(val)
} else {
*((*int16)(ptr)) = iter.ReadInt16()
}
}})
jsoniter.RegisterTypeDecoder("uint16", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint16) || val < 0 {
iter.ReportError("fuzzy decode uint16", "exceed range")
return
}
*((*uint16)(ptr)) = uint16(val)
} else {
*((*uint16)(ptr)) = iter.ReadUint16()
}
}})
jsoniter.RegisterTypeDecoder("int32", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt32) || val < float64(math.MinInt32) {
iter.ReportError("fuzzy decode int32", "exceed range")
return
}
*((*int32)(ptr)) = int32(val)
} else {
*((*int32)(ptr)) = iter.ReadInt32()
}
}})
jsoniter.RegisterTypeDecoder("uint32", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint32) || val < 0 {
iter.ReportError("fuzzy decode uint32", "exceed range")
return
}
*((*uint32)(ptr)) = uint32(val)
} else {
*((*uint32)(ptr)) = iter.ReadUint32()
}
}})
jsoniter.RegisterTypeDecoder("int64", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt64) || val < float64(math.MinInt64) {
iter.ReportError("fuzzy decode int64", "exceed range")
return
}
*((*int64)(ptr)) = int64(val)
} else {
*((*int64)(ptr)) = iter.ReadInt64()
}
}})
jsoniter.RegisterTypeDecoder("uint64", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint64) || val < 0 {
iter.ReportError("fuzzy decode uint64", "exceed range")
return
}
*((*uint64)(ptr)) = uint64(val)
} else {
*((*uint64)(ptr)) = iter.ReadUint64()
}
}})
}
type nullableFuzzyStringDecoder struct {
}
func (decoder *nullableFuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
switch valueType {
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
*((*string)(ptr)) = string(number)
case jsoniter.StringValue:
*((*string)(ptr)) = iter.ReadString()
case jsoniter.BoolValue:
*((*string)(ptr)) = strconv.FormatBool(iter.ReadBool())
case jsoniter.NilValue:
iter.ReadNil()
*((*string)(ptr)) = ""
default:
iter.ReportError("fuzzyStringDecoder", "not number or string or bool")
}
}
type fuzzyBoolDecoder struct {
}
func (decoder *fuzzyBoolDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
switch valueType {
case jsoniter.BoolValue:
*((*bool)(ptr)) = iter.ReadBool()
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
num, err := number.Int64()
if err != nil {
iter.ReportError("fuzzyBoolDecoder", "get value from json.number failed")
}
if num == 0 {
*((*bool)(ptr)) = false
} else {
*((*bool)(ptr)) = true
}
case jsoniter.StringValue:
strValue := strings.ToLower(iter.ReadString())
if strValue == "true" {
*((*bool)(ptr)) = true
} else if strValue == "false" || strValue == "" {
*((*bool)(ptr)) = false
} else {
iter.ReportError("fuzzyBoolDecoder", "unsupported bool value: "+strValue)
}
case jsoniter.NilValue:
iter.ReadNil()
*((*bool)(ptr)) = false
default:
iter.ReportError("fuzzyBoolDecoder", "not number or string or nil")
}
}
type tolerateEmptyArrayDecoder struct {
valDecoder jsoniter.ValDecoder
}
func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if iter.WhatIsNext() == jsoniter.ArrayValue {
iter.Skip()
newIter := iter.Pool().BorrowIterator([]byte("{}"))
defer iter.Pool().ReturnIterator(newIter)
decoder.valDecoder.Decode(ptr, newIter)
} else {
decoder.valDecoder.Decode(ptr, iter)
}
}
type nullableFuzzyIntegerDecoder struct {
fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator)
}
func (decoder *nullableFuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
str = string(number)
case jsoniter.StringValue:
str = iter.ReadString()
// support empty string
if str == "" {
str = "0"
}
case jsoniter.BoolValue:
if iter.ReadBool() {
str = "1"
} else {
str = "0"
}
case jsoniter.NilValue:
iter.ReadNil()
str = "0"
default:
iter.ReportError("fuzzyIntegerDecoder", "not number or string")
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
isFloat := strings.IndexByte(str, '.') != -1
decoder.fun(isFloat, ptr, newIter)
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
}
type nullableFuzzyFloat32Decoder struct {
}
func (decoder *nullableFuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
*((*float32)(ptr)) = iter.ReadFloat32()
case jsoniter.StringValue:
str = iter.ReadString()
// support empty string
if str == "" {
*((*float32)(ptr)) = 0
return
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
*((*float32)(ptr)) = newIter.ReadFloat32()
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
case jsoniter.BoolValue:
// support bool to float32
if iter.ReadBool() {
*((*float32)(ptr)) = 1
} else {
*((*float32)(ptr)) = 0
}
case jsoniter.NilValue:
iter.ReadNil()
*((*float32)(ptr)) = 0
default:
iter.ReportError("nullableFuzzyFloat32Decoder", "not number or string")
}
}
type nullableFuzzyFloat64Decoder struct {
}
func (decoder *nullableFuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
*((*float64)(ptr)) = iter.ReadFloat64()
case jsoniter.StringValue:
str = iter.ReadString()
// support empty string
if str == "" {
*((*float64)(ptr)) = 0
return
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
*((*float64)(ptr)) = newIter.ReadFloat64()
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
case jsoniter.BoolValue:
// support bool to float64
if iter.ReadBool() {
*((*float64)(ptr)) = 1
} else {
*((*float64)(ptr)) = 0
}
case jsoniter.NilValue:
// support empty string
iter.ReadNil()
*((*float64)(ptr)) = 0
default:
iter.ReportError("nullableFuzzyFloat32Decoder", "not number or string")
}
}

View File

@ -0,0 +1,156 @@
/*
Copyright 2018 The Kubernetes Authors.
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 responses
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/errors"
"net/http"
"strings"
)
// AcsResponse interface
type AcsResponse interface {
IsSuccess() bool
GetHttpStatus() int
GetHttpHeaders() map[string][]string
GetHttpContentString() string
GetHttpContentBytes() []byte
GetOriginHttpResponse() *http.Response
parseFromHttpResponse(httpResponse *http.Response) error
}
// Unmarshal return response body
func Unmarshal(response AcsResponse, httpResponse *http.Response, format string) (err error) {
err = response.parseFromHttpResponse(httpResponse)
if err != nil {
return
}
if !response.IsSuccess() {
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), "")
return
}
if _, isCommonResponse := response.(CommonResponse); isCommonResponse {
// common response need not unmarshal
return
}
if len(response.GetHttpContentBytes()) == 0 {
return
}
if strings.ToUpper(format) == "JSON" {
initJsonParserOnce()
err = jsonParser.Unmarshal(response.GetHttpContentBytes(), response)
if err != nil {
err = errors.NewClientError(errors.JsonUnmarshalErrorCode, errors.JsonUnmarshalErrorMessage, err)
}
} else if strings.ToUpper(format) == "XML" {
err = xml.Unmarshal(response.GetHttpContentBytes(), response)
}
return
}
// BaseResponse wrap originHttpResponse
type BaseResponse struct {
httpStatus int
httpHeaders map[string][]string
httpContentString string
httpContentBytes []byte
originHttpResponse *http.Response
}
// GetHttpStatus returns httpStatus
func (baseResponse *BaseResponse) GetHttpStatus() int {
return baseResponse.httpStatus
}
// GetHttpHeaders returns httpHeaders
func (baseResponse *BaseResponse) GetHttpHeaders() map[string][]string {
return baseResponse.httpHeaders
}
// GetHttpContentString returns httpContentString
func (baseResponse *BaseResponse) GetHttpContentString() string {
return baseResponse.httpContentString
}
// GetHttpContentBytes returns httpContentBytes
func (baseResponse *BaseResponse) GetHttpContentBytes() []byte {
return baseResponse.httpContentBytes
}
// GetOriginHttpResponse returns originHttpResponse
func (baseResponse *BaseResponse) GetOriginHttpResponse() *http.Response {
return baseResponse.originHttpResponse
}
// IsSuccess checks weather httpStatus is 200 or not
func (baseResponse *BaseResponse) IsSuccess() bool {
if baseResponse.GetHttpStatus() >= 200 && baseResponse.GetHttpStatus() < 300 {
return true
}
return false
}
func (baseResponse *BaseResponse) parseFromHttpResponse(httpResponse *http.Response) (err error) {
defer httpResponse.Body.Close()
body, err := ioutil.ReadAll(httpResponse.Body)
if err != nil {
return
}
baseResponse.httpStatus = httpResponse.StatusCode
baseResponse.httpHeaders = httpResponse.Header
baseResponse.httpContentBytes = body
baseResponse.httpContentString = string(body)
baseResponse.originHttpResponse = httpResponse
return
}
// String returns base response content
func (baseResponse *BaseResponse) String() string {
resultBuilder := bytes.Buffer{}
// statusCode
resultBuilder.WriteString("\n")
resultBuilder.WriteString(fmt.Sprintf("%s %s\n", baseResponse.originHttpResponse.Proto, baseResponse.originHttpResponse.Status))
// httpHeaders
//resultBuilder.WriteString("Headers:\n")
for key, value := range baseResponse.httpHeaders {
resultBuilder.WriteString(key + ": " + strings.Join(value, ";") + "\n")
}
resultBuilder.WriteString("\n")
// content
//resultBuilder.WriteString("Content:\n")
resultBuilder.WriteString(baseResponse.httpContentString + "\n")
return resultBuilder.String()
}
// CommonResponse wrap base response
type CommonResponse struct {
*BaseResponse
}
// NewCommonResponse return common response
func NewCommonResponse() (response *CommonResponse) {
return &CommonResponse{
BaseResponse: &BaseResponse{},
}
}

View File

@ -0,0 +1,128 @@
/*
Copyright 2018 The Kubernetes Authors.
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 utils
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/satori/go.uuid"
"net/url"
"reflect"
"strconv"
"time"
)
/* if you use go 1.10 or higher, you can hack this util by these to avoid "TimeZone.zip not found" on Windows */
var (
LoadLocationFromTZData func(name string, data []byte) (*time.Location, error)
TZData []byte
)
// GetUUIDV4 returns uuidHex
func GetUUIDV4() (uuidHex string) {
uuidV4 := uuid.NewV4()
uuidHex = hex.EncodeToString(uuidV4.Bytes())
return
}
// GetMD5Base64 returns base64Value
func GetMD5Base64(bytes []byte) (base64Value string) {
md5Ctx := md5.New()
md5Ctx.Write(bytes)
md5Value := md5Ctx.Sum(nil)
base64Value = base64.StdEncoding.EncodeToString(md5Value)
return
}
// GetGMTLocation returns gmt location
func GetGMTLocation() (*time.Location, error) {
if LoadLocationFromTZData != nil && TZData != nil {
return LoadLocationFromTZData("GMT", TZData)
}
return time.LoadLocation("GMT")
}
// GetTimeInFormatISO8601 returns time in ISO format
func GetTimeInFormatISO8601() (timeStr string) {
gmt, err := GetGMTLocation()
if err != nil {
panic(err)
}
return time.Now().In(gmt).Format("2006-01-02T15:04:05Z")
}
// GetTimeInFormatRFC2616 returns time in RFC format
func GetTimeInFormatRFC2616() (timeStr string) {
gmt, err := GetGMTLocation()
if err != nil {
panic(err)
}
return time.Now().In(gmt).Format("Mon, 02 Jan 2006 15:04:05 GMT")
}
// GetUrlFormedMap returns url formed map
func GetUrlFormedMap(source map[string]string) (urlEncoded string) {
urlEncoder := url.Values{}
for key, value := range source {
urlEncoder.Add(key, value)
}
urlEncoded = urlEncoder.Encode()
return
}
// GetFromJsonString returns json string
func GetFromJsonString(jsonString, key string) (result string, err error) {
var responseMap map[string]*json.RawMessage
err = json.Unmarshal([]byte(jsonString), &responseMap)
if err != nil {
return
}
fmt.Println(string(*responseMap[key]))
err = json.Unmarshal(*responseMap[key], &result)
return
}
// InitStructWithDefaultTag returns default struct
func InitStructWithDefaultTag(bean interface{}) {
configType := reflect.TypeOf(bean)
for i := 0; i < configType.Elem().NumField(); i++ {
field := configType.Elem().Field(i)
defaultValue := field.Tag.Get("default")
if defaultValue == "" {
continue
}
setter := reflect.ValueOf(bean).Elem().Field(i)
switch field.Type.String() {
case "int":
intValue, _ := strconv.ParseInt(defaultValue, 10, 64)
setter.SetInt(intValue)
case "time.Duration":
intValue, _ := strconv.ParseInt(defaultValue, 10, 64)
setter.SetInt(intValue)
case "string":
setter.SetString(defaultValue)
case "bool":
boolValue, _ := strconv.ParseBool(defaultValue)
setter.SetBool(boolValue)
}
}
}

View File

@ -0,0 +1,82 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ecs
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth"
)
// Client is the sdk client struct, each func corresponds to an OpenAPI
type Client struct {
sdk.Client
}
// NewClient creates a sdk client with environment variables
func NewClient() (client *Client, err error) {
client = &Client{}
err = client.Init()
return
}
// NewClientWithOptions creates a sdk client with regionId/sdkConfig/credential
// this is the common api to create a sdk client
func NewClientWithOptions(regionId string, config *sdk.Config, credential auth.Credential) (client *Client, err error) {
client = &Client{}
err = client.InitWithOptions(regionId, config, credential)
return
}
// NewClientWithAccessKey is a shortcut to create sdk client with accesskey
// usage: https://help.aliyun.com/document_detail/66217.html
func NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret string) (client *Client, err error) {
client = &Client{}
err = client.InitWithAccessKey(regionId, accessKeyId, accessKeySecret)
return
}
// NewClientWithStsToken is a shortcut to create sdk client with sts token
// usage: https://help.aliyun.com/document_detail/66222.html
func NewClientWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken string) (client *Client, err error) {
client = &Client{}
err = client.InitWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken)
return
}
// NewClientWithRamRoleArn is a shortcut to create sdk client with ram roleArn
// usage: https://help.aliyun.com/document_detail/66222.html
func NewClientWithRamRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
return
}
// NewClientWithEcsRamRole is a shortcut to create sdk client with ecs ram role
// usage: https://help.aliyun.com/document_detail/66223.html
func NewClientWithEcsRamRole(regionId string, roleName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithEcsRamRole(regionId, roleName)
return
}
// NewClientWithRsaKeyPair is a shortcut to create sdk client with rsa key pair
// attention: rsa key pair auth is only Japan regions available
func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, sessionExpiration int) (client *Client, err error) {
client = &Client{}
err = client.InitWithRsaKeyPair(regionId, publicKeyId, privateKey, sessionExpiration)
return
}

View File

@ -0,0 +1,140 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ecs
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeInstanceTypes invokes the ecs.DescribeInstanceTypes API synchronously
// api document: https://help.aliyun.com/api/ecs/describeinstancetypes.html
func (client *Client) DescribeInstanceTypes(request *DescribeInstanceTypesRequest) (response *DescribeInstanceTypesResponse, err error) {
response = CreateDescribeInstanceTypesResponse()
err = client.DoAction(request, response)
return
}
// DescribeInstanceTypesWithChan invokes the ecs.DescribeInstanceTypes API asynchronously
// api document: https://help.aliyun.com/api/ecs/describeinstancetypes.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeInstanceTypesWithChan(request *DescribeInstanceTypesRequest) (<-chan *DescribeInstanceTypesResponse, <-chan error) {
responseChan := make(chan *DescribeInstanceTypesResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeInstanceTypes(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeInstanceTypesWithCallback invokes the ecs.DescribeInstanceTypes API asynchronously
// api document: https://help.aliyun.com/api/ecs/describeinstancetypes.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeInstanceTypesWithCallback(request *DescribeInstanceTypesRequest, callback func(response *DescribeInstanceTypesResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeInstanceTypesResponse
var err error
defer close(result)
response, err = client.DescribeInstanceTypes(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeInstanceTypesRequest is the request struct for api DescribeInstanceTypes
type DescribeInstanceTypesRequest struct {
*requests.RpcRequest
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
InstanceTypeFamily string `position:"Query" name:"InstanceTypeFamily"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
}
// DescribeInstanceTypesResponse is the response struct for api DescribeInstanceTypes
type DescribeInstanceTypesResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
InstanceTypes InstanceTypesInDescribeInstanceTypes `json:"InstanceTypes" xml:"InstanceTypes"`
}
// InstanceTypesInDescribeInstanceTypes is a nested struct in ecs response
type InstanceTypesInDescribeInstanceTypes struct {
InstanceType []InstanceType `json:"InstanceType" xml:"InstanceType"`
}
// InstanceType is a nested struct in ecs response
type InstanceType struct {
MemorySize float64 `json:"MemorySize" xml:"MemorySize"`
InstancePpsRx int `json:"InstancePpsRx" xml:"InstancePpsRx"`
CpuCoreCount int `json:"CpuCoreCount" xml:"CpuCoreCount"`
Cores int `json:"Cores" xml:"Cores"`
Memory int `json:"Memory" xml:"Memory"`
InstanceTypeId string `json:"InstanceTypeId" xml:"InstanceTypeId"`
InstanceBandwidthRx int `json:"InstanceBandwidthRx" xml:"InstanceBandwidthRx"`
InstanceType string `json:"InstanceType" xml:"InstanceType"`
BaselineCredit int `json:"BaselineCredit" xml:"BaselineCredit"`
EniQuantity int `json:"EniQuantity" xml:"EniQuantity"`
Generation string `json:"Generation" xml:"Generation"`
GPUAmount int `json:"GPUAmount" xml:"GPUAmount"`
SupportIoOptimized string `json:"SupportIoOptimized" xml:"SupportIoOptimized"`
InstanceTypeFamily string `json:"InstanceTypeFamily" xml:"InstanceTypeFamily"`
InitialCredit int `json:"InitialCredit" xml:"InitialCredit"`
InstancePpsTx int `json:"InstancePpsTx" xml:"InstancePpsTx"`
LocalStorageAmount int `json:"LocalStorageAmount" xml:"LocalStorageAmount"`
InstanceFamilyLevel string `json:"InstanceFamilyLevel" xml:"InstanceFamilyLevel"`
LocalStorageCapacity int `json:"LocalStorageCapacity" xml:"LocalStorageCapacity"`
GPUSpec string `json:"GPUSpec" xml:"GPUSpec"`
LocalStorageCategory string `json:"LocalStorageCategory" xml:"LocalStorageCategory"`
InstanceBandwidthTx int `json:"InstanceBandwidthTx" xml:"InstanceBandwidthTx"`
}
// CreateDescribeInstanceTypesRequest creates a request to invoke DescribeInstanceTypes API
func CreateDescribeInstanceTypesRequest() (request *DescribeInstanceTypesRequest) {
request = &DescribeInstanceTypesRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ecs", "2014-05-26", "DescribeInstanceTypes", "ecs", "openAPI")
return
}
// CreateDescribeInstanceTypesResponse creates a response to parse from DescribeInstanceTypes response
func CreateDescribeInstanceTypesResponse() (response *DescribeInstanceTypesResponse) {
response = &DescribeInstanceTypesResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,82 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/auth"
)
// Client is the sdk client struct, each func corresponds to an OpenAPI
type Client struct {
sdk.Client
}
// NewClient creates a sdk client with environment variables
func NewClient() (client *Client, err error) {
client = &Client{}
err = client.Init()
return
}
// NewClientWithOptions creates a sdk client with regionId/sdkConfig/credential
// this is the common api to create a sdk client
func NewClientWithOptions(regionId string, config *sdk.Config, credential auth.Credential) (client *Client, err error) {
client = &Client{}
err = client.InitWithOptions(regionId, config, credential)
return
}
// NewClientWithAccessKey is a shortcut to create sdk client with accesskey
// usage: https://help.aliyun.com/document_detail/66217.html
func NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret string) (client *Client, err error) {
client = &Client{}
err = client.InitWithAccessKey(regionId, accessKeyId, accessKeySecret)
return
}
// NewClientWithStsToken is a shortcut to create sdk client with sts token
// usage: https://help.aliyun.com/document_detail/66222.html
func NewClientWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken string) (client *Client, err error) {
client = &Client{}
err = client.InitWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken)
return
}
// NewClientWithRamRoleArn is a shortcut to create sdk client with ram roleArn
// usage: https://help.aliyun.com/document_detail/66222.html
func NewClientWithRamRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
return
}
// NewClientWithEcsRamRole is a shortcut to create sdk client with ecs ram role
// usage: https://help.aliyun.com/document_detail/66223.html
func NewClientWithEcsRamRole(regionId string, roleName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithEcsRamRole(regionId, roleName)
return
}
// NewClientWithRsaKeyPair is a shortcut to create sdk client with rsa key pair
// attention: rsa key pair auth is only Japan regions available
func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, sessionExpiration int) (client *Client, err error) {
client = &Client{}
err = client.InitWithRsaKeyPair(regionId, publicKeyId, privateKey, sessionExpiration)
return
}

View File

@ -0,0 +1,113 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// CreateScalingRule invokes the ess.CreateScalingRule API synchronously
// api document: https://help.aliyun.com/api/ess/createscalingrule.html
func (client *Client) CreateScalingRule(request *CreateScalingRuleRequest) (response *CreateScalingRuleResponse, err error) {
response = CreateCreateScalingRuleResponse()
err = client.DoAction(request, response)
return
}
// CreateScalingRuleWithChan invokes the ess.CreateScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/createscalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) CreateScalingRuleWithChan(request *CreateScalingRuleRequest) (<-chan *CreateScalingRuleResponse, <-chan error) {
responseChan := make(chan *CreateScalingRuleResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.CreateScalingRule(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// CreateScalingRuleWithCallback invokes the ess.CreateScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/createscalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) CreateScalingRuleWithCallback(request *CreateScalingRuleRequest, callback func(response *CreateScalingRuleResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *CreateScalingRuleResponse
var err error
defer close(result)
response, err = client.CreateScalingRule(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// CreateScalingRuleRequest is the request struct for api CreateScalingRule
type CreateScalingRuleRequest struct {
*requests.RpcRequest
ScalingRuleName string `position:"Query" name:"ScalingRuleName"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
AdjustmentValue requests.Integer `position:"Query" name:"AdjustmentValue"`
ScalingGroupId string `position:"Query" name:"ScalingGroupId"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
Cooldown requests.Integer `position:"Query" name:"Cooldown"`
AdjustmentType string `position:"Query" name:"AdjustmentType"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
}
// CreateScalingRuleResponse is the response struct for api CreateScalingRule
type CreateScalingRuleResponse struct {
*responses.BaseResponse
ScalingRuleId string `json:"ScalingRuleId" xml:"ScalingRuleId"`
ScalingRuleAri string `json:"ScalingRuleAri" xml:"ScalingRuleAri"`
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateCreateScalingRuleRequest creates a request to invoke CreateScalingRule API
func CreateCreateScalingRuleRequest() (request *CreateScalingRuleRequest) {
request = &CreateScalingRuleRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "CreateScalingRule", "ess", "openAPI")
return
}
// CreateCreateScalingRuleResponse creates a response to parse from CreateScalingRule response
func CreateCreateScalingRuleResponse() (response *CreateScalingRuleResponse) {
response = &CreateScalingRuleResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,107 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// DeleteScalingRule invokes the ess.DeleteScalingRule API synchronously
// api document: https://help.aliyun.com/api/ess/deletescalingrule.html
func (client *Client) DeleteScalingRule(request *DeleteScalingRuleRequest) (response *DeleteScalingRuleResponse, err error) {
response = CreateDeleteScalingRuleResponse()
err = client.DoAction(request, response)
return
}
// DeleteScalingRuleWithChan invokes the ess.DeleteScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/deletescalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteScalingRuleWithChan(request *DeleteScalingRuleRequest) (<-chan *DeleteScalingRuleResponse, <-chan error) {
responseChan := make(chan *DeleteScalingRuleResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DeleteScalingRule(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DeleteScalingRuleWithCallback invokes the ess.DeleteScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/deletescalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DeleteScalingRuleWithCallback(request *DeleteScalingRuleRequest, callback func(response *DeleteScalingRuleResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DeleteScalingRuleResponse
var err error
defer close(result)
response, err = client.DeleteScalingRule(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DeleteScalingRuleRequest is the request struct for api DeleteScalingRule
type DeleteScalingRuleRequest struct {
*requests.RpcRequest
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
ScalingRuleId string `position:"Query" name:"ScalingRuleId"`
}
// DeleteScalingRuleResponse is the response struct for api DeleteScalingRule
type DeleteScalingRuleResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateDeleteScalingRuleRequest creates a request to invoke DeleteScalingRule API
func CreateDeleteScalingRuleRequest() (request *DeleteScalingRuleRequest) {
request = &DeleteScalingRuleRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "DeleteScalingRule", "ess", "openAPI")
return
}
// CreateDeleteScalingRuleResponse creates a response to parse from DeleteScalingRule response
func CreateDeleteScalingRuleResponse() (response *DeleteScalingRuleResponse) {
response = &DeleteScalingRuleResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,214 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeScalingConfigurations invokes the ess.DescribeScalingConfigurations API synchronously
// api document: https://help.aliyun.com/api/ess/describescalingconfigurations.html
func (client *Client) DescribeScalingConfigurations(request *DescribeScalingConfigurationsRequest) (response *DescribeScalingConfigurationsResponse, err error) {
response = CreateDescribeScalingConfigurationsResponse()
err = client.DoAction(request, response)
return
}
// DescribeScalingConfigurationsWithChan invokes the ess.DescribeScalingConfigurations API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalingconfigurations.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingConfigurationsWithChan(request *DescribeScalingConfigurationsRequest) (<-chan *DescribeScalingConfigurationsResponse, <-chan error) {
responseChan := make(chan *DescribeScalingConfigurationsResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeScalingConfigurations(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeScalingConfigurationsWithCallback invokes the ess.DescribeScalingConfigurations API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalingconfigurations.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingConfigurationsWithCallback(request *DescribeScalingConfigurationsRequest, callback func(response *DescribeScalingConfigurationsResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeScalingConfigurationsResponse
var err error
defer close(result)
response, err = client.DescribeScalingConfigurations(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeScalingConfigurationsRequest is the request struct for api DescribeScalingConfigurations
type DescribeScalingConfigurationsRequest struct {
*requests.RpcRequest
ScalingConfigurationId6 string `position:"Query" name:"ScalingConfigurationId.6"`
ScalingConfigurationId7 string `position:"Query" name:"ScalingConfigurationId.7"`
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
ScalingConfigurationId4 string `position:"Query" name:"ScalingConfigurationId.4"`
ScalingConfigurationId5 string `position:"Query" name:"ScalingConfigurationId.5"`
ScalingGroupId string `position:"Query" name:"ScalingGroupId"`
ScalingConfigurationId8 string `position:"Query" name:"ScalingConfigurationId.8"`
ScalingConfigurationId9 string `position:"Query" name:"ScalingConfigurationId.9"`
ScalingConfigurationId10 string `position:"Query" name:"ScalingConfigurationId.10"`
PageNumber requests.Integer `position:"Query" name:"PageNumber"`
ScalingConfigurationName2 string `position:"Query" name:"ScalingConfigurationName.2"`
ScalingConfigurationName3 string `position:"Query" name:"ScalingConfigurationName.3"`
ScalingConfigurationName1 string `position:"Query" name:"ScalingConfigurationName.1"`
PageSize requests.Integer `position:"Query" name:"PageSize"`
ScalingConfigurationId2 string `position:"Query" name:"ScalingConfigurationId.2"`
ScalingConfigurationId3 string `position:"Query" name:"ScalingConfigurationId.3"`
ScalingConfigurationId1 string `position:"Query" name:"ScalingConfigurationId.1"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
ScalingConfigurationName6 string `position:"Query" name:"ScalingConfigurationName.6"`
ScalingConfigurationName7 string `position:"Query" name:"ScalingConfigurationName.7"`
ScalingConfigurationName4 string `position:"Query" name:"ScalingConfigurationName.4"`
ScalingConfigurationName5 string `position:"Query" name:"ScalingConfigurationName.5"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
ScalingConfigurationName8 string `position:"Query" name:"ScalingConfigurationName.8"`
ScalingConfigurationName9 string `position:"Query" name:"ScalingConfigurationName.9"`
ScalingConfigurationName10 string `position:"Query" name:"ScalingConfigurationName.10"`
}
// DescribeScalingConfigurationsResponse is the response struct for api DescribeScalingConfigurations
type DescribeScalingConfigurationsResponse struct {
*responses.BaseResponse
TotalCount int `json:"TotalCount" xml:"TotalCount"`
PageNumber int `json:"PageNumber" xml:"PageNumber"`
PageSize int `json:"PageSize" xml:"PageSize"`
RequestId string `json:"RequestId" xml:"RequestId"`
ScalingConfigurations ScalingConfigurations `json:"ScalingConfigurations" xml:"ScalingConfigurations"`
}
// CreateDescribeScalingConfigurationsRequest creates a request to invoke DescribeScalingConfigurations API
func CreateDescribeScalingConfigurationsRequest() (request *DescribeScalingConfigurationsRequest) {
request = &DescribeScalingConfigurationsRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "DescribeScalingConfigurations", "ess", "openAPI")
return
}
// CreateDescribeScalingConfigurationsResponse creates a response to parse from DescribeScalingConfigurations response
func CreateDescribeScalingConfigurationsResponse() (response *DescribeScalingConfigurationsResponse) {
response = &DescribeScalingConfigurationsResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}
// ScalingConfigurations is a nested struct in ess response
type ScalingConfigurations struct {
ScalingConfiguration []ScalingConfiguration `json:"ScalingConfiguration" xml:"ScalingConfiguration"`
}
// ScalingConfiguration is a nested struct in ess response
type ScalingConfiguration struct {
ScalingConfigurationId string `json:"ScalingConfigurationId" xml:"ScalingConfigurationId"`
ScalingConfigurationName string `json:"ScalingConfigurationName" xml:"ScalingConfigurationName"`
ScalingGroupId string `json:"ScalingGroupId" xml:"ScalingGroupId"`
InstanceName string `json:"InstanceName" xml:"InstanceName"`
ImageId string `json:"ImageId" xml:"ImageId"`
ImageName string `json:"ImageName" xml:"ImageName"`
HostName string `json:"HostName" xml:"HostName"`
InstanceType string `json:"InstanceType" xml:"InstanceType"`
InstanceGeneration string `json:"InstanceGeneration" xml:"InstanceGeneration"`
SecurityGroupId string `json:"SecurityGroupId" xml:"SecurityGroupId"`
IoOptimized string `json:"IoOptimized" xml:"IoOptimized"`
InternetChargeType string `json:"InternetChargeType" xml:"InternetChargeType"`
InternetMaxBandwidthIn int `json:"InternetMaxBandwidthIn" xml:"InternetMaxBandwidthIn"`
InternetMaxBandwidthOut int `json:"InternetMaxBandwidthOut" xml:"InternetMaxBandwidthOut"`
SystemDiskCategory string `json:"SystemDiskCategory" xml:"SystemDiskCategory"`
SystemDiskSize int `json:"SystemDiskSize" xml:"SystemDiskSize"`
LifecycleState string `json:"LifecycleState" xml:"LifecycleState"`
CreationTime string `json:"CreationTime" xml:"CreationTime"`
LoadBalancerWeight int `json:"LoadBalancerWeight" xml:"LoadBalancerWeight"`
UserData string `json:"UserData" xml:"UserData"`
KeyPairName string `json:"KeyPairName" xml:"KeyPairName"`
RamRoleName string `json:"RamRoleName" xml:"RamRoleName"`
DeploymentSetId string `json:"DeploymentSetId" xml:"DeploymentSetId"`
SecurityEnhancementStrategy string `json:"SecurityEnhancementStrategy" xml:"SecurityEnhancementStrategy"`
SpotStrategy string `json:"SpotStrategy" xml:"SpotStrategy"`
PasswordInherit bool `json:"PasswordInherit" xml:"PasswordInherit"`
InstanceTypes InstanceTypes `json:"InstanceTypes" xml:"InstanceTypes"`
DataDisks DataDisks `json:"DataDisks" xml:"DataDisks"`
Tags Tags `json:"Tags" xml:"Tags"`
SpotPriceLimit SpotPriceLimit `json:"SpotPriceLimit" xml:"SpotPriceLimit"`
}
// InstanceTypes is a nested struct in ess response
type InstanceTypes struct {
InstanceType []string `json:"InstanceType" xml:"InstanceType"`
}
// DataDisks is a nested struct in ess response
type DataDisks struct {
DataDisk []DataDisk `json:"DataDisk" xml:"DataDisk"`
}
// DataDisk is a nested struct in ess response
type DataDisk struct {
Size int `json:"Size" xml:"Size"`
Category string `json:"Category" xml:"Category"`
SnapshotId string `json:"SnapshotId" xml:"SnapshotId"`
Device string `json:"Device" xml:"Device"`
DeleteWithInstance bool `json:"DeleteWithInstance" xml:"DeleteWithInstance"`
}
// Tags is a nested struct in ess response
type Tags struct {
Tag []Tag `json:"Tag" xml:"Tag"`
}
// Tag is a nested struct in ess response
type Tag struct {
Key string `json:"Key" xml:"Key"`
Value string `json:"Value" xml:"Value"`
}
// SpotPriceLimit is a nested struct in ess response
type SpotPriceLimit struct {
SpotPriceModel []SpotPriceModel `json:"SpotPriceModel" xml:"SpotPriceModel"`
}
// SpotPriceModel is a nested struct in ess response
type SpotPriceModel struct {
InstanceType string `json:"InstanceType" xml:"InstanceType"`
PriceLimit float64 `json:"PriceLimit" xml:"PriceLimit"`
}

View File

@ -0,0 +1,210 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeScalingGroups invokes the ess.DescribeScalingGroups API synchronously
// api document: https://help.aliyun.com/api/ess/describescalinggroups.html
func (client *Client) DescribeScalingGroups(request *DescribeScalingGroupsRequest) (response *DescribeScalingGroupsResponse, err error) {
response = CreateDescribeScalingGroupsResponse()
err = client.DoAction(request, response)
return
}
// DescribeScalingGroupsWithChan invokes the ess.DescribeScalingGroups API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalinggroups.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingGroupsWithChan(request *DescribeScalingGroupsRequest) (<-chan *DescribeScalingGroupsResponse, <-chan error) {
responseChan := make(chan *DescribeScalingGroupsResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeScalingGroups(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeScalingGroupsWithCallback invokes the ess.DescribeScalingGroups API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalinggroups.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingGroupsWithCallback(request *DescribeScalingGroupsRequest, callback func(response *DescribeScalingGroupsResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeScalingGroupsResponse
var err error
defer close(result)
response, err = client.DescribeScalingGroups(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeScalingGroupsRequest is the request struct for api DescribeScalingGroups
type DescribeScalingGroupsRequest struct {
*requests.RpcRequest
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
ScalingGroupId10 string `position:"Query" name:"ScalingGroupId.10"`
ScalingGroupId12 string `position:"Query" name:"ScalingGroupId.12"`
ScalingGroupId13 string `position:"Query" name:"ScalingGroupId.13"`
ScalingGroupId14 string `position:"Query" name:"ScalingGroupId.14"`
ScalingGroupId15 string `position:"Query" name:"ScalingGroupId.15"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
PageNumber requests.Integer `position:"Query" name:"PageNumber"`
PageSize requests.Integer `position:"Query" name:"PageSize"`
ScalingGroupName20 string `position:"Query" name:"ScalingGroupName.20"`
ScalingGroupName19 string `position:"Query" name:"ScalingGroupName.19"`
ScalingGroupId20 string `position:"Query" name:"ScalingGroupId.20"`
ScalingGroupName18 string `position:"Query" name:"ScalingGroupName.18"`
ScalingGroupName17 string `position:"Query" name:"ScalingGroupName.17"`
ScalingGroupName16 string `position:"Query" name:"ScalingGroupName.16"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
ScalingGroupName string `position:"Query" name:"ScalingGroupName"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
ScalingGroupName1 string `position:"Query" name:"ScalingGroupName.1"`
ScalingGroupName2 string `position:"Query" name:"ScalingGroupName.2"`
ScalingGroupId2 string `position:"Query" name:"ScalingGroupId.2"`
ScalingGroupId1 string `position:"Query" name:"ScalingGroupId.1"`
ScalingGroupId6 string `position:"Query" name:"ScalingGroupId.6"`
ScalingGroupId16 string `position:"Query" name:"ScalingGroupId.16"`
ScalingGroupName7 string `position:"Query" name:"ScalingGroupName.7"`
ScalingGroupName11 string `position:"Query" name:"ScalingGroupName.11"`
ScalingGroupId5 string `position:"Query" name:"ScalingGroupId.5"`
ScalingGroupId17 string `position:"Query" name:"ScalingGroupId.17"`
ScalingGroupName8 string `position:"Query" name:"ScalingGroupName.8"`
ScalingGroupName10 string `position:"Query" name:"ScalingGroupName.10"`
ScalingGroupId4 string `position:"Query" name:"ScalingGroupId.4"`
ScalingGroupId18 string `position:"Query" name:"ScalingGroupId.18"`
ScalingGroupName9 string `position:"Query" name:"ScalingGroupName.9"`
ScalingGroupId3 string `position:"Query" name:"ScalingGroupId.3"`
ScalingGroupId19 string `position:"Query" name:"ScalingGroupId.19"`
ScalingGroupName3 string `position:"Query" name:"ScalingGroupName.3"`
ScalingGroupName15 string `position:"Query" name:"ScalingGroupName.15"`
ScalingGroupId9 string `position:"Query" name:"ScalingGroupId.9"`
ScalingGroupName4 string `position:"Query" name:"ScalingGroupName.4"`
ScalingGroupName14 string `position:"Query" name:"ScalingGroupName.14"`
ScalingGroupId8 string `position:"Query" name:"ScalingGroupId.8"`
ScalingGroupName5 string `position:"Query" name:"ScalingGroupName.5"`
ScalingGroupName13 string `position:"Query" name:"ScalingGroupName.13"`
ScalingGroupId7 string `position:"Query" name:"ScalingGroupId.7"`
ScalingGroupName6 string `position:"Query" name:"ScalingGroupName.6"`
ScalingGroupName12 string `position:"Query" name:"ScalingGroupName.12"`
}
// DescribeScalingGroupsResponse is the response struct for api DescribeScalingGroups
type DescribeScalingGroupsResponse struct {
*responses.BaseResponse
TotalCount int `json:"TotalCount" xml:"TotalCount"`
PageNumber int `json:"PageNumber" xml:"PageNumber"`
PageSize int `json:"PageSize" xml:"PageSize"`
RequestId string `json:"RequestId" xml:"RequestId"`
ScalingGroups ScalingGroups `json:"ScalingGroups" xml:"ScalingGroups"`
}
// CreateDescribeScalingGroupsRequest creates a request to invoke DescribeScalingGroups API
func CreateDescribeScalingGroupsRequest() (request *DescribeScalingGroupsRequest) {
request = &DescribeScalingGroupsRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "DescribeScalingGroups", "ess", "openAPI")
return
}
// CreateDescribeScalingGroupsResponse creates a response to parse from DescribeScalingGroups response
func CreateDescribeScalingGroupsResponse() (response *DescribeScalingGroupsResponse) {
response = &DescribeScalingGroupsResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}
// ScalingGroups is a nested struct in ess response
type ScalingGroups struct {
ScalingGroup []ScalingGroup `json:"ScalingGroup" xml:"ScalingGroup"`
}
// ScalingGroup is a nested struct in ess response
type ScalingGroup struct {
DefaultCooldown int `json:"DefaultCooldown" xml:"DefaultCooldown"`
MaxSize int `json:"MaxSize" xml:"MaxSize"`
PendingWaitCapacity int `json:"PendingWaitCapacity" xml:"PendingWaitCapacity"`
RemovingWaitCapacity int `json:"RemovingWaitCapacity" xml:"RemovingWaitCapacity"`
PendingCapacity int `json:"PendingCapacity" xml:"PendingCapacity"`
RemovingCapacity int `json:"RemovingCapacity" xml:"RemovingCapacity"`
ScalingGroupName string `json:"ScalingGroupName" xml:"ScalingGroupName"`
ActiveCapacity int `json:"ActiveCapacity" xml:"ActiveCapacity"`
StandbyCapacity int `json:"StandbyCapacity" xml:"StandbyCapacity"`
ProtectedCapacity int `json:"ProtectedCapacity" xml:"ProtectedCapacity"`
ActiveScalingConfigurationId string `json:"ActiveScalingConfigurationId" xml:"ActiveScalingConfigurationId"`
LaunchTemplateId string `json:"LaunchTemplateId" xml:"LaunchTemplateId"`
LaunchTemplateVersion string `json:"LaunchTemplateVersion" xml:"LaunchTemplateVersion"`
ScalingGroupId string `json:"ScalingGroupId" xml:"ScalingGroupId"`
RegionId string `json:"RegionId" xml:"RegionId"`
TotalCapacity int `json:"TotalCapacity" xml:"TotalCapacity"`
MinSize int `json:"MinSize" xml:"MinSize"`
LifecycleState string `json:"LifecycleState" xml:"LifecycleState"`
CreationTime string `json:"CreationTime" xml:"CreationTime"`
ModificationTime string `json:"ModificationTime" xml:"ModificationTime"`
VpcId string `json:"VpcId" xml:"VpcId"`
VSwitchId string `json:"VSwitchId" xml:"VSwitchId"`
MultiAZPolicy string `json:"MultiAZPolicy" xml:"MultiAZPolicy"`
HealthCheckType string `json:"HealthCheckType" xml:"HealthCheckType"`
VSwitchIds VSwitchIds `json:"VSwitchIds" xml:"VSwitchIds"`
RemovalPolicies RemovalPolicies `json:"RemovalPolicies" xml:"RemovalPolicies"`
DBInstanceIds DBInstanceIds `json:"DBInstanceIds" xml:"DBInstanceIds"`
LoadBalancerIds LoadBalancerIds `json:"LoadBalancerIds" xml:"LoadBalancerIds"`
}
// VSwitchIds is a nested struct in ess response
type VSwitchIds struct {
VSwitchId []string `json:"VSwitchId" xml:"VSwitchId"`
}
// RemovalPolicies is a nested struct in ess response
type RemovalPolicies struct {
RemovalPolicy []string `json:"RemovalPolicy" xml:"RemovalPolicy"`
}
// DBInstanceIds is a nested struct in ess response
type DBInstanceIds struct {
DBInstanceId []string `json:"DBInstanceId" xml:"DBInstanceId"`
}
// LoadBalancerIds is a nested struct in ess response
type LoadBalancerIds struct {
LoadBalancerId []string `json:"LoadBalancerId" xml:"LoadBalancerId"`
}

View File

@ -0,0 +1,155 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeScalingInstances invokes the ess.DescribeScalingInstances API synchronously
// api document: https://help.aliyun.com/api/ess/describescalinginstances.html
func (client *Client) DescribeScalingInstances(request *DescribeScalingInstancesRequest) (response *DescribeScalingInstancesResponse, err error) {
response = CreateDescribeScalingInstancesResponse()
err = client.DoAction(request, response)
return
}
// DescribeScalingInstancesWithChan invokes the ess.DescribeScalingInstances API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalinginstances.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingInstancesWithChan(request *DescribeScalingInstancesRequest) (<-chan *DescribeScalingInstancesResponse, <-chan error) {
responseChan := make(chan *DescribeScalingInstancesResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeScalingInstances(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeScalingInstancesWithCallback invokes the ess.DescribeScalingInstances API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalinginstances.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingInstancesWithCallback(request *DescribeScalingInstancesRequest, callback func(response *DescribeScalingInstancesResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeScalingInstancesResponse
var err error
defer close(result)
response, err = client.DescribeScalingInstances(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeScalingInstancesRequest is the request struct for api DescribeScalingInstances
type DescribeScalingInstancesRequest struct {
*requests.RpcRequest
InstanceId10 string `position:"Query" name:"InstanceId.10"`
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
InstanceId12 string `position:"Query" name:"InstanceId.12"`
InstanceId11 string `position:"Query" name:"InstanceId.11"`
ScalingGroupId string `position:"Query" name:"ScalingGroupId"`
LifecycleState string `position:"Query" name:"LifecycleState"`
CreationType string `position:"Query" name:"CreationType"`
PageNumber requests.Integer `position:"Query" name:"PageNumber"`
PageSize requests.Integer `position:"Query" name:"PageSize"`
InstanceId20 string `position:"Query" name:"InstanceId.20"`
InstanceId1 string `position:"Query" name:"InstanceId.1"`
InstanceId3 string `position:"Query" name:"InstanceId.3"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
InstanceId2 string `position:"Query" name:"InstanceId.2"`
InstanceId5 string `position:"Query" name:"InstanceId.5"`
InstanceId4 string `position:"Query" name:"InstanceId.4"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
InstanceId7 string `position:"Query" name:"InstanceId.7"`
InstanceId6 string `position:"Query" name:"InstanceId.6"`
InstanceId9 string `position:"Query" name:"InstanceId.9"`
InstanceId8 string `position:"Query" name:"InstanceId.8"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
ScalingConfigurationId string `position:"Query" name:"ScalingConfigurationId"`
HealthStatus string `position:"Query" name:"HealthStatus"`
InstanceId18 string `position:"Query" name:"InstanceId.18"`
InstanceId17 string `position:"Query" name:"InstanceId.17"`
InstanceId19 string `position:"Query" name:"InstanceId.19"`
InstanceId14 string `position:"Query" name:"InstanceId.14"`
InstanceId13 string `position:"Query" name:"InstanceId.13"`
InstanceId16 string `position:"Query" name:"InstanceId.16"`
InstanceId15 string `position:"Query" name:"InstanceId.15"`
}
// DescribeScalingInstancesResponse is the response struct for api DescribeScalingInstances
type DescribeScalingInstancesResponse struct {
*responses.BaseResponse
TotalCount int `json:"TotalCount" xml:"TotalCount"`
PageNumber int `json:"PageNumber" xml:"PageNumber"`
PageSize int `json:"PageSize" xml:"PageSize"`
RequestId string `json:"RequestId" xml:"RequestId"`
ScalingInstances ScalingInstances `json:"ScalingInstances" xml:"ScalingInstances"`
}
// CreateDescribeScalingInstancesRequest creates a request to invoke DescribeScalingInstances API
func CreateDescribeScalingInstancesRequest() (request *DescribeScalingInstancesRequest) {
request = &DescribeScalingInstancesRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "DescribeScalingInstances", "ess", "openAPI")
return
}
// CreateDescribeScalingInstancesResponse creates a response to parse from DescribeScalingInstances response
func CreateDescribeScalingInstancesResponse() (response *DescribeScalingInstancesResponse) {
response = &DescribeScalingInstancesResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}
// ScalingInstances is a nested struct in ess response
type ScalingInstances struct {
ScalingInstance []ScalingInstance `json:"ScalingInstance" xml:"ScalingInstance"`
}
// ScalingInstance is a nested struct in ess response
type ScalingInstance struct {
InstanceId string `json:"InstanceId" xml:"InstanceId"`
ScalingConfigurationId string `json:"ScalingConfigurationId" xml:"ScalingConfigurationId"`
ScalingGroupId string `json:"ScalingGroupId" xml:"ScalingGroupId"`
HealthStatus string `json:"HealthStatus" xml:"HealthStatus"`
LoadBalancerWeight int `json:"LoadBalancerWeight" xml:"LoadBalancerWeight"`
LifecycleState string `json:"LifecycleState" xml:"LifecycleState"`
CreationTime string `json:"CreationTime" xml:"CreationTime"`
CreationType string `json:"CreationType" xml:"CreationType"`
}

View File

@ -0,0 +1,162 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// DescribeScalingRules invokes the ess.DescribeScalingRules API synchronously
// api document: https://help.aliyun.com/api/ess/describescalingrules.html
func (client *Client) DescribeScalingRules(request *DescribeScalingRulesRequest) (response *DescribeScalingRulesResponse, err error) {
response = CreateDescribeScalingRulesResponse()
err = client.DoAction(request, response)
return
}
// DescribeScalingRulesWithChan invokes the ess.DescribeScalingRules API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalingrules.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingRulesWithChan(request *DescribeScalingRulesRequest) (<-chan *DescribeScalingRulesResponse, <-chan error) {
responseChan := make(chan *DescribeScalingRulesResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.DescribeScalingRules(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// DescribeScalingRulesWithCallback invokes the ess.DescribeScalingRules API asynchronously
// api document: https://help.aliyun.com/api/ess/describescalingrules.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) DescribeScalingRulesWithCallback(request *DescribeScalingRulesRequest, callback func(response *DescribeScalingRulesResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *DescribeScalingRulesResponse
var err error
defer close(result)
response, err = client.DescribeScalingRules(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// DescribeScalingRulesRequest is the request struct for api DescribeScalingRules
type DescribeScalingRulesRequest struct {
*requests.RpcRequest
ScalingRuleName1 string `position:"Query" name:"ScalingRuleName.1"`
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
ScalingRuleName2 string `position:"Query" name:"ScalingRuleName.2"`
ScalingRuleName3 string `position:"Query" name:"ScalingRuleName.3"`
ScalingRuleName4 string `position:"Query" name:"ScalingRuleName.4"`
ScalingRuleName5 string `position:"Query" name:"ScalingRuleName.5"`
ScalingGroupId string `position:"Query" name:"ScalingGroupId"`
ScalingRuleName6 string `position:"Query" name:"ScalingRuleName.6"`
ScalingRuleName7 string `position:"Query" name:"ScalingRuleName.7"`
ScalingRuleName8 string `position:"Query" name:"ScalingRuleName.8"`
ScalingRuleAri9 string `position:"Query" name:"ScalingRuleAri.9"`
ScalingRuleName9 string `position:"Query" name:"ScalingRuleName.9"`
PageNumber requests.Integer `position:"Query" name:"PageNumber"`
PageSize requests.Integer `position:"Query" name:"PageSize"`
ScalingRuleId10 string `position:"Query" name:"ScalingRuleId.10"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
ScalingRuleAri1 string `position:"Query" name:"ScalingRuleAri.1"`
ScalingRuleAri2 string `position:"Query" name:"ScalingRuleAri.2"`
ScalingRuleName10 string `position:"Query" name:"ScalingRuleName.10"`
ScalingRuleAri3 string `position:"Query" name:"ScalingRuleAri.3"`
ScalingRuleAri4 string `position:"Query" name:"ScalingRuleAri.4"`
ScalingRuleId8 string `position:"Query" name:"ScalingRuleId.8"`
ScalingRuleAri5 string `position:"Query" name:"ScalingRuleAri.5"`
ScalingRuleId9 string `position:"Query" name:"ScalingRuleId.9"`
ScalingRuleAri6 string `position:"Query" name:"ScalingRuleAri.6"`
ScalingRuleAri7 string `position:"Query" name:"ScalingRuleAri.7"`
ScalingRuleAri10 string `position:"Query" name:"ScalingRuleAri.10"`
ScalingRuleAri8 string `position:"Query" name:"ScalingRuleAri.8"`
ScalingRuleId4 string `position:"Query" name:"ScalingRuleId.4"`
ScalingRuleId5 string `position:"Query" name:"ScalingRuleId.5"`
ScalingRuleId6 string `position:"Query" name:"ScalingRuleId.6"`
ScalingRuleId7 string `position:"Query" name:"ScalingRuleId.7"`
ScalingRuleId1 string `position:"Query" name:"ScalingRuleId.1"`
ScalingRuleId2 string `position:"Query" name:"ScalingRuleId.2"`
ScalingRuleId3 string `position:"Query" name:"ScalingRuleId.3"`
}
// DescribeScalingRulesResponse is the response struct for api DescribeScalingRules
type DescribeScalingRulesResponse struct {
*responses.BaseResponse
TotalCount int `json:"TotalCount" xml:"TotalCount"`
PageNumber int `json:"PageNumber" xml:"PageNumber"`
PageSize int `json:"PageSize" xml:"PageSize"`
RequestId string `json:"RequestId" xml:"RequestId"`
ScalingRules ScalingRules `json:"ScalingRules" xml:"ScalingRules"`
}
// CreateDescribeScalingRulesRequest creates a request to invoke DescribeScalingRules API
func CreateDescribeScalingRulesRequest() (request *DescribeScalingRulesRequest) {
request = &DescribeScalingRulesRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "DescribeScalingRules", "ess", "openAPI")
return
}
// CreateDescribeScalingRulesResponse creates a response to parse from DescribeScalingRules response
func CreateDescribeScalingRulesResponse() (response *DescribeScalingRulesResponse) {
response = &DescribeScalingRulesResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}
// ScalingRules is a nested struct in ess response
type ScalingRules struct {
ScalingRule []ScalingRule `json:"ScalingRule" xml:"ScalingRule"`
}
// ScalingRule is a nested struct in ess response
type ScalingRule struct {
ScalingRuleId string `json:"ScalingRuleId" xml:"ScalingRuleId"`
ScalingGroupId string `json:"ScalingGroupId" xml:"ScalingGroupId"`
ScalingRuleName string `json:"ScalingRuleName" xml:"ScalingRuleName"`
Cooldown int `json:"Cooldown" xml:"Cooldown"`
AdjustmentType string `json:"AdjustmentType" xml:"AdjustmentType"`
AdjustmentValue int `json:"AdjustmentValue" xml:"AdjustmentValue"`
MinSize int `json:"MinSize" xml:"MinSize"`
MaxSize int `json:"MaxSize" xml:"MaxSize"`
ScalingRuleAri string `json:"ScalingRuleAri" xml:"ScalingRuleAri"`
}

View File

@ -0,0 +1,110 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// ExecuteScalingRule invokes the ess.ExecuteScalingRule API synchronously
// api document: https://help.aliyun.com/api/ess/executescalingrule.html
func (client *Client) ExecuteScalingRule(request *ExecuteScalingRuleRequest) (response *ExecuteScalingRuleResponse, err error) {
response = CreateExecuteScalingRuleResponse()
err = client.DoAction(request, response)
return
}
// ExecuteScalingRuleWithChan invokes the ess.ExecuteScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/executescalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ExecuteScalingRuleWithChan(request *ExecuteScalingRuleRequest) (<-chan *ExecuteScalingRuleResponse, <-chan error) {
responseChan := make(chan *ExecuteScalingRuleResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.ExecuteScalingRule(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// ExecuteScalingRuleWithCallback invokes the ess.ExecuteScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/executescalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ExecuteScalingRuleWithCallback(request *ExecuteScalingRuleRequest, callback func(response *ExecuteScalingRuleResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *ExecuteScalingRuleResponse
var err error
defer close(result)
response, err = client.ExecuteScalingRule(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// ExecuteScalingRuleRequest is the request struct for api ExecuteScalingRule
type ExecuteScalingRuleRequest struct {
*requests.RpcRequest
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
ScalingRuleAri string `position:"Query" name:"ScalingRuleAri"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
ClientToken string `position:"Query" name:"ClientToken"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
}
// ExecuteScalingRuleResponse is the response struct for api ExecuteScalingRule
type ExecuteScalingRuleResponse struct {
*responses.BaseResponse
ScalingActivityId string `json:"ScalingActivityId" xml:"ScalingActivityId"`
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateExecuteScalingRuleRequest creates a request to invoke ExecuteScalingRule API
func CreateExecuteScalingRuleRequest() (request *ExecuteScalingRuleRequest) {
request = &ExecuteScalingRuleRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "ExecuteScalingRule", "ess", "openAPI")
return
}
// CreateExecuteScalingRuleResponse creates a response to parse from ExecuteScalingRule response
func CreateExecuteScalingRuleResponse() (response *ExecuteScalingRuleResponse) {
response = &ExecuteScalingRuleResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,118 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// ModifyScalingGroup invokes the ess.ModifyScalingGroup API synchronously
// api document: https://help.aliyun.com/api/ess/modifyscalinggroup.html
func (client *Client) ModifyScalingGroup(request *ModifyScalingGroupRequest) (response *ModifyScalingGroupResponse, err error) {
response = CreateModifyScalingGroupResponse()
err = client.DoAction(request, response)
return
}
// ModifyScalingGroupWithChan invokes the ess.ModifyScalingGroup API asynchronously
// api document: https://help.aliyun.com/api/ess/modifyscalinggroup.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ModifyScalingGroupWithChan(request *ModifyScalingGroupRequest) (<-chan *ModifyScalingGroupResponse, <-chan error) {
responseChan := make(chan *ModifyScalingGroupResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.ModifyScalingGroup(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// ModifyScalingGroupWithCallback invokes the ess.ModifyScalingGroup API asynchronously
// api document: https://help.aliyun.com/api/ess/modifyscalinggroup.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ModifyScalingGroupWithCallback(request *ModifyScalingGroupRequest, callback func(response *ModifyScalingGroupResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *ModifyScalingGroupResponse
var err error
defer close(result)
response, err = client.ModifyScalingGroup(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// ModifyScalingGroupRequest is the request struct for api ModifyScalingGroup
type ModifyScalingGroupRequest struct {
*requests.RpcRequest
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
HealthCheckType string `position:"Query" name:"HealthCheckType"`
LaunchTemplateId string `position:"Query" name:"LaunchTemplateId"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
ScalingGroupName string `position:"Query" name:"ScalingGroupName"`
ScalingGroupId string `position:"Query" name:"ScalingGroupId"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
ActiveScalingConfigurationId string `position:"Query" name:"ActiveScalingConfigurationId"`
MinSize requests.Integer `position:"Query" name:"MinSize"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
LaunchTemplateVersion string `position:"Query" name:"LaunchTemplateVersion"`
MaxSize requests.Integer `position:"Query" name:"MaxSize"`
DefaultCooldown requests.Integer `position:"Query" name:"DefaultCooldown"`
RemovalPolicy1 string `position:"Query" name:"RemovalPolicy.1"`
RemovalPolicy2 string `position:"Query" name:"RemovalPolicy.2"`
}
// ModifyScalingGroupResponse is the response struct for api ModifyScalingGroup
type ModifyScalingGroupResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateModifyScalingGroupRequest creates a request to invoke ModifyScalingGroup API
func CreateModifyScalingGroupRequest() (request *ModifyScalingGroupRequest) {
request = &ModifyScalingGroupRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "ModifyScalingGroup", "ess", "openAPI")
return
}
// CreateModifyScalingGroupResponse creates a response to parse from ModifyScalingGroup response
func CreateModifyScalingGroupResponse() (response *ModifyScalingGroupResponse) {
response = &ModifyScalingGroupResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,112 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// ModifyScalingRule invokes the ess.ModifyScalingRule API synchronously
// api document: https://help.aliyun.com/api/ess/modifyscalingrule.html
func (client *Client) ModifyScalingRule(request *ModifyScalingRuleRequest) (response *ModifyScalingRuleResponse, err error) {
response = CreateModifyScalingRuleResponse()
err = client.DoAction(request, response)
return
}
// ModifyScalingRuleWithChan invokes the ess.ModifyScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/modifyscalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ModifyScalingRuleWithChan(request *ModifyScalingRuleRequest) (<-chan *ModifyScalingRuleResponse, <-chan error) {
responseChan := make(chan *ModifyScalingRuleResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.ModifyScalingRule(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// ModifyScalingRuleWithCallback invokes the ess.ModifyScalingRule API asynchronously
// api document: https://help.aliyun.com/api/ess/modifyscalingrule.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) ModifyScalingRuleWithCallback(request *ModifyScalingRuleRequest, callback func(response *ModifyScalingRuleResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *ModifyScalingRuleResponse
var err error
defer close(result)
response, err = client.ModifyScalingRule(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// ModifyScalingRuleRequest is the request struct for api ModifyScalingRule
type ModifyScalingRuleRequest struct {
*requests.RpcRequest
ScalingRuleName string `position:"Query" name:"ScalingRuleName"`
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
AdjustmentValue requests.Integer `position:"Query" name:"AdjustmentValue"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
Cooldown requests.Integer `position:"Query" name:"Cooldown"`
AdjustmentType string `position:"Query" name:"AdjustmentType"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
ScalingRuleId string `position:"Query" name:"ScalingRuleId"`
}
// ModifyScalingRuleResponse is the response struct for api ModifyScalingRule
type ModifyScalingRuleResponse struct {
*responses.BaseResponse
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateModifyScalingRuleRequest creates a request to invoke ModifyScalingRule API
func CreateModifyScalingRuleRequest() (request *ModifyScalingRuleRequest) {
request = &ModifyScalingRuleRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "ModifyScalingRule", "ess", "openAPI")
return
}
// CreateModifyScalingRuleResponse creates a response to parse from ModifyScalingRule response
func CreateModifyScalingRuleResponse() (response *ModifyScalingRuleResponse) {
response = &ModifyScalingRuleResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,129 @@
/*
Copyright 2018 The Kubernetes Authors.
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 ess
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/responses"
)
// RemoveInstances invokes the ess.RemoveInstances API synchronously
// api document: https://help.aliyun.com/api/ess/removeinstances.html
func (client *Client) RemoveInstances(request *RemoveInstancesRequest) (response *RemoveInstancesResponse, err error) {
response = CreateRemoveInstancesResponse()
err = client.DoAction(request, response)
return
}
// RemoveInstancesWithChan invokes the ess.RemoveInstances API asynchronously
// api document: https://help.aliyun.com/api/ess/removeinstances.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) RemoveInstancesWithChan(request *RemoveInstancesRequest) (<-chan *RemoveInstancesResponse, <-chan error) {
responseChan := make(chan *RemoveInstancesResponse, 1)
errChan := make(chan error, 1)
err := client.AddAsyncTask(func() {
defer close(responseChan)
defer close(errChan)
response, err := client.RemoveInstances(request)
if err != nil {
errChan <- err
} else {
responseChan <- response
}
})
if err != nil {
errChan <- err
close(responseChan)
close(errChan)
}
return responseChan, errChan
}
// RemoveInstancesWithCallback invokes the ess.RemoveInstances API asynchronously
// api document: https://help.aliyun.com/api/ess/removeinstances.html
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
func (client *Client) RemoveInstancesWithCallback(request *RemoveInstancesRequest, callback func(response *RemoveInstancesResponse, err error)) <-chan int {
result := make(chan int, 1)
err := client.AddAsyncTask(func() {
var response *RemoveInstancesResponse
var err error
defer close(result)
response, err = client.RemoveInstances(request)
callback(response, err)
result <- 1
})
if err != nil {
defer close(result)
callback(nil, err)
result <- 0
}
return result
}
// RemoveInstancesRequest is the request struct for api RemoveInstances
type RemoveInstancesRequest struct {
*requests.RpcRequest
InstanceId10 string `position:"Query" name:"InstanceId.10"`
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
InstanceId12 string `position:"Query" name:"InstanceId.12"`
InstanceId11 string `position:"Query" name:"InstanceId.11"`
ScalingGroupId string `position:"Query" name:"ScalingGroupId"`
InstanceId20 string `position:"Query" name:"InstanceId.20"`
InstanceId1 string `position:"Query" name:"InstanceId.1"`
InstanceId3 string `position:"Query" name:"InstanceId.3"`
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
InstanceId2 string `position:"Query" name:"InstanceId.2"`
InstanceId5 string `position:"Query" name:"InstanceId.5"`
InstanceId4 string `position:"Query" name:"InstanceId.4"`
OwnerAccount string `position:"Query" name:"OwnerAccount"`
InstanceId7 string `position:"Query" name:"InstanceId.7"`
InstanceId6 string `position:"Query" name:"InstanceId.6"`
InstanceId9 string `position:"Query" name:"InstanceId.9"`
InstanceId8 string `position:"Query" name:"InstanceId.8"`
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
InstanceId18 string `position:"Query" name:"InstanceId.18"`
InstanceId17 string `position:"Query" name:"InstanceId.17"`
InstanceId19 string `position:"Query" name:"InstanceId.19"`
InstanceId14 string `position:"Query" name:"InstanceId.14"`
InstanceId13 string `position:"Query" name:"InstanceId.13"`
InstanceId16 string `position:"Query" name:"InstanceId.16"`
InstanceId15 string `position:"Query" name:"InstanceId.15"`
}
// RemoveInstancesResponse is the response struct for api RemoveInstances
type RemoveInstancesResponse struct {
*responses.BaseResponse
ScalingActivityId string `json:"ScalingActivityId" xml:"ScalingActivityId"`
RequestId string `json:"RequestId" xml:"RequestId"`
}
// CreateRemoveInstancesRequest creates a request to invoke RemoveInstances API
func CreateRemoveInstancesRequest() (request *RemoveInstancesRequest) {
request = &RemoveInstancesRequest{
RpcRequest: &requests.RpcRequest{},
}
request.InitWithApiInfo("Ess", "2014-08-28", "RemoveInstances", "ess", "openAPI")
return
}
// CreateRemoveInstancesResponse creates a response to parse from RemoveInstances response
func CreateRemoveInstancesResponse() (response *RemoveInstancesResponse) {
response = &RemoveInstancesResponse{
BaseResponse: &responses.BaseResponse{},
}
return
}

View File

@ -0,0 +1,235 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"fmt"
"github.com/golang/glog"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/sdk/requests"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/services/ess"
"time"
)
const (
refreshClientInterval = 60 * time.Minute
acsAutogenIncreaseRules = "acs-autogen-increase-rules"
defaultAdjustmentType = "TotalCapacity"
)
//autoScaling define the interface usage in alibaba-cloud-sdk-go.
type autoScaling interface {
DescribeScalingGroups(req *ess.DescribeScalingGroupsRequest) (*ess.DescribeScalingGroupsResponse, error)
DescribeScalingConfigurations(req *ess.DescribeScalingConfigurationsRequest) (*ess.DescribeScalingConfigurationsResponse, error)
DescribeScalingRules(req *ess.DescribeScalingRulesRequest) (*ess.DescribeScalingRulesResponse, error)
DescribeScalingInstances(req *ess.DescribeScalingInstancesRequest) (*ess.DescribeScalingInstancesResponse, error)
CreateScalingRule(req *ess.CreateScalingRuleRequest) (*ess.CreateScalingRuleResponse, error)
ModifyScalingGroup(req *ess.ModifyScalingGroupRequest) (*ess.ModifyScalingGroupResponse, error)
RemoveInstances(req *ess.RemoveInstancesRequest) (*ess.RemoveInstancesResponse, error)
ExecuteScalingRule(req *ess.ExecuteScalingRuleRequest) (*ess.ExecuteScalingRuleResponse, error)
ModifyScalingRule(req *ess.ModifyScalingRuleRequest) (*ess.ModifyScalingRuleResponse, error)
DeleteScalingRule(req *ess.DeleteScalingRuleRequest) (*ess.DeleteScalingRuleResponse, error)
}
func newAutoScalingWrapper(cfg *cloudConfig) (*autoScalingWrapper, error) {
if cfg.isValid() == false {
//Never reach here.
return nil, fmt.Errorf("your cloud config is not valid")
}
asw := &autoScalingWrapper{
cfg: cfg,
}
if cfg.STSEnabled == true {
go func(asw *autoScalingWrapper, cfg *cloudConfig) {
timer := time.NewTicker(refreshClientInterval)
defer timer.Stop()
for {
select {
case <-timer.C:
client, err := getEssClient(cfg)
if err == nil {
asw.autoScaling = client
}
}
}
}(asw, cfg)
}
client, err := getEssClient(cfg)
if err == nil {
asw.autoScaling = client
}
return asw, err
}
func getEssClient(cfg *cloudConfig) (client *ess.Client, err error) {
region := cfg.getRegion()
if cfg.STSEnabled == true {
auth, err := cfg.getSTSToken()
if err != nil {
glog.Errorf("Failed to get sts token from metadata,Because of %s", err.Error())
return nil, err
}
client, err = ess.NewClientWithStsToken(region, auth.AccessKeyId, auth.AccessKeySecret, auth.SecurityToken)
if err != nil {
glog.Errorf("Failed to create client with sts in metadata because of %s", err.Error())
}
} else {
client, err = ess.NewClientWithAccessKey(region, cfg.AccessKeyID, cfg.AccessKeySecret)
if err != nil {
glog.Errorf("Failed to create ess client with AccessKeyId and AccessKeySecret,Because of %s", err.Error())
}
}
return
}
//autoScalingWrapper will serve as the
type autoScalingWrapper struct {
autoScaling
cfg *cloudConfig
}
func (m autoScalingWrapper) getInstanceTypeByConfiguration(configID string, asgId string) (string, error) {
params := ess.CreateDescribeScalingConfigurationsRequest()
params.ScalingConfigurationId1 = configID
params.ScalingGroupId = asgId
resp, err := m.DescribeScalingConfigurations(params)
if err != nil {
glog.Errorf("failed to get ScalingConfiguration info request for %s,because of %s", configID, err.Error())
return "", err
}
configurations := resp.ScalingConfigurations.ScalingConfiguration
if len(configurations) < 1 {
return "", fmt.Errorf("unable to get first ScalingConfiguration for %s", configID)
}
if len(configurations) > 1 {
glog.Warningf("more than one ScalingConfiguration found for config(%q) and ASG(%q)", configID, asgId)
}
return configurations[0].InstanceType, nil
}
func (m autoScalingWrapper) getScalingGroupByID(groupID string) (*ess.ScalingGroup, error) {
params := ess.CreateDescribeScalingGroupsRequest()
params.ScalingGroupId1 = groupID
resp, err := m.DescribeScalingGroups(params)
if err != nil {
return nil, err
}
groups := resp.ScalingGroups.ScalingGroup
if len(groups) < 1 {
return nil, fmt.Errorf("unable to get first ScalingGroup for %s", groupID)
}
if len(groups) > 1 {
glog.Warningf("more than one ScalingGroup for %s, use first one", groupID)
}
return &groups[0], nil
}
func (m autoScalingWrapper) getScalingGroupByName(groupName string) (*ess.ScalingGroup, error) {
params := ess.CreateDescribeScalingGroupsRequest()
params.ScalingGroupName = groupName
resp, err := m.DescribeScalingGroups(params)
if err != nil {
return nil, err
}
groups := resp.ScalingGroups.ScalingGroup
if len(groups) < 1 {
return nil, fmt.Errorf("unable to get first ScalingGroup for %q", groupName)
}
if len(groups) > 1 {
glog.Warningf("more than one ScalingGroup for %q, use first one", groupName)
}
return &groups[0], nil
}
func (m autoScalingWrapper) getScalingInstancesByGroup(asgId string) ([]ess.ScalingInstance, error) {
params := ess.CreateDescribeScalingInstancesRequest()
params.ScalingGroupId = asgId
resp, err := m.DescribeScalingInstances(params)
if err != nil {
glog.Errorf("falied to reqest scaling instances for %s,Because of %s", asgId, err.Error())
return nil, err
}
return resp.ScalingInstances.ScalingInstance, nil
}
func (m autoScalingWrapper) setCapcityInstanceSize(groupId string, capcityInstanceSize int64) error {
var (
ruleId string
scalingRuleAri string
)
req := ess.CreateDescribeScalingRulesRequest()
req.RegionId = m.cfg.getRegion()
req.ScalingGroupId = groupId
req.ScalingRuleName1 = acsAutogenIncreaseRules
resp, err := m.DescribeScalingRules(req)
if err != nil {
//need to handle
return err
}
defer func() {
deleteReq := ess.CreateDeleteScalingRuleRequest()
deleteReq.ScalingRuleId = ruleId
deleteReq.RegionId = m.cfg.getRegion()
_, err := m.DeleteScalingRule(deleteReq)
if err != nil {
glog.Warningf("failed to clean scaling group rules,Because of %s", err.Error())
}
}()
if len(resp.ScalingRules.ScalingRule) == 0 {
//found the specific rules
createReq := ess.CreateCreateScalingRuleRequest()
createReq.RegionId = m.cfg.getRegion()
createReq.ScalingGroupId = groupId
createReq.AdjustmentType = defaultAdjustmentType
createReq.AdjustmentValue = requests.NewInteger64(capcityInstanceSize)
resp, err := m.CreateScalingRule(createReq)
if err != nil {
return err
}
ruleId = resp.ScalingRuleId
scalingRuleAri = resp.ScalingRuleAri
} else {
ruleId = resp.ScalingRules.ScalingRule[0].ScalingRuleId
scalingRuleAri = resp.ScalingRules.ScalingRule[0].ScalingRuleAri
}
modifyReq := ess.CreateModifyScalingRuleRequest()
modifyReq.RegionId = m.cfg.getRegion()
modifyReq.ScalingRuleId = ruleId
modifyReq.AdjustmentType = defaultAdjustmentType
modifyReq.AdjustmentValue = requests.NewInteger64(capcityInstanceSize)
_, err = m.ModifyScalingRule(modifyReq)
if err != nil {
return err
}
executeReq := ess.CreateExecuteScalingRuleRequest()
executeReq.RegionId = m.cfg.getRegion()
executeReq.ScalingRuleAri = scalingRuleAri
_, err = m.ExecuteScalingRule(executeReq)
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,204 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"fmt"
"github.com/golang/glog"
apiv1 "k8s.io/api/core/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
schedulercache "k8s.io/kubernetes/pkg/scheduler/cache"
)
// Asg implements NodeGroup interface.
type Asg struct {
manager *AliCloudManager
minSize int
maxSize int
regionId string
id string
}
// MaxSize returns maximum size of the node group.
func (asg *Asg) MaxSize() int {
return asg.maxSize
}
// MinSize returns minimum size of the node group.
func (asg *Asg) MinSize() int {
return asg.minSize
}
// TargetSize returns the current TARGET size of the node group. It is possible that the
// number is different from the number of nodes registered in Kubernetes.
func (asg *Asg) TargetSize() (int, error) {
size, err := asg.manager.GetAsgSize(asg)
return int(size), err
}
// IncreaseSize increases Asg size
func (asg *Asg) IncreaseSize(delta int) error {
glog.Infof("increase ASG:%s with %d nodes", asg.Id(), delta)
if delta <= 0 {
return fmt.Errorf("size increase must be positive")
}
size, err := asg.manager.GetAsgSize(asg)
if err != nil {
glog.Errorf("failed to get ASG size because of %s", err.Error())
return err
}
if int(size)+delta > asg.MaxSize() {
return fmt.Errorf("size increase is too large - desired:%d max:%d", int(size)+delta, asg.MaxSize())
}
return asg.manager.SetAsgSize(asg, size+int64(delta))
}
// DecreaseTargetSize decreases the target size of the node group. This function
// doesn't permit to delete any existing node and can be used only to reduce the
// request for new nodes that have not been yet fulfilled. Delta should be negative.
// It is assumed that cloud provider will not delete the existing nodes if the size
// when there is an option to just decrease the target.
func (asg *Asg) DecreaseTargetSize(delta int) error {
glog.V(4).Infof("Aliyun: DecreaseTargetSize() with args: %v", delta)
if delta >= 0 {
return fmt.Errorf("size decrease size must be negative")
}
size, err := asg.manager.GetAsgSize(asg)
if err != nil {
glog.Errorf("failed to get ASG size because of %s", err.Error())
return err
}
nodes, err := asg.manager.GetAsgNodes(asg)
if err != nil {
glog.Errorf("failed to get ASG nodes because of %s", err.Error())
return err
}
if int(size)+delta < len(nodes) {
return fmt.Errorf("attempt to delete existing nodes targetSize:%d delta:%d existingNodes: %d",
size, delta, len(nodes))
}
return asg.manager.SetAsgSize(asg, size+int64(delta))
}
// Belongs returns true if the given node belongs to the NodeGroup.
func (asg *Asg) Belongs(node *apiv1.Node) (bool, error) {
instanceId, err := ecsInstanceIdFromProviderId(node.Spec.ProviderID)
if err != nil {
return false, err
}
targetAsg, err := asg.manager.GetAsgForInstance(instanceId)
if err != nil {
return false, err
}
if targetAsg == nil {
return false, fmt.Errorf("%s doesn't belong to a known Asg", node.Name)
}
if targetAsg.Id() != asg.Id() {
return false, nil
}
return true, nil
}
// DeleteNodes deletes the nodes from the group.
func (asg *Asg) DeleteNodes(nodes []*apiv1.Node) error {
size, err := asg.manager.GetAsgSize(asg)
if err != nil {
glog.Errorf("failed to get ASG size because of %s", err.Error())
return err
}
if int(size) <= asg.MinSize() {
return fmt.Errorf("min size reached, nodes will not be deleted")
}
nodeIds := make([]string, 0, len(nodes))
for _, node := range nodes {
belongs, err := asg.Belongs(node)
if err != nil {
glog.Errorf("failed to check whether node:%s is belong to asg:%s", node.GetName(), asg.Id())
return err
}
if belongs != true {
return fmt.Errorf("%s belongs to a different asg than %s", node.Name, asg.Id())
}
instanceId, err := ecsInstanceIdFromProviderId(node.Spec.ProviderID)
if err != nil {
glog.Errorf("failed to find instanceId from providerId,because of %s", err.Error())
return err
}
nodeIds = append(nodeIds, instanceId)
}
return asg.manager.DeleteInstances(nodeIds)
}
// Id returns asg id.
func (asg *Asg) Id() string {
return asg.id
}
// RegionId returns regionId of asg
func (asg *Asg) RegionId() string {
return asg.regionId
}
// Debug returns a debug string for the Asg.
func (asg *Asg) Debug() string {
return fmt.Sprintf("%s (%d:%d)", asg.Id(), asg.MinSize(), asg.MaxSize())
}
// Nodes returns a list of all nodes that belong to this node group.
func (asg *Asg) Nodes() ([]string, error) {
return asg.manager.GetAsgNodes(asg)
}
// TemplateNodeInfo returns a node template for this node group.
func (asg *Asg) TemplateNodeInfo() (*schedulercache.NodeInfo, error) {
template, err := asg.manager.getAsgTemplate(asg.id)
if err != nil {
return nil, err
}
node, err := asg.manager.buildNodeFromTemplate(asg, template)
if err != nil {
glog.Errorf("failed to build instanceType:%s from template in ASG:%s,because of %s", template.InstanceType, asg.Id(), err.Error())
return nil, err
}
nodeInfo := schedulercache.NewNodeInfo(cloudprovider.BuildKubeProxy(asg.id))
nodeInfo.SetNode(node)
return nodeInfo, nil
}
// Exist checks if the node group really exists on the cloud provider side. Allows to tell the
// theoretical node group from the real one.
func (asg *Asg) Exist() bool {
return true
}
// Create creates the node group on the cloud provider side.
func (asg *Asg) Create() (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
// Autoprovisioned returns true if the node group is autoprovisioned.
func (asg *Asg) Autoprovisioned() bool {
return false
}
// Delete deletes the node group on the cloud provider side.
// This will be executed only for autoprovisioned node groups, once their size drops to 0.
func (asg *Asg) Delete() error {
return cloudprovider.ErrNotImplemented
}

View File

@ -0,0 +1,103 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"sync"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/wait"
)
type autoScalingGroups struct {
registeredAsgs []*asgInformation
instanceToAsg map[string]*Asg
cacheMutex sync.Mutex
instancesNotInManagedAsg map[string]struct{}
service *autoScalingWrapper
}
func newAutoScalingGroups(service *autoScalingWrapper) *autoScalingGroups {
registry := &autoScalingGroups{
registeredAsgs: make([]*asgInformation, 0),
service: service,
instanceToAsg: make(map[string]*Asg),
instancesNotInManagedAsg: make(map[string]struct{}),
}
go wait.Forever(func() {
registry.cacheMutex.Lock()
defer registry.cacheMutex.Unlock()
if err := registry.regenerateCache(); err != nil {
glog.Errorf("failed to do regenerating ASG cache,because of %s", err.Error())
}
}, time.Hour)
return registry
}
// Register registers asg in AliCloud Manager.
func (m *autoScalingGroups) Register(asg *Asg) {
m.cacheMutex.Lock()
defer m.cacheMutex.Unlock()
m.registeredAsgs = append(m.registeredAsgs, &asgInformation{
config: asg,
})
}
// FindForInstance returns AsgConfig of the given Instance
func (m *autoScalingGroups) FindForInstance(instanceId string) (*Asg, error) {
m.cacheMutex.Lock()
defer m.cacheMutex.Unlock()
if config, found := m.instanceToAsg[instanceId]; found {
return config, nil
}
if _, found := m.instancesNotInManagedAsg[instanceId]; found {
// The instance is already known to not belong to any configured ASG
// Skip regenerateCache so that we won't unnecessarily call DescribeAutoScalingGroups
// See https://github.com/kubernetes/contrib/issues/2541
return nil, nil
}
if err := m.regenerateCache(); err != nil {
return nil, err
}
if config, found := m.instanceToAsg[instanceId]; found {
return config, nil
}
// instance does not belong to any configured ASG
m.instancesNotInManagedAsg[instanceId] = struct{}{}
return nil, nil
}
func (m *autoScalingGroups) regenerateCache() error {
newCache := make(map[string]*Asg)
for _, asg := range m.registeredAsgs {
instances, err := m.service.getScalingInstancesByGroup(asg.config.id)
if err != nil {
return err
}
for _, instance := range instances {
newCache[instance.InstanceId] = asg.config
}
}
m.instanceToAsg = newCache
return nil
}

View File

@ -0,0 +1,99 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"github.com/golang/glog"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/metadata"
"os"
)
const (
accessKeyId = "ACCESS_KEY_ID"
accessKeyScret = "ACCESS_KEY_SECRET"
regionId = "REGION_ID"
)
type cloudConfig struct {
RegionId string
AccessKeyID string
AccessKeySecret string
STSEnabled bool
}
func (cc *cloudConfig) isValid() bool {
if cc.AccessKeyID == "" {
cc.AccessKeyID = os.Getenv(accessKeyId)
}
if cc.AccessKeySecret == "" {
cc.AccessKeySecret = os.Getenv(accessKeyScret)
}
if cc.RegionId == "" {
cc.RegionId = os.Getenv(regionId)
}
if cc.RegionId == "" || cc.AccessKeyID == "" || cc.AccessKeySecret == "" {
glog.V(5).Infof("Failed to get AccessKeyId:%s,AccessKeySecret:%s,RegionId:%s from cloudConfig and Env\n", cc.AccessKeyID, cc.AccessKeySecret, cc.RegionId)
glog.V(5).Infof("Try to use sts token in metadata instead.\n")
if cc.validateSTSToken() == true && cc.getRegion() != "" {
//if CA is working on ECS with valid role name, use sts token instead.
cc.STSEnabled = true
return true
}
} else {
cc.STSEnabled = false
return true
}
return false
}
func (cc *cloudConfig) validateSTSToken() bool {
m := metadata.NewMetaData(nil)
r, err := m.RoleName()
if err != nil || r == "" {
glog.Warningf("The role name %s is not valid and error is %v", r, err)
return false
}
return true
}
func (cc *cloudConfig) getSTSToken() (metadata.RoleAuth, error) {
m := metadata.NewMetaData(nil)
r, err := m.RoleName()
if err != nil {
return metadata.RoleAuth{}, err
}
auth, err := m.RamRoleToken(r)
if err != nil {
return metadata.RoleAuth{}, err
}
return auth, nil
}
func (cc *cloudConfig) getRegion() string {
if cc.RegionId != "" {
return cc.RegionId
}
m := metadata.NewMetaData(nil)
r, err := m.Region()
if err != nil {
glog.Errorf("Failed to get RegionId from metadata.Because of %s\n", err.Error())
}
return r
}

View File

@ -0,0 +1,209 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"fmt"
"strings"
"github.com/golang/glog"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/config"
"k8s.io/autoscaler/cluster-autoscaler/config/dynamic"
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
"os"
)
const (
// ProviderName is the cloud provider name for alicloud
ProviderName = "alicloud"
)
type aliCloudProvider struct {
manager *AliCloudManager
asgs []*Asg
resourceLimiter *cloudprovider.ResourceLimiter
}
// BuildAliCloudProvider builds CloudProvider implementation for AliCloud.
func BuildAliCloudProvider(manager *AliCloudManager, discoveryOpts cloudprovider.NodeGroupDiscoveryOptions, resourceLimiter *cloudprovider.ResourceLimiter) (cloudprovider.CloudProvider, error) {
// TODO add discoveryOpts parameters check.
if discoveryOpts.StaticDiscoverySpecified() {
return buildStaticallyDiscoveringProvider(manager, discoveryOpts.NodeGroupSpecs, resourceLimiter)
}
if discoveryOpts.AutoDiscoverySpecified() {
return nil, fmt.Errorf("only support static discovery scaling group in alicloud for now")
}
return nil, fmt.Errorf("failed to build alicloud provider: node group specs must be specified")
}
func buildStaticallyDiscoveringProvider(manager *AliCloudManager, specs []string, resourceLimiter *cloudprovider.ResourceLimiter) (*aliCloudProvider, error) {
acp := &aliCloudProvider{
manager: manager,
asgs: make([]*Asg, 0),
resourceLimiter: resourceLimiter,
}
for _, spec := range specs {
if err := acp.addNodeGroup(spec); err != nil {
glog.Warningf("failed to add node group to alicloud provider with spec: %s", spec)
return nil, err
}
}
return acp, nil
}
// add node group defined in string spec. Format:
// minNodes:maxNodes:asgName
func (ali *aliCloudProvider) addNodeGroup(spec string) error {
asg, err := buildAsgFromSpec(spec, ali.manager)
if err != nil {
glog.Errorf("failed to build ASG from spec,because of %s", err.Error())
return err
}
ali.addAsg(asg)
return nil
}
// add and register an asg to this cloud provider
func (ali *aliCloudProvider) addAsg(asg *Asg) {
ali.asgs = append(ali.asgs, asg)
ali.manager.RegisterAsg(asg)
}
func (ali *aliCloudProvider) Name() string {
return ProviderName
}
func (ali *aliCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
result := make([]cloudprovider.NodeGroup, 0, len(ali.asgs))
for _, asg := range ali.asgs {
result = append(result, asg)
}
return result
}
// NodeGroupForNode returns the node group for the given node.
func (ali *aliCloudProvider) NodeGroupForNode(node *apiv1.Node) (cloudprovider.NodeGroup, error) {
instanceId, err := ecsInstanceIdFromProviderId(node.Spec.ProviderID)
if err != nil {
glog.Errorf("failed to get instance Id from provider Id:%s,because of %s", node.Spec.ProviderID, err.Error())
return nil, err
}
return ali.manager.GetAsgForInstance(instanceId)
}
// Pricing returns pricing model for this cloud provider or error if not available.
func (ali *aliCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) {
return nil, cloudprovider.ErrNotImplemented
}
// GetAvailableMachineTypes get all machine types that can be requested from the cloud provider.
func (ali *aliCloudProvider) GetAvailableMachineTypes() ([]string, error) {
return []string{}, nil
}
// NewNodeGroup builds a theoretical node group based on the node definition provided. The node group is not automatically
// created on the cloud provider side. The node group is not returned by NodeGroups() until it is created.
func (ali *aliCloudProvider) NewNodeGroup(machineType string, labels map[string]string, systemLabels map[string]string, taints []apiv1.Taint, extraResources map[string]resource.Quantity) (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
// GetResourceLimiter returns struct containing limits (max, min) for resources (cores, memory etc.).
func (ali *aliCloudProvider) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
return ali.resourceLimiter, nil
}
// Refresh is called before every main loop and can be used to dynamically update cloud provider state.
// In particular the list of node groups returned by NodeGroups can change as a result of CloudProvider.Refresh().
func (ali *aliCloudProvider) Refresh() error {
return nil
}
// Cleanup stops the go routine that is handling the current view of the ASGs in the form of a cache
func (ali *aliCloudProvider) Cleanup() error {
return nil
}
// AliRef contains a reference to ECS instance or .
type AliRef struct {
ID string
Region string
}
// ECSInstanceIdFromProviderId must be in format: `REGION.INSTANCE_ID`
func ecsInstanceIdFromProviderId(id string) (string, error) {
parts := strings.Split(id, ".")
if len(parts) < 2 {
return "", fmt.Errorf("AliCloud: unexpected ProviderID format, providerID=%s", id)
}
return parts[1], nil
}
func buildAsgFromSpec(value string, manager *AliCloudManager) (*Asg, error) {
spec, err := dynamic.SpecFromString(value, true)
if err != nil {
return nil, fmt.Errorf("failed to parse node group spec: %v", err)
}
// check auto scaling group is exists or not
_, err = manager.aService.getScalingGroupByID(spec.Name)
if err != nil {
glog.Errorf("your scaling group: %s does not exist", spec.Name)
return nil, err
}
asg := buildAsg(manager, spec.MinSize, spec.MaxSize, spec.Name, manager.cfg.getRegion())
return asg, nil
}
func buildAsg(manager *AliCloudManager, minSize int, maxSize int, id string, regionId string) *Asg {
return &Asg{
manager: manager,
minSize: minSize,
maxSize: maxSize,
regionId: regionId,
id: id,
}
}
// BuildAlicloud returns alicloud provider
func BuildAlicloud(opts config.AutoscalingOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter) cloudprovider.CloudProvider {
var aliManager *AliCloudManager
var aliError error
if opts.CloudConfig != "" {
config, fileErr := os.Open(opts.CloudConfig)
if fileErr != nil {
glog.Fatalf("Couldn't open cloud provider configuration %s: %#v", opts.CloudConfig, fileErr)
}
defer config.Close()
aliManager, aliError = CreateAliCloudManager(config)
} else {
aliManager, aliError = CreateAliCloudManager(nil)
}
if aliError != nil {
glog.Fatalf("Failed to create Alicloud Manager: %v", aliError)
}
cloudProvider, err := BuildAliCloudProvider(aliManager, do, rl)
if err != nil {
glog.Fatalf("Failed to create Alicloud cloud provider: %v", err)
}
return cloudProvider
}

View File

@ -0,0 +1,32 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestEcsInstanceIdFromProviderId(t *testing.T) {
instanceName := "cn-hangzhou.instanceId"
instanceId, err := ecsInstanceIdFromProviderId(instanceName)
if err != nil {
t.Error(err)
return
}
assert.Equal(t, instanceId, "instanceId")
}

View File

@ -0,0 +1,142 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"fmt"
"github.com/golang/glog"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/services/ecs"
"time"
)
type ecsInstance interface {
DescribeInstanceTypes(req *ecs.DescribeInstanceTypesRequest) (*ecs.DescribeInstanceTypesResponse, error)
}
type instanceType struct {
instanceTypeID string
vcpu int64
memoryInBytes int64
gpu int64
}
type instanceTypeModel struct {
instanceType
// TODO add price model .
}
// instanceWrapper will provide functions about
// instance types,price model and so on.
type instanceWrapper struct {
ecsInstance
InstanceTypeCache map[string]*instanceTypeModel
}
func (iw *instanceWrapper) getInstanceTypeById(typeId string) (*instanceType, error) {
if instanceTypeModel := iw.FindInstanceType(typeId); instanceTypeModel != nil {
return &instanceTypeModel.instanceType, nil
}
err := iw.RefreshCache()
if err != nil {
glog.Errorf("failed to refresh instance type cache,because of %s", err.Error())
return nil, err
}
if instanceTypeModel := iw.FindInstanceType(typeId); instanceTypeModel != nil {
return &instanceTypeModel.instanceType, nil
}
return nil, fmt.Errorf("failed to find the specific instance type by Id: %s", typeId)
}
func (iw *instanceWrapper) FindInstanceType(typeId string) *instanceTypeModel {
if iw.InstanceTypeCache == nil || iw.InstanceTypeCache[typeId] == nil {
return nil
}
return iw.InstanceTypeCache[typeId]
}
func (iw *instanceWrapper) RefreshCache() error {
req := ecs.CreateDescribeInstanceTypesRequest()
resp, err := iw.DescribeInstanceTypes(req)
if err != nil {
return err
}
if iw.InstanceTypeCache == nil {
iw.InstanceTypeCache = make(map[string]*instanceTypeModel)
}
types := resp.InstanceTypes.InstanceType
for _, item := range types {
iw.InstanceTypeCache[item.InstanceTypeId] = &instanceTypeModel{
instanceType{
instanceTypeID: item.InstanceTypeId,
vcpu: int64(item.CpuCoreCount),
memoryInBytes: int64(item.MemorySize * 1024 * 1024 * 1024),
gpu: int64(item.GPUAmount),
},
}
}
return nil
}
func newInstanceWrapper(cfg *cloudConfig) (*instanceWrapper, error) {
if cfg.isValid() == false {
return nil, fmt.Errorf("your cloud config is not valid")
}
iw := &instanceWrapper{}
if cfg.STSEnabled == true {
go func(iw *instanceWrapper, cfg *cloudConfig) {
timer := time.NewTicker(refreshClientInterval)
defer timer.Stop()
for {
select {
case <-timer.C:
client, err := getEcsClient(cfg)
if err == nil {
iw.ecsInstance = client
}
}
}
}(iw, cfg)
}
client, err := getEcsClient(cfg)
if err == nil {
iw.ecsInstance = client
}
return iw, err
}
func getEcsClient(cfg *cloudConfig) (client *ecs.Client, err error) {
region := cfg.getRegion()
if cfg.STSEnabled == true {
auth, err := cfg.getSTSToken()
if err != nil {
glog.Errorf("failed to get sts token from metadata,because of %s", err.Error())
return nil, err
}
client, err = ecs.NewClientWithStsToken(region, auth.AccessKeyId, auth.AccessKeySecret, auth.SecurityToken)
if err != nil {
glog.Errorf("failed to create client with sts in metadata,because of %s", err.Error())
}
} else {
client, err = ecs.NewClientWithAccessKey(region, cfg.AccessKeyID, cfg.AccessKeySecret)
if err != nil {
glog.Errorf("failed to create ecs client with AccessKeyId and AccessKeySecret,because of %s", err.Error())
}
}
return
}

View File

@ -0,0 +1,240 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"errors"
"fmt"
"github.com/golang/glog"
"gopkg.in/gcfg.v1"
"io"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud/alibaba-cloud-sdk-go/services/ess"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
"math/rand"
"time"
)
const (
sdkCoolDownTimeout = 200 * time.Millisecond
defaultPodAmountsLimit = 110
//ResourceGPU GPU resource type
ResourceGPU apiv1.ResourceName = "nvidia.com/gpu"
)
type asgInformation struct {
config *Asg
basename string
}
// AliCloudManager handles alicloud service communication.
type AliCloudManager struct {
cfg *cloudConfig
aService *autoScalingWrapper
iService *instanceWrapper
asgs *autoScalingGroups
}
type sgTemplate struct {
InstanceType *instanceType
Region string
Zone string
}
// CreateAliCloudManager constructs aliCloudManager object.
func CreateAliCloudManager(configReader io.Reader) (*AliCloudManager, error) {
cfg := &cloudConfig{}
if configReader != nil {
if err := gcfg.ReadInto(cfg, configReader); err != nil {
glog.Errorf("couldn't read config: %v", err)
return nil, err
}
}
if cfg.isValid() == false {
return nil, errors.New("please check whether you have provided correct AccessKeyId,AccessKeySecret,RegionId or STS Token")
}
asw, err := newAutoScalingWrapper(cfg)
if err != nil {
glog.Errorf("failed to create NewAutoScalingWrapper because of %s", err.Error())
return nil, err
}
iw, err := newInstanceWrapper(cfg)
if err != nil {
glog.Errorf("failed to create NewInstanceWrapper because of %s", err.Error())
return nil, err
}
manager := &AliCloudManager{
cfg: cfg,
asgs: newAutoScalingGroups(asw),
aService: asw,
iService: iw,
}
return manager, nil
}
// RegisterAsg registers asg in AliCloud Manager.
func (m *AliCloudManager) RegisterAsg(asg *Asg) {
m.asgs.Register(asg)
}
// GetAsgForInstance returns AsgConfig of the given Instance
func (m *AliCloudManager) GetAsgForInstance(instanceId string) (*Asg, error) {
return m.asgs.FindForInstance(instanceId)
}
// GetAsgSize gets ASG size.
func (m *AliCloudManager) GetAsgSize(asgConfig *Asg) (int64, error) {
sg, err := m.aService.getScalingGroupByID(asgConfig.id)
if err != nil {
return -1, fmt.Errorf("failed to describe ASG %s,Because of %s", asgConfig.id, err.Error())
}
return int64(sg.ActiveCapacity + sg.PendingCapacity), nil
}
// SetAsgSize sets ASG size.
func (m *AliCloudManager) SetAsgSize(asg *Asg, size int64) error {
return m.aService.setCapcityInstanceSize(asg.id, size)
}
// DeleteInstances deletes the given instances. All instances must be controlled by the same ASG.
func (m *AliCloudManager) DeleteInstances(instanceIds []string) error {
glog.Infof("start to remove Instances from ASG %v", instanceIds)
if len(instanceIds) == 0 {
glog.Warningf("you don't provide any instanceIds to remove")
return nil
}
// Check whether instances are in the same group
// TODO: remove or provide more meaningful check method.
commonAsg, err := m.asgs.FindForInstance(instanceIds[0])
if err != nil {
glog.Errorf("failed to find instance:%s in ASG", instanceIds[0])
return err
}
for _, instanceId := range instanceIds {
asg, err := m.asgs.FindForInstance(instanceId)
if err != nil {
glog.Errorf("failed to find instanceId:%s from ASG and exit", instanceId)
return err
}
if asg != commonAsg {
return fmt.Errorf("cannot delete instances which doesn't belong to the same ASG")
}
}
// Remove instance from ASG in loop
for _, instanceId := range instanceIds {
req := ess.CreateRemoveInstancesRequest()
req.ScalingGroupId = commonAsg.id
req.InstanceId1 = instanceId
resp, err := m.aService.RemoveInstances(req)
if err != nil {
fmt.Errorf("failed to remove instance from scaling group %s,because of %s", commonAsg.id, err.Error())
continue
}
glog.Infof("remove instances successfully with response: %s", resp.GetHttpContentString())
// prevent from triggering api flow control
time.Sleep(sdkCoolDownTimeout)
}
return nil
}
// GetAsgNodes returns Asg nodes.
func (m *AliCloudManager) GetAsgNodes(sg *Asg) ([]string, error) {
result := make([]string, 0)
instances, err := m.aService.getScalingInstancesByGroup(sg.id)
if err != nil {
return []string{}, err
}
for _, instance := range instances {
result = append(result, getNodeProviderID(instance.InstanceId, sg.RegionId()))
}
return result, nil
}
// getNodeProviderID build provider id from ecs id and region
func getNodeProviderID(id, region string) string {
return fmt.Sprintf("%s.%s", region, id)
}
func (m *AliCloudManager) getAsgTemplate(asgId string) (*sgTemplate, error) {
sg, err := m.aService.getScalingGroupByID(asgId)
if err != nil {
glog.Errorf("failed to get ASG by id:%s,because of %s", asgId, err.Error())
return nil, err
}
typeID, err := m.aService.getInstanceTypeByConfiguration(sg.ActiveScalingConfigurationId, asgId)
if err != nil {
glog.Errorf("failed to get instanceType by configuration Id:%s from ASG:%s,because of %s", sg.ActiveScalingConfigurationId, asgId, err.Error())
return nil, err
}
instanceType, err := m.iService.getInstanceTypeById(typeID)
if err != nil {
glog.Errorf("failed to get instanceType by Id:%s,because of %s", typeID, err.Error())
return nil, err
}
return &sgTemplate{
InstanceType: instanceType,
Region: sg.RegionId,
}, nil
}
func (m *AliCloudManager) buildNodeFromTemplate(sg *Asg, template *sgTemplate) (*apiv1.Node, error) {
node := apiv1.Node{}
nodeName := fmt.Sprintf("%s-asg-%d", sg.id, rand.Int63())
node.ObjectMeta = metav1.ObjectMeta{
Name: nodeName,
SelfLink: fmt.Sprintf("/api/v1/nodes/%s", nodeName),
Labels: map[string]string{},
}
node.Status = apiv1.NodeStatus{
Capacity: apiv1.ResourceList{},
}
node.Status.Capacity[apiv1.ResourcePods] = *resource.NewQuantity(defaultPodAmountsLimit, resource.DecimalSI)
node.Status.Capacity[apiv1.ResourceCPU] = *resource.NewQuantity(template.InstanceType.vcpu, resource.DecimalSI)
node.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(template.InstanceType.memoryInBytes, resource.DecimalSI)
//add gpu resource support
node.Status.Capacity[ResourceGPU] = *resource.NewQuantity(template.InstanceType.gpu, resource.DecimalSI)
node.Status.Allocatable = node.Status.Capacity
node.Labels = cloudprovider.JoinStringMaps(node.Labels, buildGenericLabels(template, nodeName))
node.Status.Conditions = cloudprovider.BuildReadyConditions()
return &node, nil
}
func buildGenericLabels(template *sgTemplate, nodeName string) map[string]string {
result := make(map[string]string)
result[kubeletapis.LabelArch] = cloudprovider.DefaultArch
result[kubeletapis.LabelOS] = cloudprovider.DefaultOS
result[kubeletapis.LabelInstanceType] = template.InstanceType.instanceTypeID
result[kubeletapis.LabelZoneRegion] = template.Region
result[kubeletapis.LabelZoneFailureDomain] = template.Zone
result[kubeletapis.LabelHostname] = nodeName
return result
}

View File

@ -0,0 +1,39 @@
/*
Copyright 2018 The Kubernetes Authors.
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 alicloud
import (
"github.com/stretchr/testify/assert"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
"testing"
)
func TestBuildGenericLabels(t *testing.T) {
template := &sgTemplate{
InstanceType: &instanceType{
instanceTypeID: "gn5-4c-8g",
vcpu: 4,
memoryInBytes: 8 * 1024 * 1024 * 1024,
gpu: 1,
},
Region: "cn-hangzhou",
Zone: "cn-hangzhou-a",
}
nodeName := "virtual-node"
labels := buildGenericLabels(template, nodeName)
assert.Equal(t, labels[kubeletapis.LabelInstanceType], template.InstanceType.instanceTypeID)
}

View File

@ -0,0 +1,176 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
name: cluster-autoscaler
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: cluster-autoscaler
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
rules:
- apiGroups: [""]
resources: ["events","endpoints"]
verbs: ["create", "patch"]
- apiGroups: [""]
resources: ["pods/eviction"]
verbs: ["create"]
- apiGroups: [""]
resources: ["pods/status"]
verbs: ["update"]
- apiGroups: [""]
resources: ["endpoints"]
resourceNames: ["cluster-autoscaler"]
verbs: ["get","update"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["watch","list","get","update"]
- apiGroups: [""]
resources: ["pods","services","replicationcontrollers","persistentvolumeclaims","persistentvolumes"]
verbs: ["watch","list","get"]
- apiGroups: ["extensions"]
resources: ["replicasets","daemonsets"]
verbs: ["watch","list","get"]
- apiGroups: ["policy"]
resources: ["poddisruptionbudgets"]
verbs: ["watch","list"]
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["watch","list","get"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["watch","list","get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["create"]
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["cluster-autoscaler-status"]
verbs: ["delete","get","update"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: cluster-autoscaler
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-autoscaler
subjects:
- kind: ServiceAccount
name: cluster-autoscaler
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
k8s-addon: cluster-autoscaler.addons.k8s.io
k8s-app: cluster-autoscaler
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cluster-autoscaler
subjects:
- kind: ServiceAccount
name: cluster-autoscaler
namespace: kube-system
---
apiVersion: v1
kind: Secret
metadata:
name: cloud-config
type: Opaque
data:
access-key-id: [YOUR_BASE64_AK_ID]
access-key-id: [YOUR_BASE64_AK_SECRET]
region-id: [YOUR_BASE64_REGION_ID]
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
app: cluster-autoscaler
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
spec:
serviceAccountName: admin
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/autoscaler:v1.3.1
name: cluster-autoscaler
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 100m
memory: 300Mi
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=alicloud
- --nodes=[min]:[max]:[ASG_ID]
imagePullPolicy: "Always"
env:
- name: ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: cloud-config
key: access-key-id
- name: ACCESS_KEY_SECRET
valueFrom:
secretKeyRef:
name: cloud-config
key: access-key-secret
- name: REGION_ID
valueFrom:
secretKeyRef:
name: cloud-config
key: region-id
volumeMounts:
- name: ssl-certs
mountPath: /etc/ssl/certs/ca-certificates.crt
readOnly: true
volumes:
- name: ssl-certs
hostPath:
path: "/etc/ssl/certs/ca-certificates.crt"

View File

@ -0,0 +1,91 @@
/*
Copyright 2018 The Kubernetes Authors.
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 metadata
import (
"time"
)
// AttemptStrategy represents a strategy for waiting for an action
// to complete successfully. This is an internal type used by the
// implementation of other packages.
type AttemptStrategy struct {
Total time.Duration // total duration of attempt.
Delay time.Duration // interval between each try in the burst.
Min int // minimum number of retries; overrides Total
}
// Attempt struct
type Attempt struct {
strategy AttemptStrategy
last time.Time
end time.Time
force bool
count int
}
// Start begins a new sequence of attempts for the given strategy.
func (s AttemptStrategy) Start() *Attempt {
now := time.Now()
return &Attempt{
strategy: s,
last: now,
end: now.Add(s.Total),
force: true,
}
}
// Next waits until it is time to perform the next attempt or returns
// false if it is time to stop trying.
func (a *Attempt) Next() bool {
now := time.Now()
sleep := a.nextSleep(now)
if !a.force && !now.Add(sleep).Before(a.end) && a.strategy.Min <= a.count {
return false
}
a.force = false
if sleep > 0 && a.count > 0 {
time.Sleep(sleep)
now = time.Now()
}
a.count++
a.last = now
return true
}
func (a *Attempt) nextSleep(now time.Time) time.Duration {
sleep := a.strategy.Delay - now.Sub(a.last)
if sleep < 0 {
return 0
}
return sleep
}
// HasNext returns whether another attempt will be made if the current
// one fails. If it returns true, the following call to Next is
// guaranteed to return true.
func (a *Attempt) HasNext() bool {
if a.force || a.strategy.Min > a.count {
return true
}
now := time.Now()
if now.Add(a.nextSleep(now)).Before(a.end) {
a.force = true
return true
}
return false
}

View File

@ -0,0 +1,492 @@
/*
Copyright 2018 The Kubernetes Authors.
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 metadata
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"strings"
"time"
"encoding/json"
"reflect"
"os"
)
/* const vars */
const (
ENDPOINT = "http://100.100.100.200"
DNS_NAMESERVERS = "dns-conf/nameservers"
EIPV4 = "eipv4"
HOSTNAME = "hostname"
IMAGE_ID = "image-id"
INSTANCE_ID = "instance-id"
MAC = "mac"
NETWORK_TYPE = "network-type"
NTP_CONF_SERVERS = "ntp-conf/ntp-servers"
OWNER_ACCOUNT_ID = "owner-account-id"
PRIVATE_IPV4 = "private-ipv4"
REGION = "region-id"
SERIAL_NUMBER = "serial-number"
SOURCE_ADDRESS = "source-address"
VPC_CIDR_BLOCK = "vpc-cidr-block"
VPC_ID = "vpc-id"
VSWITCH_CIDR_BLOCK = "vswitch-cidr-block"
VSWITCH_ID = "vswitch-id"
ZONE = "zone-id"
RAM_SECURITY = "Ram/security-credentials"
)
// IMetaDataRequest interface
type IMetaDataRequest interface {
Version(version string) IMetaDataRequest
ResourceType(rtype string) IMetaDataRequest
Resource(resource string) IMetaDataRequest
SubResource(sub string) IMetaDataRequest
Url() (string, error)
Do(api interface{}) error
}
// MetaData wrap http client
type MetaData struct {
// mock for unit test.
mock requestMock
client *http.Client
}
// NewMetaData returns MetaData
func NewMetaData(client *http.Client) *MetaData {
if client == nil {
client = &http.Client{}
}
return &MetaData{
client: client,
}
}
// NewMockMetaData returns mock MetaData
func NewMockMetaData(client *http.Client, sendRequest requestMock) *MetaData {
if client == nil {
client = &http.Client{}
}
return &MetaData{
client: client,
mock: sendRequest,
}
}
// New returns MetaDataRequest
func (m *MetaData) New() *MetaDataRequest {
return &MetaDataRequest{
client: m.client,
sendRequest: m.mock,
}
}
// HostName returns host name
func (m *MetaData) HostName() (string, error) {
var hostname ResultList
err := m.New().Resource(HOSTNAME).Do(&hostname)
if err != nil {
return "", err
}
return hostname.result[0], nil
}
// ImageID returns image id
func (m *MetaData) ImageID() (string, error) {
var image ResultList
err := m.New().Resource(IMAGE_ID).Do(&image)
if err != nil {
return "", err
}
return image.result[0], err
}
// InstanceID returns instance Id
func (m *MetaData) InstanceID() (string, error) {
var instanceid ResultList
err := m.New().Resource(INSTANCE_ID).Do(&instanceid)
if err != nil {
return "", err
}
return instanceid.result[0], err
}
// Mac returns mac address
func (m *MetaData) Mac() (string, error) {
var mac ResultList
err := m.New().Resource(MAC).Do(&mac)
if err != nil {
return "", err
}
return mac.result[0], nil
}
// NetworkType returns network type
func (m *MetaData) NetworkType() (string, error) {
var network ResultList
err := m.New().Resource(NETWORK_TYPE).Do(&network)
if err != nil {
return "", err
}
return network.result[0], nil
}
// OwnerAccountID returns owner account id
func (m *MetaData) OwnerAccountID() (string, error) {
var owner ResultList
err := m.New().Resource(OWNER_ACCOUNT_ID).Do(&owner)
if err != nil {
return "", err
}
return owner.result[0], nil
}
// PrivateIPv4 returns private ipv4 ip address
func (m *MetaData) PrivateIPv4() (string, error) {
var private ResultList
err := m.New().Resource(PRIVATE_IPV4).Do(&private)
if err != nil {
return "", err
}
return private.result[0], nil
}
// Region returns region
func (m *MetaData) Region() (string, error) {
var region ResultList
err := m.New().Resource(REGION).Do(&region)
if err != nil {
return "", err
}
return region.result[0], nil
}
// SerialNumber returns serial number
func (m *MetaData) SerialNumber() (string, error) {
var serial ResultList
err := m.New().Resource(SERIAL_NUMBER).Do(&serial)
if err != nil {
return "", err
}
return serial.result[0], nil
}
// SourceAddress returns source address
func (m *MetaData) SourceAddress() (string, error) {
var source ResultList
err := m.New().Resource(SOURCE_ADDRESS).Do(&source)
if err != nil {
return "", err
}
return source.result[0], nil
}
// VpcCIDRBlock returns vpc cidr block
func (m *MetaData) VpcCIDRBlock() (string, error) {
var vpcCIDR ResultList
err := m.New().Resource(VPC_CIDR_BLOCK).Do(&vpcCIDR)
if err != nil {
return "", err
}
return vpcCIDR.result[0], err
}
// VpcID returns vpc id
func (m *MetaData) VpcID() (string, error) {
var vpcId ResultList
err := m.New().Resource(VPC_ID).Do(&vpcId)
if err != nil {
return "", err
}
return vpcId.result[0], err
}
// VswitchCIDRBlock returns vswitch cidr block
func (m *MetaData) VswitchCIDRBlock() (string, error) {
var cidr ResultList
err := m.New().Resource(VSWITCH_CIDR_BLOCK).Do(&cidr)
if err != nil {
return "", err
}
return cidr.result[0], err
}
// VswitchID returns vswitch id
func (m *MetaData) VswitchID() (string, error) {
var vswithcid ResultList
err := m.New().Resource(VSWITCH_ID).Do(&vswithcid)
if err != nil {
return "", err
}
return vswithcid.result[0], err
}
// EIPv4 returns eip
func (m *MetaData) EIPv4() (string, error) {
var eip ResultList
err := m.New().Resource(EIPV4).Do(&eip)
if err != nil {
return "", err
}
return eip.result[0], nil
}
// DNSNameServers returns dns servers
func (m *MetaData) DNSNameServers() ([]string, error) {
var data ResultList
err := m.New().Resource(DNS_NAMESERVERS).Do(&data)
if err != nil {
return []string{}, err
}
return data.result, nil
}
// NTPConfigServers returns ntp servers
func (m *MetaData) NTPConfigServers() ([]string, error) {
var data ResultList
err := m.New().Resource(NTP_CONF_SERVERS).Do(&data)
if err != nil {
return []string{}, err
}
return data.result, nil
}
// Zone returns zone id
func (m *MetaData) Zone() (string, error) {
var zone ResultList
err := m.New().Resource(ZONE).Do(&zone)
if err != nil {
return "", err
}
return zone.result[0], nil
}
// RoleName returns role name
func (m *MetaData) RoleName() (string, error) {
var roleName ResultList
err := m.New().Resource("ram/security-credentials/").Do(&roleName)
if err != nil {
return "", err
}
return roleName.result[0], nil
}
// RamRoleToken returns ram role token
func (m *MetaData) RamRoleToken(role string) (RoleAuth, error) {
var roleauth RoleAuth
err := m.New().Resource(RAM_SECURITY).SubResource(role).Do(&roleauth)
if err != nil {
return RoleAuth{}, err
}
return roleauth, nil
}
type requestMock func(resource string) (string, error)
// MetaDataRequest struct
type MetaDataRequest struct {
version string
resourceType string
resource string
subResource string
client *http.Client
sendRequest requestMock
}
// Version sets version
func (vpc *MetaDataRequest) Version(version string) IMetaDataRequest {
vpc.version = version
return vpc
}
// ResourceType sets resource type
func (vpc *MetaDataRequest) ResourceType(rtype string) IMetaDataRequest {
vpc.resourceType = rtype
return vpc
}
// Resource sets resource
func (vpc *MetaDataRequest) Resource(resource string) IMetaDataRequest {
vpc.resource = resource
return vpc
}
// SubResource set sub resource
func (vpc *MetaDataRequest) SubResource(sub string) IMetaDataRequest {
vpc.subResource = sub
return vpc
}
var retry = AttemptStrategy{
Min: 5,
Total: 5 * time.Second,
Delay: 200 * time.Millisecond,
}
// Url returns url
func (vpc *MetaDataRequest) Url() (string, error) {
if vpc.version == "" {
vpc.version = "latest"
}
if vpc.resourceType == "" {
vpc.resourceType = "meta-data"
}
if vpc.resource == "" {
return "", errors.New("the resource you want to visit must not be nil!")
}
endpoint := os.Getenv("METADATA_ENDPOINT")
if endpoint == "" {
endpoint = ENDPOINT
}
r := fmt.Sprintf("%s/%s/%s/%s", endpoint, vpc.version, vpc.resourceType, vpc.resource)
if vpc.subResource == "" {
return r, nil
}
return fmt.Sprintf("%s/%s", r, vpc.subResource), nil
}
// Do try to do MetaDataRequest
func (vpc *MetaDataRequest) Do(api interface{}) (err error) {
var res = ""
for r := retry.Start(); r.Next(); {
if vpc.sendRequest != nil {
res, err = vpc.sendRequest(vpc.resource)
} else {
res, err = vpc.send()
}
if !shouldRetry(err) {
break
}
}
if err != nil {
return err
}
return vpc.Decode(res, api)
}
// Decode returns decoded content
func (vpc *MetaDataRequest) Decode(data string, api interface{}) error {
if data == "" {
url, _ := vpc.Url()
return fmt.Errorf("metadata: alivpc decode data must not be nil. url=[%s]\n", url)
}
switch api.(type) {
case *ResultList:
api.(*ResultList).result = strings.Split(data, "\n")
return nil
case *RoleAuth:
return json.Unmarshal([]byte(data), api)
default:
return fmt.Errorf("metadata: unknow type to decode, type=%s\n", reflect.TypeOf(api))
}
}
func (vpc *MetaDataRequest) send() (string, error) {
url, err := vpc.Url()
if err != nil {
return "", err
}
requ, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return "", err
}
resp, err := vpc.client.Do(requ)
if err != nil {
return "", err
}
if resp.StatusCode != 200 {
return "", fmt.Errorf("Aliyun Metadata API Error: Status Code: %d", resp.StatusCode)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(data), nil
}
// TimeoutError interface
type TimeoutError interface {
error
Timeout() bool // Is the error a timeout?
}
func shouldRetry(err error) bool {
if err == nil {
return false
}
_, ok := err.(TimeoutError)
if ok {
return true
}
switch err {
case io.ErrUnexpectedEOF, io.EOF:
return true
}
switch e := err.(type) {
case *net.DNSError:
return true
case *net.OpError:
switch e.Op {
case "read", "write":
return true
}
case *url.Error:
// url.Error can be returned either by net/url if a URL cannot be
// parsed, or by net/http if the response is closed before the headers
// are received or parsed correctly. In that later case, e.Op is set to
// the HTTP method name with the first letter uppercased. We don't want
// to retry on POST operations, since those are not idempotent, all the
// other ones should be safe to retry.
switch e.Op {
case "Get", "Put", "Delete", "Head":
return shouldRetry(e.Err)
default:
return false
}
}
return false
}
// ResultList struct
type ResultList struct {
result []string
}
// RoleAuth struct
type RoleAuth struct {
AccessKeyId string
AccessKeySecret string
Expiration time.Time
SecurityToken string
LastUpdated time.Time
Code string
}

View File

@ -0,0 +1,42 @@
// +build alicloud
/*
Copyright 2018 The Kubernetes Authors.
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 builder
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud"
"k8s.io/autoscaler/cluster-autoscaler/config"
)
// AvailableCloudProviders supported by the cloud provider builder.
var AvailableCloudProviders = []string{
alicloud.ProviderName,
}
// DefaultCloudProvider for alicloud-only build is alicloud.
const DefaultCloudProvider = alicloud.ProviderName
func buildCloudProvider(opts config.AutoscalingOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter) cloudprovider.CloudProvider {
switch opts.CloudProviderName {
case alicloud.ProviderName:
return alicloud.BuildAlicloud(opts, do, rl)
}
return nil
}

View File

@ -1,4 +1,4 @@
// +build !gce,!aws,!azure,!kubemark
// +build !gce,!aws,!azure,!kubemark,!alicloud
/*
Copyright 2018 The Kubernetes Authors.
@ -20,6 +20,7 @@ package builder
import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/aws"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/azure"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/gce"
@ -33,6 +34,7 @@ var AvailableCloudProviders = []string{
azure.ProviderName,
gce.ProviderNameGCE,
gke.ProviderNameGKE,
alicloud.ProviderName,
}
// DefaultCloudProvider is GCE.
@ -48,7 +50,8 @@ func buildCloudProvider(opts config.AutoscalingOptions, do cloudprovider.NodeGro
return aws.BuildAWS(opts, do, rl)
case azure.ProviderName:
return azure.BuildAzure(opts, do, rl)
case alicloud.ProviderName:
return alicloud.BuildAlicloud(opts, do, rl)
}
return nil
}