From e6632d75d2676823f4e436153230df173ad5a089 Mon Sep 17 00:00:00 2001 From: Seokho Son Date: Mon, 3 Jun 2024 21:07:52 +0900 Subject: [PATCH] Provide mcis dynamic interal progress using requestlog --- src/api/rest/server/mcis/provisioning.go | 14 +++++++------ src/core/common/client.go | 25 ++++++++++++++++++++++++ src/core/mcis/nlb.go | 2 +- src/core/mcis/provisioning.go | 21 +++++++++++++++----- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/api/rest/server/mcis/provisioning.go b/src/api/rest/server/mcis/provisioning.go index 9adb5dda8..12db3a36a 100644 --- a/src/api/rest/server/mcis/provisioning.go +++ b/src/api/rest/server/mcis/provisioning.go @@ -120,15 +120,14 @@ func RestPostSystemMcis(c echo.Context) error { // @Param nsId path string true "Namespace ID" default(ns01) // @Param mcisReq body TbMcisDynamicReq true "Request body to provision MCIS dynamically. Must include commonSpec and commonImage info of each VM request.(ex: {name: mcis01,vm: [{commonImage: aws+ap-northeast-2+ubuntu22.04,commonSpec: aws+ap-northeast-2+t2.small}]} ) You can use /mcisRecommendVm and /mcisDynamicCheckRequest to get it) Check the guide: https://github.com/cloud-barista/cb-tumblebug/discussions/1570" // @Param option query string false "Option for MCIS creation" Enums(hold) +// @Param x-request-id header string false "Custom request ID" // @Success 200 {object} TbMcisInfo // @Failure 404 {object} common.SimpleMsg // @Failure 500 {object} common.SimpleMsg // @Router /ns/{nsId}/mcisDynamic [post] func RestPostMcisDynamic(c echo.Context) error { - reqID, idErr := common.StartRequestWithLog(c) - if idErr != nil { - return c.JSON(http.StatusBadRequest, map[string]string{"message": idErr.Error()}) - } + reqID := c.Request().Header.Get(echo.HeaderXRequestID) + nsId := c.Param("nsId") option := c.QueryParam("option") @@ -137,8 +136,11 @@ func RestPostMcisDynamic(c echo.Context) error { return common.EndRequestWithLog(c, reqID, err, nil) } - result, err := mcis.CreateMcisDynamic(nsId, req, option) - return common.EndRequestWithLog(c, reqID, err, result) + result, err := mcis.CreateMcisDynamic(reqID, nsId, req, option) + if err != nil { + return common.EndRequestWithLog(c, reqID, err, nil) + } + return c.JSON(http.StatusOK, result) } // RestPostMcisVmDynamic godoc diff --git a/src/core/common/client.go b/src/core/common/client.go index be9645826..8161a6b81 100644 --- a/src/core/common/client.go +++ b/src/core/common/client.go @@ -251,6 +251,13 @@ type RequestDetails struct { // RequestMap is a map for request details var RequestMap = sync.Map{} +// ProgressInfo contains the progress information of a request. +type ProgressInfo struct { + Title string `json:"title"` + Info interface{} `json:"info"` + Time time.Time `json:"time"` +} + // ExtractRequestInfo extracts necessary information from http.Request func ExtractRequestInfo(r *http.Request) RequestInfo { headerInfo := make(map[string]string) @@ -326,6 +333,24 @@ func EndRequestWithLog(c echo.Context, reqID string, err error, responseData int return c.JSON(http.StatusNotFound, map[string]string{"message": "Invalid Request ID"}) } +// UpdateRequestProgress updates the handling status of the request. +func UpdateRequestProgress(reqID string, progressData interface{}) { + if v, ok := RequestMap.Load(reqID); ok { + details := v.(RequestDetails) + + var responseData []interface{} + if details.ResponseData != nil { + // Convert existing ResponseData to []interface{} + responseData = details.ResponseData.([]interface{}) + } + // Append the new progressData to the existing ResponseData + responseData = append(responseData, progressData) + details.ResponseData = responseData + + RequestMap.Store(reqID, details) + } +} + // ForwardRequestToAny forwards the given request to the specified path func ForwardRequestToAny(reqPath string, method string, requestBody interface{}) (interface{}, error) { client := resty.New() diff --git a/src/core/mcis/nlb.go b/src/core/mcis/nlb.go index 9102b8422..051c7921c 100644 --- a/src/core/mcis/nlb.go +++ b/src/core/mcis/nlb.go @@ -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 diff --git a/src/core/mcis/provisioning.go b/src/core/mcis/provisioning.go index 25725e9d4..685022635 100644 --- a/src/core/mcis/provisioning.go +++ b/src/core/mcis/provisioning.go @@ -1255,11 +1255,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, deployOption string) (*TbMcisInfo, error) { +func CreateMcisDynamic(reqID string, nsId string, req *TbMcisDynamicReq, deployOption string) (*TbMcisInfo, error) { mcisReq := TbMcisReq{} mcisReq.Name = req.Name @@ -1301,7 +1301,7 @@ func CreateMcisDynamic(nsId string, req *TbMcisDynamicReq, deployOption string) //If not, generate default resources dynamically. for _, k := range vmRequest { - vmReq, err := getVmReqFromDynamicReq(nsId, &k) + vmReq, err := getVmReqFromDynamicReq(reqID, nsId, &k) if err != nil { log.Error().Err(err).Msg("Failed to prefare resources for dynamic MCIS creation") // Rollback created default resources @@ -1320,6 +1320,8 @@ func CreateMcisDynamic(nsId string, req *TbMcisDynamicReq, deployOption string) } common.PrintJsonPretty(mcisReq) + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Prepared all resources for provisioning MCIS:" + mcisReq.Name, Info: mcisReq, Time: time.Now()}) + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Start provisioning", Time: time.Now()}) // Run create MCIS with the generated MCIS request (option != register) option := "create" @@ -1344,7 +1346,7 @@ func CreateMcisVmDynamic(nsId string, mcisId string, req *TbVmDynamicReq) (*TbMc return emptyMcis, err } - vmReq, err := getVmReqFromDynamicReq(nsId, req) + vmReq, err := getVmReqFromDynamicReq("", nsId, req) if err != nil { log.Error().Err(err).Msg("") return emptyMcis, err @@ -1408,7 +1410,7 @@ func checkCommonResAvailable(req *TbVmDynamicReq) error { } // getVmReqForDynamicMcis is func to getVmReqFromDynamicReq -func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) { +func getVmReqFromDynamicReq(reqID string, nsId string, req *TbVmDynamicReq) (*TbVmReq, error) { onDemand := true @@ -1464,6 +1466,8 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) return &TbVmReq{}, err } + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Setting vNet:" + resourceName, Time: time.Now()}) + vmReq.VNetId = resourceName tempInterface, err = mcir.GetResource(nsId, common.StrVNet, vmReq.VNetId) if err != nil { @@ -1472,6 +1476,7 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) log.Error().Err(err).Msg("Failed to get the vNet") return &TbVmReq{}, err } + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Loading default vNet:" + resourceName, Time: time.Now()}) err2 := mcir.LoadDefaultResource(nsId, common.StrVNet, vmReq.ConnectionName) if err2 != nil { log.Error().Err(err2).Msg("Failed to create new default vNet " + vmReq.VNetId + " from " + vmReq.ConnectionName) @@ -1484,6 +1489,7 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) } vmReq.SubnetId = resourceName + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Setting SSHKey:" + resourceName, Time: time.Now()}) vmReq.SshKeyId = resourceName tempInterface, err = mcir.GetResource(nsId, common.StrSSHKey, vmReq.SshKeyId) if err != nil { @@ -1492,6 +1498,7 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) log.Error().Err(err).Msg("Failed to get the SSHKey") return &TbVmReq{}, err } + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Loading default SSHKey:" + resourceName, Time: time.Now()}) err2 := mcir.LoadDefaultResource(nsId, common.StrSSHKey, vmReq.ConnectionName) if err2 != nil { log.Error().Err(err2).Msg("Failed to create new default SSHKey " + vmReq.SshKeyId + " from " + vmReq.ConnectionName) @@ -1502,6 +1509,8 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) } else { log.Info().Msg("Found and utilize default SSHKey: " + vmReq.VNetId) } + + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Setting securityGroup:" + resourceName, Time: time.Now()}) securityGroup := resourceName vmReq.SecurityGroupIds = append(vmReq.SecurityGroupIds, securityGroup) tempInterface, err = mcir.GetResource(nsId, common.StrSecurityGroup, securityGroup) @@ -1511,6 +1520,7 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) log.Error().Err(err).Msg("Failed to get the securityGroup") return &TbVmReq{}, err } + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Loading default securityGroup:" + resourceName, Time: time.Now()}) err2 := mcir.LoadDefaultResource(nsId, common.StrSecurityGroup, vmReq.ConnectionName) if err2 != nil { log.Error().Err(err2).Msg("Failed to create new default securityGroup " + securityGroup + " from " + vmReq.ConnectionName) @@ -1534,6 +1544,7 @@ func getVmReqFromDynamicReq(nsId string, req *TbVmDynamicReq) (*TbVmReq, error) vmReq.VmUserPassword = k.VmUserPassword common.PrintJsonPretty(vmReq) + common.UpdateRequestProgress(reqID, common.ProgressInfo{Title: "Prepared resources for VM:" + vmReq.Name, Info: vmReq, Time: time.Now()}) return vmReq, nil }