Add tencentcloud to list of supported cloud providers

This commit is contained in:
Jerry Chan 2022-01-23 19:47:13 +08:00
parent 5cf3b9657f
commit de0588d1f4
No known key found for this signature in database
GPG Key ID: 5C46F958AF65CDE8
63 changed files with 78162 additions and 2 deletions

View File

@ -29,6 +29,7 @@ You should also take a look at the notes and "gotchas" for your specific cloud p
* [ClusterAPI](./cloudprovider/clusterapi/README.md)
* [BizflyCloud](./cloudprovider/bizflycloud/README.md)
* [Vultr](./cloudprovider/vultr/README.md)
* [TencentCloud](./cloudprovider/tencentcloud/README.md)
# Releases
@ -171,3 +172,4 @@ Supported cloud providers:
* Hetzner https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/hetzner/README.md
* Cluster API https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md
* Vultr https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/vultr/README.md
* TencentCloud https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/tencentcloud/README.md

View File

@ -1,5 +1,5 @@
//go:build !gce && !aws && !azure && !kubemark && !alicloud && !magnum && !digitalocean && !clusterapi && !huaweicloud && !ionoscloud && !linode && !hetzner && !bizflycloud && !brightbox && !packet && !oci && !vultr
// +build !gce,!aws,!azure,!kubemark,!alicloud,!magnum,!digitalocean,!clusterapi,!huaweicloud,!ionoscloud,!linode,!hetzner,!bizflycloud,!brightbox,!packet,!oci,!vultr
//go:build !gce && !aws && !azure && !kubemark && !alicloud && !magnum && !digitalocean && !clusterapi && !huaweicloud && !ionoscloud && !linode && !hetzner && !bizflycloud && !brightbox && !packet && !oci && !vultr && !tencentcloud
// +build !gce,!aws,!azure,!kubemark,!alicloud,!magnum,!digitalocean,!clusterapi,!huaweicloud,!ionoscloud,!linode,!hetzner,!bizflycloud,!brightbox,!packet,!oci,!vultr,!tencentcloud
/*
Copyright 2018 The Kubernetes Authors.
@ -40,6 +40,7 @@ import (
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/oci"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/ovhcloud"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/packet"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/vultr"
"k8s.io/autoscaler/cluster-autoscaler/config"
)
@ -66,6 +67,7 @@ var AvailableCloudProviders = []string{
cloudprovider.BrightboxProviderName,
cloudprovider.PacketProviderName,
cloudprovider.VultrProviderName,
cloudprovider.TencentcloudProviderName,
}
// DefaultCloudProvider is GCE.
@ -113,6 +115,8 @@ func buildCloudProvider(opts config.AutoscalingOptions, do cloudprovider.NodeGro
return oci.BuildOCI(opts, do, rl)
case cloudprovider.VultrProviderName:
return vultr.BuildVultr(opts, do, rl)
case cloudprovider.TencentcloudProviderName:
return tencentcloud.BuildTencentcloud(opts, do, rl)
}
return nil
}

View File

@ -0,0 +1,43 @@
//go:build tencentcloud
// +build tencentcloud
/*
Copyright 2021 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/tencentcloud"
"k8s.io/autoscaler/cluster-autoscaler/config"
)
// AvailableCloudProviders supported by the cloud provider builder.
var AvailableCloudProviders = []string{
cloudprovider.TencentcloudProviderName,
}
// DefaultCloudProvider is TKE.
const DefaultCloudProvider = cloudprovider.TkeProviderName
func buildCloudProvider(opts config.AutoscalingOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter) cloudprovider.CloudProvider {
switch opts.CloudProviderName {
case cloudprovider.TencentcloudProviderName:
return tencentcloud.BuildTencentcloud(opts, do, rl)
}
return nil
}

View File

@ -70,6 +70,8 @@ const (
VultrProviderName = "vultr"
// PacketProviderName gets the provider name of packet
PacketProviderName = "packet"
// TencentcloudProviderName gets the provider name of tencentcloud
TencentcloudProviderName = "tencentcloud"
)
// CloudProvider contains configuration info and functions for interacting with

View File

@ -0,0 +1,4 @@
approvers:
# - alphajc
reviewers:
# - alphajc

View File

@ -0,0 +1,181 @@
# Cluster Autoscaler on TencentCloud
On TencentCloud, Cluster Autoscaler utilizes CVM Auto Scaling Groups to manage node
groups. Cluster Autoscaler typically runs as a `Deployment` in your cluster.
## Requirements
Cluster Autoscaler requires [TKE](https://intl.cloud.tencent.com/document/product/457) v1.10.x or greater.
## Permissions
### CAM Policy
The following policy provides the minimum privileges necessary for Cluster Autoscaler to run:
```json
{
"version": "2.0",
"statement": [
{
"effect": "allow",
"action": [
"tke:DeleteClusterInstances",
"tke:DescribeClusterAsGroups",
"as:ModifyAutoScalingGroup",
"as:RemoveInstances",
"as:StopAutoScalingInstances",
"as:DescribeAutoScalingGroups",
"as:DescribeAutoScalingInstances",
"as:DescribeLaunchConfigurations",
"as:DescribeAutoScalingActivities"
],
"resource": [
"*"
]
}
]
}
```
### Using TencentCloud Credentials
> NOTICE: Make sure the [access key](https://intl.cloud.tencent.com/document/product/598/32675) you will be using has all the above permissions
```yaml
apiVersion: v1
kind: Secret
metadata:
name: tencentcloud-secret
type: Opaque
data:
tencentcloud_secret_id: BASE64_OF_YOUR_TENCENTCLOUD_SECRET_ID
tencentcloud_secret_key: BASE64_OF_YOUR_TENCENTCLOUD_SECRET_KEY
```
Please refer to the [relevant Kubernetes
documentation](https://kubernetes.io/docs/concepts/configuration/secret/#creating-a-secret-manually)
for creating a secret manually.
```yaml
env:
- name: SECRET_ID
valueFrom:
secretKeyRef:
name: tencentcloud-secret
key: tencentcloud_secret_id
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: tencentcloud-secret
key: tencentcloud_secret_key
- name: REGION
value: YOUR_TENCENCLOUD_REGION
- name: REGION_NAME
value: YOUR_TENCENCLOUD_REGION_NAME
- name: CLUSTER_ID
value: YOUR_TKE_CLUSTER_ID
```
## Setup
### cluster-autoscaler deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
selector:
matchLabels:
qcloud-app: cluster-autoscaler
template:
metadata:
labels:
qcloud-app: cluster-autoscaler
spec:
containers:
- args:
- --cloud-provider=tencentcloud
- --v=4
- --ok-total-unready-count=3
- --cloud-config=/etc/kubernetes/qcloud.conf
- --scale-down-utilization-threshold=0.8
- --scale-down-enabled=true
- --max-total-unready-percentage=33
- --nodes=[min]:[max]:[ASG_ID]
- --logtostderr
- --kubeconfig=/kubeconfig/config
command:
- /cluster-autoscaler
env:
- name: SECRET_ID
valueFrom:
secretKeyRef:
name: tencentcloud-secret
key: tencentcloud_secret_id
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: tencentcloud-secret
key: tencentcloud_secret_key
- name: REGION
value: YOUR_TENCENCLOUD_REGION
- name: REGION_NAME
value: YOUR_TENCENCLOUD_REGION_NAME
- name: CLUSTER_ID
value: YOUR_TKE_CLUSTER_ID
image: ccr.ccs.tencentyun.com/tkeimages/cluster-autoscaler:v1.18.4-49692187a
imagePullPolicy: Always
name: cluster-autoscaler
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
volumeMounts:
- mountPath: /etc/localtime
name: tz-config
hostAliases:
- hostnames:
- cbs.api.qcloud.com
- cvm.api.qcloud.com
- lb.api.qcloud.com
- tag.api.qcloud.com
- snapshot.api.qcloud.com
- monitor.api.qcloud.com
- scaling.api.qcloud.com
- ccs.api.qcloud.com
ip: 169.254.0.28
- hostnames:
- tke.internal.tencentcloudapi.com
- clb.internal.tencentcloudapi.com
- cvm.internal.tencentcloudapi.com
- tag.internal.tencentcloudapi.com
- as.tencentcloudapi.com
- cbs.tencentcloudapi.com
- cvm.tencentcloudapi.com
- vpc.tencentcloudapi.com
- tke.tencentcloudapi.com
ip: 169.254.0.95
restartPolicy: Always
serviceAccount: kube-admin
serviceAccountName: kube-admin
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
volumes:
- hostPath:
path: /etc/localtime
type: ""
name: tz-config
```
### Auto-Discovery Setup
Auto Discovery is not supported in TencentCloud currently.

View File

@ -0,0 +1,66 @@
/*
Copyright 2016 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 metrics
import (
tencent_errors "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
k8smetrics "k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry"
)
const (
caNamespace = "cluster_autoscaler"
)
var (
cloudAPIInvokedCount = k8smetrics.NewCounterVec(
&k8smetrics.CounterOpts{
Namespace: caNamespace,
Name: "invoked_cloudapi_total",
Help: "Number of cloudapi invoked by Node Autoprovisioning.",
}, []string{"service", "ops"},
)
cloudAPIInvokedErrorCount = k8smetrics.NewCounterVec(
&k8smetrics.CounterOpts{
Namespace: caNamespace,
Name: "invoked_cloudapi_error_total",
Help: "Number of errors that cloudapi invoked by Node Autoprovisioning.",
}, []string{"service", "ops", "code"},
)
)
func init() {
legacyregistry.MustRegister(cloudAPIInvokedCount)
legacyregistry.MustRegister(cloudAPIInvokedErrorCount)
}
// RegisterCloudAPIInvoked registers cloudapi invoked
func RegisterCloudAPIInvoked(service string, ops string, err error) {
cloudAPIInvokedCount.WithLabelValues(service, ops).Inc()
if err != nil {
if e, ok := err.(*tencent_errors.TencentCloudSDKError); ok {
RegisterCloudAPIInvokedError("as", "DescribeAutoScalingGroups", e.Code)
}
}
}
// RegisterCloudAPIInvokedError registers error in cloudapi invoked
func RegisterCloudAPIInvokedError(service string, ops string, code string) {
cloudAPIInvokedErrorCount.WithLabelValues(service, ops, code).Inc()
}

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2017-2018 Tencent Ltd.
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.

View File

@ -0,0 +1,444 @@
/*
Copyright 2016 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 v20180419
const (
// 此产品的特有错误码
// 该请求账户未通过资格审计。
ACCOUNTQUALIFICATIONRESTRICTIONS = "AccountQualificationRestrictions"
// CVM接口调用失败。
CALLCVMERROR = "CallCvmError"
// 未生成伸缩活动。
FAILEDOPERATION_NOACTIVITYTOGENERATE = "FailedOperation.NoActivityToGenerate"
// 内部错误。
INTERNALERROR = "InternalError"
// Cmq 接口调用失败。
INTERNALERROR_CALLCMQERROR = "InternalError.CallCmqError"
// 内部接口调用失败。
INTERNALERROR_CALLERROR = "InternalError.CallError"
// LB 接口调用失败。
INTERNALERROR_CALLLBERROR = "InternalError.CallLbError"
// Monitor接口调用失败。
INTERNALERROR_CALLMONITORERROR = "InternalError.CallMonitorError"
// 通知服务接口调用失败。
INTERNALERROR_CALLNOTIFICATIONERROR = "InternalError.CallNotificationError"
// STS 接口调用失败。
INTERNALERROR_CALLSTSERROR = "InternalError.CallStsError"
// Tag 接口调用失败。
INTERNALERROR_CALLTAGERROR = "InternalError.CallTagError"
// Tvpc 接口调用失败。
INTERNALERROR_CALLTVPCERROR = "InternalError.CallTvpcError"
// VPC接口调用失败。
INTERNALERROR_CALLVPCERROR = "InternalError.CallVpcError"
// 调用其他服务异常。
INTERNALERROR_CALLEEERROR = "InternalError.CalleeError"
// 内部请求错误。
INTERNALERROR_REQUESTERROR = "InternalError.RequestError"
// 未找到该镜像。
INVALIDIMAGEID_NOTFOUND = "InvalidImageId.NotFound"
// 无效的启动配置。
INVALIDLAUNCHCONFIGURATION = "InvalidLaunchConfiguration"
// 启动配置ID无效。
INVALIDLAUNCHCONFIGURATIONID = "InvalidLaunchConfigurationId"
// 参数错误。
INVALIDPARAMETER = "InvalidParameter"
// 参数冲突,指定的多个参数冲突,不能同时存在。
INVALIDPARAMETER_CONFLICT = "InvalidParameter.Conflict"
// 主机名参数不适用于该镜像。
INVALIDPARAMETER_HOSTNAMEUNAVAILABLE = "InvalidParameter.HostNameUnavailable"
// 在特定场景下的不合法参数。
INVALIDPARAMETER_INSCENARIO = "InvalidParameter.InScenario"
// 无效的参数组合。
INVALIDPARAMETER_INVALIDCOMBINATION = "InvalidParameter.InvalidCombination"
// 指定的负载均衡器在当前伸缩组中没有找到。
INVALIDPARAMETER_LOADBALANCERNOTINAUTOSCALINGGROUP = "InvalidParameter.LoadBalancerNotInAutoScalingGroup"
// 参数缺失,两种参数之中必须指定其中一个。
INVALIDPARAMETER_MUSTONEPARAMETER = "InvalidParameter.MustOneParameter"
// 部分参数存在互斥应该删掉。
INVALIDPARAMETER_PARAMETERMUSTBEDELETED = "InvalidParameter.ParameterMustBeDeleted"
// 指定的两个参数冲突,不能同时存在。
INVALIDPARAMETERCONFLICT = "InvalidParameterConflict"
// 参数取值错误。
INVALIDPARAMETERVALUE = "InvalidParameterValue"
// 指定的基础容量过大,需小于等于最大实例数。
INVALIDPARAMETERVALUE_BASECAPACITYTOOLARGE = "InvalidParameterValue.BaseCapacityTooLarge"
// 在应当指定传统型负载均衡器的参数中,错误地指定了一个非传统型的负载均衡器。
INVALIDPARAMETERVALUE_CLASSICLB = "InvalidParameterValue.ClassicLb"
// 通知接收端类型冲突。
INVALIDPARAMETERVALUE_CONFLICTNOTIFICATIONTARGET = "InvalidParameterValue.ConflictNotificationTarget"
// 定时任务指定的Cron表达式无效。
INVALIDPARAMETERVALUE_CRONEXPRESSIONILLEGAL = "InvalidParameterValue.CronExpressionIllegal"
// CVM参数校验异常。
INVALIDPARAMETERVALUE_CVMCONFIGURATIONERROR = "InvalidParameterValue.CvmConfigurationError"
// CVM参数校验异常。
INVALIDPARAMETERVALUE_CVMERROR = "InvalidParameterValue.CvmError"
// 提供的应用型负载均衡器重复。
INVALIDPARAMETERVALUE_DUPLICATEDFORWARDLB = "InvalidParameterValue.DuplicatedForwardLb"
// 指定的子网重复。
INVALIDPARAMETERVALUE_DUPLICATEDSUBNET = "InvalidParameterValue.DuplicatedSubnet"
// 定时任务设置的结束时间在开始时间。
INVALIDPARAMETERVALUE_ENDTIMEBEFORESTARTTIME = "InvalidParameterValue.EndTimeBeforeStartTime"
// 无效的过滤器。
INVALIDPARAMETERVALUE_FILTER = "InvalidParameterValue.Filter"
// 在应当指定应用型负载均衡器的参数中,错误地指定了一个非应用型的负载均衡器。
INVALIDPARAMETERVALUE_FORWARDLB = "InvalidParameterValue.ForwardLb"
// 伸缩组名称重复。
INVALIDPARAMETERVALUE_GROUPNAMEDUPLICATED = "InvalidParameterValue.GroupNameDuplicated"
// 主机名不合法。
INVALIDPARAMETERVALUE_HOSTNAMEILLEGAL = "InvalidParameterValue.HostNameIllegal"
// 指定的镜像不存在。
INVALIDPARAMETERVALUE_IMAGENOTFOUND = "InvalidParameterValue.ImageNotFound"
// 设置的实例名称不合法。
INVALIDPARAMETERVALUE_INSTANCENAMEILLEGAL = "InvalidParameterValue.InstanceNameIllegal"
// 实例机型不支持。
INVALIDPARAMETERVALUE_INSTANCETYPENOTSUPPORTED = "InvalidParameterValue.InstanceTypeNotSupported"
// 伸缩活动ID无效。
INVALIDPARAMETERVALUE_INVALIDACTIVITYID = "InvalidParameterValue.InvalidActivityId"
// 伸缩组ID无效。
INVALIDPARAMETERVALUE_INVALIDAUTOSCALINGGROUPID = "InvalidParameterValue.InvalidAutoScalingGroupId"
// 通知ID无效。
INVALIDPARAMETERVALUE_INVALIDAUTOSCALINGNOTIFICATIONID = "InvalidParameterValue.InvalidAutoScalingNotificationId"
// 告警策略ID无效。
INVALIDPARAMETERVALUE_INVALIDAUTOSCALINGPOLICYID = "InvalidParameterValue.InvalidAutoScalingPolicyId"
// 为CLB指定的地域不合法。
INVALIDPARAMETERVALUE_INVALIDCLBREGION = "InvalidParameterValue.InvalidClbRegion"
// 过滤条件无效。
INVALIDPARAMETERVALUE_INVALIDFILTER = "InvalidParameterValue.InvalidFilter"
// 镜像ID无效。
INVALIDPARAMETERVALUE_INVALIDIMAGEID = "InvalidParameterValue.InvalidImageId"
// 实例ID无效。
INVALIDPARAMETERVALUE_INVALIDINSTANCEID = "InvalidParameterValue.InvalidInstanceId"
// 实例机型无效。
INVALIDPARAMETERVALUE_INVALIDINSTANCETYPE = "InvalidParameterValue.InvalidInstanceType"
// 输入的启动配置无效。
INVALIDPARAMETERVALUE_INVALIDLAUNCHCONFIGURATION = "InvalidParameterValue.InvalidLaunchConfiguration"
// 启动配置ID无效。
INVALIDPARAMETERVALUE_INVALIDLAUNCHCONFIGURATIONID = "InvalidParameterValue.InvalidLaunchConfigurationId"
// 生命周期挂钩ID无效。
INVALIDPARAMETERVALUE_INVALIDLIFECYCLEHOOKID = "InvalidParameterValue.InvalidLifecycleHookId"
// 指定的通知组 ID 不是数值字符串格式。
INVALIDPARAMETERVALUE_INVALIDNOTIFICATIONUSERGROUPID = "InvalidParameterValue.InvalidNotificationUserGroupId"
// 指定的PAI域名类型不支持。
INVALIDPARAMETERVALUE_INVALIDPAIDOMAINNAMETYPE = "InvalidParameterValue.InvalidPaiDomainNameType"
// 定时任务ID无效。
INVALIDPARAMETERVALUE_INVALIDSCHEDULEDACTIONID = "InvalidParameterValue.InvalidScheduledActionId"
// 定时任务名称包含无效字符。
INVALIDPARAMETERVALUE_INVALIDSCHEDULEDACTIONNAMEINCLUDEILLEGALCHAR = "InvalidParameterValue.InvalidScheduledActionNameIncludeIllegalChar"
// 快照ID无效。
INVALIDPARAMETERVALUE_INVALIDSNAPSHOTID = "InvalidParameterValue.InvalidSnapshotId"
// 子网ID无效。
INVALIDPARAMETERVALUE_INVALIDSUBNETID = "InvalidParameterValue.InvalidSubnetId"
// 启动配置名称重复。
INVALIDPARAMETERVALUE_LAUNCHCONFIGURATIONNAMEDUPLICATED = "InvalidParameterValue.LaunchConfigurationNameDuplicated"
// 找不到指定启动配置。
INVALIDPARAMETERVALUE_LAUNCHCONFIGURATIONNOTFOUND = "InvalidParameterValue.LaunchConfigurationNotFound"
// 负载均衡器项目不一致。
INVALIDPARAMETERVALUE_LBPROJECTINCONSISTENT = "InvalidParameterValue.LbProjectInconsistent"
// 生命周期挂钩名称重复。
INVALIDPARAMETERVALUE_LIFECYCLEHOOKNAMEDUPLICATED = "InvalidParameterValue.LifecycleHookNameDuplicated"
// 取值超出限制。
INVALIDPARAMETERVALUE_LIMITEXCEEDED = "InvalidParameterValue.LimitExceeded"
// 无资源权限。
INVALIDPARAMETERVALUE_NORESOURCEPERMISSION = "InvalidParameterValue.NoResourcePermission"
// 提供的值不是浮点字符串格式。
INVALIDPARAMETERVALUE_NOTSTRINGTYPEFLOAT = "InvalidParameterValue.NotStringTypeFloat"
// 账号仅支持VPC网络。
INVALIDPARAMETERVALUE_ONLYVPC = "InvalidParameterValue.OnlyVpc"
// 项目ID不存在。
INVALIDPARAMETERVALUE_PROJECTIDNOTFOUND = "InvalidParameterValue.ProjectIdNotFound"
// 取值超出指定范围。
INVALIDPARAMETERVALUE_RANGE = "InvalidParameterValue.Range"
// 告警策略名称重复。
INVALIDPARAMETERVALUE_SCALINGPOLICYNAMEDUPLICATE = "InvalidParameterValue.ScalingPolicyNameDuplicate"
// 定时任务名称重复。
INVALIDPARAMETERVALUE_SCHEDULEDACTIONNAMEDUPLICATE = "InvalidParameterValue.ScheduledActionNameDuplicate"
// 伸缩组最大数量、最小数量、期望实例数取值不合法。
INVALIDPARAMETERVALUE_SIZE = "InvalidParameterValue.Size"
// 定时任务设置的开始时间在当前时间之前。
INVALIDPARAMETERVALUE_STARTTIMEBEFORECURRENTTIME = "InvalidParameterValue.StartTimeBeforeCurrentTime"
// 子网信息不合法。
INVALIDPARAMETERVALUE_SUBNETIDS = "InvalidParameterValue.SubnetIds"
// 负载均衡器四层监听器的后端端口重复。
INVALIDPARAMETERVALUE_TARGETPORTDUPLICATED = "InvalidParameterValue.TargetPortDuplicated"
// 指定的阈值不在有效范围。
INVALIDPARAMETERVALUE_THRESHOLDOUTOFRANGE = "InvalidParameterValue.ThresholdOutOfRange"
// 时间格式错误。
INVALIDPARAMETERVALUE_TIMEFORMAT = "InvalidParameterValue.TimeFormat"
// 取值过多。
INVALIDPARAMETERVALUE_TOOLONG = "InvalidParameterValue.TooLong"
// 输入参数值的长度小于最小值。
INVALIDPARAMETERVALUE_TOOSHORT = "InvalidParameterValue.TooShort"
// UserData格式错误。
INVALIDPARAMETERVALUE_USERDATAFORMATERROR = "InvalidParameterValue.UserDataFormatError"
// UserData长度过长。
INVALIDPARAMETERVALUE_USERDATASIZEEXCEEDED = "InvalidParameterValue.UserDataSizeExceeded"
// 用户组不存在。
INVALIDPARAMETERVALUE_USERGROUPIDNOTFOUND = "InvalidParameterValue.UserGroupIdNotFound"
// 指定的可用区与地域不匹配。
INVALIDPARAMETERVALUE_ZONEMISMATCHREGION = "InvalidParameterValue.ZoneMismatchRegion"
// 账户不支持该操作。
INVALIDPERMISSION = "InvalidPermission"
// 超过配额限制。
LIMITEXCEEDED = "LimitExceeded"
// 绑定指定的负载均衡器后,伸缩组绑定的负载均衡器总数超过了最大值。
LIMITEXCEEDED_AFTERATTACHLBLIMITEXCEEDED = "LimitExceeded.AfterAttachLbLimitExceeded"
// 伸缩组数量超过限制。
LIMITEXCEEDED_AUTOSCALINGGROUPLIMITEXCEEDED = "LimitExceeded.AutoScalingGroupLimitExceeded"
// 期望实例数超出限制。
LIMITEXCEEDED_DESIREDCAPACITYLIMITEXCEEDED = "LimitExceeded.DesiredCapacityLimitExceeded"
// 特定过滤器的值过多。
LIMITEXCEEDED_FILTERVALUESTOOLONG = "LimitExceeded.FilterValuesTooLong"
// 启动配置配额不足。
LIMITEXCEEDED_LAUNCHCONFIGURATIONQUOTANOTENOUGH = "LimitExceeded.LaunchConfigurationQuotaNotEnough"
// 最大实例数大于限制。
LIMITEXCEEDED_MAXSIZELIMITEXCEEDED = "LimitExceeded.MaxSizeLimitExceeded"
// 最小实例数低于限制。
LIMITEXCEEDED_MINSIZELIMITEXCEEDED = "LimitExceeded.MinSizeLimitExceeded"
// 当前剩余配额不足。
LIMITEXCEEDED_QUOTANOTENOUGH = "LimitExceeded.QuotaNotEnough"
// 定时任务数量超过限制。
LIMITEXCEEDED_SCHEDULEDACTIONLIMITEXCEEDED = "LimitExceeded.ScheduledActionLimitExceeded"
// 缺少参数错误。
MISSINGPARAMETER = "MissingParameter"
// 在特定场景下缺少参数。
MISSINGPARAMETER_INSCENARIO = "MissingParameter.InScenario"
// 竞价计费类型缺少对应的 InstanceMarketOptions 参数。
MISSINGPARAMETER_INSTANCEMARKETOPTIONS = "MissingParameter.InstanceMarketOptions"
// 伸缩组正在执行伸缩活动。
RESOURCEINUSE_ACTIVITYINPROGRESS = "ResourceInUse.ActivityInProgress"
// 伸缩组处于禁用状态。
RESOURCEINUSE_AUTOSCALINGGROUPNOTACTIVE = "ResourceInUse.AutoScalingGroupNotActive"
// 伸缩组内尚有正常实例。
RESOURCEINUSE_INSTANCEINGROUP = "ResourceInUse.InstanceInGroup"
// 指定的启动配置仍在伸缩组中使用。
RESOURCEINUSE_LAUNCHCONFIGURATIONIDINUSE = "ResourceInUse.LaunchConfigurationIdInUse"
// 超过伸缩组最大实例数。
RESOURCEINSUFFICIENT_AUTOSCALINGGROUPABOVEMAXSIZE = "ResourceInsufficient.AutoScalingGroupAboveMaxSize"
// 少于伸缩组最小实例数。
RESOURCEINSUFFICIENT_AUTOSCALINGGROUPBELOWMINSIZE = "ResourceInsufficient.AutoScalingGroupBelowMinSize"
// 伸缩组内实例数超过最大实例数。
RESOURCEINSUFFICIENT_INSERVICEINSTANCEABOVEMAXSIZE = "ResourceInsufficient.InServiceInstanceAboveMaxSize"
// 伸缩组内实例数低于最小实例数。
RESOURCEINSUFFICIENT_INSERVICEINSTANCEBELOWMINSIZE = "ResourceInsufficient.InServiceInstanceBelowMinSize"
// 伸缩组不存在。
RESOURCENOTFOUND_AUTOSCALINGGROUPNOTFOUND = "ResourceNotFound.AutoScalingGroupNotFound"
// 通知不存在。
RESOURCENOTFOUND_AUTOSCALINGNOTIFICATIONNOTFOUND = "ResourceNotFound.AutoScalingNotificationNotFound"
// 指定的 CMQ queue 不存在。
RESOURCENOTFOUND_CMQQUEUENOTFOUND = "ResourceNotFound.CmqQueueNotFound"
// 指定的实例不存在。
RESOURCENOTFOUND_INSTANCESNOTFOUND = "ResourceNotFound.InstancesNotFound"
// 目标实例不在伸缩组内。
RESOURCENOTFOUND_INSTANCESNOTINAUTOSCALINGGROUP = "ResourceNotFound.InstancesNotInAutoScalingGroup"
// 指定的启动配置不存在。
RESOURCENOTFOUND_LAUNCHCONFIGURATIONIDNOTFOUND = "ResourceNotFound.LaunchConfigurationIdNotFound"
// 生命周期挂钩对应实例不存在。
RESOURCENOTFOUND_LIFECYCLEHOOKINSTANCENOTFOUND = "ResourceNotFound.LifecycleHookInstanceNotFound"
// 无法找到指定生命周期挂钩。
RESOURCENOTFOUND_LIFECYCLEHOOKNOTFOUND = "ResourceNotFound.LifecycleHookNotFound"
// 指定的Listener不存在。
RESOURCENOTFOUND_LISTENERNOTFOUND = "ResourceNotFound.ListenerNotFound"
// 找不到指定负载均衡器。
RESOURCENOTFOUND_LOADBALANCERNOTFOUND = "ResourceNotFound.LoadBalancerNotFound"
// 指定的Location不存在。
RESOURCENOTFOUND_LOCATIONNOTFOUND = "ResourceNotFound.LocationNotFound"
// 告警策略不存在。
RESOURCENOTFOUND_SCALINGPOLICYNOTFOUND = "ResourceNotFound.ScalingPolicyNotFound"
// 指定的定时任务不存在。
RESOURCENOTFOUND_SCHEDULEDACTIONNOTFOUND = "ResourceNotFound.ScheduledActionNotFound"
// TDMQ-CMQ 队列不存在。
RESOURCENOTFOUND_TDMQCMQQUEUENOTFOUND = "ResourceNotFound.TDMQCMQQueueNotFound"
// TDMQ-CMQ 主题不存在。
RESOURCENOTFOUND_TDMQCMQTOPICNOTFOUND = "ResourceNotFound.TDMQCMQTopicNotFound"
// 伸缩组状态异常。
RESOURCEUNAVAILABLE_AUTOSCALINGGROUPABNORMALSTATUS = "ResourceUnavailable.AutoScalingGroupAbnormalStatus"
// 伸缩组被停用。
RESOURCEUNAVAILABLE_AUTOSCALINGGROUPDISABLED = "ResourceUnavailable.AutoScalingGroupDisabled"
// 伸缩组正在活动中。
RESOURCEUNAVAILABLE_AUTOSCALINGGROUPINACTIVITY = "ResourceUnavailable.AutoScalingGroupInActivity"
// 指定的 CMQ Topic 无订阅者。
RESOURCEUNAVAILABLE_CMQTOPICHASNOSUBSCRIBER = "ResourceUnavailable.CmqTopicHasNoSubscriber"
// 实例和伸缩组Vpc不一致。
RESOURCEUNAVAILABLE_CVMVPCINCONSISTENT = "ResourceUnavailable.CvmVpcInconsistent"
// 指定的实例正在活动中。
RESOURCEUNAVAILABLE_INSTANCEINOPERATION = "ResourceUnavailable.InstanceInOperation"
// 实例不支持关机不收费。
RESOURCEUNAVAILABLE_INSTANCENOTSUPPORTSTOPCHARGING = "ResourceUnavailable.InstanceNotSupportStopCharging"
// 实例已存在于伸缩组中。
RESOURCEUNAVAILABLE_INSTANCESALREADYINAUTOSCALINGGROUP = "ResourceUnavailable.InstancesAlreadyInAutoScalingGroup"
// 启动配置状态异常。
RESOURCEUNAVAILABLE_LAUNCHCONFIGURATIONSTATUSABNORMAL = "ResourceUnavailable.LaunchConfigurationStatusAbnormal"
// CLB实例的后端地域与AS服务所在地域不一致。
RESOURCEUNAVAILABLE_LBBACKENDREGIONINCONSISTENT = "ResourceUnavailable.LbBackendRegionInconsistent"
// 负载均衡器项目不一致。
RESOURCEUNAVAILABLE_LBPROJECTINCONSISTENT = "ResourceUnavailable.LbProjectInconsistent"
// 负载均衡器VPC与伸缩组不一致。
RESOURCEUNAVAILABLE_LBVPCINCONSISTENT = "ResourceUnavailable.LbVpcInconsistent"
// 生命周期动作已经被设置。
RESOURCEUNAVAILABLE_LIFECYCLEACTIONRESULTHASSET = "ResourceUnavailable.LifecycleActionResultHasSet"
// LB 在指定的伸缩组内处于活动中。
RESOURCEUNAVAILABLE_LOADBALANCERINOPERATION = "ResourceUnavailable.LoadBalancerInOperation"
// 项目不一致。
RESOURCEUNAVAILABLE_PROJECTINCONSISTENT = "ResourceUnavailable.ProjectInconsistent"
// 关机实例不允许添加到伸缩组。
RESOURCEUNAVAILABLE_STOPPEDINSTANCENOTALLOWATTACH = "ResourceUnavailable.StoppedInstanceNotAllowAttach"
// TDMQ-CMQ 主题无订阅者。
RESOURCEUNAVAILABLE_TDMQCMQTOPICHASNOSUBSCRIBER = "ResourceUnavailable.TDMQCMQTopicHasNoSubscriber"
// 指定的可用区不可用。
RESOURCEUNAVAILABLE_ZONEUNAVAILABLE = "ResourceUnavailable.ZoneUnavailable"
)

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2017-2018 Tencent Ltd.
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.

View File

@ -0,0 +1,273 @@
/*
Copyright 2016 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 common
import (
"errors"
"strings"
"sync"
"time"
)
const (
defaultBackupEndpoint = "ap-guangzhou.tencentcloudapi.com"
defaultMaxFailNum = 5
defaultMaxFailPercentage = 75
defaultWindowLength = 1 * 60 * time.Second
defaultTimeout = 60 * time.Second
)
var (
// ErrOpenState is returned when the CB state is open
errOpenState = errors.New("circuit breaker is open")
)
// counter use atomic operations to ensure consistency
// Atomic operations perform better than mutex
type counter struct {
failures int
all int
consecutiveSuccesses int
consecutiveFailures int
}
func newRegionCounter() counter {
return counter{
failures: 0,
all: 0,
consecutiveSuccesses: 0,
consecutiveFailures: 0,
}
}
func (c *counter) onSuccess() {
c.all++
c.consecutiveSuccesses++
c.consecutiveFailures = 0
}
func (c *counter) onFailure() {
c.all++
c.failures++
c.consecutiveSuccesses = 0
c.consecutiveSuccesses = 0
}
func (c *counter) clear() {
c.all = 0
c.failures = 0
c.consecutiveSuccesses = 0
}
// State is a type that represents a state of CircuitBreaker.
type state int
// These constants are states of CircuitBreaker.
const (
StateClosed state = iota
StateHalfOpen
StateOpen
)
type breakerSetting struct {
// backupEndpoint
// the default is "ap-guangzhou.tencentcloudapi.com"
backupEndpoint string
// max fail nums
// the default is 5
maxFailNum int
// max fail percentage
// the default is 75/100
maxFailPercentage int
// windowInterval decides when to reset counter if the state is StateClosed
// the default is 5minutes
windowInterval time.Duration
// timeout decides when to turn StateOpen to StateHalfOpen
// the default is 60s
timeout time.Duration
// maxRequests decides when to turn StateHalfOpen to StateClosed
maxRequests int
}
type circuitBreaker struct {
// settings
breakerSetting
// read and write lock
mu sync.Mutex
// the breaker's state: closed, open, half-open
state state
// expiry time determines whether to enter the next generation
// if in StateClosed, it will be now + windowInterval
// if in StateOpen, it will be now + timeout
// if in StateHalfOpen. it will be zero
expiry time.Time
// generation decide whether add the afterRequest's request to counter
generation uint64
// counter
counter counter
}
func newRegionBreaker(set breakerSetting) (re *circuitBreaker) {
re = new(circuitBreaker)
re.breakerSetting = set
return
}
func defaultRegionBreaker() *circuitBreaker {
defaultSet := breakerSetting{
backupEndpoint: defaultBackupEndpoint,
maxFailNum: defaultMaxFailNum,
maxFailPercentage: defaultMaxFailPercentage,
windowInterval: defaultWindowLength,
timeout: defaultTimeout,
}
return newRegionBreaker(defaultSet)
}
// currentState return the current state.
// if in StateClosed and now is over expiry time, it will turn to a new generation.
// if in StateOpen and now is over expiry time, it will turn to StateHalfOpen
func (s *circuitBreaker) currentState(now time.Time) (state, uint64) {
switch s.state {
case StateClosed:
if s.expiry.Before(now) {
s.toNewGeneration(now)
}
case StateOpen:
if s.expiry.Before(now) {
s.setState(StateHalfOpen, now)
}
}
return s.state, s.generation
}
// setState set the circuitBreaker's state to newState
// and turn to new generation
func (s *circuitBreaker) setState(newState state, now time.Time) {
if s.state == newState {
return
}
s.state = newState
s.toNewGeneration(now)
}
// toNewGeneration will increase the generation and clear the counter.
// it also will reset the expiry
func (s *circuitBreaker) toNewGeneration(now time.Time) {
s.generation++
s.counter.clear()
var zero time.Time
switch s.state {
case StateClosed:
s.expiry = now.Add(s.windowInterval)
case StateOpen:
s.expiry = now.Add(s.timeout)
default: // StateHalfOpen
s.expiry = zero
}
}
// beforeRequest return the current generation; if the breaker is in StateOpen, it will also return an errOpenState
func (s *circuitBreaker) beforeRequest() (uint64, error) {
s.mu.Lock()
defer s.mu.Unlock()
now := time.Now()
state, generation := s.currentState(now)
//log.Println(s.counter)
if state == StateOpen {
return generation, errOpenState
}
return generation, nil
}
func (s *circuitBreaker) afterRequest(before uint64, success bool) {
s.mu.Lock()
defer s.mu.Unlock()
now := time.Now()
state, generation := s.currentState(now)
// the breaker has entered the next generation, the current results abandon.
if generation != before {
return
}
if success {
s.onSuccess(state, now)
} else {
s.onFailure(state, now)
}
}
func (s *circuitBreaker) onSuccess(state state, now time.Time) {
switch state {
case StateClosed:
s.counter.onSuccess()
case StateHalfOpen:
s.counter.onSuccess()
// The conditions for closing breaker are met
if s.counter.all-s.counter.failures >= s.maxRequests {
s.setState(StateClosed, now)
}
}
}
func (s *circuitBreaker) readyToOpen(c counter) bool {
failPre := float64(c.failures) / float64(c.all)
return (c.failures >= s.maxFailNum && failPre >= float64(s.maxFailPercentage)/100.0) ||
c.consecutiveFailures > 5
}
func (s *circuitBreaker) onFailure(state state, now time.Time) {
switch state {
case StateClosed:
s.counter.onFailure()
if f := s.readyToOpen(s.counter); f {
s.setState(StateOpen, now)
}
case StateHalfOpen:
s.setState(StateOpen, now)
}
}
// checkEndpoint
// valid: cvm.ap-shanghai.tencentcloudapi.com, cvm.ap-shenzhen-fs.tencentcloudapi.comcvm.tencentcloudapi.com
// invalid: cvm.tencentcloud.com
func checkEndpoint(endpoint string) bool {
ss := strings.Split(endpoint, ".")
if len(ss) != 4 && len(ss) != 3 {
return false
}
if ss[len(ss)-2] != "tencentcloudapi" {
return false
}
// ap-beijing
if len(ss) == 4 && len(strings.Split(ss[1], "-")) < 2 {
return false
}
return true
}
func renewUrl(oldDomain, region string) string {
ss := strings.Split(oldDomain, ".")
if len(ss) == 3 {
ss = append([]string{ss[0], region}, ss[1:]...)
} else if len(ss) == 4 {
ss[1] = region
}
newDomain := strings.Join(ss, ".")
return newDomain
}

View File

@ -0,0 +1,405 @@
/*
Copyright 2016 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 common
import (
"encoding/hex"
"encoding/json"
"fmt"
"log"
"net/http"
"net/http/httputil"
"strconv"
"strings"
"time"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
tchttp "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
)
const (
octetStream = "application/octet-stream"
)
type Client struct {
region string
httpClient *http.Client
httpProfile *profile.HttpProfile
profile *profile.ClientProfile
credential CredentialIface
signMethod string
unsignedPayload bool
debug bool
rb *circuitBreaker
}
func (c *Client) Send(request tchttp.Request, response tchttp.Response) (err error) {
if request.GetScheme() == "" {
request.SetScheme(c.httpProfile.Scheme)
}
if request.GetRootDomain() == "" {
request.SetRootDomain(c.httpProfile.RootDomain)
}
if request.GetDomain() == "" {
domain := c.httpProfile.Endpoint
if domain == "" {
domain = request.GetServiceDomain(request.GetService())
}
request.SetDomain(domain)
}
if request.GetHttpMethod() == "" {
request.SetHttpMethod(c.httpProfile.ReqMethod)
}
tchttp.CompleteCommonParams(request, c.GetRegion())
// reflect to inject client if field ClientToken exists and retry feature is enabled
if c.profile.NetworkFailureMaxRetries > 0 || c.profile.RateLimitExceededMaxRetries > 0 {
safeInjectClientToken(request)
}
if c.profile.DisableRegionBreaker == true || c.rb == nil {
return c.sendWithSignature(request, response)
} else {
return c.sendWithRegionBreaker(request, response)
}
}
func (c *Client) sendWithRegionBreaker(request tchttp.Request, response tchttp.Response) (err error) {
defer func() {
e := recover()
if e != nil {
msg := fmt.Sprintf("%s", e)
err = tcerr.NewTencentCloudSDKError("ClientError.CircuitBreakerError", msg, "")
}
}()
ge, err := c.rb.beforeRequest()
if err == errOpenState {
newEndpoint := request.GetService() + "." + c.rb.backupEndpoint
request.SetDomain(newEndpoint)
}
err = c.sendWithSignature(request, response)
isSuccess := false
// Success is considered only when the server returns an effective response (have requestId and the code is not InternalError )
if e, ok := err.(*tcerr.TencentCloudSDKError); ok {
if e.GetRequestId() != "" && e.GetCode() != "InternalError" {
isSuccess = true
}
}
c.rb.afterRequest(ge, isSuccess)
return err
}
func (c *Client) sendWithSignature(request tchttp.Request, response tchttp.Response) (err error) {
if c.signMethod == "HmacSHA1" || c.signMethod == "HmacSHA256" {
return c.sendWithSignatureV1(request, response)
} else {
return c.sendWithSignatureV3(request, response)
}
}
func (c *Client) sendWithSignatureV1(request tchttp.Request, response tchttp.Response) (err error) {
// TODO: not an elegant way, it should be done in common params, but finally it need to refactor
request.GetParams()["Language"] = c.profile.Language
err = tchttp.ConstructParams(request)
if err != nil {
return err
}
err = signRequest(request, c.credential, c.signMethod)
if err != nil {
return err
}
httpRequest, err := http.NewRequestWithContext(request.GetContext(), request.GetHttpMethod(), request.GetUrl(), request.GetBodyReader())
if err != nil {
return err
}
if request.GetHttpMethod() == "POST" {
httpRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
httpResponse, err := c.sendWithRateLimitRetry(httpRequest, isRetryable(request))
if err != nil {
return err
}
err = tchttp.ParseFromHttpResponse(httpResponse, response)
return err
}
func (c *Client) sendWithSignatureV3(request tchttp.Request, response tchttp.Response) (err error) {
headers := map[string]string{
"Host": request.GetDomain(),
"X-TC-Action": request.GetAction(),
"X-TC-Version": request.GetVersion(),
"X-TC-Timestamp": request.GetParams()["Timestamp"],
"X-TC-RequestClient": request.GetParams()["RequestClient"],
"X-TC-Language": c.profile.Language,
}
if c.region != "" {
headers["X-TC-Region"] = c.region
}
if c.credential.GetToken() != "" {
headers["X-TC-Token"] = c.credential.GetToken()
}
if request.GetHttpMethod() == "GET" {
headers["Content-Type"] = "application/x-www-form-urlencoded"
} else {
headers["Content-Type"] = "application/json"
}
isOctetStream := false
cr := &tchttp.CommonRequest{}
ok := false
var octetStreamBody []byte
if cr, ok = request.(*tchttp.CommonRequest); ok {
if cr.IsOctetStream() {
isOctetStream = true
// custom headers must contain Content-Type : application/octet-stream
// todo:the custom header may overwrite headers
for k, v := range cr.GetHeader() {
headers[k] = v
}
octetStreamBody = cr.GetOctetStreamBody()
}
}
if !isOctetStream && request.GetContentType() == octetStream {
isOctetStream = true
b, _ := json.Marshal(request)
var m map[string]string
_ = json.Unmarshal(b, &m)
for k, v := range m {
key := "X-" + strings.ToUpper(request.GetService()) + "-" + k
headers[key] = v
}
headers["Content-Type"] = octetStream
octetStreamBody = request.GetBody()
}
// start signature v3 process
// build canonical request string
httpRequestMethod := request.GetHttpMethod()
canonicalURI := "/"
canonicalQueryString := ""
if httpRequestMethod == "GET" {
err = tchttp.ConstructParams(request)
if err != nil {
return err
}
params := make(map[string]string)
for key, value := range request.GetParams() {
params[key] = value
}
delete(params, "Action")
delete(params, "Version")
delete(params, "Nonce")
delete(params, "Region")
delete(params, "RequestClient")
delete(params, "Timestamp")
canonicalQueryString = tchttp.GetUrlQueriesEncoded(params)
}
canonicalHeaders := fmt.Sprintf("content-type:%s\nhost:%s\n", headers["Content-Type"], headers["Host"])
signedHeaders := "content-type;host"
requestPayload := ""
if httpRequestMethod == "POST" {
if isOctetStream {
// todo Conversion comparison between string and []byte affects performance much
requestPayload = string(octetStreamBody)
} else {
b, err := json.Marshal(request)
if err != nil {
return err
}
requestPayload = string(b)
}
}
hashedRequestPayload := ""
if c.unsignedPayload {
hashedRequestPayload = sha256hex("UNSIGNED-PAYLOAD")
headers["X-TC-Content-SHA256"] = "UNSIGNED-PAYLOAD"
} else {
hashedRequestPayload = sha256hex(requestPayload)
}
canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s",
httpRequestMethod,
canonicalURI,
canonicalQueryString,
canonicalHeaders,
signedHeaders,
hashedRequestPayload)
//log.Println("canonicalRequest:", canonicalRequest)
// build string to sign
algorithm := "TC3-HMAC-SHA256"
requestTimestamp := headers["X-TC-Timestamp"]
timestamp, _ := strconv.ParseInt(requestTimestamp, 10, 64)
t := time.Unix(timestamp, 0).UTC()
// must be the format 2006-01-02, ref to package time for more info
date := t.Format("2006-01-02")
credentialScope := fmt.Sprintf("%s/%s/tc3_request", date, request.GetService())
hashedCanonicalRequest := sha256hex(canonicalRequest)
string2sign := fmt.Sprintf("%s\n%s\n%s\n%s",
algorithm,
requestTimestamp,
credentialScope,
hashedCanonicalRequest)
//log.Println("string2sign", string2sign)
// sign string
secretDate := hmacsha256(date, "TC3"+c.credential.GetSecretKey())
secretService := hmacsha256(request.GetService(), secretDate)
secretKey := hmacsha256("tc3_request", secretService)
signature := hex.EncodeToString([]byte(hmacsha256(string2sign, secretKey)))
//log.Println("signature", signature)
// build authorization
authorization := fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",
algorithm,
c.credential.GetSecretId(),
credentialScope,
signedHeaders,
signature)
//log.Println("authorization", authorization)
headers["Authorization"] = authorization
url := request.GetScheme() + "://" + request.GetDomain() + request.GetPath()
if canonicalQueryString != "" {
url = url + "?" + canonicalQueryString
}
httpRequest, err := http.NewRequestWithContext(request.GetContext(), httpRequestMethod, url, strings.NewReader(requestPayload))
if err != nil {
return err
}
for k, v := range headers {
httpRequest.Header[k] = []string{v}
}
httpResponse, err := c.sendWithRateLimitRetry(httpRequest, isRetryable(request))
if err != nil {
return err
}
err = tchttp.ParseFromHttpResponse(httpResponse, response)
return err
}
// send http request
func (c *Client) sendHttp(request *http.Request) (response *http.Response, err error) {
if c.debug {
outBytes, err := httputil.DumpRequest(request, true)
if err != nil {
log.Printf("[ERROR] dump request failed because %s", err)
return nil, err
}
log.Printf("[DEBUG] http request = %s", outBytes)
}
response, err = c.httpClient.Do(request)
return response, err
}
func (c *Client) GetRegion() string {
return c.region
}
func (c *Client) Init(region string) *Client {
c.httpClient = &http.Client{}
c.region = region
c.signMethod = "TC3-HMAC-SHA256"
c.debug = false
log.SetFlags(log.LstdFlags | log.Lshortfile)
return c
}
func (c *Client) WithSecretId(secretId, secretKey string) *Client {
c.credential = NewCredential(secretId, secretKey)
return c
}
func (c *Client) WithCredential(cred CredentialIface) *Client {
c.credential = cred
return c
}
func (c *Client) WithProfile(clientProfile *profile.ClientProfile) *Client {
c.profile = clientProfile
if c.profile.DisableRegionBreaker == false {
c.withRegionBreaker()
}
c.signMethod = clientProfile.SignMethod
c.unsignedPayload = clientProfile.UnsignedPayload
c.httpProfile = clientProfile.HttpProfile
c.debug = clientProfile.Debug
c.httpClient.Timeout = time.Duration(c.httpProfile.ReqTimeout) * time.Second
return c
}
func (c *Client) WithSignatureMethod(method string) *Client {
c.signMethod = method
return c
}
func (c *Client) WithHttpTransport(transport http.RoundTripper) *Client {
c.httpClient.Transport = transport
return c
}
func (c *Client) WithDebug(flag bool) *Client {
c.debug = flag
return c
}
// WithProvider use specify provider to get a credential and use it to build a client
func (c *Client) WithProvider(provider Provider) (*Client, error) {
cred, err := provider.GetCredential()
if err != nil {
return nil, err
}
return c.WithCredential(cred), nil
}
func (c *Client) withRegionBreaker() *Client {
rb := defaultRegionBreaker()
if c.profile.BackupEndpoint != "" {
rb.backupEndpoint = c.profile.BackupEndpoint
} else if c.profile.BackupEndPoint != "" {
rb.backupEndpoint = c.profile.BackupEndPoint
}
c.rb = rb
return c
}
func NewClientWithSecretId(secretId, secretKey, region string) (client *Client, err error) {
client = &Client{}
client.Init(region).WithSecretId(secretId, secretKey)
return
}
// NewClientWithProviders build client with your custom providers;
// If you don't specify the providers, it will use the DefaultProviderChain to find credential
func NewClientWithProviders(region string, providers ...Provider) (client *Client, err error) {
client = (&Client{}).Init(region)
var pc Provider
if len(providers) == 0 {
pc = DefaultProviderChain()
} else {
pc = NewProviderChain(providers)
}
return client.WithProvider(pc)
}

View File

@ -0,0 +1,62 @@
/*
Copyright 2016 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 common
import (
"crypto/rand"
"fmt"
"reflect"
)
const (
fieldClientToken = "ClientToken"
)
func safeInjectClientToken(obj interface{}) {
// obj Must be struct ptr
getType := reflect.TypeOf(obj)
if getType.Kind() != reflect.Ptr || getType.Elem().Kind() != reflect.Struct {
return
}
// obj Must exist named field
_, ok := getType.Elem().FieldByName(fieldClientToken)
if !ok {
return
}
field := reflect.ValueOf(obj).Elem().FieldByName(fieldClientToken)
// field Must be string ptr
if field.Kind() != reflect.Ptr {
return
}
// Set if ClientToken is nil or empty
if field.IsNil() || (field.Elem().Kind() == reflect.String && field.Elem().Len() == 0) {
uuidVal := randomClientToken()
field.Set(reflect.ValueOf(&uuidVal))
}
}
// randomClientToken generate random string as ClientToken
// ref: https://stackoverflow.com/questions/15130321/is-there-a-method-to-generate-a-uuid-with-go-language
func randomClientToken() string {
b := make([]byte, 16)
_, _ = rand.Read(b)
return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}

View File

@ -0,0 +1,52 @@
/*
Copyright 2016 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 common
import (
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
tchttp "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
)
func NewCommonClient(cred CredentialIface, region string, clientProfile *profile.ClientProfile) (c *Client) {
return new(Client).Init(region).WithCredential(cred).WithProfile(clientProfile)
}
// SendOctetStream Invoke API with application/octet-stream content-type.
//
// Note:
// 1. only specific API can be invoked in such manner.
// 2. only TC3-HMAC-SHA256 signature method can be specified.
// 3. only POST request method can be specified
// 4. the request Must be a CommonRequest and called SetOctetStreamParameters
//
func (c *Client) SendOctetStream(request tchttp.Request, response tchttp.Response) (err error) {
if c.profile.SignMethod != "TC3-HMAC-SHA256" {
return tcerr.NewTencentCloudSDKError("ClientError", "Invalid signature method.", "")
}
if c.profile.HttpProfile.ReqMethod != "POST" {
return tcerr.NewTencentCloudSDKError("ClientError", "Invalid request method.", "")
}
//cr, ok := request.(*tchttp.CommonRequest)
//if !ok {
// return tcerr.NewTencentCloudSDKError("ClientError", "Invalid request, must be *CommonRequest!", "")
//}
//if !cr.IsOctetStream() {
// return tcerr.NewTencentCloudSDKError("ClientError", "Invalid request, does not meet the conditions for sending OctetStream", "")
//}
return c.Send(request, response)
}

View File

@ -0,0 +1,67 @@
/*
Copyright 2016 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 common
var creErr = "ClientError.CredentialError"
type CredentialIface interface {
GetSecretId() string
GetToken() string
GetSecretKey() string
// needRefresh() bool
// refresh()
}
type Credential struct {
SecretId string
SecretKey string
Token string
}
func (c *Credential) needRefresh() bool {
return false
}
func (c *Credential) refresh() {
}
func NewCredential(secretId, secretKey string) *Credential {
return &Credential{
SecretId: secretId,
SecretKey: secretKey,
}
}
func NewTokenCredential(secretId, secretKey, token string) *Credential {
return &Credential{
SecretId: secretId,
SecretKey: secretKey,
Token: token,
}
}
func (c *Credential) GetSecretKey() string {
return c.SecretKey
}
func (c *Credential) GetSecretId() string {
return c.SecretId
}
func (c *Credential) GetToken() string {
return c.Token
}

View File

@ -0,0 +1,70 @@
/*
Copyright 2016 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 common
import (
"log"
"time"
)
const ExpiredTimeout = 300
type CvmRoleCredential struct {
roleName string
expiredTime int64
tmpSecretId string
tmpSecretKey string
token string
source *CvmRoleProvider
}
func (c *CvmRoleCredential) GetSecretId() string {
if c.needRefresh() {
c.refresh()
}
return c.tmpSecretId
}
func (c *CvmRoleCredential) GetToken() string {
if c.needRefresh() {
c.refresh()
}
return c.token
}
func (c *CvmRoleCredential) GetSecretKey() string {
if c.needRefresh() {
c.refresh()
}
return c.tmpSecretKey
}
func (c *CvmRoleCredential) needRefresh() bool {
if c.tmpSecretId == "" || c.tmpSecretKey == "" || c.token == "" || c.expiredTime-ExpiredTimeout <= time.Now().Unix() {
return true
}
return false
}
func (c *CvmRoleCredential) refresh() {
newCre, err := c.source.GetCredential()
if err != nil {
log.Println(err)
return
}
*c = *newCre.(*CvmRoleCredential)
}

View File

@ -0,0 +1,113 @@
/*
Copyright 2016 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 common
import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"time"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
const (
metaUrl = "http://metadata.tencentyun.com/latest/meta-data/"
roleUrl = metaUrl + "cam/security-credentials/"
)
var roleNotBound = errors.New("get cvm role name failed, Please confirm whether the role is bound")
type CvmRoleProvider struct {
roleName string
}
type roleRsp struct {
TmpSecretId string `json:"TmpSecretId"`
TmpSecretKey string `json:"TmpSecretKey"`
ExpiredTime int64 `json:"ExpiredTime"`
Expiration time.Time `json:"Expiration"`
Token string `json:"Token"`
Code string `json:"Code"`
}
// NewCvmRoleProvider need you to specify the roleName of the cvm currently in use
func NewCvmRoleProvider(roleName string) *CvmRoleProvider {
return &CvmRoleProvider{roleName: roleName}
}
// DefaultCvmRoleProvider will auto get the cvm role name by accessing the metadata api
// more info please lookup: https://cloud.tencent.com/document/product/213/4934
func DefaultCvmRoleProvider() *CvmRoleProvider {
return NewCvmRoleProvider("")
}
func get(url string) ([]byte, error) {
rsp, err := http.Get(url)
if err != nil {
return nil, err
}
if rsp.StatusCode == http.StatusNotFound {
return nil, roleNotBound
}
body, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return []byte{}, err
}
return body, nil
}
func (r *CvmRoleProvider) getRoleName() (string, error) {
if r.roleName != "" {
return r.roleName, nil
}
rn, err := get(roleUrl)
return string(rn), err
}
func (r *CvmRoleProvider) GetCredential() (CredentialIface, error) {
roleName, err := r.getRoleName()
if err != nil {
return nil, noCvmRole
}
// get the cvm role name by accessing the metadata api
// https://cloud.tencent.com/document/product/213/4934
body, err := get(roleUrl + roleName)
if err != nil {
return nil, err
}
rspSt := new(roleRsp)
if err = json.Unmarshal(body, rspSt); err != nil {
return nil, tcerr.NewTencentCloudSDKError(creErr, err.Error(), "")
}
if rspSt.Code != "Success" {
return nil, tcerr.NewTencentCloudSDKError(creErr, "Get credential from metadata server by role name "+roleName+" failed, code="+rspSt.Code, "")
}
cre := &CvmRoleCredential{
tmpSecretId: rspSt.TmpSecretId,
tmpSecretKey: rspSt.TmpSecretKey,
token: rspSt.Token,
roleName: roleName,
expiredTime: rspSt.ExpiredTime,
source: r,
}
return cre, nil
}

View File

@ -0,0 +1,57 @@
/*
Copyright 2016 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 common
import (
"os"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
type EnvProvider struct {
secretIdENV string
secretKeyENV string
}
// DefaultEnvProvider return a default provider
// The default environment variable name are TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY
func DefaultEnvProvider() *EnvProvider {
return &EnvProvider{
secretIdENV: "TENCENTCLOUD_SECRET_ID",
secretKeyENV: "TENCENTCLOUD_SECRET_KEY",
}
}
// NewEnvProvider uses the name of the environment variable you specified to get the credentials
func NewEnvProvider(secretIdEnvName, secretKeyEnvName string) *EnvProvider {
return &EnvProvider{
secretIdENV: secretIdEnvName,
secretKeyENV: secretKeyEnvName,
}
}
func (p *EnvProvider) GetCredential() (CredentialIface, error) {
secretId, ok1 := os.LookupEnv(p.secretIdENV)
secretKey, ok2 := os.LookupEnv(p.secretKeyENV)
if !ok1 || !ok2 {
return nil, envNotSet
}
if secretId == "" || secretKey == "" {
return nil, tcerr.NewTencentCloudSDKError(creErr, "Environmental variable ("+p.secretIdENV+" or "+p.secretKeyENV+") is empty", "")
}
return NewCredential(secretId, secretKey), nil
}

View File

@ -0,0 +1,54 @@
/*
Copyright 2016 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"
)
type TencentCloudSDKError struct {
Code string
Message string
RequestId string
}
func (e *TencentCloudSDKError) Error() string {
if e.RequestId == "" {
return fmt.Sprintf("[TencentCloudSDKError] Code=%s, Message=%s", e.Code, e.Message)
}
return fmt.Sprintf("[TencentCloudSDKError] Code=%s, Message=%s, RequestId=%s", e.Code, e.Message, e.RequestId)
}
func NewTencentCloudSDKError(code, message, requestId string) error {
return &TencentCloudSDKError{
Code: code,
Message: message,
RequestId: requestId,
}
}
func (e *TencentCloudSDKError) GetCode() string {
return e.Code
}
func (e *TencentCloudSDKError) GetMessage() string {
return e.Message
}
func (e *TencentCloudSDKError) GetRequestId() string {
return e.RequestId
}

View File

@ -0,0 +1,125 @@
/*
Copyright 2016 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 common
import (
"encoding/json"
"fmt"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
const (
octetStream = "application/octet-stream"
)
type actionParameters map[string]interface{}
type CommonRequest struct {
*BaseRequest
// custom header, may be overwritten
header map[string]string
actionParameters
}
func NewCommonRequest(service, version, action string) (request *CommonRequest) {
request = &CommonRequest{
BaseRequest: &BaseRequest{},
actionParameters: actionParameters{},
}
request.Init().WithApiInfo(service, version, action)
return
}
// SetActionParameters set common request's actionParameters to your data.
// note: your data Must be a json-formatted string or byte array or map[string]interface{}
// note: you could not call SetActionParameters and SetOctetStreamParameters at once
func (cr *CommonRequest) SetActionParameters(data interface{}) error {
if data == nil {
return nil
}
switch data.(type) {
case []byte:
if err := json.Unmarshal(data.([]byte), &cr.actionParameters); err != nil {
msg := fmt.Sprintf("Fail to parse contents %s to json, because: %s", data.([]byte), err)
return tcerr.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
case string:
if err := json.Unmarshal([]byte(data.(string)), &cr.actionParameters); err != nil {
msg := fmt.Sprintf("Fail to parse contents %s to json, because: %s", data.(string), err)
return tcerr.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
case map[string]interface{}:
cr.actionParameters = data.(map[string]interface{})
default:
msg := fmt.Sprintf("Invalid data type:%T, must be one of the following: []byte, string, map[string]interface{}", data)
return tcerr.NewTencentCloudSDKError("ClientError.InvalidParameter", msg, "")
}
return nil
}
func (cr *CommonRequest) IsOctetStream() bool {
v, ok := cr.header["Content-Type"]
if !ok || v != octetStream {
return false
}
value, ok := cr.actionParameters["OctetStreamBody"]
if !ok {
return false
}
_, ok = value.([]byte)
if !ok {
return false
}
return true
}
func (cr *CommonRequest) SetHeader(header map[string]string) {
if header == nil {
return
}
cr.header = header
}
func (cr *CommonRequest) GetHeader() map[string]string {
return cr.header
}
// SetOctetStreamParameters set request body to your data, and set head Content-Type to application/octet-stream
// note: you could not call SetActionParameters and SetOctetStreamParameters on the same request
func (cr *CommonRequest) SetOctetStreamParameters(header map[string]string, body []byte) {
parameter := map[string]interface{}{}
if header == nil {
header = map[string]string{}
}
header["Content-Type"] = octetStream
cr.header = header
parameter["OctetStreamBody"] = body
cr.actionParameters = parameter
}
func (cr *CommonRequest) GetOctetStreamBody() []byte {
if cr.IsOctetStream() {
return cr.actionParameters["OctetStreamBody"].([]byte)
} else {
return nil
}
}
func (cr *CommonRequest) MarshalJSON() ([]byte, error) {
return json.Marshal(cr.actionParameters)
}

View File

@ -0,0 +1,42 @@
/*
Copyright 2016 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 common
import "encoding/json"
type actionResult map[string]interface{}
type CommonResponse struct {
*BaseResponse
*actionResult
}
func NewCommonResponse() (response *CommonResponse) {
response = &CommonResponse{
BaseResponse: &BaseResponse{},
actionResult: &actionResult{},
}
return
}
func (r *CommonResponse) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, r.actionResult)
}
func (r *CommonResponse) GetBody() []byte {
raw, _ := json.Marshal(r.actionResult)
return raw
}

View File

@ -0,0 +1,337 @@
/*
Copyright 2016 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 common
import (
"context"
"io"
//"log"
"math/rand"
"net/url"
"reflect"
"strconv"
"strings"
"time"
)
const (
POST = "POST"
GET = "GET"
HTTP = "http"
HTTPS = "https"
RootDomain = "tencentcloudapi.com"
Path = "/"
)
type Request interface {
GetAction() string
GetBodyReader() io.Reader
GetScheme() string
GetRootDomain() string
GetServiceDomain(string) string
GetDomain() string
GetHttpMethod() string
GetParams() map[string]string
GetBody() []byte
GetPath() string
GetService() string
GetUrl() string
GetVersion() string
GetContentType() string
GetContext() context.Context
SetScheme(string)
SetRootDomain(string)
SetDomain(string)
SetHttpMethod(string)
SetPath(string)
SetContentType(string)
SetBody([]byte)
SetContext(context.Context)
}
type BaseRequest struct {
context context.Context
httpMethod string
scheme string
rootDomain string
domain string
path string
params map[string]string
formParams map[string]string
service string
version string
action string
contentType string
body []byte
}
func (r *BaseRequest) GetAction() string {
return r.action
}
func (r *BaseRequest) GetHttpMethod() string {
return r.httpMethod
}
func (r *BaseRequest) GetParams() map[string]string {
return r.params
}
func (r *BaseRequest) GetPath() string {
return r.path
}
func (r *BaseRequest) GetDomain() string {
return r.domain
}
func (r *BaseRequest) GetScheme() string {
return r.scheme
}
func (r *BaseRequest) GetRootDomain() string {
return r.rootDomain
}
func (r *BaseRequest) GetServiceDomain(service string) (domain string) {
rootDomain := r.rootDomain
if rootDomain == "" {
rootDomain = RootDomain
}
domain = service + "." + rootDomain
return
}
func (r *BaseRequest) GetBody() []byte {
return r.body
}
func (r *BaseRequest) SetBody(body []byte) {
r.body = body
}
func (r *BaseRequest) GetContentType() string {
return r.contentType
}
func (r *BaseRequest) SetContentType(contentType string) {
r.contentType = contentType
}
func (r *BaseRequest) SetDomain(domain string) {
r.domain = domain
}
func (r *BaseRequest) SetScheme(scheme string) {
scheme = strings.ToLower(scheme)
switch scheme {
case HTTP:
r.scheme = HTTP
default:
r.scheme = HTTPS
}
}
func (r *BaseRequest) SetRootDomain(rootDomain string) {
r.rootDomain = rootDomain
}
func (r *BaseRequest) SetHttpMethod(method string) {
switch strings.ToUpper(method) {
case POST:
{
r.httpMethod = POST
}
case GET:
{
r.httpMethod = GET
}
default:
{
r.httpMethod = GET
}
}
}
func (r *BaseRequest) SetPath(path string) {
r.path = path
}
func (r *BaseRequest) GetService() string {
return r.service
}
func (r *BaseRequest) GetUrl() string {
if r.httpMethod == GET {
return r.GetScheme() + "://" + r.domain + r.path + "?" + GetUrlQueriesEncoded(r.params)
} else if r.httpMethod == POST {
return r.GetScheme() + "://" + r.domain + r.path
} else {
return ""
}
}
func (r *BaseRequest) GetVersion() string {
return r.version
}
func (r *BaseRequest) GetContext() context.Context {
if r.context == nil {
return context.Background()
}
return r.context
}
func (r *BaseRequest) SetContext(ctx context.Context) {
r.context = ctx
}
func GetUrlQueriesEncoded(params map[string]string) string {
values := url.Values{}
for key, value := range params {
values.Add(key, value)
}
return values.Encode()
}
func (r *BaseRequest) GetBodyReader() io.Reader {
if r.httpMethod == POST {
s := GetUrlQueriesEncoded(r.params)
return strings.NewReader(s)
} else {
return strings.NewReader("")
}
}
func (r *BaseRequest) Init() *BaseRequest {
r.domain = ""
r.path = Path
r.params = make(map[string]string)
r.formParams = make(map[string]string)
return r
}
func (r *BaseRequest) WithApiInfo(service, version, action string) *BaseRequest {
r.service = service
r.version = version
r.action = action
return r
}
func (r *BaseRequest) WithContentType(contentType string) *BaseRequest {
r.contentType = contentType
return r
}
// Deprecated, use request.GetServiceDomain instead
func GetServiceDomain(service string) (domain string) {
domain = service + "." + RootDomain
return
}
func CompleteCommonParams(request Request, region string) {
params := request.GetParams()
params["Region"] = region
if request.GetVersion() != "" {
params["Version"] = request.GetVersion()
}
params["Action"] = request.GetAction()
params["Timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
params["Nonce"] = strconv.Itoa(rand.Int())
params["RequestClient"] = "SDK_GO_1.0.335"
}
func ConstructParams(req Request) (err error) {
value := reflect.ValueOf(req).Elem()
err = flatStructure(value, req, "")
//log.Printf("[DEBUG] params=%s", req.GetParams())
return
}
func flatStructure(value reflect.Value, request Request, prefix string) (err error) {
//log.Printf("[DEBUG] reflect value: %v", value.Type())
valueType := value.Type()
for i := 0; i < valueType.NumField(); i++ {
tag := valueType.Field(i).Tag
nameTag, hasNameTag := tag.Lookup("name")
if !hasNameTag {
continue
}
field := value.Field(i)
kind := field.Kind()
if kind == reflect.Ptr && field.IsNil() {
continue
}
if kind == reflect.Ptr {
field = field.Elem()
kind = field.Kind()
}
key := prefix + nameTag
if kind == reflect.String {
s := field.String()
if s != "" {
request.GetParams()[key] = s
}
} else if kind == reflect.Bool {
request.GetParams()[key] = strconv.FormatBool(field.Bool())
} else if kind == reflect.Int || kind == reflect.Int64 {
request.GetParams()[key] = strconv.FormatInt(field.Int(), 10)
} else if kind == reflect.Uint || kind == reflect.Uint64 {
request.GetParams()[key] = strconv.FormatUint(field.Uint(), 10)
} else if kind == reflect.Float64 {
request.GetParams()[key] = strconv.FormatFloat(field.Float(), 'f', -1, 64)
} else if kind == reflect.Slice {
list := value.Field(i)
for j := 0; j < list.Len(); j++ {
vj := list.Index(j)
key := prefix + nameTag + "." + strconv.Itoa(j)
kind = vj.Kind()
if kind == reflect.Ptr && vj.IsNil() {
continue
}
if kind == reflect.Ptr {
vj = vj.Elem()
kind = vj.Kind()
}
if kind == reflect.String {
request.GetParams()[key] = vj.String()
} else if kind == reflect.Bool {
request.GetParams()[key] = strconv.FormatBool(vj.Bool())
} else if kind == reflect.Int || kind == reflect.Int64 {
request.GetParams()[key] = strconv.FormatInt(vj.Int(), 10)
} else if kind == reflect.Uint || kind == reflect.Uint64 {
request.GetParams()[key] = strconv.FormatUint(vj.Uint(), 10)
} else if kind == reflect.Float64 {
request.GetParams()[key] = strconv.FormatFloat(vj.Float(), 'f', -1, 64)
} else {
if err = flatStructure(vj, request, key+"."); err != nil {
return
}
}
}
} else {
if err = flatStructure(reflect.ValueOf(field.Interface()), request, prefix+nameTag+"."); err != nil {
return
}
}
}
return
}

View File

@ -0,0 +1,121 @@
/*
Copyright 2016 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 common
import (
"encoding/json"
"fmt"
"io/ioutil"
//"log"
"net/http"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
type Response interface {
ParseErrorFromHTTPResponse(body []byte) error
}
type BaseResponse struct {
}
type ErrorResponse struct {
Response struct {
Error struct {
Code string `json:"Code"`
Message string `json:"Message"`
} `json:"Error,omitempty"`
RequestId string `json:"RequestId"`
} `json:"Response"`
}
type DeprecatedAPIErrorResponse struct {
Code int `json:"code"`
Message string `json:"message"`
CodeDesc string `json:"codeDesc"`
}
func (r *BaseResponse) ParseErrorFromHTTPResponse(body []byte) (err error) {
resp := &ErrorResponse{}
err = json.Unmarshal(body, resp)
if err != nil {
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
if resp.Response.Error.Code != "" {
return errors.NewTencentCloudSDKError(resp.Response.Error.Code, resp.Response.Error.Message, resp.Response.RequestId)
}
deprecated := &DeprecatedAPIErrorResponse{}
err = json.Unmarshal(body, deprecated)
if err != nil {
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
if deprecated.Code != 0 {
return errors.NewTencentCloudSDKError(deprecated.CodeDesc, deprecated.Message, "")
}
return nil
}
func ParseErrorFromHTTPResponse(body []byte) (err error) {
resp := &ErrorResponse{}
err = json.Unmarshal(body, resp)
if err != nil {
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
if resp.Response.Error.Code != "" {
return errors.NewTencentCloudSDKError(resp.Response.Error.Code, resp.Response.Error.Message, resp.Response.RequestId)
}
deprecated := &DeprecatedAPIErrorResponse{}
err = json.Unmarshal(body, deprecated)
if err != nil {
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
if deprecated.Code != 0 {
return errors.NewTencentCloudSDKError(deprecated.CodeDesc, deprecated.Message, "")
}
return nil
}
func ParseFromHttpResponse(hr *http.Response, response Response) (err error) {
defer hr.Body.Close()
body, err := ioutil.ReadAll(hr.Body)
if err != nil {
msg := fmt.Sprintf("Fail to read response body because %s", err)
return errors.NewTencentCloudSDKError("ClientError.IOError", msg, "")
}
if hr.StatusCode != 200 {
msg := fmt.Sprintf("Request fail with http status code: %s, with body: %s", hr.Status, body)
return errors.NewTencentCloudSDKError("ClientError.HttpStatusCodeError", msg, "")
}
//log.Printf("[DEBUG] Response Body=%s", body)
err = response.ParseErrorFromHTTPResponse(body)
if err != nil {
return
}
err = json.Unmarshal(body, &response)
if err != nil {
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
return
}

View File

@ -0,0 +1,100 @@
/*
Copyright 2016 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 common
import (
"fmt"
"io/ioutil"
"strings"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
var (
globalSectionName = "____GLOBAL____"
iniErr = "ClientError.INIError"
)
func openFile(path string) (data []byte, err error) {
data, err = ioutil.ReadFile(path)
if err != nil {
err = tcerr.NewTencentCloudSDKError(iniErr, err.Error(), "")
}
return
}
func parse(path string) (*sections, error) {
result := &sections{map[string]*section{}}
buf, err := openFile(path)
if err != nil {
return &sections{}, err
}
content := string(buf)
lines := strings.Split(content, "\n")
if len(lines) == 0 {
msg := fmt.Sprintf("the result of reading the %s is empty", path)
return &sections{}, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
currentSectionName := globalSectionName
currentSection := &section{make(map[string]*value)}
for i, line := range lines {
line = strings.Replace(line, "\r", "", -1)
line = strings.TrimSpace(line)
if len(line) == 0 {
continue
}
// comments
if strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
// section name
if strings.HasPrefix(line, "[") {
if strings.HasSuffix(line, "]") {
tempSection := line[1 : len(line)-1]
if len(tempSection) == 0 {
msg := fmt.Sprintf("INI file %s lien %d is not valid: wrong section", path, i)
return result, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
// Save the previous section
result.contains[currentSectionName] = currentSection
// new section
currentSectionName = tempSection
currentSection = &section{make(map[string]*value, 0)}
continue
} else {
msg := fmt.Sprintf("INI file %s lien %d is not valid: wrong section", path, i)
return result, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
}
pos := strings.Index(line, "=")
if pos > 0 && pos < len(line)-1 {
key := line[:pos]
val := line[pos+1:]
key = strings.TrimSpace(key)
val = strings.TrimSpace(val)
v := &value{raw: val}
currentSection.content[key] = v
}
}
result.contains[currentSectionName] = currentSection
return result, nil
}

View File

@ -0,0 +1,99 @@
/*
Copyright 2016 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 common
import (
"fmt"
"log"
"net"
"net/http"
"reflect"
"time"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
)
const (
tplNetworkFailureRetry = "[WARN] temporary network failure, retrying (%d/%d) in %f seconds: %s"
)
func (c *Client) sendWithNetworkFailureRetry(req *http.Request, retryable bool) (resp *http.Response, err error) {
// make sure maxRetries is more than or equal 0
var maxRetries int
if retryable {
maxRetries = maxInt(c.profile.NetworkFailureMaxRetries, 0)
}
durationFunc := safeDurationFunc(c.profile.NetworkFailureRetryDuration)
for idx := 0; idx <= maxRetries; idx++ {
resp, err = c.sendHttp(req)
// retry when error occurred and retryable and not the last retry
// should not sleep on last retry even if it's retryable
if err != nil && retryable && idx < maxRetries {
if err, ok := err.(net.Error); ok && (err.Timeout() || err.Temporary()) {
duration := durationFunc(idx)
if c.debug {
log.Printf(tplNetworkFailureRetry, idx, maxRetries, duration.Seconds(), err.Error())
}
time.Sleep(duration)
continue
}
}
if err != nil {
msg := fmt.Sprintf("Fail to get response because %s", err)
err = errors.NewTencentCloudSDKError("ClientError.NetworkError", msg, "")
}
return resp, err
}
return resp, err
}
func maxInt(a, b int) int {
if a > b {
return a
}
return b
}
func safeDurationFunc(durationFunc profile.DurationFunc) profile.DurationFunc {
if durationFunc != nil {
return durationFunc
}
return profile.ExponentialBackoff
}
// isRetryable means if request is retryable or not,
// depends on if request has a `ClientToken` field or not,
// request with `ClientToken` means it's idempotent and retryable,
// unretryable request SHOULDN'T retry for temporary network failure
func isRetryable(obj interface{}) bool {
// obj Must be struct ptr
getType := reflect.TypeOf(obj)
if getType.Kind() != reflect.Ptr || getType.Elem().Kind() != reflect.Struct {
return false
}
// obj Must exist named field
_, ok := getType.Elem().FieldByName(fieldClientToken)
return ok
}

View File

@ -0,0 +1,73 @@
/*
Copyright 2016 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 profile
import (
"math"
"time"
)
type DurationFunc func(index int) time.Duration
func ConstantDurationFunc(duration time.Duration) DurationFunc {
return func(int) time.Duration {
return duration
}
}
func ExponentialBackoff(index int) time.Duration {
seconds := math.Pow(2, float64(index))
return time.Duration(seconds) * time.Second
}
type ClientProfile struct {
HttpProfile *HttpProfile
// Valid choices: HmacSHA1, HmacSHA256, TC3-HMAC-SHA256.
// Default value is TC3-HMAC-SHA256.
SignMethod string
UnsignedPayload bool
// Valid choices: zh-CN, en-US.
// Default value is zh-CN.
Language string
Debug bool
// define Whether to enable Regional auto switch
DisableRegionBreaker bool
// Deprecated. Use BackupEndpoint instead.
BackupEndPoint string
BackupEndpoint string
// define how to retry request
NetworkFailureMaxRetries int
NetworkFailureRetryDuration DurationFunc
RateLimitExceededMaxRetries int
RateLimitExceededRetryDuration DurationFunc
}
func NewClientProfile() *ClientProfile {
return &ClientProfile{
HttpProfile: NewHttpProfile(),
SignMethod: "TC3-HMAC-SHA256",
UnsignedPayload: false,
Language: "zh-CN",
Debug: false,
// now is true, will become to false in future
DisableRegionBreaker: true,
BackupEndPoint: "",
BackupEndpoint: "",
}
}

View File

@ -0,0 +1,37 @@
/*
Copyright 2016 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 profile
type HttpProfile struct {
ReqMethod string
ReqTimeout int
Scheme string
RootDomain string
Endpoint string
// Deprecated, use Scheme instead
Protocol string
}
func NewHttpProfile() *HttpProfile {
return &HttpProfile{
ReqMethod: "POST",
ReqTimeout: 60,
Scheme: "HTTPS",
RootDomain: "",
Endpoint: "",
}
}

View File

@ -0,0 +1,112 @@
/*
Copyright 2016 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 common
import (
"os"
"path/filepath"
"runtime"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
const (
EnvCredentialFile = "TENCENTCLOUD_CREDENTIALS_FILE"
)
type ProfileProvider struct {
}
// DefaultProfileProvider return a default Profile provider
// profile path :
// 1. The value of the environment variable TENCENTCLOUD_CREDENTIALS_FILE
// 2. linux: ~/.tencentcloud/credentials
// windows: \c:\Users\NAME\.tencentcloud\credentials
func DefaultProfileProvider() *ProfileProvider {
return &ProfileProvider{}
}
// getHomePath return home directory according to the system.
// if the environmental variables does not exist, it will return empty string
func getHomePath() string {
// Windows
if runtime.GOOS == "windows" {
return os.Getenv("USERPROFILE")
}
// *nix
return os.Getenv("HOME")
}
func getCredentialsFilePath() string {
homePath := getHomePath()
if homePath == "" {
return homePath
}
return filepath.Join(homePath, ".tencentcloud", "credentials")
}
func checkDefaultFile() (path string, err error) {
path = getCredentialsFilePath()
if path == "" {
return path, nil
}
_, err = os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return "", nil
}
return "", err
}
return path, nil
}
func (p *ProfileProvider) GetCredential() (CredentialIface, error) {
path, ok := os.LookupEnv(EnvCredentialFile)
// if not set custom file path, will use the default path
if !ok {
var err error
path, err = checkDefaultFile()
// only when the file exist but failed read it the err is not nil
if err != nil {
return nil, tcerr.NewTencentCloudSDKError(creErr, "Failed to find profile file,"+err.Error(), "")
}
// when the path is "" means the file dose not exist
if path == "" {
return nil, fileDoseNotExist
}
// if the EnvCredentialFile is set to "", will return an error
} else if path == "" {
return nil, tcerr.NewTencentCloudSDKError(creErr, "Environment variable '"+EnvCredentialFile+"' cannot be empty", "")
}
cfg, err := parse(path)
if err != nil {
return nil, err
}
sId := cfg.section("default").key("secret_id").string()
sKey := cfg.section("default").key("secret_key").string()
// if sId and sKey is "", but the credential file exist, means an error
if sId == "" || sKey == "" {
return nil, tcerr.NewTencentCloudSDKError(creErr, "Failed to parse profile file,please confirm whether it contains \"secret_id\" and \"secret_key\" in section: \"default\" ", "")
}
return &Credential{
SecretId: sId,
SecretKey: sKey,
Token: "",
}, nil
}

View File

@ -0,0 +1,37 @@
/*
Copyright 2016 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 common
import tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
var (
envNotSet = tcerr.NewTencentCloudSDKError(creErr, "could not find environmental variable", "")
fileDoseNotExist = tcerr.NewTencentCloudSDKError(creErr, "could not find config file", "")
noCvmRole = tcerr.NewTencentCloudSDKError(creErr, "get cvm role name failed, Please confirm whether the role is bound", "")
)
// Provider provide credential to build client.
//
// Now there are four kinds provider:
// EnvProvider : get credential from your Variable environment
// ProfileProvider : get credential from your profile
// CvmRoleProvider : get credential from your cvm role
// RoleArnProvider : get credential from your role arn
type Provider interface {
// GetCredential get the credential interface
GetCredential() (CredentialIface, error)
}

View File

@ -0,0 +1,57 @@
/*
Copyright 2016 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 common
import (
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
type ProviderChain struct {
Providers []Provider
}
// NewProviderChain returns a provider chain in your custom order
func NewProviderChain(providers []Provider) Provider {
return &ProviderChain{
Providers: providers,
}
}
// DefaultProviderChain returns a default provider chain and try to get credentials in the following order:
// 1. Environment variable
// 2. Profile
// 3. CvmRole
// If you want to customize the search order, please use the function NewProviderChain
func DefaultProviderChain() Provider {
return NewProviderChain([]Provider{DefaultEnvProvider(), DefaultProfileProvider(), DefaultCvmRoleProvider()})
}
func (c *ProviderChain) GetCredential() (CredentialIface, error) {
for _, provider := range c.Providers {
cred, err := provider.GetCredential()
if err != nil {
if err == envNotSet || err == fileDoseNotExist || err == noCvmRole {
continue
} else {
return nil, err
}
}
return cred, err
}
return nil, tcerr.NewTencentCloudSDKError(creErr, "no credential found in every providers", "")
}

View File

@ -0,0 +1,74 @@
/*
Copyright 2016 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 common
import (
"bytes"
"io"
"io/ioutil"
"log"
"net/http"
"time"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
tchttp "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
)
const (
codeLimitExceeded = "RequestLimitExceeded"
tplRateLimitRetry = "[WARN] rate limit exceeded, retrying (%d/%d) in %f seconds: %s"
)
func (c *Client) sendWithRateLimitRetry(req *http.Request, retryable bool) (resp *http.Response, err error) {
// make sure maxRetries is more than 0
maxRetries := maxInt(c.profile.RateLimitExceededMaxRetries, 0)
durationFunc := safeDurationFunc(c.profile.RateLimitExceededRetryDuration)
var shadow []byte
for idx := 0; idx <= maxRetries; idx++ {
resp, err = c.sendWithNetworkFailureRetry(req, retryable)
if err != nil {
return
}
resp.Body, shadow = shadowRead(resp.Body)
err = tchttp.ParseErrorFromHTTPResponse(shadow)
// should not sleep on last request
if err, ok := err.(*errors.TencentCloudSDKError); ok && err.Code == codeLimitExceeded && idx < maxRetries {
duration := durationFunc(idx)
if c.debug {
log.Printf(tplRateLimitRetry, idx, maxRetries, duration.Seconds(), err.Error())
}
time.Sleep(duration)
continue
}
return resp, err
}
return resp, err
}
func shadowRead(reader io.ReadCloser) (io.ReadCloser, []byte) {
val, err := ioutil.ReadAll(reader)
if err != nil {
return reader, nil
}
return ioutil.NopCloser(bytes.NewBuffer(val)), val
}

View File

@ -0,0 +1,60 @@
/*
Copyright 2016 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 regions
const (
// 曼谷
Bangkok = "ap-bangkok"
// 北京
Beijing = "ap-beijing"
// 成都
Chengdu = "ap-chengdu"
// 重庆
Chongqing = "ap-chongqing"
// 广州
Guangzhou = "ap-guangzhou"
// 广州Open
GuangzhouOpen = "ap-guangzhou-open"
// 中国香港
HongKong = "ap-hongkong"
// 孟买
Mumbai = "ap-mumbai"
// 首尔
Seoul = "ap-seoul"
// 上海
Shanghai = "ap-shanghai"
// 南京
Nanjing = "ap-nanjing"
// 上海金融
ShanghaiFSI = "ap-shanghai-fsi"
// 深圳金融
ShenzhenFSI = "ap-shenzhen-fsi"
// 新加坡
Singapore = "ap-singapore"
// 东京
Tokyo = "ap-tokyo"
// 法兰克福
Frankfurt = "eu-frankfurt"
// 莫斯科
Moscow = "eu-moscow"
// 阿什本
Ashburn = "na-ashburn"
// 硅谷
SiliconValley = "na-siliconvalley"
// 多伦多
Toronto = "na-toronto"
)

View File

@ -0,0 +1,70 @@
/*
Copyright 2016 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 common
import (
"log"
"time"
)
type RoleArnCredential struct {
roleArn string
roleSessionName string
durationSeconds int64
expiredTime int64
token string
tmpSecretId string
tmpSecretKey string
source *RoleArnProvider
}
func (c *RoleArnCredential) GetSecretId() string {
if c.needRefresh() {
c.refresh()
}
return c.tmpSecretId
}
func (c *RoleArnCredential) GetSecretKey() string {
if c.needRefresh() {
c.refresh()
}
return c.tmpSecretKey
}
func (c *RoleArnCredential) GetToken() string {
if c.needRefresh() {
c.refresh()
}
return c.token
}
func (c *RoleArnCredential) needRefresh() bool {
if c.tmpSecretKey == "" || c.tmpSecretId == "" || c.token == "" || c.expiredTime <= time.Now().Unix() {
return true
}
return false
}
func (c *RoleArnCredential) refresh() {
newCre, err := c.source.GetCredential()
if err != nil {
log.Println(err)
}
*c = *newCre.(*RoleArnCredential)
}

View File

@ -0,0 +1,121 @@
/*
Copyright 2016 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 common
import (
"encoding/json"
"strconv"
"time"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
tchttp "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
)
const (
endpoint = "sts.tencentcloudapi.com"
service = "sts"
version = "2018-08-13"
region = regions.Guangzhou
defaultSessionName = "tencentcloud-go-sdk-"
action = "AssumeRole"
defaultDurationSeconds = 7200
)
type RoleArnProvider struct {
longSecretId string
longSecretKey string
roleArn string
roleSessionName string
durationSeconds int64
}
type stsRsp struct {
Response struct {
Credentials struct {
Token string `json:"Token"`
TmpSecretId string `json:"TmpSecretId"`
TmpSecretKey string `json:"TmpSecretKey"`
} `json:"Credentials"`
ExpiredTime int `json:"ExpiredTime"`
Expiration time.Time `json:"Expiration"`
RequestId string `json:"RequestId"`
} `json:"Response"`
}
func NewRoleArnProvider(secretId, secretKey, roleArn, sessionName string, duration int64) *RoleArnProvider {
return &RoleArnProvider{
longSecretId: secretId,
longSecretKey: secretKey,
roleArn: roleArn,
roleSessionName: sessionName,
durationSeconds: duration,
}
}
// DefaultRoleArnProvider returns a RoleArnProvider that use some default options:
// 1. roleSessionName will be "tencentcloud-go-sdk-" + timestamp
// 2. durationSeconds will be 7200s
func DefaultRoleArnProvider(secretId, secretKey, roleArn string) *RoleArnProvider {
return NewRoleArnProvider(secretId, secretKey, roleArn, defaultSessionName+strconv.FormatInt(time.Now().UnixNano()/1000, 10), defaultDurationSeconds)
}
func (r *RoleArnProvider) GetCredential() (CredentialIface, error) {
if r.durationSeconds > 43200 || r.durationSeconds <= 0 {
return nil, tcerr.NewTencentCloudSDKError(creErr, "Assume Role durationSeconds should be in the range of 0~43200s", "")
}
credential := NewCredential(r.longSecretId, r.longSecretKey)
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = endpoint
cpf.HttpProfile.ReqMethod = "POST"
client := NewCommonClient(credential, region, cpf)
request := tchttp.NewCommonRequest(service, version, action)
params := map[string]interface{}{
"RoleArn": r.roleArn,
"RoleSessionName": r.roleSessionName,
"DurationSeconds": r.durationSeconds,
}
err := request.SetActionParameters(params)
if err != nil {
return nil, err
}
response := tchttp.NewCommonResponse()
err = client.Send(request, response)
if err != nil {
return nil, err
}
rspSt := new(stsRsp)
if err = json.Unmarshal(response.GetBody(), rspSt); err != nil {
return nil, tcerr.NewTencentCloudSDKError(creErr, err.Error(), "")
}
return &RoleArnCredential{
roleArn: r.roleArn,
roleSessionName: r.roleSessionName,
durationSeconds: r.durationSeconds,
expiredTime: int64(rspSt.Response.ExpiredTime) - r.durationSeconds/10*9, // credential's actual duration time is 1/10 of the original
token: rspSt.Response.Credentials.Token,
tmpSecretId: rspSt.Response.Credentials.TmpSecretId,
tmpSecretKey: rspSt.Response.Credentials.TmpSecretKey,
source: r,
}, nil
}

View File

@ -0,0 +1,43 @@
/*
Copyright 2016 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 common
type sections struct {
contains map[string]*section
}
func (ss sections) section(name string) *section {
s, ok := ss.contains[name]
if !ok {
s = new(section)
ss.contains[name] = s
}
return s
}
type section struct {
content map[string]*value
}
func (s *section) key(name string) *value {
v, ok := s.content[name]
if !ok {
v = new(value)
s.content[name] = v
}
return v
}

View File

@ -0,0 +1,106 @@
/*
Copyright 2016 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 common
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"sort"
tchttp "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
)
const (
SHA256 = "HmacSHA256"
SHA1 = "HmacSHA1"
)
func Sign(s, secretKey, method string) string {
hashed := hmac.New(sha1.New, []byte(secretKey))
if method == SHA256 {
hashed = hmac.New(sha256.New, []byte(secretKey))
}
hashed.Write([]byte(s))
return base64.StdEncoding.EncodeToString(hashed.Sum(nil))
}
func sha256hex(s string) string {
b := sha256.Sum256([]byte(s))
return hex.EncodeToString(b[:])
}
func hmacsha256(s, key string) string {
hashed := hmac.New(sha256.New, []byte(key))
hashed.Write([]byte(s))
return string(hashed.Sum(nil))
}
func signRequest(request tchttp.Request, credential CredentialIface, method string) (err error) {
if method != SHA256 {
method = SHA1
}
checkAuthParams(request, credential, method)
s := getStringToSign(request)
signature := Sign(s, credential.GetSecretKey(), method)
request.GetParams()["Signature"] = signature
return
}
func checkAuthParams(request tchttp.Request, credential CredentialIface, method string) {
params := request.GetParams()
params["SecretId"] = credential.GetSecretId()
if token := credential.GetToken(); len(token) != 0 {
params["Token"] = token
}
params["SignatureMethod"] = method
delete(params, "Signature")
}
func getStringToSign(request tchttp.Request) string {
method := request.GetHttpMethod()
domain := request.GetDomain()
path := request.GetPath()
var buf bytes.Buffer
buf.WriteString(method)
buf.WriteString(domain)
buf.WriteString(path)
buf.WriteString("?")
params := request.GetParams()
// sort params
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
for i := range keys {
k := keys[i]
buf.WriteString(k)
buf.WriteString("=")
buf.WriteString(params[k])
buf.WriteString("&")
}
buf.Truncate(buf.Len() - 1)
return buf.String()
}

View File

@ -0,0 +1,5 @@
# wrong section name
[]
invalidKey1 =
;wrong section
[default

View File

@ -0,0 +1,11 @@
app=tencentcloud-sdk-go
# default
[default]
key1 = value1
key2 = 2
;section 2
[custom]
customKey1 = 3.1415
customKey2 = true

View File

@ -0,0 +1,111 @@
/*
Copyright 2016 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 common
func IntPtr(v int) *int {
return &v
}
func Int64Ptr(v int64) *int64 {
return &v
}
func UintPtr(v uint) *uint {
return &v
}
func Uint64Ptr(v uint64) *uint64 {
return &v
}
func Float64Ptr(v float64) *float64 {
return &v
}
func BoolPtr(v bool) *bool {
return &v
}
func StringPtr(v string) *string {
return &v
}
func StringValues(ptrs []*string) []string {
values := make([]string, len(ptrs))
for i := 0; i < len(ptrs); i++ {
if ptrs[i] != nil {
values[i] = *ptrs[i]
}
}
return values
}
func IntPtrs(vals []int) []*int {
ptrs := make([]*int, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}
func Int64Ptrs(vals []int64) []*int64 {
ptrs := make([]*int64, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}
func UintPtrs(vals []uint) []*uint {
ptrs := make([]*uint, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}
func Uint64Ptrs(vals []uint64) []*uint64 {
ptrs := make([]*uint64, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}
func Float64Ptrs(vals []float64) []*float64 {
ptrs := make([]*float64, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}
func BoolPtrs(vals []bool) []*bool {
ptrs := make([]*bool, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}
func StringPtrs(vals []string) []*string {
ptrs := make([]*string, len(vals))
for i := 0; i < len(vals); i++ {
ptrs[i] = &vals[i]
}
return ptrs
}

View File

@ -0,0 +1,79 @@
/*
Copyright 2016 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 common
import (
"fmt"
"strconv"
tcerr "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
)
type value struct {
raw string
}
func (v *value) int() (int, error) {
i, e := strconv.Atoi(v.raw)
if e != nil {
msg := fmt.Sprintf("failed to parsing %s to int: %s", v.raw, e.Error())
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
return i, e
}
func (v *value) int64() (int64, error) {
i, e := strconv.ParseInt(v.raw, 10, 64)
if e != nil {
msg := fmt.Sprintf("failed to parsing %s to int64: %s", v.raw, e.Error())
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
return i, e
}
func (v *value) string() string {
return v.raw
}
func (v *value) bool() (bool, error) {
switch v.raw {
case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On":
return true, nil
case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off":
return false, nil
}
errorMsg := fmt.Sprintf("failed to parsing \"%s\" to Bool: invalid syntax", v.raw)
return false, tcerr.NewTencentCloudSDKError(iniErr, errorMsg, "")
}
func (v *value) float32() (float32, error) {
f, e := strconv.ParseFloat(v.raw, 32)
if e != nil {
msg := fmt.Sprintf("failed to parse %s to Float32: %s", v.raw, e.Error())
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
return float32(f), e
}
func (v *value) float64() (float64, error) {
f, e := strconv.ParseFloat(v.raw, 64)
if e != nil {
msg := fmt.Sprintf("failed to parse %s to Float64: %s", v.raw, e.Error())
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
}
return f, e
}

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2017-2018 Tencent Ltd.
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.

View File

@ -0,0 +1,786 @@
/*
Copyright 2016 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 v20170312
const (
// 此产品的特有错误码
// 该请求账户未通过资格审计。
ACCOUNTQUALIFICATIONRESTRICTIONS = "AccountQualificationRestrictions"
// 角色名鉴权失败
AUTHFAILURE_CAMROLENAMEAUTHENTICATEFAILED = "AuthFailure.CamRoleNameAuthenticateFailed"
// 弹性网卡不允许跨子网操作。
ENINOTALLOWEDCHANGESUBNET = "EniNotAllowedChangeSubnet"
// 账号已经存在
FAILEDOPERATION_ACCOUNTALREADYEXISTS = "FailedOperation.AccountAlreadyExists"
// 账号为当前用户
FAILEDOPERATION_ACCOUNTISYOURSELF = "FailedOperation.AccountIsYourSelf"
// 未找到指定的容灾组
FAILEDOPERATION_DISASTERRECOVERGROUPNOTFOUND = "FailedOperation.DisasterRecoverGroupNotFound"
// 标签键存在不合法字符
FAILEDOPERATION_ILLEGALTAGKEY = "FailedOperation.IllegalTagKey"
// 标签值存在不合法字符。
FAILEDOPERATION_ILLEGALTAGVALUE = "FailedOperation.IllegalTagValue"
// 询价失败
FAILEDOPERATION_INQUIRYPRICEFAILED = "FailedOperation.InquiryPriceFailed"
// 查询退换价格失败,找不到付款订单,请检查设备 `ins-xxxxxxx` 是否已过期。
FAILEDOPERATION_INQUIRYREFUNDPRICEFAILED = "FailedOperation.InquiryRefundPriceFailed"
// 请求不支持`EMR`的实例`ins-xxxxxxxx`。
FAILEDOPERATION_INVALIDINSTANCEAPPLICATIONROLEEMR = "FailedOperation.InvalidInstanceApplicationRoleEmr"
// 子网可用IP已耗尽。
FAILEDOPERATION_NOAVAILABLEIPADDRESSCOUNTINSUBNET = "FailedOperation.NoAvailableIpAddressCountInSubnet"
// 当前实例没有弹性IP
FAILEDOPERATION_NOTFOUNDEIP = "FailedOperation.NotFoundEIP"
// 账号为协作者,请填写主账号
FAILEDOPERATION_NOTMASTERACCOUNT = "FailedOperation.NotMasterAccount"
// 指定的置放群组非空。
FAILEDOPERATION_PLACEMENTSETNOTEMPTY = "FailedOperation.PlacementSetNotEmpty"
// 促销期内购买的实例不允许调整配置或计费模式。
FAILEDOPERATION_PROMOTIONALPERIORESTRICTION = "FailedOperation.PromotionalPerioRestriction"
// 镜像共享失败。
FAILEDOPERATION_QIMAGESHAREFAILED = "FailedOperation.QImageShareFailed"
// 镜像共享失败。
FAILEDOPERATION_RIMAGESHAREFAILED = "FailedOperation.RImageShareFailed"
// 安全组操作失败。
FAILEDOPERATION_SECURITYGROUPACTIONFAILED = "FailedOperation.SecurityGroupActionFailed"
// 快照容量大于磁盘大小,请选用更大的磁盘空间。
FAILEDOPERATION_SNAPSHOTSIZELARGERTHANDATASIZE = "FailedOperation.SnapshotSizeLargerThanDataSize"
// 不支持快照size小于云盘size。
FAILEDOPERATION_SNAPSHOTSIZELESSTHANDATASIZE = "FailedOperation.SnapshotSizeLessThanDataSize"
// 请求中指定的标签键为系统预留标签,禁止创建
FAILEDOPERATION_TAGKEYRESERVED = "FailedOperation.TagKeyReserved"
// 镜像是公共镜像并且启用了自动化助手服务,但它不符合 Linux&x86_64。
FAILEDOPERATION_TATAGENTNOTSUPPORT = "FailedOperation.TatAgentNotSupport"
// 实例无法退还。
FAILEDOPERATION_UNRETURNABLE = "FailedOperation.Unreturnable"
// 镜像配额超过了限制。
IMAGEQUOTALIMITEXCEEDED = "ImageQuotaLimitExceeded"
// 表示当前创建的实例个数超过了该账户允许购买的剩余配额数。
INSTANCESQUOTALIMITEXCEEDED = "InstancesQuotaLimitExceeded"
// 内部错误。
INTERNALERROR = "InternalError"
// 内部错误
INTERNALERROR_TRADEUNKNOWNERROR = "InternalError.TradeUnknownError"
// 操作内部错误。
INTERNALSERVERERROR = "InternalServerError"
// 账户余额不足。
INVALIDACCOUNT_INSUFFICIENTBALANCE = "InvalidAccount.InsufficientBalance"
// 账户有未支付订单。
INVALIDACCOUNT_UNPAIDORDER = "InvalidAccount.UnpaidOrder"
// 无效的账户Id。
INVALIDACCOUNTID_NOTFOUND = "InvalidAccountId.NotFound"
// 您无法共享镜像给自己。
INVALIDACCOUNTIS_YOURSELF = "InvalidAccountIs.YourSelf"
// 指定的ClientToken字符串长度超出限制必须小于等于64字节。
INVALIDCLIENTTOKEN_TOOLONG = "InvalidClientToken.TooLong"
// 无效的过滤器。
INVALIDFILTER = "InvalidFilter"
// [`Filter`](/document/api/213/15753#Filter)。
INVALIDFILTERVALUE_LIMITEXCEEDED = "InvalidFilterValue.LimitExceeded"
// 不支持该宿主机实例执行指定的操作。
INVALIDHOST_NOTSUPPORTED = "InvalidHost.NotSupported"
// 无效[CDH](https://cloud.tencent.com/document/product/416) `ID`。指定的[CDH](https://cloud.tencent.com/document/product/416) `ID`格式错误。例如`ID`长度错误`host-1122`。
INVALIDHOSTID_MALFORMED = "InvalidHostId.Malformed"
// 指定的HostId不存在或不属于该请求账号所有。
INVALIDHOSTID_NOTFOUND = "InvalidHostId.NotFound"
// 镜像处于共享中。
INVALIDIMAGEID_INSHARED = "InvalidImageId.InShared"
// 镜像状态不合法。
INVALIDIMAGEID_INCORRECTSTATE = "InvalidImageId.IncorrectState"
// 错误的镜像Id格式。
INVALIDIMAGEID_MALFORMED = "InvalidImageId.Malformed"
// 未找到该镜像。
INVALIDIMAGEID_NOTFOUND = "InvalidImageId.NotFound"
// 镜像大小超过限制。
INVALIDIMAGEID_TOOLARGE = "InvalidImageId.TooLarge"
// 镜像名称与原有镜像重复。
INVALIDIMAGENAME_DUPLICATE = "InvalidImageName.Duplicate"
// 不支持的操作系统类型。
INVALIDIMAGEOSTYPE_UNSUPPORTED = "InvalidImageOsType.Unsupported"
// 不支持的操作系统版本。
INVALIDIMAGEOSVERSION_UNSUPPORTED = "InvalidImageOsVersion.Unsupported"
// 不被支持的实例。
INVALIDINSTANCE_NOTSUPPORTED = "InvalidInstance.NotSupported"
// 无效实例`ID`。指定的实例`ID`格式错误。例如实例`ID`长度错误`ins-1122`。
INVALIDINSTANCEID_MALFORMED = "InvalidInstanceId.Malformed"
// 没有找到相应实例。
INVALIDINSTANCEID_NOTFOUND = "InvalidInstanceId.NotFound"
// 指定的InstanceName字符串长度超出限制必须小于等于60字节。
INVALIDINSTANCENAME_TOOLONG = "InvalidInstanceName.TooLong"
// 该实例不满足包月[退还规则](https://cloud.tencent.com/document/product/213/9711)。
INVALIDINSTANCENOTSUPPORTEDPREPAIDINSTANCE = "InvalidInstanceNotSupportedPrepaidInstance"
// 指定实例的当前状态不能进行该操作。
INVALIDINSTANCESTATE = "InvalidInstanceState"
// 指定InstanceType参数格式不合法。
INVALIDINSTANCETYPE_MALFORMED = "InvalidInstanceType.Malformed"
// 密钥对数量超过限制。
INVALIDKEYPAIR_LIMITEXCEEDED = "InvalidKeyPair.LimitExceeded"
// 无效密钥对ID。指定的密钥对ID格式错误例如 `ID` 长度错误`skey-1122`。
INVALIDKEYPAIRID_MALFORMED = "InvalidKeyPairId.Malformed"
// 无效密钥对ID。指定的密钥对ID不存在。
INVALIDKEYPAIRID_NOTFOUND = "InvalidKeyPairId.NotFound"
// 密钥对名称重复。
INVALIDKEYPAIRNAME_DUPLICATE = "InvalidKeyPairName.Duplicate"
// 密钥名称为空。
INVALIDKEYPAIRNAMEEMPTY = "InvalidKeyPairNameEmpty"
// 密钥名称包含非法字符。密钥名称只支持英文、数字和下划线。
INVALIDKEYPAIRNAMEINCLUDEILLEGALCHAR = "InvalidKeyPairNameIncludeIllegalChar"
// 密钥名称超过25个字符。
INVALIDKEYPAIRNAMETOOLONG = "InvalidKeyPairNameTooLong"
// 参数错误。
INVALIDPARAMETER = "InvalidParameter"
// DataDiskIds不应该传入RootDisk的Id。
INVALIDPARAMETER_DATADISKIDCONTAINSROOTDISK = "InvalidParameter.DataDiskIdContainsRootDisk"
// 指定的数据盘不属于指定的实例。
INVALIDPARAMETER_DATADISKNOTBELONGSPECIFIEDINSTANCE = "InvalidParameter.DataDiskNotBelongSpecifiedInstance"
// 只能包含一个系统盘快照。
INVALIDPARAMETER_DUPLICATESYSTEMSNAPSHOTS = "InvalidParameter.DuplicateSystemSnapshots"
// 该主机当前状态不支持该操作。
INVALIDPARAMETER_HOSTIDSTATUSNOTSUPPORT = "InvalidParameter.HostIdStatusNotSupport"
// 指定的hostName不符合规范。
INVALIDPARAMETER_HOSTNAMEILLEGAL = "InvalidParameter.HostNameIllegal"
// 当前接口不支持实例镜像。
INVALIDPARAMETER_INSTANCEIMAGENOTSUPPORT = "InvalidParameter.InstanceImageNotSupport"
// 云盘资源售罄。
INVALIDPARAMETER_INVALIDCLOUDDISKSOLDOUT = "InvalidParameter.InvalidCloudDiskSoldOut"
// 参数依赖不正确。
INVALIDPARAMETER_INVALIDDEPENDENCE = "InvalidParameter.InvalidDependence"
// 当前操作不支持该类型实例。
INVALIDPARAMETER_INVALIDINSTANCENOTSUPPORTED = "InvalidParameter.InvalidInstanceNotSupported"
// 指定的私有网络ip格式不正确。
INVALIDPARAMETER_INVALIDIPFORMAT = "InvalidParameter.InvalidIpFormat"
// 不能同时指定ImageIds和Filters。
INVALIDPARAMETER_INVALIDPARAMETERCOEXISTIMAGEIDSFILTERS = "InvalidParameter.InvalidParameterCoexistImageIdsFilters"
// 错误的url地址。
INVALIDPARAMETER_INVALIDPARAMETERURLERROR = "InvalidParameter.InvalidParameterUrlError"
// CoreCount和ThreadPerCore必须同时提供。
INVALIDPARAMETER_LACKCORECOUNTORTHREADPERCORE = "InvalidParameter.LackCoreCountOrThreadPerCore"
// 本地数据盘不支持创建实例镜像。
INVALIDPARAMETER_LOCALDATADISKNOTSUPPORT = "InvalidParameter.LocalDataDiskNotSupport"
// 不支持同时指定密钥登陆和保持镜像登陆方式。
INVALIDPARAMETER_PARAMETERCONFLICT = "InvalidParameter.ParameterConflict"
// 不支持设置登陆密码。
INVALIDPARAMETER_PASSWORDNOTSUPPORTED = "InvalidParameter.PasswordNotSupported"
// 指定的快照不存在。
INVALIDPARAMETER_SNAPSHOTNOTFOUND = "InvalidParameter.SnapshotNotFound"
// 多选一必选参数缺失。
INVALIDPARAMETER_SPECIFYONEPARAMETER = "InvalidParameter.SpecifyOneParameter"
// 不支持Swap盘。
INVALIDPARAMETER_SWAPDISKNOTSUPPORT = "InvalidParameter.SwapDiskNotSupport"
// 参数不包含系统盘快照。
INVALIDPARAMETER_SYSTEMSNAPSHOTNOTFOUND = "InvalidParameter.SystemSnapshotNotFound"
// 参数长度超过限制。
INVALIDPARAMETER_VALUETOOLARGE = "InvalidParameter.ValueTooLarge"
// 表示参数组合不正确。
INVALIDPARAMETERCOMBINATION = "InvalidParameterCombination"
// 指定的两个参数冲突,不能同时存在。 EIP只能绑定在实例上或指定网卡的指定内网 IP 上。
INVALIDPARAMETERCONFLICT = "InvalidParameterConflict"
// 参数取值错误。
INVALIDPARAMETERVALUE = "InvalidParameterValue"
// 共享带宽包ID不合要求请提供规范的共享带宽包ID类似bwp-xxxxxxxx字母x代表小写字符或者数字。
INVALIDPARAMETERVALUE_BANDWIDTHPACKAGEIDMALFORMED = "InvalidParameterValue.BandwidthPackageIdMalformed"
// 请确认指定的带宽包是否存在。
INVALIDPARAMETERVALUE_BANDWIDTHPACKAGEIDNOTFOUND = "InvalidParameterValue.BandwidthPackageIdNotFound"
// 找不到对应的CHC物理服务器。
INVALIDPARAMETERVALUE_CHCHOSTSNOTFOUND = "InvalidParameterValue.ChcHostsNotFound"
// SSD云硬盘为数据盘时购买大小不得小于100GB
INVALIDPARAMETERVALUE_CLOUDSSDDATADISKSIZETOOSMALL = "InvalidParameterValue.CloudSsdDataDiskSizeTooSmall"
// 核心计数不合法。
INVALIDPARAMETERVALUE_CORECOUNTVALUE = "InvalidParameterValue.CoreCountValue"
// 参数值重复。
INVALIDPARAMETERVALUE_DUPLICATE = "InvalidParameterValue.Duplicate"
// 非GPU实例不允许转为GPU实例。
INVALIDPARAMETERVALUE_GPUINSTANCEFAMILY = "InvalidParameterValue.GPUInstanceFamily"
// IP格式非法。
INVALIDPARAMETERVALUE_IPADDRESSMALFORMED = "InvalidParameterValue.IPAddressMalformed"
// ipv6地址无效
INVALIDPARAMETERVALUE_IPV6ADDRESSMALFORMED = "InvalidParameterValue.IPv6AddressMalformed"
// HostName参数值不合法
INVALIDPARAMETERVALUE_ILLEGALHOSTNAME = "InvalidParameterValue.IllegalHostName"
// 传参格式不对。
INVALIDPARAMETERVALUE_INCORRECTFORMAT = "InvalidParameterValue.IncorrectFormat"
// 不支持操作不同计费方式的实例。
INVALIDPARAMETERVALUE_INSTANCENOTSUPPORTEDMIXPRICINGMODEL = "InvalidParameterValue.InstanceNotSupportedMixPricingModel"
// 指定机型不存在
INVALIDPARAMETERVALUE_INSTANCETYPENOTFOUND = "InvalidParameterValue.InstanceTypeNotFound"
// 实例类型不可加入高性能计算集群。
INVALIDPARAMETERVALUE_INSTANCETYPENOTSUPPORTHPCCLUSTER = "InvalidParameterValue.InstanceTypeNotSupportHpcCluster"
// 高性能计算实例需指定对应的高性能计算集群。
INVALIDPARAMETERVALUE_INSTANCETYPEREQUIREDHPCCLUSTER = "InvalidParameterValue.InstanceTypeRequiredHpcCluster"
// 竞价数量不足。
INVALIDPARAMETERVALUE_INSUFFICIENTOFFERING = "InvalidParameterValue.InsufficientOffering"
// 竞价失败。
INVALIDPARAMETERVALUE_INSUFFICIENTPRICE = "InvalidParameterValue.InsufficientPrice"
// 无效的appid。
INVALIDPARAMETERVALUE_INVALIDAPPIDFORMAT = "InvalidParameterValue.InvalidAppIdFormat"
// 镜像ID不支持指定的实例机型。
INVALIDPARAMETERVALUE_INVALIDIMAGEFORGIVENINSTANCETYPE = "InvalidParameterValue.InvalidImageForGivenInstanceType"
// 当前镜像为RAW格式无法创建CVM建议您选择其他镜像。
INVALIDPARAMETERVALUE_INVALIDIMAGEFORMAT = "InvalidParameterValue.InvalidImageFormat"
// 镜像不允许执行该操作
INVALIDPARAMETERVALUE_INVALIDIMAGEID = "InvalidParameterValue.InvalidImageId"
// 当前地域不支持指定镜像所包含的操作系统。
INVALIDPARAMETERVALUE_INVALIDIMAGEOSNAME = "InvalidParameterValue.InvalidImageOsName"
// 镜像被其他操作占用,请检查,并稍后重试。
INVALIDPARAMETERVALUE_INVALIDIMAGESTATE = "InvalidParameterValue.InvalidImageState"
// IP地址不符合规范
INVALIDPARAMETERVALUE_INVALIDIPFORMAT = "InvalidParameterValue.InvalidIpFormat"
// 实例启动模板描述格式错误。
INVALIDPARAMETERVALUE_INVALIDLAUNCHTEMPLATEDESCRIPTION = "InvalidParameterValue.InvalidLaunchTemplateDescription"
// 实例启动模板名称格式错误。
INVALIDPARAMETERVALUE_INVALIDLAUNCHTEMPLATENAME = "InvalidParameterValue.InvalidLaunchTemplateName"
// 实例启动模板描述格式错误。
INVALIDPARAMETERVALUE_INVALIDLAUNCHTEMPLATEVERSIONDESCRIPTION = "InvalidParameterValue.InvalidLaunchTemplateVersionDescription"
// 参数值错误。
INVALIDPARAMETERVALUE_INVALIDPARAMETERVALUELIMIT = "InvalidParameterValue.InvalidParameterValueLimit"
// 无效密码。指定的密码不符合密码复杂度限制。例如密码长度不符合限制等。
INVALIDPARAMETERVALUE_INVALIDPASSWORD = "InvalidParameterValue.InvalidPassword"
// 时间格式不合法。
INVALIDPARAMETERVALUE_INVALIDTIMEFORMAT = "InvalidParameterValue.InvalidTimeFormat"
// UserData格式错误, 需要base64编码格式
INVALIDPARAMETERVALUE_INVALIDUSERDATAFORMAT = "InvalidParameterValue.InvalidUserDataFormat"
// 无效的模糊查询字符串。
INVALIDPARAMETERVALUE_INVALIDVAGUENAME = "InvalidParameterValue.InvalidVagueName"
// 请确认密钥是否存在。
INVALIDPARAMETERVALUE_KEYPAIRNOTFOUND = "InvalidParameterValue.KeyPairNotFound"
// 指定的密钥不支持当前操作。
INVALIDPARAMETERVALUE_KEYPAIRNOTSUPPORTED = "InvalidParameterValue.KeyPairNotSupported"
// 不支持删除默认启动模板版本。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATEDEFAULTVERSION = "InvalidParameterValue.LaunchTemplateDefaultVersion"
// 实例启动模板ID格式错误。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATEIDMALFORMED = "InvalidParameterValue.LaunchTemplateIdMalformed"
// 实例启动模板ID不存在。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATEIDNOTEXISTED = "InvalidParameterValue.LaunchTemplateIdNotExisted"
// 实例启动模板和版本ID组合不存在。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATEIDVERNOTEXISTED = "InvalidParameterValue.LaunchTemplateIdVerNotExisted"
// 指定的实例启动模板id不存在。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATEIDVERSETALREADY = "InvalidParameterValue.LaunchTemplateIdVerSetAlready"
// 实例启动模板未找到。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATENOTFOUND = "InvalidParameterValue.LaunchTemplateNotFound"
// 无效的实例启动模板版本号。
INVALIDPARAMETERVALUE_LAUNCHTEMPLATEVERSION = "InvalidParameterValue.LaunchTemplateVersion"
// 参数值数量超过限制。
INVALIDPARAMETERVALUE_LIMITEXCEEDED = "InvalidParameterValue.LimitExceeded"
// 本地盘的限制范围。
INVALIDPARAMETERVALUE_LOCALDISKSIZERANGE = "InvalidParameterValue.LocalDiskSizeRange"
// 参数值必须为开启DHCP的VPC
INVALIDPARAMETERVALUE_MUSTDHCPENABLEDVPC = "InvalidParameterValue.MustDhcpEnabledVpc"
// 不支持的操作。
INVALIDPARAMETERVALUE_NOTSUPPORTED = "InvalidParameterValue.NotSupported"
// 无效参数值。参数值取值范围不合法。
INVALIDPARAMETERVALUE_RANGE = "InvalidParameterValue.Range"
// 快照ID不合要求请提供规范的快照ID类似snap-xxxxxxxx字母x代表小写字符或者数字
INVALIDPARAMETERVALUE_SNAPSHOTIDMALFORMED = "InvalidParameterValue.SnapshotIdMalformed"
// 子网ID不合要求请提供规范的子网ID类似subnet-xxxxxxxx字母x代表小写字符或者数字
INVALIDPARAMETERVALUE_SUBNETIDMALFORMED = "InvalidParameterValue.SubnetIdMalformed"
// 创建失败,您指定的子网不存在,请您重新指定
INVALIDPARAMETERVALUE_SUBNETNOTEXIST = "InvalidParameterValue.SubnetNotExist"
// 指定的标签不存在。
INVALIDPARAMETERVALUE_TAGKEYNOTFOUND = "InvalidParameterValue.TagKeyNotFound"
// 每核心线程数不合法。
INVALIDPARAMETERVALUE_THREADPERCOREVALUE = "InvalidParameterValue.ThreadPerCoreValue"
// 参数值超过最大限制。
INVALIDPARAMETERVALUE_TOOLARGE = "InvalidParameterValue.TooLarge"
// 无效参数值。参数值太长。
INVALIDPARAMETERVALUE_TOOLONG = "InvalidParameterValue.TooLong"
// VPC ID`xxx`不合要求请提供规范的Vpc ID 类似vpc-xxxxxxxx字母x代表小写字符或者数字。
INVALIDPARAMETERVALUE_VPCIDMALFORMED = "InvalidParameterValue.VpcIdMalformed"
// 指定的VpcId不存在。
INVALIDPARAMETERVALUE_VPCIDNOTEXIST = "InvalidParameterValue.VpcIdNotExist"
// VPC网络与实例不在同一可用区
INVALIDPARAMETERVALUE_VPCIDZONEIDNOTMATCH = "InvalidParameterValue.VpcIdZoneIdNotMatch"
// 请求不支持该可用区
INVALIDPARAMETERVALUE_ZONENOTSUPPORTED = "InvalidParameterValue.ZoneNotSupported"
// 参数值数量超过限制。
INVALIDPARAMETERVALUELIMIT = "InvalidParameterValueLimit"
// 无效参数值。指定的 `Offset` 无效。
INVALIDPARAMETERVALUEOFFSET = "InvalidParameterValueOffset"
// 无效密码。指定的密码不符合密码复杂度限制。例如密码长度不符合限制等。
INVALIDPASSWORD = "InvalidPassword"
// 无效时长。目前只支持时长:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 24, 36],单位:月。
INVALIDPERIOD = "InvalidPeriod"
// 账户不支持该操作。
INVALIDPERMISSION = "InvalidPermission"
// 无效的项目ID指定的项目ID不存在。
INVALIDPROJECTID_NOTFOUND = "InvalidProjectId.NotFound"
// 无效密钥公钥。指定公钥已经存在。
INVALIDPUBLICKEY_DUPLICATE = "InvalidPublicKey.Duplicate"
// 无效密钥公钥。指定公钥格式错误,不符合`OpenSSH RSA`格式要求。
INVALIDPUBLICKEY_MALFORMED = "InvalidPublicKey.Malformed"
// 未找到该区域。
INVALIDREGION_NOTFOUND = "InvalidRegion.NotFound"
// 该区域目前不支持同步镜像。
INVALIDREGION_UNAVAILABLE = "InvalidRegion.Unavailable"
// 指定的`安全组ID`不存在。
INVALIDSECURITYGROUPID_NOTFOUND = "InvalidSecurityGroupId.NotFound"
// 指定的`安全组ID`格式错误,例如`实例ID`长度错误`sg-ide32`。
INVALIDSGID_MALFORMED = "InvalidSgId.Malformed"
// 指定的`zone`不存在。
INVALIDZONE_MISMATCHREGION = "InvalidZone.MismatchRegion"
// 一个实例绑定安全组数量不能超过5个
LIMITEXCEEDED_ASSOCIATEUSGLIMITEXCEEDED = "LimitExceeded.AssociateUSGLimitExceeded"
// 安全组关联云主机弹性网卡配额超限。
LIMITEXCEEDED_CVMSVIFSPERSECGROUPLIMITEXCEEDED = "LimitExceeded.CvmsVifsPerSecGroupLimitExceeded"
// 指定置放群组配额不足。
LIMITEXCEEDED_DISASTERRECOVERGROUP = "LimitExceeded.DisasterRecoverGroup"
// 特定实例当前ENI数量已超过目标实例类型的ENI允许的最大值需删除部分ENI后重试。
LIMITEXCEEDED_ENINUMLIMIT = "LimitExceeded.EniNumLimit"
// IP数量超过网卡上限。
LIMITEXCEEDED_IPV6ADDRESSNUM = "LimitExceeded.IPv6AddressNum"
// 当前配额不足够生产指定数量的实例
LIMITEXCEEDED_INSTANCEQUOTA = "LimitExceeded.InstanceQuota"
// 目标实例规格不支持当前规格的外网带宽上限,不支持调整。具体可参考[公网网络带宽上限](https://cloud.tencent.com/document/product/213/12523)。
LIMITEXCEEDED_INSTANCETYPEBANDWIDTH = "LimitExceeded.InstanceTypeBandwidth"
// 实例启动模板数量超限。
LIMITEXCEEDED_LAUNCHTEMPLATEQUOTA = "LimitExceeded.LaunchTemplateQuota"
// 实例启动模板版本数量超限。
LIMITEXCEEDED_LAUNCHTEMPLATEVERSIONQUOTA = "LimitExceeded.LaunchTemplateVersionQuota"
// 预付费实例已购买数量已达到最大配额,请提升配额后重试。
LIMITEXCEEDED_PREPAYQUOTA = "LimitExceeded.PrepayQuota"
// 安全组限额不足
LIMITEXCEEDED_SINGLEUSGQUOTA = "LimitExceeded.SingleUSGQuota"
// 竞价实例类型配额不足
LIMITEXCEEDED_SPOTQUOTA = "LimitExceeded.SpotQuota"
// 退还失败,退还配额已达上限。
LIMITEXCEEDED_USERRETURNQUOTA = "LimitExceeded.UserReturnQuota"
// 竞价实例配额不足
LIMITEXCEEDED_USERSPOTQUOTA = "LimitExceeded.UserSpotQuota"
// 子网IP不足
LIMITEXCEEDED_VPCSUBNETNUM = "LimitExceeded.VpcSubnetNum"
// 缺少参数错误。
MISSINGPARAMETER = "MissingParameter"
// 缺少必要参数,请至少提供一个参数。
MISSINGPARAMETER_ATLEASTONE = "MissingParameter.AtLeastOne"
// DPDK实例机型要求VPC网络
MISSINGPARAMETER_DPDKINSTANCETYPEREQUIREDVPC = "MissingParameter.DPDKInstanceTypeRequiredVPC"
// 该实例类型必须开启云监控服务
MISSINGPARAMETER_MONITORSERVICE = "MissingParameter.MonitorService"
// 同样的任务正在运行。
MUTEXOPERATION_TASKRUNNING = "MutexOperation.TaskRunning"
// 不允许未配置部署网络的CHC安装云上镜像。
OPERATIONDENIED_CHCINSTALLCLOUDIMAGEWITHOUTDEPLOYNETWORK = "OperationDenied.ChcInstallCloudImageWithoutDeployNetwork"
// 实例正在执行其他操作,请稍后再试。
OPERATIONDENIED_INSTANCEOPERATIONINPROGRESS = "OperationDenied.InstanceOperationInProgress"
// 镜像共享超过配额。
OVERQUOTA = "OverQuota"
// 该地域不支持导入镜像。
REGIONABILITYLIMIT_UNSUPPORTEDTOIMPORTIMAGE = "RegionAbilityLimit.UnsupportedToImportImage"
// 资源被占用。
RESOURCEINUSE = "ResourceInUse"
// 该可用区已售罄
RESOURCEINSUFFICIENT_AVAILABILITYZONESOLDOUT = "ResourceInsufficient.AvailabilityZoneSoldOut"
// 指定的云盘规格已售罄
RESOURCEINSUFFICIENT_CLOUDDISKSOLDOUT = "ResourceInsufficient.CloudDiskSoldOut"
// 云盘参数不符合规范
RESOURCEINSUFFICIENT_CLOUDDISKUNAVAILABLE = "ResourceInsufficient.CloudDiskUnavailable"
// 实例个数超过容灾组的配额
RESOURCEINSUFFICIENT_DISASTERRECOVERGROUPCVMQUOTA = "ResourceInsufficient.DisasterRecoverGroupCvmQuota"
// 指定的实例类型库存不足。
RESOURCEINSUFFICIENT_SPECIFIEDINSTANCETYPE = "ResourceInsufficient.SpecifiedInstanceType"
// 指定的实例类型在选择的可用区已售罄。
RESOURCEINSUFFICIENT_ZONESOLDOUTFORSPECIFIEDINSTANCE = "ResourceInsufficient.ZoneSoldOutForSpecifiedInstance"
// 高性能计算集群不存在。
RESOURCENOTFOUND_HPCCLUSTER = "ResourceNotFound.HpcCluster"
// 指定的置放群组不存在。
RESOURCENOTFOUND_INVALIDPLACEMENTSET = "ResourceNotFound.InvalidPlacementSet"
// 无可用的缺省类型的CBS资源。
RESOURCENOTFOUND_NODEFAULTCBS = "ResourceNotFound.NoDefaultCbs"
// 无可用的缺省类型的CBS资源。
RESOURCENOTFOUND_NODEFAULTCBSWITHREASON = "ResourceNotFound.NoDefaultCbsWithReason"
// 该可用区不售卖此机型
RESOURCEUNAVAILABLE_INSTANCETYPE = "ResourceUnavailable.InstanceType"
// 快照正在创建过程中。
RESOURCEUNAVAILABLE_SNAPSHOTCREATING = "ResourceUnavailable.SnapshotCreating"
// 该可用区已售罄
RESOURCESSOLDOUT_AVAILABLEZONE = "ResourcesSoldOut.AvailableZone"
// 公网IP已售罄。
RESOURCESSOLDOUT_EIPINSUFFICIENT = "ResourcesSoldOut.EipInsufficient"
// 指定的实例类型已售罄。
RESOURCESSOLDOUT_SPECIFIEDINSTANCETYPE = "ResourcesSoldOut.SpecifiedInstanceType"
// 安全组服务接口调用通用错误。
SECGROUPACTIONFAILURE = "SecGroupActionFailure"
// 未授权操作。
UNAUTHORIZEDOPERATION = "UnauthorizedOperation"
// 指定的镜像不属于用户。
UNAUTHORIZEDOPERATION_IMAGENOTBELONGTOACCOUNT = "UnauthorizedOperation.ImageNotBelongToAccount"
// 请确认Token是否有效。
UNAUTHORIZEDOPERATION_INVALIDTOKEN = "UnauthorizedOperation.InvalidToken"
// 您无法进行当前操作请确认多因子认证MFA是否失效。
UNAUTHORIZEDOPERATION_MFAEXPIRED = "UnauthorizedOperation.MFAExpired"
// 没有权限进行此操作请确认是否存在多因子认证MFA
UNAUTHORIZEDOPERATION_MFANOTFOUND = "UnauthorizedOperation.MFANotFound"
// 无权操作指定的资源请正确配置CAM策略。
UNAUTHORIZEDOPERATION_PERMISSIONDENIED = "UnauthorizedOperation.PermissionDenied"
// 未知参数错误。
UNKNOWNPARAMETER = "UnknownParameter"
// 操作不支持。
UNSUPPORTEDOPERATION = "UnsupportedOperation"
// 指定的实例付费模式或者网络付费模式不支持共享带宽包
UNSUPPORTEDOPERATION_BANDWIDTHPACKAGEIDNOTSUPPORTED = "UnsupportedOperation.BandwidthPackageIdNotSupported"
// IPv6实例不支持VPC迁移
UNSUPPORTEDOPERATION_IPV6NOTSUPPORTVPCMIGRATE = "UnsupportedOperation.IPv6NotSupportVpcMigrate"
// 请求不支持该实例计费模式
UNSUPPORTEDOPERATION_INSTANCECHARGETYPE = "UnsupportedOperation.InstanceChargeType"
// 不支持混合付费模式。
UNSUPPORTEDOPERATION_INSTANCEMIXEDPRICINGMODEL = "UnsupportedOperation.InstanceMixedPricingModel"
// 请求不支持操作系统为`Xserver windows2012cndatacenterx86_64`的实例`ins-xxxxxx` 。
UNSUPPORTEDOPERATION_INSTANCEOSWINDOWS = "UnsupportedOperation.InstanceOsWindows"
// 该子机处于封禁状态,请联系相关人员处理。
UNSUPPORTEDOPERATION_INSTANCESTATEBANNING = "UnsupportedOperation.InstanceStateBanning"
// 请求不支持永久故障的实例。
UNSUPPORTEDOPERATION_INSTANCESTATECORRUPTED = "UnsupportedOperation.InstanceStateCorrupted"
// 请求不支持进入救援模式的实例
UNSUPPORTEDOPERATION_INSTANCESTATEENTERRESCUEMODE = "UnsupportedOperation.InstanceStateEnterRescueMode"
// 不支持状态为 `ENTER_SERVICE_LIVE_MIGRATE`.的实例 `ins-xxxxxx` 。
UNSUPPORTEDOPERATION_INSTANCESTATEENTERSERVICELIVEMIGRATE = "UnsupportedOperation.InstanceStateEnterServiceLiveMigrate"
// 请求不支持正在退出救援模式的实例
UNSUPPORTEDOPERATION_INSTANCESTATEEXITRESCUEMODE = "UnsupportedOperation.InstanceStateExitRescueMode"
// 不支持状态为 `EXIT_SERVICE_LIVE_MIGRATE`.的实例 `ins-xxxxxx` 。
UNSUPPORTEDOPERATION_INSTANCESTATEEXITSERVICELIVEMIGRATE = "UnsupportedOperation.InstanceStateExitServiceLiveMigrate"
// 操作不支持已冻结的实例。
UNSUPPORTEDOPERATION_INSTANCESTATEFREEZING = "UnsupportedOperation.InstanceStateFreezing"
// 请求不支持正在隔离状态的实例。
UNSUPPORTEDOPERATION_INSTANCESTATEISOLATING = "UnsupportedOperation.InstanceStateIsolating"
// 请求不支持创建未完成的实例
UNSUPPORTEDOPERATION_INSTANCESTATEPENDING = "UnsupportedOperation.InstanceStatePending"
// 请求不支持正在重启的实例
UNSUPPORTEDOPERATION_INSTANCESTATEREBOOTING = "UnsupportedOperation.InstanceStateRebooting"
// 请求不支持救援模式的实例
UNSUPPORTEDOPERATION_INSTANCESTATERESCUEMODE = "UnsupportedOperation.InstanceStateRescueMode"
// 请求不支持开机状态的实例
UNSUPPORTEDOPERATION_INSTANCESTATERUNNING = "UnsupportedOperation.InstanceStateRunning"
// 不支持正在服务迁移的实例,请稍后再试
UNSUPPORTEDOPERATION_INSTANCESTATESERVICELIVEMIGRATE = "UnsupportedOperation.InstanceStateServiceLiveMigrate"
// 请求不支持隔离状态的实例
UNSUPPORTEDOPERATION_INSTANCESTATESHUTDOWN = "UnsupportedOperation.InstanceStateShutdown"
// 实例开机中,不允许该操作。
UNSUPPORTEDOPERATION_INSTANCESTATESTARTING = "UnsupportedOperation.InstanceStateStarting"
// 请求不支持已关机的实例
UNSUPPORTEDOPERATION_INSTANCESTATESTOPPED = "UnsupportedOperation.InstanceStateStopped"
// 请求不支持正在关机的实例
UNSUPPORTEDOPERATION_INSTANCESTATESTOPPING = "UnsupportedOperation.InstanceStateStopping"
// 不支持已销毁的实例
UNSUPPORTEDOPERATION_INSTANCESTATETERMINATED = "UnsupportedOperation.InstanceStateTerminated"
// 请求不支持正在销毁的实例
UNSUPPORTEDOPERATION_INSTANCESTATETERMINATING = "UnsupportedOperation.InstanceStateTerminating"
// 不支持指定的磁盘
UNSUPPORTEDOPERATION_INVALIDDISK = "UnsupportedOperation.InvalidDisk"
// 当前操作只支持国际版用户。
UNSUPPORTEDOPERATION_INVALIDPERMISSIONNONINTERNATIONALACCOUNT = "UnsupportedOperation.InvalidPermissionNonInternationalAccount"
// 指定的地域不支持加密盘。
UNSUPPORTEDOPERATION_INVALIDREGIONDISKENCRYPT = "UnsupportedOperation.InvalidRegionDiskEncrypt"
// 密钥不支持Windows操作系统
UNSUPPORTEDOPERATION_KEYPAIRUNSUPPORTEDWINDOWS = "UnsupportedOperation.KeyPairUnsupportedWindows"
// 机型数据盘全为本地盘不支持跨机型调整。
UNSUPPORTEDOPERATION_LOCALDATADISKCHANGEINSTANCEFAMILY = "UnsupportedOperation.LocalDataDiskChangeInstanceFamily"
// 绑定负载均衡的实例不支持修改vpc属性。
UNSUPPORTEDOPERATION_MODIFYVPCWITHCLB = "UnsupportedOperation.ModifyVPCWithCLB"
// 该实例类型不支持竞价计费
UNSUPPORTEDOPERATION_NOINSTANCETYPESUPPORTSPOT = "UnsupportedOperation.NoInstanceTypeSupportSpot"
// 当前实例不是FPGA机型。
UNSUPPORTEDOPERATION_NOTFPGAINSTANCE = "UnsupportedOperation.NotFpgaInstance"
// 针对当前实例设置定时任务失败。
UNSUPPORTEDOPERATION_NOTSUPPORTIMPORTINSTANCESACTIONTIMER = "UnsupportedOperation.NotSupportImportInstancesActionTimer"
// 操作不支持当前实例
UNSUPPORTEDOPERATION_NOTSUPPORTINSTANCEIMAGE = "UnsupportedOperation.NotSupportInstanceImage"
// 该操作仅支持预付费账户
UNSUPPORTEDOPERATION_ONLYFORPREPAIDACCOUNT = "UnsupportedOperation.OnlyForPrepaidAccount"
// 当前镜像不支持对该实例的重装操作。
UNSUPPORTEDOPERATION_RAWLOCALDISKINSREINSTALLTOQCOW2 = "UnsupportedOperation.RawLocalDiskInsReinstalltoQcow2"
// 不支持该地域
UNSUPPORTEDOPERATION_REGION = "UnsupportedOperation.Region"
// 当前用户暂不支持购买预留实例计费。
UNSUPPORTEDOPERATION_RESERVEDINSTANCEINVISIBLEFORUSER = "UnsupportedOperation.ReservedInstanceInvisibleForUser"
// 用户预留实例计费配额已达上限。
UNSUPPORTEDOPERATION_RESERVEDINSTANCEOUTOFQUATA = "UnsupportedOperation.ReservedInstanceOutofQuata"
// 请求不支持特殊机型的实例
UNSUPPORTEDOPERATION_SPECIALINSTANCETYPE = "UnsupportedOperation.SpecialInstanceType"
// 不支持关机不收费特性
UNSUPPORTEDOPERATION_STOPPEDMODESTOPCHARGING = "UnsupportedOperation.StoppedModeStopCharging"
// 该机型为包销机型RenewFlag的值只允许设置为NOTIFY_AND_AUTO_RENEW。
UNSUPPORTEDOPERATION_UNDERWRITINGINSTANCETYPEONLYSUPPORTAUTORENEW = "UnsupportedOperation.UnderwritingInstanceTypeOnlySupportAutoRenew"
// 指定机型不支持跨机型调整配置。
UNSUPPORTEDOPERATION_UNSUPPORTEDCHANGEINSTANCEFAMILY = "UnsupportedOperation.UnsupportedChangeInstanceFamily"
// 非ARM机型不支持调整到ARM机型。
UNSUPPORTEDOPERATION_UNSUPPORTEDCHANGEINSTANCEFAMILYTOARM = "UnsupportedOperation.UnsupportedChangeInstanceFamilyToARM"
// 目标机型是SA3, 不支持变配。
UNSUPPORTEDOPERATION_UNSUPPORTEDCHANGEINSTANCEFAMILYTOSA3 = "UnsupportedOperation.UnsupportedChangeInstanceFamilyToSA3"
// 不支持实例变配到此类型机型。
UNSUPPORTEDOPERATION_UNSUPPORTEDCHANGEINSTANCETOTHISINSTANCEFAMILY = "UnsupportedOperation.UnsupportedChangeInstanceToThisInstanceFamily"
// 请求不支持国际版账号
UNSUPPORTEDOPERATION_UNSUPPORTEDINTERNATIONALUSER = "UnsupportedOperation.UnsupportedInternationalUser"
// 用户限额操作的配额不足。
UNSUPPORTEDOPERATION_USERLIMITOPERATIONEXCEEDQUOTA = "UnsupportedOperation.UserLimitOperationExceedQuota"
// 私有网络ip不在子网内。
VPCADDRNOTINSUBNET = "VpcAddrNotInSubNet"
// 私有网络ip已经被使用。
VPCIPISUSED = "VpcIpIsUsed"
)

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2017-2018 Tencent Ltd.
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.

View File

@ -0,0 +1,336 @@
/*
Copyright 2016 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 v20180525
const (
// 此产品的特有错误码
// 操作失败。
FAILEDOPERATION = "FailedOperation"
// 子账户RBAC权限不足。
FAILEDOPERATION_RBACFORBIDDEN = "FailedOperation.RBACForbidden"
// 内部错误。
INTERNALERROR = "InternalError"
// 获取用户认证信息失败。
INTERNALERROR_ACCOUNTCOMMON = "InternalError.AccountCommon"
// 账户未通过认证。
INTERNALERROR_ACCOUNTUSERNOTAUTHENTICATED = "InternalError.AccountUserNotAuthenticated"
// 伸缩组资源创建报错。
INTERNALERROR_ASCOMMON = "InternalError.AsCommon"
// 没有权限。
INTERNALERROR_CAMNOAUTH = "InternalError.CamNoAuth"
// CIDR和其他集群CIDR冲突。
INTERNALERROR_CIDRCONFLICTWITHOTHERCLUSTER = "InternalError.CidrConflictWithOtherCluster"
// CIDR和其他路由冲突。
INTERNALERROR_CIDRCONFLICTWITHOTHERROUTE = "InternalError.CidrConflictWithOtherRoute"
// CIDR和vpc冲突。
INTERNALERROR_CIDRCONFLICTWITHVPCCIDR = "InternalError.CidrConflictWithVpcCidr"
// CIDR和全局路由冲突。
INTERNALERROR_CIDRCONFLICTWITHVPCGLOBALROUTE = "InternalError.CidrConflictWithVpcGlobalRoute"
// CIDR无效。
INTERNALERROR_CIDRINVALI = "InternalError.CidrInvali"
// CIDR掩码无效。
INTERNALERROR_CIDRMASKSIZEOUTOFRANGE = "InternalError.CidrMaskSizeOutOfRange"
// CIDR不在路由表之内。
INTERNALERROR_CIDROUTOFROUTETABLE = "InternalError.CidrOutOfRouteTable"
// 集群未找到。
INTERNALERROR_CLUSTERNOTFOUND = "InternalError.ClusterNotFound"
// 集群状态错误。
INTERNALERROR_CLUSTERSTATE = "InternalError.ClusterState"
// 集群节点版本过低。
INTERNALERROR_CLUSTERUPGRADENODEVERSION = "InternalError.ClusterUpgradeNodeVersion"
// 执行命令超时。
INTERNALERROR_CMDTIMEOUT = "InternalError.CmdTimeout"
// 内部HTTP客户端错误。
INTERNALERROR_COMPONENTCLIENTHTTP = "InternalError.ComponentClientHttp"
// 请求(http请求)其他云服务失败。
INTERNALERROR_COMPONENTCLINETHTTP = "InternalError.ComponentClinetHttp"
// 容器未找到。
INTERNALERROR_CONTAINERNOTFOUND = "InternalError.ContainerNotFound"
// 创建集群失败。
INTERNALERROR_CREATEMASTERFAILED = "InternalError.CreateMasterFailed"
// cvm创建节点报错。
INTERNALERROR_CVMCOMMON = "InternalError.CvmCommon"
// cvm不存在。
INTERNALERROR_CVMNOTFOUND = "InternalError.CvmNotFound"
// 存在云服务器在CVM侧查询不到。
INTERNALERROR_CVMNUMBERNOTMATCH = "InternalError.CvmNumberNotMatch"
// cvm状态不正常。
INTERNALERROR_CVMSTATUS = "InternalError.CvmStatus"
// db错误。
INTERNALERROR_DB = "InternalError.Db"
// DB错误。
INTERNALERROR_DBAFFECTIVEDROWS = "InternalError.DbAffectivedRows"
// 记录未找到。
INTERNALERROR_DBRECORDNOTFOUND = "InternalError.DbRecordNotFound"
// 获得当前安全组总数失败。
INTERNALERROR_DFWGETUSGCOUNT = "InternalError.DfwGetUSGCount"
// 获得安全组配额失败。
INTERNALERROR_DFWGETUSGQUOTA = "InternalError.DfwGetUSGQuota"
// 不支持空集群。
INTERNALERROR_EMPTYCLUSTERNOTSUPPORT = "InternalError.EmptyClusterNotSupport"
// 下一跳地址已关联CIDR。
INTERNALERROR_GATEWAYALREADYASSOCIATEDCIDR = "InternalError.GatewayAlreadyAssociatedCidr"
// 镜像未找到。
INTERNALERROR_IMAGEIDNOTFOUND = "InternalError.ImageIdNotFound"
// 初始化master失败。
INTERNALERROR_INITMASTERFAILED = "InternalError.InitMasterFailed"
// 无效CIDR。
INTERNALERROR_INVALIDPRIVATENETWORKCIDR = "InternalError.InvalidPrivateNetworkCidr"
// 连接用户Kubernetes集群失败。
INTERNALERROR_KUBECLIENTCONNECTION = "InternalError.KubeClientConnection"
// 创建集群Client出错。
INTERNALERROR_KUBECLIENTCREATE = "InternalError.KubeClientCreate"
// KubernetesAPI错误。
INTERNALERROR_KUBECOMMON = "InternalError.KubeCommon"
// kubernetes client建立失败。
INTERNALERROR_KUBERNETESCLIENTBUILDERROR = "InternalError.KubernetesClientBuildError"
// 创建Kubernetes资源失败。
INTERNALERROR_KUBERNETESCREATEOPERATIONERROR = "InternalError.KubernetesCreateOperationError"
// 删除Kubernetes资源失败。
INTERNALERROR_KUBERNETESDELETEOPERATIONERROR = "InternalError.KubernetesDeleteOperationError"
// 获取Kubernetes资源失败。
INTERNALERROR_KUBERNETESGETOPERATIONERROR = "InternalError.KubernetesGetOperationError"
// Kubernetes未知错误。
INTERNALERROR_KUBERNETESINTERNAL = "InternalError.KubernetesInternal"
// 底层调用CLB未知错误。
INTERNALERROR_LBCOMMON = "InternalError.LbCommon"
// 镜像OS不支持。
INTERNALERROR_OSNOTSUPPORT = "InternalError.OsNotSupport"
// Param。
INTERNALERROR_PARAM = "InternalError.Param"
// Pod未找到。
INTERNALERROR_PODNOTFOUND = "InternalError.PodNotFound"
// 集群不支持当前操作。
INTERNALERROR_PUBLICCLUSTEROPNOTSUPPORT = "InternalError.PublicClusterOpNotSupport"
// 超过配额限制。
INTERNALERROR_QUOTAMAXCLSLIMIT = "InternalError.QuotaMaxClsLimit"
// 超过配额限制。
INTERNALERROR_QUOTAMAXNODLIMIT = "InternalError.QuotaMaxNodLimit"
// 超过配额限制。
INTERNALERROR_QUOTAMAXRTLIMIT = "InternalError.QuotaMaxRtLimit"
// 安全组配额不足。
INTERNALERROR_QUOTAUSGLIMIT = "InternalError.QuotaUSGLimit"
// 资源已存在。
INTERNALERROR_RESOURCEEXISTALREADY = "InternalError.ResourceExistAlready"
// 路由表非空。
INTERNALERROR_ROUTETABLENOTEMPTY = "InternalError.RouteTableNotEmpty"
// 路由表不存在。
INTERNALERROR_ROUTETABLENOTFOUND = "InternalError.RouteTableNotFound"
// 创建任务失败。
INTERNALERROR_TASKCREATEFAILED = "InternalError.TaskCreateFailed"
// 任务当前所处状态不支持此操作。
INTERNALERROR_TASKLIFESTATEERROR = "InternalError.TaskLifeStateError"
// 任务未找到。
INTERNALERROR_TASKNOTFOUND = "InternalError.TaskNotFound"
// 内部错误。
INTERNALERROR_UNEXCEPTEDINTERNAL = "InternalError.UnexceptedInternal"
// 未知的内部错误。
INTERNALERROR_UNEXPECTEDINTERNAL = "InternalError.UnexpectedInternal"
// VPC未知错误。
INTERNALERROR_VPCUNEXPECTEDERROR = "InternalError.VPCUnexpectedError"
// VPC报错。
INTERNALERROR_VPCCOMMON = "InternalError.VpcCommon"
// 对等连接不存在。
INTERNALERROR_VPCPEERNOTFOUND = "InternalError.VpcPeerNotFound"
// 未发现vpc记录。
INTERNALERROR_VPCRECODRNOTFOUND = "InternalError.VpcRecodrNotFound"
// 白名单未知错误。
INTERNALERROR_WHITELISTUNEXPECTEDERROR = "InternalError.WhitelistUnexpectedError"
// 参数错误。
INVALIDPARAMETER = "InvalidParameter"
// 弹性伸缩组创建参数错误。
INVALIDPARAMETER_ASCOMMONERROR = "InvalidParameter.AsCommonError"
// CIDR掩码超出范围(集群CIDR范围 最小值: 10 最大值: 24)。
INVALIDPARAMETER_CIDRMASKSIZEOUTOFRANGE = "InvalidParameter.CIDRMaskSizeOutOfRange"
// CIDR和其他集群CIDR冲突。
INVALIDPARAMETER_CIDRCONFLICTWITHOTHERCLUSTER = "InvalidParameter.CidrConflictWithOtherCluster"
// 创建的路由与已存在的其他路由产生冲突。
INVALIDPARAMETER_CIDRCONFLICTWITHOTHERROUTE = "InvalidParameter.CidrConflictWithOtherRoute"
// CIDR和vpc的CIDR冲突。
INVALIDPARAMETER_CIDRCONFLICTWITHVPCCIDR = "InvalidParameter.CidrConflictWithVpcCidr"
// 创建的路由与VPC下已存在的全局路由产生冲突。
INVALIDPARAMETER_CIDRCONFLICTWITHVPCGLOBALROUTE = "InvalidParameter.CidrConflictWithVpcGlobalRoute"
// 参数错误CIDR不符合规范。
INVALIDPARAMETER_CIDRINVALID = "InvalidParameter.CidrInvalid"
// CIDR不在路由表之内。
INVALIDPARAMETER_CIDROUTOFROUTETABLE = "InvalidParameter.CidrOutOfRouteTable"
// 集群ID不存在。
INVALIDPARAMETER_CLUSTERNOTFOUND = "InvalidParameter.ClusterNotFound"
// 下一跳地址已关联CIDR。
INVALIDPARAMETER_GATEWAYALREADYASSOCIATEDCIDR = "InvalidParameter.GatewayAlreadyAssociatedCidr"
// 无效的私有CIDR网段。
INVALIDPARAMETER_INVALIDPRIVATENETWORKCIDR = "InvalidParameter.InvalidPrivateNetworkCIDR"
// 参数错误。
INVALIDPARAMETER_PARAM = "InvalidParameter.Param"
// Prometheus未关联本集群。
INVALIDPARAMETER_PROMCLUSTERNOTFOUND = "InvalidParameter.PromClusterNotFound"
// Prometheus实例不存在。
INVALIDPARAMETER_PROMINSTANCENOTFOUND = "InvalidParameter.PromInstanceNotFound"
// 资源未找到。
INVALIDPARAMETER_RESOURCENOTFOUND = "InvalidParameter.ResourceNotFound"
// 路由表非空。
INVALIDPARAMETER_ROUTETABLENOTEMPTY = "InvalidParameter.RouteTableNotEmpty"
// 超过配额限制。
LIMITEXCEEDED = "LimitExceeded"
// 缺少参数错误。
MISSINGPARAMETER = "MissingParameter"
// 操作被拒绝。
OPERATIONDENIED = "OperationDenied"
// 集群处于删除保护中,禁止删除。
OPERATIONDENIED_CLUSTERINDELETIONPROTECTION = "OperationDenied.ClusterInDeletionProtection"
// 资源被占用。
RESOURCEINUSE = "ResourceInUse"
// 资源不足。
RESOURCEINSUFFICIENT = "ResourceInsufficient"
// 资源不存在。
RESOURCENOTFOUND = "ResourceNotFound"
// 伸缩组不存在。
RESOURCENOTFOUND_ASASGNOTEXIST = "ResourceNotFound.AsAsgNotExist"
// 集群不存在。
RESOURCENOTFOUND_CLUSTERNOTFOUND = "ResourceNotFound.ClusterNotFound"
// 用户Kubernetes集群中未找到指定资源。
RESOURCENOTFOUND_KUBERESOURCENOTFOUND = "ResourceNotFound.KubeResourceNotFound"
// 未找到该kubernetes资源。
RESOURCENOTFOUND_KUBERNETESRESOURCENOTFOUND = "ResourceNotFound.KubernetesResourceNotFound"
// 找不到对应路由表。
RESOURCENOTFOUND_ROUTETABLENOTFOUND = "ResourceNotFound.RouteTableNotFound"
// 资源不可用。
RESOURCEUNAVAILABLE = "ResourceUnavailable"
// 集群状态不支持该操作。
RESOURCEUNAVAILABLE_CLUSTERSTATE = "ResourceUnavailable.ClusterState"
// Eks Container Instance状态不支持改操作。
RESOURCEUNAVAILABLE_EKSCONTAINERSTATUS = "ResourceUnavailable.EksContainerStatus"
// 资源售罄。
RESOURCESSOLDOUT = "ResourcesSoldOut"
// 未授权操作。
UNAUTHORIZEDOPERATION = "UnauthorizedOperation"
// 无该接口CAM权限。
UNAUTHORIZEDOPERATION_CAMNOAUTH = "UnauthorizedOperation.CamNoAuth"
// 未知参数错误。
UNKNOWNPARAMETER = "UnknownParameter"
// 操作不支持。
UNSUPPORTEDOPERATION = "UnsupportedOperation"
// AS伸缩关闭导致无法开启CA。
UNSUPPORTEDOPERATION_CAENABLEFAILED = "UnsupportedOperation.CaEnableFailed"
// 非白名单用户。
UNSUPPORTEDOPERATION_NOTINWHITELIST = "UnsupportedOperation.NotInWhitelist"
)

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2017-2018 Tencent Ltd.
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.

View File

@ -0,0 +1,621 @@
/*
Copyright 2016 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 v20170312
const (
// 此产品的特有错误码
// 账户配额不足,每个腾讯云账户每个地域下最多可创建 20 个 EIP。
ADDRESSQUOTALIMITEXCEEDED = "AddressQuotaLimitExceeded"
// 申购次数不足,每个腾讯云账户每个地域每天申购次数为配额数*2 次。
ADDRESSQUOTALIMITEXCEEDED_DAILYALLOCATE = "AddressQuotaLimitExceeded.DailyAllocate"
// CAM签名/鉴权错误。
AUTHFAILURE = "AuthFailure"
// 地址没有弹性网卡信息。
FAILEDOPERATION_ADDRESSENIINFONOTFOUND = "FailedOperation.AddressEniInfoNotFound"
// 内部错误。
INTERNALERROR = "InternalError"
// 操作内部错误。
INTERNALSERVERERROR = "InternalServerError"
// 不支持此账户。
INVALIDACCOUNT_NOTSUPPORTED = "InvalidAccount.NotSupported"
// 指定EIP处于被封堵状态。当EIP处于封堵状态的时候是不能够进行绑定操作的需要先进行解封。
INVALIDADDRESSID_BLOCKED = "InvalidAddressId.Blocked"
// 指定的EIP不存在。
INVALIDADDRESSID_NOTFOUND = "InvalidAddressId.NotFound"
// 指定EIP处于欠费状态。
INVALIDADDRESSIDSTATE_INARREARS = "InvalidAddressIdState.InArrears"
// 指定 EIP 当前状态不能进行绑定操作。只有 EIP 的状态是 UNBIND 时才能进行绑定操作。
INVALIDADDRESSIDSTATUS_NOTPERMIT = "InvalidAddressIdStatus.NotPermit"
// 指定EIP的当前状态不允许进行该操作。
INVALIDADDRESSSTATE = "InvalidAddressState"
// 不被支持的实例。
INVALIDINSTANCE_NOTSUPPORTED = "InvalidInstance.NotSupported"
// 指定实例已经绑定了EIP。需先解绑当前的EIP才能再次进行绑定操作。
INVALIDINSTANCEID_ALREADYBINDEIP = "InvalidInstanceId.AlreadyBindEip"
// 无效实例ID。指定的实例ID不存在。
INVALIDINSTANCEID_NOTFOUND = "InvalidInstanceId.NotFound"
// 指定 NetworkInterfaceId 不存在或指定的PrivateIpAddress不在NetworkInterfaceId上。
INVALIDNETWORKINTERFACEID_NOTFOUND = "InvalidNetworkInterfaceId.NotFound"
// 参数错误。
INVALIDPARAMETER = "InvalidParameter"
// 参数不支持同时指定。
INVALIDPARAMETER_COEXIST = "InvalidParameter.Coexist"
// 指定过滤条件不存在。
INVALIDPARAMETER_FILTERINVALIDKEY = "InvalidParameter.FilterInvalidKey"
// 指定过滤条件不是键值对。
INVALIDPARAMETER_FILTERNOTDICT = "InvalidParameter.FilterNotDict"
// 指定过滤选项值不是列表。
INVALIDPARAMETER_FILTERVALUESNOTLIST = "InvalidParameter.FilterValuesNotList"
// 该过滤规则不合法。
INVALIDPARAMETER_INVALIDFILTER = "InvalidParameter.InvalidFilter"
// 下一跳类型与下一跳网关不匹配。
INVALIDPARAMETER_NEXTHOPMISMATCH = "InvalidParameter.NextHopMismatch"
// 专线网关跨可用区容灾组不存在。
INVALIDPARAMETER_VPGHAGROUPNOTFOUND = "InvalidParameter.VpgHaGroupNotFound"
// 指定的两个参数冲突,不能同时存在。 EIP只能绑定在实例上或指定网卡的指定内网 IP 上。
INVALIDPARAMETERCONFLICT = "InvalidParameterConflict"
// 参数取值错误。
INVALIDPARAMETERVALUE = "InvalidParameterValue"
// 该地址ID不合法。
INVALIDPARAMETERVALUE_ADDRESSIDMALFORMED = "InvalidParameterValue.AddressIdMalformed"
// 该地址计费方式与其他地址冲突。
INVALIDPARAMETERVALUE_ADDRESSINTERNETCHARGETYPECONFLICT = "InvalidParameterValue.AddressInternetChargeTypeConflict"
// 该IP地址现在不可用。
INVALIDPARAMETERVALUE_ADDRESSIPNOTAVAILABLE = "InvalidParameterValue.AddressIpNotAvailable"
// IP地址未找到。
INVALIDPARAMETERVALUE_ADDRESSIPNOTFOUND = "InvalidParameterValue.AddressIpNotFound"
// VPC中不存在此IP地址。
INVALIDPARAMETERVALUE_ADDRESSIPNOTINVPC = "InvalidParameterValue.AddressIpNotInVpc"
// 该地址不可与此实例申请。
INVALIDPARAMETERVALUE_ADDRESSNOTAPPLICABLE = "InvalidParameterValue.AddressNotApplicable"
// 该地址不是CalcIP。
INVALIDPARAMETERVALUE_ADDRESSNOTCALCIP = "InvalidParameterValue.AddressNotCalcIP"
// 该地址不是EIP。
INVALIDPARAMETERVALUE_ADDRESSNOTEIP = "InvalidParameterValue.AddressNotEIP"
// 未找到该地址。
INVALIDPARAMETERVALUE_ADDRESSNOTFOUND = "InvalidParameterValue.AddressNotFound"
// 该IPv6地址已经发布。
INVALIDPARAMETERVALUE_ADDRESSPUBLISHED = "InvalidParameterValue.AddressPublished"
// 带宽超出限制。
INVALIDPARAMETERVALUE_BANDWIDTHOUTOFRANGE = "InvalidParameterValue.BandwidthOutOfRange"
// 带宽包ID不正确。
INVALIDPARAMETERVALUE_BANDWIDTHPACKAGEIDMALFORMED = "InvalidParameterValue.BandwidthPackageIdMalformed"
// 该带宽包正在被使用。
INVALIDPARAMETERVALUE_BANDWIDTHPACKAGEINUSE = "InvalidParameterValue.BandwidthPackageInUse"
// 未查询到该带宽包。
INVALIDPARAMETERVALUE_BANDWIDTHPACKAGENOTFOUND = "InvalidParameterValue.BandwidthPackageNotFound"
// 选择带宽低于可允许的最小范围。
INVALIDPARAMETERVALUE_BANDWIDTHTOOSMALL = "InvalidParameterValue.BandwidthTooSmall"
// 指定云联网关联黑石私有网络数量达到上限。
INVALIDPARAMETERVALUE_CCNATTACHBMVPCLIMITEXCEEDED = "InvalidParameterValue.CcnAttachBmvpcLimitExceeded"
// 目的网段不在对端VPC的CIDR范围内。
INVALIDPARAMETERVALUE_CIDRNOTINPEERVPC = "InvalidParameterValue.CidrNotInPeerVpc"
// 非法入参组合。
INVALIDPARAMETERVALUE_COMBINATION = "InvalidParameterValue.Combination"
// 入参重复。
INVALIDPARAMETERVALUE_DUPLICATE = "InvalidParameterValue.Duplicate"
// 缺少参数。
INVALIDPARAMETERVALUE_EMPTY = "InvalidParameterValue.Empty"
// IPv6规则没有更改。
INVALIDPARAMETERVALUE_IPV6RULENOTCHANGE = "InvalidParameterValue.IPv6RuleNotChange"
// 该实例的计费方式与其他实例不同。
INVALIDPARAMETERVALUE_INCONSISTENTINSTANCEINTERNETCHARGETYPE = "InvalidParameterValue.InconsistentInstanceInternetChargeType"
// 该实例不支持AnycastEIP。
INVALIDPARAMETERVALUE_INSTANCEDOESNOTSUPPORTANYCAST = "InvalidParameterValue.InstanceDoesNotSupportAnycast"
// 该实例已有WanIP。
INVALIDPARAMETERVALUE_INSTANCEHASWANIP = "InvalidParameterValue.InstanceHasWanIP"
// 该实例没有CalcIP无法完成请求。
INVALIDPARAMETERVALUE_INSTANCENOCALCIP = "InvalidParameterValue.InstanceNoCalcIP"
// 该实例没有WanIP无法完成请求。
INVALIDPARAMETERVALUE_INSTANCENOWANIP = "InvalidParameterValue.InstanceNoWanIP"
// 由于该IP被禁用无法绑定该实例。
INVALIDPARAMETERVALUE_INSTANCENORMALPUBLICIPBLOCKED = "InvalidParameterValue.InstanceNormalPublicIpBlocked"
// 弹性网卡绑定的实例与地址绑定的实例不一致。
INVALIDPARAMETERVALUE_INSTANCENOTMATCHASSOCIATEENI = "InvalidParameterValue.InstanceNotMatchAssociateEni"
// 网络计费模式没有更改。
INVALIDPARAMETERVALUE_INTERNETCHARGETYPENOTCHANGED = "InvalidParameterValue.InternetChargeTypeNotChanged"
// 无效的带宽包计费方式。
INVALIDPARAMETERVALUE_INVALIDBANDWIDTHPACKAGECHARGETYPE = "InvalidParameterValue.InvalidBandwidthPackageChargeType"
// 参数的值不存在或不支持。
INVALIDPARAMETERVALUE_INVALIDBUSINESS = "InvalidParameterValue.InvalidBusiness"
// 传入的DedicatedClusterId有误。
INVALIDPARAMETERVALUE_INVALIDDEDICATEDCLUSTERID = "InvalidParameterValue.InvalidDedicatedClusterId"
// 该IP只能绑定小时流量后付费和带宽包实例。
INVALIDPARAMETERVALUE_INVALIDINSTANCEINTERNETCHARGETYPE = "InvalidParameterValue.InvalidInstanceInternetChargeType"
// 该实例状态无法完成操作。
INVALIDPARAMETERVALUE_INVALIDINSTANCESTATE = "InvalidParameterValue.InvalidInstanceState"
// 无效的IPv6地址。
INVALIDPARAMETERVALUE_INVALIDIPV6 = "InvalidParameterValue.InvalidIpv6"
// 该Tag不合法。
INVALIDPARAMETERVALUE_INVALIDTAG = "InvalidParameterValue.InvalidTag"
// 负载均衡实例已经绑定了EIP。
INVALIDPARAMETERVALUE_LBALREADYBINDEIP = "InvalidParameterValue.LBAlreadyBindEip"
// 参数值超出限制。
INVALIDPARAMETERVALUE_LIMITEXCEEDED = "InvalidParameterValue.LimitExceeded"
// 入参格式不合法。
INVALIDPARAMETERVALUE_MALFORMED = "InvalidParameterValue.Malformed"
// 缺少绑定的实例。
INVALIDPARAMETERVALUE_MISSINGASSOCIATEENTITY = "InvalidParameterValue.MissingAssociateEntity"
// 集群类型不同的IP不可在同一请求中。
INVALIDPARAMETERVALUE_MIXEDADDRESSIPSETTYPE = "InvalidParameterValue.MixedAddressIpSetType"
// NAT网关的SNAT规则已经存在。
INVALIDPARAMETERVALUE_NATSNATRULEEXISTS = "InvalidParameterValue.NatSnatRuleExists"
// 探测目的IP和网络探测在同一个VPC内。
INVALIDPARAMETERVALUE_NETDETECTINVPC = "InvalidParameterValue.NetDetectInVpc"
// 探测目的IP在云联网的路由表中找不到匹配的下一跳。
INVALIDPARAMETERVALUE_NETDETECTNOTFOUNDIP = "InvalidParameterValue.NetDetectNotFoundIp"
// 探测目的IP与同一个私有网络内的同一个子网下的其他网络探测的探测目的IP相同。
INVALIDPARAMETERVALUE_NETDETECTSAMEIP = "InvalidParameterValue.NetDetectSameIp"
// 网络接口ID不正确。
INVALIDPARAMETERVALUE_NETWORKINTERFACEIDMALFORMED = "InvalidParameterValue.NetworkInterfaceIdMalformed"
// 未找到网络接口ID或私有IP地址未在网络接口配置。
INVALIDPARAMETERVALUE_NETWORKINTERFACENOTFOUND = "InvalidParameterValue.NetworkInterfaceNotFound"
// 该操作仅对主网卡支持。
INVALIDPARAMETERVALUE_ONLYSUPPORTEDFORMASTERNETWORKCARD = "InvalidParameterValue.OnlySupportedForMasterNetworkCard"
// 参数值不在指定范围。
INVALIDPARAMETERVALUE_RANGE = "InvalidParameterValue.Range"
// 参数值是一个系统保留对象。
INVALIDPARAMETERVALUE_RESERVED = "InvalidParameterValue.Reserved"
// 该资源已加入其他带宽包。
INVALIDPARAMETERVALUE_RESOURCEALREADYEXISTED = "InvalidParameterValue.ResourceAlreadyExisted"
// 该资源已过期。
INVALIDPARAMETERVALUE_RESOURCEEXPIRED = "InvalidParameterValue.ResourceExpired"
// 资源ID不正确。
INVALIDPARAMETERVALUE_RESOURCEIDMALFORMED = "InvalidParameterValue.ResourceIdMalformed"
// 该资源不在此带宽包中。
INVALIDPARAMETERVALUE_RESOURCENOTEXISTED = "InvalidParameterValue.ResourceNotExisted"
// 未查询到该资源。
INVALIDPARAMETERVALUE_RESOURCENOTFOUND = "InvalidParameterValue.ResourceNotFound"
// 该资源不支持此操作。
INVALIDPARAMETERVALUE_RESOURCENOTSUPPORT = "InvalidParameterValue.ResourceNotSupport"
// 子网CIDR冲突。
INVALIDPARAMETERVALUE_SUBNETCONFLICT = "InvalidParameterValue.SubnetConflict"
// 子网与辅助Cidr网段重叠。
INVALIDPARAMETERVALUE_SUBNETOVERLAPASSISTCIDR = "InvalidParameterValue.SubnetOverlapAssistCidr"
// 子网CIDR不合法。
INVALIDPARAMETERVALUE_SUBNETRANGE = "InvalidParameterValue.SubnetRange"
// 该标签和值不存在。
INVALIDPARAMETERVALUE_TAGNOTEXISTED = "InvalidParameterValue.TagNotExisted"
// 无效参数值。参数值太长。
INVALIDPARAMETERVALUE_TOOLONG = "InvalidParameterValue.TooLong"
// 该可用区不可用。
INVALIDPARAMETERVALUE_UNAVAILABLEZONE = "InvalidParameterValue.UnavailableZone"
// 目的网段和当前VPC的CIDR冲突。
INVALIDPARAMETERVALUE_VPCCIDRCONFLICT = "InvalidParameterValue.VpcCidrConflict"
// 当前功能不支持此专线网关。
INVALIDPARAMETERVALUE_VPGTYPENOTMATCH = "InvalidParameterValue.VpgTypeNotMatch"
// 目的网段和当前VPN通道的CIDR冲突。
INVALIDPARAMETERVALUE_VPNCONNCIDRCONFLICT = "InvalidParameterValue.VpnConnCidrConflict"
// VPN通道探测ip冲突。
INVALIDPARAMETERVALUE_VPNCONNHEALTHCHECKIPCONFLICT = "InvalidParameterValue.VpnConnHealthCheckIpConflict"
// 参数Zone的值与CDC所在Zone冲突。
INVALIDPARAMETERVALUE_ZONECONFLICT = "InvalidParameterValue.ZoneConflict"
// 指定弹性网卡的指定内网IP已经绑定了EIP不能重复绑定。
INVALIDPRIVATEIPADDRESS_ALREADYBINDEIP = "InvalidPrivateIpAddress.AlreadyBindEip"
// 无效的路由策略IDRouteId
INVALIDROUTEID_NOTFOUND = "InvalidRouteId.NotFound"
// 无效的路由表,路由表实例ID不合法。
INVALIDROUTETABLEID_MALFORMED = "InvalidRouteTableId.Malformed"
// 无效的路由表,路由表资源不存在,请再次核实您输入的资源信息是否正确。
INVALIDROUTETABLEID_NOTFOUND = "InvalidRouteTableId.NotFound"
// 无效的安全组,安全组实例ID不合法。
INVALIDSECURITYGROUPID_MALFORMED = "InvalidSecurityGroupID.Malformed"
// 无效的安全组,安全组实例ID不存在。
INVALIDSECURITYGROUPID_NOTFOUND = "InvalidSecurityGroupID.NotFound"
// 无效的VPC,VPC实例ID不合法。
INVALIDVPCID_MALFORMED = "InvalidVpcId.Malformed"
// 无效的VPC,VPC资源不存在。
INVALIDVPCID_NOTFOUND = "InvalidVpcId.NotFound"
// 无效的VPN网关,VPN实例ID不合法。
INVALIDVPNGATEWAYID_MALFORMED = "InvalidVpnGatewayId.Malformed"
// 无效的VPN网关,VPN实例不存在请再次核实您输入的资源信息是否正确。
INVALIDVPNGATEWAYID_NOTFOUND = "InvalidVpnGatewayId.NotFound"
// 超过配额限制。
LIMITEXCEEDED = "LimitExceeded"
// 分配IP地址数量达到上限。
LIMITEXCEEDED_ADDRESS = "LimitExceeded.Address"
// 租户申请的弹性IP超过上限。
LIMITEXCEEDED_ADDRESSQUOTALIMITEXCEEDED = "LimitExceeded.AddressQuotaLimitExceeded"
// VPC分配网段数量达到上限。
LIMITEXCEEDED_CIDRBLOCK = "LimitExceeded.CidrBlock"
// 租户每天申请的弹性IP超过上限。
LIMITEXCEEDED_DAILYALLOCATEADDRESSQUOTALIMITEXCEEDED = "LimitExceeded.DailyAllocateAddressQuotaLimitExceeded"
// 私有网络创建的NAT网关超过上限。
LIMITEXCEEDED_NATGATEWAYPERVPCLIMITEXCEEDED = "LimitExceeded.NatGatewayPerVpcLimitExceeded"
// NAT网关绑定的弹性IP超过上限。
LIMITEXCEEDED_PUBLICIPADDRESSPERNATGATEWAYLIMITEXCEEDED = "LimitExceeded.PublicIpAddressPerNatGatewayLimitExceeded"
// 安全组规则数量超过上限。
LIMITEXCEEDED_SECURITYGROUPPOLICYSET = "LimitExceeded.SecurityGroupPolicySet"
// 子网分配子网段数量达到上限。
LIMITEXCEEDED_SUBNETCIDRBLOCK = "LimitExceeded.SubnetCidrBlock"
// 缺少参数错误。
MISSINGPARAMETER = "MissingParameter"
// 资源被占用。
RESOURCEINUSE = "ResourceInUse"
// 指定IP地址已经在使用中。
RESOURCEINUSE_ADDRESS = "ResourceInUse.Address"
// 资源不足。
RESOURCEINSUFFICIENT = "ResourceInsufficient"
// 网段资源不足。
RESOURCEINSUFFICIENT_CIDRBLOCK = "ResourceInsufficient.CidrBlock"
// 资源不存在。
RESOURCENOTFOUND = "ResourceNotFound"
// Svc不存在。
RESOURCENOTFOUND_SVCNOTEXIST = "ResourceNotFound.SvcNotExist"
// 资源不可用。
RESOURCEUNAVAILABLE = "ResourceUnavailable"
// 当前用户不在指定终端节点服务的白名单内。
RESOURCEUNAVAILABLE_SERVICEWHITELISTNOTADDED = "ResourceUnavailable.ServiceWhiteListNotAdded"
// 未授权操作。
UNAUTHORIZEDOPERATION = "UnauthorizedOperation"
// 绑定关系不存在。
UNAUTHORIZEDOPERATION_ATTACHMENTNOTFOUND = "UnauthorizedOperation.AttachmentNotFound"
// 账号未实名。
UNAUTHORIZEDOPERATION_NOREALNAMEAUTHENTICATION = "UnauthorizedOperation.NoRealNameAuthentication"
// 主IP不支持指定操作。
UNAUTHORIZEDOPERATION_PRIMARYIP = "UnauthorizedOperation.PrimaryIp"
// 未知参数错误。
UNKNOWNPARAMETER = "UnknownParameter"
// 参数无法识别,可以尝试相似参数代替。
UNKNOWNPARAMETER_WITHGUESS = "UnknownParameter.WithGuess"
// 操作不支持。
UNSUPPORTEDOPERATION = "UnsupportedOperation"
// 接口不存在。
UNSUPPORTEDOPERATION_ACTIONNOTFOUND = "UnsupportedOperation.ActionNotFound"
// 欠费状态不支持该操作。
UNSUPPORTEDOPERATION_ADDRESSIPINARREAR = "UnsupportedOperation.AddressIpInArrear"
// 此付费模式的IP地址不支持该操作。
UNSUPPORTEDOPERATION_ADDRESSIPINTERNETCHARGETYPENOTPERMIT = "UnsupportedOperation.AddressIpInternetChargeTypeNotPermit"
// 绑定此实例的IP地址不支持该操作。
UNSUPPORTEDOPERATION_ADDRESSIPNOTSUPPORTINSTANCE = "UnsupportedOperation.AddressIpNotSupportInstance"
// 此IP地址状态不支持该操作。
UNSUPPORTEDOPERATION_ADDRESSIPSTATUSNOTPERMIT = "UnsupportedOperation.AddressIpStatusNotPermit"
// 该地址状态不支持此操作。
UNSUPPORTEDOPERATION_ADDRESSSTATUSNOTPERMIT = "UnsupportedOperation.AddressStatusNotPermit"
// 资源不在指定的AppId下。
UNSUPPORTEDOPERATION_APPIDMISMATCH = "UnsupportedOperation.AppIdMismatch"
// APPId不存在。
UNSUPPORTEDOPERATION_APPIDNOTFOUND = "UnsupportedOperation.AppIdNotFound"
// 绑定关系已存在。
UNSUPPORTEDOPERATION_ATTACHMENTALREADYEXISTS = "UnsupportedOperation.AttachmentAlreadyExists"
// 绑定关系不存在。
UNSUPPORTEDOPERATION_ATTACHMENTNOTFOUND = "UnsupportedOperation.AttachmentNotFound"
// 当前云联网还有预付费带宽未到期,不支持主动删除。
UNSUPPORTEDOPERATION_BANDWIDTHNOTEXPIRED = "UnsupportedOperation.BandwidthNotExpired"
// 该带宽包不支持此操作。
UNSUPPORTEDOPERATION_BANDWIDTHPACKAGEIDNOTSUPPORTED = "UnsupportedOperation.BandwidthPackageIdNotSupported"
// 已绑定EIP。
UNSUPPORTEDOPERATION_BINDEIP = "UnsupportedOperation.BindEIP"
// 指定VPC CIDR范围不支持私有网络和基础网络设备互通。
UNSUPPORTEDOPERATION_CIDRUNSUPPORTEDCLASSICLINK = "UnsupportedOperation.CIDRUnSupportedClassicLink"
// 实例已关联CCN。
UNSUPPORTEDOPERATION_CCNATTACHED = "UnsupportedOperation.CcnAttached"
// 当前云联网有流日志,不支持删除。
UNSUPPORTEDOPERATION_CCNHASFLOWLOG = "UnsupportedOperation.CcnHasFlowLog"
// 实例未关联CCN。
UNSUPPORTEDOPERATION_CCNNOTATTACHED = "UnsupportedOperation.CcnNotAttached"
// 指定的路由表不存在。
UNSUPPORTEDOPERATION_CCNROUTETABLENOTEXIST = "UnsupportedOperation.CcnRouteTableNotExist"
// CDC子网不支持创建非本地网关类型的路由。
UNSUPPORTEDOPERATION_CDCSUBNETNOTSUPPORTUNLOCALGATEWAY = "UnsupportedOperation.CdcSubnetNotSupportUnLocalGateway"
// 实例已经和VPC绑定。
UNSUPPORTEDOPERATION_CLASSICINSTANCEIDALREADYEXISTS = "UnsupportedOperation.ClassicInstanceIdAlreadyExists"
// 公网Clb不支持该规则。
UNSUPPORTEDOPERATION_CLBPOLICYLIMIT = "UnsupportedOperation.ClbPolicyLimit"
// 与该VPC下的TKE容器的网段重叠。
UNSUPPORTEDOPERATION_CONFLICTWITHDOCKERROUTE = "UnsupportedOperation.ConflictWithDockerRoute"
// 指定的VPC未发现专线网关。
UNSUPPORTEDOPERATION_DCGATEWAYSNOTFOUNDINVPC = "UnsupportedOperation.DcGatewaysNotFoundInVpc"
// 专线网关正在更新BGP Community属性。
UNSUPPORTEDOPERATION_DIRECTCONNECTGATEWAYISUPDATINGCOMMUNITY = "UnsupportedOperation.DirectConnectGatewayIsUpdatingCommunity"
// 指定的路由策略已发布至云联网,请先撤销。
UNSUPPORTEDOPERATION_DISABLEDNOTIFYCCN = "UnsupportedOperation.DisabledNotifyCcn"
// 安全组规则重复。
UNSUPPORTEDOPERATION_DUPLICATEPOLICY = "UnsupportedOperation.DuplicatePolicy"
// 不支持ECMP。
UNSUPPORTEDOPERATION_ECMP = "UnsupportedOperation.Ecmp"
// 和云联网的路由形成ECMP。
UNSUPPORTEDOPERATION_ECMPWITHCCNROUTE = "UnsupportedOperation.EcmpWithCcnRoute"
// 和用户自定义的路由形成ECMP。
UNSUPPORTEDOPERATION_ECMPWITHUSERROUTE = "UnsupportedOperation.EcmpWithUserRoute"
// 终端节点服务本身不能是终端节点。
UNSUPPORTEDOPERATION_ENDPOINTSERVICE = "UnsupportedOperation.EndPointService"
// 该种类型地址不支持此操作。
UNSUPPORTEDOPERATION_INCORRECTADDRESSRESOURCETYPE = "UnsupportedOperation.IncorrectAddressResourceType"
// 用户配置的实例和路由表不匹配。
UNSUPPORTEDOPERATION_INSTANCEANDRTBNOTMATCH = "UnsupportedOperation.InstanceAndRtbNotMatch"
// 该地址绑定的实例状态不支持此操作。
UNSUPPORTEDOPERATION_INSTANCESTATENOTSUPPORTED = "UnsupportedOperation.InstanceStateNotSupported"
// 账户余额不足。
UNSUPPORTEDOPERATION_INSUFFICIENTFUNDS = "UnsupportedOperation.InsufficientFunds"
// 不支持该操作。
UNSUPPORTEDOPERATION_INVALIDACTION = "UnsupportedOperation.InvalidAction"
// 该地址的网络付费方式不支持此操作。
UNSUPPORTEDOPERATION_INVALIDADDRESSINTERNETCHARGETYPE = "UnsupportedOperation.InvalidAddressInternetChargeType"
// 该地址状态不支持此操作。
UNSUPPORTEDOPERATION_INVALIDADDRESSSTATE = "UnsupportedOperation.InvalidAddressState"
// 无效的实例状态。
UNSUPPORTEDOPERATION_INVALIDINSTANCESTATE = "UnsupportedOperation.InvalidInstanceState"
// 该计费方式不支持此操作。
UNSUPPORTEDOPERATION_INVALIDRESOURCEINTERNETCHARGETYPE = "UnsupportedOperation.InvalidResourceInternetChargeType"
// 不支持加入此协议的带宽包。
UNSUPPORTEDOPERATION_INVALIDRESOURCEPROTOCOL = "UnsupportedOperation.InvalidResourceProtocol"
// 资源状态不合法。
UNSUPPORTEDOPERATION_INVALIDSTATE = "UnsupportedOperation.InvalidState"
// 关联当前云联网的实例的账号存在不是金融云账号。
UNSUPPORTEDOPERATION_ISNOTFINANCEACCOUNT = "UnsupportedOperation.IsNotFinanceAccount"
// 该ISP不支持此操作。
UNSUPPORTEDOPERATION_ISPNOTSUPPORTED = "UnsupportedOperation.IspNotSupported"
// 指定的CDC已存在本地网关。
UNSUPPORTEDOPERATION_LOCALGATEWAYALREADYEXISTS = "UnsupportedOperation.LocalGatewayAlreadyExists"
// 资源互斥操作任务正在执行。
UNSUPPORTEDOPERATION_MUTEXOPERATIONTASKRUNNING = "UnsupportedOperation.MutexOperationTaskRunning"
// NAT网关类型不支持SNAT规则。
UNSUPPORTEDOPERATION_NATGATEWAYTYPENOTSUPPORTSNAT = "UnsupportedOperation.NatGatewayTypeNotSupportSNAT"
// NAT实例不支持该操作。
UNSUPPORTEDOPERATION_NATNOTSUPPORTED = "UnsupportedOperation.NatNotSupported"
// 指定的子网不支持创建本地网关类型的路由。
UNSUPPORTEDOPERATION_NORMALSUBNETNOTSUPPORTLOCALGATEWAY = "UnsupportedOperation.NormalSubnetNotSupportLocalGateway"
// 当前云联网实例未处于申请中状态,无法进行操作。
UNSUPPORTEDOPERATION_NOTPENDINGCCNINSTANCE = "UnsupportedOperation.NotPendingCcnInstance"
// 当前云联网为非后付费类型,无法进行此操作。
UNSUPPORTEDOPERATION_NOTPOSTPAIDCCNOPERATION = "UnsupportedOperation.NotPostpaidCcnOperation"
// 指定的路由策略不支持发布或撤销至云联网。
UNSUPPORTEDOPERATION_NOTIFYCCN = "UnsupportedOperation.NotifyCcn"
// 预付费云联网只支持地域间限速。
UNSUPPORTEDOPERATION_PREPAIDCCNONLYSUPPORTINTERREGIONLIMIT = "UnsupportedOperation.PrepaidCcnOnlySupportInterRegionLimit"
// 指定的值是主IP。
UNSUPPORTEDOPERATION_PRIMARYIP = "UnsupportedOperation.PrimaryIp"
// Nat网关至少存在一个弹性IP弹性IP不能解绑。
UNSUPPORTEDOPERATION_PUBLICIPADDRESSDISASSOCIATE = "UnsupportedOperation.PublicIpAddressDisassociate"
// 绑定NAT网关的弹性IP不是BGP性质的IP。
UNSUPPORTEDOPERATION_PUBLICIPADDRESSISNOTBGPIP = "UnsupportedOperation.PublicIpAddressIsNotBGPIp"
// 绑定NAT网关的弹性IP不存在。
UNSUPPORTEDOPERATION_PUBLICIPADDRESSISNOTEXISTED = "UnsupportedOperation.PublicIpAddressIsNotExisted"
// 绑定NAT网关的弹性IP不是按流量计费的。
UNSUPPORTEDOPERATION_PUBLICIPADDRESSNOTBILLEDBYTRAFFIC = "UnsupportedOperation.PublicIpAddressNotBilledByTraffic"
// 输入的资源ID与IP绑定的资源不匹配请检查。
UNSUPPORTEDOPERATION_RESOURCEMISMATCH = "UnsupportedOperation.ResourceMismatch"
// 指定的终端节点服务所创建的终端节点不支持绑定安全组。
UNSUPPORTEDOPERATION_SPECIALENDPOINTSERVICE = "UnsupportedOperation.SpecialEndPointService"
// 系统路由,禁止操作。
UNSUPPORTEDOPERATION_SYSTEMROUTE = "UnsupportedOperation.SystemRoute"
// 账号ID不存在。
UNSUPPORTEDOPERATION_UINNOTFOUND = "UnsupportedOperation.UinNotFound"
// 不支持跨境。
UNSUPPORTEDOPERATION_UNABLECROSSBORDER = "UnsupportedOperation.UnableCrossBorder"
// 当前云联网无法关联金融云实例。
UNSUPPORTEDOPERATION_UNABLECROSSFINANCE = "UnsupportedOperation.UnableCrossFinance"
// 未分配IPv6网段。
UNSUPPORTEDOPERATION_UNASSIGNCIDRBLOCK = "UnsupportedOperation.UnassignCidrBlock"
// 未绑定EIP。
UNSUPPORTEDOPERATION_UNBINDEIP = "UnsupportedOperation.UnbindEIP"
// 账户还有未支付订单,请先完成付款。
UNSUPPORTEDOPERATION_UNPAIDORDERALREADYEXISTS = "UnsupportedOperation.UnpaidOrderAlreadyExists"
// 指定机型不支持弹性网卡。
UNSUPPORTEDOPERATION_UNSUPPORTEDINSTANCEFAMILY = "UnsupportedOperation.UnsupportedInstanceFamily"
// 当前用户付费类型不支持创建所选付费类型的云联网。
UNSUPPORTEDOPERATION_USERANDCCNCHARGETYPENOTMATCH = "UnsupportedOperation.UserAndCcnChargeTypeNotMatch"
// 指定安全组规则版本号和当前最新版本不一致。
UNSUPPORTEDOPERATION_VERSIONMISMATCH = "UnsupportedOperation.VersionMismatch"
// 资源不属于同一个VPC。
UNSUPPORTEDOPERATION_VPCMISMATCH = "UnsupportedOperation.VpcMismatch"
// 指定资源在不同的可用区。
UNSUPPORTEDOPERATION_ZONEMISMATCH = "UnsupportedOperation.ZoneMismatch"
// 已经达到指定区域vpc资源申请数量上限。
VPCLIMITEXCEEDED = "VpcLimitExceeded"
)

View File

@ -0,0 +1,258 @@
/*
Copyright 2021 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 tencentcloud
import (
"fmt"
"regexp"
"strings"
apiv1 "k8s.io/api/core/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/config"
schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework"
)
// TcRef contains a reference to some entity in Tencentcloud/TKE world.
type TcRef struct {
ID string
Zone string
}
func (ref TcRef) String() string {
if ref.Zone == "" {
return ref.ID
}
return fmt.Sprintf("%s/%s", ref.Zone, ref.ID)
}
// ToProviderID converts tcRef to string in format used as ProviderId in Node object.
func (ref TcRef) ToProviderID() string {
return fmt.Sprintf("qcloud:///%s/%s", ref.Zone, ref.ID)
}
// TcRefFromProviderID creates InstanceConfig object from provider id which
// must be in format: tencentcloud:///100003/ins-3ven36lk
func TcRefFromProviderID(id string) (TcRef, error) {
validIDRegex := regexp.MustCompile(`^qcloud\:\/\/\/[-0-9a-z]*\/[-0-9a-z]*$`)
if validIDRegex.FindStringSubmatch(id) == nil {
return TcRef{}, fmt.Errorf("valid provider id: expected format qcloud:///zoneid/ins-<name>, got %v", id)
}
splitted := strings.Split(id[10:], "/")
return TcRef{
ID: splitted[1],
}, nil
}
// Asg implements NodeGroup interface.
type Asg interface {
cloudprovider.NodeGroup
TencentcloudRef() TcRef
GetScalingType() string
SetScalingType(string)
}
type tcAsg struct {
tencentcloudRef TcRef
tencentcloudManager TencentcloudManager
minSize int
maxSize int
scalingType string
}
// TencentcloudRef returns ASG's TencentcloudRef
func (asg *tcAsg) TencentcloudRef() TcRef {
return asg.tencentcloudRef
}
// GetScalingType returns ASG's scaling type.
func (asg *tcAsg) GetScalingType() string {
return asg.scalingType
}
// SetScalingType set ASG's scaling type.
func (asg *tcAsg) SetScalingType(scalingType string) {
asg.scalingType = scalingType
}
// MaxSize returns maximum size of the node group.
func (asg *tcAsg) MaxSize() int {
return asg.maxSize
}
// MinSize returns minimum size of the node group.
func (asg *tcAsg) 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 Kuberentes.
func (asg *tcAsg) TargetSize() (int, error) {
size, err := asg.tencentcloudManager.GetAsgSize(asg)
return int(size), err
}
// IncreaseSize increases Asg size
func (asg *tcAsg) IncreaseSize(delta int) error {
if delta <= 0 {
return fmt.Errorf("size increase must be positive")
}
size, err := asg.tencentcloudManager.GetAsgSize(asg)
if err != nil {
return err
}
if int(size)+delta > asg.MaxSize() {
return fmt.Errorf("size increase too large - desired:%d max:%d", int(size)+delta, asg.MaxSize())
}
return asg.tencentcloudManager.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 *tcAsg) DecreaseTargetSize(delta int) error {
if delta >= 0 {
return fmt.Errorf("size decrease size must be negative")
}
size, err := asg.tencentcloudManager.GetAsgSize(asg)
if err != nil {
return err
}
if int(size)+delta < asg.MinSize() {
return fmt.Errorf("size increase too small - desired:%d min:%d", int(size)+delta, asg.MaxSize())
}
nodes, err := asg.tencentcloudManager.GetAsgNodes(asg)
if err != nil {
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.tencentcloudManager.SetAsgSize(asg, size+int64(delta))
}
// Belongs returns true if the given node belongs to the NodeGroup.
func (asg *tcAsg) Belongs(node *apiv1.Node) (bool, error) {
if node.Spec.ProviderID == "" {
return false, nil
}
ref, err := TcRefFromProviderID(node.Spec.ProviderID)
if err != nil {
return false, err
}
targetAsg, err := asg.tencentcloudManager.GetAsgForInstance(ref)
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
}
// 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 *tcAsg) Exist() bool {
return true
}
// Create creates the node group on the cloud provider side.
func (asg *tcAsg) Create() (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrAlreadyExist
}
// 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 *tcAsg) Delete() error {
return cloudprovider.ErrNotImplemented
}
// Autoprovisioned returns true if the node group is autoprovisioned.
func (asg *tcAsg) Autoprovisioned() bool {
return false
}
// DeleteNodes deletes the nodes from the group.
func (asg *tcAsg) DeleteNodes(nodes []*apiv1.Node) error {
size, err := asg.tencentcloudManager.GetAsgSize(asg)
if err != nil {
return err
}
if int(size) <= asg.MinSize() {
return fmt.Errorf("min size reached, nodes will not be deleted")
}
refs := make([]TcRef, 0, len(nodes))
for _, node := range nodes {
belongs, err := asg.Belongs(node)
if err != nil {
return err
}
if !belongs {
return fmt.Errorf("%s,%s belongs to a different asg than %s", node.Name, node.Spec.ProviderID, asg.Id())
}
tencentcloudref, err := TcRefFromProviderID(node.Spec.ProviderID)
if err != nil {
return err
}
refs = append(refs, tencentcloudref)
}
return asg.tencentcloudManager.DeleteInstances(refs)
}
// Id returns asg id.
func (asg *tcAsg) Id() string {
return asg.tencentcloudRef.ID
}
// Debug returns a debug string for the Asg.
func (asg *tcAsg) 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 *tcAsg) Nodes() ([]cloudprovider.Instance, error) {
return asg.tencentcloudManager.GetAsgNodes(asg)
}
// TemplateNodeInfo returns a node template for this node group.
func (asg *tcAsg) TemplateNodeInfo() (*schedulerframework.NodeInfo, error) {
node, err := asg.tencentcloudManager.GetAsgTemplateNode(asg)
if err != nil {
return nil, err
}
nodeInfo := schedulerframework.NewNodeInfo()
nodeInfo.SetNode(node)
return nodeInfo, nil
}
// GetOptions returns NodeGroupAutoscalingOptions that should be used for this particular
// NodeGroup. Returning a nil will result in using default options.
func (asg *tcAsg) GetOptions(defaults config.NodeGroupAutoscalingOptions) (*config.NodeGroupAutoscalingOptions, error) {
return nil, nil
}

View File

@ -0,0 +1,369 @@
/*
Copyright 2016 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 tencentcloud
import (
"fmt"
"reflect"
"sync"
"k8s.io/klog/v2"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
as "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/as/v20180419"
)
// TencentcloudCache is used for caching cluster resources state.
//
// It is needed to:
// - keep track of autoscaled ASGs in the cluster,
// - keep track of instances and which ASG they belong to,
// - limit repetitive Tencentcloud API calls.
//
// Cached resources:
// 1) ASG configuration,
// 2) instance->ASG mapping,
// 3) resource limits (self-imposed quotas),
// 4) instance types.
//
// How it works:
// - asgs (1), resource limits (3) and machine types (4) are only stored in this cache,
// not updated by it.
// - instanceRefToAsgRef (2) is based on registered asgs (1). For each asg, its instances
// are fetched from Tencentcloud API using cloudService.
// - instanceRefToAsgRef (2) is NOT updated automatically when asgs field (1) is updated. Calling
// RegenerateInstancesCache is required to sync it with registered asgs.
type TencentcloudCache struct {
cacheMutex sync.RWMutex
// Cache content.
asgs map[TcRef]Asg
instanceRefToAsgRef map[TcRef]TcRef
instancesFromUnknownAsgs map[TcRef]struct{}
asgTargetSizeCache map[TcRef]int64
instanceTypeCache map[TcRef]string
instanceTemplatesCache map[TcRef]*InstanceTemplate
resourceLimiter *cloudprovider.ResourceLimiter
// Service used to refresh cache.
cloudService CloudService
}
// NewTencentcloudCache create a empty TencentcloudCache
func NewTencentcloudCache(service CloudService) *TencentcloudCache {
registry := &TencentcloudCache{
cloudService: service,
asgs: make(map[TcRef]Asg),
instanceRefToAsgRef: make(map[TcRef]TcRef),
instancesFromUnknownAsgs: make(map[TcRef]struct{}),
asgTargetSizeCache: make(map[TcRef]int64),
instanceTypeCache: make(map[TcRef]string),
instanceTemplatesCache: make(map[TcRef]*InstanceTemplate),
}
return registry
}
// RegisterAsg registers asg in Tencentcloud Manager.
func (tc *TencentcloudCache) RegisterAsg(newAsg Asg) bool {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
oldAsg, found := tc.asgs[newAsg.TencentcloudRef()]
if found {
if !reflect.DeepEqual(oldAsg, newAsg) {
tc.asgs[newAsg.TencentcloudRef()] = newAsg
klog.V(4).Infof("Updated Asg %s", newAsg.TencentcloudRef().ID)
return true
}
return false
}
klog.V(1).Infof("Registering %s", newAsg.TencentcloudRef().ID)
tc.asgs[newAsg.TencentcloudRef()] = newAsg
return true
}
// UnregisterAsg returns true if the node group has been removed, and false if it was already missing from cache.
func (tc *TencentcloudCache) UnregisterAsg(toBeRemoved Asg) bool {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
_, found := tc.asgs[toBeRemoved.TencentcloudRef()]
if found {
klog.V(1).Infof("Unregistered Asg %s", toBeRemoved.TencentcloudRef().String())
delete(tc.asgs, toBeRemoved.TencentcloudRef())
tc.removeInstancesForAsgs(toBeRemoved.TencentcloudRef())
return true
}
return false
}
// FindForInstance returns Asg of the given Instance
func (tc *TencentcloudCache) FindForInstance(instanceRef TcRef) (Asg, error) {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
if asgRef, found := tc.instanceRefToAsgRef[instanceRef]; found {
asg, found := tc.getAsgNoLock(asgRef)
if !found {
return nil, nil
}
return asg, nil
} else if _, found := tc.instancesFromUnknownAsgs[instanceRef]; found {
return nil, nil
}
asgRef, err := tc.cloudService.GetAsgRefByInstanceRef(instanceRef)
if err != nil {
return nil, err
}
tc.instanceRefToAsgRef[instanceRef] = asgRef
asg, found := tc.getAsgNoLock(asgRef)
if !found {
return nil, nil
}
return asg, nil
}
// GetAsgInstanceTemplate returns the cached InstanceTemplate for a Asg TcRef
func (tc *TencentcloudCache) GetAsgInstanceTemplate(ref TcRef) (*InstanceTemplate, bool) {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
instanceTemplate, found := tc.instanceTemplatesCache[ref]
if found {
klog.V(5).Infof("Instance template cache hit for %s", ref)
}
return instanceTemplate, found
}
// SetAsgInstanceTemplate sets InstanceTemplate for a Asg TcRef
func (tc *TencentcloudCache) SetAsgInstanceTemplate(ref TcRef, instanceTemplate *InstanceTemplate) {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
tc.instanceTemplatesCache[ref] = instanceTemplate
}
// GetAsgs returns a copy of asgs list.
func (tc *TencentcloudCache) GetAsgs() []Asg {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
asgs := make([]Asg, 0, len(tc.asgs))
for _, asg := range tc.asgs {
asgs = append(asgs, asg)
}
return asgs
}
// GetAsgs returns a copy of asgs list.
func (tc *TencentcloudCache) getAsgRefs() []TcRef {
asgRefs := make([]TcRef, 0, len(tc.asgs))
for asgRef := range tc.asgs {
asgRefs = append(asgRefs, asgRef)
}
return asgRefs
}
// GetInstanceType returns asg instanceType
func (tc *TencentcloudCache) GetInstanceType(ref TcRef) string {
tc.cacheMutex.RLock()
defer tc.cacheMutex.RUnlock()
return tc.instanceTypeCache[ref]
}
// GetAsgTargetSize returns the cached targetSize for a TencentcloudRef
func (tc *TencentcloudCache) GetAsgTargetSize(ref TcRef) (int64, bool) {
tc.cacheMutex.RLock()
defer tc.cacheMutex.RUnlock()
size, found := tc.asgTargetSizeCache[ref]
if found {
klog.V(5).Infof("Target size cache hit for %s", ref)
}
return size, found
}
// SetAsgTargetSize sets targetSize for a TencentcloudRef
func (tc *TencentcloudCache) SetAsgTargetSize(ref TcRef, size int64) {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
tc.asgTargetSizeCache[ref] = size
}
// InvalidateAsgTargetSize clears the target size cache
func (tc *TencentcloudCache) InvalidateAsgTargetSize(ref TcRef) {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
if _, found := tc.asgTargetSizeCache[ref]; found {
klog.V(5).Infof("Target size cache invalidated for %s", ref)
delete(tc.asgTargetSizeCache, ref)
}
}
// InvalidateAllAsgTargetSizes clears the target size cache
func (tc *TencentcloudCache) InvalidateAllAsgTargetSizes() {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
klog.V(5).Infof("Target size cache invalidated")
tc.asgTargetSizeCache = map[TcRef]int64{}
}
func (tc *TencentcloudCache) removeInstancesForAsgs(asgRef TcRef) {
for instanceRef, instanceAsgRef := range tc.instanceRefToAsgRef {
if asgRef == instanceAsgRef {
delete(tc.instanceRefToAsgRef, instanceRef)
}
}
}
func (tc *TencentcloudCache) getAsgNoLock(asgRef TcRef) (asg Asg, found bool) {
asg, found = tc.asgs[asgRef]
return
}
// RegenerateInstanceCacheForAsg triggers instances cache regeneration for single ASG under lock.
func (tc *TencentcloudCache) RegenerateInstanceCacheForAsg(asgRef TcRef) error {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
return tc.regenerateInstanceCacheForAsgNoLock(asgRef)
}
func (tc *TencentcloudCache) regenerateInstanceCacheForAsgNoLock(asgRef TcRef) error {
klog.V(4).Infof("Regenerating ASG information for %s", asgRef.String())
// cleanup old entries
tc.removeInstancesForAsgs(asgRef)
instances, err := tc.cloudService.FetchAsgInstances(asgRef)
if err != nil {
klog.V(4).Infof("Failed ASG info request for %s: %v", asgRef.String(), err)
return err
}
for _, instance := range instances {
instanceRef, err := TcRefFromProviderID(instance.Id)
if err != nil {
return err
}
tc.instanceRefToAsgRef[instanceRef] = asgRef
}
return nil
}
// RegenerateInstancesCache triggers instances cache regeneration under lock.
func (tc *TencentcloudCache) RegenerateInstancesCache() error {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
tc.instanceRefToAsgRef = make(map[TcRef]TcRef)
tc.instancesFromUnknownAsgs = make(map[TcRef]struct{})
for _, asgRef := range tc.getAsgRefs() {
err := tc.regenerateInstanceCacheForAsgNoLock(asgRef)
if err != nil {
return err
}
}
return nil
}
// SetResourceLimiter sets resource limiter.
func (tc *TencentcloudCache) SetResourceLimiter(resourceLimiter *cloudprovider.ResourceLimiter) {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
tc.resourceLimiter = resourceLimiter
}
// GetResourceLimiter returns resource limiter.
func (tc *TencentcloudCache) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
tc.cacheMutex.RLock()
defer tc.cacheMutex.RUnlock()
return tc.resourceLimiter, nil
}
// RegenerateAutoScalingGroupCache add some tencentcloud asg property
func (tc *TencentcloudCache) RegenerateAutoScalingGroupCache() error {
tc.cacheMutex.Lock()
defer tc.cacheMutex.Unlock()
asgIDs := make([]string, 0)
for ref := range tc.asgs {
asgIDs = append(asgIDs, ref.ID)
}
tcAsgs, err := tc.cloudService.GetAutoScalingGroups(asgIDs)
if err != nil {
return err
}
klog.V(5).Infof("input %d asgIDs(%v), return %d asg", len(asgIDs), asgIDs, len(tcAsgs))
asgMap := make(map[string]as.AutoScalingGroup)
ascMap := make(map[string]as.LaunchConfiguration)
asc2Asg := make(map[string]string)
ascs := make([]string, 0)
for _, tcAsg := range tcAsgs {
if tcAsg.AutoScalingGroupId == nil || tcAsg.ServiceSettings == nil ||
tcAsg.ServiceSettings.ScalingMode == nil || tcAsg.LaunchConfigurationId == nil {
return fmt.Errorf("invalid autoscaling group")
}
asgMap[*tcAsg.AutoScalingGroupId] = tcAsg
ascs = append(ascs, *tcAsg.LaunchConfigurationId)
asc2Asg[*tcAsg.LaunchConfigurationId] = *tcAsg.AutoScalingGroupId
}
tcAscs, err := tc.cloudService.GetAutoscalingConfigs(ascs)
if err != nil {
return err
}
for _, tcAsc := range tcAscs {
if tcAsc.InstanceType == nil {
return fmt.Errorf("invalid launch configuration")
}
ascMap[asc2Asg[*tcAsc.LaunchConfigurationId]] = tcAsc
}
// set asg
for _, ref := range tc.getAsgRefs() {
asg := tc.asgs[ref]
tcAsg, exist := asgMap[ref.ID]
if !exist {
klog.Warningf("Cannot get asg(%s) from AS interface", ref.String())
continue
}
asg.SetScalingType(*tcAsg.ServiceSettings.ScalingMode)
tc.asgs[ref] = asg
if asgMap[ref.ID].DesiredCapacity == nil {
klog.Warningf("%s has a invalid desired capacity value", ref.String())
continue
}
tc.asgTargetSizeCache[ref] = *asgMap[ref.ID].DesiredCapacity
tc.instanceTypeCache[ref] = *ascMap[ref.ID].InstanceType
}
return nil
}

View File

@ -0,0 +1,186 @@
/*
Copyright 2021 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 tencentcloud
import (
"fmt"
"io"
"os"
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/utils/errors"
"k8s.io/klog/v2"
)
const (
// ProviderName is the cloud provider name for Tencentcloud
ProviderName = "tencentcloud"
// GPULabel is the label added to nodes with GPU resource.
GPULabel = "cloud.tencent.com/tke-accelerator"
)
var (
availableGPUTypes = map[string]struct{}{
"nvidia-tesla-k80": {},
"nvidia-tesla-p100": {},
"nvidia-tesla-v100": {},
"nvidia-tesla-p4": {},
"nvidia-tesla-t4": {},
}
)
// tencentCloudProvider implements CloudProvider interface.
type tencentCloudProvider struct {
tencentcloudManager TencentcloudManager
resourceLimiter *cloudprovider.ResourceLimiter
}
// BuildTencentCloudProvider builds CloudProvider implementation for Tencentcloud.
func BuildTencentCloudProvider(tencentcloudManager TencentcloudManager, discoveryOpts cloudprovider.NodeGroupDiscoveryOptions, resourceLimiter *cloudprovider.ResourceLimiter) (cloudprovider.CloudProvider, error) {
if discoveryOpts.StaticDiscoverySpecified() {
return buildStaticallyDiscoveringProvider(tencentcloudManager, discoveryOpts.NodeGroupSpecs, resourceLimiter)
}
return nil, fmt.Errorf("failed to build an tencentcloud cloud provider (no node group specs and no node group auto discovery)")
}
func buildStaticallyDiscoveringProvider(tencentcloudManager TencentcloudManager, specs []string, resourceLimiter *cloudprovider.ResourceLimiter) (*tencentCloudProvider, error) {
return &tencentCloudProvider{
tencentcloudManager: tencentcloudManager,
resourceLimiter: resourceLimiter,
}, nil
}
// Cleanup ...
func (tencentcloud *tencentCloudProvider) Cleanup() error {
tencentcloud.tencentcloudManager.Cleanup()
return nil
}
// Name returns name of the cloud provider.
func (tencentcloud *tencentCloudProvider) Name() string {
return ProviderName
}
// NodeGroups returns all node groups configured for this cloud provider.
func (tencentcloud *tencentCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
asgs := tencentcloud.tencentcloudManager.GetAsgs()
result := make([]cloudprovider.NodeGroup, 0, len(asgs))
for _, asg := range asgs {
result = append(result, asg)
}
return result
}
// NodeGroupForNode returns the node group for the given node.
func (tencentcloud *tencentCloudProvider) NodeGroupForNode(node *apiv1.Node) (cloudprovider.NodeGroup, error) {
if node.Spec.ProviderID == "" {
return nil, nil
}
ref, err := TcRefFromProviderID(node.Spec.ProviderID)
if err != nil {
return nil, err
}
asg, err := tencentcloud.tencentcloudManager.GetAsgForInstance(ref)
klog.V(6).Infof("node: %v, asg: %v", ref, asg)
if err != nil {
return nil, err
}
return asg, nil
}
// GPULabel returns the label added to nodes with GPU resource.
func (tencentcloud *tencentCloudProvider) GPULabel() string {
return GPULabel
}
// GetAvailableGPUTypes returns all available GPU types cloud provider supports.
func (tencentcloud *tencentCloudProvider) GetAvailableGPUTypes() map[string]struct{} {
return availableGPUTypes
}
// Pricing returns pricing model for this cloud provider or error if not available.
func (tencentcloud *tencentCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) {
return nil, cloudprovider.ErrNotImplemented
}
// GetAvailableMachineTypes get all machine types that can be requested from the cloud provider.
func (tencentcloud *tencentCloudProvider) 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 (tencentcloud *tencentCloudProvider) 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 (tencentcloud *tencentCloudProvider) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
resourceLimiter, err := tencentcloud.tencentcloudManager.GetResourceLimiter()
if err != nil {
return nil, err
}
if resourceLimiter != nil {
return resourceLimiter, nil
}
return tencentcloud.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 (tencentcloud *tencentCloudProvider) Refresh() error {
klog.V(4).Infof("Refresh loop")
if tencentcloud.tencentcloudManager.GetAsgs() == nil {
return fmt.Errorf("Refresh tencentcloud tencentcloudManager asg is nil")
}
return tencentcloud.tencentcloudManager.Refresh()
}
// BuildTencentcloud returns tencentcloud provider
func BuildTencentcloud(opts config.AutoscalingOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter) cloudprovider.CloudProvider {
var config io.ReadCloser
if opts.CloudConfig != "" {
var err error
config, err = os.Open(opts.CloudConfig)
if err != nil {
klog.Fatalf("Couldn't open cloud provider configuration %s: %#v", opts.CloudConfig, err)
}
defer config.Close()
}
manager, err := CreateTencentcloudManager(config, do, opts.Regional)
if err != nil {
klog.Fatalf("Failed to create Tencentcloud Manager: %v", err)
}
cloudProvider, err := BuildTencentCloudProvider(manager, do, rl)
if err != nil {
klog.Fatalf("Failed to create Tencentcloud cloud provider: %v", err)
}
return cloudProvider
}

View File

@ -0,0 +1,631 @@
/*
Copyright 2016 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 tencentcloud
import (
"encoding/json"
"fmt"
"io"
"math/rand"
"os"
"sync"
"time"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog/v2"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
as "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/as/v20180419"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
cvm "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
tke "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke/v20180525"
vpc "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
"k8s.io/autoscaler/cluster-autoscaler/config/dynamic"
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
)
const (
retryCountStop = 5
intervalTimeStop = 5 * time.Second
tokenExpiredTime = 7200
serviceName = "cluster-autoscaler"
refreshInterval = 1 * time.Minute
scaleToZeroSupported = true
)
// network extended resources
const (
TKERouteENIIP = "tke.cloud.tencent.com/eni-ip"
TKEDirectENI = "tke.cloud.tencent.com/direct-eni"
)
// vcuda resources
const (
VCudaCore = "tencent.com/vcuda-core"
VCudaMemory = "tencent.com/vcuda-memory"
)
// GPUMemoryMap is a coefficient to get gpu extended resources
var (
GPUMemoryMap = map[string]int64{
"GN10X": 32,
"GN10S": 16,
"GN10": 16,
"GN8": 24,
"GN7": 16,
"GN6": 8,
"GN6S": 8,
"GN2": 24,
"GN7vw": 16,
"GC1": 11,
}
)
// TencentcloudManager is handles tencentcloud communication and data caching.
type TencentcloudManager interface {
// Refresh triggers refresh of cached resources.
Refresh() error
// Cleanup cleans up open resources before the cloud provider is destroyed, i.e. go routines etc.
Cleanup() error
RegisterAsg(asg Asg)
// GetAsgs returns list of registered Asgs.
GetAsgs() []Asg
// GetAsgNodes returns Asg nodes.
GetAsgNodes(Asg Asg) ([]cloudprovider.Instance, error)
// GetAsgForInstance returns Asg to which the given instance belongs.
GetAsgForInstance(instance TcRef) (Asg, error)
// GetAsgTemplateNode returns a template node for Asg.
GetAsgTemplateNode(Asg Asg) (*apiv1.Node, error)
// GetResourceLimiter returns resource limiter.
GetResourceLimiter() (*cloudprovider.ResourceLimiter, error)
// GetAsgSize gets Asg size.
GetAsgSize(Asg Asg) (int64, error)
// SetAsgSize sets Asg size.
SetAsgSize(Asg Asg, size int64) error
// DeleteInstances deletes the given instances. All instances must be controlled by the same Asg.
DeleteInstances(instances []TcRef) error
}
type tencentcloudManagerImpl struct {
mutex sync.Mutex
lastRefresh time.Time
cloudService CloudService
cache *TencentcloudCache
regional bool
explicitlyConfigured map[TcRef]bool
interrupt chan struct{}
}
// CloudConfig represent tencentcloud configuration
type CloudConfig struct {
Region string `json:"region"`
RegionName string `json:"regionName"`
Zone string `json:"zone"`
DryRun bool `json:dryRun`
SecretID string
SecretKey string
ClusterID string
IsTest bool
}
// LabelAutoScalingGroupID represents the label of AutoScalingGroup
const LabelAutoScalingGroupID = "cloud.tencent.com/auto-scaling-group-id"
var cloudConfig CloudConfig
func readCloudConfig(configReader io.Reader) error {
if configReader == nil {
return fmt.Errorf("tencentcloud cloud config is not exists")
}
if err := json.NewDecoder(configReader).Decode(&cloudConfig); err != nil {
return err
}
testEnv := os.Getenv("TEST_ENV")
if testEnv == "true" {
cloudConfig.IsTest = true
}
dryRun := os.Getenv("DRY_RUN")
if dryRun == "true" {
cloudConfig.DryRun = true
}
secretID := os.Getenv("SECRET_ID")
secretKey := os.Getenv("SECRET_KEY")
region := os.Getenv("REGION")
regionName := os.Getenv("REGION_NAME")
clusterID := os.Getenv("CLUSTER_ID")
if secretID == "" {
return fmt.Errorf("please specify the environment variable: SECRET_ID")
}
if secretKey == "" {
return fmt.Errorf("please specify the environment variable: SECRET_KEY")
}
if region == "" {
return fmt.Errorf("please specify the environment variable: REGION")
}
if regionName == "" {
return fmt.Errorf("please specify the environment variable: REGION_NAME")
}
if clusterID == "" {
return fmt.Errorf("please specify the environment variable: CLUSTER_ID")
}
cloudConfig.SecretID = secretID
cloudConfig.SecretKey = secretKey
cloudConfig.Region = region
cloudConfig.RegionName = regionName
cloudConfig.ClusterID = clusterID
klog.V(4).Infof("tencentcloud config %+v", cloudConfig)
return nil
}
// CreateTencentcloudManager constructs tencentcloudManager object.
func CreateTencentcloudManager(configReader io.Reader, discoveryOpts cloudprovider.NodeGroupDiscoveryOptions, regional bool) (TencentcloudManager, error) {
err := readCloudConfig(configReader)
if err != nil {
return nil, err
}
credential := common.NewCredential(cloudConfig.SecretID, cloudConfig.SecretKey)
cvmClient, err := cvm.NewClient(credential, cloudConfig.RegionName, newCVMClientProfile())
if err != nil {
return nil, err
}
vpcClient, err := vpc.NewClient(credential, cloudConfig.RegionName, newVPCClientProfile())
if err != nil {
return nil, err
}
asClient, err := as.NewClient(credential, cloudConfig.RegionName, newASClientProfile())
if err != nil {
return nil, err
}
tkeClient, err := tke.NewClient(credential, cloudConfig.RegionName, newTKEClientProfile())
if err != nil {
return nil, err
}
var service CloudService
if cloudConfig.DryRun {
service = NewCloudMockService(cvmClient, vpcClient, asClient, tkeClient)
} else {
service = NewCloudService(cvmClient, vpcClient, asClient, tkeClient)
}
manager := &tencentcloudManagerImpl{
cache: NewTencentcloudCache(service),
cloudService: service,
regional: regional,
interrupt: make(chan struct{}),
explicitlyConfigured: make(map[TcRef]bool),
}
if err := manager.fetchExplicitAsgs(discoveryOpts.NodeGroupSpecs); err != nil {
return nil, fmt.Errorf("failed to fetch ASGs: %v", err)
}
go wait.Until(func() {
if err := manager.cache.RegenerateInstancesCache(); err != nil {
klog.Errorf("Error while regenerating Mig cache: %v", err)
}
}, time.Hour, manager.interrupt)
return manager, nil
}
// Fetch explicitly configured ASGs. These ASGs should never be unregistered
// during refreshes, even if they no longer exist in Tencentcloud.
func (m *tencentcloudManagerImpl) fetchExplicitAsgs(specs []string) error {
changed := false
for _, spec := range specs {
asg, err := m.buildAsgFromFlag(spec)
if err != nil {
return err
}
if m.registerAsg(asg) {
changed = true
}
m.explicitlyConfigured[asg.TencentcloudRef()] = true
}
if changed {
err := m.cache.RegenerateAutoScalingGroupCache()
if err != nil {
return err
}
err = m.cache.RegenerateInstancesCache()
if err != nil {
return err
}
for _, asg := range m.cache.GetAsgs() {
// Try to build a node from template to validate that this group
// can be scaled up from 0 nodes.
// We may never need to do it, so just log error if it fails.
if _, err := m.GetAsgTemplateNode(asg); err != nil {
klog.Errorf("Can't build node from template for %s, won't be able to scale from 0: %v", asg.TencentcloudRef().String(), err)
}
}
}
return nil
}
// GetResourceLimiter() (*cloudprovider.ResourceLimiter, error)
func (m *tencentcloudManagerImpl) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
return m.cache.GetResourceLimiter()
}
// registerAsg registers asg in TencentcloudManager. Returns true if the node group didn't exist before or its config has changed.
func (m *tencentcloudManagerImpl) registerAsg(asg Asg) bool {
return m.cache.RegisterAsg(asg)
}
func (m *tencentcloudManagerImpl) buildAsgFromFlag(flag string) (Asg, error) {
s, err := dynamic.SpecFromString(flag, scaleToZeroSupported)
if err != nil {
return nil, fmt.Errorf("failed to parse node group spec: %v", err)
}
return m.buildAsgFromSpec(s)
}
func (m *tencentcloudManagerImpl) buildAsgFromSpec(s *dynamic.NodeGroupSpec) (Asg, error) {
return &tcAsg{
tencentcloudManager: m,
minSize: s.MinSize,
maxSize: s.MaxSize,
tencentcloudRef: TcRef{
ID: s.Name,
},
}, nil
}
// Refresh triggers refresh of cached resources.
func (m *tencentcloudManagerImpl) Refresh() error {
m.cache.InvalidateAllAsgTargetSizes()
if m.lastRefresh.Add(refreshInterval).After(time.Now()) {
return nil
}
return m.forceRefresh()
}
func (m *tencentcloudManagerImpl) forceRefresh() error {
// TODO refresh
m.lastRefresh = time.Now()
klog.V(2).Infof("Refreshed Tencentcloud resources, next refresh after %v", m.lastRefresh.Add(refreshInterval))
return nil
}
// GetAsgs returns list of registered ASGs.
func (m *tencentcloudManagerImpl) GetAsgs() []Asg {
return m.cache.GetAsgs()
}
// RegisterAsg registers asg in Tencentcloud Manager.
func (m *tencentcloudManagerImpl) RegisterAsg(asg Asg) {
m.cache.RegisterAsg(asg)
}
// GetAsgForInstance returns asg of the given Instance
func (m *tencentcloudManagerImpl) GetAsgForInstance(instance TcRef) (Asg, error) {
return m.cache.FindForInstance(instance)
}
// GetAsgSize gets ASG size.
func (m *tencentcloudManagerImpl) GetAsgSize(asg Asg) (int64, error) {
targetSize, found := m.cache.GetAsgTargetSize(asg.TencentcloudRef())
if found {
return targetSize, nil
}
group, err := m.cloudService.GetAutoScalingGroup(asg.TencentcloudRef())
if err != nil {
return -1, err
}
if group.DesiredCapacity == nil {
return -1, fmt.Errorf("%s invalid desired capacity", asg.Id())
}
m.cache.SetAsgTargetSize(asg.TencentcloudRef(), *group.DesiredCapacity)
return *group.DesiredCapacity, nil
}
// SetAsgSize sets ASG size.
func (m *tencentcloudManagerImpl) SetAsgSize(asg Asg, size int64) error {
klog.V(0).Infof("Setting asg %s size to %d", asg.Id(), size)
err := m.cloudService.ResizeAsg(asg.TencentcloudRef(), uint64(size))
if err != nil {
return err
}
m.cache.SetAsgTargetSize(asg.TencentcloudRef(), size)
return nil
}
// Cleanup ...
func (m *tencentcloudManagerImpl) Cleanup() error {
return nil
}
// DeleteInstances deletes the given instances. All instances must be controlled by the same ASG.
func (m *tencentcloudManagerImpl) DeleteInstances(instances []TcRef) error {
if len(instances) == 0 {
return nil
}
commonAsg, err := m.cache.FindForInstance(instances[0])
if err != nil {
return err
}
toDeleteInstances := make([]string, 0)
for _, instance := range instances {
asg, err := m.cache.FindForInstance(instance)
if err != nil {
return err
}
if asg != commonAsg {
return fmt.Errorf("can not delete instances which don't belong to the same ASG")
}
toDeleteInstances = append(toDeleteInstances, instance.ID)
}
m.cache.InvalidateAsgTargetSize(commonAsg.TencentcloudRef())
m.cache.cloudService.DeleteInstances(commonAsg, toDeleteInstances)
return nil
}
// GetAsgNodes returns Asg nodes.
func (m *tencentcloudManagerImpl) GetAsgNodes(asg Asg) ([]cloudprovider.Instance, error) {
result := make([]cloudprovider.Instance, 0)
instances, err := m.cloudService.GetAutoScalingInstances(asg.TencentcloudRef())
if err != nil {
return result, err
}
for _, instance := range instances {
if instance == nil || instance.LifeCycleState == nil || instance.InstanceId == nil {
continue
}
if *instance.LifeCycleState == "Removing" {
continue
}
instanceRef, err := m.cloudService.GetTencentcloudInstanceRef(instance)
if err != nil {
klog.Warning("failed to get tencentcloud instance ref:", err)
} else if instanceRef.Zone == "" {
klog.V(4).Infof("Skipping %s, that is scheduling by AS", *instance.InstanceId)
} else {
result = append(result, cloudprovider.Instance{Id: instanceRef.ToProviderID()})
}
}
return result, nil
}
// InstanceTemplate represents CVM template
type InstanceTemplate struct {
InstanceType string
Region string
Zone string
Cpu int64
Mem int64
Gpu int64
// gpu虚拟化资源
VCudaCore int64
VCudaMem int64
// vpc-cni的集群eni-ip资源
TKERouteENIIP int64
TKEDirectENI int64
Label map[string]string
Taints []*tke.Taint
}
// NetworkExtendedResources represents network extended resources
type NetworkExtendedResources struct {
TKERouteENIIP int64
TKEDirectENI int64
}
var networkExtendedResourcesMap = make(map[string]*NetworkExtendedResources)
// GetAsgInstanceTemplate returns instance template for Asg with given ref
func (m *tencentcloudManagerImpl) GetAsgInstanceTemplate(asgRef TcRef) (*InstanceTemplate, error) {
m.mutex.Lock()
defer m.mutex.Unlock()
instanceTemplate, found := m.cache.GetAsgInstanceTemplate(asgRef)
if found {
return instanceTemplate, nil
}
getNetworkExtendedResources := func(instanceType string) (*NetworkExtendedResources, error) {
if resources, exist := networkExtendedResourcesMap[instanceType]; exist {
return resources, nil
}
pli, err := m.cloudService.DescribeVpcCniPodLimits(instanceType)
if err != nil {
return nil, err
}
resources := &NetworkExtendedResources{}
if pli != nil {
if pli.PodLimits == nil ||
pli.PodLimits.TKERouteENINonStaticIP == nil ||
pli.PodLimits.TKEDirectENI == nil {
return nil, fmt.Errorf("get wrong eni limits(nil)")
}
resources.TKEDirectENI = *pli.PodLimits.TKEDirectENI
resources.TKERouteENIIP = *pli.PodLimits.TKERouteENINonStaticIP
}
klog.Infof("%v", resources)
networkExtendedResourcesMap[instanceType] = resources
return resources, nil
}
instanceInfo, err := m.cloudService.GetInstanceInfoByType(m.cache.GetInstanceType(asgRef))
if err != nil {
return nil, err
}
npInfo, err := m.cloudService.GetNodePoolInfo(cloudConfig.ClusterID, asgRef.ID)
if err != nil {
return nil, err
}
labels := make(map[string]string)
for _, label := range npInfo.Labels {
if label.Name != nil && label.Value != nil {
labels[*label.Name] = *label.Value
}
}
labels[LabelAutoScalingGroupID] = asgRef.ID
asg, err := m.cloudService.GetAutoScalingGroup(asgRef)
if err != nil {
return nil, err
}
if len(asg.SubnetIdSet) < 1 || asg.SubnetIdSet[0] == nil {
return nil, fmt.Errorf("Failed to get asg zone")
}
zone, err := m.cloudService.GetZoneBySubnetID(*asg.SubnetIdSet[0])
if err != nil {
return nil, err
}
zoneInfo, err := m.cloudService.GetZoneInfo(zone)
if err != nil {
return nil, err
}
// eni
networkExtendedResources, err := getNetworkExtendedResources(instanceInfo.InstanceType)
if err != nil {
return nil, err
}
gpuMult, ok := GPUMemoryMap[instanceInfo.InstanceFamily]
if !ok {
gpuMult = 24
}
vcudaMem := instanceInfo.GPU * gpuMult * 4
instanceTemplate = &InstanceTemplate{
InstanceType: instanceInfo.InstanceType,
Region: cloudConfig.Region,
Zone: *zoneInfo.ZoneId,
Cpu: instanceInfo.CPU,
Mem: instanceInfo.Memory,
Gpu: instanceInfo.GPU,
VCudaCore: instanceInfo.GPU * 100,
VCudaMem: vcudaMem,
TKEDirectENI: networkExtendedResources.TKEDirectENI,
TKERouteENIIP: networkExtendedResources.TKERouteENIIP,
Label: labels,
Taints: npInfo.Taints,
}
m.cache.SetAsgInstanceTemplate(asgRef, instanceTemplate)
return instanceTemplate, nil
}
func (m *tencentcloudManagerImpl) GetAsgTemplateNode(asg Asg) (*apiv1.Node, error) {
template, err := m.GetAsgInstanceTemplate(asg.TencentcloudRef())
if err != nil {
return nil, err
}
node := apiv1.Node{}
nodeName := fmt.Sprintf("%s-%d", asg.TencentcloudRef().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(110, resource.DecimalSI)
node.Status.Capacity[apiv1.ResourceCPU] = *resource.NewQuantity(template.Cpu, resource.DecimalSI)
node.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(template.Mem*1024*1024*1024, resource.DecimalSI)
if template.TKERouteENIIP > 0 {
node.Status.Capacity[TKERouteENIIP] = *resource.NewQuantity(template.TKERouteENIIP, resource.DecimalSI)
}
if template.TKEDirectENI > 0 {
node.Status.Capacity[TKEDirectENI] = *resource.NewQuantity(template.TKEDirectENI, resource.DecimalSI)
}
if template.Gpu > 0 {
node.Status.Capacity[gpu.ResourceNvidiaGPU] = *resource.NewQuantity(template.Gpu, resource.DecimalSI)
node.Status.Capacity[VCudaCore] = *resource.NewQuantity(template.VCudaCore, resource.DecimalSI)
node.Status.Capacity[VCudaMemory] = *resource.NewQuantity(template.VCudaMem, resource.DecimalSI)
klog.Infof("Capacity resource set gpu %s(%d)", gpu.ResourceNvidiaGPU, template.Gpu)
}
// TODO: use proper allocatable!!
node.Status.Allocatable = node.Status.Capacity
node.Labels = cloudprovider.JoinStringMaps(node.Labels, template.Label)
// GenericLabels
node.Labels = cloudprovider.JoinStringMaps(node.Labels, buildGenericLabels(template, nodeName))
node.Spec.Taints = extractTaintsFromAsg(template.Taints)
node.Status.Conditions = cloudprovider.BuildReadyConditions()
return &node, nil
}
func buildGenericLabels(template *InstanceTemplate, nodeName string) map[string]string {
result := make(map[string]string)
// TODO: extract it somehow
result[apiv1.LabelArchStable] = cloudprovider.DefaultArch
result[apiv1.LabelOSStable] = cloudprovider.DefaultOS
result[apiv1.LabelInstanceType] = template.InstanceType
result[apiv1.LabelZoneRegion] = template.Region
result[apiv1.LabelZoneFailureDomain] = template.Zone
result[apiv1.LabelHostname] = nodeName
return result
}
func extractTaintsFromAsg(npTaints []*tke.Taint) []apiv1.Taint {
taints := make([]apiv1.Taint, 0)
for _, npTaint := range npTaints {
if npTaint != nil && npTaint.Key != nil && npTaint.Value != nil && npTaint.Effect != nil {
taints = append(taints, apiv1.Taint{
Key: *npTaint.Key,
Value: *npTaint.Value,
Effect: apiv1.TaintEffect(*npTaint.Effect),
})
}
}
return taints
}

View File

@ -0,0 +1,49 @@
/*
Copyright 2016 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 tencentcloud
import (
as "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/as/v20180419"
cvm "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
tke "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke/v20180525"
vpc "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
"k8s.io/klog/v2"
)
// MockCloudService mock cloud service
type MockCloudService struct {
CloudService
}
// NewCloudMockService creates an instance of caching MockCloudService
func NewCloudMockService(cvmClient *cvm.Client, vpcClient *vpc.Client, asClient *as.Client, tkeClient *tke.Client) CloudService {
return &MockCloudService{
CloudService: NewCloudService(cvmClient, vpcClient, asClient, tkeClient),
}
}
// DeleteInstances remove instances of specified ASG.
func (mcs *MockCloudService) DeleteInstances(asg Asg, instances []string) error {
klog.Infof("Delete Instances %v from %s", instances, asg.TencentcloudRef().String())
return nil
}
// ResizeAsg set the target size of ASG.
func (mcs *MockCloudService) ResizeAsg(ref TcRef, size uint64) error {
klog.Infof("Resize %s to %d", ref.String(), size)
return nil
}

View File

@ -0,0 +1,68 @@
/*
Copyright 2016 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 tencentcloud
import "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
// Tencent Cloud Service Http Endpoint
const (
ASHttpEndpoint = "as.tencentcloudapi.com"
VPCHttpEndpoint = "vpc.tencentcloudapi.com"
CVMHttpEndpoint = "cvm.tencentcloudapi.com"
TKEHttpEndpoint = "tke.tencentcloudapi.com"
TestASHttpEndpoint = "as.test.tencentcloudapi.com"
TestVPCHttpEndpoint = "vpc.test.tencentcloudapi.com"
TestCVMHttpEndpoint = "cvm.test.tencentcloudapi.com"
TestTKEHttpEndpoint = "tke.test.tencentcloudapi.com"
)
func newASClientProfile() *profile.ClientProfile {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = ASHttpEndpoint
if cloudConfig.IsTest {
cpf.HttpProfile.Endpoint = TestASHttpEndpoint
}
return cpf
}
func newVPCClientProfile() *profile.ClientProfile {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = VPCHttpEndpoint
if cloudConfig.IsTest {
cpf.HttpProfile.Endpoint = TestVPCHttpEndpoint
}
return cpf
}
func newCVMClientProfile() *profile.ClientProfile {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = CVMHttpEndpoint
if cloudConfig.IsTest {
cpf.HttpProfile.Endpoint = TestCVMHttpEndpoint
}
return cpf
}
func newTKEClientProfile() *profile.ClientProfile {
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = TKEHttpEndpoint
if cloudConfig.IsTest {
cpf.HttpProfile.Endpoint = TestTKEHttpEndpoint
}
return cpf
}

View File

@ -0,0 +1,773 @@
/*
Copyright 2016 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 tencentcloud
import (
"fmt"
"time"
"k8s.io/klog/v2"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/metrics"
as "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/as/v20180419"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
cvm "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
tke "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke/v20180525"
vpc "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)
const deleteInstanceModeTerminate = "terminate"
// CloudService is used for communicating with Tencentcloud API.
type CloudService interface {
// FetchAsgInstances returns instances of the specified ASG.
FetchAsgInstances(TcRef) ([]cloudprovider.Instance, error)
// DeleteInstances remove instances of specified ASG.
DeleteInstances(Asg, []string) error
// GetAsgRefByInstanceRef returns asgRef according to instanceRef
GetAsgRefByInstanceRef(TcRef) (TcRef, error)
// GetAutoScalingGroups queries and returns a set of ASG.
GetAutoScalingGroups([]string) ([]as.AutoScalingGroup, error)
// GetAutoscalingConfigs queries and returns a set of ASG launchconfiguration.
GetAutoscalingConfigs([]string) ([]as.LaunchConfiguration, error)
// GetAutoScalingGroups queries and returns a set of ASG.
GetAutoScalingGroup(TcRef) (as.AutoScalingGroup, error)
// ResizeAsg set the target size of ASG.
ResizeAsg(TcRef, uint64) error
// GetAutoScalingInstances returns instances of specific ASG.
GetAutoScalingInstances(TcRef) ([]*as.Instance, error)
// GetTencentcloudInstanceRef returns a Tencentcloud ref.
GetTencentcloudInstanceRef(*as.Instance) (TcRef, error)
// DescribeVpcCniPodLimits list network limits
DescribeVpcCniPodLimits(string) (*tke.PodLimitsInstance, error)
// GetInstanceInfoByType queries the number of CPU, memory, and GPU resources of the model configured for generating template
GetInstanceInfoByType(string) (*InstanceInfo, error)
// GetNodePoolInfo returns nodepool information from TKE.
GetNodePoolInfo(string, string) (*NodePoolInfo, error)
// GetZoneBySubnetID return zone by subnetID.
GetZoneBySubnetID(string) (string, error)
// GetZoneInfo invokes cvm.DescribeZones to query zone information.
GetZoneInfo(string) (*cvm.ZoneInfo, error)
}
// CloudServiceImpl provides several utility methods over the auto-scaling cloudService provided by Tencentcloud SDK
type CloudServiceImpl struct {
asClient *as.Client
cvmClient *cvm.Client
tkeClient *tke.Client
vpcClient *vpc.Client
}
const (
maxRecordsReturnedByAPI = 100
)
// CVM stop mode
const (
StoppedModeStopCharging = "STOP_CHARGING"
StoppedModeKeepCharging = "KEEP_CHARGING"
)
// AS scaling mode
const (
ScalingModeClassic = "CLASSIC_SCALING"
ScalingModeWakeUpStopped = "WAKE_UP_STOPPED_SCALING"
)
var zoneInfos = make(map[string]*cvm.ZoneInfo)
// SubnetInfo represents subnet's detail
type SubnetInfo struct {
SubnetID string
Zone string
ZoneID int
}
// NewCloudService creates an instance of caching CloudServiceImpl
func NewCloudService(cvmClient *cvm.Client, vpcClient *vpc.Client, asClient *as.Client, tkeClient *tke.Client) CloudService {
return &CloudServiceImpl{
cvmClient: cvmClient,
vpcClient: vpcClient,
asClient: asClient,
tkeClient: tkeClient,
}
}
// FetchAsgInstances returns instances of the specified ASG.
func (ts *CloudServiceImpl) FetchAsgInstances(asgRef TcRef) ([]cloudprovider.Instance, error) {
tencentcloudInstances, err := ts.GetAutoScalingInstances(asgRef)
if err != nil {
klog.V(4).Infof("Failed ASG info request for %s %s: %v", asgRef.Zone, asgRef.ID, err)
return nil, err
}
infos := []cloudprovider.Instance{}
for _, instance := range tencentcloudInstances {
ref, err := ts.GetTencentcloudInstanceRef(instance)
if err != nil {
return nil, err
}
infos = append(infos, cloudprovider.Instance{
Id: ref.ToProviderID(),
})
}
return infos, nil
}
// DeleteInstances remove instances of specified ASG.
// NOTICE: 一般情况下都是移除一个节点,只有在创建失败时才有批量移除,暂未分页处理
// 如果是关机模式的伸缩组进行关机操作,其它进行移除操作
// 目前执行移除操作走 TKE 接口,需要 cluster 属性,开源时切换为 as 接口
func (ts *CloudServiceImpl) DeleteInstances(asg Asg, instances []string) error {
// TODO 处理缩容保护
if asg.GetScalingType() == ScalingModeWakeUpStopped {
return ts.stopInstances(asg, instances)
}
if ts.tkeClient == nil {
return fmt.Errorf("tkeClient is not initialized")
}
req := tke.NewDeleteClusterInstancesRequest()
req.InstanceIds = common.StringPtrs(instances)
req.ClusterId = &cloudConfig.ClusterID
req.InstanceDeleteMode = common.StringPtr(deleteInstanceModeTerminate)
_, err := ts.tkeClient.DeleteClusterInstances(req)
if err != nil {
if e, ok := err.(*errors.TencentCloudSDKError); ok {
metrics.RegisterCloudAPIInvokedError("tke", "DeleteClusterInstances", e.Code)
}
}
return err
}
// GetAutoscalingConfigs queries and returns a set of ASG launchconfiguration.
func (ts *CloudServiceImpl) GetAutoscalingConfigs(ascs []string) ([]as.LaunchConfiguration, error) {
if ts.asClient == nil {
return nil, fmt.Errorf("asClient is not initialized")
}
if len(ascs) > maxRecordsReturnedByAPI {
klog.Warning("The number of Launch Configuration IDs exceeds 100: ", len(ascs))
}
// 查询AS启动配置对应机型
req := as.NewDescribeLaunchConfigurationsRequest()
req.LaunchConfigurationIds = common.StringPtrs(ascs)
req.Limit = common.Uint64Ptr(maxRecordsReturnedByAPI)
resp, err := ts.asClient.DescribeLaunchConfigurations(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeLaunchConfigurations", err)
if err != nil {
return nil, err
}
if resp == nil || resp.Response == nil ||
resp.Response.LaunchConfigurationSet == nil {
return nil, fmt.Errorf("DescribeLaunchConfigurations returned a invalid response")
}
res := make([]as.LaunchConfiguration, 0)
for _, lc := range resp.Response.LaunchConfigurationSet {
if lc != nil {
res = append(res, *lc)
}
}
if len(res) != len(ascs) {
return nil, fmt.Errorf("DescribeLaunchConfigurations need: %d, real: %d", len(ascs), len(res))
}
return res, nil
}
// InstanceInfo represents CVM's detail
type InstanceInfo struct {
CPU int64
Memory int64
GPU int64
InstanceFamily string
InstanceType string
}
// GetInstanceInfoByType queries the number of CPU, memory, and GPU resources of the model configured for generating template
func (ts *CloudServiceImpl) GetInstanceInfoByType(instanceType string) (*InstanceInfo, error) {
if ts.cvmClient == nil {
return nil, fmt.Errorf("cvmClient is not initialized")
}
// DescribeZoneInstanceConfigInfos
instanceTypeRequest := cvm.NewDescribeInstanceTypeConfigsRequest()
instanceTypeRequest.Filters = []*cvm.Filter{
{
Name: common.StringPtr("instance-type"),
Values: []*string{&instanceType},
},
}
resp, err := ts.cvmClient.DescribeInstanceTypeConfigs(instanceTypeRequest)
metrics.RegisterCloudAPIInvoked("cvm", "DescribeInstanceTypeConfigs", err)
if err != nil {
return nil, err
}
if resp == nil ||
resp.Response == nil ||
resp.Response.InstanceTypeConfigSet == nil ||
len(resp.Response.InstanceTypeConfigSet) < 1 ||
resp.Response.InstanceTypeConfigSet[0].CPU == nil ||
resp.Response.InstanceTypeConfigSet[0].Memory == nil ||
resp.Response.InstanceTypeConfigSet[0].GPU == nil ||
resp.Response.InstanceTypeConfigSet[0].InstanceFamily == nil ||
resp.Response.InstanceTypeConfigSet[0].InstanceType == nil ||
resp.Response.InstanceTypeConfigSet[0].Zone == nil {
return nil, fmt.Errorf("DescribeInstanceTypeConfigs returned a invalid response")
}
return &InstanceInfo{
*resp.Response.InstanceTypeConfigSet[0].CPU,
*resp.Response.InstanceTypeConfigSet[0].Memory,
*resp.Response.InstanceTypeConfigSet[0].GPU,
*resp.Response.InstanceTypeConfigSet[0].InstanceFamily,
*resp.Response.InstanceTypeConfigSet[0].InstanceType,
}, nil
}
// GetAutoScalingGroups queries and returns a set of ASG.
func (ts *CloudServiceImpl) GetAutoScalingGroups(asgIds []string) ([]as.AutoScalingGroup, error) {
if ts.asClient == nil {
return nil, fmt.Errorf("asClient is not initialized")
}
if len(asgIds) > maxRecordsReturnedByAPI {
klog.Warning("The number of ASG IDs exceeds 100: ", len(asgIds))
}
req := as.NewDescribeAutoScalingGroupsRequest()
req.AutoScalingGroupIds = common.StringPtrs(asgIds)
req.Limit = common.Uint64Ptr(maxRecordsReturnedByAPI)
response, err := ts.asClient.DescribeAutoScalingGroups(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeAutoScalingGroups", err)
if err != nil {
return nil, err
}
if response == nil || response.Response == nil || response.Response.AutoScalingGroupSet == nil {
return nil, fmt.Errorf("DescribeAutoScalingGroups returned a invalid response")
}
asgs := make([]as.AutoScalingGroup, 0)
for _, asg := range response.Response.AutoScalingGroupSet {
if asg != nil {
asgs = append(asgs, *asg)
}
}
return asgs, nil
}
// GetAutoScalingGroup returns the specific ASG.
func (ts *CloudServiceImpl) GetAutoScalingGroup(asgRef TcRef) (as.AutoScalingGroup, error) {
if ts.asClient == nil {
return as.AutoScalingGroup{}, fmt.Errorf("asClient is not initialized")
}
req := as.NewDescribeAutoScalingGroupsRequest()
req.AutoScalingGroupIds = []*string{&asgRef.ID}
resp, err := ts.asClient.DescribeAutoScalingGroups(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeAutoScalingGroups", err)
if err != nil {
return as.AutoScalingGroup{}, err
}
if resp == nil || resp.Response == nil || resp.Response.AutoScalingGroupSet == nil ||
len(resp.Response.AutoScalingGroupSet) != 1 || resp.Response.AutoScalingGroupSet[0] == nil {
return as.AutoScalingGroup{}, fmt.Errorf("DescribeAutoScalingGroups returned a invalid response")
}
return *resp.Response.AutoScalingGroupSet[0], nil
}
// GetAutoScalingInstances returns instances of specific ASG.
func (ts *CloudServiceImpl) GetAutoScalingInstances(asgRef TcRef) ([]*as.Instance, error) {
if ts.asClient == nil {
return nil, fmt.Errorf("asClient is not initialized")
}
req := as.NewDescribeAutoScalingInstancesRequest()
filter := as.Filter{
Name: common.StringPtr("auto-scaling-group-id"),
Values: common.StringPtrs([]string{asgRef.ID}),
}
req.Filters = []*as.Filter{&filter}
req.Limit = common.Int64Ptr(maxRecordsReturnedByAPI)
req.Offset = common.Int64Ptr(0)
resp, err := ts.asClient.DescribeAutoScalingInstances(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeAutoScalingInstances", err)
if err != nil {
return nil, err
}
res := resp.Response.AutoScalingInstanceSet
totalCount := uint64(0)
if resp.Response.TotalCount != nil {
totalCount = *resp.Response.TotalCount
}
for uint64(len(res)) < totalCount {
req.Offset = common.Int64Ptr(int64(len(res)))
resp, err = ts.asClient.DescribeAutoScalingInstances(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeAutoScalingInstances", err)
if err != nil {
return nil, err
}
if resp.Response == nil || resp.Response.AutoScalingInstanceSet == nil {
return res, fmt.Errorf("query auto-scaling instances returned incorrect results")
}
if resp.Response.TotalCount != nil {
if totalCount != *resp.Response.TotalCount {
klog.Warningf("%s instance totalCount changed: %d->%d, reset request", totalCount, *resp.Response.TotalCount)
totalCount = *resp.Response.TotalCount
res = []*as.Instance{}
}
}
res = append(res, resp.Response.AutoScalingInstanceSet...)
}
return res, nil
}
// GetAsgRefByInstanceRef returns asgRef according to instanceRef
func (ts *CloudServiceImpl) GetAsgRefByInstanceRef(instanceRef TcRef) (TcRef, error) {
if ts.asClient == nil {
return TcRef{}, fmt.Errorf("asClient is not initialized")
}
req := as.NewDescribeAutoScalingInstancesRequest()
req.InstanceIds = common.StringPtrs([]string{instanceRef.ID})
resp, err := ts.asClient.DescribeAutoScalingInstances(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeAutoScalingInstances", err)
if err != nil {
return TcRef{}, err
}
if resp == nil || resp.Response == nil ||
resp.Response.AutoScalingInstanceSet == nil ||
resp.Response.TotalCount == nil ||
*resp.Response.TotalCount != 1 ||
len(resp.Response.AutoScalingInstanceSet) != 1 {
if *resp.Response.TotalCount == 0 || len(resp.Response.AutoScalingInstanceSet) == 0 {
return TcRef{}, nil
} else if resp.Response.AutoScalingInstanceSet[0] == nil ||
resp.Response.AutoScalingInstanceSet[0].AutoScalingGroupId == nil {
return TcRef{}, fmt.Errorf("DescribeAutoScalingInstances response is invalid by instance %v: %#v", instanceRef, resp)
}
}
return TcRef{
ID: *resp.Response.AutoScalingInstanceSet[0].AutoScalingGroupId,
}, nil
}
// ResizeAsg set the target size of ASG.
func (ts *CloudServiceImpl) ResizeAsg(ref TcRef, size uint64) error {
if ts.asClient == nil {
return fmt.Errorf("asClient is not initialized")
}
req := as.NewModifyAutoScalingGroupRequest()
req.AutoScalingGroupId = common.StringPtr(ref.ID)
req.DesiredCapacity = common.Uint64Ptr(size)
resp, err := ts.asClient.ModifyAutoScalingGroup(req)
metrics.RegisterCloudAPIInvoked("as", "ModifyAutoScalingGroup", err)
if err != nil {
return err
}
if resp == nil || resp.Response == nil ||
resp.Response.RequestId == nil {
return fmt.Errorf("ModifyAutoScalingGroup returned a invalid response")
}
klog.V(4).Infof("ResizeAsg size %d, requestID: %s", size, *resp.Response.RequestId)
return nil
}
// GetZoneBySubnetID 查询子网的所属可用区
func (ts *CloudServiceImpl) GetZoneBySubnetID(subnetID string) (string, error) {
if ts.vpcClient == nil {
return "", fmt.Errorf("vpcClient is not initialized")
}
if ts.cvmClient == nil {
return "", fmt.Errorf("cvmClient is not initialized")
}
req := vpc.NewDescribeSubnetsRequest()
req.SubnetIds = []*string{common.StringPtr(subnetID)}
resp, err := ts.vpcClient.DescribeSubnets(req)
if err != nil {
return "", err
} else if resp.Response == nil || len(resp.Response.SubnetSet) < 1 ||
resp.Response.SubnetSet[0] == nil || resp.Response.SubnetSet[0].Zone == nil {
return "", fmt.Errorf("Failed to invoke DescribeSubnets from vpc, subnetId %v, err: response subenet is nil", subnetID)
}
zone := *resp.Response.SubnetSet[0].Zone
return zone, nil
}
// GetZoneInfo invokes cvm.DescribeZones to query zone information.
// zoneInfo will be cache.
func (ts *CloudServiceImpl) GetZoneInfo(zone string) (*cvm.ZoneInfo, error) {
if zone == "" {
return nil, fmt.Errorf("Param is invalid: zone is empty")
}
if zoneInfo, exist := zoneInfos[zone]; exist {
return zoneInfo, nil
}
req := cvm.NewDescribeZonesRequest()
resp, err := ts.cvmClient.DescribeZones(req)
metrics.RegisterCloudAPIInvoked("cvm", "DescribeZones", err)
if err != nil {
return nil, err
} else if resp.Response == nil || resp.Response.TotalCount == nil || *resp.Response.TotalCount < 1 {
return nil, fmt.Errorf("DescribeZones returns a invalid response")
}
for _, it := range resp.Response.ZoneSet {
if it != nil && it.Zone != nil && *it.Zone == zone {
zoneInfos[zone] = it
return it, nil
}
}
return nil, fmt.Errorf("Failed to get zoneInfo: %s is not exist", zone)
}
// GetTencentcloudInstanceRef returns a Tencentcloud ref.
func (ts *CloudServiceImpl) GetTencentcloudInstanceRef(instance *as.Instance) (TcRef, error) {
if instance == nil {
return TcRef{}, fmt.Errorf("instance is nil")
}
zoneID := ""
if instance.Zone != nil && *instance.Zone != "" {
zoneInfo, err := ts.GetZoneInfo(*instance.Zone)
if err != nil {
return TcRef{}, err
}
zoneID = *zoneInfo.ZoneId
}
return TcRef{
ID: *instance.InstanceId,
Zone: zoneID,
}, nil
}
// NodePoolInfo represents the information nodePool or clusterAsg from dashboard
type NodePoolInfo struct {
Labels []*tke.Label
Taints []*tke.Taint
}
// GetNodePoolInfo returns nodepool information from TKE.
func (ts *CloudServiceImpl) GetNodePoolInfo(clusterID string, asgID string) (*NodePoolInfo, error) {
if ts.tkeClient == nil {
return nil, fmt.Errorf("tkeClient is not initialized")
}
// From NodePool
npReq := tke.NewDescribeClusterNodePoolsRequest()
npReq.ClusterId = common.StringPtr(clusterID)
npResp, err := ts.tkeClient.DescribeClusterNodePools(npReq)
if e, ok := err.(*errors.TencentCloudSDKError); ok {
metrics.RegisterCloudAPIInvokedError("tke", "DescribeClusterNodePools", e.Code)
return nil, e
}
if npResp == nil || npResp.Response == nil || npResp.Response.RequestId == nil {
return nil, errors.NewTencentCloudSDKError("DASHBOARD_ERROR", "empty response", "-")
}
var targetNodePool *tke.NodePool
for _, np := range npResp.Response.NodePoolSet {
if np.AutoscalingGroupId != nil && *np.AutoscalingGroupId == asgID {
targetNodePool = np
break
}
}
if targetNodePool != nil {
return &NodePoolInfo{
Labels: targetNodePool.Labels,
Taints: targetNodePool.Taints,
}, nil
}
// Compatible with DEPRECATED autoScalingGroups
asgReq := tke.NewDescribeClusterAsGroupsRequest()
asgReq.AutoScalingGroupIds = []*string{common.StringPtr(asgID)}
asgReq.ClusterId = common.StringPtr(clusterID)
asgResp, err := ts.tkeClient.DescribeClusterAsGroups(asgReq)
if err != nil {
if e, ok := err.(*errors.TencentCloudSDKError); ok {
metrics.RegisterCloudAPIInvokedError("tke", "DescribeClusterAsGroups", e.Code)
}
return nil, err
}
if asgResp == nil || asgResp.Response == nil {
return nil, errors.NewTencentCloudSDKError("DASHBOARD_ERROR", "empty response", "-")
}
asgCount := len(asgResp.Response.ClusterAsGroupSet)
if asgCount != 1 {
return nil, errors.NewTencentCloudSDKError("UNEXPECTED_ERROR",
fmt.Sprintf("%s get %d autoScalingGroup", asgID, asgCount), *asgResp.Response.RequestId)
}
asg := asgResp.Response.ClusterAsGroupSet[0]
if asg == nil {
return nil, errors.NewTencentCloudSDKError("UNEXPECTED_ERROR", "asg is nil", *asgResp.Response.RequestId)
}
return &NodePoolInfo{
Labels: asg.Labels,
}, nil
}
// DescribeVpcCniPodLimits list network limits
func (ts *CloudServiceImpl) DescribeVpcCniPodLimits(instanceType string) (*tke.PodLimitsInstance, error) {
if ts.tkeClient == nil {
return nil, fmt.Errorf("tkeClient is not initialized")
}
req := tke.NewDescribeVpcCniPodLimitsRequest()
req.InstanceType = common.StringPtr(instanceType)
resp, err := ts.tkeClient.DescribeVpcCniPodLimits(req)
if err != nil {
if e, ok := err.(*errors.TencentCloudSDKError); ok {
metrics.RegisterCloudAPIInvokedError("tke", "DescribeVpcCniPodLimits", e.Code)
}
return nil, err
}
if resp == nil || resp.Response == nil || resp.Response.RequestId == nil {
return nil, errors.NewTencentCloudSDKError("DASHBOARD_ERROR", "empty response", "-")
}
if len(resp.Response.PodLimitsInstanceSet) == 0 {
return nil, nil
}
// PodLimitsInstanceSet 分可用区返回,会存在多组值,不过内容都一样,取第一个
return resp.Response.PodLimitsInstanceSet[0], nil
}
func (ts *CloudServiceImpl) stopAutoScalingInstancesWithRetry(req *as.StopAutoScalingInstancesRequest) error {
var err error
scalingActivityID := ""
for i := 0; i < retryCountStop; i++ {
if i > 0 {
time.Sleep(intervalTimeStop)
}
var resp = &as.StopAutoScalingInstancesResponse{}
resp, err = ts.asClient.StopAutoScalingInstances(req)
metrics.RegisterCloudAPIInvoked("as", "StopAutoScalingInstances", err)
if err != nil {
if asErr, ok := err.(*errors.TencentCloudSDKError); ok {
// 仍然有不支持的
if asErr.Code == "ResourceUnavailable.StoppedInstanceWithInconsistentChargingMode" {
continue
}
}
// 如果错误不是因为机型的原因,就重试
klog.Warningf("StopAutoScalingInstances failed %v, %d retry", err.Error(), i)
} else {
if resp.Response.ActivityId != nil {
scalingActivityID = *resp.Response.ActivityId
}
break
}
}
if err != nil {
return err
}
// check activity
err = ts.ensureAutoScalingActivityDone(scalingActivityID)
if err != nil {
return err
}
return nil
}
// removeInstances invoke as.RemoveInstances
// api document: https://cloud.tencent.com/document/api/377/20431
func (ts *CloudServiceImpl) removeInstances(asg Asg, instances []string) error {
if ts.asClient == nil {
return fmt.Errorf("asClient is not initialized")
}
req := as.NewRemoveInstancesRequest()
req.AutoScalingGroupId = common.StringPtr(asg.Id())
req.InstanceIds = common.StringPtrs(instances)
resp, err := ts.asClient.RemoveInstances(req)
metrics.RegisterCloudAPIInvoked("as", "RemoveInstances", err)
if err != nil {
return err
}
if resp == nil || resp.Response == nil ||
resp.Response.ActivityId == nil ||
resp.Response.RequestId == nil {
return fmt.Errorf("RemoveInstances returned a invalid response")
}
klog.V(4).Infof("Remove instances %v, asaID: %s, requestID: %s", instances, *resp.Response.ActivityId, *resp.Response.RequestId)
return nil
}
// stopInstances 关闭instanceList中符合关机不收费的机型的机器如果不支持的机器就进行关机收费操作
// TODO 注意该方法仅供上层调用instanceList的长度需要上层控制长度最大限制100
func (ts *CloudServiceImpl) stopInstances(asg Asg, instances []string) error {
if ts.asClient == nil {
return fmt.Errorf("asClient is not initialized")
}
req := as.NewStopAutoScalingInstancesRequest()
req.AutoScalingGroupId = common.StringPtr(asg.Id())
req.InstanceIds = common.StringPtrs(instances)
req.StoppedMode = common.StringPtr(StoppedModeStopCharging)
// 没有dry run所以先试跑一次如果超过了就直接超过了
keepChargingIns := make([]string, 0)
stopChargingIns := make([]string, 0)
var errOut error
scalingActivityID := ""
for i := 0; i < retryCountStop; i++ {
// 从第二次开始等待5s钟一般autoscaling移出节点的时间为3s
if i > 0 {
time.Sleep(intervalTimeStop)
}
resp, err := ts.asClient.StopAutoScalingInstances(req)
metrics.RegisterCloudAPIInvoked("as", "StopAutoScalingInstances", err)
if e, ok := err.(*errors.TencentCloudSDKError); ok {
metrics.RegisterCloudAPIInvokedError("as", "StopAutoScalingInstances", e.Code)
}
if err == nil {
// 一次成功
klog.Info("StopAutoScalingInstances succeed")
klog.V(4).Infof("res:%#v", resp.Response)
if resp.Response.ActivityId != nil {
scalingActivityID = *resp.Response.ActivityId
}
break
} else if asErr, ok := err.(*errors.TencentCloudSDKError); ok &&
(asErr.Code == "ResourceUnavailable.StoppedInstanceWithInconsistentChargingMode" ||
asErr.Code == "ResourceUnavailable.InstanceNotSupportStopCharging") { // TODO 这里拿code和msg返回做判断有点危险
stopChargingIns, keepChargingIns = getInstanceIdsFromMessage(instances, asErr.Message)
break
} else {
errOut = err
klog.Warningf("Failed to StopAutoScalingInstances res:%#v", err)
}
}
// 如果是一次就过了说明instance是全部可以关机不收费的直接结束
if errOut == nil && scalingActivityID != "" {
// check activity
err := ts.ensureAutoScalingActivityDone(scalingActivityID)
if err != nil {
return err
}
return nil
} else if errOut != nil {
// 如果一直在报其他的错误,就返回错误
return errOut
}
// 如果有不支持关机不收费的话,就分别执行两次。
// 支持关机不收费的实例,进行`StopCharging`操作
if len(stopChargingIns) != 0 {
req.InstanceIds = common.StringPtrs(stopChargingIns)
req.StoppedMode = common.StringPtr(StoppedModeStopCharging)
err := ts.stopAutoScalingInstancesWithRetry(req)
if err != nil {
errOut = err
}
}
if len(keepChargingIns) != 0 {
// 不支持关机不收费的实例,进行`KeepCharging`操作
req.InstanceIds = common.StringPtrs(keepChargingIns)
req.StoppedMode = common.StringPtr(StoppedModeKeepCharging)
err := ts.stopAutoScalingInstancesWithRetry(req)
if err != nil {
errOut = err
}
}
if errOut != nil {
return errOut
}
return nil
}
func (ts *CloudServiceImpl) ensureAutoScalingActivityDone(scalingActivityID string) error {
if scalingActivityID == "" {
return fmt.Errorf("ActivityId is nil")
}
checker := func(r interface{}, e error) bool {
if e != nil {
return false
}
resp, ok := r.(*as.DescribeAutoScalingActivitiesResponse)
if !ok || resp.Response == nil || len(resp.Response.ActivitySet) != 1 {
return false
}
if resp.Response.ActivitySet[0].StatusCode != nil {
if *resp.Response.ActivitySet[0].StatusCode == "INIT" || *resp.Response.ActivitySet[0].StatusCode == "RUNNING" {
return false
}
return true
}
return true
}
do := func() (interface{}, error) {
if ts.asClient == nil {
return nil, fmt.Errorf("asClient is not initialized")
}
req := as.NewDescribeAutoScalingActivitiesRequest()
req.ActivityIds = common.StringPtrs([]string{scalingActivityID})
resp, err := ts.asClient.DescribeAutoScalingActivities(req)
metrics.RegisterCloudAPIInvoked("as", "DescribeAutoScalingActivities", err)
if err != nil {
return nil, err
}
return resp, nil
}
ret, isTimeout, err := retryDo(do, checker, 1200, 2)
if err != nil {
return fmt.Errorf("EnsureAutoScalingActivityDone scalingActivityId:%s failed:%v", scalingActivityID, err)
}
if isTimeout {
return fmt.Errorf("EnsureAutoScalingActivityDone scalingActivityId:%s timeout", scalingActivityID)
}
resp, ok := ret.(*as.DescribeAutoScalingActivitiesResponse)
if !ok || resp.Response == nil || len(resp.Response.ActivitySet) != 1 {
return fmt.Errorf("EnsureAutoScalingActivityDone scalingActivityId:%s failed", scalingActivityID)
}
if resp.Response.ActivitySet[0].StatusCode != nil && *resp.Response.ActivitySet[0].StatusCode != "SUCCESSFUL" {
if resp.Response.ActivitySet[0].StatusMessageSimplified == nil {
resp.Response.ActivitySet[0].StatusMessageSimplified = common.StringPtr("no message")
}
return fmt.Errorf("AutoScalingActivity scalingActivityId:%s %s %s", scalingActivityID, *resp.Response.ActivitySet[0].StatusCode, *resp.Response.ActivitySet[0].StatusMessageSimplified)
}
return nil
}

View File

@ -0,0 +1,62 @@
/*
Copyright 2016 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 tencentcloud
import (
"regexp"
"time"
)
func getInstanceIdsFromMessage(instances []string, msg string) ([]string, []string) {
errInstance := make([]string, 0)
// 为了防止修改instanceIds中的值
regx := regexp.MustCompile(`ins-([0-9]|[a-z])*`)
res := regx.FindAll([]byte(msg), -1)
for _, r := range res {
errInstance = append(errInstance, string(r))
}
for _, errIns := range errInstance {
for i, okIns := range instances {
if errIns == okIns {
instances = append(instances[:i], instances[i+1:]...)
break
}
}
}
return instances, errInstance
}
func retryDo(op func() (interface{}, error), checker func(interface{}, error) bool, timeout uint64, interval uint64) (ret interface{}, isTimeout bool, err error) {
isTimeout = false
var tm <-chan time.Time = time.After(time.Duration(timeout) * time.Second)
times := 0
for {
times = times + 1
select {
case <-tm:
isTimeout = true
return
default:
}
ret, err = op()
if checker(ret, err) {
return
}
time.Sleep(time.Duration(interval) * time.Second)
}
}

View File

@ -37,6 +37,7 @@ excluded_packages=(
'cluster-autoscaler/cloudprovider/ionoscloud/ionos-cloud-sdk-go'
'cluster-autoscaler/cloudprovider/hetzner/hcloud-go'
'cluster-autoscaler/expander/grpcplugin/protos'
'cluster-autoscaler/cloudprovider/tencentcloud/tencentcloud-sdk-go'
)
FIND_PACKAGES='go list ./... '