Add tencentcloud to list of supported cloud providers
This commit is contained in:
parent
5cf3b9657f
commit
de0588d1f4
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
approvers:
|
||||
# - alphajc
|
||||
reviewers:
|
||||
# - alphajc
|
||||
|
|
@ -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.
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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.
|
||||
|
|
@ -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.com,cvm.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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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:])
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 := §ions{map[string]*section{}}
|
||||
buf, err := openFile(path)
|
||||
if err != nil {
|
||||
return §ions{}, 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 §ions{}, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
currentSectionName := globalSectionName
|
||||
currentSection := §ion{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 = §ion{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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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: "",
|
||||
}
|
||||
}
|
||||
|
|
@ -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: "",
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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", "")
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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"
|
||||
)
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# wrong section name
|
||||
[]
|
||||
invalidKey1 =
|
||||
;wrong section
|
||||
[default
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
app=tencentcloud-sdk-go
|
||||
|
||||
# default
|
||||
[default]
|
||||
key1 = value1
|
||||
key2 = 2
|
||||
|
||||
;section 2
|
||||
[custom]
|
||||
customKey1 = 3.1415
|
||||
customKey2 = true
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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.
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
|
||||
// 无效的路由策略ID(RouteId)。
|
||||
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"
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 ./... '
|
||||
|
|
|
|||
Loading…
Reference in New Issue