mirror of https://github.com/portainer/portainer
feat(database): initial commit
parent
cc487ae68a
commit
3e0ec6a379
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/portainer/portainer/api/cli"
|
"github.com/portainer/portainer/api/cli"
|
||||||
"github.com/portainer/portainer/api/cron"
|
"github.com/portainer/portainer/api/cron"
|
||||||
"github.com/portainer/portainer/api/crypto"
|
"github.com/portainer/portainer/api/crypto"
|
||||||
|
"github.com/portainer/portainer/api/database"
|
||||||
"github.com/portainer/portainer/api/docker"
|
"github.com/portainer/portainer/api/docker"
|
||||||
"github.com/portainer/portainer/api/exec"
|
"github.com/portainer/portainer/api/exec"
|
||||||
"github.com/portainer/portainer/api/filesystem"
|
"github.com/portainer/portainer/api/filesystem"
|
||||||
|
@ -100,6 +101,10 @@ func initLDAPService() portainer.LDAPService {
|
||||||
return &ldap.Service{}
|
return &ldap.Service{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initDatabaseService() portainer.DatabaseService {
|
||||||
|
return &database.Service{}
|
||||||
|
}
|
||||||
|
|
||||||
func initGitService() portainer.GitService {
|
func initGitService() portainer.GitService {
|
||||||
return &git.Service{}
|
return &git.Service{}
|
||||||
}
|
}
|
||||||
|
@ -526,6 +531,8 @@ func main() {
|
||||||
|
|
||||||
gitService := initGitService()
|
gitService := initGitService()
|
||||||
|
|
||||||
|
databaseService := initDatabaseService()
|
||||||
|
|
||||||
cryptoService := initCryptoService()
|
cryptoService := initCryptoService()
|
||||||
|
|
||||||
digitalSignatureService := initDigitalSignatureService()
|
digitalSignatureService := initDigitalSignatureService()
|
||||||
|
@ -684,6 +691,7 @@ func main() {
|
||||||
ComposeStackManager: composeStackManager,
|
ComposeStackManager: composeStackManager,
|
||||||
ExtensionManager: extensionManager,
|
ExtensionManager: extensionManager,
|
||||||
CryptoService: cryptoService,
|
CryptoService: cryptoService,
|
||||||
|
DatabaseService: databaseService,
|
||||||
JWTService: jwtService,
|
JWTService: jwtService,
|
||||||
FileService: fileService,
|
FileService: fileService,
|
||||||
LDAPService: ldapService,
|
LDAPService: ldapService,
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/boltdb/bolt"
|
||||||
|
//"strconv"
|
||||||
|
//"net/http"
|
||||||
|
//"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
databaseFileName = "portainer.db"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service represents a service for managing Database.
|
||||||
|
type Service struct{}
|
||||||
|
|
||||||
|
// DatabaseExport makes the BoltDB into read only mode, takes a backup and then put it back to writable mode.
|
||||||
|
func (service *Service) DatabaseExport(storePath string) (int64, error) {
|
||||||
|
//var databaseExport int64
|
||||||
|
//var w http.ResponseWriter
|
||||||
|
// var r io.Reader
|
||||||
|
dataStorePath := storePath + "/" + databaseFileName
|
||||||
|
|
||||||
|
_, err := bolt.Open(dataStorePath, 0666, &bolt.Options{ReadOnly: true})
|
||||||
|
|
||||||
|
/*
|
||||||
|
db, err := bolt.Open(dataStorePath, 0666, &bolt.Options{ReadOnly: true})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.View(func(tx *bolt.Tx) error {
|
||||||
|
w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
w.Header().Set("Content-Disposition", `attachment; filename="portainer.db"`)
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
|
||||||
|
databaseExport, err := tx.WriteTo(w)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return 0, err
|
||||||
|
}
|
|
@ -84,6 +84,11 @@ func (service *Service) GetBinaryFolder() string {
|
||||||
return path.Join(service.fileStorePath, BinaryStorePath)
|
return path.Join(service.fileStorePath, BinaryStorePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootFolder returns the full path to the root store on the filesystem
|
||||||
|
func (service *Service) GetRootFolder() string {
|
||||||
|
return service.fileStorePath
|
||||||
|
}
|
||||||
|
|
||||||
// ExtractExtensionArchive extracts the content of an extension archive
|
// ExtractExtensionArchive extracts the content of an extension archive
|
||||||
// specified as raw data into the binary store on the filesystem
|
// specified as raw data into the binary store on the filesystem
|
||||||
func (service *Service) ExtractExtensionArchive(data []byte) error {
|
func (service *Service) ExtractExtensionArchive(data []byte) error {
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
//"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (handler *Handler) databaseExport(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
|
storePath := handler.FileService.GetRootFolder()
|
||||||
|
databaseExport, err := handler.DatabaseService.DatabaseExport(storePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusInternalServerError, "Error exporting database", err}
|
||||||
|
}
|
||||||
|
|
||||||
|
database := &portainer.Database{
|
||||||
|
DatabaseExport: databaseExport,
|
||||||
|
}
|
||||||
|
|
||||||
|
//w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
//w.Header().Set("Content-Disposition", `attachment; filename="my.db"`)
|
||||||
|
//w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
|
||||||
|
|
||||||
|
return response.JSON(w, database)
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/portainer/portainer/api/http/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler is the HTTP handler used to handle webhook operations.
|
||||||
|
type Handler struct {
|
||||||
|
*mux.Router
|
||||||
|
DatabaseService portainer.DatabaseService
|
||||||
|
FileService portainer.FileService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHandler creates a handler to manage settings operations.
|
||||||
|
func NewHandler(bouncer *security.RequestBouncer) *Handler {
|
||||||
|
h := &Handler{
|
||||||
|
Router: mux.NewRouter(),
|
||||||
|
}
|
||||||
|
h.Handle("/database",
|
||||||
|
//bouncer.RestrictedAccess(httperror.LoggerHandler(h.databaseExport))).Methods(http.MethodGet)
|
||||||
|
bouncer.PublicAccess(httperror.LoggerHandler(h.databaseExport))).Methods(http.MethodGet)
|
||||||
|
return h
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/portainer/portainer/api/http/handler/roles"
|
"github.com/portainer/portainer/api/http/handler/roles"
|
||||||
|
|
||||||
"github.com/portainer/portainer/api/http/handler/auth"
|
"github.com/portainer/portainer/api/http/handler/auth"
|
||||||
|
"github.com/portainer/portainer/api/http/handler/database"
|
||||||
"github.com/portainer/portainer/api/http/handler/dockerhub"
|
"github.com/portainer/portainer/api/http/handler/dockerhub"
|
||||||
"github.com/portainer/portainer/api/http/handler/endpointgroups"
|
"github.com/portainer/portainer/api/http/handler/endpointgroups"
|
||||||
"github.com/portainer/portainer/api/http/handler/endpointproxy"
|
"github.com/portainer/portainer/api/http/handler/endpointproxy"
|
||||||
|
@ -34,6 +35,7 @@ import (
|
||||||
// Handler is a collection of all the service handlers.
|
// Handler is a collection of all the service handlers.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
AuthHandler *auth.Handler
|
AuthHandler *auth.Handler
|
||||||
|
DatabaseHandler *database.Handler
|
||||||
DockerHubHandler *dockerhub.Handler
|
DockerHubHandler *dockerhub.Handler
|
||||||
EndpointGroupHandler *endpointgroups.Handler
|
EndpointGroupHandler *endpointgroups.Handler
|
||||||
EndpointHandler *endpoints.Handler
|
EndpointHandler *endpoints.Handler
|
||||||
|
@ -63,6 +65,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/auth"):
|
case strings.HasPrefix(r.URL.Path, "/api/auth"):
|
||||||
http.StripPrefix("/api", h.AuthHandler).ServeHTTP(w, r)
|
http.StripPrefix("/api", h.AuthHandler).ServeHTTP(w, r)
|
||||||
|
case strings.HasPrefix(r.URL.Path, "/api/database"):
|
||||||
|
http.StripPrefix("/api", h.DatabaseHandler).ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/dockerhub"):
|
case strings.HasPrefix(r.URL.Path, "/api/dockerhub"):
|
||||||
http.StripPrefix("/api", h.DockerHubHandler).ServeHTTP(w, r)
|
http.StripPrefix("/api", h.DockerHubHandler).ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/endpoint_groups"):
|
case strings.HasPrefix(r.URL.Path, "/api/endpoint_groups"):
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/portainer/portainer/api/docker"
|
"github.com/portainer/portainer/api/docker"
|
||||||
"github.com/portainer/portainer/api/http/handler"
|
"github.com/portainer/portainer/api/http/handler"
|
||||||
"github.com/portainer/portainer/api/http/handler/auth"
|
"github.com/portainer/portainer/api/http/handler/auth"
|
||||||
|
"github.com/portainer/portainer/api/http/handler/database"
|
||||||
"github.com/portainer/portainer/api/http/handler/dockerhub"
|
"github.com/portainer/portainer/api/http/handler/dockerhub"
|
||||||
"github.com/portainer/portainer/api/http/handler/endpointgroups"
|
"github.com/portainer/portainer/api/http/handler/endpointgroups"
|
||||||
"github.com/portainer/portainer/api/http/handler/endpointproxy"
|
"github.com/portainer/portainer/api/http/handler/endpointproxy"
|
||||||
|
@ -51,6 +52,7 @@ type Server struct {
|
||||||
JobScheduler portainer.JobScheduler
|
JobScheduler portainer.JobScheduler
|
||||||
Snapshotter portainer.Snapshotter
|
Snapshotter portainer.Snapshotter
|
||||||
RoleService portainer.RoleService
|
RoleService portainer.RoleService
|
||||||
|
DatabaseService portainer.DatabaseService
|
||||||
DockerHubService portainer.DockerHubService
|
DockerHubService portainer.DockerHubService
|
||||||
EndpointService portainer.EndpointService
|
EndpointService portainer.EndpointService
|
||||||
EndpointGroupService portainer.EndpointGroupService
|
EndpointGroupService portainer.EndpointGroupService
|
||||||
|
@ -122,6 +124,10 @@ func (server *Server) Start() error {
|
||||||
var roleHandler = roles.NewHandler(requestBouncer)
|
var roleHandler = roles.NewHandler(requestBouncer)
|
||||||
roleHandler.RoleService = server.RoleService
|
roleHandler.RoleService = server.RoleService
|
||||||
|
|
||||||
|
var databaseHandler = database.NewHandler(requestBouncer)
|
||||||
|
databaseHandler.DatabaseService = server.DatabaseService
|
||||||
|
databaseHandler.FileService = server.FileService
|
||||||
|
|
||||||
var dockerHubHandler = dockerhub.NewHandler(requestBouncer)
|
var dockerHubHandler = dockerhub.NewHandler(requestBouncer)
|
||||||
dockerHubHandler.DockerHubService = server.DockerHubService
|
dockerHubHandler.DockerHubService = server.DockerHubService
|
||||||
|
|
||||||
|
@ -225,6 +231,7 @@ func (server *Server) Start() error {
|
||||||
server.Handler = &handler.Handler{
|
server.Handler = &handler.Handler{
|
||||||
RoleHandler: roleHandler,
|
RoleHandler: roleHandler,
|
||||||
AuthHandler: authHandler,
|
AuthHandler: authHandler,
|
||||||
|
DatabaseHandler: databaseHandler,
|
||||||
DockerHubHandler: dockerHubHandler,
|
DockerHubHandler: dockerHubHandler,
|
||||||
EndpointGroupHandler: endpointGroupHandler,
|
EndpointGroupHandler: endpointGroupHandler,
|
||||||
EndpointHandler: endpointHandler,
|
EndpointHandler: endpointHandler,
|
||||||
|
|
|
@ -224,6 +224,11 @@ type (
|
||||||
Password string `json:"Password,omitempty"`
|
Password string `json:"Password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Database represents all the required information to connect and use the database features
|
||||||
|
Database struct {
|
||||||
|
DatabaseExport int64 `json:"DatabaseExport"`
|
||||||
|
}
|
||||||
|
|
||||||
// EndpointID represents an endpoint identifier
|
// EndpointID represents an endpoint identifier
|
||||||
EndpointID int
|
EndpointID int
|
||||||
|
|
||||||
|
@ -575,6 +580,11 @@ type (
|
||||||
Valid bool `json:"Valid,omitempty"`
|
Valid bool `json:"Valid,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Server defines the interface to serve the API
|
||||||
|
DatabaseService interface {
|
||||||
|
DatabaseExport(storePath string) (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
// CLIService represents a service for managing CLI
|
// CLIService represents a service for managing CLI
|
||||||
CLIService interface {
|
CLIService interface {
|
||||||
ParseFlags(version string) (*CLIFlags, error)
|
ParseFlags(version string) (*CLIFlags, error)
|
||||||
|
@ -789,6 +799,7 @@ type (
|
||||||
GetScheduleFolder(identifier string) string
|
GetScheduleFolder(identifier string) string
|
||||||
ExtractExtensionArchive(data []byte) error
|
ExtractExtensionArchive(data []byte) error
|
||||||
GetBinaryFolder() string
|
GetBinaryFolder() string
|
||||||
|
GetRootFolder() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitService represents a service for managing Git
|
// GitService represents a service for managing Git
|
||||||
|
|
Loading…
Reference in New Issue