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

[k8scluster] update k8scluster dynamic #1914

Merged
Merged
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
10 changes: 5 additions & 5 deletions src/api/rest/server/resource/k8scluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ func RestPostK8sClusterDynamicCheckRequest(c echo.Context) error {
// @Accept json
// @Produce json
// @Param nsId path string true "Namespace ID" default(default)
// @Param k8sclusterReq body model.TbK8sClusterDynamicReq true "Request body to provision K8sCluster dynamically. <br> Must include commonSpec and commonImage info. <br> (ex: {name: k8scluster-01, commonImage: azure+koreacentral+ubuntu22.04, commonSpec: azure+koreacentral+Standard_B2s}]}) <br> You can use /k8sclusterRecommendNode and /k8sclusterDynamicCheckRequest to get it. <br> Check the guide: https://github.com/cloud-barista/cb-tumblebug/discussions/1570"
// @Param k8sclusterReq body model.TbK8sClusterDynamicReq true "Request body to provision K8sCluster dynamically. <br> Must include commonSpec and commonImage info. <br> (ex: {name: k8scluster-01, commonImage: azure+koreacentral+ubuntu22.04, commonSpec: azure+koreacentral+Standard_B2s}]}) <br> You can use /k8sclusterRecommendNode and /k8sclusterDynamicCheckRequest to get it. <br> Check the guide: https://github.com/cloud-barista/cb-tumblebug/discussions/1913"
// @Param option query string false "Option for K8sCluster creation" Enums(hold)
// @Param x-request-id header string false "Custom request ID"
// @Success 200 {object} model.TbK8sClusterInfo
Expand Down Expand Up @@ -640,8 +640,8 @@ func RestGetControlK8sCluster(c echo.Context) error {
}
}

// RestRecommendNode godoc
// @ID RecommendNode
// RestRecommendK8sNode godoc
// @ID RecommendK8sNode
// @Summary Recommend K8sCluster's Node plan (filter and priority)
// @Description Recommend K8sCluster's Node plan (filter and priority) Find details from https://github.com/cloud-barista/cb-tumblebug/discussions/1234
// @Tags [Kubernetes] Cluster Management
Expand All @@ -652,7 +652,7 @@ func RestGetControlK8sCluster(c echo.Context) error {
// @Failure 404 {object} model.SimpleMsg
// @Failure 500 {object} model.SimpleMsg
// @Router /k8sclusterRecommendNode [post]
func RestRecommendNode(c echo.Context) error {
func RestRecommendK8sNode(c echo.Context) error {

nsId := model.SystemCommonNs

Expand All @@ -661,6 +661,6 @@ func RestRecommendNode(c echo.Context) error {
return common.EndRequestWithLog(c, err, nil)
}

content, err := infra.RecommendVm(nsId, *u)
content, err := infra.RecommendK8sNode(nsId, *u)
return common.EndRequestWithLog(c, err, content)
}
2 changes: 1 addition & 1 deletion src/api/rest/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ func RunServer() {
g.DELETE("/:nsId/k8scluster", rest_resource.RestDeleteAllK8sCluster)
g.PUT("/:nsId/k8scluster/:k8sClusterId/upgrade", rest_resource.RestPutUpgradeK8sCluster)

e.POST("/tumblebug/k8sclusterRecommendNode", rest_resource.RestRecommendNode)
e.POST("/tumblebug/k8sclusterRecommendNode", rest_resource.RestRecommendK8sNode)
e.POST("/tumblebug/k8sclusterDynamicCheckRequest", rest_resource.RestPostK8sClusterDynamicCheckRequest)
g.POST("/:nsId/k8sclusterDynamic", rest_resource.RestPostK8sClusterDynamic)
g.GET("/:nsId/control/k8scluster/:k8sClusterId", rest_resource.RestGetControlK8sCluster)
Expand Down
101 changes: 24 additions & 77 deletions src/core/common/utility.go
Original file line number Diff line number Diff line change
Expand Up @@ -1498,92 +1498,39 @@ func GetModelK8sRequiredSubnetCount(providerName string) (*model.K8sClusterRequi
}, nil
}

/*
func isValidSpecForK8sCluster(spec *resource.TbSpecInfo) bool {
//
// Check for Provider
//
func FilterDigitsAndDots(input string) string {
re := regexp.MustCompile(`[^0-9.]`)
return re.ReplaceAllString(input, "")
}

providerName := strings.ToLower(spec.ProviderName)
func CompareVersions(version1, version2 string) int {
v1Parts := strings.Split(version1, ".")
v2Parts := strings.Split(version2, ".")

var k8sClusterDetail *common.model.K8sClusterDetail = nil
for provider, detail := range common.RuntimeK8sClusterInfo.CSPs {
provider = strings.ToLower(provider)
if provider == providerName {
k8sClusterDetail = &detail
break
}
}
if k8sClusterDetail == nil {
return false
// Adjust length by appending 0 if necessary
maxLength := len(v1Parts)
if len(v2Parts) > maxLength {
maxLength = len(v2Parts)
}

//
// Check for Region
//

regionName := strings.ToLower(spec.RegionName)
for i := 0; i < maxLength; i++ {
var v1, v2 int

// Check for Version
isExist := false
for _, versionDetail := range k8sClusterDetail.Version {
for _, region := range versionDetail.Region {
region = strings.ToLower(region)
if region == "all" || region == regionName {
if len(versionDetail.Available) > 0 {
isExist = true
break
}
}
// If a part is missing, treat it as 0
if i < len(v1Parts) {
v1, _ = strconv.Atoi(v1Parts[i])
}
if isExist == true {
break
if i < len(v2Parts) {
v2, _ = strconv.Atoi(v2Parts[i])
}
}
if isExist == false {
return false
}

// Check for NodeImage
isExist = false
for _, nodeImageDetail := range k8sClusterDetail.NodeImage {
for _, region := range nodeImageDetail.Region {
region = strings.ToLower(region)
if region == "all" || region == regionName {
if len(nodeImageDetail.Available) > 0 {
isExist = true
break
}
}
}
if isExist == true {
break
// Compare each part
if v1 > v2 {
return 1
} else if v1 < v2 {
return -1
}
}
if isExist == false {
return false
}

// Check for RootDisk
isExist = false
for _, rootDiskDetail := range k8sClusterDetail.RootDisk {
for _, region := range rootDiskDetail.Region {
region = strings.ToLower(region)
if region == "all" || region == regionName {
if len(rootDiskDetail.Type) > 0 {
isExist = true
break
}
}
}
if isExist == true {
break
}
}
if isExist == false {
return false
}

return true
return 0
}
*/
69 changes: 44 additions & 25 deletions src/core/infra/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package infra
import (
"encoding/json"
"fmt"
"regexp"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -1669,15 +1668,17 @@ func filterCheckMciDynamicReqInfoToCheckK8sClusterDynamicReqInfo(mciDReqInfo *mo
}
}

nodeDReqInfo := model.CheckNodeDynamicReqInfo{
ConnectionConfigCandidates: k.ConnectionConfigCandidates,
Spec: k.Spec,
Image: imageListForK8s,
Region: k.Region,
SystemMessage: k.SystemMessage,
}
if len(imageListForK8s) > 0 {
nodeDReqInfo := model.CheckNodeDynamicReqInfo{
ConnectionConfigCandidates: k.ConnectionConfigCandidates,
Spec: k.Spec,
Image: imageListForK8s,
Region: k.Region,
SystemMessage: k.SystemMessage,
}

k8sDReqInfo.ReqCheck = append(k8sDReqInfo.ReqCheck, nodeDReqInfo)
k8sDReqInfo.ReqCheck = append(k8sDReqInfo.ReqCheck, nodeDReqInfo)
}
}
}
}
Expand All @@ -1703,11 +1704,6 @@ func CheckK8sClusterDynamicReq(req *model.K8sClusterConnectionConfigCandidatesRe
return k8sDReqInfo, err
}

