Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 完善创建AKS集群功能 #3564

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ func (ng *NodeGroup) RecommendNodeGroupConf(opt *cloudprovider.CommonOption) ([]
Cpu: 8,
Memory: 16,
}, opt)
if err != nil {
return nil, fmt.Errorf("list node instance type failed, %s", err.Error())
}
if len(insTypes) == 0 {
return nil, fmt.Errorf("RecommendNodeGroupConf no valid instanceType for 8c16g")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func CheckCloudNodeGroupStatusTask(taskID string, stepName string) error { // no

asgInfo, ltvInfo, err := checkNodegroupStatus(ctx, dependInfo)
if err != nil {
blog.Errorf("CheckCloudNodeGroupStatusTask[%s]: getClusterDependBasicInfo failed: %v", taskID, err)
blog.Errorf("CheckCloudNodeGroupStatusTask[%s]: checkNodegroupStatus failed: %v", taskID, err)
retErr := fmt.Errorf("getClusterDependBasicInfo failed, %s", err.Error())
_ = state.UpdateStepFailure(start, stepName, retErr)
return retErr
Expand All @@ -340,9 +340,9 @@ func CheckCloudNodeGroupStatusTask(taskID string, stepName string) error { // no
err = cloudprovider.GetStorageModel().UpdateNodeGroup(context.Background(),
generateNodeGroupFromAsgAndLtv(dependInfo.NodeGroup, asgInfo, ltvInfo))
if err != nil {
blog.Errorf("CreateCloudNodeGroupTask[%s]: updateNodeGroupCloudArgsID[%s] in task %s step %s failed, %s",
blog.Errorf("CreateCloudNodeGroupTask[%s]: UpdateNodeGroup[%s] in task %s step %s failed, %s",
taskID, nodeGroupID, taskID, stepName, err.Error())
retErr := fmt.Errorf("call CreateCloudNodeGroupTask updateNodeGroupCloudArgsID[%s] api err, %s", nodeGroupID,
retErr := fmt.Errorf("call CreateCloudNodeGroupTask UpdateNodeGroup[%s] api err, %s", nodeGroupID,
err.Error())
_ = state.UpdateStepFailure(start, stepName, retErr)
return retErr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ package business
import (
"context"
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
"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/remote/cidrtree"
"github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/utils"
"net"
"time"

"github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider"
"github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/cloudprovider/azure/api"
Expand Down Expand Up @@ -50,3 +58,212 @@ func SubnetUsedIpCount(ctx context.Context, opt *cloudprovider.ListNetworksOptio

return usedIPCount, nil
}

// GetVpcCIDRBlocks 获取vpc所属的cidr段(包括普通辅助cidr、容器辅助cidr)
func GetVpcCIDRBlocks(opt *cloudprovider.CommonOption, vpcId, resourceGroup string) ([]*net.IPNet, error) {
vpcCli, err := api.NewAksServiceImplWithCommonOption(opt)
if err != nil {
return nil, err
}

vpcSet, err := vpcCli.GetVirtualNetworks(context.Background(), resourceGroup, vpcId)
if err != nil {
return nil, err
}
if vpcSet == nil {
return nil, fmt.Errorf("GetVpcCIDRBlocks GetVirtualNetworks[%s] empty", vpcId)
}

cidrs := make([]string, 0)

for _, v := range vpcSet.Properties.AddressSpace.AddressPrefixes {
cidrs = append(cidrs, *v)
}

var ret []*net.IPNet
for _, v := range cidrs {
_, c, err := net.ParseCIDR(v)
if err != nil {
return ret, err
}
ret = append(ret, c)
}
return ret, nil

}

// GetAllocatedSubnetsByVpc 获取vpc已分配的子网cidr段
func GetAllocatedSubnetsByVpc(opt *cloudprovider.CommonOption, vpcId, resourceGroup string) ([]*net.IPNet, error) {
vpcCli, err := api.NewAksServiceImplWithCommonOption(opt)
if err != nil {
return nil, err
}

subnets, err := vpcCli.ListSubnets(context.Background(), resourceGroup, vpcId)
if err != nil {
return nil, err
}

var ret []*net.IPNet
for _, subnet := range subnets {
if subnet.Properties != nil && subnet.Properties.AddressPrefix != nil {
_, c, err := net.ParseCIDR(*subnet.Properties.AddressPrefix)
if err != nil {
return ret, err
}
ret = append(ret, c)
}
}
return ret, nil
}

// GetFreeIPNets return free subnets
func GetFreeIPNets(opt *cloudprovider.CommonOption, vpcId, resourceGroup string) ([]*net.IPNet, error) {
// 获取vpc cidr blocks
allBlocks, err := GetVpcCIDRBlocks(opt, vpcId, resourceGroup)
if err != nil {
return nil, err
}

// 获取vpc 已使用子网列表
allSubnets, err := GetAllocatedSubnetsByVpc(opt, vpcId, resourceGroup)
if err != nil {
return nil, err
}

// 空闲IP列表
return cidrtree.GetFreeIPNets(allBlocks, nil, allSubnets), nil
}

// AllocateSubnet allocate directrouter subnet
func AllocateSubnet(opt *cloudprovider.CommonOption, vpcId, resourceGroup string,
mask int, clusterId, subnetName string) (*cidrtree.Subnet, error) {
frees, err := GetFreeIPNets(opt, vpcId, resourceGroup)
if err != nil {
return nil, err
}
sub, err := cidrtree.AllocateFromFrees(mask, frees)
if err != nil {
return nil, err
}

if subnetName == "" {
subnetName = fmt.Sprintf("bcs-subnet-%s-%s", clusterId, utils.RandomString(8))
}

// create vpc subnet
vpcCli, err := api.NewAksServiceImplWithCommonOption(opt)
if err != nil {
return nil, err
}

subnet := armnetwork.Subnet{
Name: to.Ptr(subnetName), // nolint
Properties: &armnetwork.SubnetPropertiesFormat{
AddressPrefix: to.Ptr(sub.String()), // nolint
},
}
// 更新和创建subnet为同一个接口
ret, err := vpcCli.UpdateSubnet(context.Background(), resourceGroup, vpcId, subnetName, subnet)
if err != nil {
return nil, err
}

return subnetFromVpcSubnet(opt, ret, vpcId, resourceGroup), err
}

// subnetFromVpcSubnet trans vpc subnet to local subnet
func subnetFromVpcSubnet(opt *cloudprovider.CommonOption, info *armnetwork.Subnet, vpcId,
resourceGroupName string) *cidrtree.Subnet {
s := &cidrtree.Subnet{}
if info == nil {
return s
}
s.ID = *info.ID
s.Name = *info.Name
if info.Properties != nil && info.Properties.AddressPrefix != nil {
_, s.IPNet, _ = net.ParseCIDR(*info.Properties.AddressPrefix)
}
s.VpcID = vpcId

netOpt := &cloudprovider.ListNetworksOption{
CommonOption: *opt,
ResourceGroupName: resourceGroupName,
}
s.AvailableIps = func() uint64 {
totalIPs, errLocal := utils.ConvertCIDRToStep(*info.Properties.AddressPrefix)
if errLocal != nil {
return 0
}

usedIpCnt, errLocal := SubnetUsedIpCount(context.Background(), netOpt, *info.ID)
if errLocal != nil {
return 0
}

return uint64(totalIPs - usedIpCnt - 5) // 减去5个系统保留的IP地址
}()

return s
}

// AllocateClusterVpcCniSubnets 集群分配所需的vpc-cni子网资源
func AllocateClusterVpcCniSubnets(ctx context.Context, clusterId, vpcId string,
subnets []*proto.NewSubnet, opt *cloudprovider.CommonOption) ([]string, error) {
taskID := cloudprovider.GetTaskIDFromContext(ctx)

subnetIDs := make([]string, 0)

for i := range subnets {
mask := 0 // nolint
if subnets[i].Mask > 0 {
mask = int(subnets[i].Mask)
} else if subnets[i].IpCnt > 0 {
lenMask, err := utils.GetMaskLenByNum(utils.IPV4, float64(subnets[i].IpCnt))
if err != nil {
blog.Errorf("AllocateClusterVpcCniSubnets[%s] failed: %v", taskID, err)
continue
}

mask = lenMask
} else {
mask = utils.DefaultMask
}

sub, err := AllocateSubnet(opt, vpcId, subnets[i].Zone, mask, clusterId, "")
if err != nil {
blog.Errorf("AllocateClusterVpcCniSubnets[%s] failed: %v", taskID, err)
continue
}

blog.Infof("AllocateClusterVpcCniSubnets[%s] vpc[%s] zone[%s] subnet[%s]",
taskID, vpcId, subnets[i].Zone, sub.ID)
subnetIDs = append(subnetIDs, sub.ID)
time.Sleep(time.Millisecond * 500)
}

blog.Infof("AllocateClusterVpcCniSubnets[%s] subnets[%v]", taskID, subnetIDs)
return subnetIDs, nil
}

// CheckConflictFromVpc check cidr conflict in vpc cidrs
func CheckConflictFromVpc(opt *cloudprovider.CommonOption, vpcId, cidr, resourceGroupName string) ([]string, error) {
ipNets, err := GetVpcCIDRBlocks(opt, vpcId, resourceGroupName)
if err != nil {
return nil, err
}

_, c, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}

conflictCidrs := make([]string, 0)
for i := range ipNets {
if cidrtree.CidrContains(ipNets[i], c) || cidrtree.CidrContains(c, ipNets[i]) {
conflictCidrs = append(conflictCidrs, ipNets[i].String())
}
}

return conflictCidrs, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package azure
import (
"context"
"fmt"
"github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/common"
"github.com/Tencent/bk-bcs/bcs-services/bcs-cluster-manager/internal/utils"
"sync"

"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice"
Expand All @@ -42,6 +44,23 @@ type CloudInfoManager struct {
// InitCloudClusterDefaultInfo init cluster defaultConfig
func (c *CloudInfoManager) InitCloudClusterDefaultInfo(cls *proto.Cluster,
opt *cloudprovider.InitClusterConfigOption) error {
if c == nil || cls == nil {
return fmt.Errorf("%s InitCloudClusterDefaultInfo request is empty", cloudName)
}

if opt == nil || opt.Cloud == nil {
return fmt.Errorf("%s InitCloudClusterDefaultInfo option is empty", cloudName)
}

if cls.GetClusterAdvanceSettings() == nil {
return fmt.Errorf("initCloudCluster advanced setting empty")
}

if !utils.StringInSlice(cls.ClusterAdvanceSettings.NetworkType,
[]string{common.AzureCniOverlay, common.AzureCniNodeSubnet}) {
return fmt.Errorf("initCloudCluster not supported networkPlugin[%s]", cls.ClusterAdvanceSettings.NetworkType)
}

return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ func (n *NodeManager) ListNodeInstanceType(info cloudprovider.InstanceInfo, opt
continue
}

if info.NodeFamily != "" && info.NodeFamily != *v.Family {
continue
}
if info.Cpu != 0 && info.Cpu != uint32(cpu) {
continue
}
if info.Memory != 0 && info.Memory != uint32(mem) {
continue
}

zones := make([]string, 0)
if len(v.LocationInfo) != 0 {
for _, z := range v.LocationInfo[0].Zones {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,71 @@ func (ng *NodeGroup) UpdateNodeGroup(group *proto.NodeGroup, opt *cloudprovider.

// RecommendNodeGroupConf recommends nodegroup configs
func (ng *NodeGroup) RecommendNodeGroupConf(opt *cloudprovider.CommonOption) ([]*proto.RecommendNodeGroupConf, error) {
return nil, cloudprovider.ErrCloudNotImplemented
if opt == nil {
return nil, fmt.Errorf("invalid request")
}

mgr := NodeManager{}
insTypes, err := mgr.ListNodeInstanceType(cloudprovider.InstanceInfo{
Region: opt.Region,
Cpu: 8,
Memory: 16,
}, opt)
if err != nil {
return nil, fmt.Errorf("list node instance type failed, %s", err.Error())
}

validInsTypes := make([]*proto.InstanceType, 0)
for _, in := range insTypes {
if in.Status == common.InstanceSell {
validInsTypes = append(validInsTypes, in)
}
}
if len(validInsTypes) == 0 {
return nil, fmt.Errorf("RecommendNodeGroupConf no valid instanceType for 8c16g")
}

configs := make([]*proto.RecommendNodeGroupConf, 0)
configs = append(configs,
generateNodeGroupConf("agentpool", "System", validInsTypes[0]),
generateNodeGroupConf("userpool", "User", validInsTypes[0]))

return configs, nil
}

func generateNodeGroupConf(name, mode string, t *proto.InstanceType) *proto.RecommendNodeGroupConf {
return &proto.RecommendNodeGroupConf{
Name: name,
Mode: mode,
Zones: t.Zones,
InstanceProfile: &proto.InstanceProfile{
NodeOS: "Ubuntu",
InstanceType: t.NodeType,
InstanceChargeType: "TRAFFIC_POSTPAID_BY_HOUR",
},
HardwareProfile: &proto.HardwareProfile{
CPU: 8,
Mem: 16,
SystemDisk: &proto.DataDisk{
DiskType: "CLOUD_PREMIUM",
DiskSize: "100",
},
DataDisks: []*proto.DataDisk{
{
DiskType: "Premium_LRS",
DiskSize: "100",
},
},
},
NetworkProfile: &proto.NetworkProfile{
PublicIPAssigned: false,
},
ScalingProfile: &proto.ScalingProfile{
MaxSize: 5,
// 释放模式
ScalingMode: "Delete",
},
}
}

// GetNodesInGroup 从云上拉取该节点池的所有节点 - get all nodes belong to NodeGroup
Expand Down
Loading
Loading