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

Add remote file transfer feature #1821

Merged
merged 1 commit into from
Sep 20, 2024
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
89 changes: 89 additions & 0 deletions src/api/rest/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8535,6 +8535,95 @@ const docTemplate = `{
}
}
},
"/ns/{nsId}/transferFile/mci/{mciId}": {
"post": {
"description": "Transfer a file to specified MCI to the specified path.\nThe file size should be less than 10MB.\nNot for gerneral file transfer but for specific purpose (small configuration files).",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
"[MC-Infra] MCI Remote Command"
],
"summary": "Transfer a file to specified MCI",
"operationId": "PostFileToMci",
"parameters": [
{
"type": "string",
"default": "default",
"description": "Namespace ID",
"name": "nsId",
"in": "path",
"required": true
},
{
"type": "string",
"default": "mci01",
"description": "MCI ID",
"name": "mciId",
"in": "path",
"required": true
},
{
"type": "string",
"default": "g1",
"description": "subGroupId to apply the file transfer only for VMs in subGroup of MCI",
"name": "subGroupId",
"in": "query"
},
{
"type": "string",
"default": "g1-1",
"description": "vmId to apply the file transfer only for a VM in MCI",
"name": "vmId",
"in": "query"
},
{
"type": "string",
"default": "/home/cb-user/",
"description": "Target path where the file will be stored",
"name": "path",
"in": "formData",
"required": true
},
{
"type": "file",
"description": "The file to be uploaded (Max 10MB)",
"name": "file",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "Custom request ID",
"name": "x-request-id",
"in": "header"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/model.MciSshCmdResult"
}
},
"400": {
"description": "Invalid request",
"schema": {
"$ref": "#/definitions/model.SimpleMsg"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/model.SimpleMsg"
}
}
}
}
},
"/object": {
"get": {
"description": "Get value of an object",
Expand Down
89 changes: 89 additions & 0 deletions src/api/rest/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -8529,6 +8529,95 @@
}
}
},
"/ns/{nsId}/transferFile/mci/{mciId}": {
"post": {
"description": "Transfer a file to specified MCI to the specified path.\nThe file size should be less than 10MB.\nNot for gerneral file transfer but for specific purpose (small configuration files).",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
"[MC-Infra] MCI Remote Command"
],
"summary": "Transfer a file to specified MCI",
"operationId": "PostFileToMci",
"parameters": [
{
"type": "string",
"default": "default",
"description": "Namespace ID",
"name": "nsId",
"in": "path",
"required": true
},
{
"type": "string",
"default": "mci01",
"description": "MCI ID",
"name": "mciId",
"in": "path",
"required": true
},
{
"type": "string",
"default": "g1",
"description": "subGroupId to apply the file transfer only for VMs in subGroup of MCI",
"name": "subGroupId",
"in": "query"
},
{
"type": "string",
"default": "g1-1",
"description": "vmId to apply the file transfer only for a VM in MCI",
"name": "vmId",
"in": "query"
},
{
"type": "string",
"default": "/home/cb-user/",
"description": "Target path where the file will be stored",
"name": "path",
"in": "formData",
"required": true
},
{
"type": "file",
"description": "The file to be uploaded (Max 10MB)",
"name": "file",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "Custom request ID",
"name": "x-request-id",
"in": "header"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/model.MciSshCmdResult"
}
},
"400": {
"description": "Invalid request",
"schema": {
"$ref": "#/definitions/model.SimpleMsg"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/model.SimpleMsg"
}
}
}
}
},
"/object": {
"get": {
"description": "Get value of an object",
Expand Down
80 changes: 80 additions & 0 deletions src/api/rest/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6448,6 +6448,86 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/model.SimpleMsg'
/ns/{nsId}/transferFile/mci/{mciId}:
post:
tags:
- "[MC-Infra] MCI Remote Command"
summary: Transfer a file to specified MCI
description: |-
Transfer a file to specified MCI to the specified path.
The file size should be less than 10MB.
Not for gerneral file transfer but for specific purpose (small configuration files).
operationId: PostFileToMci
parameters:
- name: nsId
in: path
description: Namespace ID
required: true
schema:
type: string
default: default
- name: mciId
in: path
description: MCI ID
required: true
schema:
type: string
default: mci01
- name: subGroupId
in: query
description: subGroupId to apply the file transfer only for VMs in subGroup
of MCI
schema:
type: string
default: g1
- name: vmId
in: query
description: vmId to apply the file transfer only for a VM in MCI
schema:
type: string
default: g1-1
- name: x-request-id
in: header
description: Custom request ID
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
required:
- file
- path
type: object
properties:
path:
type: string
description: Target path where the file will be stored
default: /home/cb-user/
file:
type: string
description: The file to be uploaded (Max 10MB)
format: binary
required: true
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/model.MciSshCmdResult'
"400":
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/model.SimpleMsg'
"500":
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/model.SimpleMsg'
/object:
get:
tags:
Expand Down
78 changes: 78 additions & 0 deletions src/api/rest/server/infra/remoteCommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ limitations under the License.
package infra

import (
"fmt"
"io"
"net/http"

"github.com/cloud-barista/cb-tumblebug/src/core/common"
Expand Down Expand Up @@ -76,6 +78,82 @@ func RestPostCmdMci(c echo.Context) error {

}

// RestPostFileToMci godoc
// @ID PostFileToMci
// @Summary Transfer a file to specified MCI
// @Description Transfer a file to specified MCI to the specified path.
// @Description The file size should be less than 10MB.
// @Description Not for gerneral file transfer but for specific purpose (small configuration files).
// @Tags [MC-Infra] MCI Remote Command
// @Accept multipart/form-data
// @Produce json
// @Param nsId path string true "Namespace ID" default(default)
// @Param mciId path string true "MCI ID" default(mci01)
// @Param subGroupId query string false "subGroupId to apply the file transfer only for VMs in subGroup of MCI" default(g1)
// @Param vmId query string false "vmId to apply the file transfer only for a VM in MCI" default(g1-1)
// @Param path formData string true "Target path where the file will be stored" default(/home/cb-user/)
// @Param file formData file true "The file to be uploaded (Max 10MB)"
// @Param x-request-id header string false "Custom request ID"
// @Success 200 {object} model.MciSshCmdResult
// @Failure 400 {object} model.SimpleMsg "Invalid request"
// @Failure 500 {object} model.SimpleMsg "Internal Server Error"
// @Router /ns/{nsId}/transferFile/mci/{mciId} [post]
func RestPostFileToMci(c echo.Context) error {
reqID, idErr := common.StartRequestWithLog(c)
if idErr != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"message": idErr.Error()})
}
nsId := c.Param("nsId")
mciId := c.Param("mciId")
subGroupId := c.QueryParam("subGroupId")
vmId := c.QueryParam("vmId")
targetPath := c.FormValue("path")

if targetPath == "" {
err := fmt.Errorf("target path is required")
return common.EndRequestWithLog(c, reqID, err, nil)
}

// Validate the file
file, err := c.FormFile("file")
if err != nil {
err = fmt.Errorf("failed to read the file %v", err)
return common.EndRequestWithLog(c, reqID, err, nil)
}

// File size validation
fileSizeLimit := int64(10 * 1024 * 1024) // (10MB limit)
if file.Size > fileSizeLimit {
err := fmt.Errorf("file too large, max size is %v", fileSizeLimit)
return common.EndRequestWithLog(c, reqID, err, nil)
}

// Open the file and read it into memory
src, err := file.Open()
if err != nil {
err = fmt.Errorf("failed to open the file %v", err)
return common.EndRequestWithLog(c, reqID, err, nil)
}
defer src.Close()

// Read the file into memory
fileBytes, err := io.ReadAll(src)
if err != nil {
err = fmt.Errorf("failed to read the file %v", err)
return common.EndRequestWithLog(c, reqID, err, nil)
}

// Call the TransferFileToMci function
result, err := infra.TransferFileToMci(nsId, mciId, subGroupId, vmId, fileBytes, file.Filename, targetPath)
if err != nil {
err = fmt.Errorf("failed to transfer file to mci %v", err)
return common.EndRequestWithLog(c, reqID, err, nil)
}

// Return the result
return common.EndRequestWithLog(c, reqID, err, result)
}

// RestSetBastionNodes godoc
// @ID SetBastionNodes
// @Summary Set bastion nodes for a VM
Expand Down
1 change: 1 addition & 0 deletions src/api/rest/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ func RunServer(port string) {
g.GET("/:nsId/control/mci/:mciId/vm/:vmId", rest_infra.RestGetControlMciVm)

g.POST("/:nsId/cmd/mci/:mciId", rest_infra.RestPostCmdMci)
g.POST("/:nsId/transferFile/mci/:mciId", rest_infra.RestPostFileToMci)
g.PUT("/:nsId/mci/:mciId/vm/:targetVmId/bastion/:bastionVmId", rest_infra.RestSetBastionNodes)
g.DELETE("/:nsId/mci/:mciId/bastion/:bastionVmId", rest_infra.RestRemoveBastionNodes)
g.GET("/:nsId/mci/:mciId/vm/:targetVmId/bastion", rest_infra.RestGetBastionNodes)
Expand Down
Loading