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

Feature/add backup restore #51

Merged
merged 3 commits into from
Sep 9, 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
10 changes: 10 additions & 0 deletions data/example/RDB/aws.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"operationId": "opt-00735",
"targetPoint": {
"provider": "aws",
"host": "database-1.c36826os8m6p.ap-northeast-2.rds.amazonaws.com",
"port": "3306",
"username": "admin",
"password": "NAmutech7^^7"
}
}
569 changes: 0 additions & 569 deletions internal/auth/base.go

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions pkg/rdbms/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,13 @@ func (d *MysqlDBMS) GetInsert(dbName, tableName string, insertSql *[]string) err
columns = append(columns, columnName)
}

selectQuery := "SELECT " + strings.Join(columns, ", ") + " FROM " + tableName
tableName = escapeColumnName(tableName)
escapedColumns := make([]string, len(columns))
for i, column := range columns {
escapedColumns[i] = escapeColumnName(column)
}

selectQuery := "SELECT " + strings.Join(escapedColumns, ", ") + " FROM " + tableName
selRows, err := d.db.Query(selectQuery)
if err != nil {
return err
Expand All @@ -218,6 +224,7 @@ func (d *MysqlDBMS) GetInsert(dbName, tableName string, insertSql *[]string) err

err := selRows.Scan(valuePtrs...)
if err != nil {

return err
}

Expand All @@ -231,10 +238,7 @@ func (d *MysqlDBMS) GetInsert(dbName, tableName string, insertSql *[]string) err

for _, entry := range data {
values := []string{}
escapedColumns := []string{}
for _, column := range columns {
escapedColumn := escapeColumnName(column)
escapedColumns = append(escapedColumns, escapedColumn)
val := entry[column]
if val.Valid {
escapedValue := ReplaceEscapeString(val.String)
Expand Down
7 changes: 7 additions & 0 deletions service/rdbc/rdbc.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func New(rdb RDBMS, opts ...Option) (*RDBController, error) {
func (rdb *RDBController) ListDB(dst *[]string) error {
err := rdb.client.ListDB(dst)
if err != nil {
logrus.Info("RDB", *dst)
return err
}
return nil
Expand Down Expand Up @@ -155,20 +156,25 @@ func (rdb *RDBController) Copy(dst *RDBController) error {
func (rdb *RDBController) Get(dbName string, sql *string) error {
var sqlTemp string
if err := rdb.client.ShowCreateDBSql(dbName, &sqlTemp); err != nil {
logrus.Error("ERR DB")
return err
}
sqlWrite(sql, sqlTemp)
sqlWrite(sql, fmt.Sprintf("USE %s;", dbName))

var tableList []string
if err := rdb.client.ListTable(dbName, &tableList); err != nil {
logrus.Error("ERR List TB")

return err
}

for _, table := range tableList {
sqlWrite(sql, fmt.Sprintf("DROP TABLE IF EXISTS %s;", table))

if err := rdb.client.ShowCreateTableSql(dbName, table, &sqlTemp); err != nil {
logrus.Error("ERR Creatte TB")

return err
}
sqlWrite(sql, sqlTemp)
Expand All @@ -177,6 +183,7 @@ func (rdb *RDBController) Get(dbName string, sql *string) error {
for _, table := range tableList {
var insertData []string
if err := rdb.client.GetInsert(dbName, table, &insertData); err != nil {
logrus.Error("Insert quer err")
return err
}

Expand Down
221 changes: 220 additions & 1 deletion websrc/controllers/backupHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,228 @@ limitations under the License.
package controllers

import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"time"

"github.com/cloud-barista/mc-data-manager/internal/auth"
"github.com/cloud-barista/mc-data-manager/models"
"github.com/cloud-barista/mc-data-manager/service/nrdbc"
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
)

func BackupRootHandler(ctx echo.Context) {
// BackupOSPostHandler godoc
//
// @Summary Export data from objectstorage
// @Description Export data from a objectstorage to files.
// @Tags [Data Export], [Object Storage]
// @Accept json
// @Produce json
// @Param RequestBody body models.BackupTask true "Parameters required for backup"
// @Success 200 {object} models.BasicResponse "Successfully backup data"
// @Failure 500 {object} models.BasicResponse "Internal Server Error"
// @Router /backup/objectstorage [post]
func BackupOSPostHandler(ctx echo.Context) error {
start := time.Now()
logger, logstrings := pageLogInit("backup-objectstorage", "Export data from objectstorage", start)
params := models.BackupTask{}
if !getDataWithReBind(logger, start, ctx, &params) {
return ctx.JSON(http.StatusOK, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

switch params.SourcePoint.Provider {
case string(models.AWS):
return MigrationS3ToLinuxPostHandler(ctx)
case string(models.NCP):
return MigrationNCPToLinuxPostHandler(ctx)
case string(models.GCP):
return MigrationGCPToLinuxPostHandler(ctx)
default:
logger.Errorf("Unsupported provider: %v", params.SourcePoint.Provider)
errorMsg := fmt.Sprintf("unsupported provider: %v", params.SourcePoint.Provider)
return ctx.JSON(http.StatusBadRequest, models.BasicResponse{
Result: logstrings.String(),
Error: &errorMsg,
})
}
}

// BackupMySQLPostHandler godoc
//
// @Summary Export data from MySQL
// @Description Export data from a MySQL database to SQL files.
// @Tags [Data Export], [RDBMS]
// @Accept json
// @Produce json
// @Param RequestBody body models.BackupTask true "Parameters required for backup"
// @Success 200 {object} models.BasicResponse "Successfully backup data"
// @Failure 500 {object} models.BasicResponse "Internal Server Error"
// @Router /backup/rdb [post]
func BackupRDBPostHandler(ctx echo.Context) error {

var err error

start := time.Now()

logger, logstrings := pageLogInit("migmysql", "Export data from mysql", start)

params := models.BackupTask{}
if !getDataWithBind(logger, start, ctx, &params) {
return ctx.JSON(http.StatusOK, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

rdbc := getMysqlRDBC(logger, start, "smig", params.SourcePoint)
if rdbc == nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

err = os.MkdirAll(params.TargetPoint.Path, 0755)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}
dbList := []string{}
if err := rdbc.ListDB(&dbList); err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

var sqlData string
for _, db := range dbList {
sqlData = ""
if err := rdbc.Get(db, &sqlData); err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

file, err := os.Create(filepath.Join(params.TargetPoint.Path, fmt.Sprintf("%s.sql", db)))
if err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}
defer file.Close()

_, err = file.WriteString(sqlData)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}
logrus.Infof("successfully exported : %s", file.Name())
file.Close()
}

jobEnd(logger, "Successfully exported data from mysql", start)
return ctx.JSON(http.StatusOK, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})

}

// BackupMySQLPostHandler godoc
//
// @Summary Export data from MySQL
// @Description Export data from a MySQL database to SQL files.
// @Tags [Data Export], [RDBMS]
// @Accept json
// @Produce json
// @Param RequestBody body models.BackupTask true "Parameters required for backup"
// @Success 200 {object} models.BasicResponse "Successfully backup data"
// @Failure 500 {object} models.BasicResponse "Internal Server Error"
// @Router /backup/nrdb [post]
func BackupNRDBPostHandler(ctx echo.Context) error {

var NRDBC *nrdbc.NRDBController
var err error
start := time.Now()

logger, logstrings := pageLogInit("backup-nrdb", "backup data from nrdb", start)

params := models.BackupTask{}
if !getDataWithReBind(logger, start, ctx, &params) {
return ctx.JSON(http.StatusOK, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

NRDBC, err = auth.GetNRDMS(&params.SourcePoint)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

err = os.MkdirAll(params.TargetPoint.Path, 0755)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

tableList, err := NRDBC.ListTables()
if err != nil {
return ctx.JSON(http.StatusInternalServerError, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}

var dstData []map[string]interface{}
for _, table := range tableList {
logrus.Infof("Export start: %s", table)
dstData = []map[string]interface{}{}

if err := NRDBC.Get(table, &dstData); err != nil {
logrus.Errorf("Get error : %v", err)
return err
}

file, err := os.Create(filepath.Join(params.TargetPoint.Path, fmt.Sprintf("%s.json", table)))
if err != nil {
logrus.Errorf("File create error : %v", err)
return err
}
defer file.Close()

encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
if err := encoder.Encode(dstData); err != nil {
logrus.Errorf("data encoding error : %v", err)
return err
}
logrus.Infof("successfully exported : %s", file.Name())
}

jobEnd(logger, "Successfully exported data from mysql", start)
return ctx.JSON(http.StatusOK, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})

}
Loading