Skip to content

Commit

Permalink
Provisioning MCIS dynamic with hold option
Browse files Browse the repository at this point in the history
  • Loading branch information
seokho-son committed May 15, 2024
1 parent 558f357 commit 61d193d
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 21 deletions.
16 changes: 15 additions & 1 deletion src/api/rest/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2021,7 +2021,9 @@ const docTemplate = `{
"resume",
"reboot",
"terminate",
"refine"
"refine",
"continue",
"withdraw"
],
"type": "string",
"description": "Action to MCIS",
Expand Down Expand Up @@ -4214,6 +4216,15 @@ const docTemplate = `{
"schema": {
"$ref": "#/definitions/mcis.TbMcisDynamicReq"
}
},
{
"enum": [
"hold"
],
"type": "string",
"description": "Option for MCIS creation",
"name": "option",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -8397,6 +8408,9 @@ const docTemplate = `{
"location": {
"$ref": "#/definitions/common.Location"
},
"regionId": {
"type": "string"
},
"regionName": {
"type": "string"
},
Expand Down
16 changes: 15 additions & 1 deletion src/api/rest/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -2014,7 +2014,9 @@
"resume",
"reboot",
"terminate",
"refine"
"refine",
"continue",
"withdraw"
],
"type": "string",
"description": "Action to MCIS",
Expand Down Expand Up @@ -4207,6 +4209,15 @@
"schema": {
"$ref": "#/definitions/mcis.TbMcisDynamicReq"
}
},
{
"enum": [
"hold"
],
"type": "string",
"description": "Option for MCIS creation",
"name": "option",
"in": "query"
}
],
"responses": {
Expand Down Expand Up @@ -8390,6 +8401,9 @@
"location": {
"$ref": "#/definitions/common.Location"
},
"regionId": {
"type": "string"
},
"regionName": {
"type": "string"
},
Expand Down
10 changes: 10 additions & 0 deletions src/api/rest/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ definitions:
type: string
location:
$ref: '#/definitions/common.Location'
regionId:
type: string
regionName:
type: string
zones:
Expand Down Expand Up @@ -4211,6 +4213,8 @@ paths:
- reboot
- terminate
- refine
- continue
- withdraw
in: query
name: action
required: true
Expand Down Expand Up @@ -5702,6 +5706,12 @@ paths:
required: true
schema:
$ref: '#/definitions/mcis.TbMcisDynamicReq'
- description: Option for MCIS creation
enum:
- hold
in: query
name: option
type: string
produces:
- application/json
responses:
Expand Down
6 changes: 3 additions & 3 deletions src/api/rest/server/mcis/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
// @Produce json
// @Param nsId path string true "Namespace ID" default(ns01)
// @Param mcisId path string true "MCIS ID" default(mcis01)
// @Param action query string true "Action to MCIS" Enums(suspend, resume, reboot, terminate, refine)
// @Param action query string true "Action to MCIS" Enums(suspend, resume, reboot, terminate, refine, continue, withdraw)
// @Param force query string false "Force control to skip checking controllable status" Enums(false, true)
// @Success 200 {object} common.SimpleMsg
// @Failure 404 {object} common.SimpleMsg
Expand All @@ -53,7 +53,7 @@ func RestGetControlMcis(c echo.Context) error {
}
returnObj := common.SimpleMsg{}

if action == "suspend" || action == "resume" || action == "reboot" || action == "terminate" || action == "refine" {
if action == "suspend" || action == "resume" || action == "reboot" || action == "terminate" || action == "refine" || action == "continue" || action == "withdraw" {

resultString, err := mcis.HandleMcisAction(nsId, mcisId, action, forceOption)
if err != nil {
Expand All @@ -63,7 +63,7 @@ func RestGetControlMcis(c echo.Context) error {
return common.EndRequestWithLog(c, reqID, err, returnObj)

} else {
err := fmt.Errorf("'action' should be one of these: suspend, resume, reboot, terminate, refine")
err := fmt.Errorf("'action' should be one of these: suspend, resume, reboot, terminate, refine, continue, withdraw")
return common.EndRequestWithLog(c, reqID, err, returnObj)
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/api/rest/server/mcis/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func RestPostSystemMcis(c echo.Context) error {
// @Produce json
// @Param nsId path string true "Namespace ID" default(ns01)
// @Param mcisReq body TbMcisDynamicReq true "Request body to provision MCIS dynamically"
// @Param option query string false "Option for MCIS creation" Enums(hold)
// @Success 200 {object} TbMcisInfo
// @Failure 404 {object} common.SimpleMsg
// @Failure 500 {object} common.SimpleMsg
Expand All @@ -125,13 +126,14 @@ func RestPostMcisDynamic(c echo.Context) error {
return c.JSON(http.StatusBadRequest, map[string]string{"message": idErr.Error()})
}
nsId := c.Param("nsId")
option := c.QueryParam("option")

req := &mcis.TbMcisDynamicReq{}
if err := c.Bind(req); err != nil {
return common.EndRequestWithLog(c, reqID, err, nil)
}

result, err := mcis.CreateMcisDynamic(nsId, req)
result, err := mcis.CreateMcisDynamic(nsId, req, option)
return common.EndRequestWithLog(c, reqID, err, result)
}

Expand Down
5 changes: 5 additions & 0 deletions src/core/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type CSPDetail struct {

// RegionDetail is structure for region information
type RegionDetail struct {
RegionId string `mapstructure:"id" json:"regionId"`
RegionName string `mapstructure:"regionName" json:"regionName"`
Description string `mapstructure:"description" json:"description"`
Location Location `mapstructure:"location" json:"location"`
Expand Down Expand Up @@ -73,6 +74,10 @@ func AdjustKeysToLowercase(cloudInfo *CloudInfo) {
for regionKey, regionDetail := range cspDetail.Regions {
lowerRegionKey := strings.ToLower(regionKey)
regionDetail.RegionName = lowerRegionKey
// keep the original regionId if it is not empty (some CSP uses regionName case-sensitive)
if regionDetail.RegionId == "" {
regionDetail.RegionId = regionKey
}
newRegions[lowerRegionKey] = regionDetail
}
cspDetail.Regions = newRegions
Expand Down
7 changes: 4 additions & 3 deletions src/core/common/utility.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,14 +596,15 @@ func RegisterRegionZone(providerName string, regionName string) error {
// register representative regionZone (region only)
requestBody.RegionName = providerName + "-" + regionName
keyValueInfoList := []KeyValue{}

if len(RuntimeCloudInfo.CSPs[providerName].Regions[regionName].Zones) > 0 {
keyValueInfoList = []KeyValue{
{Key: "Region", Value: regionName},
{Key: "Region", Value: RuntimeCloudInfo.CSPs[providerName].Regions[regionName].RegionId},
{Key: "Zone", Value: RuntimeCloudInfo.CSPs[providerName].Regions[regionName].Zones[0]},
}
} else {
keyValueInfoList = []KeyValue{
{Key: "Region", Value: regionName},
{Key: "Region", Value: RuntimeCloudInfo.CSPs[providerName].Regions[regionName].RegionId},
{Key: "Zone", Value: "N/A"},
}
}
Expand All @@ -629,7 +630,7 @@ func RegisterRegionZone(providerName string, regionName string) error {
for _, zoneName := range RuntimeCloudInfo.CSPs[providerName].Regions[regionName].Zones {
requestBody.RegionName = providerName + "-" + regionName + "-" + zoneName
keyValueInfoList := []KeyValue{
{Key: "Region", Value: regionName},
{Key: "Region", Value: RuntimeCloudInfo.CSPs[providerName].Regions[regionName].RegionId},
{Key: "Zone", Value: zoneName},
}
requestBody.AvailableZoneList = RuntimeCloudInfo.CSPs[providerName].Regions[regionName].Zones
Expand Down
11 changes: 5 additions & 6 deletions src/core/mcir/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -1651,12 +1651,12 @@ func LoadCommonResource() (common.IdList, error) {
// Update registered Spec object with Cost info
costPerHour, err2 := strconv.ParseFloat(strings.ReplaceAll(row[3], " ", ""), 32)
if err2 != nil {
log.Error().Err(err2).Msg("Not valid CostPerHour value in the asset")
log.Error().Msgf("Not valid CostPerHour value in the asset: %s", specInfoId)
costPerHour = 99999999.9
}
evaluationScore01, err2 := strconv.ParseFloat(strings.ReplaceAll(row[4], " ", ""), 32)
if err2 != nil {
log.Error().Err(err2).Msg("Not valid evaluationScore01 value in the asset")
log.Error().Msgf("Not valid evaluationScore01 value in the asset: %s", specInfoId)
evaluationScore01 = -99.9
}
specUpdateRequest :=
Expand Down Expand Up @@ -1912,12 +1912,12 @@ func LoadDefaultResource(nsId string, resType string, connectionName string) err

common.PrintJsonPretty(reqTmp)

resultInfo, err := CreateSshKey(nsId, &reqTmp, "")
_, err := CreateSshKey(nsId, &reqTmp, "")
if err != nil {
log.Error().Err(err).Msg("Failed to create SshKey")
return err
}
common.PrintJsonPretty(resultInfo)
// common.PrintJsonPretty(resultInfo)
} else {
return errors.New("Not valid option (provide sg, sshkey, vnet, or all)")
}
Expand Down Expand Up @@ -1981,9 +1981,8 @@ func ToNamingRuleCompatible(rawName string) string {
// UpdateResourceObject is func to update the resource object
func UpdateResourceObject(nsId string, resourceType string, resourceObject interface{}) {
resourceId, err := GetIdFromStruct(resourceObject)
fmt.Printf("in UpdateResourceObject; extracted resourceId: %s \n", resourceId) // for debug
if resourceId == "" || err != nil {
fmt.Printf("in UpdateResourceObject; failed to extract resourceId. \n") // for debug
log.Debug().Msgf("in UpdateResourceObject; failed to extract resourceId") // for debug
return
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/mcir/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ func FilterSpecsByRange(nsId string, filter FilterSpecsByRangeRequest) ([]TbSpec

// Convert the first letter of the field name to lowercase to match typical database column naming conventions
dbFieldName := strings.ToLower(field.Name[:1]) + field.Name[1:]
log.Info().Msgf("Field: %s, Value: %v", dbFieldName, value)
log.Debug().Msgf("Field: %s, Value: %v", dbFieldName, value)

if value.Kind() == reflect.Struct {
// Handle range filters like VCPU, MemoryGiB, etc.
Expand Down
14 changes: 14 additions & 0 deletions src/core/mcis/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ func HandleMcisAction(nsId string, mcisId string, action string, force bool) (st

return "Terminated the MCIS", nil

} else if action == "continue" {
log.Debug().Msg("[continue MCIS provisioning]")
key := common.GenMcisKey(nsId, mcisId, "")
holdingMcisMap.Store(key, action)

return "Continue the holding MCIS", nil

} else if action == "withdraw" {
log.Debug().Msg("[withdraw MCIS provisioning]")
key := common.GenMcisKey(nsId, mcisId, "")
holdingMcisMap.Store(key, action)

return "Withdraw the holding MCIS", nil

} else if action == "refine" { // refine delete VMs in StatusFailed or StatusUndefined
log.Debug().Msg("[refine MCIS]")

Expand Down
2 changes: 1 addition & 1 deletion src/core/mcis/nlb.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func CreateMcSwNlb(nsId string, mcisId string, req *TbNLBReq, option string) (Mc
vmDynamicReq := TbVmDynamicReq{Name: vmGroupName, CommonSpec: commonSpec, CommonImage: commonImage, SubGroupSize: subGroupSize}
mcisDynamicReq.Vm = append(mcisDynamicReq.Vm, vmDynamicReq)

mcisInfo, err := CreateMcisDynamic(nsId, &mcisDynamicReq)
mcisInfo, err := CreateMcisDynamic(nsId, &mcisDynamicReq, "")
if err != nil {
log.Error().Err(err).Msg("")
return emptyObj, err
Expand Down
38 changes: 35 additions & 3 deletions src/core/mcis/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ type TbVmRecommendInfo struct {
PlacementParam []common.KeyValue `json:"placementParam"`
}

var holdingMcisMap sync.Map

// MCIS and VM Provisioning

// CreateMcisVm is func to post (create) McisVm
Expand Down Expand Up @@ -957,6 +959,32 @@ func CreateMcis(nsId string, req *TbMcisReq, option string) (*TbMcisInfo, error)
}
}

// hold option will hold the MCIS creation process until the user releases it.
if option == "hold" {
key := common.GenMcisKey(nsId, mcisId, "")
holdingMcisMap.Store(key, "holding")
for {
value, ok := holdingMcisMap.Load(key)
if !ok {
break
}
if value == "continue" {
holdingMcisMap.Delete(key)
break
} else if value == "withdraw" {
holdingMcisMap.Delete(key)
DelMcis(nsId, mcisId, "force")
err := fmt.Errorf("Withdrawed MCIS creation")
log.Error().Err(err).Msg("")
return nil, err
}

log.Info().Msgf("MCIS: %s (holding)", key)
time.Sleep(5 * time.Second)
}
option = "create"
}

//goroutin
var wg sync.WaitGroup

Expand Down Expand Up @@ -1222,11 +1250,11 @@ func CreateSystemMcisDynamic(option string) (*TbMcisInfo, error) {
return nil, err
}

return CreateMcisDynamic(nsId, req)
return CreateMcisDynamic(nsId, req, "")
}

// CreateMcisDynamic is func to create MCIS obeject and deploy requested VMs in a dynamic way
func CreateMcisDynamic(nsId string, req *TbMcisDynamicReq) (*TbMcisInfo, error) {
func CreateMcisDynamic(nsId string, req *TbMcisDynamicReq, deployOption string) (*TbMcisInfo, error) {

mcisReq := TbMcisReq{}
mcisReq.Name = req.Name
Expand Down Expand Up @@ -1290,6 +1318,9 @@ func CreateMcisDynamic(nsId string, req *TbMcisDynamicReq) (*TbMcisInfo, error)

// Run create MCIS with the generated MCIS request (option != register)
option := "create"
if deployOption == "hold" {
option = "hold"
}
return CreateMcis(nsId, &mcisReq, option)
}

Expand Down Expand Up @@ -1643,6 +1674,7 @@ func CreateVm(nsId string, mcisId string, vmInfoData *TbVmInfo, option string) e
// Try lookup customImage
requestBody.ReqInfo.ImageName, err = common.GetCspResourceId(nsId, common.StrCustomImage, vmInfoData.ImageId)
if requestBody.ReqInfo.ImageName == "" || err != nil {
log.Warn().Msgf("Not found the Image: %s in nsId: %s, find it from SystemCommonNs", vmInfoData.ImageId, nsId)
errAgg := err.Error()
// If customImage doesn't exist, then try lookup image
requestBody.ReqInfo.ImageName, err = common.GetCspResourceId(nsId, common.StrImage, vmInfoData.ImageId)
Expand All @@ -1668,7 +1700,7 @@ func CreateVm(nsId string, mcisId string, vmInfoData *TbVmInfo, option string) e

requestBody.ReqInfo.VMSpecName, err = common.GetCspResourceId(nsId, common.StrSpec, vmInfoData.SpecId)
if requestBody.ReqInfo.VMSpecName == "" || err != nil {
log.Warn().Msg(err.Error())
log.Warn().Msgf("Not found the Spec: %s in nsId: %s, find it from SystemCommonNs", vmInfoData.SpecId, nsId)
errAgg := err.Error()
// If cannot find the resource, use common resource
requestBody.ReqInfo.VMSpecName, err = common.GetCspResourceId(common.SystemCommonNs, common.StrSpec, vmInfoData.SpecId)
Expand Down
2 changes: 1 addition & 1 deletion src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func setConfig() {

for attempt < maxAttempts {
if common.CheckSpiderReady() == nil {
log.Info().Msg("CB-Spider is now ready.")
log.Info().Msg("CB-Spider is now ready. Initializing CB-Tumblebug...")
break
}
log.Info().Msgf("CB-Spider at %s is not ready. Attempt %d/%d", common.SpiderRestUrl, attempt+1, maxAttempts)
Expand Down

0 comments on commit 61d193d

Please sign in to comment.