From e8e60511e94ea313e268fc52178364a9f8b87d07 Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Fri, 3 Nov 2023 16:37:20 +0300 Subject: [PATCH] feature: Queue system --- app/handlers/extension.go | 1 - app/handlers/file.go | 34 ++------ app/handlers/queue.go | 68 ++++++++++++++++ app/middleware/auth/new.go | 13 +++ app/models/queue.go | 64 +++++++++++++++ app/routes/index.go | 6 +- go.mod | 21 ++--- go.sum | 25 ++++++ internal/file/file.go | 49 ++++++++++++ internal/process_queue/install_package.go | 97 +++++++++++++++++++++++ internal/process_queue/process_queue.go | 5 ++ 11 files changed, 342 insertions(+), 41 deletions(-) create mode 100644 app/handlers/queue.go create mode 100644 app/models/queue.go create mode 100644 internal/file/file.go create mode 100644 internal/process_queue/install_package.go create mode 100644 internal/process_queue/process_queue.go diff --git a/app/handlers/extension.go b/app/handlers/extension.go index b2a5ac23..7dfcc950 100644 --- a/app/handlers/extension.go +++ b/app/handlers/extension.go @@ -133,7 +133,6 @@ func ExtensionLogger(c *fiber.Ctx) error { "request_details", formData, ) - // TODO: complete and handle mail_tags at the end return c.Type("json").SendString(`{ "status": 200, "message": "log added successfully" diff --git a/app/handlers/file.go b/app/handlers/file.go index 8ff7de6f..3f65fe9b 100644 --- a/app/handlers/file.go +++ b/app/handlers/file.go @@ -7,6 +7,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/limanmys/render-engine/app/models" "github.com/limanmys/render-engine/internal/bridge" + "github.com/limanmys/render-engine/internal/file" "github.com/limanmys/render-engine/internal/liman" "github.com/limanmys/render-engine/internal/sandbox" "github.com/limanmys/render-engine/pkg/helpers" @@ -23,37 +24,12 @@ func PutFile(c *fiber.Ctx) error { } } - server, err := liman.GetServer(&models.Server{ID: c.FormValue("server_id")}) - if err != nil { - return err - } - - session, err := bridge.GetSession( - c.Locals("user_id").(string), - server.ID, - server.IPAddress, - ) - if err != nil { - return err - } - - established := session.CreateFileConnection( + _, err := file.PutFileHandler( c.Locals("user_id").(string), - server.ID, - server.IPAddress, + c.FormValue("server_id"), + c.FormValue("remote_path"), + c.FormValue("local_path"), ) - if !established { - return logger.FiberError(fiber.StatusServiceUnavailable, "cannot establish file connection") - } - - remotePath := "" - if server.Os == "linux" { - remotePath = "/tmp/" + filepath.Base(c.FormValue("remote_path")) - } else { - remotePath = session.WindowsPath + c.FormValue("remote_path") - } - - err = session.Put(c.FormValue("local_path"), remotePath) if err != nil { return err } diff --git a/app/handlers/queue.go b/app/handlers/queue.go new file mode 100644 index 00000000..0cf8dc09 --- /dev/null +++ b/app/handlers/queue.go @@ -0,0 +1,68 @@ +package handlers + +import ( + "github.com/gofiber/fiber/v2" + "github.com/limanmys/render-engine/app/models" + "github.com/limanmys/render-engine/internal/database" + "github.com/limanmys/render-engine/internal/liman" + "github.com/limanmys/render-engine/internal/process_queue" + "github.com/limanmys/render-engine/pkg/logger" + "gorm.io/gorm" +) + +type QueueHandler struct { + db *gorm.DB +} + +func NewQueueHandler() *QueueHandler { + return &QueueHandler{ + db: database.Connection(), + } +} + +func (h *QueueHandler) Create(c *fiber.Ctx) error { + queue := &models.Queue{} + if err := c.BodyParser(&queue); err != nil { + return err + } + + if queue.Data["server_id"] == nil { + return c.Status(422).JSON(fiber.Map{ + "server_id": "server id is required", + }) + } + + // Check if user is eligible to use this server + user, _ := liman.GetUser(&models.User{ID: c.Locals("user_id").(string)}) + if user.Status == 0 { + var count int64 + h.db.Model(&models.Permission{}).Find(&models.Permission{ + MorphID: c.Locals("user_id").(string), + Type: "server", + Value: queue.Data["server_id"].(string), + }).Count(&count) + + if count < 1 { + return logger.FiberError(fiber.StatusForbidden, "you are not allowed to use this server") + } + } + + // Create queue object + if err := h.db.Create(queue).Error; err != nil { + return err + } + + // Start processing by type + var processor process_queue.ProcessQueue + switch queue.Type { + case models.OperationInstall: + processor = &process_queue.InstallPackage{ + Queue: queue, + DB: h.db, + UserID: c.Locals("user_id").(string), + } + go processor.Process() + } + + return c.JSON(queue) +} diff --git a/app/middleware/auth/new.go b/app/middleware/auth/new.go index 709ee9f2..9e7fb00f 100644 --- a/app/middleware/auth/new.go +++ b/app/middleware/auth/new.go @@ -41,5 +41,18 @@ func authorization(c *fiber.Ctx) error { return c.Next() } + if len(string(c.Request().Header.Peek("Authorization"))) > 0 { + user, err := liman.AuthWithToken( + strings.Trim(string(c.Request().Header.Peek("Authorization")), ""), + ) + + if err != nil { + return logger.FiberError(fiber.StatusUnauthorized, err.Error()) + } + + c.Locals("user_id", user) + return c.Next() + } + return logger.FiberError(fiber.StatusUnauthorized, "authorization token is missing") } diff --git a/app/models/queue.go b/app/models/queue.go new file mode 100644 index 00000000..d5c29d8d --- /dev/null +++ b/app/models/queue.go @@ -0,0 +1,64 @@ +package models + +import ( + "time" + + gormjsonb "github.com/dariubs/gorm-jsonb" + "github.com/google/uuid" + "github.com/limanmys/render-engine/internal/database" + "gorm.io/gorm" +) + +type Operation string +type Status string + +const ( + OperationCreate Operation = "create" + OperationUpdate Operation = "update" + OperationInstall Operation = "install" + + StatusPending Status = "pending" + StatusProcessing Status = "processing" + StatusDone Status = "done" + StatusFailed Status = "failed" +) + +// Queue structure of Queue object +type Queue struct { + ID string `json:"id"` + Type Operation `json:"type"` + Status Status `json:"status"` + Data gormjsonb.JSONB `json:"data" gorm:"type:jsonb;index,type:gin"` + Error string `json:"error"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +func (Queue) TableName() string { + return "queue" +} + +// Fill ID of Queue object with UUID beforeCreate +func (q *Queue) BeforeCreate(tx *gorm.DB) (err error) { + q.ID = uuid.New().String() + q.Status = StatusPending + q.CreatedAt = time.Now() + q.UpdatedAt = time.Now() + return +} + +func (q *Queue) BeforeUpdate(tx *gorm.DB) (err error) { + q.UpdatedAt = time.Now() + return +} + +func (q *Queue) UpdateStatus(status Status) { + q.Status = status + database.Connection().Model(q).Save(q) +} + +func (q *Queue) UpdateError(err string) { + q.Error = err + q.Status = StatusFailed + database.Connection().Model(q).Save(q) +} diff --git a/app/routes/index.go b/app/routes/index.go index 3203a9a1..a81b3a8e 100644 --- a/app/routes/index.go +++ b/app/routes/index.go @@ -33,7 +33,7 @@ func Install(app *fiber.App) { // extensionDb app.Post("/setExtensionDb", handlers.SetExtensionDb) - // logger: deprecate on liman v2 + // logger app.Post("/sendLog", handlers.ExtensionLogger) // background job @@ -44,4 +44,8 @@ func Install(app *fiber.App) { // metrics app.Get("/metrics", monitor.New()) + + // queue handler + queueHandler := handlers.NewQueueHandler() + app.Post("/queue", queueHandler.Create) } diff --git a/go.mod b/go.mod index 5e75d7b4..5349e3a2 100644 --- a/go.mod +++ b/go.mod @@ -4,15 +4,15 @@ go 1.19 require ( github.com/Nerzal/gocloak/v13 v13.8.0 - github.com/go-resty/resty/v2 v2.9.1 - github.com/gofiber/fiber/v2 v2.49.2 + github.com/go-resty/resty/v2 v2.10.0 + github.com/gofiber/fiber/v2 v2.50.0 github.com/gofiber/helmet/v2 v2.2.26 - github.com/google/uuid v1.3.1 + github.com/google/uuid v1.4.0 github.com/joho/godotenv v1.5.1 go.uber.org/zap v1.26.0 - gorm.io/driver/mysql v1.5.1 - gorm.io/driver/postgres v1.5.2 - gorm.io/gorm v1.25.4 + gorm.io/driver/mysql v1.5.2 + gorm.io/driver/postgres v1.5.4 + gorm.io/gorm v1.25.5 ) require ( @@ -33,7 +33,7 @@ require ( github.com/kr/fs v0.1.0 // indirect github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/philhofer/fwd v1.1.2 // indirect @@ -47,21 +47,22 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.16.0 // indirect + golang.org/x/net v0.17.0 // indirect ) require ( github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alessio/shellescape v1.4.2 - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.0.6 // indirect github.com/avast/retry-go v3.0.0+incompatible + github.com/dariubs/gorm-jsonb v0.1.5 github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/hirochachacha/go-smb2 v1.1.0 github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/masterzen/winrm v0.0.0-20230926183142-a7fbe840deba github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 diff --git a/go.sum b/go.sum index 1fcd5ef0..ed45c1ff 100644 --- a/go.sum +++ b/go.sum @@ -15,10 +15,14 @@ github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4u github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/dariubs/gorm-jsonb v0.1.5 h1:0sc6pBQ0V1i3MqIos3SiQjRxtzs3pTnAZaAtb+SFM20= +github.com/dariubs/gorm-jsonb v0.1.5/go.mod h1:e6GXwMviS3e9QxADNOWWZq0WBTdxpK2SoYOExMUfRoM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -28,6 +32,8 @@ github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPr github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM= github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4= +github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= +github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -35,6 +41,8 @@ github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68 github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= github.com/gofiber/fiber/v2 v2.49.2 h1:ONEN3/Vc+dUCxxDgZZwpqvhISgHqb+bu+isBiEyKEQs= github.com/gofiber/fiber/v2 v2.49.2/go.mod h1:gNsKnyrmfEWFpJxQAV0qvW6l70K1dZGno12oLtukcts= +github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw= +github.com/gofiber/fiber/v2 v2.50.0/go.mod h1:21eytvay9Is7S6z+OgPi7c7n4++tnClWmhpimVHMimw= github.com/gofiber/helmet/v2 v2.2.26 h1:KreQVUpCIGppPQ6Yt8qQMaIR4fVXMnvBdsda0dJSsO8= github.com/gofiber/helmet/v2 v2.2.26/go.mod h1:XE0DF4cgf0M5xIt7qyAK5zOi8jJblhxfSDv9DAmEEQo= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -48,6 +56,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= @@ -89,6 +99,8 @@ github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/d github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -108,6 +120,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= @@ -219,6 +233,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -254,6 +270,7 @@ golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -266,6 +283,7 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -288,9 +306,16 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= +gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= +gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/internal/file/file.go b/internal/file/file.go new file mode 100644 index 00000000..13342fd5 --- /dev/null +++ b/internal/file/file.go @@ -0,0 +1,49 @@ +package file + +import ( + "path/filepath" + + "github.com/gofiber/fiber/v2" + "github.com/limanmys/render-engine/app/models" + "github.com/limanmys/render-engine/internal/bridge" + "github.com/limanmys/render-engine/internal/liman" + "github.com/limanmys/render-engine/pkg/logger" +) + +func PutFileHandler(user_id, server_id, remote_path, local_path string) (string, error) { + server, err := liman.GetServer(&models.Server{ID: server_id}) + if err != nil { + return "", err + } + + session, err := bridge.GetSession( + user_id, + server.ID, + server.IPAddress, + ) + if err != nil { + return "", err + } + + established := session.CreateFileConnection( + user_id, + server.ID, + server.IPAddress, + ) + if !established { + return "", logger.FiberError(fiber.StatusServiceUnavailable, "cannot establish file connection") + } + + remotePath := "" + if server.Os == "linux" { + remotePath = "/tmp/" + filepath.Base(remote_path) + } else { + remotePath = session.WindowsPath + remote_path + } + + err = session.Put(local_path, remotePath) + if err != nil { + return "", err + } + return remotePath, nil +} diff --git a/internal/process_queue/install_package.go b/internal/process_queue/install_package.go new file mode 100644 index 00000000..99bd4aa8 --- /dev/null +++ b/internal/process_queue/install_package.go @@ -0,0 +1,97 @@ +package process_queue + +import ( + "os" + "path/filepath" + "strings" + + "github.com/limanmys/render-engine/app/models" + "github.com/limanmys/render-engine/internal/bridge" + "github.com/limanmys/render-engine/internal/file" + "github.com/limanmys/render-engine/internal/liman" + "gorm.io/gorm" +) + +type InstallPackage struct { + Queue *models.Queue + DB *gorm.DB + UserID string +} + +func (p InstallPackage) Process() error { + p.Queue.UpdateStatus(models.StatusProcessing) + + location, err := p.sendPackageToRemoteServer() + if err != nil { + p.Queue.UpdateError(err.Error()) + return err + } + + err = p.installPackage(location) + if err != nil { + p.Queue.UpdateError(err.Error()) + return err + } + + p.Queue.UpdateStatus(models.StatusDone) + + return nil +} + +func (p InstallPackage) sendPackageToRemoteServer() (string, error) { + path := p.Queue.Data["path"].(string) + fileName := filepath.Base(path) + + location, err := file.PutFileHandler( + p.UserID, + p.Queue.Data["server_id"].(string), + "/tmp/"+fileName, + path, + ) + + if err == nil { + os.Remove(path) + } + + return location, err +} + +func (p InstallPackage) installPackage(location string) error { + server, err := liman.GetServer(&models.Server{ID: p.Queue.Data["server_id"].(string)}) + if err != nil { + return err + } + + shell, err := bridge.GetSession( + p.UserID, + server.ID, + server.IPAddress, + ) + if err != nil { + return err + } + + osType, _ := shell.Run("cat /etc/os-release | grep ^ID_LIKE | cut -d '=' -f2 | xargs") + packageManager := "" + if strings.ToLower(osType) == "debian" { + packageManager = "apt" + } else { + packageManager = "yum" + } + + switch packageManager { + case "apt": + _, err := shell.Run("DEBIAN_FRONTEND=noninteractive sudo -p liman-pass-sudo apt install -fyq " + location) + if err != nil { + return err + } + case "yum": + _, err := shell.Run("sudo -p liman-pass-sudo /usr/bin/yum install -yq " + location) + if err != nil { + return err + } + } + shell.Run("rm -rf " + location) + + return nil +} diff --git a/internal/process_queue/process_queue.go b/internal/process_queue/process_queue.go new file mode 100644 index 00000000..360ab0e2 --- /dev/null +++ b/internal/process_queue/process_queue.go @@ -0,0 +1,5 @@ +package process_queue + +type ProcessQueue interface { + Process() error +}