diff --git a/bcs-services/bcs-cluster-manager/go.mod b/bcs-services/bcs-cluster-manager/go.mod index 52caec7f11..250213a7b2 100644 --- a/bcs-services/bcs-cluster-manager/go.mod +++ b/bcs-services/bcs-cluster-manager/go.mod @@ -43,20 +43,20 @@ require ( github.com/kirito41dd/xslice v0.0.1 github.com/micro/go-micro/v2 v2.9.1 github.com/parnurzeal/gorequest v0.2.16 - github.com/prometheus/client_golang v1.11.0 + github.com/prometheus/client_golang v1.14.0 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/as v1.0.398 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.768 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.376 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.0.544 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc v1.0.714 go.mongodb.org/mongo-driver v1.5.3 - google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 - google.golang.org/grpc v1.46.0 + google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 + google.golang.org/grpc v1.49.0 google.golang.org/protobuf v1.28.1 gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 - k8s.io/api v0.23.1 - k8s.io/apimachinery v0.23.1 + k8s.io/api v0.26.1 + k8s.io/apimachinery v0.26.1 k8s.io/client-go v11.0.0+incompatible k8s.io/kubectl v0.0.0-00010101000000-000000000000 ) @@ -69,13 +69,15 @@ require ( require ( github.com/Tencent/bk-bcs/bcs-common/pkg/i18n v0.0.0-20230908142111-fef103db0120 github.com/apparentlymart/go-cidr v1.1.0 + github.com/aws/aws-sdk-go v1.44.312 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag v1.0.768 - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b google.golang.org/api v0.44.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/apiextensions-apiserver v0.20.0 + sigs.k8s.io/aws-iam-authenticator v0.6.7 ) require ( @@ -93,48 +95,45 @@ require ( github.com/BurntSushi/toml v1.1.0 // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect github.com/Tencent/bk-bcs/bcs-runtime/bcs-k8s/kubernetes/common v0.0.0-20220330120237-0bbed74dcf6d // indirect github.com/TencentBlueKing/bk-audit-go-sdk v0.0.5 // indirect github.com/TencentBlueKing/crypto-golang-sdk v1.0.0 // indirect github.com/TencentBlueKing/iam-go-sdk v0.0.8 // indirect - github.com/aws/aws-sdk-go v1.37.27 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bitly/go-simplejson v0.5.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/cloudflare/circl v1.2.0 // indirect github.com/coreos/bbolt v1.3.4 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.11.2 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-stack/stack v1.8.0 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gomodule/redigo v2.0.0+incompatible // indirect github.com/google/btree v1.0.1 // indirect - github.com/google/go-cmp v0.5.7 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/gax-go/v2 v2.0.5 // indirect @@ -142,7 +141,7 @@ require ( github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -157,13 +156,13 @@ require ( github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattbaird/jsonpatch v0.0.0-20200820163806-098863c1fc24 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect github.com/miekg/dns v1.1.50 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/mitchellh/hashstructure v1.1.0 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect + github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect @@ -173,15 +172,15 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.28.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/russross/blackfriday v1.5.2 // indirect github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect - github.com/spf13/cobra v1.2.1 // indirect + github.com/spf13/cobra v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/streadway/amqp v1.0.0 // indirect github.com/stretchr/testify v1.8.4 // indirect @@ -200,27 +199,26 @@ require ( go.uber.org/zap v1.19.0 // indirect golang.org/x/crypto v0.5.0 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/net v0.5.0 // indirect golang.org/x/sync v0.0.0-20220907140024-f12130a52804 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/term v0.4.0 // indirect - golang.org/x/text v0.6.0 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/cli-runtime v0.23.1 // indirect - k8s.io/component-base v0.23.1 // indirect + k8s.io/component-base v0.25.0-alpha.0 // indirect k8s.io/klog v1.0.0 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect - k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect moul.io/http2curl v1.0.0 // indirect - sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/kustomize/api v0.10.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/eks.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/eks.go new file mode 100644 index 0000000000..81e6655b3d --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/eks.go @@ -0,0 +1,71 @@ +package api + +import ( + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/eks" +) + +// EksClient eks client +type EksClient struct { + *eks.EKS + Session *session.Session +} + +// NewEksClient init Eks client +func NewEksClient(opt *cloudprovider.CommonOption) (*EksClient, error) { + if opt == nil || opt.Account == nil || len(opt.Account.SecretID) == 0 || len(opt.Account.SecretKey) == 0 { + return nil, cloudprovider.ErrCloudCredentialLost + } + if len(opt.Region) == 0 { + return nil, cloudprovider.ErrCloudRegionLost + } + + awsConf := &aws.Config{} + awsConf.Region = aws.String(opt.Region) + awsConf.Credentials = credentials.NewStaticCredentials(opt.Account.SecretID, opt.Account.SecretKey, "") + + sess, err := session.NewSession(awsConf) + if err != nil { + return nil, err + } + + return &EksClient{ + Session: sess, + EKS: eks.New(sess), + }, nil +} + +// ListEksCluster get tke cluster list, region parameter init tke client +func (cli *EksClient) ListEksCluster() ([]*string, error) { + if cli == nil { + return nil, cloudprovider.ErrServerIsNil + } + + input := &eks.ListClustersInput{} + output, err := cli.ListClusters(input) + if err != nil { + return nil, err + } + + return output.Clusters, nil +} + +// GetEksCluster get eks cluster +func (cli *EksClient) GetEksCluster(clusterName string) (*eks.Cluster, error) { + if cli == nil { + return nil, cloudprovider.ErrServerIsNil + } + + input := &eks.DescribeClusterInput{ + Name: aws.String(clusterName), + } + output, err := cli.DescribeCluster(input) + if err != nil { + return nil, err + } + + return output.Cluster, nil +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/node.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/node.go new file mode 100644 index 0000000000..6f7b98d97c --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/node.go @@ -0,0 +1,139 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 api + +import ( + "sync" + + "github.com/Tencent/bk-bcs/bcs-common/common/blog" + proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" +) + +const ( + defaultRegion = "ap-northeast-1" +) + +var nodeMgr sync.Once + +func init() { + nodeMgr.Do(func() { + // init Node + cloudprovider.InitNodeManager("aws", &NodeManager{}) + }) +} + +// GetEc2Client get ec2 client from common option +func GetEc2Client(opt *cloudprovider.CommonOption) (*ec2.EC2, error) { + if opt == nil || len(opt.Account.SecretID) == 0 || len(opt.Account.SecretKey) == 0 { + return nil, cloudprovider.ErrCloudCredentialLost + } + + if len(opt.Region) == 0 { + return nil, cloudprovider.ErrCloudRegionLost + } + + awsConf := &aws.Config{Region: &opt.Region} + awsConf.Credentials = credentials.NewStaticCredentials(opt.Account.SecretID, opt.Account.SecretKey, "") + + sess, err := session.NewSession(awsConf) + if err != nil { + return nil, err + } + + return ec2.New(sess), nil +} + +// NodeManager CVM relative API management +type NodeManager struct { +} + +// GetNodeByIP get specified Node by innerIP address +func (nm *NodeManager) GetNodeByIP(ip string, opt *cloudprovider.GetNodeOption) (*proto.Node, error) { + return nil, nil +} + +// ListNodesByIP list node by IP set +func (nm *NodeManager) ListNodesByIP(ips []string, opt *cloudprovider.ListNodesOption) ([]*proto.Node, error) { + return nil, nil +} + +// GetCVMImageIDByImageName get imageID by imageName +func (nm *NodeManager) GetCVMImageIDByImageName(imageName string, opt *cloudprovider.CommonOption) (string, error) { + return "", nil +} + +// GetCloudRegions get cloud regions +func (nm *NodeManager) GetCloudRegions(opt *cloudprovider.CommonOption) ([]*proto.RegionInfo, error) { + //set default region + opt.Region = defaultRegion + + client, err := GetEc2Client(opt) + if err != nil { + blog.Errorf("create ec2 client when GetRegionsInfo failed: %v", err) + return nil, err + } + + output, err := client.DescribeRegions(&ec2.DescribeRegionsInput{}) + if err != nil { + blog.Errorf("ec2 client DescribeRegions failed: %v", err) + return nil, err + } + + regions := make([]*proto.RegionInfo, 0) + for _, v := range output.Regions { + regions = append(regions, &proto.RegionInfo{ + Region: aws.StringValue(v.RegionName), + RegionName: aws.StringValue(v.RegionName), + RegionState: aws.StringValue(v.OptInStatus), + }) + } + + return regions, nil +} + +// GetZoneList get zoneList by region +func (nm *NodeManager) GetZoneList(opt *cloudprovider.CommonOption) ([]*proto.ZoneInfo, error) { + return nil, nil +} + +// ListNodeInstanceType list node type by zone and node family +func (nm *NodeManager) ListNodeInstanceType(info cloudprovider.InstanceInfo, opt *cloudprovider.CommonOption) ( + []*proto.InstanceType, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// GetExternalNodeByIP get specified Node by innerIP address +func (nm *NodeManager) GetExternalNodeByIP(ip string, opt *cloudprovider.GetNodeOption) (*proto.Node, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// ListExternalNodesByIP list node by IP set +func (nm *NodeManager) ListExternalNodesByIP(ips []string, opt *cloudprovider.ListNodesOption) ([]*proto.Node, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// ListOsImage get osimage list +func (nm *NodeManager) ListOsImage(provider string, opt *cloudprovider.CommonOption) ([]*proto.OsImage, error) { + return nil, nil +} + +// ListKeyPairs keyPairs list +func (nm *NodeManager) ListKeyPairs(opt *cloudprovider.CommonOption) ([]*proto.KeyPair, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/utils.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/utils.go new file mode 100644 index 0000000000..5021e4bbdb --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/utils.go @@ -0,0 +1,98 @@ +package api + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "net" + "time" + + cutils "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider/utils" + + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/types" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/eks" + "k8s.io/client-go/rest" + "sigs.k8s.io/aws-iam-authenticator/pkg/token" +) + +// GetClusterKubeConfig get eks cluster kebeconfig +func GetClusterKubeConfig(sess *session.Session, cluster *eks.Cluster) (string, error) { + generator, err := token.NewGenerator(false, false) + if err != nil { + return "", err + } + + awsToken, err := generator.GetWithOptions(&token.GetTokenOptions{ + Session: sess, + ClusterID: aws.StringValue(cluster.Name), + }) + if err != nil { + return "", err + } + + decodedCA, err := base64.StdEncoding.DecodeString(aws.StringValue(cluster.CertificateAuthority.Data)) + if err != nil { + return "", fmt.Errorf("GetClusterKubeConfig invalid certificate failed, cluster=%s: %w", + aws.StringValue(cluster.Name), err) + } + + restConfig := &rest.Config{ + Host: aws.StringValue(cluster.Endpoint), + TLSClientConfig: rest.TLSClientConfig{ + CAData: decodedCA, + }, + BearerToken: awsToken.Token, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + } + + saToken, err := cutils.GenerateSATokenByRestConfig(context.Background(), restConfig) + if err != nil { + return "", fmt.Errorf("getClusterKubeConfig generate k8s serviceaccount token failed,cluster=%s: %w", + aws.StringValue(cluster.Name), err) + } + + typesConfig := &types.Config{ + APIVersion: "v1", + Kind: "Config", + Clusters: []types.NamedCluster{ + { + Name: aws.StringValue(cluster.Name), + Cluster: types.ClusterInfo{ + Server: aws.StringValue(cluster.Endpoint), + CertificateAuthorityData: decodedCA, + }, + }, + }, + AuthInfos: []types.NamedAuthInfo{ + { + Name: aws.StringValue(cluster.Name), + AuthInfo: types.AuthInfo{ + Token: saToken, + }, + }, + }, + Contexts: []types.NamedContext{ + { + Name: aws.StringValue(cluster.Name), + Context: types.Context{ + Cluster: aws.StringValue(cluster.Name), + AuthInfo: aws.StringValue(cluster.Name), + }, + }, + }, + CurrentContext: aws.StringValue(cluster.Name), + } + + configByte, err := json.Marshal(typesConfig) + if err != nil { + return "", fmt.Errorf("GetClusterKubeConfig marsh kubeconfig failed, %v", err) + } + + return base64.StdEncoding.EncodeToString(configByte), nil +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/vpc.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/vpc.go new file mode 100644 index 0000000000..1bfe1d5b13 --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api/vpc.go @@ -0,0 +1,96 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 api + +import ( + "fmt" + "strings" + "sync" + + proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" +) + +var vpcMgr sync.Once + +func init() { + vpcMgr.Do(func() { + // init VPC manager + cloudprovider.InitVPCManager("aws", &VPCManager{}) + }) +} + +// VPCManager is the manager for VPC +type VPCManager struct{} + +// ListVpcs list vpcs +func (vm *VPCManager) ListVpcs(vpcID string, opt *cloudprovider.CommonOption) ([]*proto.CloudVpc, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// ListSubnets list vpc subnets +func (vm *VPCManager) ListSubnets(vpcID string, opt *cloudprovider.CommonOption) ([]*proto.Subnet, error) { + locationList := strings.Split(opt.Region, "-") + if len(locationList) == 3 { + opt.Region = strings.Join(locationList[:2], "-") + } + + client, err := GetEc2Client(opt) + if err != nil { + return nil, fmt.Errorf("create google client failed, err %s", err.Error()) + } + output, err := client.DescribeSubnets(&ec2.DescribeSubnetsInput{}) + if err != nil { + return nil, fmt.Errorf("list regions failed, err %s", err.Error()) + } + + result := make([]*proto.Subnet, 0) + for _, v := range output.Subnets { + subnet := &proto.Subnet{ + VpcID: aws.StringValue(v.VpcId), + SubnetID: aws.StringValue(v.SubnetId), + SubnetName: aws.StringValue(v.SubnetId), + CidrRange: aws.StringValue(v.CidrBlock), + Zone: aws.StringValue(v.AvailabilityZone), + } + + ipv6CidrBlocks := make([]string, 0) + for _, y := range v.Ipv6CidrBlockAssociationSet { + ipv6CidrBlocks = append(ipv6CidrBlocks, aws.StringValue(y.Ipv6CidrBlock)) + } + + if len(ipv6CidrBlocks) > 0 { + subnet.Ipv6CidrRange = strings.Join(ipv6CidrBlocks, ",") + } + + result = append(result, subnet) + } + return result, nil +} + +// ListSecurityGroups list security groups +func (vm *VPCManager) ListSecurityGroups(opt *cloudprovider.CommonOption) ([]*proto.SecurityGroup, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// GetCloudNetworkAccountType 查询用户网络类型 +func (vm *VPCManager) GetCloudNetworkAccountType(opt *cloudprovider.CommonOption) (*proto.CloudAccountType, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// ListBandwidthPacks list bandWidthPacks +func (vm *VPCManager) ListBandwidthPacks(opt *cloudprovider.CommonOption) ([]*proto.BandwidthPackageInfo, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cloud.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cloud.go new file mode 100644 index 0000000000..14b0c12975 --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cloud.go @@ -0,0 +1,108 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 aws + +import ( + "fmt" + "sync" + + cmproto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api" + + "github.com/aws/aws-sdk-go/service/eks" +) + +var cloudInfoMgr sync.Once + +func init() { + cloudInfoMgr.Do(func() { + // init Cluster + cloudprovider.InitCloudInfoManager(cloudName, &CloudInfoManager{}) + }) +} + +// CloudInfoManager management cluster info +type CloudInfoManager struct { +} + +// InitCloudClusterDefaultInfo init cluster defaultConfig +func (c *CloudInfoManager) InitCloudClusterDefaultInfo(cls *cmproto.Cluster, + opt *cloudprovider.InitClusterConfigOption) error { + return nil +} + +// SyncClusterCloudInfo get cluster cloudInfo by clusterID or kubeConfig +func (c *CloudInfoManager) SyncClusterCloudInfo(cls *cmproto.Cluster, + opt *cloudprovider.SyncClusterCloudInfoOption) error { + if c == nil || cls == nil { + return fmt.Errorf("%s SyncClusterCloudInfo request is empty", cloudName) + } + + if opt == nil || opt.Cloud == nil { + return fmt.Errorf("%s SyncClusterCloudInfo option is empty", cloudName) + } + + // get cloud cluster + + client, err := api.NewEksClient(opt.Common) + if err != nil { + return fmt.Errorf("New EKS Client failed: %v", err) + } + + cluster, err := client.GetEksCluster(opt.ImportMode.CloudID) + if err != nil { + return fmt.Errorf("Get EKS Cluster failed: %v", err) + } + cls.SystemID = *cluster.Name + cls.VpcID = *cluster.ResourcesVpcConfig.VpcId + + kubeConfig, err := api.GetClusterKubeConfig(client.Session, cluster) + if err != nil { + return fmt.Errorf("SyncClusterCloudInfo GetClusterKubeConfig failed: %v", err) + } + + cls.KubeConfig = kubeConfig + cls.SystemID = *cluster.Name + cls.VpcID = *cluster.ResourcesVpcConfig.VpcId + + // cluster cloud basic setting + clusterBasicSettingByEKS(cls, cluster) + + // cluster cloud network setting + clusterNetworkSettingByEKS(cls, cluster) + + return nil +} + +func clusterBasicSettingByEKS(cls *cmproto.Cluster, cluster *eks.Cluster) { + cls.ClusterBasicSettings = &cmproto.ClusterBasicSetting{ + Version: *cluster.Version, + VersionName: *cluster.Version, + } +} + +func clusterNetworkSettingByEKS(cls *cmproto.Cluster, cluster *eks.Cluster) { + if cluster.KubernetesNetworkConfig.ServiceIpv4Cidr != nil { + cls.NetworkSettings = &cmproto.NetworkSetting{ + ClusterIPv4CIDR: *cluster.KubernetesNetworkConfig.ServiceIpv4Cidr, + ServiceIPv4CIDR: *cluster.KubernetesNetworkConfig.ServiceIpv4Cidr, + } + } else if cluster.KubernetesNetworkConfig.ServiceIpv6Cidr != nil { + cls.NetworkSettings = &cmproto.NetworkSetting{ + ClusterIPv4CIDR: *cluster.KubernetesNetworkConfig.ServiceIpv6Cidr, + ServiceIPv4CIDR: *cluster.KubernetesNetworkConfig.ServiceIpv6Cidr, + } + } +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cluster.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cluster.go index 4b25d4bea2..0931b16370 100644 --- a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cluster.go +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/cluster.go @@ -14,8 +14,12 @@ package aws import ( + "fmt" + + "github.com/Tencent/bk-bcs/bcs-common/common/blog" proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/api" ) func init() { @@ -45,8 +49,37 @@ func (c *Cluster) DeleteVirtualCluster(cls *proto.Cluster, // ImportCluster import cluster according cloudprovider func (c *Cluster) ImportCluster(cls *proto.Cluster, opt *cloudprovider.ImportClusterOption) (*proto.Task, error) { - // call qcloud interface to create cluster - return nil, cloudprovider.ErrCloudNotImplemented + // call aws interface to create cluster + if cls == nil { + return nil, fmt.Errorf("qcloud ImportCluster cluster is empty") + } + + if opt == nil || opt.Cloud == nil { + return nil, fmt.Errorf("qcloud ImportCluster cluster opt or cloud is empty") + } + + if len(opt.Account.SecretID) == 0 || len(opt.Account.SecretKey) == 0 || len(opt.Region) == 0 { + return nil, fmt.Errorf("qcloud CreateCluster opt lost valid crendential info") + } + + mgr, err := cloudprovider.GetTaskManager(opt.Cloud.CloudProvider) + if err != nil { + blog.Errorf("get cloud %s TaskManager when ImportCluster %d failed, %s", + opt.Cloud.CloudID, cls.ClusterName, err.Error(), + ) + return nil, err + } + + // build import cluster task + task, err := mgr.BuildImportClusterTask(cls, opt) + if err != nil { + blog.Errorf("build ImportCluster task for cluster %s with cloudprovider %s failed, %s", + cls.ClusterName, cls.Provider, err.Error(), + ) + return nil, err + } + + return task, nil } // DeleteCluster delete kubenretes cluster according cloudprovider @@ -61,7 +94,29 @@ func (c *Cluster) GetCluster(cloudID string, opt *cloudprovider.GetClusterOption // ListCluster get cloud cluster list by region func (c *Cluster) ListCluster(opt *cloudprovider.ListClusterOption) ([]*proto.CloudClusterInfo, error) { - return nil, cloudprovider.ErrCloudNotImplemented + if opt == nil || len(opt.Account.SecretID) == 0 || len(opt.Account.SecretKey) == 0 || len(opt.Region) == 0 { + return nil, fmt.Errorf("qcloud ListCluster cluster lost operation") + } + + cli, err := api.NewEksClient(&opt.CommonOption) + if err != nil { + return nil, err + } + + clusters, err := cli.ListEksCluster() + if err != nil { + return nil, err + } + + cloudClusterList := make([]*proto.CloudClusterInfo, 0) + for _, v := range clusters { + cloudClusterList = append(cloudClusterList, &proto.CloudClusterInfo{ + ClusterID: *v, + ClusterName: *v, + }) + } + + return cloudClusterList, nil } // GetNodesInCluster get all nodes belong to cluster according cloudprovider @@ -82,8 +137,8 @@ func (c *Cluster) DeleteNodesFromCluster(cls *proto.Cluster, nodes []*proto.Node } // CheckClusterCidrAvailable check cluster CIDR nodesNum when add nodes -func (c *Cluster) CheckClusterCidrAvailable(cls *proto.Cluster, - opt *cloudprovider.CheckClusterCIDROption) (bool, error) { +func (c *Cluster) CheckClusterCidrAvailable(cls *proto.Cluster, opt *cloudprovider.CheckClusterCIDROption) (bool, + error) { if cls == nil || opt == nil { return true, nil } diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/nodegroup.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/nodegroup.go index ac716e6e56..3ebe99e06c 100644 --- a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/nodegroup.go +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/nodegroup.go @@ -21,14 +21,14 @@ func init() { cloudprovider.InitNodeGroupManager("aws", &NodeGroup{}) } -// NodeGroup nodegroup management for blueking resource pool solution +// NodeGroup management for blueking resource pool solution type NodeGroup struct { } // CreateNodeGroup create nodegroup by cloudprovider api, only create NodeGroup entity -func (ng *NodeGroup) CreateNodeGroup(group *proto.NodeGroup, - opt *cloudprovider.CreateNodeGroupOption) (*proto.Task, error) { - return nil, nil +func (ng *NodeGroup) CreateNodeGroup(group *proto.NodeGroup, opt *cloudprovider.CreateNodeGroupOption) (*proto.Task, + error) { + return nil, cloudprovider.ErrCloudNotImplemented } // DeleteNodeGroup delete nodegroup by cloudprovider api, all nodes belong to NodeGroup @@ -45,11 +45,12 @@ func (ng *NodeGroup) UpdateNodeGroup( } // GetNodesInGroup get all nodes belong to NodeGroup -func (ng *NodeGroup) GetNodesInGroup(group *proto.NodeGroup, opt *cloudprovider.CommonOption) ([]*proto.Node, error) { +func (ng *NodeGroup) GetNodesInGroup(group *proto.NodeGroup, opt *cloudprovider.CommonOption) ([]*proto.Node, + error) { return nil, cloudprovider.ErrCloudNotImplemented } -// GetNodesInGroupV2 get nodeGroup nodes by v2 version +// GetNodesInGroupV2 get all nodes belong to NodeGroup func (ng *NodeGroup) GetNodesInGroupV2(group *proto.NodeGroup, opt *cloudprovider.CommonOption) ([]*proto.NodeGroupNode, error) { return nil, cloudprovider.ErrCloudNotImplemented diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/taskmgr.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/taskmgr.go new file mode 100644 index 0000000000..6fe672ba99 --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/taskmgr.go @@ -0,0 +1,220 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 aws + +import ( + "fmt" + "sync" + "time" + + proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/tasks" + "github.com/google/uuid" +) + +var taskMgr sync.Once + +func init() { + taskMgr.Do(func() { + cloudprovider.InitTaskManager(cloudName, newtask()) + }) +} + +func newtask() *Task { + task := &Task{ + works: make(map[string]interface{}), + } + + // import task + task.works[importClusterNodesStep.StepMethod] = tasks.ImportClusterNodesTask + task.works[registerClusterKubeConfigStep.StepMethod] = tasks.RegisterClusterKubeConfigTask + + return task +} + +// Task eks cluster task struct +type Task struct { + works map[string]interface{} +} + +// Name get cloudName +func (t *Task) Name() string { + return cloudName +} + +// GetAllTask register all backgroup task for worker running +func (t *Task) GetAllTask() map[string]interface{} { + return t.works +} + +// BuildCreateVirtualClusterTask build create virtual cluster task +func (t *Task) BuildCreateVirtualClusterTask(cls *proto.Cluster, + opt *cloudprovider.CreateVirtualClusterOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildDeleteVirtualClusterTask build delete virtual cluster task +func (t *Task) BuildDeleteVirtualClusterTask(cls *proto.Cluster, + opt *cloudprovider.DeleteVirtualClusterOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildCreateClusterTask build create cluster task +func (t *Task) BuildCreateClusterTask(cls *proto.Cluster, opt *cloudprovider.CreateClusterOption) ( + *proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildImportClusterTask build import cluster task +func (t *Task) BuildImportClusterTask(cls *proto.Cluster, opt *cloudprovider.ImportClusterOption) ( + *proto.Task, error) { + // validate request params + if cls == nil { + return nil, fmt.Errorf("BuildImportClusterTask cluster info empty") + } + if opt == nil || opt.Cloud == nil { + return nil, fmt.Errorf("BuildImportClusterTask TaskOptions is lost") + } + + // init task information + nowStr := time.Now().Format(time.RFC3339) + task := &proto.Task{ + TaskID: uuid.New().String(), + TaskType: cloudprovider.GetTaskType(cloudName, cloudprovider.ImportCluster), + TaskName: cloudprovider.ImportClusterTask.String(), + Status: cloudprovider.TaskStatusInit, + Message: "task initializing", + Start: nowStr, + Steps: make(map[string]*proto.Step), + StepSequence: make([]string, 0), + ClusterID: cls.ClusterID, + ProjectID: cls.ProjectID, + Creator: opt.Operator, + Updater: opt.Operator, + LastUpdate: nowStr, + CommonParams: make(map[string]string), + ForceTerminate: false, + } + + // setting all steps details + importCluster := &ImportClusterTaskOption{Cluster: cls} + // step1: import cluster registerKubeConfigStep + importCluster.BuildRegisterKubeConfigStep(task) + // step2: import cluster nodes step + importCluster.BuildImportClusterNodesStep(task) + + // set current step + if len(task.StepSequence) == 0 { + return nil, fmt.Errorf("BuildImportClusterTask task StepSequence empty") + } + task.CurrentStep = task.StepSequence[0] + task.CommonParams[cloudprovider.OperatorKey.String()] = opt.Operator + task.CommonParams[cloudprovider.JobTypeKey.String()] = cloudprovider.ImportClusterJob.String() + + return task, nil +} + +// BuildDeleteClusterTask build deleteCluster task +func (t *Task) BuildDeleteClusterTask(cls *proto.Cluster, opt *cloudprovider.DeleteClusterOption) ( + *proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildAddNodesToClusterTask build addNodes task +func (t *Task) BuildAddNodesToClusterTask(cls *proto.Cluster, nodes []*proto.Node, + opt *cloudprovider.AddNodesOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildRemoveNodesFromClusterTask build removeNodes task +func (t *Task) BuildRemoveNodesFromClusterTask(cls *proto.Cluster, nodes []*proto.Node, + opt *cloudprovider.DeleteNodesOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildCreateNodeGroupTask build create node group task +func (t *Task) BuildCreateNodeGroupTask(group *proto.NodeGroup, opt *cloudprovider.CreateNodeGroupOption) ( + *proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildCleanNodesInGroupTask clean specified nodes in NodeGroup +// including remove nodes from NodeGroup, clean data in nodes +func (t *Task) BuildCleanNodesInGroupTask(nodes []*proto.Node, group *proto.NodeGroup, + opt *cloudprovider.CleanNodesOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildDeleteNodeGroupTask when delete nodegroup, we need to create background +// task to clean all nodes in nodegroup, release all resource in cloudprovider, +// finnally delete nodes information in local storage. +// @param group: need to delete +func (t *Task) BuildDeleteNodeGroupTask(group *proto.NodeGroup, nodes []*proto.Node, + opt *cloudprovider.DeleteNodeGroupOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildMoveNodesToGroupTask build move nodes to group task +func (t *Task) BuildMoveNodesToGroupTask(nodes []*proto.Node, group *proto.NodeGroup, + opt *cloudprovider.MoveNodesOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildUpdateDesiredNodesTask build update desired nodes task +func (t *Task) BuildUpdateDesiredNodesTask(desired uint32, group *proto.NodeGroup, + opt *cloudprovider.UpdateDesiredNodeOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildSwitchNodeGroupAutoScalingTask ensure auto scaler status and update nodegroup status to normal +func (t *Task) BuildSwitchNodeGroupAutoScalingTask(group *proto.NodeGroup, enable bool, + opt *cloudprovider.SwitchNodeGroupAutoScalingOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildUpdateAutoScalingOptionTask update auto scaling option +func (t *Task) BuildUpdateAutoScalingOptionTask(scalingOption *proto.ClusterAutoScalingOption, + opt *cloudprovider.UpdateScalingOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildSwitchAutoScalingOptionStatusTask switch auto scaling option status +func (t *Task) BuildSwitchAutoScalingOptionStatusTask(scalingOption *proto.ClusterAutoScalingOption, enable bool, + opt *cloudprovider.CommonOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildSwitchAsOptionStatusTask switch auto scaling option status +func (t *Task) BuildSwitchAsOptionStatusTask(scalingOption *proto.ClusterAutoScalingOption, enable bool, + opt *cloudprovider.CommonOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildUpdateNodeGroupTask when update nodegroup, we need to create background task, +func (t *Task) BuildUpdateNodeGroupTask(group *proto.NodeGroup, opt *cloudprovider.CommonOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildAddExternalNodeToCluster add external to cluster +func (t *Task) BuildAddExternalNodeToCluster(group *proto.NodeGroup, nodes []*proto.Node, + opt *cloudprovider.AddExternalNodesOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} + +// BuildDeleteExternalNodeFromCluster remove external node from cluster +func (t *Task) BuildDeleteExternalNodeFromCluster(group *proto.NodeGroup, nodes []*proto.Node, + opt *cloudprovider.DeleteExternalNodesOption) (*proto.Task, error) { + return nil, cloudprovider.ErrCloudNotImplemented +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/tasks/importCluster.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/tasks/importCluster.go new file mode 100644 index 0000000000..46bfb6622b --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/tasks/importCluster.go @@ -0,0 +1,203 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 tasks + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "time" + + proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/common" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/types" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/utils" + + "github.com/Tencent/bk-bcs/bcs-common/common/blog" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + k8scorev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +// RegisterClusterKubeConfigTask register cluster kubeConfig connection +func RegisterClusterKubeConfigTask(taskID string, stepName string) error { + start := time.Now() + // get task information and validate + state, step, err := cloudprovider.GetTaskStateAndCurrentStep(taskID, stepName) + if err != nil { + return err + } + if step == nil { + return nil + } + + // step login started here + clusterID := step.Params[cloudprovider.ClusterIDKey.String()] + cloudID := step.Params[cloudprovider.CloudIDKey.String()] + + basicInfo, err := cloudprovider.GetClusterDependBasicInfo(cloudprovider.GetBasicInfoReq{ + ClusterID: clusterID, + CloudID: cloudID, + }) + if err != nil { + blog.Errorf("RegisterClusterKubeConfigTask[%s]: getClusterDependBasicInfo failed: %v", taskID, err) + retErr := fmt.Errorf("getClusterDependBasicInfo failed, %s", err.Error()) + _ = state.UpdateStepFailure(start, stepName, retErr) + return retErr + } + + ctx := cloudprovider.WithTaskIDForContext(context.Background(), taskID) + + err = importClusterCredential(ctx, basicInfo) + if err != nil { + blog.Errorf("RegisterClusterKubeConfigTask[%s]: importClusterCredential failed: %v", taskID, err) + retErr := fmt.Errorf("importClusterCredential failed, %s", err.Error()) + _ = state.UpdateStepFailure(start, stepName, retErr) + return retErr + } + + // update step + if err = state.UpdateStepSucc(start, stepName); err != nil { + blog.Errorf("RegisterClusterKubeConfigTask[%s] task %s %s update to storage fatal", taskID, taskID, stepName) + return err + } + + return nil +} + +func importClusterCredential(ctx context.Context, data *cloudprovider.CloudDependBasicInfo) error { + configByte, err := base64.StdEncoding.DecodeString(data.Cluster.KubeConfig) + if err != nil { + return fmt.Errorf("failed to decode kubeconfig, %v", err) + } + typesConfig := &types.Config{} + err = json.Unmarshal(configByte, typesConfig) + if err != nil { + return fmt.Errorf("failed to unmarshal kubeconfig, %v", err) + } + err = cloudprovider.UpdateClusterCredentialByConfig(data.Cluster.ClusterID, typesConfig) + if err != nil { + return err + } + + return nil +} + +// ImportClusterNodesTask call gkeInterface or kubeConfig import cluster nodes +func ImportClusterNodesTask(taskID string, stepName string) error { + start := time.Now() + // get task information and validate + state, step, err := cloudprovider.GetTaskStateAndCurrentStep(taskID, stepName) + if err != nil { + return err + } + if step == nil { + return nil + } + + // step login started here + clusterID := step.Params[cloudprovider.ClusterIDKey.String()] + cloudID := step.Params[cloudprovider.CloudIDKey.String()] + + basicInfo, err := cloudprovider.GetClusterDependBasicInfo(cloudprovider.GetBasicInfoReq{ + ClusterID: clusterID, + CloudID: cloudID, + }) + if err != nil { + blog.Errorf("ImportClusterNodesTask[%s]: getClusterDependBasicInfo failed: %v", taskID, err) + retErr := fmt.Errorf("getClusterDependBasicInfo failed, %s", err.Error()) + _ = state.UpdateStepFailure(start, stepName, retErr) + return retErr + } + + // import cluster instances + err = importClusterInstances(basicInfo) + if err != nil { + blog.Errorf("ImportClusterNodesTask[%s]: importClusterInstances failed: %v", taskID, err) + retErr := fmt.Errorf("importClusterInstances failed, %s", err.Error()) + _ = state.UpdateStepFailure(start, stepName, retErr) + return retErr + } + + // update cluster masterNodes info + err = cloudprovider.GetStorageModel().UpdateCluster(context.Background(), basicInfo.Cluster) + if err != nil { + blog.Errorf("ImportClusterNodesTask[%s]: update cluster failed: %v", taskID, err) + retErr := fmt.Errorf("update cluster failed, %s", err.Error()) + _ = state.UpdateStepFailure(start, stepName, retErr) + return retErr + } + + // update step + if err = state.UpdateStepSucc(start, stepName); err != nil { + blog.Errorf("ImportClusterNodesTask[%s] task %s %s update to storage fatal", taskID, taskID, stepName) + return err + } + + return nil +} + +func importClusterInstances(data *cloudprovider.CloudDependBasicInfo) error { + kubeConfigByte, err := base64.StdEncoding.DecodeString(data.Cluster.KubeConfig) + if err != nil { + return fmt.Errorf("decode kube config failed: %v", err) + } + + config, err := clientcmd.RESTConfigFromKubeConfig(kubeConfigByte) + if err != nil { + return fmt.Errorf("build rest config failed: %v", err) + } + + config.Burst = 200 + config.QPS = 100 + kubeCli, err := kubernetes.NewForConfig(config) + if err != nil { + return fmt.Errorf("build kube client failed: %s", err) + } + + nodes, err := kubeCli.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("list nodes failed, %s", err.Error()) + } + + err = importClusterNodesToCM(context.Background(), nodes.Items, data.Cluster.ClusterID) + if err != nil { + return fmt.Errorf("inport cluster nodes to cm failed, %s", err.Error()) + } + + return nil +} + +// ImportClusterNodesToCM writes cluster nodes to DB +func importClusterNodesToCM(ctx context.Context, nodes []k8scorev1.Node, clusterID string) error { + for i := range nodes { + ipv4, ipv6 := utils.GetNodeIPAddress(&nodes[i]) + node := &proto.Node{ + InnerIP: utils.SliceToString(ipv4), + InnerIPv6: utils.SliceToString(ipv6), + Status: common.StatusRunning, + NodeName: nodes[i].Name, + ClusterID: clusterID, + } + err := cloudprovider.GetStorageModel().CreateNode(ctx, node) + if err != nil { + blog.Errorf("ImportClusterNodesToCM CreateNode[%s] failed: %v", nodes[i].Name, err) + } + } + + return nil +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/utils.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/utils.go new file mode 100644 index 0000000000..f972bf6b6d --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/utils.go @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 aws + +import ( + "fmt" + proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" +) + +var ( + cloudName = "aws" +) + +// tasks +var ( + // import cluster task + importClusterNodesStep = cloudprovider.StepInfo{ + StepMethod: fmt.Sprintf("%s-ImportClusterNodesTask", cloudName), + StepName: "导入集群节点", + } + registerClusterKubeConfigStep = cloudprovider.StepInfo{ + StepMethod: fmt.Sprintf("%s-RegisterClusterKubeConfigTask", cloudName), + StepName: "注册集群kubeConfig认证", + } +) + +// ImportClusterTaskOption 纳管集群 +type ImportClusterTaskOption struct { + Cluster *proto.Cluster +} + +// BuildRegisterKubeConfigStep 注册集群kubeConfig +func (ic *ImportClusterTaskOption) BuildRegisterKubeConfigStep(task *proto.Task) { + registerKubeConfigStep := cloudprovider.InitTaskStep(registerClusterKubeConfigStep) + registerKubeConfigStep.Params[cloudprovider.ClusterIDKey.String()] = ic.Cluster.ClusterID + registerKubeConfigStep.Params[cloudprovider.CloudIDKey.String()] = ic.Cluster.Provider + + task.Steps[registerClusterKubeConfigStep.StepMethod] = registerKubeConfigStep + task.StepSequence = append(task.StepSequence, registerClusterKubeConfigStep.StepMethod) +} + +// BuildImportClusterNodesStep 纳管集群节点 +func (ic *ImportClusterTaskOption) BuildImportClusterNodesStep(task *proto.Task) { + importNodesStep := cloudprovider.InitTaskStep(importClusterNodesStep) + importNodesStep.Params[cloudprovider.ClusterIDKey.String()] = ic.Cluster.ClusterID + importNodesStep.Params[cloudprovider.CloudIDKey.String()] = ic.Cluster.Provider + + task.Steps[importClusterNodesStep.StepMethod] = importNodesStep + task.StepSequence = append(task.StepSequence, importClusterNodesStep.StepMethod) +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/validate.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/validate.go new file mode 100644 index 0000000000..a86bb532b6 --- /dev/null +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/aws/validate.go @@ -0,0 +1,181 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 aws + +import ( + "encoding/base64" + "fmt" + "sync" + + "github.com/Tencent/bk-bcs/bcs-common/common/blog" + proto "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/api/clustermanager" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/clusterops" + "github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/types" +) + +var validateMgr sync.Once + +func init() { + validateMgr.Do(func() { + // init Cluster + cloudprovider.InitCloudValidateManager(cloudName, &CloudValidate{}) + }) +} + +// CloudValidate qcloud validate management implementation +type CloudValidate struct { +} + +// CreateClusterValidate create cluster validate +func (c *CloudValidate) CreateClusterValidate(req *proto.CreateClusterReq, opt *cloudprovider.CommonOption) error { + return nil +} + +// ImportClusterValidate check importCluster operation +func (c *CloudValidate) ImportClusterValidate(req *proto.ImportClusterReq, opt *cloudprovider.CommonOption) error { + // call cloud interface to check cluster + if c == nil || req == nil { + return fmt.Errorf("%s ImportClusterValidate request is empty", cloudName) + } + + if opt == nil || opt.Account == nil { + return fmt.Errorf("%s ImportClusterValidate options is empty", cloudName) + } + + if opt.Account.SecretID == "" || opt.Account.SecretKey == "" { + return fmt.Errorf("%s ImportClusterValidate request lost valid crendential info", cloudName) + } + + if req.CloudMode.CloudID == "" && req.CloudMode.KubeConfig == "" { + return fmt.Errorf("%s ImportClusterValidate cluster cloudID & kubeConfig empty", cloudName) + } + + if req.CloudMode.KubeConfig != "" { + _, err := types.GetKubeConfigFromYAMLBody(false, types.YamlInput{ + FileName: "", + YamlContent: req.CloudMode.KubeConfig, + }) + if err != nil { + return fmt.Errorf("%s ImportClusterValidate GetKubeConfigFromYAMLBody failed: %v", cloudName, err) + } + + kubeRet := base64.StdEncoding.EncodeToString([]byte(req.CloudMode.KubeConfig)) + kubeCli, err := clusterops.NewKubeClient(kubeRet) + if err != nil { + return fmt.Errorf("%s ImportClusterValidate NewKubeClient failed: %v", cloudName, err) + } + + _, err = kubeCli.Discovery().ServerVersion() + if err != nil { + return fmt.Errorf("%s ImportClusterValidate connect cluster by kubeConfig failed: %v", cloudName, err) + } + + blog.Infof("%s ImportClusterValidate CloudMode connect cluster ByKubeConfig success", cloudName) + } + + return nil +} + +// ImportCloudAccountValidate create cloudAccount account validation +func (c *CloudValidate) ImportCloudAccountValidate(account *proto.Account) error { + return nil +} + +// GetCloudRegionZonesValidate xxx +func (c *CloudValidate) GetCloudRegionZonesValidate(req *proto.GetCloudRegionZonesRequest, + account *proto.Account) error { + return nil +} + +// ListCloudRegionClusterValidate xxx +func (c *CloudValidate) ListCloudRegionClusterValidate(req *proto.ListCloudRegionClusterRequest, + account *proto.Account) error { + // call cloud interface to check account + if c == nil || account == nil { + return fmt.Errorf("%s ListCloudRegionClusterValidate request is empty", cloudName) + } + + if account.SecretID == "" || account.SecretKey == "" { + return fmt.Errorf("%s ImportClusterValidate request lost valid crendential info", cloudName) + } + + if len(req.Region) == 0 { + return fmt.Errorf("%s ListCloudRegionClusterValidate request lost valid region info", cloudName) + } + + return nil +} + +// ListCloudSubnetsValidate xxx +func (c *CloudValidate) ListCloudSubnetsValidate(req *proto.ListCloudSubnetsRequest, account *proto.Account) error { + return nil +} + +// ListSecurityGroupsValidate xxx +func (c *CloudValidate) ListSecurityGroupsValidate(req *proto.ListCloudSecurityGroupsRequest, + account *proto.Account) error { + return nil +} + +// ListKeyPairsValidate list key pairs validate +func (c *CloudValidate) ListKeyPairsValidate(req *proto.ListKeyPairsRequest, account *proto.Account) error { + if len(req.Region) == 0 { + return fmt.Errorf("%s ListKeyPairsValidate request lost valid region info", cloudName) + } + + return nil +} + +// ListCloudVpcsValidate list vpcs validate +func (c *CloudValidate) ListCloudVpcsValidate(req *proto.ListCloudVpcsRequest, account *proto.Account) error { + return nil +} + +// ListInstancesValidate xxx +func (c *CloudValidate) ListInstancesValidate(req *proto.ListCloudInstancesRequest, account *proto.Account) error { + return nil +} + +// ListInstanceTypeValidate xxx +func (c *CloudValidate) ListInstanceTypeValidate(req *proto.ListCloudInstanceTypeRequest, + account *proto.Account) error { + return nil +} + +// ListCloudOsImageValidate xxx +func (c *CloudValidate) ListCloudOsImageValidate(req *proto.ListCloudOsImageRequest, account *proto.Account) error { + return nil +} + +// CreateNodeGroupValidate xxx +func (c *CloudValidate) CreateNodeGroupValidate(req *proto.CreateNodeGroupRequest, + opt *cloudprovider.CommonOption) error { + return nil +} + +// AddNodesToClusterValidate add nodes to cluster validate +func (c *CloudValidate) AddNodesToClusterValidate(req *proto.AddNodesRequest, opt *cloudprovider.CommonOption) error { + return nil +} + +// DeleteNodesFromClusterValidate delete nodes from cluster validate +func (c *CloudValidate) DeleteNodesFromClusterValidate(req *proto.DeleteNodesRequest, opt *cloudprovider.CommonOption) error { + return nil +} + +// CreateCloudAccountValidate create cloud account validate +func (c *CloudValidate) CreateCloudAccountValidate(account *proto.Account) error { + return nil +} diff --git a/bcs-services/bcs-cluster-manager/internal/cloudprovider/google/api/vpc.go b/bcs-services/bcs-cluster-manager/internal/cloudprovider/google/api/vpc.go index e2b6794871..8f906a4ff5 100644 --- a/bcs-services/bcs-cluster-manager/internal/cloudprovider/google/api/vpc.go +++ b/bcs-services/bcs-cluster-manager/internal/cloudprovider/google/api/vpc.go @@ -35,12 +35,12 @@ func init() { type VPCManager struct{} // ListVpcs list vpcs -func (c *VPCManager) ListVpcs(vpcID string, opt *cloudprovider.CommonOption) ([]*proto.CloudVpc, error) { +func (vm *VPCManager) ListVpcs(vpcID string, opt *cloudprovider.CommonOption) ([]*proto.CloudVpc, error) { return nil, cloudprovider.ErrCloudNotImplemented } // ListSubnets list vpc subnets -func (vm VPCManager) ListSubnets(vpcID string, opt *cloudprovider.CommonOption) ([]*proto.Subnet, error) { +func (vm *VPCManager) ListSubnets(vpcID string, opt *cloudprovider.CommonOption) ([]*proto.Subnet, error) { locationList := strings.Split(opt.Region, "-") if len(locationList) == 3 { opt.Region = strings.Join(locationList[:2], "-") @@ -75,16 +75,16 @@ func (vm VPCManager) ListSubnets(vpcID string, opt *cloudprovider.CommonOption) } // ListSecurityGroups list security groups -func (vm VPCManager) ListSecurityGroups(opt *cloudprovider.CommonOption) ([]*proto.SecurityGroup, error) { +func (vm *VPCManager) ListSecurityGroups(opt *cloudprovider.CommonOption) ([]*proto.SecurityGroup, error) { return nil, cloudprovider.ErrCloudNotImplemented } // GetCloudNetworkAccountType 查询用户网络类型 -func (vm VPCManager) GetCloudNetworkAccountType(opt *cloudprovider.CommonOption) (*proto.CloudAccountType, error) { +func (vm *VPCManager) GetCloudNetworkAccountType(opt *cloudprovider.CommonOption) (*proto.CloudAccountType, error) { return nil, cloudprovider.ErrCloudNotImplemented } // ListBandwidthPacks list bandWidthPacks -func (vm VPCManager) ListBandwidthPacks(opt *cloudprovider.CommonOption) ([]*proto.BandwidthPackageInfo, error) { +func (vm *VPCManager) ListBandwidthPacks(opt *cloudprovider.CommonOption) ([]*proto.BandwidthPackageInfo, error) { return nil, cloudprovider.ErrCloudNotImplemented }