2018-06-11 13:13:19 +00:00
package endpoints
import (
2019-07-25 22:38:07 +00:00
"errors"
2020-08-04 00:44:17 +00:00
"fmt"
2019-07-25 22:38:07 +00:00
"net"
2018-06-11 13:13:19 +00:00
"net/http"
2019-07-25 22:38:07 +00:00
"net/url"
2018-07-20 09:02:06 +00:00
"runtime"
2018-06-11 13:13:19 +00:00
"strconv"
2019-09-20 04:14:19 +00:00
"strings"
2020-08-04 00:44:17 +00:00
"time"
2018-06-11 13:13:19 +00:00
2018-09-10 10:01:38 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
2021-02-09 08:09:06 +00:00
portainer "github.com/portainer/portainer/api"
2020-08-04 00:44:17 +00:00
"github.com/portainer/portainer/api/crypto"
2019-03-21 01:20:14 +00:00
"github.com/portainer/portainer/api/http/client"
2020-06-16 07:58:16 +00:00
"github.com/portainer/portainer/api/internal/edge"
2018-06-11 13:13:19 +00:00
)
type endpointCreatePayload struct {
2020-06-09 02:43:32 +00:00
Name string
URL string
2020-08-04 00:44:17 +00:00
EndpointCreationType endpointCreationEnum
2020-06-09 02:43:32 +00:00
PublicURL string
GroupID int
TLS bool
TLSSkipVerify bool
TLSSkipClientVerify bool
TLSCACertFile [ ] byte
TLSCertFile [ ] byte
TLSKeyFile [ ] byte
AzureApplicationID string
AzureTenantID string
AzureAuthenticationKey string
TagIDs [ ] portainer . TagID
EdgeCheckinInterval int
2018-06-11 13:13:19 +00:00
}
2020-08-04 00:44:17 +00:00
type endpointCreationEnum int
const (
_ endpointCreationEnum = iota
localDockerEnvironment
agentEnvironment
azureEnvironment
edgeAgentEnvironment
localKubernetesEnvironment
)
2018-06-11 13:13:19 +00:00
func ( payload * endpointCreatePayload ) Validate ( r * http . Request ) error {
name , err := request . RetrieveMultiPartFormValue ( r , "Name" , false )
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid endpoint name" )
2018-06-11 13:13:19 +00:00
}
payload . Name = name
2020-08-04 00:44:17 +00:00
endpointCreationType , err := request . RetrieveNumericMultiPartFormValue ( r , "EndpointCreationType" , false )
if err != nil || endpointCreationType == 0 {
return errors . New ( "Invalid endpoint type value. Value must be one of: 1 (Docker environment), 2 (Agent environment), 3 (Azure environment), 4 (Edge Agent environment) or 5 (Local Kubernetes environment)" )
2018-06-11 13:13:19 +00:00
}
2020-08-04 00:44:17 +00:00
payload . EndpointCreationType = endpointCreationEnum ( endpointCreationType )
2018-06-11 13:13:19 +00:00
groupID , _ := request . RetrieveNumericMultiPartFormValue ( r , "GroupID" , true )
if groupID == 0 {
groupID = 1
}
payload . GroupID = groupID
2020-03-29 09:54:14 +00:00
var tagIDs [ ] portainer . TagID
err = request . RetrieveMultiPartFormJSONValue ( r , "TagIds" , & tagIDs , true )
2018-06-15 07:18:25 +00:00
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid TagIds parameter" )
2018-06-15 07:18:25 +00:00
}
2020-03-29 09:54:14 +00:00
payload . TagIDs = tagIDs
if payload . TagIDs == nil {
payload . TagIDs = make ( [ ] portainer . TagID , 0 )
2018-07-26 08:13:18 +00:00
}
2018-06-15 07:18:25 +00:00
2018-06-11 13:13:19 +00:00
useTLS , _ := request . RetrieveBooleanMultiPartFormValue ( r , "TLS" , true )
payload . TLS = useTLS
if payload . TLS {
skipTLSServerVerification , _ := request . RetrieveBooleanMultiPartFormValue ( r , "TLSSkipVerify" , true )
payload . TLSSkipVerify = skipTLSServerVerification
skipTLSClientVerification , _ := request . RetrieveBooleanMultiPartFormValue ( r , "TLSSkipClientVerify" , true )
payload . TLSSkipClientVerify = skipTLSClientVerification
if ! payload . TLSSkipVerify {
2018-09-10 10:01:38 +00:00
caCert , _ , err := request . RetrieveMultiPartFormFile ( r , "TLSCACertFile" )
2018-06-11 13:13:19 +00:00
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid CA certificate file. Ensure that the file is uploaded correctly" )
2018-06-11 13:13:19 +00:00
}
payload . TLSCACertFile = caCert
}
if ! payload . TLSSkipClientVerify {
2018-09-10 10:01:38 +00:00
cert , _ , err := request . RetrieveMultiPartFormFile ( r , "TLSCertFile" )
2018-06-11 13:13:19 +00:00
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid certificate file. Ensure that the file is uploaded correctly" )
2018-06-11 13:13:19 +00:00
}
payload . TLSCertFile = cert
2018-09-10 10:01:38 +00:00
key , _ , err := request . RetrieveMultiPartFormFile ( r , "TLSKeyFile" )
2018-06-11 13:13:19 +00:00
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid key file. Ensure that the file is uploaded correctly" )
2018-06-11 13:13:19 +00:00
}
payload . TLSKeyFile = key
}
}
2020-08-04 00:44:17 +00:00
switch payload . EndpointCreationType {
case azureEnvironment :
2020-06-09 02:43:32 +00:00
azureApplicationID , err := request . RetrieveMultiPartFormValue ( r , "AzureApplicationID" , false )
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid Azure application ID" )
2020-06-09 02:43:32 +00:00
}
payload . AzureApplicationID = azureApplicationID
azureTenantID , err := request . RetrieveMultiPartFormValue ( r , "AzureTenantID" , false )
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid Azure tenant ID" )
2020-06-09 02:43:32 +00:00
}
payload . AzureTenantID = azureTenantID
2020-05-19 03:08:57 +00:00
2020-06-09 02:43:32 +00:00
azureAuthenticationKey , err := request . RetrieveMultiPartFormValue ( r , "AzureAuthenticationKey" , false )
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid Azure authentication key" )
2020-06-09 02:43:32 +00:00
}
payload . AzureAuthenticationKey = azureAuthenticationKey
default :
2020-07-05 23:21:03 +00:00
endpointURL , err := request . RetrieveMultiPartFormValue ( r , "URL" , true )
2020-06-09 02:43:32 +00:00
if err != nil {
2020-07-07 21:57:52 +00:00
return errors . New ( "Invalid endpoint URL" )
2020-06-09 02:43:32 +00:00
}
2020-07-05 23:21:03 +00:00
payload . URL = endpointURL
2020-06-09 02:43:32 +00:00
publicURL , _ := request . RetrieveMultiPartFormValue ( r , "PublicURL" , true )
payload . PublicURL = publicURL
}
2018-06-11 13:13:19 +00:00
2020-06-04 05:35:09 +00:00
checkinInterval , _ := request . RetrieveNumericMultiPartFormValue ( r , "CheckinInterval" , true )
payload . EdgeCheckinInterval = checkinInterval
2018-06-11 13:13:19 +00:00
return nil
}
2021-02-23 03:21:39 +00:00
// @id EndpointCreate
// @summary Create a new endpoint
// @description Create a new endpoint that will be used to manage an environment.
// @description **Access policy**: administrator
// @tags endpoints
// @security jwt
// @accept multipart/form-data
// @produce json
// @param Name formData string true "Name that will be used to identify this endpoint (example: my-endpoint)"
2021-06-14 02:45:57 +00:00
// @param EndpointCreationType formData integer true "Environment type. Value must be one of: 1 (Local Docker environment), 2 (Agent environment), 3 (Azure environment), 4 (Edge agent environment) or 5 (Local Kubernetes Environment" Enum(1,2,3,4,5)
2021-02-23 03:21:39 +00:00
// @param URL formData string false "URL or IP address of a Docker host (example: docker.mydomain.tld:2375). Defaults to local if not specified (Linux: /var/run/docker.sock, Windows: //./pipe/docker_engine)"
// @param PublicURL formData string false "URL or IP address where exposed containers will be reachable. Defaults to URL if not specified (example: docker.mydomain.tld:2375)"
// @param GroupID formData int false "Endpoint group identifier. If not specified will default to 1 (unassigned)."
// @param TLS formData bool false "Require TLS to connect against this endpoint"
// @param TLSSkipVerify formData bool false "Skip server verification when using TLS"
// @param TLSSkipClientVerify formData bool false "Skip client verification when using TLS"
// @param TLSCACertFile formData file false "TLS CA certificate file"
// @param TLSCertFile formData file false "TLS client certificate file"
// @param TLSKeyFile formData file false "TLS client key file"
// @param AzureApplicationID formData string false "Azure application ID. Required if endpoint type is set to 3"
// @param AzureTenantID formData string false "Azure tenant ID. Required if endpoint type is set to 3"
// @param AzureAuthenticationKey formData string false "Azure authentication key. Required if endpoint type is set to 3"
// @param TagIDs formData []int false "List of tag identifiers to which this endpoint is associated"
// @param EdgeCheckinInterval formData int false "The check in interval for edge agent (in seconds)"
// @success 200 {object} portainer.Endpoint "Success"
// @failure 400 "Invalid request"
// @failure 500 "Server error"
// @router /endpoints [post]
2018-06-11 13:13:19 +00:00
func ( handler * Handler ) endpointCreate ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
payload := & endpointCreatePayload { }
err := payload . Validate ( r )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid request payload" , err }
}
endpoint , endpointCreationError := handler . createEndpoint ( payload )
if endpointCreationError != nil {
return endpointCreationError
}
2020-05-20 05:23:15 +00:00
endpointGroup , err := handler . DataStore . EndpointGroup ( ) . EndpointGroup ( endpoint . GroupID )
2020-05-14 02:14:28 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to find an endpoint group inside the database" , err }
}
2020-05-20 05:23:15 +00:00
edgeGroups , err := handler . DataStore . EdgeGroup ( ) . EdgeGroups ( )
2020-05-14 02:14:28 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve edge groups from the database" , err }
}
2020-05-20 05:23:15 +00:00
edgeStacks , err := handler . DataStore . EdgeStack ( ) . EdgeStacks ( )
2020-05-14 02:14:28 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve edge stacks from the database" , err }
}
relationObject := & portainer . EndpointRelation {
EndpointID : endpoint . ID ,
EdgeStacks : map [ portainer . EdgeStackID ] bool { } ,
}
2020-07-05 23:21:03 +00:00
if endpoint . Type == portainer . EdgeAgentOnDockerEnvironment || endpoint . Type == portainer . EdgeAgentOnKubernetesEnvironment {
2020-06-16 07:58:16 +00:00
relatedEdgeStacks := edge . EndpointRelatedEdgeStacks ( endpoint , endpointGroup , edgeGroups , edgeStacks )
2020-05-14 02:14:28 +00:00
for _ , stackID := range relatedEdgeStacks {
relationObject . EdgeStacks [ stackID ] = true
}
}
2020-05-20 05:23:15 +00:00
err = handler . DataStore . EndpointRelation ( ) . CreateEndpointRelation ( relationObject )
2020-05-14 02:14:28 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist the relation object inside the database" , err }
}
2018-06-11 13:13:19 +00:00
return response . JSON ( w , endpoint )
}
func ( handler * Handler ) createEndpoint ( payload * endpointCreatePayload ) ( * portainer . Endpoint , * httperror . HandlerError ) {
2020-08-04 00:44:17 +00:00
switch payload . EndpointCreationType {
case azureEnvironment :
2020-06-09 02:43:32 +00:00
return handler . createAzureEndpoint ( payload )
2020-07-05 23:21:03 +00:00
2020-08-04 00:44:17 +00:00
case edgeAgentEnvironment :
return handler . createEdgeAgentEndpoint ( payload )
2020-07-05 23:21:03 +00:00
2020-08-04 00:44:17 +00:00
case localKubernetesEnvironment :
2020-07-05 23:21:03 +00:00
return handler . createKubernetesEndpoint ( payload )
2020-08-04 00:44:17 +00:00
}
endpointType := portainer . DockerEnvironment
if payload . EndpointCreationType == agentEnvironment {
agentPlatform , err := handler . pingAndCheckPlatform ( payload )
if err != nil {
return nil , & httperror . HandlerError { http . StatusInternalServerError , "Unable to get endpoint type" , err }
}
2020-07-05 23:21:03 +00:00
2020-08-04 00:44:17 +00:00
if agentPlatform == portainer . AgentPlatformDocker {
endpointType = portainer . AgentOnDockerEnvironment
} else if agentPlatform == portainer . AgentPlatformKubernetes {
endpointType = portainer . AgentOnKubernetesEnvironment
payload . URL = strings . TrimPrefix ( payload . URL , "tcp://" )
}
2018-06-11 13:13:19 +00:00
}
if payload . TLS {
2020-08-04 00:44:17 +00:00
return handler . createTLSSecuredEndpoint ( payload , endpointType )
2018-06-11 13:13:19 +00:00
}
return handler . createUnsecuredEndpoint ( payload )
}
2020-06-09 02:43:32 +00:00
func ( handler * Handler ) createAzureEndpoint ( payload * endpointCreatePayload ) ( * portainer . Endpoint , * httperror . HandlerError ) {
credentials := portainer . AzureCredentials {
ApplicationID : payload . AzureApplicationID ,
TenantID : payload . AzureTenantID ,
AuthenticationKey : payload . AzureAuthenticationKey ,
}
httpClient := client . NewHTTPClient ( )
_ , err := httpClient . ExecuteAzureAuthenticationRequest ( & credentials )
if err != nil {
return nil , & httperror . HandlerError { http . StatusInternalServerError , "Unable to authenticate against Azure" , err }
}
endpointID := handler . DataStore . Endpoint ( ) . GetNextIdentifier ( )
endpoint := & portainer . Endpoint {
ID : portainer . EndpointID ( endpointID ) ,
Name : payload . Name ,
URL : "https://management.azure.com" ,
Type : portainer . AzureEnvironment ,
GroupID : portainer . EndpointGroupID ( payload . GroupID ) ,
PublicURL : payload . PublicURL ,
UserAccessPolicies : portainer . UserAccessPolicies { } ,
TeamAccessPolicies : portainer . TeamAccessPolicies { } ,
Extensions : [ ] portainer . EndpointExtension { } ,
AzureCredentials : credentials ,
TagIDs : payload . TagIDs ,
Status : portainer . EndpointStatusUp ,
2020-07-05 23:21:03 +00:00
Snapshots : [ ] portainer . DockerSnapshot { } ,
Kubernetes : portainer . KubernetesDefault ( ) ,
2020-06-09 02:43:32 +00:00
}
err = handler . saveEndpointAndUpdateAuthorizations ( endpoint )
if err != nil {
return nil , & httperror . HandlerError { http . StatusInternalServerError , "An error occured while trying to create the endpoint" , err }
}
return endpoint , nil
}
2020-08-04 00:44:17 +00:00
func ( handler * Handler ) createEdgeAgentEndpoint ( payload * endpointCreatePayload ) ( * portainer . Endpoint , * httperror . HandlerError ) {
2020-05-20 05:23:15 +00:00
endpointID := handler . DataStore . Endpoint ( ) . GetNextIdentifier ( )
2019-07-25 22:38:07 +00:00
portainerURL , err := url . Parse ( payload . URL )
if err != nil {
return nil , & httperror . HandlerError { http . StatusBadRequest , "Invalid endpoint URL" , err }
}
portainerHost , _ , err := net . SplitHostPort ( portainerURL . Host )
if err != nil {
portainerHost = portainerURL . Host
}
if portainerHost == "localhost" {
return nil , & httperror . HandlerError { http . StatusBadRequest , "Invalid endpoint URL" , errors . New ( "cannot use localhost as endpoint URL" ) }
}
edgeKey := handler . ReverseTunnelService . GenerateEdgeKey ( payload . URL , portainerHost , endpointID )
endpoint := & portainer . Endpoint {
ID : portainer . EndpointID ( endpointID ) ,
Name : payload . Name ,
URL : portainerHost ,
2020-08-04 00:44:17 +00:00
Type : portainer . EdgeAgentOnDockerEnvironment ,
2019-07-25 22:38:07 +00:00
GroupID : portainer . EndpointGroupID ( payload . GroupID ) ,
TLSConfig : portainer . TLSConfiguration {
TLS : false ,
} ,
2021-07-14 09:15:21 +00:00
UserAccessPolicies : portainer . UserAccessPolicies { } ,
TeamAccessPolicies : portainer . TeamAccessPolicies { } ,
2020-06-04 05:35:09 +00:00
Extensions : [ ] portainer . EndpointExtension { } ,
TagIDs : payload . TagIDs ,
Status : portainer . EndpointStatusUp ,
2020-07-05 23:21:03 +00:00
Snapshots : [ ] portainer . DockerSnapshot { } ,
2020-06-04 05:35:09 +00:00
EdgeKey : edgeKey ,
EdgeCheckinInterval : payload . EdgeCheckinInterval ,
2020-07-05 23:21:03 +00:00
Kubernetes : portainer . KubernetesDefault ( ) ,
2019-07-25 22:38:07 +00:00
}
2019-10-07 02:42:01 +00:00
err = handler . saveEndpointAndUpdateAuthorizations ( endpoint )
2018-06-11 13:13:19 +00:00
if err != nil {
2019-10-07 02:42:01 +00:00
return nil , & httperror . HandlerError { http . StatusInternalServerError , "An error occured while trying to create the endpoint" , err }
2018-06-11 13:13:19 +00:00
}
return endpoint , nil
}
func ( handler * Handler ) createUnsecuredEndpoint ( payload * endpointCreatePayload ) ( * portainer . Endpoint , * httperror . HandlerError ) {
endpointType := portainer . DockerEnvironment
2018-07-20 09:02:06 +00:00
if payload . URL == "" {
payload . URL = "unix:///var/run/docker.sock"
if runtime . GOOS == "windows" {
payload . URL = "npipe:////./pipe/docker_engine"
}
2018-06-11 13:13:19 +00:00
}
2020-05-20 05:23:15 +00:00
endpointID := handler . DataStore . Endpoint ( ) . GetNextIdentifier ( )
2018-06-11 13:13:19 +00:00
endpoint := & portainer . Endpoint {
2018-07-24 12:47:19 +00:00
ID : portainer . EndpointID ( endpointID ) ,
2018-06-11 13:13:19 +00:00
Name : payload . Name ,
URL : payload . URL ,
Type : endpointType ,
GroupID : portainer . EndpointGroupID ( payload . GroupID ) ,
PublicURL : payload . PublicURL ,
TLSConfig : portainer . TLSConfiguration {
TLS : false ,
} ,
2019-05-24 06:04:58 +00:00
UserAccessPolicies : portainer . UserAccessPolicies { } ,
TeamAccessPolicies : portainer . TeamAccessPolicies { } ,
Extensions : [ ] portainer . EndpointExtension { } ,
2020-03-29 09:54:14 +00:00
TagIDs : payload . TagIDs ,
2019-05-24 06:04:58 +00:00
Status : portainer . EndpointStatusUp ,
2020-07-05 23:21:03 +00:00
Snapshots : [ ] portainer . DockerSnapshot { } ,
Kubernetes : portainer . KubernetesDefault ( ) ,
2018-06-11 13:13:19 +00:00
}
2018-07-23 07:51:33 +00:00
err := handler . snapshotAndPersistEndpoint ( endpoint )
2018-06-11 13:13:19 +00:00
if err != nil {
2018-07-23 07:51:33 +00:00
return nil , err
2018-06-11 13:13:19 +00:00
}
return endpoint , nil
}
2020-07-05 23:21:03 +00:00
func ( handler * Handler ) createKubernetesEndpoint ( payload * endpointCreatePayload ) ( * portainer . Endpoint , * httperror . HandlerError ) {
if payload . URL == "" {
payload . URL = "https://kubernetes.default.svc"
2018-06-11 13:13:19 +00:00
}
2020-07-05 23:21:03 +00:00
endpointID := handler . DataStore . Endpoint ( ) . GetNextIdentifier ( )
endpoint := & portainer . Endpoint {
ID : portainer . EndpointID ( endpointID ) ,
Name : payload . Name ,
URL : payload . URL ,
Type : portainer . KubernetesLocalEnvironment ,
GroupID : portainer . EndpointGroupID ( payload . GroupID ) ,
PublicURL : payload . PublicURL ,
TLSConfig : portainer . TLSConfiguration {
TLS : payload . TLS ,
TLSSkipVerify : payload . TLSSkipVerify ,
} ,
UserAccessPolicies : portainer . UserAccessPolicies { } ,
TeamAccessPolicies : portainer . TeamAccessPolicies { } ,
Extensions : [ ] portainer . EndpointExtension { } ,
TagIDs : payload . TagIDs ,
Status : portainer . EndpointStatusUp ,
Snapshots : [ ] portainer . DockerSnapshot { } ,
Kubernetes : portainer . KubernetesDefault ( ) ,
2018-06-11 13:13:19 +00:00
}
2020-07-05 23:21:03 +00:00
err := handler . snapshotAndPersistEndpoint ( endpoint )
if err != nil {
return nil , err
2018-06-11 13:13:19 +00:00
}
2020-07-05 23:21:03 +00:00
return endpoint , nil
}
func ( handler * Handler ) createTLSSecuredEndpoint ( payload * endpointCreatePayload , endpointType portainer . EndpointType ) ( * portainer . Endpoint , * httperror . HandlerError ) {
2020-05-20 05:23:15 +00:00
endpointID := handler . DataStore . Endpoint ( ) . GetNextIdentifier ( )
2018-06-11 13:13:19 +00:00
endpoint := & portainer . Endpoint {
2018-07-24 12:47:19 +00:00
ID : portainer . EndpointID ( endpointID ) ,
2018-06-11 13:13:19 +00:00
Name : payload . Name ,
URL : payload . URL ,
Type : endpointType ,
GroupID : portainer . EndpointGroupID ( payload . GroupID ) ,
PublicURL : payload . PublicURL ,
TLSConfig : portainer . TLSConfiguration {
TLS : payload . TLS ,
TLSSkipVerify : payload . TLSSkipVerify ,
} ,
2019-05-24 06:04:58 +00:00
UserAccessPolicies : portainer . UserAccessPolicies { } ,
TeamAccessPolicies : portainer . TeamAccessPolicies { } ,
Extensions : [ ] portainer . EndpointExtension { } ,
2020-03-29 09:54:14 +00:00
TagIDs : payload . TagIDs ,
2019-05-24 06:04:58 +00:00
Status : portainer . EndpointStatusUp ,
2020-07-05 23:21:03 +00:00
Snapshots : [ ] portainer . DockerSnapshot { } ,
Kubernetes : portainer . KubernetesDefault ( ) ,
2018-06-11 13:13:19 +00:00
}
2020-07-05 23:21:03 +00:00
err := handler . storeTLSFiles ( endpoint , payload )
2018-06-11 13:13:19 +00:00
if err != nil {
2020-07-05 23:21:03 +00:00
return nil , err
2018-06-11 13:13:19 +00:00
}
2020-07-05 23:21:03 +00:00
err = handler . snapshotAndPersistEndpoint ( endpoint )
if err != nil {
return nil , err
2018-06-11 13:13:19 +00:00
}
return endpoint , nil
}
2018-07-23 07:51:33 +00:00
func ( handler * Handler ) snapshotAndPersistEndpoint ( endpoint * portainer . Endpoint ) * httperror . HandlerError {
2020-07-05 23:21:03 +00:00
err := handler . SnapshotService . SnapshotEndpoint ( endpoint )
2018-07-23 07:51:33 +00:00
if err != nil {
2019-09-20 04:14:19 +00:00
if strings . Contains ( err . Error ( ) , "Invalid request signature" ) {
err = errors . New ( "agent already paired with another Portainer instance" )
}
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to initiate communications with endpoint" , err }
2018-07-23 07:51:33 +00:00
}
2019-10-07 02:42:01 +00:00
err = handler . saveEndpointAndUpdateAuthorizations ( endpoint )
2018-07-23 07:51:33 +00:00
if err != nil {
2019-10-07 02:42:01 +00:00
return & httperror . HandlerError { http . StatusInternalServerError , "An error occured while trying to create the endpoint" , err }
}
return nil
}
func ( handler * Handler ) saveEndpointAndUpdateAuthorizations ( endpoint * portainer . Endpoint ) error {
2021-02-09 08:09:06 +00:00
endpoint . SecuritySettings = portainer . EndpointSecuritySettings {
AllowVolumeBrowserForRegularUsers : false ,
EnableHostManagementFeatures : false ,
2021-06-03 09:36:54 +00:00
AllowSysctlSettingForRegularUsers : true ,
2021-02-09 08:09:06 +00:00
AllowBindMountsForRegularUsers : true ,
AllowPrivilegedModeForRegularUsers : true ,
AllowHostNamespaceForRegularUsers : true ,
AllowContainerCapabilitiesForRegularUsers : true ,
AllowDeviceMappingForRegularUsers : true ,
AllowStackManagementForRegularUsers : true ,
}
2020-05-20 05:23:15 +00:00
err := handler . DataStore . Endpoint ( ) . CreateEndpoint ( endpoint )
2019-10-07 02:42:01 +00:00
if err != nil {
return err
}
2020-05-14 02:14:28 +00:00
for _ , tagID := range endpoint . TagIDs {
2020-05-20 05:23:15 +00:00
tag , err := handler . DataStore . Tag ( ) . Tag ( tagID )
2020-05-14 02:14:28 +00:00
if err != nil {
return err
}
tag . Endpoints [ endpoint . ID ] = true
2020-05-20 05:23:15 +00:00
err = handler . DataStore . Tag ( ) . UpdateTag ( tagID , tag )
2020-05-14 02:14:28 +00:00
if err != nil {
return err
}
}
2018-07-23 07:51:33 +00:00
return nil
}
2018-06-11 13:13:19 +00:00
func ( handler * Handler ) storeTLSFiles ( endpoint * portainer . Endpoint , payload * endpointCreatePayload ) * httperror . HandlerError {
folder := strconv . Itoa ( int ( endpoint . ID ) )
if ! payload . TLSSkipVerify {
caCertPath , err := handler . FileService . StoreTLSFileFromBytes ( folder , portainer . TLSFileCA , payload . TLSCACertFile )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist TLS CA certificate file on disk" , err }
}
endpoint . TLSConfig . TLSCACertPath = caCertPath
}
if ! payload . TLSSkipClientVerify {
certPath , err := handler . FileService . StoreTLSFileFromBytes ( folder , portainer . TLSFileCert , payload . TLSCertFile )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist TLS certificate file on disk" , err }
}
endpoint . TLSConfig . TLSCertPath = certPath
keyPath , err := handler . FileService . StoreTLSFileFromBytes ( folder , portainer . TLSFileKey , payload . TLSKeyFile )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist TLS key file on disk" , err }
}
endpoint . TLSConfig . TLSKeyPath = keyPath
}
return nil
}
2020-08-04 00:44:17 +00:00
func ( handler * Handler ) pingAndCheckPlatform ( payload * endpointCreatePayload ) ( portainer . AgentPlatform , error ) {
httpCli := & http . Client {
Timeout : 3 * time . Second ,
}
if payload . TLS {
tlsConfig , err := crypto . CreateTLSConfigurationFromBytes ( payload . TLSCACertFile , payload . TLSCertFile , payload . TLSKeyFile , payload . TLSSkipVerify , payload . TLSSkipClientVerify )
if err != nil {
return 0 , err
}
httpCli . Transport = & http . Transport {
TLSClientConfig : tlsConfig ,
}
}
url , err := url . Parse ( fmt . Sprintf ( "%s/ping" , payload . URL ) )
if err != nil {
return 0 , err
}
url . Scheme = "https"
req , err := http . NewRequest ( http . MethodGet , url . String ( ) , nil )
if err != nil {
return 0 , err
}
resp , err := httpCli . Do ( req )
if err != nil {
return 0 , err
}
defer resp . Body . Close ( )
if resp . StatusCode != http . StatusNoContent {
return 0 , fmt . Errorf ( "Failed request with status %d" , resp . StatusCode )
}
agentPlatformHeader := resp . Header . Get ( portainer . HTTPResponseAgentPlatform )
if agentPlatformHeader == "" {
return 0 , errors . New ( "Agent Platform Header is missing" )
}
agentPlatformNumber , err := strconv . Atoi ( agentPlatformHeader )
if err != nil {
return 0 , err
}
if agentPlatformNumber == 0 {
return 0 , errors . New ( "Agent platform is invalid" )
}
return portainer . AgentPlatform ( agentPlatformNumber ) , nil
}