mirror of
https://github.com/labring/sealos.git
synced 2026-09-24 15:46:19 +08:00
@@ -24,7 +24,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
install "github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
|
||||
+28
-28
@@ -84,7 +84,7 @@ spec:
|
||||
listKind: BGPConfigurationList
|
||||
plural: bgpconfigurations
|
||||
singular: bgpconfiguration
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -218,7 +218,7 @@ spec:
|
||||
listKind: BGPPeerList
|
||||
plural: bgppeers
|
||||
singular: bgppeer
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -325,7 +325,7 @@ spec:
|
||||
listKind: BlockAffinityList
|
||||
plural: blockaffinities
|
||||
singular: blockaffinity
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -386,7 +386,7 @@ spec:
|
||||
listKind: ClusterInformationList
|
||||
plural: clusterinformations
|
||||
singular: clusterinformation
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -450,7 +450,7 @@ spec:
|
||||
listKind: FelixConfigurationList
|
||||
plural: felixconfigurations
|
||||
singular: felixconfiguration
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -1013,7 +1013,7 @@ spec:
|
||||
listKind: GlobalNetworkPolicyList
|
||||
plural: globalnetworkpolicies
|
||||
singular: globalnetworkpolicy
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -1784,7 +1784,7 @@ spec:
|
||||
listKind: GlobalNetworkSetList
|
||||
plural: globalnetworksets
|
||||
singular: globalnetworkset
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -1837,7 +1837,7 @@ spec:
|
||||
listKind: HostEndpointList
|
||||
plural: hostendpoints
|
||||
singular: hostendpoint
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -1945,7 +1945,7 @@ spec:
|
||||
listKind: IPAMBlockList
|
||||
plural: ipamblocks
|
||||
singular: ipamblock
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -2026,7 +2026,7 @@ spec:
|
||||
listKind: IPAMConfigList
|
||||
plural: ipamconfigs
|
||||
singular: ipamconfig
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -2082,7 +2082,7 @@ spec:
|
||||
listKind: IPAMHandleList
|
||||
plural: ipamhandles
|
||||
singular: ipamhandle
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -2138,7 +2138,7 @@ spec:
|
||||
listKind: IPPoolList
|
||||
plural: ippools
|
||||
singular: ippool
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -2237,7 +2237,7 @@ spec:
|
||||
listKind: KubeControllersConfigurationList
|
||||
plural: kubecontrollersconfigurations
|
||||
singular: kubecontrollersconfiguration
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
@@ -3653,7 +3653,7 @@ spec:
|
||||
configMapKeyRef:
|
||||
name: calico-config
|
||||
key: calico_backend
|
||||
# Cluster type to identify the deployment type
|
||||
# Infra type to identify the deployment type
|
||||
- name: CLUSTER_TYPE
|
||||
value: "k8s,bgp"
|
||||
# Auto-detect the BGP IP address.
|
||||
@@ -3870,7 +3870,7 @@ metadata:
|
||||
|
||||
---
|
||||
|
||||
# This manifest creates a Pod Disruption Budget for Controller to allow K8s Cluster Autoscaler to evict
|
||||
# This manifest creates a Pod Disruption Budget for Controller to allow K8s Infra Autoscaler to evict
|
||||
|
||||
apiVersion: policy/v1beta1
|
||||
kind: PodDisruptionBudget
|
||||
@@ -3941,7 +3941,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: felixconfigurations.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -3955,7 +3955,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: ipamblocks.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -3970,7 +3970,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: blockaffinities.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -3985,7 +3985,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: ipamhandles.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4000,7 +4000,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: ipamconfigs.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4015,7 +4015,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: bgppeers.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4030,7 +4030,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: bgpconfigurations.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4045,7 +4045,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: ippools.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4060,7 +4060,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: hostendpoints.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4075,7 +4075,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: clusterinformations.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4090,7 +4090,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: globalnetworkpolicies.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4105,7 +4105,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: globalnetworksets.crd.projectcalico.org
|
||||
spec:
|
||||
scope: Cluster
|
||||
scope: Infra
|
||||
group: crd.projectcalico.org
|
||||
version: v1
|
||||
names:
|
||||
@@ -4484,7 +4484,7 @@ spec:
|
||||
configMapKeyRef:
|
||||
name: calico-config
|
||||
key: calico_backend
|
||||
# Cluster type to identify the deployment type
|
||||
# Infra type to identify the deployment type
|
||||
- name: CLUSTER_TYPE
|
||||
value: "k8s,bgp"
|
||||
# Auto-detect the BGP IP address.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# infra模块
|
||||
|
||||
根据Clusterfile里的定义去申请IaaS资源,保障IaaS资源与Clusterfile中的定义保持终态一致
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2021 cuisongliu@qq.com.
|
||||
|
||||
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 aliyun
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v2 "github.com/fanux/sealos/pkg/types/v1beta1"
|
||||
)
|
||||
|
||||
const (
|
||||
EnvAccessKey = "ECS_AKID"
|
||||
EnvAccessSecret = "ECS_AKSK"
|
||||
EnvRegion = "ECS_REGION"
|
||||
)
|
||||
|
||||
const (
|
||||
Scheme = "https"
|
||||
IPProtocol = "tcp"
|
||||
APIServerPortRange = "6443/6443"
|
||||
SSHPortRange = "22/22"
|
||||
SourceCidrIP = "0.0.0.0/0"
|
||||
CidrBlock = "172.16.0.0/24"
|
||||
Policy = "accept"
|
||||
DestinationResource = "InstanceType"
|
||||
InstanceChargeType = "PostPaid"
|
||||
InternetChargeType = "PayByTraffic"
|
||||
defaultImageAmdID = "centos_7_9_x64_20G_alibase_20210927.vhd"
|
||||
defaultImageArmID = "anolisos_7_7_arm64_20G_anck_alibase_20211118.vhd"
|
||||
Product = "product"
|
||||
Role = "role"
|
||||
Master = "master"
|
||||
Node = "node"
|
||||
Stopped = "Stopped"
|
||||
AvailableTypeStatus = "WithStock"
|
||||
Bandwidth = "100"
|
||||
AliDomain = "www.sealyun.com/"
|
||||
DefaultRegionID = "cn-shanghai"
|
||||
TryTimes = 10
|
||||
TrySleepTime = time.Second
|
||||
JustGetInstanceInfo = 0
|
||||
)
|
||||
|
||||
type ResourceName string
|
||||
|
||||
const (
|
||||
EipID ResourceName = AliDomain + "EipID"
|
||||
VpcID ResourceName = AliDomain + "VpcID"
|
||||
VSwitchID ResourceName = AliDomain + "VSwitchID"
|
||||
SecurityGroupID ResourceName = AliDomain + "SecurityGroupID"
|
||||
SystemInfo ResourceName = AliDomain + "SystemInfo"
|
||||
ShouldBeDeleteInstancesIDs ResourceName = "ShouldBeDeleteInstancesIDs"
|
||||
)
|
||||
|
||||
func (r ResourceName) Value(status v2.InfraStatus) string {
|
||||
var value string
|
||||
switch r {
|
||||
case EipID:
|
||||
value = status.EIPID
|
||||
case VpcID:
|
||||
value = status.VpcID
|
||||
case VSwitchID:
|
||||
value = status.VSwitchID
|
||||
case SecurityGroupID:
|
||||
value = status.SecurityGroupID
|
||||
case ShouldBeDeleteInstancesIDs:
|
||||
value = status.ShouldBeDeleteInstancesIDs
|
||||
default:
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,522 @@
|
||||
// Copyright © 2021 Alibaba Group Holding 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.
|
||||
|
||||
package aliyun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
v2 "github.com/fanux/sealos/pkg/types/v1beta1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
||||
)
|
||||
|
||||
type Instance struct {
|
||||
CPU int
|
||||
Memory float64
|
||||
InstanceID string
|
||||
PrimaryIPAddress string
|
||||
}
|
||||
|
||||
type EcsManager struct {
|
||||
}
|
||||
|
||||
func (a *AliProvider) RetryEcsRequest(request requests.AcsRequest, response responses.AcsResponse) error {
|
||||
return a.RetryEcsAction(request, response, TryTimes)
|
||||
}
|
||||
|
||||
func (a *AliProvider) RetryEcsAction(request requests.AcsRequest, response responses.AcsResponse, tryTimes int) error {
|
||||
return utils.Retry(tryTimes, TrySleepTime, func() error {
|
||||
err := a.EcsClient.DoAction(request, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (a *AliProvider) RetryEcsInstanceType(request requests.AcsRequest, response responses.AcsResponse, instances []string) error {
|
||||
for i := 0; i < len(instances); i++ {
|
||||
switch req := request.(type) {
|
||||
case *ecs.ModifyInstanceSpecRequest:
|
||||
req.InstanceType = instances[i]
|
||||
case *ecs.RunInstancesRequest:
|
||||
req.InstanceType = instances[i]
|
||||
}
|
||||
err := a.RetryEcsAction(request, response, 4)
|
||||
if err == nil {
|
||||
a.Infra.Spec.Instance.Type = instances[i]
|
||||
logger.Debug("use SystemInfo type: %s", instances[i])
|
||||
break
|
||||
} else if i == len(instances)-1 {
|
||||
return fmt.Errorf("failed to get ecs SystemInfo type, %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) TryGetInstance(request *ecs.DescribeInstancesRequest, response *ecs.DescribeInstancesResponse, expectCount int) error {
|
||||
return utils.Retry(TryTimes, TrySleepTime, func() error {
|
||||
err := a.EcsClient.DoAction(request, response)
|
||||
var ipList []string
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
instances := response.Instances.Instance
|
||||
if expectCount == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(instances) != expectCount {
|
||||
return errors.New("the number of instances is not as expected")
|
||||
}
|
||||
for _, instance := range instances {
|
||||
if instance.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress == "" {
|
||||
return errors.New("PrimaryIpAddress cannt nob be nil")
|
||||
}
|
||||
if len(ipList) != 0 && !utils.NotIn(instance.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress, ipList) {
|
||||
return errors.New("PrimaryIpAddress cannt nob be same")
|
||||
}
|
||||
|
||||
ipList = append(ipList, instance.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (a *AliProvider) InputIPlist(instanceRole string) (ipList []string, err error) {
|
||||
var hosts *v2.Hosts
|
||||
switch instanceRole {
|
||||
case Master:
|
||||
hosts = &a.Infra.Spec.Masters
|
||||
case Node:
|
||||
hosts = a.Infra.Spec.Nodes
|
||||
}
|
||||
if hosts == nil {
|
||||
return nil, err
|
||||
}
|
||||
instances, err := a.GetInstancesInfo(instanceRole, hosts.Count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, instance := range instances {
|
||||
ipList = append(ipList, instance.PrimaryIPAddress)
|
||||
}
|
||||
return ipList, nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) GetInstanceStatus(instanceID string) (instanceStatus string, err error) {
|
||||
request := ecs.CreateDescribeInstanceStatusRequest()
|
||||
request.Scheme = Scheme
|
||||
request.InstanceId = &[]string{instanceID}
|
||||
response := ecs.CreateDescribeInstanceStatusResponse()
|
||||
err = a.RetryEcsRequest(request, response)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get SystemInfo status failed %v , error :%v", instanceID, err)
|
||||
}
|
||||
if len(response.InstanceStatuses.InstanceStatus) == 0 {
|
||||
return "", fmt.Errorf("SystemInfo list is empty")
|
||||
}
|
||||
return response.InstanceStatuses.InstanceStatus[0].Status, nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) PoweroffInstance(instanceID string) error {
|
||||
request := ecs.CreateStopInstancesRequest()
|
||||
request.Scheme = Scheme
|
||||
request.InstanceId = &[]string{instanceID}
|
||||
|
||||
response := ecs.CreateStopInstancesResponse()
|
||||
return a.RetryEcsRequest(request, response)
|
||||
}
|
||||
|
||||
func (a *AliProvider) StartInstance(instanceID string) error {
|
||||
request := ecs.CreateStartInstanceRequest()
|
||||
request.Scheme = Scheme
|
||||
request.InstanceId = instanceID
|
||||
|
||||
response := ecs.CreateStartInstanceResponse()
|
||||
return a.RetryEcsRequest(request, response)
|
||||
}
|
||||
|
||||
func (a *AliProvider) ChangeInstanceType(instanceID, instanceRole string, cpu int, memory float64) error {
|
||||
instanceStatus, err := a.GetInstanceStatus(instanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if instanceStatus != Stopped {
|
||||
err = a.PoweroffInstance(instanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
expectInstanceType, err := a.GetAvailableResource(instanceRole, cpu, memory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request := ecs.CreateModifyInstanceSpecRequest()
|
||||
request.Scheme = Scheme
|
||||
request.InstanceId = instanceID
|
||||
//_, err = d.Client.ModifyInstanceSpec(request)
|
||||
response := ecs.CreateModifyInstanceSpecResponse()
|
||||
err = a.RetryEcsInstanceType(request, response, expectInstanceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return a.StartInstance(instanceID)
|
||||
}
|
||||
|
||||
func (a *AliProvider) GetInstancesInfo(instancesRole string, expectCount int) (instances []Instance, err error) {
|
||||
var count int
|
||||
tag := make(map[string]string)
|
||||
tag[Product] = a.Infra.Name
|
||||
tag[Role] = instancesRole
|
||||
if expectCount == 0 {
|
||||
count = -1
|
||||
} else {
|
||||
count = expectCount
|
||||
}
|
||||
instancesTags := CreateDescribeInstancesTag(tag)
|
||||
request := ecs.CreateDescribeInstancesRequest()
|
||||
request.Scheme = Scheme
|
||||
request.RegionId = a.Infra.Status.RegionID
|
||||
request.VSwitchId = a.Infra.Status.VSwitchID
|
||||
request.SecurityGroupId = a.Infra.Status.SecurityGroupID
|
||||
request.Tag = &instancesTags
|
||||
response := ecs.CreateDescribeInstancesResponse()
|
||||
err = a.TryGetInstance(request, response, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, i := range response.Instances.Instance {
|
||||
instances = append(instances,
|
||||
Instance{
|
||||
CPU: i.Cpu,
|
||||
Memory: float64(i.Memory / 1024),
|
||||
InstanceID: i.InstanceId,
|
||||
PrimaryIPAddress: i.NetworkInterfaces.NetworkInterface[0].PrimaryIpAddress})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a *AliProvider) ReconcileInstances(instanceRole string) error {
|
||||
var hosts *v2.Hosts
|
||||
var instances []Instance
|
||||
var instancesIDs string
|
||||
var IPList []string
|
||||
switch instanceRole {
|
||||
case Master:
|
||||
hosts = &a.Infra.Spec.Masters
|
||||
instancesIDs = a.Infra.Status.MasterIDs
|
||||
if hosts.Count == 0 {
|
||||
return errors.New("master count not set")
|
||||
}
|
||||
case Node:
|
||||
hosts = a.Infra.Spec.Nodes
|
||||
instancesIDs = a.Infra.Status.NodeIDs
|
||||
if hosts == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if hosts == nil {
|
||||
return errors.New("hosts not set")
|
||||
}
|
||||
var err error
|
||||
if instancesIDs != "" {
|
||||
instances, err = a.GetInstancesInfo(instanceRole, JustGetInstanceInfo)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i := hosts.Count; len(instances) < i {
|
||||
err = a.RunInstances(instanceRole, i-len(instances))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ipList, err := a.InputIPlist(instanceRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
IPList = utils.AppendIPList(IPList, ipList)
|
||||
logger.Info("get scale up IP list %v, append iplist %v, host count %s", ipList, IPList, hosts.Count)
|
||||
}
|
||||
|
||||
for _, instance := range instances {
|
||||
if instance.CPU != hosts.CPU || instance.Memory != hosts.Memory {
|
||||
err = a.ChangeInstanceType(instance.InstanceID, instanceRole, hosts.CPU, hosts.Memory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if instanceRole == Master {
|
||||
a.Infra.Status.Masters = IPList
|
||||
} else {
|
||||
a.Infra.Status.Nodes = IPList
|
||||
}
|
||||
logger.Info("reconcile %s instances success %v ", instanceRole, IPList)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) DeleteInstances() error {
|
||||
instanceIDs := strings.Split(a.Infra.Status.ShouldBeDeleteInstancesIDs, ",")
|
||||
if len(instanceIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
request := ecs.CreateDeleteInstancesRequest()
|
||||
request.Scheme = Scheme
|
||||
request.InstanceId = &instanceIDs
|
||||
request.Force = requests.NewBoolean(true)
|
||||
//_, err := d.Client.DeleteInstances(request)
|
||||
response := ecs.CreateDeleteInstancesResponse()
|
||||
err := a.RetryEcsRequest(request, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Infra.Status.ShouldBeDeleteInstancesIDs = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateDescribeInstancesTag(tags map[string]string) (instanceTags []ecs.DescribeInstancesTag) {
|
||||
for k, v := range tags {
|
||||
instanceTags = append(instanceTags, ecs.DescribeInstancesTag{Key: k, Value: v})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateInstanceDataDisk(dataDisks []string, category string) (instanceDisks []ecs.RunInstancesDataDisk) {
|
||||
for _, v := range dataDisks {
|
||||
instanceDisks = append(instanceDisks,
|
||||
ecs.RunInstancesDataDisk{Size: v, Category: category})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type InstanceInfo struct {
|
||||
InstanceType string
|
||||
ZoneID string
|
||||
}
|
||||
|
||||
func (a *AliProvider) GetAvailableResourcesForSystem() (instances *InstanceInfo, err error) {
|
||||
request := ecs.CreateDescribeAvailableResourceRequest()
|
||||
request.Scheme = Scheme
|
||||
if a.Infra.Status.ZoneID != "" {
|
||||
request.ZoneId = a.Infra.Status.ZoneID
|
||||
}
|
||||
if a.Infra.Spec.Instance.Type != "" {
|
||||
request.InstanceType = a.Infra.Spec.Instance.Type
|
||||
}
|
||||
|
||||
request.RegionId = a.Infra.Status.RegionID
|
||||
request.DestinationResource = DestinationResource
|
||||
request.InstanceChargeType = InstanceChargeType
|
||||
request.SystemDiskCategory = a.Infra.Spec.Instance.SystemCategory
|
||||
request.DataDiskCategory = a.Infra.Spec.Instance.DataCategory
|
||||
request.SpotStrategy = a.Infra.Status.SpotStrategy
|
||||
|
||||
response := ecs.CreateDescribeAvailableResourceResponse()
|
||||
err = a.EcsClient.DoAction(request, response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(response.AvailableZones.AvailableZone) < 1 {
|
||||
return nil, fmt.Errorf("resources not find")
|
||||
}
|
||||
for _, i := range response.AvailableZones.AvailableZone {
|
||||
for _, f := range i.AvailableResources.AvailableResource {
|
||||
for _, r := range f.SupportedResources.SupportedResource {
|
||||
if r.StatusCategory == AvailableTypeStatus {
|
||||
return &InstanceInfo{
|
||||
InstanceType: r.Value,
|
||||
ZoneID: i.ZoneId,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func (a *AliProvider) GetAvailableResource(instanceRole string, cores int, memory float64) (instanceType []string, err error) {
|
||||
request := ecs.CreateDescribeAvailableResourceRequest()
|
||||
request.Scheme = Scheme
|
||||
request.RegionId = a.Infra.Status.RegionID
|
||||
request.ZoneId = a.Infra.Status.ZoneID
|
||||
request.DestinationResource = DestinationResource
|
||||
request.InstanceChargeType = InstanceChargeType
|
||||
request.Cores = requests.NewInteger(cores)
|
||||
request.Memory = requests.NewFloat(memory)
|
||||
|
||||
response := ecs.CreateDescribeAvailableResourceResponse()
|
||||
err = a.EcsClient.DoAction(request, response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(response.AvailableZones.AvailableZone) < 1 {
|
||||
return nil, fmt.Errorf("resources not find")
|
||||
}
|
||||
for _, i := range response.AvailableZones.AvailableZone {
|
||||
for _, f := range i.AvailableResources.AvailableResource {
|
||||
for _, r := range f.SupportedResources.SupportedResource {
|
||||
if r.StatusCategory == AvailableTypeStatus {
|
||||
instanceType = append(instanceType, r.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var defaultInstanceType []string
|
||||
switch instanceRole {
|
||||
case Master:
|
||||
defaultInstanceType = []string{a.Infra.Status.MasterInstanceType}
|
||||
case Node:
|
||||
defaultInstanceType = []string{a.Infra.Status.NodeInstanceType}
|
||||
}
|
||||
instanceType = append(defaultInstanceType, instanceType...)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *AliProvider) RunInstances(instanceRole string, count int) error {
|
||||
var hosts *v2.Hosts
|
||||
switch instanceRole {
|
||||
case Master:
|
||||
hosts = &a.Infra.Spec.Masters
|
||||
case Node:
|
||||
hosts = a.Infra.Spec.Nodes
|
||||
}
|
||||
instances := hosts
|
||||
if instances == nil {
|
||||
return errors.New("host not set")
|
||||
}
|
||||
systemDiskSize := instances.Disks.System
|
||||
var instanceType []string
|
||||
var err error
|
||||
|
||||
instanceType, err = a.GetAvailableResource(instanceRole, instances.CPU, instances.Memory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tag := make(map[string]string)
|
||||
tag[Product] = a.Infra.Name
|
||||
tag[Role] = instanceRole
|
||||
instancesTag := CreateInstanceTag(tag)
|
||||
|
||||
dataDisks := instances.Disks.Data
|
||||
datadisk := CreateInstanceDataDisk(dataDisks, a.Infra.Spec.Instance.DataCategory)
|
||||
|
||||
request := ecs.CreateRunInstancesRequest()
|
||||
request.Scheme = Scheme
|
||||
request.ImageId = a.Infra.Spec.Instance.ImageID
|
||||
request.Password = a.Infra.Spec.Auth.Passwd
|
||||
request.SecurityGroupId = a.Infra.Status.SecurityGroupID
|
||||
request.VSwitchId = a.Infra.Status.VSwitchID
|
||||
request.SystemDiskSize = systemDiskSize
|
||||
request.SystemDiskCategory = a.Infra.Spec.Instance.SystemCategory
|
||||
request.DataDisk = &datadisk
|
||||
request.SpotStrategy = a.Infra.Status.SpotStrategy
|
||||
request.Amount = requests.NewInteger(count)
|
||||
request.Tag = &instancesTag
|
||||
//response, err := d.Client.RunInstances(request)
|
||||
response := ecs.CreateRunInstancesResponse()
|
||||
err = a.RetryEcsInstanceType(request, response, instanceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
instancesIDs := strings.Join(response.InstanceIdSets.InstanceIdSet, ",")
|
||||
switch instanceRole {
|
||||
case Master:
|
||||
a.Infra.Status.MasterIDs += instancesIDs
|
||||
case Node:
|
||||
a.Infra.Status.NodeIDs += instancesIDs
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) AuthorizeSecurityGroup(securityGroupID, portRange string) bool {
|
||||
request := ecs.CreateAuthorizeSecurityGroupRequest()
|
||||
request.Scheme = Scheme
|
||||
request.SecurityGroupId = securityGroupID
|
||||
request.IpProtocol = IPProtocol
|
||||
request.PortRange = portRange
|
||||
request.SourceCidrIp = SourceCidrIP
|
||||
request.Policy = Policy
|
||||
|
||||
response := ecs.CreateAuthorizeSecurityGroupResponse()
|
||||
err := a.RetryEcsRequest(request, response)
|
||||
if err != nil {
|
||||
logger.Error("%v", err)
|
||||
return false
|
||||
}
|
||||
return response.BaseResponse.IsSuccess()
|
||||
}
|
||||
|
||||
func (a *AliProvider) CreateSecurityGroup() error {
|
||||
request := ecs.CreateCreateSecurityGroupRequest()
|
||||
request.Scheme = Scheme
|
||||
request.RegionId = a.Infra.Status.RegionID
|
||||
request.VpcId = a.Infra.Status.VpcID
|
||||
response := ecs.CreateCreateSecurityGroupResponse()
|
||||
err := a.RetryEcsRequest(request, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !a.AuthorizeSecurityGroup(response.SecurityGroupId, SSHPortRange) {
|
||||
return fmt.Errorf("authorize securitygroup ssh port failed")
|
||||
}
|
||||
if !a.AuthorizeSecurityGroup(response.SecurityGroupId, APIServerPortRange) {
|
||||
return fmt.Errorf("authorize securitygroup apiserver port failed")
|
||||
}
|
||||
a.Infra.Status.SecurityGroupID = response.SecurityGroupId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) DeleteSecurityGroup() error {
|
||||
request := ecs.CreateDeleteSecurityGroupRequest()
|
||||
request.Scheme = Scheme
|
||||
request.SecurityGroupId = a.Infra.Status.SecurityGroupID
|
||||
|
||||
response := ecs.CreateDeleteSecurityGroupResponse()
|
||||
return a.RetryEcsRequest(request, response)
|
||||
}
|
||||
|
||||
func CreateInstanceTag(tags map[string]string) (instanceTags []ecs.RunInstancesTag) {
|
||||
for k, v := range tags {
|
||||
instanceTags = append(instanceTags, ecs.RunInstancesTag{Key: k, Value: v})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LoadConfig(config *Config) error {
|
||||
config.AccessKey = os.Getenv(EnvAccessKey)
|
||||
config.AccessSecret = os.Getenv(EnvAccessSecret)
|
||||
config.regionID = os.Getenv(EnvRegion)
|
||||
if config.regionID == "" {
|
||||
config.regionID = DefaultRegionID
|
||||
}
|
||||
if config.AccessKey == "" || config.AccessSecret == "" || config.regionID == "" {
|
||||
return fmt.Errorf("please set accessKey and accessKeySecret ENV, example: export ACCESSKEYID=xxx export ACCESSKEYSECRET=xxx , how to get AK SK: https://ram.console.aliyun.com/manage/ak")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
// Copyright © 2021 Alibaba Group Holding 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.
|
||||
|
||||
package aliyun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/fanux/sealos/pkg/types/validation"
|
||||
|
||||
v2 "github.com/fanux/sealos/pkg/types/v1beta1"
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
|
||||
)
|
||||
|
||||
type ActionName string
|
||||
|
||||
const (
|
||||
CreateVPC ActionName = "CreateVPC"
|
||||
CreateVSwitch ActionName = "CreateVSwitch"
|
||||
CreateSecurityGroup ActionName = "CreateSecurityGroup"
|
||||
ReconcileInstance ActionName = "ReconcileInstance"
|
||||
BindEIP ActionName = "BindEIP"
|
||||
ReleaseEIP ActionName = "ReleaseEIP"
|
||||
ClearInstances ActionName = "ClearInstances"
|
||||
DeleteVSwitch ActionName = "DeleteVSwitch"
|
||||
DeleteSecurityGroup ActionName = "DeleteSecurityGroup"
|
||||
DeleteVPC ActionName = "DeleteVPC"
|
||||
GetSystemInfo ActionName = "GetSystemInfo"
|
||||
)
|
||||
|
||||
type AliProvider struct {
|
||||
Config Config
|
||||
EcsClient ecs.Client
|
||||
VpcClient vpc.Client
|
||||
Infra *v2.Infra
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
AccessKey string
|
||||
AccessSecret string
|
||||
regionID string
|
||||
}
|
||||
|
||||
type Alifunc func() error
|
||||
|
||||
func (a *AliProvider) ReconcileResource(resourceKey ResourceName, action Alifunc) error {
|
||||
if resourceKey.Value(a.Infra.Status) != "" {
|
||||
logger.Warn("create resource exists %s: %s", resourceKey, resourceKey.Value(a.Infra.Status))
|
||||
return nil
|
||||
}
|
||||
if err := action(); err != nil {
|
||||
logger.Error("reconcile resource %s failed err: %s", resourceKey, err)
|
||||
return err
|
||||
}
|
||||
if resourceKey.Value(a.Infra.Status) != "" {
|
||||
logger.Info("create resource success %s: %s", resourceKey, resourceKey.Value(a.Infra.Status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) DeleteResource(resourceKey ResourceName, action Alifunc) {
|
||||
val := resourceKey.Value(a.Infra.Status)
|
||||
if val == "" {
|
||||
logger.Warn("delete resource not exists %s", resourceKey)
|
||||
return
|
||||
}
|
||||
if err := action(); err != nil {
|
||||
logger.Error("delete resource %s failed err: %s", resourceKey, err)
|
||||
} else {
|
||||
logger.Info("delete resource Success %s: %s", resourceKey, val)
|
||||
}
|
||||
}
|
||||
|
||||
var RecocileFuncMap = map[ActionName]func(provider *AliProvider) error{
|
||||
CreateVPC: func(aliProvider *AliProvider) error {
|
||||
return aliProvider.ReconcileResource(VpcID, aliProvider.CreateVPC)
|
||||
},
|
||||
|
||||
CreateVSwitch: func(aliProvider *AliProvider) error {
|
||||
return aliProvider.ReconcileResource(VSwitchID, aliProvider.CreateVSwitch)
|
||||
},
|
||||
CreateSecurityGroup: func(aliProvider *AliProvider) error {
|
||||
return aliProvider.ReconcileResource(SecurityGroupID, aliProvider.CreateSecurityGroup)
|
||||
},
|
||||
ReconcileInstance: func(aliProvider *AliProvider) error {
|
||||
err := aliProvider.ReconcileInstances(Master)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = aliProvider.ReconcileInstances(Node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
GetSystemInfo: func(aliProvider *AliProvider) error {
|
||||
return aliProvider.ReconcileResource(SystemInfo, aliProvider.SystemInfo)
|
||||
},
|
||||
BindEIP: func(aliProvider *AliProvider) error {
|
||||
return aliProvider.ReconcileResource(EipID, aliProvider.BindEipForMaster0)
|
||||
},
|
||||
}
|
||||
|
||||
var DeleteFuncMap = map[ActionName]func(provider *AliProvider){
|
||||
ReleaseEIP: func(aliProvider *AliProvider) {
|
||||
aliProvider.DeleteResource(EipID, aliProvider.ReleaseEipAddress)
|
||||
},
|
||||
ClearInstances: func(aliProvider *AliProvider) {
|
||||
var instanceIDs []string
|
||||
roles := []string{Master, Node}
|
||||
for _, role := range roles {
|
||||
instances, err := aliProvider.GetInstancesInfo(role, JustGetInstanceInfo)
|
||||
if err != nil {
|
||||
logger.Error("get %s instanceinfo failed %v", role, err)
|
||||
}
|
||||
for _, instance := range instances {
|
||||
instanceIDs = append(instanceIDs, instance.InstanceID)
|
||||
}
|
||||
}
|
||||
if len(instanceIDs) != 0 {
|
||||
aliProvider.Infra.Status.ShouldBeDeleteInstancesIDs = strings.Join(instanceIDs, ",")
|
||||
}
|
||||
aliProvider.DeleteResource(ShouldBeDeleteInstancesIDs, aliProvider.DeleteInstances)
|
||||
},
|
||||
DeleteVSwitch: func(aliProvider *AliProvider) {
|
||||
aliProvider.DeleteResource(VSwitchID, aliProvider.DeleteVSwitch)
|
||||
},
|
||||
DeleteSecurityGroup: func(aliProvider *AliProvider) {
|
||||
aliProvider.DeleteResource(SecurityGroupID, aliProvider.DeleteSecurityGroup)
|
||||
},
|
||||
DeleteVPC: func(aliProvider *AliProvider) {
|
||||
aliProvider.DeleteResource(VpcID, aliProvider.DeleteVPC)
|
||||
},
|
||||
}
|
||||
|
||||
func (a *AliProvider) NewClient() error {
|
||||
ecsClient, err := ecs.NewClientWithAccessKey(a.Config.regionID, a.Config.AccessKey, a.Config.AccessSecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vpcClient, err := vpc.NewClientWithAccessKey(a.Config.regionID, a.Config.AccessKey, a.Config.AccessSecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.EcsClient = *ecsClient
|
||||
a.VpcClient = *vpcClient
|
||||
a.Infra.Status.RegionID = a.Config.regionID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) ClearCluster() {
|
||||
todolist := []ActionName{
|
||||
ReleaseEIP,
|
||||
ClearInstances,
|
||||
DeleteVSwitch,
|
||||
DeleteSecurityGroup,
|
||||
DeleteVPC,
|
||||
}
|
||||
for _, name := range todolist {
|
||||
DeleteFuncMap[name](a)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AliProvider) Reconcile() error {
|
||||
if a.Infra.Annotations == nil {
|
||||
a.Infra.Annotations = make(map[string]string)
|
||||
}
|
||||
if a.Infra.DeletionTimestamp != nil {
|
||||
logger.Info("DeletionTimestamp not nil Clear Infra")
|
||||
a.ClearCluster()
|
||||
return nil
|
||||
}
|
||||
todolist := []ActionName{
|
||||
CreateVPC,
|
||||
GetSystemInfo,
|
||||
CreateVSwitch,
|
||||
CreateSecurityGroup,
|
||||
ReconcileInstance,
|
||||
BindEIP,
|
||||
}
|
||||
|
||||
for _, actionname := range todolist {
|
||||
err := RecocileFuncMap[actionname](a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) Apply() error {
|
||||
if err := v2.Default(a.Infra, defaultInfra); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validation.ValidateInfra(a.Infra); len(err) != 0 {
|
||||
return err.ToAggregate()
|
||||
}
|
||||
return a.Reconcile()
|
||||
}
|
||||
|
||||
func defaultInfra(infra *v2.Infra) error {
|
||||
//https://help.aliyun.com/document_detail/63440.htm?spm=a2c4g.11186623.0.0.f5952752gkxpB7#t9856.html
|
||||
if infra.Spec.Instance.IsSeize {
|
||||
infra.Status.SpotStrategy = "SpotAsPriceGo"
|
||||
} else {
|
||||
infra.Status.SpotStrategy = "NoSpot"
|
||||
}
|
||||
if infra.Spec.Platform == v2.ARM64 {
|
||||
switch infra.Status.RegionID {
|
||||
case "cn-shanghai":
|
||||
infra.Status.ZoneID = "cn-shanghai-l"
|
||||
case "cn-beijing":
|
||||
infra.Status.ZoneID = "cn-beijing-k"
|
||||
case "cn-hangzhou":
|
||||
infra.Status.ZoneID = "cn-hangzhou-i"
|
||||
default:
|
||||
return errors.New("not available ZoneID for arm, support RegionID[cn-shanghai,cn-beijing,cn-hangzhou]")
|
||||
}
|
||||
infra.Spec.Instance.ImageID = defaultImageArmID
|
||||
} else {
|
||||
infra.Spec.Instance.ImageID = defaultImageAmdID
|
||||
}
|
||||
//"cloud_efficiency", "cloud_essd", "cloud_ssd"
|
||||
if infra.Spec.Instance.SystemCategory == "" {
|
||||
infra.Spec.Instance.SystemCategory = "cloud_efficiency"
|
||||
}
|
||||
if infra.Spec.Instance.DataCategory == "" {
|
||||
infra.Spec.Instance.DataCategory = "cloud_efficiency"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright © 2021 Alibaba Group Holding 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.
|
||||
|
||||
package aliyun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
|
||||
)
|
||||
|
||||
type VpcManager struct {
|
||||
Config Config
|
||||
Client *vpc.Client
|
||||
}
|
||||
|
||||
func (a *AliProvider) RetryVpcRequest(request requests.AcsRequest, response responses.AcsResponse) error {
|
||||
return utils.Retry(TryTimes, TrySleepTime, func() error {
|
||||
err := a.VpcClient.DoAction(request, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (a *AliProvider) CreateVPC() error {
|
||||
request := vpc.CreateCreateVpcRequest()
|
||||
request.Scheme = Scheme
|
||||
request.RegionId = a.Infra.Status.RegionID
|
||||
//response, err := d.Client.CreateVpc(request)
|
||||
response := vpc.CreateCreateVpcResponse()
|
||||
err := a.RetryVpcRequest(request, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Infra.Status.VpcID = response.VpcId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) DeleteVPC() error {
|
||||
request := vpc.CreateDeleteVpcRequest()
|
||||
request.Scheme = Scheme
|
||||
request.VpcId = a.Infra.Status.VpcID
|
||||
|
||||
//response, err := d.Client.DeleteVpc(request)
|
||||
response := vpc.CreateDeleteVpcResponse()
|
||||
return a.RetryVpcRequest(request, response)
|
||||
}
|
||||
|
||||
func (a *AliProvider) CreateVSwitch() error {
|
||||
request := vpc.CreateCreateVSwitchRequest()
|
||||
request.Scheme = Scheme
|
||||
request.ZoneId = a.Infra.Status.ZoneID
|
||||
request.CidrBlock = CidrBlock
|
||||
request.VpcId = a.Infra.Status.VpcID
|
||||
request.RegionId = a.Infra.Status.RegionID
|
||||
//response, err := d.Client.CreateVSwitch(request)
|
||||
response := vpc.CreateCreateVSwitchResponse()
|
||||
err := a.RetryVpcRequest(request, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Infra.Status.VSwitchID = response.VSwitchId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) DeleteVSwitch() error {
|
||||
request := vpc.CreateDeleteVSwitchRequest()
|
||||
request.Scheme = Scheme
|
||||
request.VSwitchId = a.Infra.Status.VSwitchID
|
||||
|
||||
response := vpc.CreateDeleteVSwitchResponse()
|
||||
return a.RetryVpcRequest(request, response)
|
||||
}
|
||||
|
||||
func (a *AliProvider) SystemInfo() error {
|
||||
availableInstance, err := a.GetAvailableResourcesForSystem()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Infra.Spec.Instance.Type = availableInstance.InstanceType
|
||||
a.Infra.Status.MasterInstanceType = availableInstance.InstanceType
|
||||
a.Infra.Status.NodeInstanceType = availableInstance.InstanceType
|
||||
a.Infra.Status.ZoneID = availableInstance.ZoneID
|
||||
|
||||
logger.Info("fetch resource success %s: %s", "ZoneID", a.Infra.Status.ZoneID)
|
||||
logger.Info("fetch resource success %s: %s", "InstanceType", a.Infra.Spec.Instance.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) BindEipForMaster0() error {
|
||||
instances, err := a.GetInstancesInfo(Master, JustGetInstanceInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(instances) == 0 {
|
||||
return errors.New("can not find master0 ")
|
||||
}
|
||||
master0 := instances[0]
|
||||
eIP, eIPID, err := a.AllocateEipAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = a.AssociateEipAddress(master0.InstanceID, eIPID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Infra.Status.EIP = eIP
|
||||
a.Infra.Status.EIPID = eIPID
|
||||
a.Infra.Status.Master0ID = master0.InstanceID
|
||||
a.Infra.Status.Master0InternalIP = master0.PrimaryIPAddress
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) AllocateEipAddress() (eIP, eIPID string, err error) {
|
||||
request := vpc.CreateAllocateEipAddressRequest()
|
||||
request.Scheme = Scheme
|
||||
request.Bandwidth = Bandwidth
|
||||
request.InternetChargeType = InternetChargeType
|
||||
response := vpc.CreateAllocateEipAddressResponse()
|
||||
err = a.RetryVpcRequest(request, response)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return response.EipAddress, response.AllocationId, nil
|
||||
}
|
||||
|
||||
func (a *AliProvider) AssociateEipAddress(instanceID, eipID string) error {
|
||||
request := vpc.CreateAssociateEipAddressRequest()
|
||||
request.Scheme = Scheme
|
||||
request.InstanceId = instanceID
|
||||
request.AllocationId = eipID
|
||||
|
||||
response := vpc.CreateAssociateEipAddressResponse()
|
||||
return a.RetryVpcRequest(request, response)
|
||||
}
|
||||
|
||||
func (a *AliProvider) UnassociateEipAddress() error {
|
||||
request := vpc.CreateUnassociateEipAddressRequest()
|
||||
request.Scheme = Scheme
|
||||
request.AllocationId = a.Infra.Status.EIPID
|
||||
request.Force = requests.NewBoolean(true)
|
||||
response := vpc.CreateUnassociateEipAddressResponse()
|
||||
return a.RetryVpcRequest(request, response)
|
||||
}
|
||||
|
||||
func (a *AliProvider) ReleaseEipAddress() error {
|
||||
err := a.UnassociateEipAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request := vpc.CreateReleaseEipAddressRequest()
|
||||
request.Scheme = Scheme
|
||||
request.AllocationId = a.Infra.Status.EIPID
|
||||
response := vpc.CreateReleaseEipAddressResponse()
|
||||
return a.RetryVpcRequest(request, response)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright © 2021 Alibaba Group Holding 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.
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/fanux/sealos/pkg/infra/aliyun"
|
||||
v2 "github.com/fanux/sealos/pkg/types/v1beta1"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
// Apply apply iaas resources and save metadata info like vpc instance id to cluster status
|
||||
// https://github.com/fanux/sealgate/tree/master/cloud
|
||||
Apply() error
|
||||
}
|
||||
|
||||
func newAliProvider(infra *v2.Infra) (Interface, error) {
|
||||
config := new(aliyun.Config)
|
||||
err := aliyun.LoadConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aliProvider := new(aliyun.AliProvider)
|
||||
aliProvider.Config = *config
|
||||
aliProvider.Infra = infra
|
||||
err = aliProvider.NewClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return aliProvider, nil
|
||||
}
|
||||
|
||||
func NewDefaultProvider(infra *v2.Infra) (Interface, error) {
|
||||
switch infra.Spec.Provider {
|
||||
case v2.AliyunProvider:
|
||||
return newAliProvider(infra)
|
||||
default:
|
||||
return nil, fmt.Errorf("the provider is invalid, please set the provider correctly")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Copyright © 2021 Alibaba Group Holding 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.
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
v2 "github.com/fanux/sealos/pkg/types/v1beta1"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestApply(t *testing.T) {
|
||||
//setup infra
|
||||
password := os.Getenv("SealosPassword")
|
||||
infra := v2.Infra{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Infra",
|
||||
APIVersion: v2.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "my-infra",
|
||||
},
|
||||
Spec: v2.InfraSpec{
|
||||
Instance: v2.Instance{
|
||||
IsSeize: true,
|
||||
Type: "ecs.c6r.large",
|
||||
},
|
||||
Platform: v2.ARM64,
|
||||
Masters: v2.Hosts{
|
||||
Count: 1,
|
||||
CPU: 2,
|
||||
Memory: 4,
|
||||
Disks: v2.Disks{
|
||||
System: "100",
|
||||
Data: []string{"100"},
|
||||
},
|
||||
},
|
||||
Nodes: &v2.Hosts{
|
||||
Count: 1,
|
||||
CPU: 2,
|
||||
Memory: 4,
|
||||
Disks: v2.Disks{
|
||||
System: "100",
|
||||
Data: []string{"100"},
|
||||
},
|
||||
},
|
||||
Provider: v2.AliyunProvider,
|
||||
Auth: v2.Auth{
|
||||
Passwd: password,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
aliProvider, err := NewDefaultProvider(&infra)
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
} else {
|
||||
fmt.Printf("%v", aliProvider.Apply())
|
||||
}
|
||||
|
||||
t.Run("modify instance type", func(t *testing.T) {
|
||||
infra.Spec.Masters.CPU = 4
|
||||
infra.Spec.Masters.Memory = 8
|
||||
infra.Spec.Nodes.CPU = 4
|
||||
infra.Spec.Nodes.Memory = 8
|
||||
fmt.Printf("%v", aliProvider.Apply())
|
||||
})
|
||||
|
||||
t.Run("add instance count", func(t *testing.T) {
|
||||
infra.Spec.Masters.Count = 5
|
||||
infra.Spec.Nodes.Count = 5
|
||||
fmt.Printf("%v", aliProvider.Apply())
|
||||
fmt.Printf("%v \n", infra.Spec.Masters)
|
||||
fmt.Printf("%v \n", infra.Spec.Nodes)
|
||||
})
|
||||
|
||||
t.Run("reduce instance count", func(t *testing.T) {
|
||||
infra.Spec.Masters.Count = 1
|
||||
infra.Spec.Nodes.Count = 1
|
||||
fmt.Printf("%v", aliProvider.Apply())
|
||||
})
|
||||
|
||||
t.Run("modify instance type & count both", func(t *testing.T) {
|
||||
infra.Spec.Masters.CPU = 8
|
||||
infra.Spec.Masters.Memory = 16
|
||||
infra.Spec.Nodes.CPU = 8
|
||||
infra.Spec.Nodes.Memory = 16
|
||||
infra.Spec.Masters.Count = 5
|
||||
infra.Spec.Nodes.Count = 5
|
||||
fmt.Printf("%v", aliProvider.Apply())
|
||||
})
|
||||
|
||||
// todo
|
||||
t.Run("modify instance system disk", func(t *testing.T) {
|
||||
|
||||
})
|
||||
|
||||
j, _ := yaml.Marshal(&infra)
|
||||
t.Log("output yaml:", string(j))
|
||||
//teardown
|
||||
time.Sleep(20 * time.Second)
|
||||
now := metav1.Now()
|
||||
infra.ObjectMeta.DeletionTimestamp = &now
|
||||
t.Log(fmt.Sprintf("%v", aliProvider.Apply()))
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/cni"
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 install
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
"github.com/fanux/sealgate/cloud"
|
||||
extver "github.com/linuxsuren/cobra-extension/version"
|
||||
)
|
||||
|
||||
//VersionURL is base64 encode k8s version and offline package url
|
||||
var (
|
||||
VersionURL string
|
||||
URLMap map[string]string
|
||||
DefaultURL = "https://sealyun.oss-cn-beijing.aliyuncs.com/37374d999dbadb788ef0461844a70151-1.16.0/kube1.16.0.tar.gz"
|
||||
)
|
||||
|
||||
//Flags is command line paras
|
||||
type Flags struct {
|
||||
Master int
|
||||
MasterType string
|
||||
Node int
|
||||
NodeType string
|
||||
Version string
|
||||
Flavor string
|
||||
Passwd string
|
||||
Zone string
|
||||
Interaction bool
|
||||
Image string
|
||||
}
|
||||
|
||||
// Cluster is cluster metadata
|
||||
type Cluster struct {
|
||||
cloud.Config
|
||||
Flags
|
||||
Name string
|
||||
Masters []cloud.VM
|
||||
Nodes []cloud.VM
|
||||
VPCID string
|
||||
SwitchID string
|
||||
SecuretyGroupID string
|
||||
}
|
||||
|
||||
var C Cluster
|
||||
var ClusterDir = v1.DefaultConfigPath + "/clusters/"
|
||||
|
||||
// 2019.11.28 今天刚修完陪产假,在新装修的公寓中写代码,刚配的眼镜感觉带着有点不舒服,看屏幕不是很清楚
|
||||
/*
|
||||
配眼镜的人也不是很专业,二宝还是个女儿,非常可爱而且非常乖,不像大宝那么吵。 一直很想写日记但是不知道往哪里写合适
|
||||
既然github要把代码存两千年那为啥不写到代码里,如此这便成为我第一篇代码日记。
|
||||
|
||||
碳纤维地暖开了半天还是冰凉的,感觉是被忽悠了。
|
||||
|
||||
一写代码就精神万分,一搞管理上的杂事就效率很低,所以做技术还是要专注些。
|
||||
*/
|
||||
func CloudInstall(c *Cluster) {
|
||||
URLMap = make(map[string]string)
|
||||
URLMap["v1.16.0"] = DefaultURL
|
||||
|
||||
config := c.Config
|
||||
p := cloud.NewProvider(config)
|
||||
|
||||
_ = v1.Dump(fmt.Sprintf("%s%s.yaml", ClusterDir, c.Name), c)
|
||||
|
||||
//TODO concurrence create master and nodes vms, should not create two vpcs
|
||||
/*
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
// create masters vms
|
||||
res, err := p.Create(newRequest(c, "master", true, c.Master))
|
||||
if err != nil {
|
||||
logger.Error("init cluster failed: %s", err)
|
||||
return
|
||||
}
|
||||
c.Masters = res.VMs
|
||||
c.VPCID = res.VPCID
|
||||
c.SwitchID = res.SwitchID
|
||||
c.SecuretyGroupID = res.SecuretyGroupID
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
// create nodes vms
|
||||
res, err := p.Create(newRequest(c, "node", false, c.Node))
|
||||
if err != nil {
|
||||
logger.Error("init cluster failed: %s", err)
|
||||
return
|
||||
}
|
||||
c.Nodes = res.VMs
|
||||
wg.Done()
|
||||
}()
|
||||
wg.Wait()
|
||||
*/
|
||||
// create masters vms
|
||||
res, err := p.Create(newRequest(c, "master", true, c.Master))
|
||||
if err != nil {
|
||||
logger.Error("init cluster failed: %s", err)
|
||||
return
|
||||
}
|
||||
c.Masters = res.VMs
|
||||
c.VPCID = res.VPCID
|
||||
c.SwitchID = res.SwitchID
|
||||
c.SecuretyGroupID = res.SecuretyGroupID
|
||||
|
||||
// create nodes vms
|
||||
res, err = p.Create(newRequest(c, "node", false, c.Node))
|
||||
if err != nil {
|
||||
logger.Error("init cluster failed: %s", err)
|
||||
return
|
||||
}
|
||||
c.Nodes = res.VMs
|
||||
|
||||
//TODO wget package on master0 and scp to other nodes
|
||||
logger.Info("wait few minute for download offline package on master0...")
|
||||
cmd := newWgetCommand(c)
|
||||
CmdWorkSpace(c.Masters[0].FIP, cmd, "/root")
|
||||
|
||||
// exec sealos init on master0
|
||||
cmd = newCommand(c)
|
||||
CmdWorkSpace(c.Masters[0].FIP, cmd, "/root")
|
||||
}
|
||||
|
||||
func getURL(version string) string {
|
||||
url, ok := URLMap[version]
|
||||
if !ok {
|
||||
logger.Error("version offline package not found: %s", version)
|
||||
os.Exit(1)
|
||||
return DefaultURL
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
func getLocalURL(version string) string {
|
||||
return fmt.Sprintf("/root/kube%s.tar.gz", version[1:])
|
||||
}
|
||||
|
||||
func newCommand(c *Cluster) string {
|
||||
//TODO should download it on master0 and copy to other nodes
|
||||
version := extver.GetVersion()
|
||||
if strings.HasPrefix(version, "v") {
|
||||
version = strings.TrimPrefix(version, "v")
|
||||
}
|
||||
releaseURL := fmt.Sprintf("https://github.com/fanux/sealos/releases/download/v%s/sealos_%s_linux_amd64.tar.gz",
|
||||
version, version)
|
||||
cmd := fmt.Sprintf("wget %s -O -| tar -xz && chmod +x sealos", releaseURL)
|
||||
cmd += fmt.Sprintf(" && ./sealos init --passwd %s --pkg-url %s --version %s", c.Passwd, getLocalURL(c.Version), c.Version)
|
||||
for _, master := range c.Masters {
|
||||
cmd += fmt.Sprintf(" --master %s", master.IP)
|
||||
}
|
||||
for _, node := range c.Nodes {
|
||||
cmd += fmt.Sprintf(" --node %s", node.IP)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newWgetCommand(c *Cluster) string {
|
||||
cmd := fmt.Sprintf("cd /root && wget %s", getURL(c.Version))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newRequest(c *Cluster, namePrefix string, fip bool, num int) cloud.Request {
|
||||
r := cloud.Request{
|
||||
Num: num,
|
||||
Image: c.Flags.Image,
|
||||
NamePrefix: namePrefix,
|
||||
FIP: fip,
|
||||
Flavor: c.Flags.Flavor,
|
||||
Passwd: c.Flags.Passwd,
|
||||
ZoneID: c.Flags.Zone,
|
||||
VPCID: c.VPCID,
|
||||
SwitchID: c.SwitchID,
|
||||
SecuretyGroupID: c.SecuretyGroupID,
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// CmdWorkSpace exec cmd on specified workdir.
|
||||
func CmdWorkSpace(node, cmd, workdir string) {
|
||||
command := fmt.Sprintf("cd %s && %s", workdir, cmd)
|
||||
_ = v1.SSHConfig.CmdAsync(node, command)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
|
||||
+8
-1
@@ -15,11 +15,12 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/kubernetes/nodeclient"
|
||||
@@ -154,3 +155,9 @@ func (e *ExecFlag) execByNodeIP() {
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// CmdWorkSpace exec cmd on specified workdir.
|
||||
func CmdWorkSpace(node, cmd, workdir string) {
|
||||
command := fmt.Sprintf("cd %s && %s", workdir, cmd)
|
||||
_ = v1.SSHConfig.CmdAsync(node, command)
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/cni"
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
"github.com/fanux/sealos/pkg/utils/ssh"
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v1 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
nodeclient2 "github.com/fanux/sealos/pkg/kubernetes/nodeclient"
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 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 version
|
||||
|
||||
// Info contains versioning information.
|
||||
// TODO: Add []string of api versions supported? It's still unclear
|
||||
// how we'll want to distribute that information.
|
||||
type Info struct {
|
||||
Major string `json:"major"`
|
||||
Minor string `json:"minor"`
|
||||
GitVersion string `json:"gitVersion"`
|
||||
GitCommit string `json:"gitCommit"`
|
||||
GitTreeState string `json:"gitTreeState"`
|
||||
BuildDate string `json:"buildDate"`
|
||||
GoVersion string `json:"goVersion"`
|
||||
Compiler string `json:"compiler"`
|
||||
Platform string `json:"platform"`
|
||||
}
|
||||
|
||||
// String returns info as a human-friendly version string.
|
||||
func (info Info) String() string {
|
||||
return info.GitVersion
|
||||
}
|
||||
@@ -228,7 +228,7 @@ func validateKubeConfig(outDir, filename string, config *clientcmdapi.Config) er
|
||||
}
|
||||
currentCluster := currentCtx.Cluster
|
||||
if currentConfig.Clusters[currentCluster] == nil {
|
||||
return errors.Errorf("failed to find the given CurrentContext Cluster in Clusters of the kubeconfig file %s", kubeConfigFilePath)
|
||||
return errors.Errorf("failed to find the given CurrentContext Infra in Clusters of the kubeconfig file %s", kubeConfigFilePath)
|
||||
}
|
||||
|
||||
// Make sure the compared CAs are whitespace-trimmed. The function clientcmd.LoadFromFile() just decodes
|
||||
|
||||
@@ -16,7 +16,7 @@ package kubeconfig
|
||||
|
||||
import clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
// GetClusterFromKubeConfig returns the default Cluster of the specified KubeConfig
|
||||
// GetClusterFromKubeConfig returns the default Infra of the specified KubeConfig
|
||||
func GetClusterFromKubeConfig(config *clientcmdapi.Config) *clientcmdapi.Cluster {
|
||||
// If there is an unnamed cluster object, use it
|
||||
if config.Clusters[""] != nil {
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
v12 "github.com/fanux/sealos/pkg/types/v1"
|
||||
v12 "github.com/fanux/sealos/pkg/types/v1alpha1"
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils"
|
||||
|
||||
"github.com/fanux/sealos/pkg/cni"
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
|
||||
v2 "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -44,40 +44,40 @@ type Metadata struct {
|
||||
|
||||
// SealConfig for ~/.sealos/config.yaml
|
||||
type SealConfig struct {
|
||||
Masters []string
|
||||
Nodes []string
|
||||
Masters []string `json:"masters"`
|
||||
Nodes []string `json:"nodes"`
|
||||
//config from kubeadm.cfg. ex. cluster.local
|
||||
DNSDomain string
|
||||
APIServerCertSANs []string
|
||||
DNSDomain string `json:"dnsdomain"`
|
||||
APIServerCertSANs []string `json:"apiservercertsans"`
|
||||
|
||||
//SSHConfig
|
||||
User string
|
||||
Passwd string
|
||||
PrivateKey string
|
||||
PkPassword string
|
||||
User string `json:"user"`
|
||||
Passwd string `json:"passwd"`
|
||||
PrivateKey string `json:"privatekey"`
|
||||
PkPassword string `json:"pkpassword"`
|
||||
//ApiServer ex. apiserver.cluster.local
|
||||
APIServerDomain string
|
||||
Network string
|
||||
VIP string
|
||||
PkgURL string
|
||||
Version string
|
||||
Repo string
|
||||
PodCIDR string
|
||||
SvcCIDR string
|
||||
APIServerDomain string `json:"apiserverdomain"`
|
||||
Network string `json:"network"`
|
||||
VIP string `json:"vip"`
|
||||
PkgURL string `json:"pkgurl"`
|
||||
Version string `json:"version"`
|
||||
Repo string `json:"repo"`
|
||||
PodCIDR string `json:"podcidr"`
|
||||
SvcCIDR string `json:"svccidr"`
|
||||
//certs location
|
||||
CertPath string
|
||||
CertEtcdPath string
|
||||
CertPath string `json:"certpath"`
|
||||
CertEtcdPath string `json:"certetcdpath"`
|
||||
//lvscare images
|
||||
LvscareName string
|
||||
LvscareTag string
|
||||
AliOss
|
||||
LvscareName string `json:"lvscarename"`
|
||||
LvscareTag string `json:"lvscaretag"`
|
||||
AliOss `json:"alioss"`
|
||||
}
|
||||
type AliOss struct {
|
||||
OssEndpoint string
|
||||
AccessKeyID string
|
||||
AccessKeySecrets string
|
||||
BucketName string
|
||||
ObjectPath string
|
||||
OssEndpoint string `json:"ossendpoint"`
|
||||
AccessKeyID string `json:"accesskeyid"`
|
||||
AccessKeySecrets string `json:"accesskeysecrets"`
|
||||
BucketName string `json:"bucketname"`
|
||||
ObjectPath string `json:"objectpath"`
|
||||
}
|
||||
|
||||
//Dump is
|
||||
@@ -115,7 +115,7 @@ func (c *SealConfig) Dump(path string) {
|
||||
c.AliOss.OssEndpoint = OssEndpoint
|
||||
c.AliOss.BucketName = BucketName
|
||||
c.AliOss.ObjectPath = ObjectPath
|
||||
y, err := v2.Marshal(c)
|
||||
y, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
logger.Error("dump config file failed: %s", err)
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func (c *SealConfig) Dump(path string) {
|
||||
}
|
||||
|
||||
func Dump(path string, content interface{}) error {
|
||||
y, err := v2.Marshal(content)
|
||||
y, err := yaml.Marshal(content)
|
||||
if err != nil {
|
||||
logger.Error("dump config file failed: %s", err)
|
||||
return err
|
||||
@@ -157,7 +157,7 @@ func (c *SealConfig) Load(path string) (err error) {
|
||||
return fmt.Errorf("read config file %s failed %w", path, err)
|
||||
}
|
||||
|
||||
err = v2.Unmarshal(y, c)
|
||||
err = yaml.Unmarshal(y, c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal config file failed: %w", err)
|
||||
}
|
||||
@@ -203,7 +203,7 @@ func Load(path string, content interface{}) error {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
err = v2.Unmarshal(y, content)
|
||||
err = yaml.Unmarshal(y, content)
|
||||
if err != nil {
|
||||
logger.Error("unmarshal config file failed: %s", err)
|
||||
}
|
||||
@@ -231,7 +231,7 @@ func (c *SealConfig) ShowDefaultConfig() {
|
||||
c.LvscareName = "fanux/lvscare"
|
||||
c.LvscareTag = "latest"
|
||||
|
||||
y, err := v2.Marshal(c)
|
||||
y, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
logger.Error("marshal config file failed: %s", err)
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2021 cuisongliu@qq.com.
|
||||
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Default(infra *Infra, fn func(infra *Infra) error) error {
|
||||
if string(infra.Spec.Platform) == "" {
|
||||
infra.Spec.Platform = AMD64
|
||||
}
|
||||
if infra.Spec.Auth.User == "" {
|
||||
infra.Spec.Auth.User = "root"
|
||||
}
|
||||
if infra.Spec.Masters.CPU <= 0 {
|
||||
infra.Spec.Masters.CPU = 2
|
||||
}
|
||||
if infra.Spec.Masters.Memory <= 0 {
|
||||
infra.Spec.Masters.Memory = 4
|
||||
}
|
||||
if len(infra.Spec.Masters.Disks.System) == 0 {
|
||||
infra.Spec.Masters.Disks.System = "40"
|
||||
}
|
||||
if infra.Spec.Auth.Passwd == "" {
|
||||
infra.Spec.Auth.Passwd = createPassword()
|
||||
}
|
||||
return fn(infra)
|
||||
}
|
||||
|
||||
const (
|
||||
digits = "0123456789"
|
||||
specials = "~=+%^*/()[]{}/!@#$?|"
|
||||
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
passwordLength = 16
|
||||
)
|
||||
|
||||
func createPassword() string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
all := digits + specials + letter
|
||||
length := passwordLength
|
||||
buf := make([]byte, length)
|
||||
buf[0] = digits[rand.Intn(len(digits))]
|
||||
buf[1] = specials[rand.Intn(len(specials))]
|
||||
for i := 2; i < length; i++ {
|
||||
buf[i] = all[rand.Intn(len(all))]
|
||||
}
|
||||
rand.Shuffle(len(buf), func(i, j int) {
|
||||
buf[i], buf[j] = buf[j], buf[i]
|
||||
})
|
||||
return string(buf)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:protobuf-gen=package
|
||||
// +k8s:openapi-gen=false
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=apps.sealyun.com
|
||||
|
||||
package v1beta1
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 v1beta1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "apps.sealyun.com"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||
|
||||
type Provider string
|
||||
|
||||
const (
|
||||
AliyunProvider Provider = "AliyunProvider"
|
||||
)
|
||||
|
||||
type Platform string
|
||||
|
||||
const (
|
||||
AMD64 Platform = "amd64"
|
||||
ARM64 Platform = "arm64"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
User string `json:"user,omitempty"`
|
||||
Passwd string `json:"passwd,omitempty"`
|
||||
}
|
||||
|
||||
type Hosts struct {
|
||||
CPU int `json:"cpu,omitempty"`
|
||||
Memory float64 `json:"memory,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Disks Disks `json:"disks"`
|
||||
}
|
||||
type Disks struct {
|
||||
System string `json:"system,omitempty"`
|
||||
Data []string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type Instance struct {
|
||||
SystemCategory string `json:"systemCategory,omitempty"`
|
||||
DataCategory string `json:"dataCategory,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
IsSeize bool `json:"isSeize,omitempty"`
|
||||
ImageID string `json:"imageID,omitempty"`
|
||||
}
|
||||
|
||||
// InfraSpec defines the desired state of Infra
|
||||
type InfraSpec struct {
|
||||
// INSERT ADDITIONAL SPEC FIELDS - desired state of Infra
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
Instance Instance `json:"instance"`
|
||||
// Foo is an example field of Infra. Edit types.go to remove/update
|
||||
Provider Provider `json:"provider,omitempty"`
|
||||
Platform Platform `json:"platform,omitempty"`
|
||||
|
||||
Auth Auth `json:"auth,omitempty"`
|
||||
Masters Hosts `json:"masters,omitempty"`
|
||||
Nodes *Hosts `json:"nodes,omitempty"`
|
||||
}
|
||||
|
||||
// InfraStatus defines the observed state of Infra
|
||||
type InfraStatus struct {
|
||||
ZoneID string `json:"zoneID,omitempty"`
|
||||
RegionID string `json:"regionID,omitempty"`
|
||||
|
||||
VpcID string `json:"vpcID,omitempty"`
|
||||
VSwitchID string `json:"vSwitchID,omitempty"`
|
||||
SecurityGroupID string `json:"securityGroupID,omitempty"`
|
||||
|
||||
Master0ID string `json:"master0ID,omitempty"`
|
||||
Master0InternalIP string `json:"master0InternalIP,omitempty"`
|
||||
EIP string `json:"eip,omitempty"`
|
||||
EIPID string `json:"eipID,omitempty"`
|
||||
|
||||
MasterIDs string `json:"masterIDs,omitempty"`
|
||||
NodeIDs string `json:"nodeIDs,omitempty"`
|
||||
|
||||
Masters []string `json:"masters,omitempty"`
|
||||
Nodes []string `json:"nodes,omitempty"`
|
||||
|
||||
MasterInstanceType string `json:"masterInstanceType,omitempty"`
|
||||
NodeInstanceType string `json:"nodeInstanceType,omitempty"`
|
||||
|
||||
SpotStrategy string `json:"spotStrategy,omitempty"`
|
||||
ShouldBeDeleteInstancesIDs string `json:"shouldBeDeleteInstancesIDs,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Infra is the Schema for the Infras API
|
||||
type Infra struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec InfraSpec `json:"spec,omitempty"`
|
||||
Status InfraStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// InfraList contains a list of Infra
|
||||
type InfraList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Infra `json:"items"`
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Auth) DeepCopyInto(out *Auth) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth.
|
||||
func (in *Auth) DeepCopy() *Auth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Auth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Disks) DeepCopyInto(out *Disks) {
|
||||
*out = *in
|
||||
if in.Data != nil {
|
||||
in, out := &in.Data, &out.Data
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Disks.
|
||||
func (in *Disks) DeepCopy() *Disks {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Disks)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Hosts) DeepCopyInto(out *Hosts) {
|
||||
*out = *in
|
||||
in.Disks.DeepCopyInto(&out.Disks)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Hosts.
|
||||
func (in *Hosts) DeepCopy() *Hosts {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Hosts)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Infra) DeepCopyInto(out *Infra) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Infra.
|
||||
func (in *Infra) DeepCopy() *Infra {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Infra)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Infra) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InfraList) DeepCopyInto(out *InfraList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Infra, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraList.
|
||||
func (in *InfraList) DeepCopy() *InfraList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(InfraList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *InfraList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InfraSpec) DeepCopyInto(out *InfraSpec) {
|
||||
*out = *in
|
||||
out.Instance = in.Instance
|
||||
out.Auth = in.Auth
|
||||
in.Masters.DeepCopyInto(&out.Masters)
|
||||
if in.Nodes != nil {
|
||||
in, out := &in.Nodes, &out.Nodes
|
||||
*out = new(Hosts)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraSpec.
|
||||
func (in *InfraSpec) DeepCopy() *InfraSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(InfraSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InfraStatus) DeepCopyInto(out *InfraStatus) {
|
||||
*out = *in
|
||||
if in.Masters != nil {
|
||||
in, out := &in.Masters, &out.Masters
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Nodes != nil {
|
||||
in, out := &in.Nodes, &out.Nodes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraStatus.
|
||||
func (in *InfraStatus) DeepCopy() *InfraStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(InfraStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Instance) DeepCopyInto(out *Instance) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance.
|
||||
func (in *Instance) DeepCopy() *Instance {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Instance)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 validation
|
||||
|
||||
import (
|
||||
"github.com/fanux/sealos/pkg/types/v1beta1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// ValidateInfraName validates that the given name can be used as a infra name.
|
||||
var ValidateInfraName = apimachineryvalidation.NameIsDNSSubdomain
|
||||
|
||||
func validateHosts(hosts *v1beta1.Hosts, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
if hosts.Count == 0 {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Key("count"), hosts.Count,
|
||||
"hosts count not set"))
|
||||
}
|
||||
if hosts.CPU == 0 {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Key("cpu"), hosts.Count,
|
||||
"hosts cpu not set"))
|
||||
}
|
||||
if hosts.Memory == 0 {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Key("memory"), hosts.Count,
|
||||
"hosts memory not set"))
|
||||
}
|
||||
if len(hosts.Disks.System) == 0 {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Child("disks").Key("system"), hosts.Count,
|
||||
"hosts system disk not set"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func ValidateInfra(infra *v1beta1.Infra) field.ErrorList {
|
||||
allErrors := apimachineryvalidation.ValidateObjectMeta(&infra.ObjectMeta, false, ValidateInfraName, field.NewPath("metadata"))
|
||||
allErrors = append(allErrors, validateInfraSpec(&infra.Spec, field.NewPath("spec"))...)
|
||||
return allErrors
|
||||
}
|
||||
func validateInfraSpec(spec *v1beta1.InfraSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
|
||||
allErrors = append(allErrors, validateHosts(&spec.Masters, fldPath.Child("masters"))...)
|
||||
|
||||
if spec.Nodes != nil {
|
||||
allErrors = append(allErrors, validateHosts(spec.Nodes, fldPath.Child("nodes"))...)
|
||||
}
|
||||
|
||||
switch spec.Platform {
|
||||
case v1beta1.ARM64:
|
||||
case v1beta1.AMD64:
|
||||
default:
|
||||
allErrors = append(allErrors, field.Invalid(fldPath.Key("platform"), spec.Platform,
|
||||
"spec platform not support"))
|
||||
}
|
||||
|
||||
return allErrors
|
||||
}
|
||||
func ValidateInfraUpdate(infra, oldInfra *v1beta1.Infra) field.ErrorList {
|
||||
allErrs := apimachineryvalidation.ValidateObjectMetaUpdate(&infra.ObjectMeta, &oldInfra.ObjectMeta, field.NewPath("metadata"))
|
||||
newInfraClone := infra.DeepCopy()
|
||||
if newInfraClone.Spec.Provider != oldInfra.Spec.Provider {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Key("provider"), "fields can't modify are forbidden"))
|
||||
}
|
||||
if newInfraClone.Spec.Platform != oldInfra.Spec.Platform {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Key("platform"), "fields can't modify are forbidden"))
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(newInfraClone.Spec.Auth, oldInfra.Spec.Auth) {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Key("auth"), "fields can't modify are forbidden"))
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(newInfraClone.Spec.Masters.Disks, oldInfra.Spec.Masters.Disks) {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Child("masters").Key("disks"), "fields can't modify are forbidden"))
|
||||
}
|
||||
if newInfraClone.Spec.Nodes != nil && oldInfra.Spec.Nodes != nil {
|
||||
if !apiequality.Semantic.DeepEqual(newInfraClone.Spec.Nodes.Disks, oldInfra.Spec.Nodes.Disks) {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Child("nodes").Key("disks"), "fields can't modify are forbidden"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
+6
-10
@@ -17,13 +17,11 @@ package utils
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
)
|
||||
|
||||
const md5sumCmd = "md5sum %s | cut -d\" \" -f1"
|
||||
|
||||
func FromLocal(localPath string) string {
|
||||
func Md5File(localPath string) string {
|
||||
cmd := fmt.Sprintf(md5sumCmd, localPath)
|
||||
return BashEval(cmd)
|
||||
}
|
||||
@@ -37,13 +35,11 @@ func UserHomeDir() string {
|
||||
return home
|
||||
}
|
||||
|
||||
func FileExist(filename string) bool {
|
||||
_, err := os.Stat(filename)
|
||||
if !os.IsNotExist(err) {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
logger.Warn(err)
|
||||
func FileExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil || os.IsExist(err) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
)
|
||||
|
||||
type HostFile struct {
|
||||
Path string
|
||||
Hosts map[string]*Hostname
|
||||
}
|
||||
|
||||
type Hostname struct {
|
||||
Comment string
|
||||
Domain string
|
||||
IP string
|
||||
}
|
||||
|
||||
func NewHostname(comment string, domain string, ip string) *Hostname {
|
||||
return &Hostname{comment, domain, ip}
|
||||
}
|
||||
func (h *HostFile) Add(host *Hostname) {
|
||||
if h.Hosts == nil {
|
||||
h.Hosts = make(map[string]*Hostname)
|
||||
}
|
||||
h.Hosts[host.Domain] = host
|
||||
}
|
||||
|
||||
func (h *HostFile) Delete(host string) {
|
||||
delete(h.Hosts, host)
|
||||
}
|
||||
|
||||
func getHostPath() string {
|
||||
path := os.Getenv("GOHOST_FILE")
|
||||
if path == "" {
|
||||
path = "/etc/hosts"
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (h *Hostname) toString() string {
|
||||
if len(h.Comment) > 0 {
|
||||
h.Comment += "\n"
|
||||
}
|
||||
return h.Comment + h.IP + " " + h.Domain + "\n"
|
||||
}
|
||||
func appendToFile(filePath string, hostname *Hostname) {
|
||||
fp, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
logger.Warn("failed opening file %s : %s\n", filePath, err)
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
_, err = fp.WriteString(hostname.toString())
|
||||
if err != nil {
|
||||
logger.Warn("failed append string: %s: %s\n", filePath, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostFile) ParseHostFile(path string) (map[string]*Hostname, error) {
|
||||
if !FileExist(path) {
|
||||
logger.Warn("path %s is not exists", path)
|
||||
return nil, errors.New("path %s is not exists")
|
||||
}
|
||||
|
||||
fp, fpErr := os.Open(path)
|
||||
if fpErr != nil {
|
||||
logger.Warn("open file '%s' failed\n", path)
|
||||
return nil, fmt.Errorf("open file '%s' failed ", path)
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
br := bufio.NewReader(fp)
|
||||
hostnameMap := make(map[string]*Hostname)
|
||||
curComment := ""
|
||||
for {
|
||||
str, rErr := br.ReadString('\n')
|
||||
if rErr == io.EOF {
|
||||
break
|
||||
}
|
||||
if len(str) == 0 || str == "\r\n" || IsEmptyLine(str) {
|
||||
continue
|
||||
}
|
||||
|
||||
if str[0] == '#' {
|
||||
// 处理注释
|
||||
curComment += str
|
||||
continue
|
||||
}
|
||||
tmpHostnameArr := strings.Fields(str)
|
||||
curDomain := TrimWS(tmpHostnameArr[1])
|
||||
if !CheckDomain(curDomain) {
|
||||
return hostnameMap, errors.New(" file contain error domain" + curDomain)
|
||||
}
|
||||
curIP := TrimWS(tmpHostnameArr[0])
|
||||
checkIP := CheckIP(curIP)
|
||||
if !checkIP {
|
||||
return hostnameMap, nil
|
||||
}
|
||||
tmpHostname := NewHostname(curComment, curDomain, curIP)
|
||||
hostnameMap[tmpHostname.Domain] = tmpHostname
|
||||
|
||||
curComment = ""
|
||||
}
|
||||
|
||||
return hostnameMap, nil
|
||||
}
|
||||
|
||||
func (h *HostFile) AppendHost(domain string, ip string) {
|
||||
if domain == "" || ip == "" {
|
||||
return
|
||||
}
|
||||
|
||||
hostname := NewHostname("", domain, ip)
|
||||
appendToFile(getHostPath(), hostname)
|
||||
}
|
||||
|
||||
func (h *HostFile) writeToFile(hostnameMap map[string]*Hostname, path string) {
|
||||
if !FileExist(path) {
|
||||
logger.Warn("path %s is not exists", path)
|
||||
return
|
||||
}
|
||||
|
||||
fp, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
logger.Warn("open file '%s' failed: %v", path, err)
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
for _, mapVal := range hostnameMap {
|
||||
_, writeErr := fp.WriteString(mapVal.toString())
|
||||
if writeErr != nil {
|
||||
logger.Warn(writeErr)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HostFile) DeleteDomain(domain string) {
|
||||
if domain == "" {
|
||||
return
|
||||
}
|
||||
|
||||
currHostsMap, parseErr := h.ParseHostFile(getHostPath())
|
||||
if parseErr != nil {
|
||||
logger.Warn("parse file failed" + parseErr.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(currHostsMap) == 0 || currHostsMap[domain] == nil {
|
||||
logger.Warn("domain %s not exist\n", domain)
|
||||
return
|
||||
}
|
||||
|
||||
delete(currHostsMap, domain)
|
||||
h.writeToFile(currHostsMap, getHostPath())
|
||||
}
|
||||
|
||||
func (h *HostFile) ListCurrentHosts() {
|
||||
currHostsMap, parseErr := h.ParseHostFile(getHostPath())
|
||||
if parseErr != nil {
|
||||
logger.Warn("parse file failed" + parseErr.Error())
|
||||
return
|
||||
}
|
||||
if len(currHostsMap) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, mapVal := range currHostsMap {
|
||||
fmt.Println(mapVal.toString())
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ func DownloadFile(location string) (filePATH, md5 string) {
|
||||
location = absPATH
|
||||
}
|
||||
//file md5
|
||||
md5 = FromLocal(location)
|
||||
md5 = Md5File(location)
|
||||
return location, md5
|
||||
}
|
||||
|
||||
|
||||
+28
-13
@@ -20,7 +20,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/fanux/sealos/pkg/utils/logger"
|
||||
@@ -87,24 +87,34 @@ func AssemblyIPList(args *string) error {
|
||||
*args = result
|
||||
return nil
|
||||
}
|
||||
func CheckIP(i string) bool {
|
||||
if !strings.Contains(i, ":") {
|
||||
return net.ParseIP(i) != nil
|
||||
}
|
||||
if _, err := net.ResolveTCPAddr("tcp", i); err != nil {
|
||||
func CheckIP(ipStr string) bool {
|
||||
host, _, err := net.SplitHostPort(ipStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
ip := net.ParseIP(host)
|
||||
if _, err = net.ResolveTCPAddr("tcp", ipStr); err != nil {
|
||||
return false
|
||||
}
|
||||
return ip != nil
|
||||
}
|
||||
|
||||
//IPFormat is
|
||||
func IPFormat(host string) string {
|
||||
ipAndPort := strings.Split(host, ":")
|
||||
if len(ipAndPort) != 2 {
|
||||
logger.Error("invalied host fomat [%s], must like 172.0.0.2:22", host)
|
||||
os.Exit(1)
|
||||
func IPFormat(ipStr string) string {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
host, _, err := net.SplitHostPort(ipStr)
|
||||
if err != nil {
|
||||
logger.Error("invalied host fomat [%s], must like 172.0.0.2:22.error: %s", ipStr, err)
|
||||
return ""
|
||||
}
|
||||
ip = net.ParseIP(host)
|
||||
}
|
||||
return ipAndPort[0]
|
||||
if ip == nil {
|
||||
logger.Error("invalied host fomat [%s], must like 172.0.0.2:22", ipStr)
|
||||
return ""
|
||||
}
|
||||
return ip.String()
|
||||
}
|
||||
|
||||
func HostnameAndIP(node []string) ([]string, []string) {
|
||||
@@ -166,3 +176,8 @@ func RemoveDeduplicate(a []string) []string {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func CheckDomain(domain string) bool {
|
||||
_, errURL := url.Parse(domain)
|
||||
return errURL == nil
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ func (c *connLogger) Init(jsonConfig string) error {
|
||||
if len(jsonConfig) == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("consoleWriter Init:%s\n", jsonConfig)
|
||||
err := json.Unmarshal([]byte(jsonConfig), c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -16,7 +16,6 @@ package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
@@ -59,7 +58,6 @@ func (c *consoleLogger) Init(jsonConfig string) error {
|
||||
if len(jsonConfig) == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("consoleWriter Init:%s\n", jsonConfig)
|
||||
err := json.Unmarshal([]byte(jsonConfig), c)
|
||||
if runtime.GOOS == "windows" {
|
||||
c.Colorful = false
|
||||
|
||||
@@ -153,7 +153,7 @@ func (r *LocalLogger) SetLogger(adapterName string, configs ...string) error {
|
||||
}
|
||||
|
||||
config := append(configs, "{}")[0]
|
||||
var num int = -1
|
||||
var num = -1
|
||||
var i int
|
||||
var l *nameLogger
|
||||
for i, l = range r.outputs {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright © 2021 Alibaba Group Holding 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.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Retry(tryTimes int, trySleepTime time.Duration, action func() error) error {
|
||||
var err error
|
||||
for i := 0; i < tryTimes; i++ {
|
||||
err = action()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
time.Sleep(trySleepTime * time.Duration(2*i+1))
|
||||
}
|
||||
return fmt.Errorf("retry action timeout: %v", err)
|
||||
}
|
||||
@@ -39,7 +39,7 @@ func (ss *SSH) CopyForMD5(host, localFilePath, remoteFilePath, md5 string) bool
|
||||
//如果有md5则可以验证
|
||||
//如果没有md5则拿到本地数据后验证
|
||||
if md5 == "" {
|
||||
md5 = utils.FromLocal(localFilePath)
|
||||
md5 = utils.Md5File(localFilePath)
|
||||
}
|
||||
logger.Debug("[ssh]source file md5 value is %s", md5)
|
||||
ss.Copy(host, localFilePath, remoteFilePath)
|
||||
@@ -362,7 +362,7 @@ func (ss *SSH) copyLocalFileToRemote(host string, sshClient *ssh.Client, sftpCli
|
||||
|
||||
func (ss *SSH) isCopyMd5Success(sshClient *ssh.Client, localFile, remoteFile string) bool {
|
||||
cmd := fmt.Sprintf("md5sum %s | cut -d\" \" -f1", remoteFile)
|
||||
localMd5 := utils.FromLocal(localFile)
|
||||
localMd5 := utils.Md5File(localFile)
|
||||
sshSession, err := sshClient.NewSession()
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -399,7 +399,7 @@ func (ss *SSH) isCopyMd5Success(sshClient *ssh.Client, localFile, remoteFile str
|
||||
}
|
||||
|
||||
func (ss *SSH) ValidateMd5sumLocalWithRemote(host, localFile, remoteFile string) bool {
|
||||
localMd5 := utils.FromLocal(localFile)
|
||||
localMd5 := utils.Md5File(localFile)
|
||||
return localMd5 == ss.Md5Sum(host, remoteFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
package ssh
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type SSH struct {
|
||||
User string
|
||||
|
||||
+12
-1
@@ -20,6 +20,7 @@ import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"net"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -110,7 +111,7 @@ func ContainList(list []string, toComplete string) (containerList []string) {
|
||||
|
||||
// RandString 生成随机字符串
|
||||
func RandString(len int) string {
|
||||
var r *rand.Rand = rand.New(rand.NewSource(time.Now().Unix()))
|
||||
var r = rand.New(rand.NewSource(time.Now().Unix()))
|
||||
bytes := make([]byte, len)
|
||||
for i := 0; i < len; i++ {
|
||||
b := r.Intn(26) + 65
|
||||
@@ -118,3 +119,13 @@ func RandString(len int) string {
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func IsEmptyLine(str string) bool {
|
||||
re := regexp.MustCompile(`^\s*$`)
|
||||
|
||||
return re.MatchString(str)
|
||||
}
|
||||
|
||||
func TrimWS(str string) string {
|
||||
return strings.Trim(str, " \n\t")
|
||||
}
|
||||
|
||||
@@ -108,3 +108,33 @@ func VersionToIntAll(version string) int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//VersionCompare is version compare
|
||||
// if v1 >= v2 return true, else return false
|
||||
func VersionCompare(v1, v2 string) bool {
|
||||
v1 = strings.Replace(v1, "v", "", -1)
|
||||
v2 = strings.Replace(v2, "v", "", -1)
|
||||
v1 = strings.Split(v1, "-")[0]
|
||||
v2 = strings.Split(v2, "-")[0]
|
||||
v1List := strings.Split(v1, ".")
|
||||
v2List := strings.Split(v2, ".")
|
||||
|
||||
if len(v1List) != 3 || len(v2List) != 3 {
|
||||
logger.Error("error version format %s %s", v1, v2)
|
||||
return false
|
||||
}
|
||||
if v1List[0] > v2List[0] {
|
||||
return true
|
||||
} else if v1List[0] < v2List[0] {
|
||||
return false
|
||||
}
|
||||
if v1List[1] > v2List[1] {
|
||||
return true
|
||||
} else if v1List[1] < v2List[1] {
|
||||
return false
|
||||
}
|
||||
if v1List[2] > v2List[2] {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 version
|
||||
|
||||
// Base version information.
|
||||
//
|
||||
// This is the fallback data used when version information from git is not
|
||||
// provided via go ldflags. It provides an approximation of the Kubernetes
|
||||
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
|
||||
// information from git.
|
||||
//
|
||||
// If you are looking at these fields in the git tree, they look
|
||||
// strange. They are modified on the fly by the build process. The
|
||||
// in-tree values are dummy values used for "git archive", which also
|
||||
// works for GitHub tar downloads.
|
||||
//
|
||||
// When releasing a new Kubernetes version, this file is updated by
|
||||
// build/mark_new_version.sh to reflect the new version, and then a
|
||||
// git annotated tag (using format vX.Y where X == Major version and Y
|
||||
// == Minor version) is created to point to the commit that updates
|
||||
// component-base/version/base.go
|
||||
var (
|
||||
// semantic version, derived by build scripts (see
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/release/versioning.md
|
||||
// for a detailed discussion of this field)
|
||||
//
|
||||
// TODO: This field is still called "gitVersion" for legacy
|
||||
// reasons. For prerelease versions, the build metadata on the
|
||||
// semantic version is a git hash, but the version itself is no
|
||||
// longer the direct output of "git describe", but a slight
|
||||
// translation to be semver compliant.
|
||||
|
||||
// NOTE: The $Format strings are replaced during 'git archive' thanks to the
|
||||
// companion .gitattributes file containing 'export-subst' in this same
|
||||
// directory. See also https://git-scm.com/docs/gitattributes
|
||||
gitVersion = "latest"
|
||||
gitCommit = "" // sha1 from git, output of $(git rev-parse HEAD)
|
||||
|
||||
buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 version
|
||||
|
||||
// Info contains versioning information.
|
||||
// TODO: Add []string of api versions supported? It's still unclear
|
||||
// how we'll want to distribute that information.
|
||||
type Info struct {
|
||||
GitVersion string `json:"gitVersion"`
|
||||
GitCommit string `json:"gitCommit,omitempty"`
|
||||
BuildDate string `json:"buildDate"`
|
||||
GoVersion string `json:"goVersion"`
|
||||
Compiler string `json:"compiler"`
|
||||
Platform string `json:"platform"`
|
||||
}
|
||||
|
||||
// String returns info as a human-friendly version string.
|
||||
func (info Info) String() string {
|
||||
return info.GitVersion
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright © 2021 sealos.
|
||||
//
|
||||
// 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 version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Get returns the overall codebase version. It's for detecting
|
||||
// what code a binary was built from.
|
||||
func Get() Info {
|
||||
// These variables typically come from -ldflags settings and in
|
||||
// their absence fallback to the settings in ./base.go
|
||||
return Info{
|
||||
GitVersion: gitVersion,
|
||||
GitCommit: gitCommit,
|
||||
BuildDate: buildDate,
|
||||
GoVersion: runtime.Version(),
|
||||
Compiler: runtime.Compiler,
|
||||
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user