func filterDigitsAndDots(input string) string {
re := regexp.MustCompile(`[^0-9.]`)
return re.ReplaceAllString(input, "")
}

func getK8sRecommendVersion(providerName, regionName, reqVersion string) (string, error) {
availableVersion, err := common.GetAvailableK8sVersion(providerName, regionName)
if err != nil {
Expand All @@ -1718,17 +1714,29 @@ func getK8sRecommendVersion(providerName, regionName, reqVersion string) (string

recVersion := model.StrEmpty
versionIdList := []string{}
for _, verDetail := range *availableVersion {
versionIdList = append(versionIdList, verDetail.Id)
if strings.EqualFold(reqVersion, verDetail.Id) {
recVersion = verDetail.Id
break
} else {
availVersion := filterDigitsAndDots(verDetail.Id)
filteredReqVersion := filterDigitsAndDots(reqVersion)
if strings.HasPrefix(availVersion, filteredReqVersion) {
recVersion = availVersion

if reqVersion == "" {
for _, verDetail := range *availableVersion {
versionIdList = append(versionIdList, verDetail.Id)
filteredRecVersion := common.FilterDigitsAndDots(recVersion)
filteredAvailVersion := common.FilterDigitsAndDots(verDetail.Id)
if common.CompareVersions(filteredRecVersion, filteredAvailVersion) < 0 {
recVersion = verDetail.Id
}
}
} else {
for _, verDetail := range *availableVersion {
versionIdList = append(versionIdList, verDetail.Id)
if strings.EqualFold(reqVersion, verDetail.Id) {
recVersion = verDetail.Id
break
} else {
availVersion := common.FilterDigitsAndDots(verDetail.Id)
filteredReqVersion := common.FilterDigitsAndDots(reqVersion)
if strings.HasPrefix(availVersion, filteredReqVersion) {
recVersion = availVersion
break
}
}
}
}
Expand Down Expand Up @@ -1943,10 +1951,21 @@ func getK8sClusterReqFromDynamicReq(reqID string, nsId string, dReq *model.TbK8s
k8sngReq.RootDiskType = dReq.RootDiskType
k8sngReq.RootDiskSize = dReq.RootDiskSize
k8sngReq.OnAutoScaling = dReq.OnAutoScaling
if k8sngReq.OnAutoScaling == "" {
k8sngReq.OnAutoScaling = "true"
}
k8sngReq.DesiredNodeSize = dReq.DesiredNodeSize
if k8sngReq.DesiredNodeSize == "" {
k8sngReq.DesiredNodeSize = "1"
}
k8sngReq.MinNodeSize = dReq.MinNodeSize
if k8sngReq.MinNodeSize == "" {
k8sngReq.MinNodeSize = "1"
}
k8sngReq.MaxNodeSize = dReq.MaxNodeSize

if k8sngReq.MaxNodeSize == "" {
k8sngReq.MaxNodeSize = "2"
}
k8sReq.Description = dReq.Description
k8sReq.Name = dReq.Name
if k8sReq.Name == "" {
Expand Down
33 changes: 33 additions & 0 deletions src/core/infra/recommendation.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,39 @@ func RecommendVmPerformance(nsId string, specList *[]model.TbSpecInfo) ([]model.
return result, nil
}

// RecommendK8sNode is func to recommend a node for K8sCluster
func RecommendK8sNode(nsId string, plan model.DeploymentPlan) ([]model.TbSpecInfo, error) {
emptyObjList := []model.TbSpecInfo{}

limitOrig := plan.Limit
plan.Limit = strconv.Itoa(math.MaxInt)

tbSpecInfoListForVm, err := RecommendVm(nsId, plan)
if err != nil {
return emptyObjList, err
}

limitNum, err := strconv.Atoi(limitOrig)
if err != nil {
limitNum = math.MaxInt
}

tbSpecInfoListForK8s := []model.TbSpecInfo{}
count := 0
for _, tbSpecInfo := range tbSpecInfoListForVm {
if strings.Contains(tbSpecInfo.InfraType, model.StrK8s) ||
strings.Contains(tbSpecInfo.InfraType, model.StrKubernetes) {
tbSpecInfoListForK8s = append(tbSpecInfoListForK8s, tbSpecInfo)
count++
if count == limitNum {
break
}
}
}

return tbSpecInfoListForK8s, nil
}

// // GetRecommendList is func to get recommendation list
// func GetRecommendList(nsId string, cpuSize string, memSize string, diskSize string) ([]TbVmPriority, error) {

Expand Down
8 changes: 4 additions & 4 deletions src/core/model/k8scluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ type TbK8sAddonsInfo struct {
// K8sClusterConnectionConfigCandidatesReq is struct for a request to check requirements to create a new K8sCluster instance dynamically (with default resource option)
type K8sClusterConnectionConfigCandidatesReq struct {
// CommonSpec is field for id of a spec in common namespace
CommonSpecs []string `json:"commonSpec" validate:"required" example:"azure+koreacentral+Standard_B2s"`
CommonSpecs []string `json:"commonSpec" validate:"required" example:"tencent+ap-seoul+S2.MEDIUM4"`
}

// CheckK8sClusterDynamicReqInfo is struct to check requirements to create a new K8sCluster instance dynamically (with default resource option)
Expand Down Expand Up @@ -500,10 +500,10 @@ type TbK8sClusterDynamicReq struct {
NodeGroupName string `json:"nodeGroupName" example:"nodegroup-01"`

// CommonSpec is field for id of a spec in common namespace
CommonSpec string `json:"commonSpec" validate:"required" example:"azure+koreacentral+standard_b2s"`
CommonSpec string `json:"commonSpec" validate:"required" example:"tencent+ap-seoul+S2.MEDIUM4"`

// CommonImage is field for id of a image in common namespace
CommonImage string `json:"commonImage" validate:"required" example:"default, azure+koreacentrall+ubuntu20.04"`
CommonImage string `json:"commonImage" validate:"required" example:"default, tencent+ap-seoul+ubuntu20.04"`

RootDiskType string `json:"rootDiskType,omitempty" example:"default, TYPE1, ..." default:"default"` // "", "default", "TYPE1", AWS: ["standard", "gp2", "gp3"], Azure: ["PremiumSSD", "StandardSSD", "StandardHDD"], GCP: ["pd-standard", "pd-balanced", "pd-ssd", "pd-extreme"], ALIBABA: ["cloud_efficiency", "cloud", "cloud_essd"], TENCENT: ["CLOUD_PREMIUM", "CLOUD_SSD"]
RootDiskSize string `json:"rootDiskSize,omitempty" example:"default, 30, 42, ..." default:"default"` // "default", Integer (GB): ["50", ..., "1000"]
Expand All @@ -515,5 +515,5 @@ type TbK8sClusterDynamicReq struct {

// if ConnectionName is given, the VM tries to use associtated credential.
// if not, it will use predefined ConnectionName in Spec objects
ConnectionName string `json:"connectionName,omitempty" default:"azure-koreacentral"`
ConnectionName string `json:"connectionName,omitempty" default:"tencent-ap-seoul"`
}