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
2022-01-23 19:48:04 +00:00
"github.com/gofrs/uuid"
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
2022-01-23 19:48:04 +00:00
IsEdgeDevice bool
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 {
2021-09-08 08:42:17 +00:00
return errors . New ( "Invalid environment 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 {
2021-09-08 08:42:17 +00:00
return errors . New ( "Invalid environment 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 {
2021-09-08 08:42:17 +00:00
return errors . New ( "Invalid environment 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
2022-01-23 19:48:04 +00:00
isEdgeDevice , _ := request . RetrieveBooleanMultiPartFormValue ( r , "IsEdgeDevice" , true )
payload . IsEdgeDevice = isEdgeDevice
2018-06-11 13:13:19 +00:00
return nil
}
2021-02-23 03:21:39 +00:00
// @id EndpointCreate
2021-09-20 00:14:22 +00:00
// @summary Create a new environment(endpoint)
// @description Create a new environment(endpoint) that will be used to manage an environment(endpoint).
2021-02-23 03:21:39 +00:00
// @description **Access policy**: administrator
// @tags endpoints
2021-11-30 02:31:16 +00:00
// @security ApiKeyAuth
2021-02-23 03:21:39 +00:00
// @security jwt
// @accept multipart/form-data
// @produce json
2021-09-20 00:14:22 +00:00
// @param Name formData string true "Name that will be used to identify this environment(endpoint) (example: my-environment)"
// @param EndpointCreationType formData integer true "Environment(Endpoint) 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)"
2021-09-20 00:14:22 +00:00
// @param GroupID formData int false "Environment(Endpoint) group identifier. If not specified will default to 1 (unassigned)."
// @param TLS formData bool false "Require TLS to connect against this environment(endpoint)"
2021-02-23 03:21:39 +00:00
// @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"
2021-09-20 00:14:22 +00:00
// @param AzureApplicationID formData string false "Azure application ID. Required if environment(endpoint) type is set to 3"
// @param AzureTenantID formData string false "Azure tenant ID. Required if environment(endpoint) type is set to 3"
// @param AzureAuthenticationKey formData string false "Azure authentication key. Required if environment(endpoint) type is set to 3"
// @param TagIDs formData []int false "List of tag identifiers to which this environment(endpoint) is associated"
2021-02-23 03:21:39 +00:00
// @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 {
2021-09-08 08:42:17 +00:00
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to find an environment group inside the database" , err }
2020-05-14 02:14:28 +00:00
}
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
}
}
chore(store) EE-1981: Refactor/store/error checking, and other refactoring (#6173)
* use the Store interface IsErrObjectNotFound() to avoid revealing internal errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* what happens when you extract the datastore interfaces into their own package
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* Start renaming Storage methods
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the boltdb specific code from the Portainer storage code (example, the others need the same)
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extract bolt.Tx from datastore code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* minimise imports by putting moving the struct definition into the file that needs the Service imports
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extraction of boltdb.Tx
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the use of bucket.SetSequence
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* almost done - just endpoint.Synchonise :/
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* so, endpoint.Synchonize looks hard, but i can't find where we use it, so 'delete first refactoring'
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix test compile errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* test compile fixes after rebase
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix a mis-remembering I had wrt deserialisation - last time i used AnyData - jsoniter's bindTo looks interesting for the same reason
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* set us up to make the connection an interface
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make the db connection a datastore interface, and separate out our datastore services from the bolt ones
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* rename methods to something less oltdb internals specific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* these errors are not boltdb secific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* start using the db-backend factory method too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* export boltdb raw in case we can't export from the service layer
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add a raw export from boltdb to yaml for broken db's, and an export services to yaml in backup
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add the version info by hand for now
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* actually, the export from services can be fully typed - its the import that needs to do more work
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* redo raw export, and make import capable of using it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add DockerHub
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* migration from anything older than v1.21.0 has been broken for quite a while, deleting the un-tested code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix go test ./... again
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* my goland wasn't setup to gofmt
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the two extremely dubious migration tests down into store, so they can use the test store code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* the migrator is now free of boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* reverse goland overzealous replcement of internal with boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more undo over-zealous goland internal->boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* yay, now bolt is only mentioned inside the api/database/ dir
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* and this might be the last of the boltdb references?
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add todo
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the store code into a separate module too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* don't need the fileService in boltdb anymore
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use IsErrObjectNotFound()
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use a string to select what database backend we use
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make isNew store an ephemeral bool that doesn't stay true after we've initialised it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the import.json wip to a separate file so its more obvious - we'll be using it for testing, emergency fixups, and in the next part of the store work, when we improve migrations and data model lifecycles
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* undo vscode formatting html
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix app templates symbol (#6221)
* feat(webhook) EE-2125 send registry auth haeder when update swarms service via webhook (#6220)
* feat(webhook) EE-2125 add some helpers to registry utils
* feat(webhook) EE-2125 persist registryID when creating a webhook
* feat(webhook) EE-2125 send registry auth header when executing a webhook
* feat(webhook) EE-2125 send registryID to backend when creating a service with webhook
* feat(webhook) EE-2125 use the initial registry ID to create webhook on editing service screen
* feat(webhook) EE-2125 update webhook when update registry
* feat(webhook) EE-2125 add endpoint of update webhook
* feat(webhook) EE-2125 code cleanup
* feat(webhook) EE-2125 fix a typo
* feat(webhook) EE-2125 fix circle import issue with unit test
Co-authored-by: Simon Meng <simon.meng@portainer.io>
* fix(kubeconfig): show kubeconfig download button for non admin users [EE-2123] (#6204)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
* fix data-cy for k8s cluster menu (#6226)
LGTM
* feat(stack): make stack created from app template editable EE-1941 (#6104)
feat(stack): make stack from app template editable
* fix(container):disable Duplicate/Edit button when the container is portainer (#6223)
* fix/ee-1909/show-pull-image-error (#6195)
Co-authored-by: sunportainer <ericsun@SG1.local>
* feat(cy): add data-cy to helm install button (#6241)
* feat(cy): add data-cy to add registry button (#6242)
* refactor(app): convert root folder files to es6 (#4159)
* refactor(app): duplicate constants as es6 exports (#4158)
* fix(docker): provide workaround to save network name variable (#6080)
* fix/EE-1862/unable-to-stop-or-remove-stack workaround for var without default value in yaml file
* fix/EE-1862/unable-to-stop-or-remove-stack check yaml file
* fixed func and var names
* wrapper error and used bool for stringset
* UT case for createNetworkEnvFile
* UT case for %s=%s
* powerful StringSet
* wrapper error for extract network name
* wrapper all the return err
* store more env
* put to env file
* make default value None
* feat: gzip static resources (#6258)
* fix(ssl)//handle --sslcert and --sslkey ee-2106 (#6203)
* fix/ee-2106/handle-sslcert-sslkey
Co-authored-by: sunportainer <ericsun@SG1.local>
* fix(server):support disable https only ee-2068 (#6232)
* fix/ee-2068/disable-forcely-https
* feat(store): implement store tests EE-2112 (#6224)
* add store tests
* add some more tests
* Update missing helm user repo methods
* remove redundant comments
* add webhook export
* update webhooks
* use the Store interface IsErrObjectNotFound() to avoid revealing internal errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* what happens when you extract the datastore interfaces into their own package
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* Start renaming Storage methods
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the boltdb specific code from the Portainer storage code (example, the others need the same)
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extract bolt.Tx from datastore code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* minimise imports by putting moving the struct definition into the file that needs the Service imports
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extraction of boltdb.Tx
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the use of bucket.SetSequence
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* almost done - just endpoint.Synchonise :/
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* so, endpoint.Synchonize looks hard, but i can't find where we use it, so 'delete first refactoring'
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix test compile errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* test compile fixes after rebase
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix a mis-remembering I had wrt deserialisation - last time i used AnyData - jsoniter's bindTo looks interesting for the same reason
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* set us up to make the connection an interface
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make the db connection a datastore interface, and separate out our datastore services from the bolt ones
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* rename methods to something less oltdb internals specific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* these errors are not boltdb secific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* start using the db-backend factory method too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* export boltdb raw in case we can't export from the service layer
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add a raw export from boltdb to yaml for broken db's, and an export services to yaml in backup
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add the version info by hand for now
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* actually, the export from services can be fully typed - its the import that needs to do more work
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* redo raw export, and make import capable of using it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add DockerHub
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* migration from anything older than v1.21.0 has been broken for quite a while, deleting the un-tested code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix go test ./... again
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* my goland wasn't setup to gofmt
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the two extremely dubious migration tests down into store, so they can use the test store code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* the migrator is now free of boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* reverse goland overzealous replcement of internal with boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more undo over-zealous goland internal->boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* yay, now bolt is only mentioned inside the api/database/ dir
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* and this might be the last of the boltdb references?
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add todo
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the store code into a separate module too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* don't need the fileService in boltdb anymore
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use IsErrObjectNotFound()
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use a string to select what database backend we use
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make isNew store an ephemeral bool that doesn't stay true after we've initialised it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the import.json wip to a separate file so its more obvious - we'll be using it for testing, emergency fixups, and in the next part of the store work, when we improve migrations and data model lifecycles
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* undo vscode formatting html
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* Update missing helm user repo methods
* feat(store): implement store tests EE-2112 (#6224)
* add store tests
* add some more tests
* remove redundant comments
* add webhook export
* update webhooks
* fix build issues after rebasing
* move migratorparams
* remove unneeded integer type conversions
* disable the db import/export for now
Co-authored-by: Richard Wei <54336863+WaysonWei@users.noreply.github.com>
Co-authored-by: cong meng <mcpacino@gmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: Marcelo Rydel <marcelorydel26@gmail.com>
Co-authored-by: Hao Zhang <hao.zhang@portainer.io>
Co-authored-by: sunportainer <93502624+sunportainer@users.noreply.github.com>
Co-authored-by: sunportainer <ericsun@SG1.local>
Co-authored-by: wheresolivia <78844659+wheresolivia@users.noreply.github.com>
Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Co-authored-by: Chao Geng <93526589+chaogeng77977@users.noreply.github.com>
Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: Matt Hook <hookenz@gmail.com>
2021-12-15 02:26:09 +00:00
err = handler . DataStore . EndpointRelation ( ) . Create ( 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 {
2021-09-08 08:42:17 +00:00
return nil , & httperror . HandlerError { http . StatusInternalServerError , "Unable to get environment type" , err }
2020-08-04 00:44:17 +00:00
}
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 { } ,
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 {
2021-09-08 08:42:17 +00:00
return nil , & httperror . HandlerError { http . StatusInternalServerError , "An error occured while trying to create the environment" , err }
2020-06-09 02:43:32 +00:00
}
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 {
2021-09-08 08:42:17 +00:00
return nil , & httperror . HandlerError { http . StatusBadRequest , "Invalid environment URL" , err }
2019-07-25 22:38:07 +00:00
}
portainerHost , _ , err := net . SplitHostPort ( portainerURL . Host )
if err != nil {
portainerHost = portainerURL . Host
}
if portainerHost == "localhost" {
2021-09-08 08:42:17 +00:00
return nil , & httperror . HandlerError { http . StatusBadRequest , "Invalid environment URL" , errors . New ( "cannot use localhost as environment URL" ) }
2019-07-25 22:38:07 +00:00
}
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
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 ( ) ,
2022-01-23 19:48:04 +00:00
IsEdgeDevice : payload . IsEdgeDevice ,
}
settings , err := handler . DataStore . Settings ( ) . Settings ( )
if err != nil {
return nil , & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve the settings from the database" , err }
}
if settings . EnforceEdgeID {
edgeID , err := uuid . NewV4 ( )
if err != nil {
return nil , & httperror . HandlerError { http . StatusInternalServerError , "Cannot generate the Edge ID" , err }
}
endpoint . EdgeID = edgeID . String ( )
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 {
2021-09-08 08:42:17 +00:00
return nil , & httperror . HandlerError { http . StatusInternalServerError , "An error occured while trying to create the environment" , 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 { } ,
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 ( ) ,
2022-01-23 19:48:04 +00:00
IsEdgeDevice : payload . IsEdgeDevice ,
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 { } ,
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 { } ,
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 ( ) ,
2022-01-23 19:48:04 +00:00
IsEdgeDevice : payload . IsEdgeDevice ,
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" )
}
2021-09-08 08:42:17 +00:00
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to initiate communications with environment" , 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 {
2021-09-08 08:42:17 +00:00
return & httperror . HandlerError { http . StatusInternalServerError , "An error occured while trying to create the environment" , err }
2019-10-07 02:42:01 +00:00
}
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 ,
}
chore(store) EE-1981: Refactor/store/error checking, and other refactoring (#6173)
* use the Store interface IsErrObjectNotFound() to avoid revealing internal errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* what happens when you extract the datastore interfaces into their own package
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* Start renaming Storage methods
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the boltdb specific code from the Portainer storage code (example, the others need the same)
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extract bolt.Tx from datastore code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* minimise imports by putting moving the struct definition into the file that needs the Service imports
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extraction of boltdb.Tx
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the use of bucket.SetSequence
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* almost done - just endpoint.Synchonise :/
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* so, endpoint.Synchonize looks hard, but i can't find where we use it, so 'delete first refactoring'
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix test compile errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* test compile fixes after rebase
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix a mis-remembering I had wrt deserialisation - last time i used AnyData - jsoniter's bindTo looks interesting for the same reason
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* set us up to make the connection an interface
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make the db connection a datastore interface, and separate out our datastore services from the bolt ones
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* rename methods to something less oltdb internals specific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* these errors are not boltdb secific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* start using the db-backend factory method too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* export boltdb raw in case we can't export from the service layer
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add a raw export from boltdb to yaml for broken db's, and an export services to yaml in backup
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add the version info by hand for now
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* actually, the export from services can be fully typed - its the import that needs to do more work
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* redo raw export, and make import capable of using it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add DockerHub
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* migration from anything older than v1.21.0 has been broken for quite a while, deleting the un-tested code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix go test ./... again
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* my goland wasn't setup to gofmt
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the two extremely dubious migration tests down into store, so they can use the test store code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* the migrator is now free of boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* reverse goland overzealous replcement of internal with boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more undo over-zealous goland internal->boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* yay, now bolt is only mentioned inside the api/database/ dir
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* and this might be the last of the boltdb references?
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add todo
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the store code into a separate module too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* don't need the fileService in boltdb anymore
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use IsErrObjectNotFound()
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use a string to select what database backend we use
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make isNew store an ephemeral bool that doesn't stay true after we've initialised it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the import.json wip to a separate file so its more obvious - we'll be using it for testing, emergency fixups, and in the next part of the store work, when we improve migrations and data model lifecycles
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* undo vscode formatting html
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix app templates symbol (#6221)
* feat(webhook) EE-2125 send registry auth haeder when update swarms service via webhook (#6220)
* feat(webhook) EE-2125 add some helpers to registry utils
* feat(webhook) EE-2125 persist registryID when creating a webhook
* feat(webhook) EE-2125 send registry auth header when executing a webhook
* feat(webhook) EE-2125 send registryID to backend when creating a service with webhook
* feat(webhook) EE-2125 use the initial registry ID to create webhook on editing service screen
* feat(webhook) EE-2125 update webhook when update registry
* feat(webhook) EE-2125 add endpoint of update webhook
* feat(webhook) EE-2125 code cleanup
* feat(webhook) EE-2125 fix a typo
* feat(webhook) EE-2125 fix circle import issue with unit test
Co-authored-by: Simon Meng <simon.meng@portainer.io>
* fix(kubeconfig): show kubeconfig download button for non admin users [EE-2123] (#6204)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
* fix data-cy for k8s cluster menu (#6226)
LGTM
* feat(stack): make stack created from app template editable EE-1941 (#6104)
feat(stack): make stack from app template editable
* fix(container):disable Duplicate/Edit button when the container is portainer (#6223)
* fix/ee-1909/show-pull-image-error (#6195)
Co-authored-by: sunportainer <ericsun@SG1.local>
* feat(cy): add data-cy to helm install button (#6241)
* feat(cy): add data-cy to add registry button (#6242)
* refactor(app): convert root folder files to es6 (#4159)
* refactor(app): duplicate constants as es6 exports (#4158)
* fix(docker): provide workaround to save network name variable (#6080)
* fix/EE-1862/unable-to-stop-or-remove-stack workaround for var without default value in yaml file
* fix/EE-1862/unable-to-stop-or-remove-stack check yaml file
* fixed func and var names
* wrapper error and used bool for stringset
* UT case for createNetworkEnvFile
* UT case for %s=%s
* powerful StringSet
* wrapper error for extract network name
* wrapper all the return err
* store more env
* put to env file
* make default value None
* feat: gzip static resources (#6258)
* fix(ssl)//handle --sslcert and --sslkey ee-2106 (#6203)
* fix/ee-2106/handle-sslcert-sslkey
Co-authored-by: sunportainer <ericsun@SG1.local>
* fix(server):support disable https only ee-2068 (#6232)
* fix/ee-2068/disable-forcely-https
* feat(store): implement store tests EE-2112 (#6224)
* add store tests
* add some more tests
* Update missing helm user repo methods
* remove redundant comments
* add webhook export
* update webhooks
* use the Store interface IsErrObjectNotFound() to avoid revealing internal errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* what happens when you extract the datastore interfaces into their own package
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* Start renaming Storage methods
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the boltdb specific code from the Portainer storage code (example, the others need the same)
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extract bolt.Tx from datastore code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* minimise imports by putting moving the struct definition into the file that needs the Service imports
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more extraction of boltdb.Tx
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the use of bucket.SetSequence
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* almost done - just endpoint.Synchonise :/
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* so, endpoint.Synchonize looks hard, but i can't find where we use it, so 'delete first refactoring'
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix test compile errors
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* test compile fixes after rebase
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix a mis-remembering I had wrt deserialisation - last time i used AnyData - jsoniter's bindTo looks interesting for the same reason
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* set us up to make the connection an interface
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make the db connection a datastore interface, and separate out our datastore services from the bolt ones
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* rename methods to something less oltdb internals specific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* these errors are not boltdb secific
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* start using the db-backend factory method too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* export boltdb raw in case we can't export from the service layer
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add a raw export from boltdb to yaml for broken db's, and an export services to yaml in backup
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add the version info by hand for now
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* actually, the export from services can be fully typed - its the import that needs to do more work
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* redo raw export, and make import capable of using it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add DockerHub
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* migration from anything older than v1.21.0 has been broken for quite a while, deleting the un-tested code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* fix go test ./... again
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* my goland wasn't setup to gofmt
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the two extremely dubious migration tests down into store, so they can use the test store code
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* the migrator is now free of boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* reverse goland overzealous replcement of internal with boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* more undo over-zealous goland internal->boltdb
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* yay, now bolt is only mentioned inside the api/database/ dir
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* and this might be the last of the boltdb references?
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* add todo
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* extract the store code into a separate module too
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* don't need the fileService in boltdb anymore
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use IsErrObjectNotFound()
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* use a string to select what database backend we use
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* make isNew store an ephemeral bool that doesn't stay true after we've initialised it
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* move the import.json wip to a separate file so its more obvious - we'll be using it for testing, emergency fixups, and in the next part of the store work, when we improve migrations and data model lifecycles
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* undo vscode formatting html
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
* Update missing helm user repo methods
* feat(store): implement store tests EE-2112 (#6224)
* add store tests
* add some more tests
* remove redundant comments
* add webhook export
* update webhooks
* fix build issues after rebasing
* move migratorparams
* remove unneeded integer type conversions
* disable the db import/export for now
Co-authored-by: Richard Wei <54336863+WaysonWei@users.noreply.github.com>
Co-authored-by: cong meng <mcpacino@gmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: Marcelo Rydel <marcelorydel26@gmail.com>
Co-authored-by: Hao Zhang <hao.zhang@portainer.io>
Co-authored-by: sunportainer <93502624+sunportainer@users.noreply.github.com>
Co-authored-by: sunportainer <ericsun@SG1.local>
Co-authored-by: wheresolivia <78844659+wheresolivia@users.noreply.github.com>
Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Co-authored-by: Chao Geng <93526589+chaogeng77977@users.noreply.github.com>
Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: Matt Hook <hookenz@gmail.com>
2021-12-15 02:26:09 +00:00
err := handler . DataStore . Endpoint ( ) . Create ( 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
}