[AlibabaCloud] Change alicloud to alibabacloud (#470)
This commit is contained in:
57
README.md
Normal file
57
README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Alibaba Cloud ECI
|
||||
|
||||
<img src="eci.svg" width="200" height="200" />
|
||||
|
||||
Alibaba Cloud ECI(Elastic Container Instance) is a service that allow you run containers without having to manage servers or clusters.
|
||||
|
||||
You can find more infomation via [alibaba cloud ECI web portal](https://www.aliyun.com/product/eci)
|
||||
|
||||
## Alibaba Cloud ECI Virtual-Kubelet Provider
|
||||
Alibaba ECI provider is an adapter to connect between k8s and ECI service to implement pod from k8s cluster on alibaba cloud platform
|
||||
|
||||
## Prerequisites
|
||||
To using ECI service on alibaba cloud, you may need open ECI service on [web portal](https://www.aliyun.com/product/eci), and then the ECI service will be available
|
||||
|
||||
## Deployment of the ECI provider in your cluster
|
||||
configure and launch virtual kubelet
|
||||
```
|
||||
export ECI_REGION=cn-hangzhou
|
||||
export ECI_SECURITY_GROUP=sg-123
|
||||
export ECI_VSWITCH=vsw-123
|
||||
export ECI_ACCESS_KEY=123
|
||||
export ECI_SECRET_KEY=123
|
||||
|
||||
VKUBELET_TAINT_KEY=alibabacloud.com/eci virtual-kubelet --provider alibabacloud
|
||||
```
|
||||
confirm the virtual kubelet is connected to k8s cluster
|
||||
```
|
||||
$kubectl get node
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
cn-shanghai.i-uf69qodr5ntaxleqdhhk Ready <none> 1d v1.9.3
|
||||
virtual-kubelet Ready agent 10s v1.8.3
|
||||
```
|
||||
|
||||
## Schedule K8s Pod to ECI via virtual kubelet
|
||||
You can assign pod to virtual kubelet via node-selector and toleration.
|
||||
```
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
nodeName: virtual-kubelet
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
tolerations:
|
||||
- key: alibabacloud.com/eci
|
||||
operator: "Exists"
|
||||
effect: NoSchedule
|
||||
```
|
||||
|
||||
# Alibaba Cloud Serverless Kubernetes
|
||||
Alibaba Cloud serverless kubernetes allows you to quickly create kubernetes container applications without
|
||||
having to manage and maintain clusters and servers. It is based on ECI and fully compatible with the Kuberentes API.
|
||||
|
||||
You can find more infomation via [alibaba cloud serverless kubernetes product doc](https://www.alibabacloud.com/help/doc-detail/94078.htm)
|
||||
|
||||
56
config.go
Normal file
56
config.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package alibabacloud
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers"
|
||||
)
|
||||
|
||||
type providerConfig struct {
|
||||
Region string
|
||||
OperatingSystem string
|
||||
CPU string
|
||||
Memory string
|
||||
Pods string
|
||||
VSwitch string
|
||||
SecureGroup string
|
||||
ClusterName string
|
||||
}
|
||||
|
||||
func (p *ECIProvider) loadConfig(r io.Reader) error {
|
||||
var config providerConfig
|
||||
if _, err := toml.DecodeReader(r, &config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.region = config.Region
|
||||
if p.region == "" {
|
||||
p.region = "cn-hangzhou"
|
||||
}
|
||||
|
||||
p.vSwitch = config.VSwitch
|
||||
p.secureGroup = config.SecureGroup
|
||||
|
||||
p.cpu = config.CPU
|
||||
if p.cpu == "" {
|
||||
p.cpu = "20"
|
||||
}
|
||||
p.memory = config.Memory
|
||||
if p.memory == "" {
|
||||
p.memory = "100Gi"
|
||||
}
|
||||
p.pods = config.Pods
|
||||
if p.pods == "" {
|
||||
p.pods = "20"
|
||||
}
|
||||
p.operatingSystem = config.OperatingSystem
|
||||
if p.operatingSystem == "" {
|
||||
p.operatingSystem = providers.OperatingSystemLinux
|
||||
}
|
||||
p.clusterName = config.ClusterName
|
||||
if p.clusterName == "" {
|
||||
p.clusterName = "default"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
895
eci.go
Normal file
895
eci.go
Normal file
@@ -0,0 +1,895 @@
|
||||
package alibabacloud
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/cpuguy83/strongerrors"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/log"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/manager"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/alibabacloud/eci"
|
||||
"k8s.io/api/core/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// The service account secret mount path.
|
||||
const serviceAccountSecretMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
|
||||
|
||||
const podTagTimeFormat = "2006-01-02T15-04-05Z"
|
||||
const timeFormat = "2006-01-02T15:04:05Z"
|
||||
|
||||
// ECIProvider implements the virtual-kubelet provider interface and communicates with Alibaba Cloud's ECI APIs.
|
||||
type ECIProvider struct {
|
||||
eciClient *eci.Client
|
||||
resourceManager *manager.ResourceManager
|
||||
resourceGroup string
|
||||
region string
|
||||
nodeName string
|
||||
operatingSystem string
|
||||
clusterName string
|
||||
cpu string
|
||||
memory string
|
||||
pods string
|
||||
internalIP string
|
||||
daemonEndpointPort int32
|
||||
secureGroup string
|
||||
vSwitch string
|
||||
}
|
||||
|
||||
// AuthConfig is the secret returned from an ImageRegistryCredential
|
||||
type AuthConfig struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Auth string `json:"auth,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
ServerAddress string `json:"serveraddress,omitempty"`
|
||||
IdentityToken string `json:"identitytoken,omitempty"`
|
||||
RegistryToken string `json:"registrytoken,omitempty"`
|
||||
}
|
||||
|
||||
var validEciRegions = []string{
|
||||
"cn-hangzhou",
|
||||
"cn-shanghai",
|
||||
"cn-beijing",
|
||||
"us-west-1",
|
||||
}
|
||||
|
||||
// isValidECIRegion checks to make sure we're using a valid ECI region
|
||||
func isValidECIRegion(region string) bool {
|
||||
regionLower := strings.ToLower(region)
|
||||
regionTrimmed := strings.Replace(regionLower, " ", "", -1)
|
||||
|
||||
for _, validRegion := range validEciRegions {
|
||||
if regionTrimmed == validRegion {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// NewECIProvider creates a new ECIProvider.
|
||||
func NewECIProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string, internalIP string, daemonEndpointPort int32) (*ECIProvider, error) {
|
||||
var p ECIProvider
|
||||
var err error
|
||||
|
||||
p.resourceManager = rm
|
||||
|
||||
if config != "" {
|
||||
f, err := os.Open(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := p.loadConfig(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if r := os.Getenv("ECI_CLUSTER_NAME"); r != "" {
|
||||
p.clusterName = r
|
||||
}
|
||||
if p.clusterName == "" {
|
||||
p.clusterName = "default"
|
||||
}
|
||||
if r := os.Getenv("ECI_REGION"); r != "" {
|
||||
p.region = r
|
||||
}
|
||||
if p.region == "" {
|
||||
return nil, errors.New("Region can't be empty please set ECI_REGION\n")
|
||||
}
|
||||
if r := p.region; !isValidECIRegion(r) {
|
||||
unsupportedRegionMessage := fmt.Sprintf("Region %s is invalid. Current supported regions are: %s",
|
||||
r, strings.Join(validEciRegions, ", "))
|
||||
|
||||
return nil, errors.New(unsupportedRegionMessage)
|
||||
}
|
||||
|
||||
var accessKey, secretKey string
|
||||
|
||||
if ak := os.Getenv("ECI_ACCESS_KEY"); ak != "" {
|
||||
accessKey = ak
|
||||
}
|
||||
if sk := os.Getenv("ECI_SECRET_KEY"); sk != "" {
|
||||
secretKey = sk
|
||||
}
|
||||
if sg := os.Getenv("ECI_SECURITY_GROUP"); sg != "" {
|
||||
p.secureGroup = sg
|
||||
}
|
||||
if vsw := os.Getenv("ECI_VSWITCH"); vsw != "" {
|
||||
p.vSwitch = vsw
|
||||
}
|
||||
if p.secureGroup == "" {
|
||||
return nil, errors.New("secureGroup can't be empty\n")
|
||||
}
|
||||
|
||||
if p.vSwitch == "" {
|
||||
return nil, errors.New("vSwitch can't be empty\n")
|
||||
}
|
||||
|
||||
p.eciClient, err = eci.NewClientWithAccessKey(p.region, accessKey, secretKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.cpu = "1000"
|
||||
p.memory = "4Ti"
|
||||
p.pods = "1000"
|
||||
|
||||
if cpuQuota := os.Getenv("ECI_QUOTA_CPU"); cpuQuota != "" {
|
||||
p.cpu = cpuQuota
|
||||
}
|
||||
|
||||
if memoryQuota := os.Getenv("ECI_QUOTA_MEMORY"); memoryQuota != "" {
|
||||
p.memory = memoryQuota
|
||||
}
|
||||
|
||||
if podsQuota := os.Getenv("ECI_QUOTA_POD"); podsQuota != "" {
|
||||
p.pods = podsQuota
|
||||
}
|
||||
|
||||
p.operatingSystem = operatingSystem
|
||||
p.nodeName = nodeName
|
||||
p.internalIP = internalIP
|
||||
p.daemonEndpointPort = daemonEndpointPort
|
||||
return &p, err
|
||||
}
|
||||
|
||||
// CreatePod accepts a Pod definition and creates
|
||||
// an ECI deployment
|
||||
func (p *ECIProvider) CreatePod(ctx context.Context, pod *v1.Pod) error {
|
||||
//Ignore daemonSet Pod
|
||||
if pod != nil && pod.OwnerReferences != nil && len(pod.OwnerReferences) != 0 && pod.OwnerReferences[0].Kind == "DaemonSet" {
|
||||
msg := fmt.Sprintf("Skip to create DaemonSet pod %q", pod.Name)
|
||||
log.G(ctx).WithField("Method", "CreatePod").Info(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
request := eci.CreateCreateContainerGroupRequest()
|
||||
request.RestartPolicy = string(pod.Spec.RestartPolicy)
|
||||
|
||||
// get containers
|
||||
containers, err := p.getContainers(pod, false)
|
||||
initContainers, err := p.getContainers(pod, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get registry creds
|
||||
creds, err := p.getImagePullSecrets(pod)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get volumes
|
||||
volumes, err := p.getVolumes(pod)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// assign all the things
|
||||
request.Containers = containers
|
||||
request.InitContainers = initContainers
|
||||
request.Volumes = volumes
|
||||
request.ImageRegistryCredentials = creds
|
||||
CreationTimestamp := pod.CreationTimestamp.UTC().Format(podTagTimeFormat)
|
||||
tags := []eci.Tag{
|
||||
eci.Tag{Key: "ClusterName", Value: p.clusterName},
|
||||
eci.Tag{Key: "NodeName", Value: p.nodeName},
|
||||
eci.Tag{Key: "NameSpace", Value: pod.Namespace},
|
||||
eci.Tag{Key: "PodName", Value: pod.Name},
|
||||
eci.Tag{Key: "UID", Value: string(pod.UID)},
|
||||
eci.Tag{Key: "CreationTimestamp", Value: CreationTimestamp},
|
||||
}
|
||||
|
||||
ContainerGroupName := containerGroupName(pod)
|
||||
request.Tags = tags
|
||||
request.SecurityGroupId = p.secureGroup
|
||||
request.VSwitchId = p.vSwitch
|
||||
request.ContainerGroupName = ContainerGroupName
|
||||
msg := fmt.Sprintf("CreateContainerGroup request %+v", request)
|
||||
log.G(ctx).WithField("Method", "CreatePod").Info(msg)
|
||||
response, err := p.eciClient.CreateContainerGroup(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg = fmt.Sprintf("CreateContainerGroup successed. %s, %s, %s", response.RequestId, response.ContainerGroupId, ContainerGroupName)
|
||||
log.G(ctx).WithField("Method", "CreatePod").Info(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func containerGroupName(pod *v1.Pod) string {
|
||||
return fmt.Sprintf("%s-%s", pod.Namespace, pod.Name)
|
||||
}
|
||||
|
||||
// UpdatePod is a noop, ECI currently does not support live updates of a pod.
|
||||
func (p *ECIProvider) UpdatePod(ctx context.Context, pod *v1.Pod) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePod deletes the specified pod out of ECI.
|
||||
func (p *ECIProvider) DeletePod(ctx context.Context, pod *v1.Pod) error {
|
||||
eciId := ""
|
||||
for _, cg := range p.GetCgs() {
|
||||
if getECITagValue(&cg, "PodName") == pod.Name && getECITagValue(&cg, "NameSpace") == pod.Namespace {
|
||||
eciId = cg.ContainerGroupId
|
||||
break
|
||||
}
|
||||
}
|
||||
if eciId == "" {
|
||||
return strongerrors.NotFound(fmt.Errorf("DeletePod can't find Pod %s-%s", pod.Namespace, pod.Name))
|
||||
}
|
||||
|
||||
request := eci.CreateDeleteContainerGroupRequest()
|
||||
request.ContainerGroupId = eciId
|
||||
_, err := p.eciClient.DeleteContainerGroup(request)
|
||||
return wrapError(err)
|
||||
}
|
||||
|
||||
// GetPod returns a pod by name that is running inside ECI
|
||||
// returns nil if a pod by that name is not found.
|
||||
func (p *ECIProvider) GetPod(ctx context.Context, namespace, name string) (*v1.Pod, error) {
|
||||
pods, err := p.GetPods(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pod := range pods {
|
||||
if pod.Name == name && pod.Namespace == namespace {
|
||||
return pod, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetContainerLogs returns the logs of a pod by name that is running inside ECI.
|
||||
func (p *ECIProvider) GetContainerLogs(ctx context.Context, namespace, podName, containerName string, tail int) (string, error) {
|
||||
eciId := ""
|
||||
for _, cg := range p.GetCgs() {
|
||||
if getECITagValue(&cg, "PodName") == podName && getECITagValue(&cg, "NameSpace") == namespace {
|
||||
eciId = cg.ContainerGroupId
|
||||
break
|
||||
}
|
||||
}
|
||||
if eciId == "" {
|
||||
return "", errors.New(fmt.Sprintf("GetContainerLogs can't find Pod %s-%s", namespace, podName))
|
||||
}
|
||||
|
||||
request := eci.CreateDescribeContainerLogRequest()
|
||||
request.ContainerGroupId = eciId
|
||||
request.ContainerName = containerName
|
||||
request.Tail = requests.Integer(tail)
|
||||
|
||||
// get logs from cg
|
||||
logContent := ""
|
||||
retry := 10
|
||||
for i := 0; i < retry; i++ {
|
||||
response, err := p.eciClient.DescribeContainerLog(request)
|
||||
if err != nil {
|
||||
msg := fmt.Sprint("Error getting container logs, retrying")
|
||||
log.G(ctx).WithField("Method", "GetContainerLogs").Info(msg)
|
||||
time.Sleep(5000 * time.Millisecond)
|
||||
} else {
|
||||
logContent = response.Content
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return logContent, nil
|
||||
}
|
||||
|
||||
// Get full pod name as defined in the provider context
|
||||
func (p *ECIProvider) GetPodFullName(namespace string, pod string) string {
|
||||
return fmt.Sprintf("%s-%s", namespace, pod)
|
||||
}
|
||||
|
||||
// ExecInContainer executes a command in a container in the pod, copying data
|
||||
// between in/out/err and the container's stdin/stdout/stderr.
|
||||
func (p *ECIProvider) ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, errstream io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPodStatus returns the status of a pod by name that is running inside ECI
|
||||
// returns nil if a pod by that name is not found.
|
||||
func (p *ECIProvider) GetPodStatus(ctx context.Context, namespace, name string) (*v1.PodStatus, error) {
|
||||
pod, err := p.GetPod(ctx, namespace, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pod == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &pod.Status, nil
|
||||
}
|
||||
|
||||
func (p *ECIProvider) GetCgs() []eci.ContainerGroup {
|
||||
cgs := make([]eci.ContainerGroup, 0)
|
||||
request := eci.CreateDescribeContainerGroupsRequest()
|
||||
for {
|
||||
cgsResponse, err := p.eciClient.DescribeContainerGroups(request)
|
||||
if err != nil || len(cgsResponse.ContainerGroups) == 0 {
|
||||
break
|
||||
}
|
||||
request.NextToken = cgsResponse.NextToken
|
||||
|
||||
for _, cg := range cgsResponse.ContainerGroups {
|
||||
if getECITagValue(&cg, "NodeName") != p.nodeName {
|
||||
continue
|
||||
}
|
||||
cn := getECITagValue(&cg, "ClusterName")
|
||||
if cn == "" {
|
||||
cn = "default"
|
||||
}
|
||||
if cn != p.clusterName {
|
||||
continue
|
||||
}
|
||||
cgs = append(cgs, cg)
|
||||
}
|
||||
if request.NextToken == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
return cgs
|
||||
}
|
||||
|
||||
// GetPods returns a list of all pods known to be running within ECI.
|
||||
func (p *ECIProvider) GetPods(ctx context.Context) ([]*v1.Pod, error) {
|
||||
pods := make([]*v1.Pod, 0)
|
||||
for _, cg := range p.GetCgs() {
|
||||
c := cg
|
||||
pod, err := containerGroupToPod(&c)
|
||||
if err != nil {
|
||||
msg := fmt.Sprint("error converting container group to pod", cg.ContainerGroupId, err)
|
||||
log.G(context.TODO()).WithField("Method", "GetPods").Info(msg)
|
||||
continue
|
||||
}
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
return pods, nil
|
||||
}
|
||||
|
||||
// Capacity returns a resource list containing the capacity limits set for ECI.
|
||||
func (p *ECIProvider) Capacity(ctx context.Context) v1.ResourceList {
|
||||
return v1.ResourceList{
|
||||
"cpu": resource.MustParse(p.cpu),
|
||||
"memory": resource.MustParse(p.memory),
|
||||
"pods": resource.MustParse(p.pods),
|
||||
}
|
||||
}
|
||||
|
||||
// NodeConditions returns a list of conditions (Ready, OutOfDisk, etc), for updates to the node status
|
||||
// within Kubernetes.
|
||||
func (p *ECIProvider) NodeConditions(ctx context.Context) []v1.NodeCondition {
|
||||
// TODO: Make these dynamic and augment with custom ECI specific conditions of interest
|
||||
return []v1.NodeCondition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: v1.ConditionTrue,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletReady",
|
||||
Message: "kubelet is ready.",
|
||||
},
|
||||
{
|
||||
Type: "OutOfDisk",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletHasSufficientDisk",
|
||||
Message: "kubelet has sufficient disk space available",
|
||||
},
|
||||
{
|
||||
Type: "MemoryPressure",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletHasSufficientMemory",
|
||||
Message: "kubelet has sufficient memory available",
|
||||
},
|
||||
{
|
||||
Type: "DiskPressure",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "KubeletHasNoDiskPressure",
|
||||
Message: "kubelet has no disk pressure",
|
||||
},
|
||||
{
|
||||
Type: "NetworkUnavailable",
|
||||
Status: v1.ConditionFalse,
|
||||
LastHeartbeatTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "RouteCreated",
|
||||
Message: "RouteController created a route",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NodeAddresses returns a list of addresses for the node status
|
||||
// within Kubernetes.
|
||||
func (p *ECIProvider) NodeAddresses(ctx context.Context) []v1.NodeAddress {
|
||||
// TODO: Make these dynamic and augment with custom ECI specific conditions of interest
|
||||
return []v1.NodeAddress{
|
||||
{
|
||||
Type: "InternalIP",
|
||||
Address: p.internalIP,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status
|
||||
// within Kubernetes.
|
||||
func (p *ECIProvider) NodeDaemonEndpoints(ctx context.Context) *v1.NodeDaemonEndpoints {
|
||||
return &v1.NodeDaemonEndpoints{
|
||||
KubeletEndpoint: v1.DaemonEndpoint{
|
||||
Port: p.daemonEndpointPort,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OperatingSystem returns the operating system that was provided by the config.
|
||||
func (p *ECIProvider) OperatingSystem() string {
|
||||
return p.operatingSystem
|
||||
}
|
||||
|
||||
func (p *ECIProvider) getImagePullSecrets(pod *v1.Pod) ([]eci.ImageRegistryCredential, error) {
|
||||
ips := make([]eci.ImageRegistryCredential, 0, len(pod.Spec.ImagePullSecrets))
|
||||
for _, ref := range pod.Spec.ImagePullSecrets {
|
||||
secret, err := p.resourceManager.GetSecret(ref.Name, pod.Namespace)
|
||||
if err != nil {
|
||||
return ips, err
|
||||
}
|
||||
if secret == nil {
|
||||
return nil, fmt.Errorf("error getting image pull secret")
|
||||
}
|
||||
// TODO: Check if secret type is v1.SecretTypeDockercfg and use DockerConfigKey instead of hardcoded value
|
||||
// TODO: Check if secret type is v1.SecretTypeDockerConfigJson and use DockerConfigJsonKey to determine if it's in json format
|
||||
// TODO: Return error if it's not one of these two types
|
||||
switch secret.Type {
|
||||
case v1.SecretTypeDockercfg:
|
||||
ips, err = readDockerCfgSecret(secret, ips)
|
||||
case v1.SecretTypeDockerConfigJson:
|
||||
ips, err = readDockerConfigJSONSecret(secret, ips)
|
||||
default:
|
||||
return nil, fmt.Errorf("image pull secret type is not one of kubernetes.io/dockercfg or kubernetes.io/dockerconfigjson")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return ips, err
|
||||
}
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func readDockerCfgSecret(secret *v1.Secret, ips []eci.ImageRegistryCredential) ([]eci.ImageRegistryCredential, error) {
|
||||
var err error
|
||||
var authConfigs map[string]AuthConfig
|
||||
repoData, ok := secret.Data[string(v1.DockerConfigKey)]
|
||||
|
||||
if !ok {
|
||||
return ips, fmt.Errorf("no dockercfg present in secret")
|
||||
}
|
||||
|
||||
err = json.Unmarshal(repoData, &authConfigs)
|
||||
if err != nil {
|
||||
return ips, fmt.Errorf("failed to unmarshal auth config %+v", err)
|
||||
}
|
||||
|
||||
for server, authConfig := range authConfigs {
|
||||
ips = append(ips, eci.ImageRegistryCredential{
|
||||
Password: authConfig.Password,
|
||||
Server: server,
|
||||
UserName: authConfig.Username,
|
||||
})
|
||||
}
|
||||
|
||||
return ips, err
|
||||
}
|
||||
|
||||
func readDockerConfigJSONSecret(secret *v1.Secret, ips []eci.ImageRegistryCredential) ([]eci.ImageRegistryCredential, error) {
|
||||
var err error
|
||||
repoData, ok := secret.Data[string(v1.DockerConfigJsonKey)]
|
||||
|
||||
if !ok {
|
||||
return ips, fmt.Errorf("no dockerconfigjson present in secret")
|
||||
}
|
||||
|
||||
var authConfigs map[string]map[string]AuthConfig
|
||||
|
||||
err = json.Unmarshal(repoData, &authConfigs)
|
||||
if err != nil {
|
||||
return ips, err
|
||||
}
|
||||
|
||||
auths, ok := authConfigs["auths"]
|
||||
|
||||
if !ok {
|
||||
return ips, fmt.Errorf("malformed dockerconfigjson in secret")
|
||||
}
|
||||
|
||||
for server, authConfig := range auths {
|
||||
ips = append(ips, eci.ImageRegistryCredential{
|
||||
Password: authConfig.Password,
|
||||
Server: server,
|
||||
UserName: authConfig.Username,
|
||||
})
|
||||
}
|
||||
|
||||
return ips, err
|
||||
}
|
||||
|
||||
func (p *ECIProvider) getContainers(pod *v1.Pod, init bool) ([]eci.CreateContainer, error) {
|
||||
podContainers := pod.Spec.Containers
|
||||
if init {
|
||||
podContainers = pod.Spec.InitContainers
|
||||
}
|
||||
containers := make([]eci.CreateContainer, 0, len(podContainers))
|
||||
for _, container := range podContainers {
|
||||
c := eci.CreateContainer{
|
||||
Name: container.Name,
|
||||
Image: container.Image,
|
||||
Commands: append(container.Command, container.Args...),
|
||||
Ports: make([]eci.ContainerPort, 0, len(container.Ports)),
|
||||
}
|
||||
|
||||
for _, p := range container.Ports {
|
||||
c.Ports = append(c.Ports, eci.ContainerPort{
|
||||
Port: requests.Integer(strconv.FormatInt(int64(p.ContainerPort), 10)),
|
||||
Protocol: string(p.Protocol),
|
||||
})
|
||||
}
|
||||
|
||||
c.VolumeMounts = make([]eci.VolumeMount, 0, len(container.VolumeMounts))
|
||||
for _, v := range container.VolumeMounts {
|
||||
c.VolumeMounts = append(c.VolumeMounts, eci.VolumeMount{
|
||||
Name: v.Name,
|
||||
MountPath: v.MountPath,
|
||||
ReadOnly: requests.Boolean(strconv.FormatBool(v.ReadOnly)),
|
||||
})
|
||||
}
|
||||
|
||||
c.EnvironmentVars = make([]eci.EnvironmentVar, 0, len(container.Env))
|
||||
for _, e := range container.Env {
|
||||
c.EnvironmentVars = append(c.EnvironmentVars, eci.EnvironmentVar{Key: e.Name, Value: e.Value})
|
||||
}
|
||||
|
||||
cpuRequest := 1.00
|
||||
if _, ok := container.Resources.Requests[v1.ResourceCPU]; ok {
|
||||
cpuRequest = float64(container.Resources.Requests.Cpu().MilliValue()) / 1000.00
|
||||
}
|
||||
|
||||
c.Cpu = requests.Float(fmt.Sprintf("%.3f", cpuRequest))
|
||||
|
||||
memoryRequest := 2.0
|
||||
if _, ok := container.Resources.Requests[v1.ResourceMemory]; ok {
|
||||
memoryRequest = float64(container.Resources.Requests.Memory().Value()) / 1024.0 / 1024.0 / 1024.0
|
||||
}
|
||||
|
||||
c.Memory = requests.Float(fmt.Sprintf("%.3f", memoryRequest))
|
||||
|
||||
c.ImagePullPolicy = string(container.ImagePullPolicy)
|
||||
c.WorkingDir = container.WorkingDir
|
||||
|
||||
containers = append(containers, c)
|
||||
}
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
func (p *ECIProvider) getVolumes(pod *v1.Pod) ([]eci.Volume, error) {
|
||||
volumes := make([]eci.Volume, 0, len(pod.Spec.Volumes))
|
||||
for _, v := range pod.Spec.Volumes {
|
||||
// Handle the case for the EmptyDir.
|
||||
if v.EmptyDir != nil {
|
||||
volumes = append(volumes, eci.Volume{
|
||||
Type: eci.VOL_TYPE_EMPTYDIR,
|
||||
Name: v.Name,
|
||||
EmptyDirVolumeEnable: requests.Boolean(strconv.FormatBool(true)),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle the case for the NFS.
|
||||
if v.NFS != nil {
|
||||
volumes = append(volumes, eci.Volume{
|
||||
Type: eci.VOL_TYPE_NFS,
|
||||
Name: v.Name,
|
||||
NfsVolumeServer: v.NFS.Server,
|
||||
NfsVolumePath: v.NFS.Path,
|
||||
NfsVolumeReadOnly: requests.Boolean(strconv.FormatBool(v.NFS.ReadOnly)),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle the case for ConfigMap volume.
|
||||
if v.ConfigMap != nil {
|
||||
ConfigFileToPaths := make([]eci.ConfigFileToPath, 0)
|
||||
configMap, err := p.resourceManager.GetConfigMap(v.ConfigMap.Name, pod.Namespace)
|
||||
if v.ConfigMap.Optional != nil && !*v.ConfigMap.Optional && k8serr.IsNotFound(err) {
|
||||
return nil, fmt.Errorf("ConfigMap %s is required by Pod %s and does not exist", v.ConfigMap.Name, pod.Name)
|
||||
}
|
||||
if configMap == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for k, v := range configMap.Data {
|
||||
var b bytes.Buffer
|
||||
enc := base64.NewEncoder(base64.StdEncoding, &b)
|
||||
enc.Write([]byte(v))
|
||||
|
||||
ConfigFileToPaths = append(ConfigFileToPaths, eci.ConfigFileToPath{Path: k, Content: b.String()})
|
||||
}
|
||||
|
||||
if len(ConfigFileToPaths) != 0 {
|
||||
volumes = append(volumes, eci.Volume{
|
||||
Type: eci.VOL_TYPE_CONFIGFILEVOLUME,
|
||||
Name: v.Name,
|
||||
ConfigFileToPaths: ConfigFileToPaths,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if v.Secret != nil {
|
||||
ConfigFileToPaths := make([]eci.ConfigFileToPath, 0)
|
||||
secret, err := p.resourceManager.GetSecret(v.Secret.SecretName, pod.Namespace)
|
||||
if v.Secret.Optional != nil && !*v.Secret.Optional && k8serr.IsNotFound(err) {
|
||||
return nil, fmt.Errorf("Secret %s is required by Pod %s and does not exist", v.Secret.SecretName, pod.Name)
|
||||
}
|
||||
if secret == nil {
|
||||
continue
|
||||
}
|
||||
for k, v := range secret.Data {
|
||||
var b bytes.Buffer
|
||||
enc := base64.NewEncoder(base64.StdEncoding, &b)
|
||||
enc.Write(v)
|
||||
ConfigFileToPaths = append(ConfigFileToPaths, eci.ConfigFileToPath{Path: k, Content: b.String()})
|
||||
}
|
||||
|
||||
if len(ConfigFileToPaths) != 0 {
|
||||
volumes = append(volumes, eci.Volume{
|
||||
Type: eci.VOL_TYPE_CONFIGFILEVOLUME,
|
||||
Name: v.Name,
|
||||
ConfigFileToPaths: ConfigFileToPaths,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If we've made it this far we have found a volume type that isn't supported
|
||||
return nil, fmt.Errorf("Pod %s requires volume %s which is of an unsupported type\n", pod.Name, v.Name)
|
||||
}
|
||||
|
||||
return volumes, nil
|
||||
}
|
||||
|
||||
func containerGroupToPod(cg *eci.ContainerGroup) (*v1.Pod, error) {
|
||||
var podCreationTimestamp, containerStartTime metav1.Time
|
||||
|
||||
CreationTimestamp := getECITagValue(cg, "CreationTimestamp")
|
||||
if CreationTimestamp != "" {
|
||||
if t, err := time.Parse(podTagTimeFormat, CreationTimestamp); err == nil {
|
||||
podCreationTimestamp = metav1.NewTime(t)
|
||||
}
|
||||
}
|
||||
|
||||
if t, err := time.Parse(timeFormat, cg.Containers[0].CurrentState.StartTime); err == nil {
|
||||
containerStartTime = metav1.NewTime(t)
|
||||
}
|
||||
|
||||
// Use the Provisioning State if it's not Succeeded,
|
||||
// otherwise use the state of the instance.
|
||||
eciState := cg.Status
|
||||
|
||||
containers := make([]v1.Container, 0, len(cg.Containers))
|
||||
containerStatuses := make([]v1.ContainerStatus, 0, len(cg.Containers))
|
||||
for _, c := range cg.Containers {
|
||||
container := v1.Container{
|
||||
Name: c.Name,
|
||||
Image: c.Image,
|
||||
Command: c.Commands,
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse(fmt.Sprintf("%.2f", c.Cpu)),
|
||||
v1.ResourceMemory: resource.MustParse(fmt.Sprintf("%.1fG", c.Memory)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
container.Resources.Limits = v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse(fmt.Sprintf("%.2f", c.Cpu)),
|
||||
v1.ResourceMemory: resource.MustParse(fmt.Sprintf("%.1fG", c.Memory)),
|
||||
}
|
||||
|
||||
containers = append(containers, container)
|
||||
containerStatus := v1.ContainerStatus{
|
||||
Name: c.Name,
|
||||
State: eciContainerStateToContainerState(c.CurrentState),
|
||||
LastTerminationState: eciContainerStateToContainerState(c.PreviousState),
|
||||
Ready: eciStateToPodPhase(c.CurrentState.State) == v1.PodRunning,
|
||||
RestartCount: int32(c.RestartCount),
|
||||
Image: c.Image,
|
||||
ImageID: "",
|
||||
ContainerID: getContainerID(cg.ContainerGroupId, c.Name),
|
||||
}
|
||||
|
||||
// Add to containerStatuses
|
||||
containerStatuses = append(containerStatuses, containerStatus)
|
||||
}
|
||||
|
||||
pod := v1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: getECITagValue(cg, "PodName"),
|
||||
Namespace: getECITagValue(cg, "NameSpace"),
|
||||
ClusterName: getECITagValue(cg, "ClusterName"),
|
||||
UID: types.UID(getECITagValue(cg, "UID")),
|
||||
CreationTimestamp: podCreationTimestamp,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: getECITagValue(cg, "NodeName"),
|
||||
Volumes: []v1.Volume{},
|
||||
Containers: containers,
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
Phase: eciStateToPodPhase(eciState),
|
||||
Conditions: eciStateToPodConditions(eciState, podCreationTimestamp),
|
||||
Message: "",
|
||||
Reason: "",
|
||||
HostIP: "",
|
||||
PodIP: cg.IntranetIp,
|
||||
StartTime: &containerStartTime,
|
||||
ContainerStatuses: containerStatuses,
|
||||
},
|
||||
}
|
||||
|
||||
return &pod, nil
|
||||
}
|
||||
|
||||
func getContainerID(cgID, containerName string) string {
|
||||
if cgID == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
containerResourceID := fmt.Sprintf("%s/containers/%s", cgID, containerName)
|
||||
|
||||
h := sha256.New()
|
||||
h.Write([]byte(strings.ToUpper(containerResourceID)))
|
||||
hashBytes := h.Sum(nil)
|
||||
return fmt.Sprintf("eci://%s", hex.EncodeToString(hashBytes))
|
||||
}
|
||||
|
||||
func eciStateToPodPhase(state string) v1.PodPhase {
|
||||
switch state {
|
||||
case "Scheduling":
|
||||
return v1.PodPending
|
||||
case "ScheduleFailed":
|
||||
return v1.PodFailed
|
||||
case "Pending":
|
||||
return v1.PodPending
|
||||
case "Running":
|
||||
return v1.PodRunning
|
||||
case "Failed":
|
||||
return v1.PodFailed
|
||||
case "Succeeded":
|
||||
return v1.PodSucceeded
|
||||
}
|
||||
return v1.PodUnknown
|
||||
}
|
||||
|
||||
func eciStateToPodConditions(state string, transitionTime metav1.Time) []v1.PodCondition {
|
||||
switch state {
|
||||
case "Running", "Succeeded":
|
||||
return []v1.PodCondition{
|
||||
v1.PodCondition{
|
||||
Type: v1.PodReady,
|
||||
Status: v1.ConditionTrue,
|
||||
LastTransitionTime: transitionTime,
|
||||
}, v1.PodCondition{
|
||||
Type: v1.PodInitialized,
|
||||
Status: v1.ConditionTrue,
|
||||
LastTransitionTime: transitionTime,
|
||||
}, v1.PodCondition{
|
||||
Type: v1.PodScheduled,
|
||||
Status: v1.ConditionTrue,
|
||||
LastTransitionTime: transitionTime,
|
||||
},
|
||||
}
|
||||
}
|
||||
return []v1.PodCondition{}
|
||||
}
|
||||
|
||||
func eciContainerStateToContainerState(cs eci.ContainerState) v1.ContainerState {
|
||||
t1, err := time.Parse(timeFormat, cs.StartTime)
|
||||
if err != nil {
|
||||
return v1.ContainerState{}
|
||||
}
|
||||
|
||||
startTime := metav1.NewTime(t1)
|
||||
|
||||
// Handle the case where the container is running.
|
||||
if cs.State == "Running" || cs.State == "Succeeded" {
|
||||
return v1.ContainerState{
|
||||
Running: &v1.ContainerStateRunning{
|
||||
StartedAt: startTime,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
t2, err := time.Parse(timeFormat, cs.FinishTime)
|
||||
if err != nil {
|
||||
return v1.ContainerState{}
|
||||
}
|
||||
|
||||
finishTime := metav1.NewTime(t2)
|
||||
|
||||
// Handle the case where the container failed.
|
||||
if cs.State == "Failed" || cs.State == "Canceled" {
|
||||
return v1.ContainerState{
|
||||
Terminated: &v1.ContainerStateTerminated{
|
||||
ExitCode: int32(cs.ExitCode),
|
||||
Reason: cs.State,
|
||||
Message: cs.DetailStatus,
|
||||
StartedAt: startTime,
|
||||
FinishedAt: finishTime,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the case where the container is pending.
|
||||
// Which should be all other eci states.
|
||||
return v1.ContainerState{
|
||||
Waiting: &v1.ContainerStateWaiting{
|
||||
Reason: cs.State,
|
||||
Message: cs.DetailStatus,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getECITagValue(cg *eci.ContainerGroup, key string) string {
|
||||
for _, tag := range cg.Tags {
|
||||
if tag.Key == key {
|
||||
return tag.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
16
eci.svg
Normal file
16
eci.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#00C1DE;}
|
||||
</style>
|
||||
<g>
|
||||
<polygon class="st0" points="41.4,22.7 41.4,25 43.7,25.6 43.7,31.8 24,36.3 4.3,31.8 4.3,25.6 6.5,25 6.5,22.7 2,23.7 2,33.7
|
||||
24,38.7 46,33.7 46,23.7 "/>
|
||||
<polygon class="st0" points="38.1,10.6 24,8 9.9,10.6 24,12.9 "/>
|
||||
<polygon class="st0" points="22.8,15.1 8.8,12.6 8.8,30.2 22.8,33.4 "/>
|
||||
<path class="st0" d="M25.2,33.4l14-3.2V12.6l-14,2.5V33.4z M35.2,15.3l2-0.4v13.7l-2,0.5V15.3z M31.3,15.9l2-0.4v13.9l-2,0.5V15.9z
|
||||
M27.5,16.6l2-0.4v14l-2,0.5V16.6z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 878 B |
6
eci.toml
Normal file
6
eci.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
Region = "cn-hangzhou"
|
||||
OperatingSystem = "Linux"
|
||||
CPU = "20"
|
||||
Memory = "100Gi"
|
||||
Pods = "20"
|
||||
ClusterName = "default"
|
||||
81
eci/client.go
Normal file
81
eci/client.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
|
||||
)
|
||||
|
||||
// Client is the sdk client struct, each func corresponds to an OpenAPI
|
||||
type Client struct {
|
||||
sdk.Client
|
||||
}
|
||||
|
||||
// NewClient creates a sdk client with environment variables
|
||||
func NewClient() (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.Init()
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithOptions creates a sdk client with regionId/sdkConfig/credential
|
||||
// this is the common api to create a sdk client
|
||||
func NewClientWithOptions(regionId string, config *sdk.Config, credential auth.Credential) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.InitWithOptions(regionId, config, credential)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithAccessKey is a shortcut to create sdk client with accesskey
|
||||
// usage: https://help.aliyun.com/document_detail/66217.html
|
||||
func NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret string) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.InitWithAccessKey(regionId, accessKeyId, accessKeySecret)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithStsToken is a shortcut to create sdk client with sts token
|
||||
// usage: https://help.aliyun.com/document_detail/66222.html
|
||||
func NewClientWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken string) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.InitWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithRamRoleArn is a shortcut to create sdk client with ram roleArn
|
||||
// usage: https://help.aliyun.com/document_detail/66222.html
|
||||
func NewClientWithRamRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithEcsRamRole is a shortcut to create sdk client with ecs ram role
|
||||
// usage: https://help.aliyun.com/document_detail/66223.html
|
||||
func NewClientWithEcsRamRole(regionId string, roleName string) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.InitWithEcsRamRole(regionId, roleName)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithRsaKeyPair is a shortcut to create sdk client with rsa key pair
|
||||
// attention: rsa key pair auth is only Japan regions available
|
||||
func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, sessionExpiration int) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
err = client.InitWithRsaKeyPair(regionId, publicKeyId, privateKey, sessionExpiration)
|
||||
return
|
||||
}
|
||||
138
eci/create_container_group.go
Normal file
138
eci/create_container_group.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
)
|
||||
|
||||
// CreateContainerGroup invokes the eci.CreateContainerGroup API synchronously
|
||||
// api document: https://help.aliyun.com/api/eci/createcontainergroup.html
|
||||
func (client *Client) CreateContainerGroup(request *CreateContainerGroupRequest) (response *CreateContainerGroupResponse, err error) {
|
||||
response = CreateCreateContainerGroupResponse()
|
||||
err = client.DoAction(request, response)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateContainerGroupWithChan invokes the eci.CreateContainerGroup API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/createcontainergroup.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) CreateContainerGroupWithChan(request *CreateContainerGroupRequest) (<-chan *CreateContainerGroupResponse, <-chan error) {
|
||||
responseChan := make(chan *CreateContainerGroupResponse, 1)
|
||||
errChan := make(chan error, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
defer close(responseChan)
|
||||
defer close(errChan)
|
||||
response, err := client.CreateContainerGroup(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
responseChan <- response
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(responseChan)
|
||||
close(errChan)
|
||||
}
|
||||
return responseChan, errChan
|
||||
}
|
||||
|
||||
// CreateContainerGroupWithCallback invokes the eci.CreateContainerGroup API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/createcontainergroup.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) CreateContainerGroupWithCallback(request *CreateContainerGroupRequest, callback func(response *CreateContainerGroupResponse, err error)) <-chan int {
|
||||
result := make(chan int, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
var response *CreateContainerGroupResponse
|
||||
var err error
|
||||
defer close(result)
|
||||
response, err = client.CreateContainerGroup(request)
|
||||
callback(response, err)
|
||||
result <- 1
|
||||
})
|
||||
if err != nil {
|
||||
defer close(result)
|
||||
callback(nil, err)
|
||||
result <- 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CreateContainerGroupRequest is the request struct for api CreateContainerGroup
|
||||
type CreateContainerGroupRequest struct {
|
||||
*requests.RpcRequest
|
||||
Containers []CreateContainer `position:"Query" name:"Container" type:"Repeated"`
|
||||
InitContainers []CreateContainer `position:"Query" name:"InitContainer" type:"Repeated"`
|
||||
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
|
||||
SecurityGroupId string `position:"Query" name:"SecurityGroupId"`
|
||||
ImageRegistryCredentials []ImageRegistryCredential `position:"Query" name:"ImageRegistryCredential" type:"Repeated"`
|
||||
Tags []Tag `position:"Query" name:"Tag" type:"Repeated"`
|
||||
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
|
||||
RestartPolicy string `position:"Query" name:"RestartPolicy"`
|
||||
OwnerAccount string `position:"Query" name:"OwnerAccount"`
|
||||
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
|
||||
VSwitchId string `position:"Query" name:"VSwitchId"`
|
||||
Volumes []Volume `position:"Query" name:"Volume" type:"Repeated"`
|
||||
ContainerGroupName string `position:"Query" name:"ContainerGroupName"`
|
||||
ZoneId string `position:"Query" name:"ZoneId"`
|
||||
}
|
||||
|
||||
type CreateContainer struct {
|
||||
Name string `name:"Name"`
|
||||
Image string `name:"Image"`
|
||||
Memory requests.Float `name:"Memory"`
|
||||
Cpu requests.Float `name:"Cpu"`
|
||||
WorkingDir string `name:"WorkingDir"`
|
||||
ImagePullPolicy string `name:"ImagePullPolicy"`
|
||||
Commands []string `name:"Command" type:"Repeated"`
|
||||
Args []string `name:"Arg" type:"Repeated"`
|
||||
VolumeMounts []VolumeMount `name:"VolumeMount" type:"Repeated"`
|
||||
Ports []ContainerPort `name:"Port" type:"Repeated"`
|
||||
EnvironmentVars []EnvironmentVar `name:"EnvironmentVar" type:"Repeated"`
|
||||
}
|
||||
|
||||
// CreateContainerGroupImageRegistryCredential is a repeated param struct in CreateContainerGroupRequest
|
||||
type ImageRegistryCredential struct {
|
||||
Server string `name:"Server"`
|
||||
UserName string `name:"UserName"`
|
||||
Password string `name:"Password"`
|
||||
}
|
||||
|
||||
// CreateContainerGroupResponse is the response struct for api CreateContainerGroup
|
||||
type CreateContainerGroupResponse struct {
|
||||
*responses.BaseResponse
|
||||
RequestId string
|
||||
ContainerGroupId string
|
||||
}
|
||||
|
||||
// CreateCreateContainerGroupRequest creates a request to invoke CreateContainerGroup API
|
||||
func CreateCreateContainerGroupRequest() (request *CreateContainerGroupRequest) {
|
||||
request = &CreateContainerGroupRequest{
|
||||
RpcRequest: &requests.RpcRequest{},
|
||||
}
|
||||
request.InitWithApiInfo("Eci", "2018-08-08", "CreateContainerGroup", "eci", "openAPI")
|
||||
return
|
||||
}
|
||||
|
||||
// CreateCreateContainerGroupResponse creates a response to parse from CreateContainerGroup response
|
||||
func CreateCreateContainerGroupResponse() (response *CreateContainerGroupResponse) {
|
||||
response = &CreateContainerGroupResponse{
|
||||
BaseResponse: &responses.BaseResponse{},
|
||||
}
|
||||
return
|
||||
}
|
||||
107
eci/delete_container_group.go
Normal file
107
eci/delete_container_group.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
)
|
||||
|
||||
// DeleteContainerGroup invokes the eci.DeleteContainerGroup API synchronously
|
||||
// api document: https://help.aliyun.com/api/eci/deletecontainergroup.html
|
||||
func (client *Client) DeleteContainerGroup(request *DeleteContainerGroupRequest) (response *DeleteContainerGroupResponse, err error) {
|
||||
response = CreateDeleteContainerGroupResponse()
|
||||
err = client.DoAction(request, response)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteContainerGroupWithChan invokes the eci.DeleteContainerGroup API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/deletecontainergroup.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) DeleteContainerGroupWithChan(request *DeleteContainerGroupRequest) (<-chan *DeleteContainerGroupResponse, <-chan error) {
|
||||
responseChan := make(chan *DeleteContainerGroupResponse, 1)
|
||||
errChan := make(chan error, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
defer close(responseChan)
|
||||
defer close(errChan)
|
||||
response, err := client.DeleteContainerGroup(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
responseChan <- response
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(responseChan)
|
||||
close(errChan)
|
||||
}
|
||||
return responseChan, errChan
|
||||
}
|
||||
|
||||
// DeleteContainerGroupWithCallback invokes the eci.DeleteContainerGroup API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/deletecontainergroup.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) DeleteContainerGroupWithCallback(request *DeleteContainerGroupRequest, callback func(response *DeleteContainerGroupResponse, err error)) <-chan int {
|
||||
result := make(chan int, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
var response *DeleteContainerGroupResponse
|
||||
var err error
|
||||
defer close(result)
|
||||
response, err = client.DeleteContainerGroup(request)
|
||||
callback(response, err)
|
||||
result <- 1
|
||||
})
|
||||
if err != nil {
|
||||
defer close(result)
|
||||
callback(nil, err)
|
||||
result <- 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DeleteContainerGroupRequest is the request struct for api DeleteContainerGroup
|
||||
type DeleteContainerGroupRequest struct {
|
||||
*requests.RpcRequest
|
||||
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
|
||||
ContainerGroupId string `position:"Query" name:"ContainerGroupId"`
|
||||
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
|
||||
OwnerAccount string `position:"Query" name:"OwnerAccount"`
|
||||
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
|
||||
}
|
||||
|
||||
// DeleteContainerGroupResponse is the response struct for api DeleteContainerGroup
|
||||
type DeleteContainerGroupResponse struct {
|
||||
*responses.BaseResponse
|
||||
RequestId string `json:"RequestId" xml:"RequestId"`
|
||||
}
|
||||
|
||||
// CreateDeleteContainerGroupRequest creates a request to invoke DeleteContainerGroup API
|
||||
func CreateDeleteContainerGroupRequest() (request *DeleteContainerGroupRequest) {
|
||||
request = &DeleteContainerGroupRequest{
|
||||
RpcRequest: &requests.RpcRequest{},
|
||||
}
|
||||
request.InitWithApiInfo("Eci", "2018-08-08", "DeleteContainerGroup", "eci", "openAPI")
|
||||
return
|
||||
}
|
||||
|
||||
// CreateDeleteContainerGroupResponse creates a response to parse from DeleteContainerGroup response
|
||||
func CreateDeleteContainerGroupResponse() (response *DeleteContainerGroupResponse) {
|
||||
response = &DeleteContainerGroupResponse{
|
||||
BaseResponse: &responses.BaseResponse{},
|
||||
}
|
||||
return
|
||||
}
|
||||
122
eci/describe_container_groups.go
Normal file
122
eci/describe_container_groups.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
)
|
||||
|
||||
// DescribeContainerGroups invokes the eci.DescribeContainerGroups API synchronously
|
||||
// api document: https://help.aliyun.com/api/eci/describecontainergroups.html
|
||||
func (client *Client) DescribeContainerGroups(request *DescribeContainerGroupsRequest) (response *DescribeContainerGroupsResponse, err error) {
|
||||
response = CreateDescribeContainerGroupsResponse()
|
||||
err = client.DoAction(request, response)
|
||||
return
|
||||
}
|
||||
|
||||
// DescribeContainerGroupsWithChan invokes the eci.DescribeContainerGroups API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/describecontainergroups.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) DescribeContainerGroupsWithChan(request *DescribeContainerGroupsRequest) (<-chan *DescribeContainerGroupsResponse, <-chan error) {
|
||||
responseChan := make(chan *DescribeContainerGroupsResponse, 1)
|
||||
errChan := make(chan error, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
defer close(responseChan)
|
||||
defer close(errChan)
|
||||
response, err := client.DescribeContainerGroups(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
responseChan <- response
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(responseChan)
|
||||
close(errChan)
|
||||
}
|
||||
return responseChan, errChan
|
||||
}
|
||||
|
||||
// DescribeContainerGroupsWithCallback invokes the eci.DescribeContainerGroups API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/describecontainergroups.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) DescribeContainerGroupsWithCallback(request *DescribeContainerGroupsRequest, callback func(response *DescribeContainerGroupsResponse, err error)) <-chan int {
|
||||
result := make(chan int, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
var response *DescribeContainerGroupsResponse
|
||||
var err error
|
||||
defer close(result)
|
||||
response, err = client.DescribeContainerGroups(request)
|
||||
callback(response, err)
|
||||
result <- 1
|
||||
})
|
||||
if err != nil {
|
||||
defer close(result)
|
||||
callback(nil, err)
|
||||
result <- 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DescribeContainerGroupsRequest is the request struct for api DescribeContainerGroups
|
||||
type DescribeContainerGroupsRequest struct {
|
||||
*requests.RpcRequest
|
||||
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
|
||||
NextToken string `position:"Query" name:"NextToken"`
|
||||
Limit requests.Integer `position:"Query" name:"Limit"`
|
||||
Tags *[]DescribeContainerGroupsTag `position:"Query" name:"Tag" type:"Repeated"`
|
||||
ContainerGroupId string `position:"Query" name:"ContainerGroupId"`
|
||||
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
|
||||
OwnerAccount string `position:"Query" name:"OwnerAccount"`
|
||||
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
|
||||
VSwitchId string `position:"Query" name:"VSwitchId"`
|
||||
ContainerGroupName string `position:"Query" name:"ContainerGroupName"`
|
||||
ZoneId string `position:"Query" name:"ZoneId"`
|
||||
}
|
||||
|
||||
// DescribeContainerGroupsTag is a repeated param struct in DescribeContainerGroupsRequest
|
||||
type DescribeContainerGroupsTag struct {
|
||||
Key string `name:"Key"`
|
||||
Value string `name:"Value"`
|
||||
}
|
||||
|
||||
// DescribeContainerGroupsResponse is the response struct for api DescribeContainerGroups
|
||||
type DescribeContainerGroupsResponse struct {
|
||||
*responses.BaseResponse
|
||||
RequestId string `json:"RequestId" xml:"RequestId"`
|
||||
NextToken string `json:"NextToken" xml:"NextToken"`
|
||||
TotalCount int `json:"TotalCount" xml:"TotalCount"`
|
||||
ContainerGroups []ContainerGroup `json:"ContainerGroups" xml:"ContainerGroups"`
|
||||
}
|
||||
|
||||
// CreateDescribeContainerGroupsRequest creates a request to invoke DescribeContainerGroups API
|
||||
func CreateDescribeContainerGroupsRequest() (request *DescribeContainerGroupsRequest) {
|
||||
request = &DescribeContainerGroupsRequest{
|
||||
RpcRequest: &requests.RpcRequest{},
|
||||
}
|
||||
request.InitWithApiInfo("Eci", "2018-08-08", "DescribeContainerGroups", "eci", "openAPI")
|
||||
return
|
||||
}
|
||||
|
||||
// CreateDescribeContainerGroupsResponse creates a response to parse from DescribeContainerGroups response
|
||||
func CreateDescribeContainerGroupsResponse() (response *DescribeContainerGroupsResponse) {
|
||||
response = &DescribeContainerGroupsResponse{
|
||||
BaseResponse: &responses.BaseResponse{},
|
||||
}
|
||||
return
|
||||
}
|
||||
112
eci/describe_container_log.go
Normal file
112
eci/describe_container_log.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
)
|
||||
|
||||
// DescribeContainerLog invokes the eci.DescribeContainerLog API synchronously
|
||||
// api document: https://help.aliyun.com/api/eci/describecontainerlog.html
|
||||
func (client *Client) DescribeContainerLog(request *DescribeContainerLogRequest) (response *DescribeContainerLogResponse, err error) {
|
||||
response = CreateDescribeContainerLogResponse()
|
||||
err = client.DoAction(request, response)
|
||||
return
|
||||
}
|
||||
|
||||
// DescribeContainerLogWithChan invokes the eci.DescribeContainerLog API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/describecontainerlog.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) DescribeContainerLogWithChan(request *DescribeContainerLogRequest) (<-chan *DescribeContainerLogResponse, <-chan error) {
|
||||
responseChan := make(chan *DescribeContainerLogResponse, 1)
|
||||
errChan := make(chan error, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
defer close(responseChan)
|
||||
defer close(errChan)
|
||||
response, err := client.DescribeContainerLog(request)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
} else {
|
||||
responseChan <- response
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
close(responseChan)
|
||||
close(errChan)
|
||||
}
|
||||
return responseChan, errChan
|
||||
}
|
||||
|
||||
// DescribeContainerLogWithCallback invokes the eci.DescribeContainerLog API asynchronously
|
||||
// api document: https://help.aliyun.com/api/eci/describecontainerlog.html
|
||||
// asynchronous document: https://help.aliyun.com/document_detail/66220.html
|
||||
func (client *Client) DescribeContainerLogWithCallback(request *DescribeContainerLogRequest, callback func(response *DescribeContainerLogResponse, err error)) <-chan int {
|
||||
result := make(chan int, 1)
|
||||
err := client.AddAsyncTask(func() {
|
||||
var response *DescribeContainerLogResponse
|
||||
var err error
|
||||
defer close(result)
|
||||
response, err = client.DescribeContainerLog(request)
|
||||
callback(response, err)
|
||||
result <- 1
|
||||
})
|
||||
if err != nil {
|
||||
defer close(result)
|
||||
callback(nil, err)
|
||||
result <- 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DescribeContainerLogRequest is the request struct for api DescribeContainerLog
|
||||
type DescribeContainerLogRequest struct {
|
||||
*requests.RpcRequest
|
||||
ResourceOwnerId requests.Integer `position:"Query" name:"ResourceOwnerId"`
|
||||
ContainerName string `position:"Query" name:"ContainerName"`
|
||||
StartTime string `position:"Query" name:"StartTime"`
|
||||
ContainerGroupId string `position:"Query" name:"ContainerGroupId"`
|
||||
ResourceOwnerAccount string `position:"Query" name:"ResourceOwnerAccount"`
|
||||
Tail requests.Integer `position:"Query" name:"Tail"`
|
||||
OwnerAccount string `position:"Query" name:"OwnerAccount"`
|
||||
OwnerId requests.Integer `position:"Query" name:"OwnerId"`
|
||||
}
|
||||
|
||||
// DescribeContainerLogResponse is the response struct for api DescribeContainerLog
|
||||
type DescribeContainerLogResponse struct {
|
||||
*responses.BaseResponse
|
||||
RequestId string `json:"RequestId" xml:"RequestId"`
|
||||
ContainerName string `json:"ContainerName" xml:"ContainerName"`
|
||||
Content string `json:"Content" xml:"Content"`
|
||||
}
|
||||
|
||||
// CreateDescribeContainerLogRequest creates a request to invoke DescribeContainerLog API
|
||||
func CreateDescribeContainerLogRequest() (request *DescribeContainerLogRequest) {
|
||||
request = &DescribeContainerLogRequest{
|
||||
RpcRequest: &requests.RpcRequest{},
|
||||
}
|
||||
request.InitWithApiInfo("Eci", "2018-08-08", "DescribeContainerLog", "eci", "openAPI")
|
||||
return
|
||||
}
|
||||
|
||||
// CreateDescribeContainerLogResponse creates a response to parse from DescribeContainerLog response
|
||||
func CreateDescribeContainerLogResponse() (response *DescribeContainerLogResponse) {
|
||||
response = &DescribeContainerLogResponse{
|
||||
BaseResponse: &responses.BaseResponse{},
|
||||
}
|
||||
return
|
||||
}
|
||||
22
eci/struct_config_file_to_path.go
Normal file
22
eci/struct_config_file_to_path.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// ConfigFileVolumeConfigFileToPath is a nested struct in eci response
|
||||
type ConfigFileToPath struct {
|
||||
Content string `name:"Content"`
|
||||
Path string `name:"Path"`
|
||||
}
|
||||
34
eci/struct_container.go
Normal file
34
eci/struct_container.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// Container is a nested struct in eci response
|
||||
type Container struct {
|
||||
Name string `json:"Name" xml:"Name" `
|
||||
Image string `json:"Image" xml:"Image"`
|
||||
Memory float64 `json:"Memory" xml:"Memory"`
|
||||
Cpu float64 `json:"Cpu" xml:"Cpu"`
|
||||
RestartCount int `json:"RestartCount" xml:"RestartCount"`
|
||||
WorkingDir string `json:"WorkingDir" xml:"WorkingDir"`
|
||||
ImagePullPolicy string `json:"ImagePullPolicy" xml:"ImagePullPolicy"`
|
||||
Commands []string `json:"Commands" xml:"Commands"`
|
||||
Args []string `json:"Args" xml:"Args"`
|
||||
PreviousState ContainerState `json:"PreviousState" xml:"PreviousState"`
|
||||
CurrentState ContainerState `json:"CurrentState" xml:"CurrentState"`
|
||||
VolumeMounts []VolumeMount `json:"VolumeMounts" xml:"VolumeMounts"`
|
||||
Ports []ContainerPort `json:"Ports" xml:"Ports"`
|
||||
EnvironmentVars []EnvironmentVar `json:"EnvironmentVars" xml:"EnvironmentVars"`
|
||||
}
|
||||
38
eci/struct_container_group.go
Normal file
38
eci/struct_container_group.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// ContainerGroup is a nested struct in eci response
|
||||
type ContainerGroup struct {
|
||||
ContainerGroupId string `json:"ContainerGroupId" xml:"ContainerGroupId"`
|
||||
ContainerGroupName string `json:"ContainerGroupName" xml:"ContainerGroupName"`
|
||||
RegionId string `json:"RegionId" xml:"RegionId"`
|
||||
ZoneId string `json:"ZoneId" xml:"ZoneId"`
|
||||
Memory float64 `json:"Memory" xml:"Memory"`
|
||||
Cpu float64 `json:"Cpu" xml:"Cpu"`
|
||||
VSwitchId string `json:"VSwitchId" xml:"VSwitchId"`
|
||||
SecurityGroupId string `json:"SecurityGroupId" xml:"SecurityGroupId"`
|
||||
RestartPolicy string `json:"RestartPolicy" xml:"RestartPolicy"`
|
||||
IntranetIp string `json:"IntranetIp" xml:"IntranetIp"`
|
||||
Status string `json:"Status" xml:"Status"`
|
||||
InternetIp string `json:"InternetIp" xml:"InternetIp"`
|
||||
CreationTime string `json:"CreationTime" xml:"CreationTime"`
|
||||
SucceededTime string `json:"SucceededTime" xml:"SucceededTime"`
|
||||
Tags []Tag `json:"Tags" xml:"Tags"`
|
||||
Events []Event `json:"Events" xml:"Events"`
|
||||
Containers []Container `json:"Containers" xml:"Containers"`
|
||||
Volumes []Volume `json:"Volumes" xml:"Volumes"`
|
||||
}
|
||||
26
eci/struct_container_port.go
Normal file
26
eci/struct_container_port.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package eci
|
||||
|
||||
import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
)
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// ContainerPort is a nested struct in eci response
|
||||
type ContainerPort struct {
|
||||
Port requests.Integer `name:"Port"`
|
||||
Protocol string `name:"Protocol"`
|
||||
}
|
||||
25
eci/struct_container_state.go
Normal file
25
eci/struct_container_state.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// CurrentState is a nested struct in eci response
|
||||
type ContainerState struct {
|
||||
State string `json:"State" xml:"State"`
|
||||
DetailStatus string `json:"DetailStatus" xml:"DetailStatus"`
|
||||
ExitCode int `json:"ExitCode" xml:"ExitCode"`
|
||||
StartTime string `json:"StartTime" xml:"StartTime"`
|
||||
FinishTime string `json:"FinishTime" xml:"FinishTime"`
|
||||
}
|
||||
22
eci/struct_environment_var.go
Normal file
22
eci/struct_environment_var.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// EnvironmentVar is a nested struct in eci response
|
||||
type EnvironmentVar struct {
|
||||
Key string `name:"Key"`
|
||||
Value string `name:"Value"`
|
||||
}
|
||||
26
eci/struct_event.go
Normal file
26
eci/struct_event.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// Event is a nested struct in eci response
|
||||
type Event struct {
|
||||
Count int `json:"Count" xml:"Count"`
|
||||
Type string `json:"Type" xml:"Type"`
|
||||
Name string `json:"Name" xml:"Name"`
|
||||
Message string `json:"Message" xml:"Message"`
|
||||
FirstTimestamp string `json:"FirstTimestamp" xml:"FirstTimestamp"`
|
||||
LastTimestamp string `json:"LastTimestamp" xml:"LastTimestamp"`
|
||||
}
|
||||
22
eci/struct_tag.go
Normal file
22
eci/struct_tag.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package eci
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// Label is a nested struct in eci response
|
||||
type Tag struct {
|
||||
Key string `name:"Key"`
|
||||
Value string `name:"Value"`
|
||||
}
|
||||
35
eci/struct_volume.go
Normal file
35
eci/struct_volume.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package eci
|
||||
|
||||
import "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// Volume is a nested struct in eci response
|
||||
const (
|
||||
VOL_TYPE_NFS = "NFSVolume"
|
||||
VOL_TYPE_EMPTYDIR = "EmptyDirVolume"
|
||||
VOL_TYPE_CONFIGFILEVOLUME = "ConfigFileVolume"
|
||||
)
|
||||
|
||||
type Volume struct {
|
||||
Type string `name:"Type"`
|
||||
Name string `name:"Name"`
|
||||
NfsVolumePath string `name:"NFSVolume.Path"`
|
||||
NfsVolumeServer string `name:"NFSVolume.Server"`
|
||||
NfsVolumeReadOnly requests.Boolean `name:"NFSVolume.ReadOnly"`
|
||||
EmptyDirVolumeEnable requests.Boolean `name:"EmptyDirVolume.Enable"`
|
||||
ConfigFileToPaths []ConfigFileToPath `name:"ConfigFileVolume.ConfigFileToPath" type:"Repeated"`
|
||||
}
|
||||
25
eci/struct_volume_mount.go
Normal file
25
eci/struct_volume_mount.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package eci
|
||||
|
||||
import "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
|
||||
//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.
|
||||
//
|
||||
// Code generated by Alibaba Cloud SDK Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
// VolumeMount is a nested struct in eci response
|
||||
type VolumeMount struct {
|
||||
MountPath string `name:"MountPath"`
|
||||
ReadOnly requests.Boolean `name:"ReadOnly"`
|
||||
Name string `name:"Name"`
|
||||
}
|
||||
26
errors.go
Normal file
26
errors.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package alibabacloud
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
|
||||
"github.com/cpuguy83/strongerrors"
|
||||
)
|
||||
|
||||
func wrapError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
se, ok := err.(*errors.ServerError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
switch se.HttpStatus() {
|
||||
case http.StatusNotFound:
|
||||
return strongerrors.NotFound(err)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user