mirror of https://github.com/portainer/portainer
fix(endpoints): add the ability to update TLS for an existing endpoint (#784)
parent
44e48423ed
commit
abc929824c
|
@ -7,11 +7,9 @@ import (
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/orcaman/concurrent-map"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DockerHandler represents an HTTP API handler for proxying requests to the Docker API.
|
// DockerHandler represents an HTTP API handler for proxying requests to the Docker API.
|
||||||
|
@ -19,8 +17,7 @@ type DockerHandler struct {
|
||||||
*mux.Router
|
*mux.Router
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
EndpointService portainer.EndpointService
|
EndpointService portainer.EndpointService
|
||||||
ProxyFactory ProxyFactory
|
ProxyService *ProxyService
|
||||||
proxies cmap.ConcurrentMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDockerHandler returns a new instance of DockerHandler.
|
// NewDockerHandler returns a new instance of DockerHandler.
|
||||||
|
@ -28,10 +25,6 @@ func NewDockerHandler(mw *middleWareService, resourceControlService portainer.Re
|
||||||
h := &DockerHandler{
|
h := &DockerHandler{
|
||||||
Router: mux.NewRouter(),
|
Router: mux.NewRouter(),
|
||||||
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||||
ProxyFactory: ProxyFactory{
|
|
||||||
ResourceControlService: resourceControlService,
|
|
||||||
},
|
|
||||||
proxies: cmap.New(),
|
|
||||||
}
|
}
|
||||||
h.PathPrefix("/{id}/").Handler(
|
h.PathPrefix("/{id}/").Handler(
|
||||||
mw.authenticated(http.HandlerFunc(h.proxyRequestsToDockerAPI)))
|
mw.authenticated(http.HandlerFunc(h.proxyRequestsToDockerAPI)))
|
||||||
|
@ -74,41 +67,14 @@ func (handler *DockerHandler) proxyRequestsToDockerAPI(w http.ResponseWriter, r
|
||||||
}
|
}
|
||||||
|
|
||||||
var proxy http.Handler
|
var proxy http.Handler
|
||||||
item, ok := handler.proxies.Get(string(endpointID))
|
proxy = handler.ProxyService.GetProxy(string(endpointID))
|
||||||
if !ok {
|
if proxy == nil {
|
||||||
proxy, err = handler.createAndRegisterEndpointProxy(endpoint)
|
proxy, err = handler.ProxyService.CreateAndRegisterProxy(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, err, http.StatusBadRequest, handler.Logger)
|
Error(w, err, http.StatusBadRequest, handler.Logger)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
proxy = item.(http.Handler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.StripPrefix("/"+id, proxy).ServeHTTP(w, r)
|
http.StripPrefix("/"+id, proxy).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *DockerHandler) createAndRegisterEndpointProxy(endpoint *portainer.Endpoint) (http.Handler, error) {
|
|
||||||
var proxy http.Handler
|
|
||||||
|
|
||||||
endpointURL, err := url.Parse(endpoint.URL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if endpointURL.Scheme == "tcp" {
|
|
||||||
if endpoint.TLS {
|
|
||||||
proxy, err = handler.ProxyFactory.newHTTPSProxy(endpointURL, endpoint)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
proxy = handler.ProxyFactory.newHTTPProxy(endpointURL)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Assume unix:// scheme
|
|
||||||
proxy = handler.ProxyFactory.newSocketProxy(endpointURL.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.proxies.Set(string(endpoint.ID), proxy)
|
|
||||||
return proxy, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ type EndpointHandler struct {
|
||||||
authorizeEndpointManagement bool
|
authorizeEndpointManagement bool
|
||||||
EndpointService portainer.EndpointService
|
EndpointService portainer.EndpointService
|
||||||
FileService portainer.FileService
|
FileService portainer.FileService
|
||||||
|
ProxyService *ProxyService
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -281,6 +282,12 @@ func (handler *EndpointHandler) handlePutEndpoint(w http.ResponseWriter, r *http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = handler.ProxyService.CreateAndRegisterProxy(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = handler.EndpointService.UpdateEndpoint(endpoint.ID, endpoint)
|
err = handler.EndpointService.UpdateEndpoint(endpoint.ID, endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||||
|
@ -320,6 +327,8 @@ func (handler *EndpointHandler) handleDeleteEndpoint(w http.ResponseWriter, r *h
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler.ProxyService.DeleteProxy(string(endpointID))
|
||||||
|
|
||||||
err = handler.EndpointService.DeleteEndpoint(portainer.EndpointID(endpointID))
|
err = handler.EndpointService.DeleteEndpoint(portainer.EndpointID(endpointID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/orcaman/concurrent-map"
|
||||||
|
"github.com/portainer/portainer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProxyService represents a service used to manage Docker proxies.
|
||||||
|
type ProxyService struct {
|
||||||
|
proxyFactory *ProxyFactory
|
||||||
|
proxies cmap.ConcurrentMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProxyService initializes a new ProxyService
|
||||||
|
func NewProxyService(resourceControlService portainer.ResourceControlService) *ProxyService {
|
||||||
|
return &ProxyService{
|
||||||
|
proxies: cmap.New(),
|
||||||
|
proxyFactory: &ProxyFactory{
|
||||||
|
ResourceControlService: resourceControlService,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAndRegisterProxy creates a new HTTP reverse proxy and adds it to the registered proxies.
|
||||||
|
// It can also be used to create a new HTTP reverse proxy and replace an already registered proxy.
|
||||||
|
func (service *ProxyService) CreateAndRegisterProxy(endpoint *portainer.Endpoint) (http.Handler, error) {
|
||||||
|
var proxy http.Handler
|
||||||
|
|
||||||
|
endpointURL, err := url.Parse(endpoint.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpointURL.Scheme == "tcp" {
|
||||||
|
if endpoint.TLS {
|
||||||
|
proxy, err = service.proxyFactory.newHTTPSProxy(endpointURL, endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
proxy = service.proxyFactory.newHTTPProxy(endpointURL)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Assume unix:// scheme
|
||||||
|
proxy = service.proxyFactory.newSocketProxy(endpointURL.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
service.proxies.Set(string(endpoint.ID), proxy)
|
||||||
|
return proxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProxy returns the proxy associated to a key
|
||||||
|
func (service *ProxyService) GetProxy(key string) http.Handler {
|
||||||
|
proxy, ok := service.proxies.Get(key)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return proxy.(http.Handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProxy deletes the proxy associated to a key
|
||||||
|
func (service *ProxyService) DeleteProxy(key string) {
|
||||||
|
service.proxies.Remove(key)
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ func (server *Server) Start() error {
|
||||||
jwtService: server.JWTService,
|
jwtService: server.JWTService,
|
||||||
authDisabled: server.AuthDisabled,
|
authDisabled: server.AuthDisabled,
|
||||||
}
|
}
|
||||||
|
proxyService := NewProxyService(server.ResourceControlService)
|
||||||
|
|
||||||
var authHandler = NewAuthHandler(middleWareService)
|
var authHandler = NewAuthHandler(middleWareService)
|
||||||
authHandler.UserService = server.UserService
|
authHandler.UserService = server.UserService
|
||||||
|
@ -45,12 +46,14 @@ func (server *Server) Start() error {
|
||||||
templatesHandler.containerTemplatesURL = server.TemplatesURL
|
templatesHandler.containerTemplatesURL = server.TemplatesURL
|
||||||
var dockerHandler = NewDockerHandler(middleWareService, server.ResourceControlService)
|
var dockerHandler = NewDockerHandler(middleWareService, server.ResourceControlService)
|
||||||
dockerHandler.EndpointService = server.EndpointService
|
dockerHandler.EndpointService = server.EndpointService
|
||||||
|
dockerHandler.ProxyService = proxyService
|
||||||
var websocketHandler = NewWebSocketHandler()
|
var websocketHandler = NewWebSocketHandler()
|
||||||
websocketHandler.EndpointService = server.EndpointService
|
websocketHandler.EndpointService = server.EndpointService
|
||||||
var endpointHandler = NewEndpointHandler(middleWareService)
|
var endpointHandler = NewEndpointHandler(middleWareService)
|
||||||
endpointHandler.authorizeEndpointManagement = server.EndpointManagement
|
endpointHandler.authorizeEndpointManagement = server.EndpointManagement
|
||||||
endpointHandler.EndpointService = server.EndpointService
|
endpointHandler.EndpointService = server.EndpointService
|
||||||
endpointHandler.FileService = server.FileService
|
endpointHandler.FileService = server.FileService
|
||||||
|
endpointHandler.ProxyService = proxyService
|
||||||
var uploadHandler = NewUploadHandler(middleWareService)
|
var uploadHandler = NewUploadHandler(middleWareService)
|
||||||
uploadHandler.FileService = server.FileService
|
uploadHandler.FileService = server.FileService
|
||||||
var fileHandler = newFileHandler(server.AssetsPath)
|
var fileHandler = newFileHandler(server.AssetsPath)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package portainer
|
package portainer
|
||||||
|
|
||||||
import (
|
import "io"
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Pair defines a key/value string pair
|
// Pair defines a key/value string pair
|
||||||
|
|
|
@ -10,6 +10,7 @@ function ($scope, $state, $stateParams, $filter, EndpointService, Messages) {
|
||||||
error: '',
|
error: '',
|
||||||
uploadInProgress: false
|
uploadInProgress: false
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
TLSCACert: null,
|
TLSCACert: null,
|
||||||
TLSCert: null,
|
TLSCert: null,
|
||||||
|
|
|
@ -24,13 +24,14 @@ angular.module('portainer.services')
|
||||||
if (endpointParams.type && endpointParams.URL) {
|
if (endpointParams.type && endpointParams.URL) {
|
||||||
query.URL = endpointParams.type === 'local' ? ("unix://" + endpointParams.URL) : ("tcp://" + endpointParams.URL);
|
query.URL = endpointParams.type === 'local' ? ("unix://" + endpointParams.URL) : ("tcp://" + endpointParams.URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
Endpoints.update({id: id}, query).$promise
|
FileUploadService.uploadTLSFilesForEndpoint(id, endpointParams.TLSCACert, endpointParams.TLSCert, endpointParams.TLSKey)
|
||||||
.then(function success() {
|
.then(function success() {
|
||||||
return FileUploadService.uploadTLSFilesForEndpoint(id, endpointParams.TLSCAFile, endpointParams.TLSCertFile, endpointParams.TLSKeyFile);
|
deferred.notify({upload: false});
|
||||||
|
return Endpoints.update({id: id}, query).$promise;
|
||||||
})
|
})
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
deferred.notify({upload: false});
|
|
||||||
deferred.resolve(data);
|
deferred.resolve(data);
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
|
|
Loading…
Reference in New Issue