mirror of https://github.com/portainer/portainer
Introduce deploymentkeys
parent
6591498ab9
commit
ba9838296e
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/bolt/deploymentkey"
|
||||
"github.com/portainer/portainer/api/bolt/dockerhub"
|
||||
"github.com/portainer/portainer/api/bolt/endpoint"
|
||||
"github.com/portainer/portainer/api/bolt/endpointgroup"
|
||||
|
@ -39,6 +40,7 @@ type Store struct {
|
|||
checkForDataMigration bool
|
||||
fileService portainer.FileService
|
||||
RoleService *role.Service
|
||||
DeploymentKeyService *deploymentkey.Service
|
||||
DockerHubService *dockerhub.Service
|
||||
EndpointGroupService *endpointgroup.Service
|
||||
EndpointService *endpoint.Service
|
||||
|
@ -148,6 +150,12 @@ func (store *Store) initServices() error {
|
|||
}
|
||||
store.RoleService = authorizationsetService
|
||||
|
||||
deploymentkeyService, err := deploymentkey.NewService(store.db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
store.DeploymentKeyService = deploymentkeyService
|
||||
|
||||
dockerhubService, err := dockerhub.NewService(store.db)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package deploymentkey
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/bolt/internal"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
const (
|
||||
// BucketName represents the name of the bucket where this service stores data.
|
||||
BucketName = "deploymentkey"
|
||||
)
|
||||
|
||||
// Service represents a service for managing deploymentkey data.
|
||||
type Service struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
// NewService creates a new instance of a service.
|
||||
func NewService(db *bolt.DB) (*Service, error) {
|
||||
err := internal.CreateBucket(db, BucketName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Service{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeploymentKeys return all the deployment keys that are created.
|
||||
func (service *Service) DeploymentKeys() ([]portainer.DeploymentKey, error) {
|
||||
var deploymentkeys = make([]portainer.DeploymentKey, 0)
|
||||
|
||||
err := service.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(BucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var deploymentkey portainer.DeploymentKey
|
||||
err := internal.UnmarshalObject(v, &deploymentkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
deploymentkeys = append(deploymentkeys, deploymentkey)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return deploymentkeys, err
|
||||
}
|
||||
|
||||
// DeploymentKey returns the deployment key by deployment key ID.
|
||||
func (service *Service) DeploymentKey(ID portainer.DeploymentKeyID) (*portainer.DeploymentKey, error) {
|
||||
var deploymentkey portainer.DeploymentKey
|
||||
identifier := internal.Itob(int(ID))
|
||||
|
||||
err := internal.GetObject(service.db, BucketName, identifier, &deploymentkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &deploymentkey, nil
|
||||
}
|
||||
|
||||
// DeploymentKeyByName returns a deploymentkey by name.
|
||||
func (service *Service) DeploymentKeyByName(name string) (*portainer.DeploymentKey, error) {
|
||||
var deploymentkey *portainer.DeploymentKey
|
||||
|
||||
err := service.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(BucketName))
|
||||
|
||||
cursor := bucket.Cursor()
|
||||
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||
var t portainer.DeploymentKey
|
||||
err := internal.UnmarshalObject(v, &t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.Name == name {
|
||||
deploymentkey = &t
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if deploymentkey == nil {
|
||||
return portainer.ErrObjectNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return deploymentkey, err
|
||||
}
|
||||
|
||||
// DeleteDeploymentKey deletes a deployment key.
|
||||
func (service *Service) DeleteDeploymentKey(ID portainer.DeploymentKeyID) error {
|
||||
identifier := internal.Itob(int(ID))
|
||||
return internal.DeleteObject(service.db, BucketName, identifier)
|
||||
}
|
||||
|
||||
// CreateDeploymentKey creates a deployment key.
|
||||
func (service *Service) CreateDeploymentKey(deploymentkey *portainer.DeploymentKey) error {
|
||||
return service.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(BucketName))
|
||||
|
||||
id, _ := bucket.NextSequence()
|
||||
deploymentkey.ID = portainer.DeploymentKeyID(id)
|
||||
|
||||
data, err := internal.MarshalObject(deploymentkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bucket.Put(internal.Itob(int(deploymentkey.ID)), data)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package deploymentkeys
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
"github.com/portainer/libhttp/response"
|
||||
"github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
type deploymentKeyCreatePayload struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (payload *deploymentKeyCreatePayload) Validate(r *http.Request) error {
|
||||
if govalidator.IsNull(payload.Name) {
|
||||
return portainer.Error("Invalid deploymentkey name")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (handler *Handler) deploymentkeyCreate(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||
var payload deploymentKeyCreatePayload
|
||||
err := request.DecodeAndValidateJSONPayload(r, &payload)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err}
|
||||
}
|
||||
|
||||
deploymentkey, err := handler.DeploymentKeyService.DeploymentKeyByName(payload.Name)
|
||||
if err == portainer.ErrObjectNotFound {
|
||||
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a deployment key with the specified identifier inside the database", err}
|
||||
} else if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a deployment key with the specified identifier inside the database", err}
|
||||
}
|
||||
|
||||
// Add a function to call and create public key and private key
|
||||
|
||||
deploymentkey = &portainer.DeploymentKey{
|
||||
Name: payload.Name,
|
||||
PublicKey: "SHA256:hellotherepublic",
|
||||
PrivateKey: "SHA256:hellothereprivate",
|
||||
}
|
||||
|
||||
err = handler.DeploymentKeyService.CreateDeploymentKey(deploymentkey)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist the deployment key inside the database", err}
|
||||
}
|
||||
|
||||
return response.JSON(w, deploymentkey)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package deploymentkeys
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
"github.com/portainer/libhttp/response"
|
||||
"github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
// DELETE request on /api/webhook/:serviceID
|
||||
func (handler *Handler) deploymentkeyDelete(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||
id, err := request.RetrieveNumericRouteVariableValue(r, "id")
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid deployment key id", err}
|
||||
}
|
||||
|
||||
err = handler.DeploymentKeyService.DeleteDeploymentKey(portainer.DeploymentKeyID(id))
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to remove the deployment key from the database", err}
|
||||
}
|
||||
|
||||
return response.Empty(w)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package deploymentkeys
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
"github.com/portainer/libhttp/response"
|
||||
"github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
// GET request on /api/deployment_keys/:id
|
||||
func (handler *Handler) deploymentkeyInspect(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||
deploymentkeyID, err := request.RetrieveNumericRouteVariableValue(r, "id")
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid deploymentkey identifier route variable", err}
|
||||
}
|
||||
|
||||
deploymentkey, err := handler.DeploymentKeyService.DeploymentKey(portainer.DeploymentKeyID(deploymentkeyID))
|
||||
if err == portainer.ErrObjectNotFound {
|
||||
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a deployment key with the specified identifier inside the database", err}
|
||||
} else if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a deployment key with the specified identifier inside the database", err}
|
||||
}
|
||||
|
||||
return response.JSON(w, deploymentkey)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package deploymentkeys
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/response"
|
||||
)
|
||||
|
||||
// GET request on /api/deployment_keys
|
||||
func (handler *Handler) deploymentkeyList(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||
deploymentkeys, err := handler.DeploymentKeyService.DeploymentKeys()
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve deploymentkeys from the database", err}
|
||||
}
|
||||
|
||||
return response.JSON(w, deploymentkeys)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package deploymentkeys
|
||||
|
||||
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
|
||||
DeploymentKeyService portainer.DeploymentKeyService
|
||||
}
|
||||
|
||||
// NewHandler creates a handler to manage settings operations.
|
||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
|
||||
h := &Handler{
|
||||
Router: mux.NewRouter(),
|
||||
}
|
||||
h.Handle("/deployment_keys",
|
||||
// bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.deploymentkeyCreate))).Methods(http.MethodPost)
|
||||
bouncer.PublicAccess(httperror.LoggerHandler(h.deploymentkeyCreate))).Methods(http.MethodPost)
|
||||
h.Handle("/deployment_keys",
|
||||
// bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.deploymentkeyList))).Methods(http.MethodGet)
|
||||
bouncer.PublicAccess(httperror.LoggerHandler(h.deploymentkeyList))).Methods(http.MethodGet)
|
||||
h.Handle("/deployment_keys/{id}",
|
||||
// bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.deploymentkeyList))).Methods(http.MethodGet)
|
||||
bouncer.PublicAccess(httperror.LoggerHandler(h.deploymentkeyInspect))).Methods(http.MethodGet)
|
||||
h.Handle("/deployment_keys/{id}",
|
||||
// bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.deploymentkeyDelete))).Methods(http.MethodDelete)
|
||||
bouncer.PublicAccess(httperror.LoggerHandler(h.deploymentkeyDelete))).Methods(http.MethodDelete)
|
||||
return h
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/portainer/portainer/api/http/handler/roles"
|
||||
|
||||
"github.com/portainer/portainer/api/http/handler/auth"
|
||||
"github.com/portainer/portainer/api/http/handler/deploymentkeys"
|
||||
"github.com/portainer/portainer/api/http/handler/dockerhub"
|
||||
"github.com/portainer/portainer/api/http/handler/endpointgroups"
|
||||
"github.com/portainer/portainer/api/http/handler/endpointproxy"
|
||||
|
@ -34,6 +35,7 @@ import (
|
|||
// Handler is a collection of all the service handlers.
|
||||
type Handler struct {
|
||||
AuthHandler *auth.Handler
|
||||
DeploymentKeyHandler *deploymentkeys.Handler
|
||||
DockerHubHandler *dockerhub.Handler
|
||||
EndpointGroupHandler *endpointgroups.Handler
|
||||
EndpointHandler *endpoints.Handler
|
||||
|
@ -63,6 +65,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
switch {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/auth"):
|
||||
http.StripPrefix("/api", h.AuthHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/deployment_keys"):
|
||||
http.StripPrefix("/api", h.DeploymentKeyHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/dockerhub"):
|
||||
http.StripPrefix("/api", h.DockerHubHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/endpoint_groups"):
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/Microsoft/go-winio"
|
||||
"net"
|
||||
"net/http"
|
||||
"github.com/Microsoft/go-winio"
|
||||
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
|
|
|
@ -216,6 +216,18 @@ type (
|
|||
TLSConfig TLSConfiguration `json:"TLSConfig"`
|
||||
}
|
||||
|
||||
// DeploymentKeyID represents
|
||||
DeploymentKeyID int
|
||||
|
||||
// DeploymentKey represents the SSH key details that will be used to
|
||||
// connect to GitHub for deployments based on private key clone
|
||||
DeploymentKey struct {
|
||||
ID DeploymentKeyID `json:"Id`
|
||||
Name string `json:"Name"`
|
||||
PublicKey string `json:"PublicKey"`
|
||||
PrivateKey string `json:"PrivateKey"`
|
||||
}
|
||||
|
||||
// DockerHub represents all the required information to connect and use the
|
||||
// Docker Hub
|
||||
DockerHub struct {
|
||||
|
@ -674,6 +686,15 @@ type (
|
|||
GetNextIdentifier() int
|
||||
}
|
||||
|
||||
// DeploymentKeyService represents a service for managing the DeploymentKey object
|
||||
DeploymentKeyService interface {
|
||||
DeploymentKey(ID DeploymentKeyID) (*DeploymentKey, error)
|
||||
DeploymentKeyByName(name string) (*DeploymentKey, error)
|
||||
DeploymentKeys() ([]DeploymentKey, error)
|
||||
DeleteDeploymentKey(ID DeploymentKeyID) error
|
||||
CreateDeploymentKey(deploymentkey *DeploymentKey) error
|
||||
}
|
||||
|
||||
// DockerHubService represents a service for managing the DockerHub object
|
||||
DockerHubService interface {
|
||||
DockerHub() (*DockerHub, error)
|
||||
|
@ -876,7 +897,7 @@ const (
|
|||
PortainerAgentSignatureMessage = "Portainer-App"
|
||||
// SupportedDockerAPIVersion is the minimum Docker API version supported by Portainer
|
||||
SupportedDockerAPIVersion = "1.24"
|
||||
// ExtensionServer represents the server used by Portainer to communicate with extensions
|
||||
// ExtensionServer represents the server used by Portainer to communicate with extensions
|
||||
ExtensionServer = "localhost"
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue