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:
parent
609e9e44a6
commit
962826e46a
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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{}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 = ""
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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{},
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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"`
|
||||
}
|
||||
|
|
@ -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"`
|
||||
}
|
||||
|
|
@ -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"`
|
||||
}
|
||||
|
|
@ -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"`
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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(®ion)
|
||||
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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue