From ea0b34de729df0fedbfc9b22ebc20f940ed3cdd0 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Wed, 23 Feb 2022 16:21:35 +1000 Subject: [PATCH] move registry struct definitions to dataservice/registry Signed-off-by: Sven Dowideit --- api/apikey/apikey.go | 5 +- api/apikey/cache.go | 3 +- api/apikey/service.go | 5 +- api/cmd/portainer/main.go | 2 +- api/database/types.go | 35 +++ .../apikeyrepository/apikeyrepository.go | 2 +- api/dataservices/endpoint/endpoint.go | 6 +- .../helmuserrepository/helmuserrepository.go | 2 +- api/dataservices/interface.go | 39 +-- api/dataservices/registry/registry.go | 107 +++++++- api/dataservices/role/role.go | 6 +- api/dataservices/team/team.go | 8 +- api/dataservices/team/tests/utils.go | 3 +- .../teammembership/teammembership.go | 8 +- api/dataservices/user/user.go | 8 +- api/datastore/datastore_test.go | 15 +- api/datastore/init.go | 7 +- api/datastore/migrator/migrate_dbversion17.go | 25 +- api/datastore/migrator/migrate_dbversion20.go | 10 +- api/datastore/migrator/migrate_dbversion31.go | 26 +- api/datastore/services.go | 2 +- api/exec/exectest/kubernetes_mocks.go | 5 +- api/exec/kubernetes_deploy.go | 9 +- api/exec/swarm_stack.go | 3 +- api/http/handler/auth/authenticate.go | 3 +- .../customtemplates/customtemplate_list.go | 3 +- api/http/handler/customtemplates/handler.go | 3 +- .../endpointgroups/endpointgroup_create.go | 4 +- .../endpointgroups/endpointgroup_update.go | 5 +- api/http/handler/endpoints/endpoint_create.go | 9 +- .../endpoints/endpoint_dockerhub_status.go | 9 +- .../endpoints/endpoint_registries_inspect.go | 4 +- .../endpoints/endpoint_registries_list.go | 9 +- .../endpoints/endpoint_registry_access.go | 25 +- api/http/handler/endpoints/endpoint_update.go | 4 +- api/http/handler/helm/user_helm_repos.go | 5 +- api/http/handler/registries/handler.go | 5 +- .../handler/registries/registry_configure.go | 9 +- .../handler/registries/registry_create.go | 15 +- .../registries/registry_create_test.go | 26 +- .../handler/registries/registry_delete.go | 6 +- .../handler/registries/registry_inspect.go | 5 +- .../handler/registries/registry_update.go | 11 +- .../registries/registry_update_test.go | 12 +- .../resourcecontrol_create.go | 5 +- .../resourcecontrol_update.go | 5 +- .../handler/stacks/create_compose_stack.go | 12 +- .../handler/stacks/create_kubernetes_stack.go | 9 +- api/http/handler/stacks/create_swarm_stack.go | 10 +- api/http/handler/stacks/handler.go | 4 +- api/http/handler/stacks/stack_create.go | 8 +- api/http/handler/stacks/stack_delete.go | 2 +- api/http/handler/stacks/stack_list.go | 2 +- .../teammemberships/teammembership_create.go | 11 +- .../teammemberships/teammembership_update.go | 7 +- api/http/handler/teams/team_delete.go | 12 +- api/http/handler/teams/team_inspect.go | 6 +- api/http/handler/teams/team_memberships.go | 6 +- api/http/handler/teams/team_update.go | 4 +- .../handler/users/user_create_access_token.go | 5 +- api/http/handler/users/user_delete.go | 5 +- .../handler/users/user_get_access_tokens.go | 7 +- api/http/handler/users/user_inspect.go | 6 +- api/http/handler/users/user_memberships.go | 5 +- .../handler/users/user_remove_access_token.go | 7 +- api/http/handler/users/user_update.go | 7 +- .../handler/users/user_update_password.go | 5 +- api/http/handler/webhooks/handler.go | 3 +- api/http/handler/webhooks/webhook_create.go | 3 +- api/http/handler/webhooks/webhook_execute.go | 3 +- api/http/handler/webhooks/webhook_update.go | 3 +- .../proxy/factory/azure/access_control.go | 5 +- api/http/proxy/factory/azure/transport.go | 5 +- .../proxy/factory/docker/access_control.go | 6 +- api/http/proxy/factory/docker/registry.go | 9 +- api/http/proxy/factory/docker/transport.go | 15 +- api/http/proxy/factory/docker/volumes.go | 2 +- .../proxy/factory/kubernetes/namespaces.go | 4 +- api/http/proxy/factory/kubernetes/token.go | 2 +- .../proxy/factory/kubernetes/transport.go | 5 +- api/http/security/authorization.go | 11 +- api/http/security/bouncer.go | 5 +- api/http/security/bouncer_test.go | 3 +- api/http/security/filter.go | 5 +- api/internal/authorization/access_control.go | 11 +- api/internal/authorization/authorizations.go | 22 +- .../endpint_role_with_override.go | 19 +- api/internal/registryutils/access/access.go | 11 +- api/internal/registryutils/auth_header.go | 4 +- api/internal/registryutils/ecr_kube_secret.go | 3 +- api/internal/registryutils/ecr_reg_token.go | 11 +- api/internal/testhelpers/datastore.go | 8 +- api/jwt/jwt.go | 5 +- api/kubernetes/cli/access.go | 5 +- api/kubernetes/cli/access_test.go | 7 +- api/kubernetes/cli/namespace_test.go | 3 +- api/kubernetes/cli/registries.go | 8 +- api/portainer.go | 233 +++++------------- api/stacks/deploy.go | 5 +- api/stacks/deploy_test.go | 33 +-- api/stacks/deployer.go | 9 +- 101 files changed, 610 insertions(+), 539 deletions(-) diff --git a/api/apikey/apikey.go b/api/apikey/apikey.go index 8302e6b73..97e2f0271 100644 --- a/api/apikey/apikey.go +++ b/api/apikey/apikey.go @@ -2,6 +2,7 @@ package apikey import ( "crypto/rand" + "github.com/portainer/portainer/api/database" "io" portainer "github.com/portainer/portainer/api" @@ -12,11 +13,11 @@ type APIKeyService interface { HashRaw(rawKey string) []byte GenerateApiKey(user portainer.User, description string) (string, *portainer.APIKey, error) GetAPIKey(apiKeyID portainer.APIKeyID) (*portainer.APIKey, error) - GetAPIKeys(userID portainer.UserID) ([]portainer.APIKey, error) + GetAPIKeys(userID database.UserID) ([]portainer.APIKey, error) GetDigestUserAndKey(digest []byte) (portainer.User, portainer.APIKey, error) UpdateAPIKey(apiKey *portainer.APIKey) error DeleteAPIKey(apiKeyID portainer.APIKeyID) error - InvalidateUserKeyCache(userId portainer.UserID) bool + InvalidateUserKeyCache(userId database.UserID) bool } // generateRandomKey generates a random key of specified length diff --git a/api/apikey/cache.go b/api/apikey/cache.go index 520f7274a..64b70d22a 100644 --- a/api/apikey/cache.go +++ b/api/apikey/cache.go @@ -3,6 +3,7 @@ package apikey import ( lru "github.com/hashicorp/golang-lru" portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/database" ) const defaultAPIKeyCacheSize = 1024 @@ -57,7 +58,7 @@ func (c *apiKeyCache) Delete(digest []byte) { } // InvalidateUserKeyCache loops through all the api-keys associated to a user and removes them from the cache -func (c *apiKeyCache) InvalidateUserKeyCache(userId portainer.UserID) bool { +func (c *apiKeyCache) InvalidateUserKeyCache(userId database.UserID) bool { present := false for _, k := range c.cache.Keys() { user, _, _ := c.Get([]byte(k.(string))) diff --git a/api/apikey/service.go b/api/apikey/service.go index be794509b..c2df2b432 100644 --- a/api/apikey/service.go +++ b/api/apikey/service.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/base64" "fmt" + "github.com/portainer/portainer/api/database" "time" "github.com/pkg/errors" @@ -70,7 +71,7 @@ func (a *apiKeyService) GetAPIKey(apiKeyID portainer.APIKeyID) (*portainer.APIKe } // GetAPIKeys returns all the API keys associated to a user. -func (a *apiKeyService) GetAPIKeys(userID portainer.UserID) ([]portainer.APIKey, error) { +func (a *apiKeyService) GetAPIKeys(userID database.UserID) ([]portainer.APIKey, error) { return a.apiKeyRepository.GetAPIKeysByUserID(userID) } @@ -122,6 +123,6 @@ func (a *apiKeyService) DeleteAPIKey(apiKeyID portainer.APIKeyID) error { return a.apiKeyRepository.DeleteAPIKey(apiKeyID) } -func (a *apiKeyService) InvalidateUserKeyCache(userId portainer.UserID) bool { +func (a *apiKeyService) InvalidateUserKeyCache(userId database.UserID) bool { return a.cache.InvalidateUserKeyCache(userId) } diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 3c7e8968c..cb3e17f30 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -375,7 +375,7 @@ func initKeyPair(fileService portainer.FileService, signatureService portainer.D } func createTLSSecuredEndpoint(flags *portainer.CLIFlags, dataStore dataservices.DataStore, snapshotService portainer.SnapshotService) error { - tlsConfiguration := portainer.TLSConfiguration{ + tlsConfiguration := database.TLSConfiguration{ TLS: *flags.TLS, TLSSkipVerify: *flags.TLSSkipVerify, } diff --git a/api/database/types.go b/api/database/types.go index e010f8eeb..f0f8fc8a3 100644 --- a/api/database/types.go +++ b/api/database/types.go @@ -4,3 +4,38 @@ package database // EndpointID represents an environment(endpoint) identifier type EndpointID int + +// UserAccessPolicies represent the association of an access policy and a user +type UserAccessPolicies map[UserID]AccessPolicy + +// TeamAccessPolicies represent the association of an access policy and a team +type TeamAccessPolicies map[TeamID]AccessPolicy + +// TLSConfiguration represents a TLS configuration +type TLSConfiguration struct { + // Use TLS + TLS bool `json:"TLS" example:"true"` + // Skip the verification of the server TLS certificate + TLSSkipVerify bool `json:"TLSSkipVerify" example:"false"` + // Path to the TLS CA certificate file + TLSCACertPath string `json:"TLSCACert,omitempty" example:"/data/tls/ca.pem"` + // Path to the TLS client certificate file + TLSCertPath string `json:"TLSCert,omitempty" example:"/data/tls/cert.pem"` + // Path to the TLS client key file + TLSKeyPath string `json:"TLSKey,omitempty" example:"/data/tls/key.pem"` +} + +// TeamID represents a team identifier +type TeamID int + +// UserID represents a user identifier +type UserID int + +// AccessPolicy represent a policy that can be associated to a user or team +type AccessPolicy struct { + // Role identifier. Reference the role that will be associated to this access policy + RoleID RoleID `json:"RoleId" example:"1"` +} + +// RoleID represents a role identifier +type RoleID int diff --git a/api/dataservices/apikeyrepository/apikeyrepository.go b/api/dataservices/apikeyrepository/apikeyrepository.go index dbcb2707b..4f852eb1a 100644 --- a/api/dataservices/apikeyrepository/apikeyrepository.go +++ b/api/dataservices/apikeyrepository/apikeyrepository.go @@ -33,7 +33,7 @@ func NewService(connection database.Connection) (*Service, error) { } // GetAPIKeysByUserID returns a slice containing all the APIKeys a user has access to. -func (service *Service) GetAPIKeysByUserID(userID portainer.UserID) ([]portainer.APIKey, error) { +func (service *Service) GetAPIKeysByUserID(userID database.UserID) ([]portainer.APIKey, error) { var result = make([]portainer.APIKey, 0) err := service.connection.GetAll( diff --git a/api/dataservices/endpoint/endpoint.go b/api/dataservices/endpoint/endpoint.go index 6e237b382..cdf99ecbc 100644 --- a/api/dataservices/endpoint/endpoint.go +++ b/api/dataservices/endpoint/endpoint.go @@ -99,11 +99,11 @@ func (service *Service) NewDefault() *portainer.Endpoint { //URL: *flags.EndpointURL, //GroupID: portainer.EndpointGroupID(1), //Type: portainer.DockerEnvironment, - TLSConfig: portainer.TLSConfiguration{ + TLSConfig: database.TLSConfiguration{ TLS: false, }, - UserAccessPolicies: portainer.UserAccessPolicies{}, - TeamAccessPolicies: portainer.TeamAccessPolicies{}, + UserAccessPolicies: database.UserAccessPolicies{}, + TeamAccessPolicies: database.TeamAccessPolicies{}, TagIDs: []portainer.TagID{}, Status: portainer.EndpointStatusUp, Snapshots: []portainer.DockerSnapshot{}, diff --git a/api/dataservices/helmuserrepository/helmuserrepository.go b/api/dataservices/helmuserrepository/helmuserrepository.go index a09b586f6..4c1be3150 100644 --- a/api/dataservices/helmuserrepository/helmuserrepository.go +++ b/api/dataservices/helmuserrepository/helmuserrepository.go @@ -55,7 +55,7 @@ func (service *Service) HelmUserRepositories() ([]portainer.HelmUserRepository, } // HelmUserRepositoryByUserID return an array containing all the HelmUserRepository objects where the specified userID is present. -func (service *Service) HelmUserRepositoryByUserID(userID portainer.UserID) ([]portainer.HelmUserRepository, error) { +func (service *Service) HelmUserRepositoryByUserID(userID database.UserID) ([]portainer.HelmUserRepository, error) { var result = make([]portainer.HelmUserRepository, 0) err := service.connection.GetAll( diff --git a/api/dataservices/interface.go b/api/dataservices/interface.go index 446603956..45f857dd7 100644 --- a/api/dataservices/interface.go +++ b/api/dataservices/interface.go @@ -5,6 +5,7 @@ package dataservices import ( "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/dataservices/edgejob" + "github.com/portainer/portainer/api/dataservices/registry" "io" "time" @@ -140,7 +141,7 @@ type ( // HelmUserRepositoryService represents a service to manage HelmUserRepositories HelmUserRepositoryService interface { HelmUserRepositories() ([]portainer.HelmUserRepository, error) - HelmUserRepositoryByUserID(userID portainer.UserID) ([]portainer.HelmUserRepository, error) + HelmUserRepositoryByUserID(userID database.UserID) ([]portainer.HelmUserRepository, error) Create(record *portainer.HelmUserRepository) error UpdateHelmUserRepository(ID portainer.HelmUserRepositoryID, repository *portainer.HelmUserRepository) error DeleteHelmUserRepository(ID portainer.HelmUserRepositoryID) error @@ -158,11 +159,11 @@ type ( // RegistryService represents a service for managing registry data RegistryService interface { - Registry(ID portainer.RegistryID) (*portainer.Registry, error) - Registries() ([]portainer.Registry, error) - Create(registry *portainer.Registry) error - UpdateRegistry(ID portainer.RegistryID, registry *portainer.Registry) error - DeleteRegistry(ID portainer.RegistryID) error + Registry(ID registry.RegistryID) (*registry.Registry, error) + Registries() ([]registry.Registry, error) + Create(registry *registry.Registry) error + UpdateRegistry(ID registry.RegistryID, registry *registry.Registry) error + DeleteRegistry(ID registry.RegistryID) error BucketName() string } @@ -179,10 +180,10 @@ type ( // RoleService represents a service for managing user roles RoleService interface { - Role(ID portainer.RoleID) (*portainer.Role, error) + Role(ID database.RoleID) (*portainer.Role, error) Roles() ([]portainer.Role, error) Create(role *portainer.Role) error - UpdateRole(ID portainer.RoleID, role *portainer.Role) error + UpdateRole(ID database.RoleID, role *portainer.Role) error BucketName() string } @@ -192,7 +193,7 @@ type ( GetAPIKey(keyID portainer.APIKeyID) (*portainer.APIKey, error) UpdateAPIKey(key *portainer.APIKey) error DeleteAPIKey(ID portainer.APIKeyID) error - GetAPIKeysByUserID(userID portainer.UserID) ([]portainer.APIKey, error) + GetAPIKeysByUserID(userID database.UserID) ([]portainer.APIKey, error) GetAPIKeyByDigest(digest []byte) (*portainer.APIKey, error) } @@ -238,12 +239,12 @@ type ( // TeamService represents a service for managing user data TeamService interface { - Team(ID portainer.TeamID) (*portainer.Team, error) + Team(ID database.TeamID) (*portainer.Team, error) TeamByName(name string) (*portainer.Team, error) Teams() ([]portainer.Team, error) Create(team *portainer.Team) error - UpdateTeam(ID portainer.TeamID, team *portainer.Team) error - DeleteTeam(ID portainer.TeamID) error + UpdateTeam(ID database.TeamID, team *portainer.Team) error + DeleteTeam(ID database.TeamID) error BucketName() string } @@ -251,13 +252,13 @@ type ( TeamMembershipService interface { TeamMembership(ID portainer.TeamMembershipID) (*portainer.TeamMembership, error) TeamMemberships() ([]portainer.TeamMembership, error) - TeamMembershipsByUserID(userID portainer.UserID) ([]portainer.TeamMembership, error) - TeamMembershipsByTeamID(teamID portainer.TeamID) ([]portainer.TeamMembership, error) + TeamMembershipsByUserID(userID database.UserID) ([]portainer.TeamMembership, error) + TeamMembershipsByTeamID(teamID database.TeamID) ([]portainer.TeamMembership, error) Create(membership *portainer.TeamMembership) error UpdateTeamMembership(ID portainer.TeamMembershipID, membership *portainer.TeamMembership) error DeleteTeamMembership(ID portainer.TeamMembershipID) error - DeleteTeamMembershipByUserID(userID portainer.UserID) error - DeleteTeamMembershipByTeamID(teamID portainer.TeamID) error + DeleteTeamMembershipByUserID(userID database.UserID) error + DeleteTeamMembershipByTeamID(teamID database.TeamID) error BucketName() string } @@ -270,13 +271,13 @@ type ( // UserService represents a service for managing user data UserService interface { - User(ID portainer.UserID) (*portainer.User, error) + User(ID database.UserID) (*portainer.User, error) UserByUsername(username string) (*portainer.User, error) Users() ([]portainer.User, error) UsersByRole(role portainer.UserRole) ([]portainer.User, error) Create(user *portainer.User) error - UpdateUser(ID portainer.UserID, user *portainer.User) error - DeleteUser(ID portainer.UserID) error + UpdateUser(ID database.UserID, user *portainer.User) error + DeleteUser(ID database.UserID) error BucketName() string } diff --git a/api/dataservices/registry/registry.go b/api/dataservices/registry/registry.go index 8ba6f53c9..b7e334b72 100644 --- a/api/dataservices/registry/registry.go +++ b/api/dataservices/registry/registry.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/portainer/portainer/api/database" - portainer "github.com/portainer/portainer/api" "github.com/sirupsen/logrus" ) @@ -35,8 +34,8 @@ func NewService(connection database.Connection) (*Service, error) { } // Registry returns an registry by ID. -func (service *Service) Registry(ID portainer.RegistryID) (*portainer.Registry, error) { - var registry portainer.Registry +func (service *Service) Registry(ID RegistryID) (*Registry, error) { + var registry Registry identifier := service.connection.ConvertToKey(int(ID)) err := service.connection.GetObject(BucketName, identifier, ®istry) @@ -48,44 +47,128 @@ func (service *Service) Registry(ID portainer.RegistryID) (*portainer.Registry, } // Registries returns an array containing all the registries. -func (service *Service) Registries() ([]portainer.Registry, error) { - var registries = make([]portainer.Registry, 0) +func (service *Service) Registries() ([]Registry, error) { + var registries = make([]Registry, 0) err := service.connection.GetAll( BucketName, - &portainer.Registry{}, + &Registry{}, func(obj interface{}) (interface{}, error) { - registry, ok := obj.(*portainer.Registry) + registry, ok := obj.(*Registry) if !ok { logrus.WithField("obj", obj).Errorf("Failed to convert to Registry object") return nil, fmt.Errorf("Failed to convert to Registry object: %s", obj) } registries = append(registries, *registry) - return &portainer.Registry{}, nil + return &Registry{}, nil }) return registries, err } // CreateRegistry creates a new registry. -func (service *Service) Create(registry *portainer.Registry) error { +func (service *Service) Create(registry *Registry) error { return service.connection.CreateObject( BucketName, func(id uint64) (int, interface{}) { - registry.ID = portainer.RegistryID(id) + registry.ID = RegistryID(id) return int(registry.ID), registry }, ) } // UpdateRegistry updates an registry. -func (service *Service) UpdateRegistry(ID portainer.RegistryID, registry *portainer.Registry) error { +func (service *Service) UpdateRegistry(ID RegistryID, registry *Registry) error { identifier := service.connection.ConvertToKey(int(ID)) return service.connection.UpdateObject(BucketName, identifier, registry) } // DeleteRegistry deletes an registry. -func (service *Service) DeleteRegistry(ID portainer.RegistryID) error { +func (service *Service) DeleteRegistry(ID RegistryID) error { identifier := service.connection.ConvertToKey(int(ID)) return service.connection.DeleteObject(BucketName, identifier) } + +// Registry represents a Docker registry with all the info required to connect to it +type Registry struct { + // Registry Identifier + ID RegistryID `json:"Id" example:"1"` + // Registry Type (1 - Quay, 2 - Azure, 3 - Custom, 4 - Gitlab, 5 - ProGet, 6 - DockerHub, 7 - ECR) + Type RegistryType `json:"Type" enums:"1,2,3,4,5,6,7"` + // Registry Name + Name string `json:"Name" example:"my-registry"` + // URL or IP address of the Docker registry + URL string `json:"URL" example:"registry.mydomain.tld:2375"` + // Base URL, introduced for ProGet registry + BaseURL string `json:"BaseURL" example:"registry.mydomain.tld:2375"` + // Is authentication against this registry enabled + Authentication bool `json:"Authentication" example:"true"` + // Username or AccessKeyID used to authenticate against this registry + Username string `json:"Username" example:"registry user"` + // Password or SecretAccessKey used to authenticate against this registry + Password string `json:"Password,omitempty" example:"registry_password"` + ManagementConfiguration *RegistryManagementConfiguration `json:"ManagementConfiguration"` + Gitlab GitlabRegistryData `json:"Gitlab"` + Quay QuayRegistryData `json:"Quay"` + Ecr EcrData `json:"Ecr"` + RegistryAccesses RegistryAccesses `json:"RegistryAccesses"` + + // Deprecated fields + // Deprecated in DBVersion == 31 + UserAccessPolicies database.UserAccessPolicies `json:"UserAccessPolicies"` + // Deprecated in DBVersion == 31 + TeamAccessPolicies database.TeamAccessPolicies `json:"TeamAccessPolicies"` + + // Deprecated in DBVersion == 18 + AuthorizedUsers []database.UserID `json:"AuthorizedUsers"` + // Deprecated in DBVersion == 18 + AuthorizedTeams []database.TeamID `json:"AuthorizedTeams"` + + // Stores temporary access token + AccessToken string `json:"AccessToken,omitempty"` + AccessTokenExpiry int64 `json:"AccessTokenExpiry,omitempty"` +} + +type RegistryAccesses map[database.EndpointID]RegistryAccessPolicies + +type RegistryAccessPolicies struct { + UserAccessPolicies database.UserAccessPolicies `json:"UserAccessPolicies"` + TeamAccessPolicies database.TeamAccessPolicies `json:"TeamAccessPolicies"` + Namespaces []string `json:"Namespaces"` +} + +// RegistryID represents a registry identifier +type RegistryID int + +// RegistryManagementConfiguration represents a configuration that can be used to query the registry API via the registry management extension. +type RegistryManagementConfiguration struct { + Type RegistryType `json:"Type"` + Authentication bool `json:"Authentication"` + Username string `json:"Username"` + Password string `json:"Password"` + TLSConfig database.TLSConfiguration `json:"TLSConfig"` + Ecr EcrData `json:"Ecr"` + AccessToken string `json:"AccessToken,omitempty"` + AccessTokenExpiry int64 `json:"AccessTokenExpiry,omitempty"` +} + +// RegistryType represents a type of registry +type RegistryType int + +// GitlabRegistryData represents data required for gitlab registry to work +type GitlabRegistryData struct { + ProjectID int `json:"ProjectId"` + InstanceURL string `json:"InstanceURL"` + ProjectPath string `json:"ProjectPath"` +} + +// QuayRegistryData represents data required for Quay registry to work +type QuayRegistryData struct { + UseOrganisation bool `json:"UseOrganisation"` + OrganisationName string `json:"OrganisationName"` +} + +// EcrData represents data required for ECR registry +type EcrData struct { + Region string `json:"Region" example:"ap-southeast-2"` +} diff --git a/api/dataservices/role/role.go b/api/dataservices/role/role.go index 0afa8cd59..f84ae9ac8 100644 --- a/api/dataservices/role/role.go +++ b/api/dataservices/role/role.go @@ -35,7 +35,7 @@ func NewService(connection database.Connection) (*Service, error) { } // Role returns a Role by ID -func (service *Service) Role(ID portainer.RoleID) (*portainer.Role, error) { +func (service *Service) Role(ID database.RoleID) (*portainer.Role, error) { var set portainer.Role identifier := service.connection.ConvertToKey(int(ID)) @@ -72,14 +72,14 @@ func (service *Service) Create(role *portainer.Role) error { return service.connection.CreateObject( BucketName, func(id uint64) (int, interface{}) { - role.ID = portainer.RoleID(id) + role.ID = database.RoleID(id) return int(role.ID), role }, ) } // UpdateRole updates a role. -func (service *Service) UpdateRole(ID portainer.RoleID, role *portainer.Role) error { +func (service *Service) UpdateRole(ID database.RoleID, role *portainer.Role) error { identifier := service.connection.ConvertToKey(int(ID)) return service.connection.UpdateObject(BucketName, identifier, role) } diff --git a/api/dataservices/team/team.go b/api/dataservices/team/team.go index 60b817ce6..05e6ff4ff 100644 --- a/api/dataservices/team/team.go +++ b/api/dataservices/team/team.go @@ -38,7 +38,7 @@ func NewService(connection database.Connection) (*Service, error) { } // Team returns a Team by ID -func (service *Service) Team(ID portainer.TeamID) (*portainer.Team, error) { +func (service *Service) Team(ID database.TeamID) (*portainer.Team, error) { var team portainer.Team identifier := service.connection.ConvertToKey(int(ID)) @@ -101,7 +101,7 @@ func (service *Service) Teams() ([]portainer.Team, error) { } // UpdateTeam saves a Team. -func (service *Service) UpdateTeam(ID portainer.TeamID, team *portainer.Team) error { +func (service *Service) UpdateTeam(ID database.TeamID, team *portainer.Team) error { identifier := service.connection.ConvertToKey(int(ID)) return service.connection.UpdateObject(BucketName, identifier, team) } @@ -111,14 +111,14 @@ func (service *Service) Create(team *portainer.Team) error { return service.connection.CreateObject( BucketName, func(id uint64) (int, interface{}) { - team.ID = portainer.TeamID(id) + team.ID = database.TeamID(id) return int(team.ID), team }, ) } // DeleteTeam deletes a Team. -func (service *Service) DeleteTeam(ID portainer.TeamID) error { +func (service *Service) DeleteTeam(ID database.TeamID) error { identifier := service.connection.ConvertToKey(int(ID)) return service.connection.DeleteObject(BucketName, identifier) } diff --git a/api/dataservices/team/tests/utils.go b/api/dataservices/team/tests/utils.go index cdcd29ee3..3beb38dd2 100644 --- a/api/dataservices/team/tests/utils.go +++ b/api/dataservices/team/tests/utils.go @@ -1,6 +1,7 @@ package tests import ( + "github.com/portainer/portainer/api/database" "testing" portainer "github.com/portainer/portainer/api" @@ -17,7 +18,7 @@ type teamBuilder struct { func (b *teamBuilder) createNew(name string) *portainer.Team { b.count++ team := &portainer.Team{ - ID: portainer.TeamID(b.count), + ID: database.TeamID(b.count), Name: name, } diff --git a/api/dataservices/teammembership/teammembership.go b/api/dataservices/teammembership/teammembership.go index 9c6fb4794..270c47ac1 100644 --- a/api/dataservices/teammembership/teammembership.go +++ b/api/dataservices/teammembership/teammembership.go @@ -68,7 +68,7 @@ func (service *Service) TeamMemberships() ([]portainer.TeamMembership, error) { } // TeamMembershipsByUserID return an array containing all the TeamMembership objects where the specified userID is present. -func (service *Service) TeamMembershipsByUserID(userID portainer.UserID) ([]portainer.TeamMembership, error) { +func (service *Service) TeamMembershipsByUserID(userID database.UserID) ([]portainer.TeamMembership, error) { var memberships = make([]portainer.TeamMembership, 0) err := service.connection.GetAll( @@ -90,7 +90,7 @@ func (service *Service) TeamMembershipsByUserID(userID portainer.UserID) ([]port } // TeamMembershipsByTeamID return an array containing all the TeamMembership objects where the specified teamID is present. -func (service *Service) TeamMembershipsByTeamID(teamID portainer.TeamID) ([]portainer.TeamMembership, error) { +func (service *Service) TeamMembershipsByTeamID(teamID database.TeamID) ([]portainer.TeamMembership, error) { var memberships = make([]portainer.TeamMembership, 0) err := service.connection.GetAll( @@ -135,7 +135,7 @@ func (service *Service) DeleteTeamMembership(ID portainer.TeamMembershipID) erro } // DeleteTeamMembershipByUserID deletes all the TeamMembership object associated to a UserID. -func (service *Service) DeleteTeamMembershipByUserID(userID portainer.UserID) error { +func (service *Service) DeleteTeamMembershipByUserID(userID database.UserID) error { return service.connection.DeleteAllObjects( BucketName, func(obj interface{}) (id int, ok bool) { @@ -153,7 +153,7 @@ func (service *Service) DeleteTeamMembershipByUserID(userID portainer.UserID) er } // DeleteTeamMembershipByTeamID deletes all the TeamMembership object associated to a TeamID. -func (service *Service) DeleteTeamMembershipByTeamID(teamID portainer.TeamID) error { +func (service *Service) DeleteTeamMembershipByTeamID(teamID database.TeamID) error { return service.connection.DeleteAllObjects( BucketName, func(obj interface{}) (id int, ok bool) { diff --git a/api/dataservices/user/user.go b/api/dataservices/user/user.go index 7a8663eac..c832c5256 100644 --- a/api/dataservices/user/user.go +++ b/api/dataservices/user/user.go @@ -38,7 +38,7 @@ func NewService(connection database.Connection) (*Service, error) { } // User returns a user by ID -func (service *Service) User(ID portainer.UserID) (*portainer.User, error) { +func (service *Service) User(ID database.UserID) (*portainer.User, error) { var user portainer.User identifier := service.connection.ConvertToKey(int(ID)) @@ -122,7 +122,7 @@ func (service *Service) UsersByRole(role portainer.UserRole) ([]portainer.User, } // UpdateUser saves a user. -func (service *Service) UpdateUser(ID portainer.UserID, user *portainer.User) error { +func (service *Service) UpdateUser(ID database.UserID, user *portainer.User) error { identifier := service.connection.ConvertToKey(int(ID)) user.Username = strings.ToLower(user.Username) return service.connection.UpdateObject(BucketName, identifier, user) @@ -133,7 +133,7 @@ func (service *Service) Create(user *portainer.User) error { return service.connection.CreateObject( BucketName, func(id uint64) (int, interface{}) { - user.ID = portainer.UserID(id) + user.ID = database.UserID(id) user.Username = strings.ToLower(user.Username) return int(user.ID), user @@ -142,7 +142,7 @@ func (service *Service) Create(user *portainer.User) error { } // DeleteUser deletes a user. -func (service *Service) DeleteUser(ID portainer.UserID) error { +func (service *Service) DeleteUser(ID database.UserID) error { identifier := service.connection.ConvertToKey(int(ID)) return service.connection.DeleteObject(BucketName, identifier) } diff --git a/api/datastore/datastore_test.go b/api/datastore/datastore_test.go index 269bcfada..78fa63c23 100644 --- a/api/datastore/datastore_test.go +++ b/api/datastore/datastore_test.go @@ -3,6 +3,7 @@ package datastore import ( "fmt" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "runtime" "strings" "testing" @@ -92,11 +93,11 @@ func newEndpoint(endpointType portainer.EndpointType, id database.EndpointID, na Type: endpointType, GroupID: portainer.EndpointGroupID(1), PublicURL: "", - TLSConfig: portainer.TLSConfiguration{ + TLSConfig: database.TLSConfiguration{ TLS: false, }, - UserAccessPolicies: portainer.UserAccessPolicies{}, - TeamAccessPolicies: portainer.TeamAccessPolicies{}, + UserAccessPolicies: database.UserAccessPolicies{}, + TeamAccessPolicies: database.TeamAccessPolicies{}, TagIDs: []portainer.TagID{}, Status: portainer.EndpointStatusUp, Snapshots: []portainer.DockerSnapshot{}, @@ -104,7 +105,7 @@ func newEndpoint(endpointType portainer.EndpointType, id database.EndpointID, na } if TLS { - endpoint.TLSConfig = portainer.TLSConfiguration{ + endpoint.TLSConfig = database.TLSConfiguration{ TLS: true, TLSSkipVerify: true, } @@ -329,17 +330,17 @@ func (store *Store) testRegistries(t *testing.T) { regService := store.RegistryService is.NotNil(regService, "RegistryService shouldn't be nil") - reg1 := &portainer.Registry{ + reg1 := ®istry.Registry{ ID: 1, Type: portainer.DockerHubRegistry, Name: "Dockerhub Registry Test", } - reg2 := &portainer.Registry{ + reg2 := ®istry.Registry{ ID: 2, Type: portainer.GitlabRegistry, Name: "Gitlab Registry Test", - Gitlab: portainer.GitlabRegistryData{ + Gitlab: registry.GitlabRegistryData{ ProjectID: 12345, InstanceURL: "http://gitlab.com/12345", ProjectPath: "mytestproject", diff --git a/api/datastore/init.go b/api/datastore/init.go index a2a6309b9..45e08f804 100644 --- a/api/datastore/init.go +++ b/api/datastore/init.go @@ -3,6 +3,7 @@ package datastore import ( "github.com/gofrs/uuid" portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/database" ) // Init creates the default data set. @@ -55,7 +56,7 @@ func (store *Store) checkOrCreateDefaultSettings() error { LDAPSettings: portainer.LDAPSettings{ AnonymousMode: true, AutoCreateUsers: true, - TLSConfig: portainer.TLSConfiguration{}, + TLSConfig: database.TLSConfiguration{}, SearchSettings: []portainer.LDAPSearchSettings{ {}, }, @@ -112,8 +113,8 @@ func (store *Store) checkOrCreateDefaultData() error { Name: "Unassigned", Description: "Unassigned environments", Labels: []portainer.Pair{}, - UserAccessPolicies: portainer.UserAccessPolicies{}, - TeamAccessPolicies: portainer.TeamAccessPolicies{}, + UserAccessPolicies: database.UserAccessPolicies{}, + TeamAccessPolicies: database.TeamAccessPolicies{}, TagIDs: []portainer.TagID{}, } diff --git a/api/datastore/migrator/migrate_dbversion17.go b/api/datastore/migrator/migrate_dbversion17.go index 4e17090a8..b9562efd3 100644 --- a/api/datastore/migrator/migrate_dbversion17.go +++ b/api/datastore/migrator/migrate_dbversion17.go @@ -2,6 +2,7 @@ package migrator import ( portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/database" ) func (m *Migrator) updateUsersToDBVersion18() error { @@ -45,16 +46,16 @@ func (m *Migrator) updateEndpointsToDBVersion18() error { } for _, endpoint := range legacyEndpoints { - endpoint.UserAccessPolicies = make(portainer.UserAccessPolicies) + endpoint.UserAccessPolicies = make(database.UserAccessPolicies) for _, userID := range endpoint.AuthorizedUsers { - endpoint.UserAccessPolicies[userID] = portainer.AccessPolicy{ + endpoint.UserAccessPolicies[userID] = database.AccessPolicy{ RoleID: 4, } } - endpoint.TeamAccessPolicies = make(portainer.TeamAccessPolicies) + endpoint.TeamAccessPolicies = make(database.TeamAccessPolicies) for _, teamID := range endpoint.AuthorizedTeams { - endpoint.TeamAccessPolicies[teamID] = portainer.AccessPolicy{ + endpoint.TeamAccessPolicies[teamID] = database.AccessPolicy{ RoleID: 4, } } @@ -75,16 +76,16 @@ func (m *Migrator) updateEndpointGroupsToDBVersion18() error { } for _, endpointGroup := range legacyEndpointGroups { - endpointGroup.UserAccessPolicies = make(portainer.UserAccessPolicies) + endpointGroup.UserAccessPolicies = make(database.UserAccessPolicies) for _, userID := range endpointGroup.AuthorizedUsers { - endpointGroup.UserAccessPolicies[userID] = portainer.AccessPolicy{ + endpointGroup.UserAccessPolicies[userID] = database.AccessPolicy{ RoleID: 4, } } - endpointGroup.TeamAccessPolicies = make(portainer.TeamAccessPolicies) + endpointGroup.TeamAccessPolicies = make(database.TeamAccessPolicies) for _, teamID := range endpointGroup.AuthorizedTeams { - endpointGroup.TeamAccessPolicies[teamID] = portainer.AccessPolicy{ + endpointGroup.TeamAccessPolicies[teamID] = database.AccessPolicy{ RoleID: 4, } } @@ -105,14 +106,14 @@ func (m *Migrator) updateRegistriesToDBVersion18() error { } for _, registry := range legacyRegistries { - registry.UserAccessPolicies = make(portainer.UserAccessPolicies) + registry.UserAccessPolicies = make(database.UserAccessPolicies) for _, userID := range registry.AuthorizedUsers { - registry.UserAccessPolicies[userID] = portainer.AccessPolicy{} + registry.UserAccessPolicies[userID] = database.AccessPolicy{} } - registry.TeamAccessPolicies = make(portainer.TeamAccessPolicies) + registry.TeamAccessPolicies = make(database.TeamAccessPolicies) for _, teamID := range registry.AuthorizedTeams { - registry.TeamAccessPolicies[teamID] = portainer.AccessPolicy{} + registry.TeamAccessPolicies[teamID] = database.AccessPolicy{} } err = m.registryService.UpdateRegistry(registry.ID, ®istry) diff --git a/api/datastore/migrator/migrate_dbversion20.go b/api/datastore/migrator/migrate_dbversion20.go index 23ddd82ab..6b1b08d7f 100644 --- a/api/datastore/migrator/migrate_dbversion20.go +++ b/api/datastore/migrator/migrate_dbversion20.go @@ -1,7 +1,7 @@ package migrator import ( - portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/internal/authorization" ) @@ -42,7 +42,7 @@ func (m *Migrator) updateUsersAndRolesToDBVersion22() error { } } - endpointAdministratorRole, err := m.roleService.Role(portainer.RoleID(1)) + endpointAdministratorRole, err := m.roleService.Role(database.RoleID(1)) if err != nil { return err } @@ -51,7 +51,7 @@ func (m *Migrator) updateUsersAndRolesToDBVersion22() error { err = m.roleService.UpdateRole(endpointAdministratorRole.ID, endpointAdministratorRole) - helpDeskRole, err := m.roleService.Role(portainer.RoleID(2)) + helpDeskRole, err := m.roleService.Role(database.RoleID(2)) if err != nil { return err } @@ -60,7 +60,7 @@ func (m *Migrator) updateUsersAndRolesToDBVersion22() error { err = m.roleService.UpdateRole(helpDeskRole.ID, helpDeskRole) - standardUserRole, err := m.roleService.Role(portainer.RoleID(3)) + standardUserRole, err := m.roleService.Role(database.RoleID(3)) if err != nil { return err } @@ -69,7 +69,7 @@ func (m *Migrator) updateUsersAndRolesToDBVersion22() error { err = m.roleService.UpdateRole(standardUserRole.ID, standardUserRole) - readOnlyUserRole, err := m.roleService.Role(portainer.RoleID(4)) + readOnlyUserRole, err := m.roleService.Role(database.RoleID(4)) if err != nil { return err } diff --git a/api/datastore/migrator/migrate_dbversion31.go b/api/datastore/migrator/migrate_dbversion31.go index d84bd8446..ee29901e2 100644 --- a/api/datastore/migrator/migrate_dbversion31.go +++ b/api/datastore/migrator/migrate_dbversion31.go @@ -2,7 +2,9 @@ package migrator import ( "fmt" + "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/dataservices/errors" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "log" portainer "github.com/portainer/portainer/api" @@ -54,25 +56,25 @@ func (m *Migrator) updateRegistriesToDB32() error { for _, registry := range registries { - registry.RegistryAccesses = portainer.RegistryAccesses{} + registry.RegistryAccesses = registry2.RegistryAccesses{} for _, endpoint := range endpoints { - filteredUserAccessPolicies := portainer.UserAccessPolicies{} + filteredUserAccessPolicies := database.UserAccessPolicies{} for userId, registryPolicy := range registry.UserAccessPolicies { if _, found := endpoint.UserAccessPolicies[userId]; found { filteredUserAccessPolicies[userId] = registryPolicy } } - filteredTeamAccessPolicies := portainer.TeamAccessPolicies{} + filteredTeamAccessPolicies := database.TeamAccessPolicies{} for teamId, registryPolicy := range registry.TeamAccessPolicies { if _, found := endpoint.TeamAccessPolicies[teamId]; found { filteredTeamAccessPolicies[teamId] = registryPolicy } } - registry.RegistryAccesses[endpoint.ID] = portainer.RegistryAccessPolicies{ + registry.RegistryAccesses[endpoint.ID] = registry2.RegistryAccessPolicies{ UserAccessPolicies: filteredUserAccessPolicies, TeamAccessPolicies: filteredTeamAccessPolicies, Namespaces: []string{}, @@ -95,14 +97,14 @@ func (m *Migrator) updateDockerhubToDB32() error { return nil } - registry := &portainer.Registry{ + registry := ®istry2.Registry{ Type: portainer.DockerHubRegistry, Name: "Dockerhub (authenticated - migrated)", URL: "docker.io", Authentication: true, Username: dockerhub.Username, Password: dockerhub.Password, - RegistryAccesses: portainer.RegistryAccesses{}, + RegistryAccesses: registry2.RegistryAccesses{}, } // The following code will make this function idempotent. @@ -122,7 +124,7 @@ func (m *Migrator) updateDockerhubToDB32() error { migrated = true } else { // delete subsequent duplicates - m.registryService.DeleteRegistry(portainer.RegistryID(r.ID)) + m.registryService.DeleteRegistry(registry2.RegistryID(r.ID)) } } } @@ -142,25 +144,25 @@ func (m *Migrator) updateDockerhubToDB32() error { endpoint.Type != portainer.AgentOnKubernetesEnvironment && endpoint.Type != portainer.EdgeAgentOnKubernetesEnvironment { - userAccessPolicies := portainer.UserAccessPolicies{} + userAccessPolicies := database.UserAccessPolicies{} for userId := range endpoint.UserAccessPolicies { if _, found := endpoint.UserAccessPolicies[userId]; found { - userAccessPolicies[userId] = portainer.AccessPolicy{ + userAccessPolicies[userId] = database.AccessPolicy{ RoleID: 0, } } } - teamAccessPolicies := portainer.TeamAccessPolicies{} + teamAccessPolicies := database.TeamAccessPolicies{} for teamId := range endpoint.TeamAccessPolicies { if _, found := endpoint.TeamAccessPolicies[teamId]; found { - teamAccessPolicies[teamId] = portainer.AccessPolicy{ + teamAccessPolicies[teamId] = database.AccessPolicy{ RoleID: 0, } } } - registry.RegistryAccesses[endpoint.ID] = portainer.RegistryAccessPolicies{ + registry.RegistryAccesses[endpoint.ID] = registry2.RegistryAccessPolicies{ UserAccessPolicies: userAccessPolicies, TeamAccessPolicies: teamAccessPolicies, Namespaces: []string{}, diff --git a/api/datastore/services.go b/api/datastore/services.go index 59bfefddb..d8a5fbd12 100644 --- a/api/datastore/services.go +++ b/api/datastore/services.go @@ -356,7 +356,7 @@ type storeExport struct { EndpointRelation []portainer.EndpointRelation `json:"endpoint_relations,omitempty"` Extensions []portainer.Extension `json:"extension,omitempty"` HelmUserRepository []portainer.HelmUserRepository `json:"helm_user_repository,omitempty"` - Registry []portainer.Registry `json:"registries,omitempty"` + Registry []registry.Registry `json:"registries,omitempty"` ResourceControl []portainer.ResourceControl `json:"resource_control,omitempty"` Role []portainer.Role `json:"roles,omitempty"` Schedules []portainer.Schedule `json:"schedules,omitempty"` diff --git a/api/exec/exectest/kubernetes_mocks.go b/api/exec/exectest/kubernetes_mocks.go index cabc4a716..da78c2b61 100644 --- a/api/exec/exectest/kubernetes_mocks.go +++ b/api/exec/exectest/kubernetes_mocks.go @@ -2,6 +2,7 @@ package exectest import ( portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/database" ) type kubernetesMockDeployer struct{} @@ -10,11 +11,11 @@ func NewKubernetesDeployer() portainer.KubernetesDeployer { return &kubernetesMockDeployer{} } -func (deployer *kubernetesMockDeployer) Deploy(userID portainer.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { +func (deployer *kubernetesMockDeployer) Deploy(userID database.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { return "", nil } -func (deployer *kubernetesMockDeployer) Remove(userID portainer.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { +func (deployer *kubernetesMockDeployer) Remove(userID database.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { return "", nil } diff --git a/api/exec/kubernetes_deploy.go b/api/exec/kubernetes_deploy.go index 64e22f035..3b3445941 100644 --- a/api/exec/kubernetes_deploy.go +++ b/api/exec/kubernetes_deploy.go @@ -3,6 +3,7 @@ package exec import ( "bytes" "fmt" + "github.com/portainer/portainer/api/database" "os/exec" "path" "runtime" @@ -42,7 +43,7 @@ func NewKubernetesDeployer(kubernetesTokenCacheManager *kubernetes.TokenCacheMan } } -func (deployer *KubernetesDeployer) getToken(userID portainer.UserID, endpoint *portainer.Endpoint, setLocalAdminToken bool) (string, error) { +func (deployer *KubernetesDeployer) getToken(userID database.UserID, endpoint *portainer.Endpoint, setLocalAdminToken bool) (string, error) { kubeCLI, err := deployer.kubernetesClientFactory.GetKubeClient(endpoint) if err != nil { return "", err @@ -76,16 +77,16 @@ func (deployer *KubernetesDeployer) getToken(userID portainer.UserID, endpoint * } // Deploy upserts Kubernetes resources defined in manifest(s) -func (deployer *KubernetesDeployer) Deploy(userID portainer.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { +func (deployer *KubernetesDeployer) Deploy(userID database.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { return deployer.command("apply", userID, endpoint, manifestFiles, namespace) } // Remove deletes Kubernetes resources defined in manifest(s) -func (deployer *KubernetesDeployer) Remove(userID portainer.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { +func (deployer *KubernetesDeployer) Remove(userID database.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { return deployer.command("delete", userID, endpoint, manifestFiles, namespace) } -func (deployer *KubernetesDeployer) command(operation string, userID portainer.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { +func (deployer *KubernetesDeployer) command(operation string, userID database.UserID, endpoint *portainer.Endpoint, manifestFiles []string, namespace string) (string, error) { token, err := deployer.getToken(userID, endpoint, endpoint.Type == portainer.KubernetesLocalEnvironment) if err != nil { return "", errors.Wrap(err, "failed generating a user token") diff --git a/api/exec/swarm_stack.go b/api/exec/swarm_stack.go index 1c273135b..480a543fa 100644 --- a/api/exec/swarm_stack.go +++ b/api/exec/swarm_stack.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/portainer/portainer/api/dataservices/registry" "os" "os/exec" "path" @@ -54,7 +55,7 @@ func NewSwarmStackManager( } // Login executes the docker login command against a list of registries (including DockerHub). -func (manager *SwarmStackManager) Login(registries []portainer.Registry, endpoint *portainer.Endpoint) error { +func (manager *SwarmStackManager) Login(registries []registry.Registry, endpoint *portainer.Endpoint) error { command, args, err := manager.prepareDockerCommandAndArgs(manager.binaryPath, manager.configPath, endpoint) if err != nil { return err diff --git a/api/http/handler/auth/authenticate.go b/api/http/handler/auth/authenticate.go index 37c895b44..b39686021 100644 --- a/api/http/handler/auth/authenticate.go +++ b/api/http/handler/auth/authenticate.go @@ -2,6 +2,7 @@ package auth import ( "errors" + "github.com/portainer/portainer/api/database" "log" "net/http" "strings" @@ -197,7 +198,7 @@ func teamExists(teamName string, ldapGroups []string) bool { return false } -func teamMembershipExists(teamID portainer.TeamID, memberships []portainer.TeamMembership) bool { +func teamMembershipExists(teamID database.TeamID, memberships []portainer.TeamMembership) bool { for _, membership := range memberships { if membership.TeamID == teamID { return true diff --git a/api/http/handler/customtemplates/customtemplate_list.go b/api/http/handler/customtemplates/customtemplate_list.go index 63d1ab05f..8405c4445 100644 --- a/api/http/handler/customtemplates/customtemplate_list.go +++ b/api/http/handler/customtemplates/customtemplate_list.go @@ -1,6 +1,7 @@ package customtemplates import ( + "github.com/portainer/portainer/api/database" "net/http" "strconv" @@ -53,7 +54,7 @@ func (handler *Handler) customTemplateList(w http.ResponseWriter, r *http.Reques return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user information from the database", err} } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range securityContext.UserMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } diff --git a/api/http/handler/customtemplates/handler.go b/api/http/handler/customtemplates/handler.go index 7bc9b4b3d..129aeec20 100644 --- a/api/http/handler/customtemplates/handler.go +++ b/api/http/handler/customtemplates/handler.go @@ -1,6 +1,7 @@ package customtemplates import ( + "github.com/portainer/portainer/api/database" "net/http" "github.com/gorilla/mux" @@ -48,7 +49,7 @@ func userCanAccessTemplate(customTemplate portainer.CustomTemplate, securityCont return true } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range securityContext.UserMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } diff --git a/api/http/handler/endpointgroups/endpointgroup_create.go b/api/http/handler/endpointgroups/endpointgroup_create.go index f6917bd68..46c9c0610 100644 --- a/api/http/handler/endpointgroups/endpointgroup_create.go +++ b/api/http/handler/endpointgroups/endpointgroup_create.go @@ -56,8 +56,8 @@ func (handler *Handler) endpointGroupCreate(w http.ResponseWriter, r *http.Reque endpointGroup := &portainer.EndpointGroup{ Name: payload.Name, Description: payload.Description, - UserAccessPolicies: portainer.UserAccessPolicies{}, - TeamAccessPolicies: portainer.TeamAccessPolicies{}, + UserAccessPolicies: database.UserAccessPolicies{}, + TeamAccessPolicies: database.TeamAccessPolicies{}, TagIDs: payload.TagIDs, } diff --git a/api/http/handler/endpointgroups/endpointgroup_update.go b/api/http/handler/endpointgroups/endpointgroup_update.go index d9c83752d..0aaf4ae5b 100644 --- a/api/http/handler/endpointgroups/endpointgroup_update.go +++ b/api/http/handler/endpointgroups/endpointgroup_update.go @@ -1,6 +1,7 @@ package endpointgroups import ( + "github.com/portainer/portainer/api/database" "net/http" "reflect" @@ -18,8 +19,8 @@ type endpointGroupUpdatePayload struct { Description string `example:"description"` // List of tag identifiers associated to the environment(endpoint) group TagIDs []portainer.TagID `example:"3,4"` - UserAccessPolicies portainer.UserAccessPolicies - TeamAccessPolicies portainer.TeamAccessPolicies + UserAccessPolicies database.UserAccessPolicies + TeamAccessPolicies database.TeamAccessPolicies } func (payload *endpointGroupUpdatePayload) Validate(r *http.Request) error { diff --git a/api/http/handler/endpoints/endpoint_create.go b/api/http/handler/endpoints/endpoint_create.go index e01dbf86f..ab4c409ed 100644 --- a/api/http/handler/endpoints/endpoint_create.go +++ b/api/http/handler/endpoints/endpoint_create.go @@ -3,6 +3,7 @@ package endpoints import ( "errors" "fmt" + "github.com/portainer/portainer/api/database" "net" "net/http" "net/url" @@ -313,7 +314,7 @@ func (handler *Handler) createEdgeAgentEndpoint(payload *endpointCreatePayload) endpoint.Type = portainer.EdgeAgentOnDockerEnvironment endpoint.PublicURL = payload.PublicURL endpoint.TagIDs = payload.TagIDs - endpoint.TLSConfig = portainer.TLSConfiguration{ + endpoint.TLSConfig = database.TLSConfiguration{ TLS: false, } endpoint.IsEdgeDevice = payload.IsEdgeDevice @@ -362,7 +363,7 @@ func (handler *Handler) createUnsecuredEndpoint(payload *endpointCreatePayload) endpoint.Type = portainer.DockerEnvironment endpoint.PublicURL = payload.PublicURL endpoint.TagIDs = payload.TagIDs - endpoint.TLSConfig = portainer.TLSConfiguration{ + endpoint.TLSConfig = database.TLSConfiguration{ TLS: false, } endpoint.IsEdgeDevice = payload.IsEdgeDevice @@ -387,7 +388,7 @@ func (handler *Handler) createKubernetesEndpoint(payload *endpointCreatePayload) endpoint.Type = portainer.KubernetesLocalEnvironment endpoint.PublicURL = payload.PublicURL endpoint.TagIDs = payload.TagIDs - endpoint.TLSConfig = portainer.TLSConfiguration{ + endpoint.TLSConfig = database.TLSConfiguration{ TLS: payload.TLS, TLSSkipVerify: payload.TLSSkipVerify, } @@ -409,7 +410,7 @@ func (handler *Handler) createTLSSecuredEndpoint(payload *endpointCreatePayload, endpoint.Type = endpointType endpoint.PublicURL = payload.PublicURL endpoint.TagIDs = payload.TagIDs - endpoint.TLSConfig = portainer.TLSConfiguration{ + endpoint.TLSConfig = database.TLSConfiguration{ TLS: payload.TLS, TLSSkipVerify: payload.TLSSkipVerify, } diff --git a/api/http/handler/endpoints/endpoint_dockerhub_status.go b/api/http/handler/endpoints/endpoint_dockerhub_status.go index d22ae7f6e..88339c4e6 100644 --- a/api/http/handler/endpoints/endpoint_dockerhub_status.go +++ b/api/http/handler/endpoints/endpoint_dockerhub_status.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "github.com/portainer/portainer/api/database" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" "strconv" "strings" @@ -62,12 +63,12 @@ func (handler *Handler) endpointDockerhubStatus(w http.ResponseWriter, r *http.R return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry identifier route variable", err} } - var registry *portainer.Registry + var registry *registry2.Registry if registryID == 0 { - registry = &portainer.Registry{} + registry = ®istry2.Registry{} } else { - registry, err = handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err = handler.DataStore.Registry().Registry(registry2.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a registry with the specified identifier inside the database", err} } else if err != nil { @@ -93,7 +94,7 @@ func (handler *Handler) endpointDockerhubStatus(w http.ResponseWriter, r *http.R return response.JSON(w, resp) } -func getDockerHubToken(httpClient *client.HTTPClient, registry *portainer.Registry) (string, error) { +func getDockerHubToken(httpClient *client.HTTPClient, registry *registry2.Registry) (string, error) { type dockerhubTokenResponse struct { Token string `json:"token"` } diff --git a/api/http/handler/endpoints/endpoint_registries_inspect.go b/api/http/handler/endpoints/endpoint_registries_inspect.go index 5fc4b0e4e..0f1e538de 100644 --- a/api/http/handler/endpoints/endpoint_registries_inspect.go +++ b/api/http/handler/endpoints/endpoint_registries_inspect.go @@ -2,12 +2,12 @@ package endpoints import ( "github.com/portainer/portainer/api/database" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" httperrors "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" ) @@ -38,7 +38,7 @@ func (handler *Handler) endpointRegistryInspect(w http.ResponseWriter, r *http.R return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid registry identifier route variable", Err: err} } - registry, err := handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err := handler.DataStore.Registry().Registry(registry2.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{StatusCode: http.StatusNotFound, Message: "Unable to find a registry with the specified identifier inside the database", Err: err} } else if err != nil { diff --git a/api/http/handler/endpoints/endpoint_registries_list.go b/api/http/handler/endpoints/endpoint_registries_list.go index 4dc68e45e..a1b80c6ec 100644 --- a/api/http/handler/endpoints/endpoint_registries_list.go +++ b/api/http/handler/endpoints/endpoint_registries_list.go @@ -2,6 +2,7 @@ package endpoints import ( "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "net/http" "github.com/pkg/errors" @@ -88,7 +89,7 @@ func (handler *Handler) endpointRegistriesList(w http.ResponseWriter, r *http.Re return response.JSON(w, registries) } -func (handler *Handler) isNamespaceAuthorized(endpoint *portainer.Endpoint, namespace string, userId portainer.UserID, memberships []portainer.TeamMembership, isAdmin bool) (bool, error) { +func (handler *Handler) isNamespaceAuthorized(endpoint *portainer.Endpoint, namespace string, userId database.UserID, memberships []portainer.TeamMembership, isAdmin bool) (bool, error) { if isAdmin || namespace == "" { return true, nil } @@ -115,12 +116,12 @@ func (handler *Handler) isNamespaceAuthorized(endpoint *portainer.Endpoint, name return security.AuthorizedAccess(userId, memberships, namespacePolicy.UserAccessPolicies, namespacePolicy.TeamAccessPolicies), nil } -func filterRegistriesByNamespace(registries []portainer.Registry, endpointId database.EndpointID, namespace string) []portainer.Registry { +func filterRegistriesByNamespace(registries []registry.Registry, endpointId database.EndpointID, namespace string) []registry.Registry { if namespace == "" { return registries } - filteredRegistries := []portainer.Registry{} + filteredRegistries := []registry.Registry{} for _, registry := range registries { for _, authorizedNamespace := range registry.RegistryAccesses[endpointId].Namespaces { @@ -133,7 +134,7 @@ func filterRegistriesByNamespace(registries []portainer.Registry, endpointId dat return filteredRegistries } -func hideRegistryFields(registry *portainer.Registry, hideAccesses bool) { +func hideRegistryFields(registry *registry.Registry, hideAccesses bool) { registry.Password = "" registry.ManagementConfiguration = nil if hideAccesses { diff --git a/api/http/handler/endpoints/endpoint_registry_access.go b/api/http/handler/endpoints/endpoint_registry_access.go index 9004066b5..25d5e4c6e 100644 --- a/api/http/handler/endpoints/endpoint_registry_access.go +++ b/api/http/handler/endpoints/endpoint_registry_access.go @@ -2,6 +2,7 @@ package endpoints import ( "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "net/http" httperror "github.com/portainer/libhttp/error" @@ -12,8 +13,8 @@ import ( ) type registryAccessPayload struct { - UserAccessPolicies portainer.UserAccessPolicies - TeamAccessPolicies portainer.TeamAccessPolicies + UserAccessPolicies database.UserAccessPolicies + TeamAccessPolicies database.TeamAccessPolicies Namespaces []string } @@ -70,7 +71,7 @@ func (handler *Handler) endpointRegistryAccess(w http.ResponseWriter, r *http.Re return &httperror.HandlerError{StatusCode: http.StatusForbidden, Message: "User is not authorized", Err: err} } - registry, err := handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + thisRegistry, err := handler.DataStore.Registry().Registry(registry.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{StatusCode: http.StatusNotFound, Message: "Unable to find an environment with the specified identifier inside the database", Err: err} } else if err != nil { @@ -83,18 +84,18 @@ func (handler *Handler) endpointRegistryAccess(w http.ResponseWriter, r *http.Re return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid request payload", Err: err} } - if registry.RegistryAccesses == nil { - registry.RegistryAccesses = portainer.RegistryAccesses{} + if thisRegistry.RegistryAccesses == nil { + thisRegistry.RegistryAccesses = registry.RegistryAccesses{} } - if _, ok := registry.RegistryAccesses[endpoint.ID]; !ok { - registry.RegistryAccesses[endpoint.ID] = portainer.RegistryAccessPolicies{} + if _, ok := thisRegistry.RegistryAccesses[endpoint.ID]; !ok { + thisRegistry.RegistryAccesses[endpoint.ID] = registry.RegistryAccessPolicies{} } - registryAccess := registry.RegistryAccesses[endpoint.ID] + registryAccess := thisRegistry.RegistryAccesses[endpoint.ID] if endpoint.Type == portainer.KubernetesLocalEnvironment || endpoint.Type == portainer.AgentOnKubernetesEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment { - err := handler.updateKubeAccess(endpoint, registry, registryAccess.Namespaces, payload.Namespaces) + err := handler.updateKubeAccess(endpoint, thisRegistry, registryAccess.Namespaces, payload.Namespaces) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: "Unable to update kube access policies", Err: err} } @@ -105,14 +106,14 @@ func (handler *Handler) endpointRegistryAccess(w http.ResponseWriter, r *http.Re registryAccess.TeamAccessPolicies = payload.TeamAccessPolicies } - registry.RegistryAccesses[database.EndpointID(endpointID)] = registryAccess + thisRegistry.RegistryAccesses[database.EndpointID(endpointID)] = registryAccess - handler.DataStore.Registry().UpdateRegistry(registry.ID, registry) + handler.DataStore.Registry().UpdateRegistry(thisRegistry.ID, thisRegistry) return response.Empty(w) } -func (handler *Handler) updateKubeAccess(endpoint *portainer.Endpoint, registry *portainer.Registry, oldNamespaces, newNamespaces []string) error { +func (handler *Handler) updateKubeAccess(endpoint *portainer.Endpoint, registry *registry.Registry, oldNamespaces, newNamespaces []string) error { oldNamespacesSet := toSet(oldNamespaces) newNamespacesSet := toSet(newNamespaces) diff --git a/api/http/handler/endpoints/endpoint_update.go b/api/http/handler/endpoints/endpoint_update.go index 044b348fc..4eff614c2 100644 --- a/api/http/handler/endpoints/endpoint_update.go +++ b/api/http/handler/endpoints/endpoint_update.go @@ -41,8 +41,8 @@ type endpointUpdatePayload struct { AzureAuthenticationKey *string `example:"cOrXoK/1D35w8YQ8nH1/8ZGwzz45JIYD5jxHKXEQknk="` // List of tag identifiers to which this environment(endpoint) is associated TagIDs []portainer.TagID `example:"1,2"` - UserAccessPolicies portainer.UserAccessPolicies - TeamAccessPolicies portainer.TeamAccessPolicies + UserAccessPolicies database.UserAccessPolicies + TeamAccessPolicies database.TeamAccessPolicies // The check in interval for edge agent (in seconds) EdgeCheckinInterval *int `example:"5"` // Associated Kubernetes data diff --git a/api/http/handler/helm/user_helm_repos.go b/api/http/handler/helm/user_helm_repos.go index 6f8e5b204..11048565c 100644 --- a/api/http/handler/helm/user_helm_repos.go +++ b/api/http/handler/helm/user_helm_repos.go @@ -1,6 +1,7 @@ package helm import ( + "github.com/portainer/portainer/api/database" "net/http" "strings" @@ -49,7 +50,7 @@ func (handler *Handler) userCreateHelmRepo(w http.ResponseWriter, r *http.Reques if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - userID := portainer.UserID(tokenData.ID) + userID := database.UserID(tokenData.ID) p := new(addHelmRepoUrlPayload) err = request.DecodeAndValidateJSONPayload(r, p) @@ -108,7 +109,7 @@ func (handler *Handler) userGetHelmRepos(w http.ResponseWriter, r *http.Request) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - userID := portainer.UserID(tokenData.ID) + userID := database.UserID(tokenData.ID) settings, err := handler.dataStore.Settings().Settings() if err != nil { diff --git a/api/http/handler/registries/handler.go b/api/http/handler/registries/handler.go index cfa414049..76e6f3245 100644 --- a/api/http/handler/registries/handler.go +++ b/api/http/handler/registries/handler.go @@ -1,6 +1,7 @@ package registries import ( + "github.com/portainer/portainer/api/dataservices/registry" "net/http" "github.com/gorilla/mux" @@ -12,7 +13,7 @@ import ( "github.com/portainer/portainer/api/kubernetes/cli" ) -func hideFields(registry *portainer.Registry, hideAccesses bool) { +func hideFields(registry *registry.Registry, hideAccesses bool) { registry.Password = "" registry.ManagementConfiguration = nil if hideAccesses { @@ -68,7 +69,7 @@ type accessGuard interface { AuthenticatedAccess(h http.Handler) http.Handler } -func (handler *Handler) registriesHaveSameURLAndCredentials(r1, r2 *portainer.Registry) bool { +func (handler *Handler) registriesHaveSameURLAndCredentials(r1, r2 *registry.Registry) bool { hasSameUrl := r1.URL == r2.URL hasSameCredentials := r1.Authentication == r2.Authentication && (!r1.Authentication || (r1.Authentication && r1.Username == r2.Username)) diff --git a/api/http/handler/registries/registry_configure.go b/api/http/handler/registries/registry_configure.go index 0c56e267d..2a4adbc4f 100644 --- a/api/http/handler/registries/registry_configure.go +++ b/api/http/handler/registries/registry_configure.go @@ -2,13 +2,14 @@ package registries import ( "errors" + "github.com/portainer/portainer/api/database" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" "strconv" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" httperrors "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" ) @@ -118,14 +119,14 @@ func (handler *Handler) registryConfigure(w http.ResponseWriter, r *http.Request return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry identifier route variable", err} } - registry, err := handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err := handler.DataStore.Registry().Registry(registry2.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a registry with the specified identifier inside the database", err} } else if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a registry with the specified identifier inside the database", err} } - registry.ManagementConfiguration = &portainer.RegistryManagementConfiguration{ + registry.ManagementConfiguration = ®istry2.RegistryManagementConfiguration{ Type: registry.Type, } @@ -144,7 +145,7 @@ func (handler *Handler) registryConfigure(w http.ResponseWriter, r *http.Request } if payload.TLS { - registry.ManagementConfiguration.TLSConfig = portainer.TLSConfiguration{ + registry.ManagementConfiguration.TLSConfig = database.TLSConfiguration{ TLS: true, TLSSkipVerify: payload.TLSSkipVerify, } diff --git a/api/http/handler/registries/registry_create.go b/api/http/handler/registries/registry_create.go index 724b33aff..dbb2a14bb 100644 --- a/api/http/handler/registries/registry_create.go +++ b/api/http/handler/registries/registry_create.go @@ -3,6 +3,7 @@ package registries import ( "errors" "fmt" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" "github.com/asaskevich/govalidator" @@ -25,7 +26,7 @@ type registryCreatePayload struct { // 5 (ProGet registry), // 6 (DockerHub) // 7 (ECR) - Type portainer.RegistryType `example:"1" validate:"required" enums:"1,2,3,4,5,6,7"` + Type registry2.RegistryType `example:"1" validate:"required" enums:"1,2,3,4,5,6,7"` // URL or IP address of the Docker registry URL string `example:"registry.mydomain.tld:2375/feed" validate:"required"` // BaseURL required for ProGet registry @@ -37,11 +38,11 @@ type registryCreatePayload struct { // Password used to authenticate against this registry. required when Authentication is true Password string `example:"registry_password"` // Gitlab specific details, required when type = 4 - Gitlab portainer.GitlabRegistryData + Gitlab registry2.GitlabRegistryData // Quay specific details, required when type = 1 - Quay portainer.QuayRegistryData + Quay registry2.QuayRegistryData // ECR specific details, required when type = 7 - Ecr portainer.EcrData + Ecr registry2.EcrData } func (payload *registryCreatePayload) Validate(_ *http.Request) error { @@ -105,8 +106,8 @@ func (handler *Handler) registryCreate(w http.ResponseWriter, r *http.Request) * return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err} } - registry := &portainer.Registry{ - Type: portainer.RegistryType(payload.Type), + registry := ®istry2.Registry{ + Type: registry2.RegistryType(payload.Type), Name: payload.Name, URL: payload.URL, BaseURL: payload.BaseURL, @@ -115,7 +116,7 @@ func (handler *Handler) registryCreate(w http.ResponseWriter, r *http.Request) * Password: payload.Password, Gitlab: payload.Gitlab, Quay: payload.Quay, - RegistryAccesses: portainer.RegistryAccesses{}, + RegistryAccesses: registry2.RegistryAccesses{}, Ecr: payload.Ecr, } diff --git a/api/http/handler/registries/registry_create_test.go b/api/http/handler/registries/registry_create_test.go index 711a6ef36..caa01f3c6 100644 --- a/api/http/handler/registries/registry_create_test.go +++ b/api/http/handler/registries/registry_create_test.go @@ -3,6 +3,8 @@ package registries import ( "bytes" "encoding/json" + "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "net/http" "net/http/httptest" "testing" @@ -52,9 +54,9 @@ func Test_registryCreatePayload_Validate(t *testing.T) { type testRegistryService struct { dataservices.RegistryService - createRegistry func(r *portainer.Registry) error - updateRegistry func(ID portainer.RegistryID, r *portainer.Registry) error - getRegistry func(ID portainer.RegistryID) (*portainer.Registry, error) + createRegistry func(r *registry.Registry) error + updateRegistry func(ID registry.RegistryID, r *registry.Registry) error + getRegistry func(ID registry.RegistryID) (*registry.Registry, error) } type testDataStore struct { @@ -66,23 +68,23 @@ func (t testDataStore) Registry() dataservices.RegistryService { return t.registry } -func (t testRegistryService) CreateRegistry(r *portainer.Registry) error { +func (t testRegistryService) CreateRegistry(r *registry.Registry) error { return t.createRegistry(r) } -func (t testRegistryService) UpdateRegistry(ID portainer.RegistryID, r *portainer.Registry) error { +func (t testRegistryService) UpdateRegistry(ID registry.RegistryID, r *registry.Registry) error { return t.updateRegistry(ID, r) } -func (t testRegistryService) Registry(ID portainer.RegistryID) (*portainer.Registry, error) { +func (t testRegistryService) Registry(ID registry.RegistryID) (*registry.Registry, error) { return t.getRegistry(ID) } -func (t testRegistryService) Registries() ([]portainer.Registry, error) { +func (t testRegistryService) Registries() ([]registry.Registry, error) { return nil, nil } -func (t testRegistryService) Create(registry *portainer.Registry) error { +func (t testRegistryService) Create(registry *registry.Registry) error { return nil } @@ -96,7 +98,7 @@ func deleteTestHandler_registryCreate(t *testing.T) { Authentication: false, Username: "username", Password: "password", - Gitlab: portainer.GitlabRegistryData{}, + Gitlab: registry.GitlabRegistryData{}, } payloadBytes, err := json.Marshal(payload) assert.NoError(t, err) @@ -105,17 +107,17 @@ func deleteTestHandler_registryCreate(t *testing.T) { restrictedContext := &security.RestrictedRequestContext{ IsAdmin: true, - UserID: portainer.UserID(1), + UserID: database.UserID(1), } ctx := security.StoreRestrictedRequestContext(r, restrictedContext) r = r.WithContext(ctx) - registry := portainer.Registry{} + registry := registry.Registry{} handler := Handler{} handler.DataStore = testDataStore{ registry: &testRegistryService{ - createRegistry: func(r *portainer.Registry) error { + createRegistry: func(r *registry.Registry) error { registry = *r return nil }, diff --git a/api/http/handler/registries/registry_delete.go b/api/http/handler/registries/registry_delete.go index e2e3d4f64..10b8af912 100644 --- a/api/http/handler/registries/registry_delete.go +++ b/api/http/handler/registries/registry_delete.go @@ -1,12 +1,12 @@ package registries import ( + "github.com/portainer/portainer/api/dataservices/registry" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" httperrors "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" ) @@ -38,14 +38,14 @@ func (handler *Handler) registryDelete(w http.ResponseWriter, r *http.Request) * return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry identifier route variable", err} } - _, err = handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + _, err = handler.DataStore.Registry().Registry(registry.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a registry with the specified identifier inside the database", err} } else if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a registry with the specified identifier inside the database", err} } - err = handler.DataStore.Registry().DeleteRegistry(portainer.RegistryID(registryID)) + err = handler.DataStore.Registry().DeleteRegistry(registry.RegistryID(registryID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to remove the registry from the database", err} } diff --git a/api/http/handler/registries/registry_inspect.go b/api/http/handler/registries/registry_inspect.go index 99ba68ec7..be9552e8c 100644 --- a/api/http/handler/registries/registry_inspect.go +++ b/api/http/handler/registries/registry_inspect.go @@ -1,10 +1,9 @@ package registries import ( + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" - portainer "github.com/portainer/portainer/api" - httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" @@ -32,7 +31,7 @@ func (handler *Handler) registryInspect(w http.ResponseWriter, r *http.Request) return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry identifier route variable", err} } - registry, err := handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err := handler.DataStore.Registry().Registry(registry2.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a registry with the specified identifier inside the database", err} } else if err != nil { diff --git a/api/http/handler/registries/registry_update.go b/api/http/handler/registries/registry_update.go index cf0a6a51a..119e3b370 100644 --- a/api/http/handler/registries/registry_update.go +++ b/api/http/handler/registries/registry_update.go @@ -2,6 +2,7 @@ package registries import ( "errors" + "github.com/portainer/portainer/api/dataservices/registry" "github.com/portainer/portainer/api/internal/endpointutils" "net/http" @@ -27,11 +28,11 @@ type registryUpdatePayload struct { // Password used to authenticate against this registry. required when Authentication is true Password *string `example:"registry_password"` // Quay data - Quay *portainer.QuayRegistryData + Quay *registry.QuayRegistryData // Registry access control - RegistryAccesses *portainer.RegistryAccesses `json:",omitempty"` + RegistryAccesses *registry.RegistryAccesses `json:",omitempty"` // ECR data - Ecr *portainer.EcrData `json:",omitempty"` + Ecr *registry.EcrData `json:",omitempty"` } func (payload *registryUpdatePayload) Validate(r *http.Request) error { @@ -70,7 +71,7 @@ func (handler *Handler) registryUpdate(w http.ResponseWriter, r *http.Request) * return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry identifier route variable", err} } - registry, err := handler.DataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err := handler.DataStore.Registry().Registry(registry.RegistryID(registryID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a registry with the specified identifier inside the database", err} } else if err != nil { @@ -172,7 +173,7 @@ func (handler *Handler) registryUpdate(w http.ResponseWriter, r *http.Request) * return response.JSON(w, registry) } -func (handler *Handler) updateEndpointRegistryAccess(endpoint *portainer.Endpoint, registry *portainer.Registry, endpointAccess portainer.RegistryAccessPolicies) error { +func (handler *Handler) updateEndpointRegistryAccess(endpoint *portainer.Endpoint, registry *registry.Registry, endpointAccess registry.RegistryAccessPolicies) error { cli, err := handler.K8sClientFactory.GetKubeClient(endpoint) if err != nil { diff --git a/api/http/handler/registries/registry_update_test.go b/api/http/handler/registries/registry_update_test.go index 73bf65d64..fc58a8e01 100644 --- a/api/http/handler/registries/registry_update_test.go +++ b/api/http/handler/registries/registry_update_test.go @@ -3,6 +3,8 @@ package registries import ( "bytes" "encoding/json" + "github.com/portainer/portainer/api/database" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" "net/http/httptest" "testing" @@ -46,27 +48,27 @@ func delete_TestHandler_registryUpdate(t *testing.T) { } payloadBytes, err := json.Marshal(payload) assert.NoError(t, err) - registry := portainer.Registry{Type: portainer.ProGetRegistry, ID: 5} + registry := registry2.Registry{Type: portainer.ProGetRegistry, ID: 5} r := httptest.NewRequest(http.MethodPut, "/registries/5", bytes.NewReader(payloadBytes)) w := httptest.NewRecorder() restrictedContext := &security.RestrictedRequestContext{ IsAdmin: true, - UserID: portainer.UserID(1), + UserID: database.UserID(1), } ctx := security.StoreRestrictedRequestContext(r, restrictedContext) r = r.WithContext(ctx) - updatedRegistry := portainer.Registry{} + updatedRegistry := registry2.Registry{} handler := newHandler(nil) handler.initRouter(TestBouncer{}) handler.DataStore = testDataStore{ registry: &testRegistryService{ - getRegistry: func(_ portainer.RegistryID) (*portainer.Registry, error) { + getRegistry: func(_ registry2.RegistryID) (*registry2.Registry, error) { return ®istry, nil }, - updateRegistry: func(ID portainer.RegistryID, r *portainer.Registry) error { + updateRegistry: func(ID registry2.RegistryID, r *registry2.Registry) error { assert.Equal(t, ID, r.ID) updatedRegistry = *r return nil diff --git a/api/http/handler/resourcecontrols/resourcecontrol_create.go b/api/http/handler/resourcecontrols/resourcecontrol_create.go index e72d064c6..a6728898c 100644 --- a/api/http/handler/resourcecontrols/resourcecontrol_create.go +++ b/api/http/handler/resourcecontrols/resourcecontrol_create.go @@ -2,6 +2,7 @@ package resourcecontrols import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" "github.com/asaskevich/govalidator" @@ -108,7 +109,7 @@ func (handler *Handler) resourceControlCreate(w http.ResponseWriter, r *http.Req var userAccesses = make([]portainer.UserResourceAccess, 0) for _, v := range payload.Users { userAccess := portainer.UserResourceAccess{ - UserID: portainer.UserID(v), + UserID: database.UserID(v), AccessLevel: portainer.ReadWriteAccessLevel, } userAccesses = append(userAccesses, userAccess) @@ -117,7 +118,7 @@ func (handler *Handler) resourceControlCreate(w http.ResponseWriter, r *http.Req var teamAccesses = make([]portainer.TeamResourceAccess, 0) for _, v := range payload.Teams { teamAccess := portainer.TeamResourceAccess{ - TeamID: portainer.TeamID(v), + TeamID: database.TeamID(v), AccessLevel: portainer.ReadWriteAccessLevel, } teamAccesses = append(teamAccesses, teamAccess) diff --git a/api/http/handler/resourcecontrols/resourcecontrol_update.go b/api/http/handler/resourcecontrols/resourcecontrol_update.go index 6620ef512..8d45f869a 100644 --- a/api/http/handler/resourcecontrols/resourcecontrol_update.go +++ b/api/http/handler/resourcecontrols/resourcecontrol_update.go @@ -2,6 +2,7 @@ package resourcecontrols import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -85,7 +86,7 @@ func (handler *Handler) resourceControlUpdate(w http.ResponseWriter, r *http.Req var userAccesses = make([]portainer.UserResourceAccess, 0) for _, v := range payload.Users { userAccess := portainer.UserResourceAccess{ - UserID: portainer.UserID(v), + UserID: database.UserID(v), AccessLevel: portainer.ReadWriteAccessLevel, } userAccesses = append(userAccesses, userAccess) @@ -95,7 +96,7 @@ func (handler *Handler) resourceControlUpdate(w http.ResponseWriter, r *http.Req var teamAccesses = make([]portainer.TeamResourceAccess, 0) for _, v := range payload.Teams { teamAccess := portainer.TeamResourceAccess{ - TeamID: portainer.TeamID(v), + TeamID: database.TeamID(v), AccessLevel: portainer.ReadWriteAccessLevel, } teamAccesses = append(teamAccesses, teamAccess) diff --git a/api/http/handler/stacks/create_compose_stack.go b/api/http/handler/stacks/create_compose_stack.go index a90486fa6..33a360ab8 100644 --- a/api/http/handler/stacks/create_compose_stack.go +++ b/api/http/handler/stacks/create_compose_stack.go @@ -2,6 +2,8 @@ package stacks import ( "fmt" + "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "log" "net/http" "strconv" @@ -39,7 +41,7 @@ func (payload *composeStackFromFileContentPayload) Validate(r *http.Request) err } return nil } -func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID, stack *portainer.Stack) error { +func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID, stack *portainer.Stack) error { resourceControl, err := handler.DataStore.ResourceControl().ResourceControlByResourceIDAndType(stackutils.ResourceControlID(stack.EndpointID, stack.Name), portainer.StackResourceControl) if err != nil { return err @@ -70,7 +72,7 @@ func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r return nil } -func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload composeStackFromFileContentPayload err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { @@ -189,7 +191,7 @@ func (payload *composeStackFromGitRepositoryPayload) Validate(r *http.Request) e return nil } -func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload composeStackFromGitRepositoryPayload err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { @@ -337,7 +339,7 @@ func decodeRequestForm(r *http.Request) (*composeStackFromFileUploadPayload, err return payload, nil } -func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { payload, err := decodeRequestForm(r) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid request payload", Err: err} @@ -413,7 +415,7 @@ func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter, type composeStackDeploymentConfig struct { stack *portainer.Stack endpoint *portainer.Endpoint - registries []portainer.Registry + registries []registry.Registry isAdmin bool user *portainer.User } diff --git a/api/http/handler/stacks/create_kubernetes_stack.go b/api/http/handler/stacks/create_kubernetes_stack.go index 01e4f63c5..82d523ee7 100644 --- a/api/http/handler/stacks/create_kubernetes_stack.go +++ b/api/http/handler/stacks/create_kubernetes_stack.go @@ -2,6 +2,7 @@ package stacks import ( "fmt" + "github.com/portainer/portainer/api/database" "net/http" "os" "strconv" @@ -96,7 +97,7 @@ type createKubernetesStackResponse struct { Output string `json:"Output"` } -func (handler *Handler) createKubernetesStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createKubernetesStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload kubernetesStringDeploymentPayload if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil { return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid request payload", Err: err} @@ -167,7 +168,7 @@ func (handler *Handler) createKubernetesStackFromFileContent(w http.ResponseWrit return response.JSON(w, resp) } -func (handler *Handler) createKubernetesStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createKubernetesStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload kubernetesGitDeploymentPayload if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil { return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid request payload", Err: err} @@ -281,7 +282,7 @@ func (handler *Handler) createKubernetesStackFromGitRepository(w http.ResponseWr return response.JSON(w, resp) } -func (handler *Handler) createKubernetesStackFromManifestURL(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createKubernetesStackFromManifestURL(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload kubernetesManifestURLDeploymentPayload if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil { return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid request payload", Err: err} @@ -353,7 +354,7 @@ func (handler *Handler) createKubernetesStackFromManifestURL(w http.ResponseWrit return response.JSON(w, resp) } -func (handler *Handler) deployKubernetesStack(userID portainer.UserID, endpoint *portainer.Endpoint, stack *portainer.Stack, appLabels k.KubeAppLabels) (string, error) { +func (handler *Handler) deployKubernetesStack(userID database.UserID, endpoint *portainer.Endpoint, stack *portainer.Stack, appLabels k.KubeAppLabels) (string, error) { handler.stackCreationMutex.Lock() defer handler.stackCreationMutex.Unlock() diff --git a/api/http/handler/stacks/create_swarm_stack.go b/api/http/handler/stacks/create_swarm_stack.go index e3563f467..e550388a8 100644 --- a/api/http/handler/stacks/create_swarm_stack.go +++ b/api/http/handler/stacks/create_swarm_stack.go @@ -2,6 +2,8 @@ package stacks import ( "fmt" + "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "net/http" "strconv" "time" @@ -43,7 +45,7 @@ func (payload *swarmStackFromFileContentPayload) Validate(r *http.Request) error return nil } -func (handler *Handler) createSwarmStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createSwarmStackFromFileContent(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload swarmStackFromFileContentPayload err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { @@ -156,7 +158,7 @@ func (payload *swarmStackFromGitRepositoryPayload) Validate(r *http.Request) err return nil } -func (handler *Handler) createSwarmStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createSwarmStackFromGitRepository(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { var payload swarmStackFromGitRepositoryPayload err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { @@ -294,7 +296,7 @@ func (payload *swarmStackFromFileUploadPayload) Validate(r *http.Request) error return nil } -func (handler *Handler) createSwarmStackFromFileUpload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createSwarmStackFromFileUpload(w http.ResponseWriter, r *http.Request, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { payload := &swarmStackFromFileUploadPayload{} err := payload.Validate(r) if err != nil { @@ -359,7 +361,7 @@ func (handler *Handler) createSwarmStackFromFileUpload(w http.ResponseWriter, r type swarmStackDeploymentConfig struct { stack *portainer.Stack endpoint *portainer.Endpoint - registries []portainer.Registry + registries []registry.Registry prune bool isAdmin bool user *portainer.User diff --git a/api/http/handler/stacks/handler.go b/api/http/handler/stacks/handler.go index 10d720fb6..f176947c0 100644 --- a/api/http/handler/stacks/handler.go +++ b/api/http/handler/stacks/handler.go @@ -96,7 +96,7 @@ func (handler *Handler) userCanAccessStack(securityContext *security.RestrictedR return false, err } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range securityContext.UserMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } @@ -108,7 +108,7 @@ func (handler *Handler) userCanAccessStack(securityContext *security.RestrictedR return handler.userIsAdminOrEndpointAdmin(user, endpointID) } -func (handler *Handler) userIsAdmin(userID portainer.UserID) (bool, error) { +func (handler *Handler) userIsAdmin(userID database.UserID) (bool, error) { user, err := handler.DataStore.User().User(userID) if err != nil { return false, err diff --git a/api/http/handler/stacks/stack_create.go b/api/http/handler/stacks/stack_create.go index 10c718280..696efdb3b 100644 --- a/api/http/handler/stacks/stack_create.go +++ b/api/http/handler/stacks/stack_create.go @@ -117,7 +117,7 @@ func (handler *Handler) stackCreate(w http.ResponseWriter, r *http.Request) *htt return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: type. Value must be one of: 1 (Swarm stack) or 2 (Compose stack)", errors.New(request.ErrInvalidQueryParameter)} } -func (handler *Handler) createComposeStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createComposeStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { switch method { case "string": @@ -131,7 +131,7 @@ func (handler *Handler) createComposeStack(w http.ResponseWriter, r *http.Reques return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid value for query parameter: method. Value must be one of: string, repository or file", Err: errors.New(request.ErrInvalidQueryParameter)} } -func (handler *Handler) createSwarmStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createSwarmStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { switch method { case "string": return handler.createSwarmStackFromFileContent(w, r, endpoint, userID) @@ -144,7 +144,7 @@ func (handler *Handler) createSwarmStack(w http.ResponseWriter, r *http.Request, return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid value for query parameter: method. Value must be one of: string, repository or file", Err: errors.New(request.ErrInvalidQueryParameter)} } -func (handler *Handler) createKubernetesStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) createKubernetesStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint, userID database.UserID) *httperror.HandlerError { switch method { case "string": return handler.createKubernetesStackFromFileContent(w, r, endpoint, userID) @@ -213,7 +213,7 @@ func (handler *Handler) isValidStackFile(stackFileContent []byte, securitySettin return nil } -func (handler *Handler) decorateStackResponse(w http.ResponseWriter, stack *portainer.Stack, userID portainer.UserID) *httperror.HandlerError { +func (handler *Handler) decorateStackResponse(w http.ResponseWriter, stack *portainer.Stack, userID database.UserID) *httperror.HandlerError { var resourceControl *portainer.ResourceControl isAdmin, err := handler.userIsAdmin(userID) diff --git a/api/http/handler/stacks/stack_delete.go b/api/http/handler/stacks/stack_delete.go index f1ddb3bb9..3ad212d0c 100644 --- a/api/http/handler/stacks/stack_delete.go +++ b/api/http/handler/stacks/stack_delete.go @@ -177,7 +177,7 @@ func (handler *Handler) deleteExternalStack(r *http.Request, w http.ResponseWrit return response.Empty(w) } -func (handler *Handler) deleteStack(userID portainer.UserID, stack *portainer.Stack, endpoint *portainer.Endpoint) error { +func (handler *Handler) deleteStack(userID database.UserID, stack *portainer.Stack, endpoint *portainer.Endpoint) error { if stack.Type == portainer.DockerSwarmStack { return handler.SwarmStackManager.Remove(stack, endpoint) } diff --git a/api/http/handler/stacks/stack_list.go b/api/http/handler/stacks/stack_list.go index c83b408a2..07aabf34d 100644 --- a/api/http/handler/stacks/stack_list.go +++ b/api/http/handler/stacks/stack_list.go @@ -75,7 +75,7 @@ func (handler *Handler) stackList(w http.ResponseWriter, r *http.Request) *httpe return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user information from the database", err} } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range securityContext.UserMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } diff --git a/api/http/handler/teammemberships/teammembership_create.go b/api/http/handler/teammemberships/teammembership_create.go index f550a0ab2..a8fb01752 100644 --- a/api/http/handler/teammemberships/teammembership_create.go +++ b/api/http/handler/teammemberships/teammembership_create.go @@ -2,6 +2,7 @@ package teammemberships import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -63,26 +64,26 @@ func (handler *Handler) teamMembershipCreate(w http.ResponseWriter, r *http.Requ return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err} } - if !security.AuthorizedTeamManagement(portainer.TeamID(payload.TeamID), securityContext) { + if !security.AuthorizedTeamManagement(database.TeamID(payload.TeamID), securityContext) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to manage team memberships", httperrors.ErrResourceAccessDenied} } - memberships, err := handler.DataStore.TeamMembership().TeamMembershipsByUserID(portainer.UserID(payload.UserID)) + memberships, err := handler.DataStore.TeamMembership().TeamMembershipsByUserID(database.UserID(payload.UserID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve team memberships from the database", err} } if len(memberships) > 0 { for _, membership := range memberships { - if membership.UserID == portainer.UserID(payload.UserID) && membership.TeamID == portainer.TeamID(payload.TeamID) { + if membership.UserID == database.UserID(payload.UserID) && membership.TeamID == database.TeamID(payload.TeamID) { return &httperror.HandlerError{http.StatusConflict, "Team membership already registered", errors.New("Team membership already exists for this user and team")} } } } membership := &portainer.TeamMembership{ - UserID: portainer.UserID(payload.UserID), - TeamID: portainer.TeamID(payload.TeamID), + UserID: database.UserID(payload.UserID), + TeamID: database.TeamID(payload.TeamID), Role: portainer.MembershipRole(payload.Role), } diff --git a/api/http/handler/teammemberships/teammembership_update.go b/api/http/handler/teammemberships/teammembership_update.go index 5deceb145..7eb0d04e7 100644 --- a/api/http/handler/teammemberships/teammembership_update.go +++ b/api/http/handler/teammemberships/teammembership_update.go @@ -2,6 +2,7 @@ package teammemberships import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -68,7 +69,7 @@ func (handler *Handler) teamMembershipUpdate(w http.ResponseWriter, r *http.Requ return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err} } - if !security.AuthorizedTeamManagement(portainer.TeamID(payload.TeamID), securityContext) { + if !security.AuthorizedTeamManagement(database.TeamID(payload.TeamID), securityContext) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the membership", httperrors.ErrResourceAccessDenied} } @@ -83,8 +84,8 @@ func (handler *Handler) teamMembershipUpdate(w http.ResponseWriter, r *http.Requ return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the role of membership", httperrors.ErrResourceAccessDenied} } - membership.UserID = portainer.UserID(payload.UserID) - membership.TeamID = portainer.TeamID(payload.TeamID) + membership.UserID = database.UserID(payload.UserID) + membership.TeamID = database.TeamID(payload.TeamID) membership.Role = portainer.MembershipRole(payload.Role) err = handler.DataStore.TeamMembership().UpdateTeamMembership(membership.ID, membership) diff --git a/api/http/handler/teams/team_delete.go b/api/http/handler/teams/team_delete.go index cea1585dc..2b737ebfd 100644 --- a/api/http/handler/teams/team_delete.go +++ b/api/http/handler/teams/team_delete.go @@ -1,13 +1,13 @@ package teams import ( + "github.com/portainer/portainer/api/database" "net/http" "github.com/pkg/errors" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" ) // @id TeamDelete @@ -30,25 +30,25 @@ func (handler *Handler) teamDelete(w http.ResponseWriter, r *http.Request) *http return &httperror.HandlerError{http.StatusBadRequest, "Invalid team identifier route variable", err} } - _, err = handler.DataStore.Team().Team(portainer.TeamID(teamID)) + _, err = handler.DataStore.Team().Team(database.TeamID(teamID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a team with the specified identifier inside the database", err} } else if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a team with the specified identifier inside the database", err} } - err = handler.DataStore.Team().DeleteTeam(portainer.TeamID(teamID)) + err = handler.DataStore.Team().DeleteTeam(database.TeamID(teamID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to delete the team from the database", err} } - err = handler.DataStore.TeamMembership().DeleteTeamMembershipByTeamID(portainer.TeamID(teamID)) + err = handler.DataStore.TeamMembership().DeleteTeamMembershipByTeamID(database.TeamID(teamID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to delete associated team memberships from the database", err} } // update default team if deleted team was default - err = handler.updateDefaultTeamIfDeleted(portainer.TeamID(teamID)) + err = handler.updateDefaultTeamIfDeleted(database.TeamID(teamID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to reset default team", err} } @@ -57,7 +57,7 @@ func (handler *Handler) teamDelete(w http.ResponseWriter, r *http.Request) *http } // updateDefaultTeamIfDeleted resets the default team to nil if default team was the deleted team -func (handler *Handler) updateDefaultTeamIfDeleted(teamID portainer.TeamID) error { +func (handler *Handler) updateDefaultTeamIfDeleted(teamID database.TeamID) error { settings, err := handler.DataStore.Settings().Settings() if err != nil { return errors.Wrap(err, "failed to fetch settings") diff --git a/api/http/handler/teams/team_inspect.go b/api/http/handler/teams/team_inspect.go index 8e1c90bc5..64885bc23 100644 --- a/api/http/handler/teams/team_inspect.go +++ b/api/http/handler/teams/team_inspect.go @@ -1,12 +1,12 @@ package teams import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" ) @@ -38,11 +38,11 @@ func (handler *Handler) teamInspect(w http.ResponseWriter, r *http.Request) *htt return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err} } - if !security.AuthorizedTeamManagement(portainer.TeamID(teamID), securityContext) { + if !security.AuthorizedTeamManagement(database.TeamID(teamID), securityContext) { return &httperror.HandlerError{http.StatusForbidden, "Access denied to team", errors.ErrResourceAccessDenied} } - team, err := handler.DataStore.Team().Team(portainer.TeamID(teamID)) + team, err := handler.DataStore.Team().Team(database.TeamID(teamID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a team with the specified identifier inside the database", err} } else if err != nil { diff --git a/api/http/handler/teams/team_memberships.go b/api/http/handler/teams/team_memberships.go index 7be4090e5..843f1c023 100644 --- a/api/http/handler/teams/team_memberships.go +++ b/api/http/handler/teams/team_memberships.go @@ -1,12 +1,12 @@ package teams import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" ) @@ -36,11 +36,11 @@ func (handler *Handler) teamMemberships(w http.ResponseWriter, r *http.Request) return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err} } - if !security.AuthorizedTeamManagement(portainer.TeamID(teamID), securityContext) { + if !security.AuthorizedTeamManagement(database.TeamID(teamID), securityContext) { return &httperror.HandlerError{http.StatusForbidden, "Access denied to team", errors.ErrResourceAccessDenied} } - memberships, err := handler.DataStore.TeamMembership().TeamMembershipsByTeamID(portainer.TeamID(teamID)) + memberships, err := handler.DataStore.TeamMembership().TeamMembershipsByTeamID(database.TeamID(teamID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve associated team memberships from the database", err} } diff --git a/api/http/handler/teams/team_update.go b/api/http/handler/teams/team_update.go index 50568ad71..1eb64cc81 100644 --- a/api/http/handler/teams/team_update.go +++ b/api/http/handler/teams/team_update.go @@ -1,12 +1,12 @@ package teams import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" ) type teamUpdatePayload struct { @@ -48,7 +48,7 @@ func (handler *Handler) teamUpdate(w http.ResponseWriter, r *http.Request) *http return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err} } - team, err := handler.DataStore.Team().Team(portainer.TeamID(teamID)) + team, err := handler.DataStore.Team().Team(database.TeamID(teamID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a team with the specified identifier inside the database", err} } else if err != nil { diff --git a/api/http/handler/users/user_create_access_token.go b/api/http/handler/users/user_create_access_token.go index ad8fb880d..e66482666 100644 --- a/api/http/handler/users/user_create_access_token.go +++ b/api/http/handler/users/user_create_access_token.go @@ -2,6 +2,7 @@ package users import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" "github.com/asaskevich/govalidator" @@ -75,11 +76,11 @@ func (handler *Handler) userCreateAccessToken(w http.ResponseWriter, r *http.Req return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.ID != portainer.UserID(userID) { + if tokenData.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to create user access token", httperrors.ErrUnauthorized} } - user, err := handler.DataStore.User().User(portainer.UserID(userID)) + user, err := handler.DataStore.User().User(database.UserID(userID)) if err != nil { return &httperror.HandlerError{http.StatusBadRequest, "Unable to find a user", err} } diff --git a/api/http/handler/users/user_delete.go b/api/http/handler/users/user_delete.go index db344a080..1e2253643 100644 --- a/api/http/handler/users/user_delete.go +++ b/api/http/handler/users/user_delete.go @@ -2,6 +2,7 @@ package users import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -41,11 +42,11 @@ func (handler *Handler) userDelete(w http.ResponseWriter, r *http.Request) *http return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.ID == portainer.UserID(userID) { + if tokenData.ID == database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Cannot remove your own user account. Contact another administrator", errAdminCannotRemoveSelf} } - user, err := handler.DataStore.User().User(portainer.UserID(userID)) + user, err := handler.DataStore.User().User(database.UserID(userID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err} } else if err != nil { diff --git a/api/http/handler/users/user_get_access_tokens.go b/api/http/handler/users/user_get_access_tokens.go index ac04adccd..0ecea95ff 100644 --- a/api/http/handler/users/user_get_access_tokens.go +++ b/api/http/handler/users/user_get_access_tokens.go @@ -1,6 +1,7 @@ package users import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -38,11 +39,11 @@ func (handler *Handler) userGetAccessTokens(w http.ResponseWriter, r *http.Reque return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.Role != portainer.AdministratorRole && tokenData.ID != portainer.UserID(userID) { + if tokenData.Role != portainer.AdministratorRole && tokenData.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to get user access tokens", httperrors.ErrUnauthorized} } - _, err = handler.DataStore.User().User(portainer.UserID(userID)) + _, err = handler.DataStore.User().User(database.UserID(userID)) if err != nil { if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err} @@ -50,7 +51,7 @@ func (handler *Handler) userGetAccessTokens(w http.ResponseWriter, r *http.Reque return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a user with the specified identifier inside the database", err} } - apiKeys, err := handler.apiKeyService.GetAPIKeys(portainer.UserID(userID)) + apiKeys, err := handler.apiKeyService.GetAPIKeys(database.UserID(userID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Internal Server Error", err} } diff --git a/api/http/handler/users/user_inspect.go b/api/http/handler/users/user_inspect.go index 7ab848f3f..05f6ea5f1 100644 --- a/api/http/handler/users/user_inspect.go +++ b/api/http/handler/users/user_inspect.go @@ -1,12 +1,12 @@ package users import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" ) @@ -38,11 +38,11 @@ func (handler *Handler) userInspect(w http.ResponseWriter, r *http.Request) *htt return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err} } - if !securityContext.IsAdmin && securityContext.UserID != portainer.UserID(userID) { + if !securityContext.IsAdmin && securityContext.UserID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied inspect user", errors.ErrResourceAccessDenied} } - user, err := handler.DataStore.User().User(portainer.UserID(userID)) + user, err := handler.DataStore.User().User(database.UserID(userID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err} } else if err != nil { diff --git a/api/http/handler/users/user_memberships.go b/api/http/handler/users/user_memberships.go index 82a1b366e..92d17a738 100644 --- a/api/http/handler/users/user_memberships.go +++ b/api/http/handler/users/user_memberships.go @@ -1,6 +1,7 @@ package users import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -36,11 +37,11 @@ func (handler *Handler) userMemberships(w http.ResponseWriter, r *http.Request) return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.Role != portainer.AdministratorRole && tokenData.ID != portainer.UserID(userID) { + if tokenData.Role != portainer.AdministratorRole && tokenData.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update user memberships", errors.ErrUnauthorized} } - memberships, err := handler.DataStore.TeamMembership().TeamMembershipsByUserID(portainer.UserID(userID)) + memberships, err := handler.DataStore.TeamMembership().TeamMembershipsByUserID(database.UserID(userID)) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist membership changes inside the database", err} } diff --git a/api/http/handler/users/user_remove_access_token.go b/api/http/handler/users/user_remove_access_token.go index 21edde55e..1ccdfec50 100644 --- a/api/http/handler/users/user_remove_access_token.go +++ b/api/http/handler/users/user_remove_access_token.go @@ -1,6 +1,7 @@ package users import ( + "github.com/portainer/portainer/api/database" "net/http" httperror "github.com/portainer/libhttp/error" @@ -43,11 +44,11 @@ func (handler *Handler) userRemoveAccessToken(w http.ResponseWriter, r *http.Req if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.Role != portainer.AdministratorRole && tokenData.ID != portainer.UserID(userID) { + if tokenData.Role != portainer.AdministratorRole && tokenData.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to get user access tokens", httperrors.ErrUnauthorized} } - _, err = handler.DataStore.User().User(portainer.UserID(userID)) + _, err = handler.DataStore.User().User(database.UserID(userID)) if err != nil { if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err} @@ -60,7 +61,7 @@ func (handler *Handler) userRemoveAccessToken(w http.ResponseWriter, r *http.Req if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "API Key not found", err} } - if apiKey.UserID != portainer.UserID(userID) { + if apiKey.UserID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to remove api-key", httperrors.ErrUnauthorized} } diff --git a/api/http/handler/users/user_update.go b/api/http/handler/users/user_update.go index cec78759c..9b20b58f6 100644 --- a/api/http/handler/users/user_update.go +++ b/api/http/handler/users/user_update.go @@ -2,6 +2,7 @@ package users import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" "time" @@ -62,7 +63,7 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.Role != portainer.AdministratorRole && tokenData.ID != portainer.UserID(userID) { + if tokenData.Role != portainer.AdministratorRole && tokenData.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update user", httperrors.ErrUnauthorized} } @@ -76,7 +77,7 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update user to administrator role", httperrors.ErrResourceAccessDenied} } - user, err := handler.DataStore.User().User(portainer.UserID(userID)) + user, err := handler.DataStore.User().User(database.UserID(userID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err} } else if err != nil { @@ -88,7 +89,7 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http if err != nil && !handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve users from the database", err} } - if sameNameUser != nil && sameNameUser.ID != portainer.UserID(userID) { + if sameNameUser != nil && sameNameUser.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusConflict, "Another user with the same username already exists", errUserAlreadyExists} } diff --git a/api/http/handler/users/user_update_password.go b/api/http/handler/users/user_update_password.go index 99c92ebab..d1f2ab364 100644 --- a/api/http/handler/users/user_update_password.go +++ b/api/http/handler/users/user_update_password.go @@ -2,6 +2,7 @@ package users import ( "errors" + "github.com/portainer/portainer/api/database" "net/http" "time" @@ -59,7 +60,7 @@ func (handler *Handler) userUpdatePassword(w http.ResponseWriter, r *http.Reques return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve user authentication token", err} } - if tokenData.Role != portainer.AdministratorRole && tokenData.ID != portainer.UserID(userID) { + if tokenData.Role != portainer.AdministratorRole && tokenData.ID != database.UserID(userID) { return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update user", httperrors.ErrUnauthorized} } @@ -69,7 +70,7 @@ func (handler *Handler) userUpdatePassword(w http.ResponseWriter, r *http.Reques return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err} } - user, err := handler.DataStore.User().User(portainer.UserID(userID)) + user, err := handler.DataStore.User().User(database.UserID(userID)) if handler.DataStore.IsErrObjectNotFound(err) { return &httperror.HandlerError{http.StatusNotFound, "Unable to find a user with the specified identifier inside the database", err} } else if err != nil { diff --git a/api/http/handler/webhooks/handler.go b/api/http/handler/webhooks/handler.go index 665b70365..f61776129 100644 --- a/api/http/handler/webhooks/handler.go +++ b/api/http/handler/webhooks/handler.go @@ -1,6 +1,7 @@ package webhooks import ( + "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/internal/authorization" "net/http" @@ -49,7 +50,7 @@ func (handler *Handler) checkResourceAccess(r *http.Request, resourceID string, if rc == nil || err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: "Unable to retrieve a resource control associated to the resource", Err: err} } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range securityContext.UserMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } diff --git a/api/http/handler/webhooks/webhook_create.go b/api/http/handler/webhooks/webhook_create.go index 3572c1c85..a32ebb1c3 100644 --- a/api/http/handler/webhooks/webhook_create.go +++ b/api/http/handler/webhooks/webhook_create.go @@ -3,6 +3,7 @@ package webhooks import ( "errors" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/registryutils/access" "net/http" @@ -18,7 +19,7 @@ import ( type webhookCreatePayload struct { ResourceID string EndpointID int - RegistryID portainer.RegistryID + RegistryID registry.RegistryID WebhookType int } diff --git a/api/http/handler/webhooks/webhook_execute.go b/api/http/handler/webhooks/webhook_execute.go index c578e9af2..1377fc418 100644 --- a/api/http/handler/webhooks/webhook_execute.go +++ b/api/http/handler/webhooks/webhook_execute.go @@ -4,6 +4,7 @@ import ( "context" "errors" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "github.com/portainer/portainer/api/internal/registryutils" "io" "net/http" @@ -67,7 +68,7 @@ func (handler *Handler) executeServiceWebhook( w http.ResponseWriter, endpoint *portainer.Endpoint, resourceID string, - registryID portainer.RegistryID, + registryID registry.RegistryID, imageTag string, ) *httperror.HandlerError { dockerClient, err := handler.DockerClientFactory.CreateClient(endpoint, "", nil) diff --git a/api/http/handler/webhooks/webhook_update.go b/api/http/handler/webhooks/webhook_update.go index 0fff1ec82..2b6e27aa4 100644 --- a/api/http/handler/webhooks/webhook_update.go +++ b/api/http/handler/webhooks/webhook_update.go @@ -2,6 +2,7 @@ package webhooks import ( "errors" + "github.com/portainer/portainer/api/dataservices/registry" "net/http" "github.com/portainer/portainer/api/http/security" @@ -14,7 +15,7 @@ import ( ) type webhookUpdatePayload struct { - RegistryID portainer.RegistryID + RegistryID registry.RegistryID } func (payload *webhookUpdatePayload) Validate(r *http.Request) error { diff --git a/api/http/proxy/factory/azure/access_control.go b/api/http/proxy/factory/azure/access_control.go index 6c6bcff15..3bdb7b2c2 100644 --- a/api/http/proxy/factory/azure/access_control.go +++ b/api/http/proxy/factory/azure/access_control.go @@ -1,6 +1,7 @@ package azure import ( + "github.com/portainer/portainer/api/database" "log" "net/http" @@ -36,7 +37,7 @@ func (transport *Transport) createAzureRequestContext(request *http.Request) (*a return nil, err } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range teamMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } @@ -59,7 +60,7 @@ func decorateObject(object map[string]interface{}, resourceControl *portainer.Re func (transport *Transport) createPrivateResourceControl( resourceIdentifier string, resourceType portainer.ResourceControlType, - userID portainer.UserID) (*portainer.ResourceControl, error) { + userID database.UserID) (*portainer.ResourceControl, error) { resourceControl := authorization.NewPrivateResourceControl(resourceIdentifier, resourceType, userID) diff --git a/api/http/proxy/factory/azure/transport.go b/api/http/proxy/factory/azure/transport.go index eeff6550e..384802546 100644 --- a/api/http/proxy/factory/azure/transport.go +++ b/api/http/proxy/factory/azure/transport.go @@ -1,6 +1,7 @@ package azure import ( + "github.com/portainer/portainer/api/database" "net/http" "path" "strconv" @@ -29,8 +30,8 @@ type ( azureRequestContext struct { isAdmin bool - userID portainer.UserID - userTeamIDs []portainer.TeamID + userID database.UserID + userTeamIDs []database.TeamID resourceControls []portainer.ResourceControl } ) diff --git a/api/http/proxy/factory/docker/access_control.go b/api/http/proxy/factory/docker/access_control.go index c7ac52cff..da50fdd9d 100644 --- a/api/http/proxy/factory/docker/access_control.go +++ b/api/http/proxy/factory/docker/access_control.go @@ -74,8 +74,8 @@ func (transport *Transport) newResourceControlFromPortainerLabels(labelsObject m } if len(teamNames) > 0 || len(userNames) > 0 { - teamIDs := make([]portainer.TeamID, 0) - userIDs := make([]portainer.UserID, 0) + teamIDs := make([]database.TeamID, 0) + userIDs := make([]database.UserID, 0) for _, name := range teamNames { team, err := transport.dataStore.Team().TeamByName(name) @@ -110,7 +110,7 @@ func (transport *Transport) newResourceControlFromPortainerLabels(labelsObject m return nil, nil } -func (transport *Transport) createPrivateResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userID portainer.UserID) (*portainer.ResourceControl, error) { +func (transport *Transport) createPrivateResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userID database.UserID) (*portainer.ResourceControl, error) { resourceControl := authorization.NewPrivateResourceControl(resourceIdentifier, resourceType, userID) err := transport.dataStore.ResourceControl().Create(resourceControl) diff --git a/api/http/proxy/factory/docker/registry.go b/api/http/proxy/factory/docker/registry.go index 39e65ed2e..925cb52d1 100644 --- a/api/http/proxy/factory/docker/registry.go +++ b/api/http/proxy/factory/docker/registry.go @@ -4,6 +4,7 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/dataservices" + "github.com/portainer/portainer/api/dataservices/registry" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/registryutils" ) @@ -14,7 +15,7 @@ type ( user *portainer.User endpointID database.EndpointID teamMemberships []portainer.TeamMembership - registries []portainer.Registry + registries []registry.Registry } registryAuthenticationHeader struct { @@ -24,19 +25,19 @@ type ( } portainerRegistryAuthenticationHeader struct { - RegistryId portainer.RegistryID `json:"registryId"` + RegistryId registry.RegistryID `json:"registryId"` } ) func createRegistryAuthenticationHeader( dataStore dataservices.DataStore, - registryId portainer.RegistryID, + registryId registry.RegistryID, accessContext *registryAccessContext, ) (authenticationHeader registryAuthenticationHeader, err error) { if registryId == 0 { // dockerhub (anonymous) authenticationHeader.Serveraddress = "docker.io" } else { // any "custom" registry - var matchingRegistry *portainer.Registry + var matchingRegistry *registry.Registry for _, registry := range accessContext.registries { if registry.ID == registryId && (accessContext.isAdmin || diff --git a/api/http/proxy/factory/docker/transport.go b/api/http/proxy/factory/docker/transport.go index cbc0de1fb..fba1887b6 100644 --- a/api/http/proxy/factory/docker/transport.go +++ b/api/http/proxy/factory/docker/transport.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "github.com/portainer/portainer/api/database" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "io/ioutil" "log" "net/http" @@ -49,8 +50,8 @@ type ( restrictedDockerOperationContext struct { isAdmin bool - userID portainer.UserID - userTeamIDs []portainer.TeamID + userID database.UserID + userTeamIDs []database.TeamID resourceControls []portainer.ResourceControl } @@ -173,12 +174,12 @@ func (transport *Transport) proxyAgentRequest(r *http.Request) (*http.Response, r.URL.Path = strings.TrimSuffix(requestPath, "/") - registry := &portainer.Registry{ + registry := ®istry2.Registry{ Type: portainer.DockerHubRegistry, } if registryID != 0 { - registry, err = transport.dataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err = transport.dataStore.Registry().Registry(registry2.RegistryID(registryID)) if err != nil { return nil, fmt.Errorf("failed fetching registry: %w", err) } @@ -459,7 +460,7 @@ func (transport *Transport) restrictedResourceOperation(request *http.Request, r return nil, err } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range teamMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } @@ -553,7 +554,7 @@ func (transport *Transport) interceptAndRewriteRequest(request *http.Request, op // https://docs.docker.com/engine/api/v1.37/#operation/ServiceCreate // https://docs.docker.com/engine/api/v1.37/#operation/SecretCreate // https://docs.docker.com/engine/api/v1.37/#operation/ConfigCreate -func (transport *Transport) decorateGenericResourceCreationResponse(response *http.Response, resourceIdentifierAttribute string, resourceType portainer.ResourceControlType, userID portainer.UserID) error { +func (transport *Transport) decorateGenericResourceCreationResponse(response *http.Response, resourceIdentifierAttribute string, resourceType portainer.ResourceControlType, userID database.UserID) error { responseObject, err := utils.GetResponseAsJSONObject(response) if err != nil { return err @@ -709,7 +710,7 @@ func (transport *Transport) createOperationContext(request *http.Request) (*rest return nil, err } - userTeamIDs := make([]portainer.TeamID, 0) + userTeamIDs := make([]database.TeamID, 0) for _, membership := range teamMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } diff --git a/api/http/proxy/factory/docker/volumes.go b/api/http/proxy/factory/docker/volumes.go index 19ad6a2b0..656d13739 100644 --- a/api/http/proxy/factory/docker/volumes.go +++ b/api/http/proxy/factory/docker/volumes.go @@ -157,7 +157,7 @@ func (transport *Transport) decorateVolumeResourceCreationOperation(request *htt return response, err } -func (transport *Transport) decorateVolumeCreationResponse(response *http.Response, resourceType portainer.ResourceControlType, userID portainer.UserID) error { +func (transport *Transport) decorateVolumeCreationResponse(response *http.Response, resourceType portainer.ResourceControlType, userID database.UserID) error { responseObject, err := utils.GetResponseAsJSONObject(response) if err != nil { return err diff --git a/api/http/proxy/factory/kubernetes/namespaces.go b/api/http/proxy/factory/kubernetes/namespaces.go index c501f7cc7..4d3f33955 100644 --- a/api/http/proxy/factory/kubernetes/namespaces.go +++ b/api/http/proxy/factory/kubernetes/namespaces.go @@ -1,10 +1,10 @@ package kubernetes import ( + registry2 "github.com/portainer/portainer/api/dataservices/registry" "net/http" "github.com/pkg/errors" - portainer "github.com/portainer/portainer/api" ) func (transport *baseTransport) proxyNamespaceDeleteOperation(request *http.Request, namespace string) (*http.Response, error) { @@ -32,7 +32,7 @@ func (transport *baseTransport) proxyNamespaceDeleteOperation(request *http.Requ } if len(namespaces) != len(registryAccessPolicies.Namespaces) { - updatedAccessPolicies := portainer.RegistryAccessPolicies{ + updatedAccessPolicies := registry2.RegistryAccessPolicies{ Namespaces: namespaces, UserAccessPolicies: registryAccessPolicies.UserAccessPolicies, TeamAccessPolicies: registryAccessPolicies.TeamAccessPolicies, diff --git a/api/http/proxy/factory/kubernetes/token.go b/api/http/proxy/factory/kubernetes/token.go index c587a29bd..0c0d8990e 100644 --- a/api/http/proxy/factory/kubernetes/token.go +++ b/api/http/proxy/factory/kubernetes/token.go @@ -50,7 +50,7 @@ func (manager *tokenManager) GetUserServiceAccountToken(userID int, endpointID d token, ok := manager.tokenCache.getToken(userID) if !ok { - memberships, err := manager.dataStore.TeamMembership().TeamMembershipsByUserID(portainer.UserID(userID)) + memberships, err := manager.dataStore.TeamMembership().TeamMembershipsByUserID(database.UserID(userID)) if err != nil { return "", err } diff --git a/api/http/proxy/factory/kubernetes/transport.go b/api/http/proxy/factory/kubernetes/transport.go index 1fcc13fd0..d08f144e1 100644 --- a/api/http/proxy/factory/kubernetes/transport.go +++ b/api/http/proxy/factory/kubernetes/transport.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + registry2 "github.com/portainer/portainer/api/dataservices/registry" "io/ioutil" "log" "net/http" @@ -165,12 +166,12 @@ func decorateAgentDockerHubRequest(r *http.Request, dataStore dataservices.DataS r.URL.Path = strings.TrimSuffix(requestPath, "/") - registry := &portainer.Registry{ + registry := ®istry2.Registry{ Type: portainer.DockerHubRegistry, } if registryID != 0 { - registry, err = dataStore.Registry().Registry(portainer.RegistryID(registryID)) + registry, err = dataStore.Registry().Registry(registry2.RegistryID(registryID)) if err != nil { return fmt.Errorf("failed fetching registry: %w", err) } diff --git a/api/http/security/authorization.go b/api/http/security/authorization.go index 2b74d1aeb..588ca91f3 100644 --- a/api/http/security/authorization.go +++ b/api/http/security/authorization.go @@ -2,6 +2,7 @@ package security import ( "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "net/http" portainer "github.com/portainer/portainer/api" @@ -90,7 +91,7 @@ func AuthorizedResourceControlUpdate(resourceControl *portainer.ResourceControl, // AuthorizedTeamManagement ensure that access to the management of the specified team is granted. // It will check if the user is either administrator or leader of that team. -func AuthorizedTeamManagement(teamID portainer.TeamID, context *RestrictedRequestContext) bool { +func AuthorizedTeamManagement(teamID database.TeamID, context *RestrictedRequestContext) bool { if context.IsAdmin { return true } @@ -107,7 +108,7 @@ func AuthorizedTeamManagement(teamID portainer.TeamID, context *RestrictedReques // authorizedEndpointAccess ensure that the user can access the specified environment(endpoint). // It will check if the user is part of the authorized users or part of a team that is // listed in the authorized teams of the environment(endpoint) and the associated group. -func authorizedEndpointAccess(endpoint *portainer.Endpoint, endpointGroup *portainer.EndpointGroup, userID portainer.UserID, memberships []portainer.TeamMembership) bool { +func authorizedEndpointAccess(endpoint *portainer.Endpoint, endpointGroup *portainer.EndpointGroup, userID database.UserID, memberships []portainer.TeamMembership) bool { groupAccess := AuthorizedAccess(userID, memberships, endpointGroup.UserAccessPolicies, endpointGroup.TeamAccessPolicies) if !groupAccess { return AuthorizedAccess(userID, memberships, endpoint.UserAccessPolicies, endpoint.TeamAccessPolicies) @@ -118,14 +119,14 @@ func authorizedEndpointAccess(endpoint *portainer.Endpoint, endpointGroup *porta // authorizedEndpointGroupAccess ensure that the user can access the specified environment(endpoint) group. // It will check if the user is part of the authorized users or part of a team that is // listed in the authorized teams. -func authorizedEndpointGroupAccess(endpointGroup *portainer.EndpointGroup, userID portainer.UserID, memberships []portainer.TeamMembership) bool { +func authorizedEndpointGroupAccess(endpointGroup *portainer.EndpointGroup, userID database.UserID, memberships []portainer.TeamMembership) bool { return AuthorizedAccess(userID, memberships, endpointGroup.UserAccessPolicies, endpointGroup.TeamAccessPolicies) } // AuthorizedRegistryAccess ensure that the user can access the specified registry. // It will check if the user is part of the authorized users or part of a team that is // listed in the authorized teams for a specified environment(endpoint), -func AuthorizedRegistryAccess(registry *portainer.Registry, user *portainer.User, teamMemberships []portainer.TeamMembership, endpointID database.EndpointID) bool { +func AuthorizedRegistryAccess(registry *registry.Registry, user *portainer.User, teamMemberships []portainer.TeamMembership, endpointID database.EndpointID) bool { if user.Role == portainer.AdministratorRole { return true } @@ -136,7 +137,7 @@ func AuthorizedRegistryAccess(registry *portainer.Registry, user *portainer.User } // AuthorizedAccess verifies the userID or memberships are authorized to use an object per the supplied access policies -func AuthorizedAccess(userID portainer.UserID, memberships []portainer.TeamMembership, userAccessPolicies portainer.UserAccessPolicies, teamAccessPolicies portainer.TeamAccessPolicies) bool { +func AuthorizedAccess(userID database.UserID, memberships []portainer.TeamMembership, userAccessPolicies database.UserAccessPolicies, teamAccessPolicies database.TeamAccessPolicies) bool { _, userAccess := userAccessPolicies[userID] if userAccess { return true diff --git a/api/http/security/bouncer.go b/api/http/security/bouncer.go index c827f17be..de2a040a8 100644 --- a/api/http/security/bouncer.go +++ b/api/http/security/bouncer.go @@ -3,6 +3,7 @@ package security import ( "errors" "fmt" + "github.com/portainer/portainer/api/database" "net/http" "strings" "time" @@ -27,7 +28,7 @@ type ( RestrictedRequestContext struct { IsAdmin bool IsTeamLeader bool - UserID portainer.UserID + UserID database.UserID UserMemberships []portainer.TeamMembership } @@ -350,7 +351,7 @@ func mwSecureHeaders(next http.Handler) http.Handler { }) } -func (bouncer *RequestBouncer) newRestrictedContextRequest(userID portainer.UserID, userRole portainer.UserRole) (*RestrictedRequestContext, error) { +func (bouncer *RequestBouncer) newRestrictedContextRequest(userID database.UserID, userRole portainer.UserRole) (*RestrictedRequestContext, error) { if userRole == portainer.AdministratorRole { return &RestrictedRequestContext{ IsAdmin: true, diff --git a/api/http/security/bouncer_test.go b/api/http/security/bouncer_test.go index d749522b7..c9520e84c 100644 --- a/api/http/security/bouncer_test.go +++ b/api/http/security/bouncer_test.go @@ -2,6 +2,7 @@ package security import ( "fmt" + "github.com/portainer/portainer/api/database" "net/http" "net/http/httptest" "testing" @@ -22,7 +23,7 @@ var testHandler200 = http.HandlerFunc(func(w http.ResponseWriter, r *http.Reques func tokenLookupSucceed(dataStore dataservices.DataStore, jwtService dataservices.JWTService) tokenLookup { return func(r *http.Request) *portainer.TokenData { - uid := portainer.UserID(1) + uid := database.UserID(1) dataStore.User().Create(&portainer.User{ID: uid}) jwtService.GenerateToken(&portainer.TokenData{ID: uid}) return &portainer.TokenData{ID: 1} diff --git a/api/http/security/filter.go b/api/http/security/filter.go index 31745143a..bac4c2da9 100644 --- a/api/http/security/filter.go +++ b/api/http/security/filter.go @@ -3,6 +3,7 @@ package security import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" ) // FilterUserTeams filters teams based on user role. @@ -65,12 +66,12 @@ func FilterUsers(users []portainer.User, context *RestrictedRequestContext) []po // FilterRegistries filters registries based on user role and team memberships. // Non administrator users only have access to authorized registries. -func FilterRegistries(registries []portainer.Registry, user *portainer.User, teamMemberships []portainer.TeamMembership, endpointID database.EndpointID) []portainer.Registry { +func FilterRegistries(registries []registry.Registry, user *portainer.User, teamMemberships []portainer.TeamMembership, endpointID database.EndpointID) []registry.Registry { if user.Role == portainer.AdministratorRole { return registries } - filteredRegistries := []portainer.Registry{} + filteredRegistries := []registry.Registry{} for _, registry := range registries { if AuthorizedRegistryAccess(®istry, user, teamMemberships, endpointID) { diff --git a/api/internal/authorization/access_control.go b/api/internal/authorization/access_control.go index 5004088db..37038d4ee 100644 --- a/api/internal/authorization/access_control.go +++ b/api/internal/authorization/access_control.go @@ -1,6 +1,7 @@ package authorization import ( + "github.com/portainer/portainer/api/database" "strconv" portainer "github.com/portainer/portainer/api" @@ -24,7 +25,7 @@ func NewAdministratorsOnlyResourceControl(resourceIdentifier string, resourceTyp // NewPrivateResourceControl will create a new private resource control associated to the resource specified by the // identifier and type parameters. It automatically assigns it to the user specified by the userID parameter. -func NewPrivateResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userID portainer.UserID) *portainer.ResourceControl { +func NewPrivateResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userID database.UserID) *portainer.ResourceControl { return &portainer.ResourceControl{ Type: resourceType, ResourceID: resourceIdentifier, @@ -72,7 +73,7 @@ func NewPublicResourceControl(resourceIdentifier string, resourceType portainer. } // NewRestrictedResourceControl will create a new resource control with user and team accesses restrictions. -func NewRestrictedResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userIDs []portainer.UserID, teamIDs []portainer.TeamID) *portainer.ResourceControl { +func NewRestrictedResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userIDs []database.UserID, teamIDs []database.TeamID) *portainer.ResourceControl { userAccesses := make([]portainer.UserResourceAccess, 0) teamAccesses := make([]portainer.TeamResourceAccess, 0) @@ -135,7 +136,7 @@ func DecorateCustomTemplates(templates []portainer.CustomTemplate, resourceContr } // FilterAuthorizedStacks returns a list of decorated stacks filtered through resource control access checks. -func FilterAuthorizedStacks(stacks []portainer.Stack, user *portainer.User, userTeamIDs []portainer.TeamID) []portainer.Stack { +func FilterAuthorizedStacks(stacks []portainer.Stack, user *portainer.User, userTeamIDs []database.TeamID) []portainer.Stack { authorizedStacks := make([]portainer.Stack, 0) for _, stack := range stacks { @@ -148,7 +149,7 @@ func FilterAuthorizedStacks(stacks []portainer.Stack, user *portainer.User, user } // FilterAuthorizedCustomTemplates returns a list of decorated custom templates filtered through resource control access checks. -func FilterAuthorizedCustomTemplates(customTemplates []portainer.CustomTemplate, user *portainer.User, userTeamIDs []portainer.TeamID) []portainer.CustomTemplate { +func FilterAuthorizedCustomTemplates(customTemplates []portainer.CustomTemplate, user *portainer.User, userTeamIDs []database.TeamID) []portainer.CustomTemplate { authorizedTemplates := make([]portainer.CustomTemplate, 0) for _, customTemplate := range customTemplates { @@ -162,7 +163,7 @@ func FilterAuthorizedCustomTemplates(customTemplates []portainer.CustomTemplate, // UserCanAccessResource will valid that a user has permissions defined in the specified resource control // based on its identifier and the team(s) he is part of. -func UserCanAccessResource(userID portainer.UserID, userTeamIDs []portainer.TeamID, resourceControl *portainer.ResourceControl) bool { +func UserCanAccessResource(userID database.UserID, userTeamIDs []database.TeamID, resourceControl *portainer.ResourceControl) bool { if resourceControl == nil { return false } diff --git a/api/internal/authorization/authorizations.go b/api/internal/authorization/authorizations.go index 2fe074a63..529902e40 100644 --- a/api/internal/authorization/authorizations.go +++ b/api/internal/authorization/authorizations.go @@ -445,7 +445,7 @@ func (service *Service) UpdateUsersAuthorizations() error { return nil } -func (service *Service) updateUserAuthorizations(userID portainer.UserID) error { +func (service *Service) updateUserAuthorizations(userID database.UserID) error { user, err := service.dataStore.User().User(userID) if err != nil { return err @@ -495,8 +495,8 @@ func (service *Service) getAuthorizations(user *portainer.User) (portainer.Endpo func getUserEndpointAuthorizations(user *portainer.User, endpoints []portainer.Endpoint, endpointGroups []portainer.EndpointGroup, roles []portainer.Role, userMemberships []portainer.TeamMembership) portainer.EndpointAuthorizations { endpointAuthorizations := make(portainer.EndpointAuthorizations) - groupUserAccessPolicies := map[portainer.EndpointGroupID]portainer.UserAccessPolicies{} - groupTeamAccessPolicies := map[portainer.EndpointGroupID]portainer.TeamAccessPolicies{} + groupUserAccessPolicies := map[portainer.EndpointGroupID]database.UserAccessPolicies{} + groupTeamAccessPolicies := map[portainer.EndpointGroupID]database.TeamAccessPolicies{} for _, endpointGroup := range endpointGroups { groupUserAccessPolicies[endpointGroup.ID] = endpointGroup.UserAccessPolicies groupTeamAccessPolicies[endpointGroup.ID] = endpointGroup.TeamAccessPolicies @@ -531,7 +531,7 @@ func getUserEndpointAuthorizations(user *portainer.User, endpoints []portainer.E } func getAuthorizationsFromUserEndpointPolicy(user *portainer.User, endpoint *portainer.Endpoint, roles []portainer.Role) portainer.Authorizations { - policyRoles := make([]portainer.RoleID, 0) + policyRoles := make([]database.RoleID, 0) policy, ok := endpoint.UserAccessPolicies[user.ID] if ok { @@ -541,8 +541,8 @@ func getAuthorizationsFromUserEndpointPolicy(user *portainer.User, endpoint *por return getAuthorizationsFromRoles(policyRoles, roles) } -func getAuthorizationsFromUserEndpointGroupPolicy(user *portainer.User, endpoint *portainer.Endpoint, roles []portainer.Role, groupAccessPolicies map[portainer.EndpointGroupID]portainer.UserAccessPolicies) portainer.Authorizations { - policyRoles := make([]portainer.RoleID, 0) +func getAuthorizationsFromUserEndpointGroupPolicy(user *portainer.User, endpoint *portainer.Endpoint, roles []portainer.Role, groupAccessPolicies map[portainer.EndpointGroupID]database.UserAccessPolicies) portainer.Authorizations { + policyRoles := make([]database.RoleID, 0) policy, ok := groupAccessPolicies[endpoint.GroupID][user.ID] if ok { @@ -553,7 +553,7 @@ func getAuthorizationsFromUserEndpointGroupPolicy(user *portainer.User, endpoint } func getAuthorizationsFromTeamEndpointPolicies(memberships []portainer.TeamMembership, endpoint *portainer.Endpoint, roles []portainer.Role) portainer.Authorizations { - policyRoles := make([]portainer.RoleID, 0) + policyRoles := make([]database.RoleID, 0) for _, membership := range memberships { policy, ok := endpoint.TeamAccessPolicies[membership.TeamID] @@ -565,8 +565,8 @@ func getAuthorizationsFromTeamEndpointPolicies(memberships []portainer.TeamMembe return getAuthorizationsFromRoles(policyRoles, roles) } -func getAuthorizationsFromTeamEndpointGroupPolicies(memberships []portainer.TeamMembership, endpoint *portainer.Endpoint, roles []portainer.Role, groupAccessPolicies map[portainer.EndpointGroupID]portainer.TeamAccessPolicies) portainer.Authorizations { - policyRoles := make([]portainer.RoleID, 0) +func getAuthorizationsFromTeamEndpointGroupPolicies(memberships []portainer.TeamMembership, endpoint *portainer.Endpoint, roles []portainer.Role, groupAccessPolicies map[portainer.EndpointGroupID]database.TeamAccessPolicies) portainer.Authorizations { + policyRoles := make([]database.RoleID, 0) for _, membership := range memberships { policy, ok := groupAccessPolicies[endpoint.GroupID][membership.TeamID] @@ -578,7 +578,7 @@ func getAuthorizationsFromTeamEndpointGroupPolicies(memberships []portainer.Team return getAuthorizationsFromRoles(policyRoles, roles) } -func getAuthorizationsFromRoles(roleIdentifiers []portainer.RoleID, roles []portainer.Role) portainer.Authorizations { +func getAuthorizationsFromRoles(roleIdentifiers []database.RoleID, roles []portainer.Role) portainer.Authorizations { var associatedRoles []portainer.Role for _, id := range roleIdentifiers { @@ -602,7 +602,7 @@ func getAuthorizationsFromRoles(roleIdentifiers []portainer.RoleID, roles []port return authorizations } -func (service *Service) UserIsAdminOrAuthorized(userID portainer.UserID, endpointID database.EndpointID, authorizations []portainer.Authorization) (bool, error) { +func (service *Service) UserIsAdminOrAuthorized(userID database.UserID, endpointID database.EndpointID, authorizations []portainer.Authorization) (bool, error) { user, err := service.dataStore.User().User(userID) if err != nil { return false, err diff --git a/api/internal/authorization/endpint_role_with_override.go b/api/internal/authorization/endpint_role_with_override.go index c26913947..a6bdfc673 100644 --- a/api/internal/authorization/endpint_role_with_override.go +++ b/api/internal/authorization/endpint_role_with_override.go @@ -1,6 +1,9 @@ package authorization -import portainer "github.com/portainer/portainer/api" +import ( + portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/database" +) // CleanNAPWithOverridePolicies Clean Namespace Access Policies with override policies func (service *Service) CleanNAPWithOverridePolicies( @@ -54,7 +57,7 @@ func (service *Service) CleanNAPWithOverridePolicies( } func (service *Service) getUserEndpointAccessWithPolicies( - userID portainer.UserID, + userID database.UserID, endpoint *portainer.Endpoint, endpointGroup *portainer.EndpointGroup, ) (bool, error) { @@ -83,9 +86,9 @@ func (service *Service) getUserEndpointAccessWithPolicies( } func userAccess( - userID portainer.UserID, - userAccessPolicies portainer.UserAccessPolicies, - teamAccessPolicies portainer.TeamAccessPolicies, + userID database.UserID, + userAccessPolicies database.UserAccessPolicies, + teamAccessPolicies database.TeamAccessPolicies, memberships []portainer.TeamMembership, ) bool { if _, ok := userAccessPolicies[userID]; ok { @@ -102,7 +105,7 @@ func userAccess( } func (service *Service) getTeamEndpointAccessWithPolicies( - teamID portainer.TeamID, + teamID database.TeamID, endpoint *portainer.Endpoint, endpointGroup *portainer.EndpointGroup, ) (bool, error) { @@ -126,8 +129,8 @@ func (service *Service) getTeamEndpointAccessWithPolicies( } func teamAccess( - teamID portainer.TeamID, - teamAccessPolicies portainer.TeamAccessPolicies, + teamID database.TeamID, + teamAccessPolicies database.TeamAccessPolicies, ) bool { _, ok := teamAccessPolicies[teamID] return ok diff --git a/api/internal/registryutils/access/access.go b/api/internal/registryutils/access/access.go index 7659a0e70..2d133b79e 100644 --- a/api/internal/registryutils/access/access.go +++ b/api/internal/registryutils/access/access.go @@ -3,6 +3,7 @@ package access import ( "fmt" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" @@ -11,9 +12,9 @@ import ( func hasPermission( dataStore dataservices.DataStore, - userID portainer.UserID, + userID database.UserID, endpointID database.EndpointID, - registry *portainer.Registry, + registry *registry.Registry, ) (hasPermission bool, err error) { user, err := dataStore.User().User(userID) if err != nil { @@ -37,10 +38,10 @@ func hasPermission( // GetAccessibleRegistry get the registry if the user has permission func GetAccessibleRegistry( dataStore dataservices.DataStore, - userID portainer.UserID, + userID database.UserID, endpointID database.EndpointID, - registryID portainer.RegistryID, -) (registry *portainer.Registry, err error) { + registryID registry.RegistryID, +) (registry *registry.Registry, err error) { registry, err = dataStore.Registry().Registry(registryID) if err != nil { diff --git a/api/internal/registryutils/auth_header.go b/api/internal/registryutils/auth_header.go index de5d3a999..a21b54ee4 100644 --- a/api/internal/registryutils/auth_header.go +++ b/api/internal/registryutils/auth_header.go @@ -3,7 +3,7 @@ package registryutils import ( "encoding/base64" "encoding/json" - portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/dataservices/registry" ) type ( @@ -15,7 +15,7 @@ type ( ) // GetRegistryAuthHeader generate the X-Registry-Auth header from registry -func GetRegistryAuthHeader(registry *portainer.Registry) (header string, err error) { +func GetRegistryAuthHeader(registry *registry.Registry) (header string, err error) { authHeader := authHeader{ ServerAddress: registry.URL, } diff --git a/api/internal/registryutils/ecr_kube_secret.go b/api/internal/registryutils/ecr_kube_secret.go index 4e6f818ba..783003cce 100644 --- a/api/internal/registryutils/ecr_kube_secret.go +++ b/api/internal/registryutils/ecr_kube_secret.go @@ -4,9 +4,10 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/dataservices" + "github.com/portainer/portainer/api/dataservices/registry" ) -func isRegistryAssignedToNamespace(registry portainer.Registry, endpointID database.EndpointID, namespace string) (in bool) { +func isRegistryAssignedToNamespace(registry registry.Registry, endpointID database.EndpointID, namespace string) (in bool) { for _, ns := range registry.RegistryAccesses[endpointID].Namespaces { if ns == namespace { return true diff --git a/api/internal/registryutils/ecr_reg_token.go b/api/internal/registryutils/ecr_reg_token.go index 0bfd8a616..c39bc0dff 100644 --- a/api/internal/registryutils/ecr_reg_token.go +++ b/api/internal/registryutils/ecr_reg_token.go @@ -1,6 +1,7 @@ package registryutils import ( + "github.com/portainer/portainer/api/dataservices/registry" "time" log "github.com/sirupsen/logrus" @@ -10,11 +11,11 @@ import ( "github.com/portainer/portainer/api/dataservices" ) -func isRegTokenValid(registry *portainer.Registry) (valid bool) { +func isRegTokenValid(registry *registry.Registry) (valid bool) { return registry.AccessToken != "" && registry.AccessTokenExpiry > time.Now().Unix() } -func doGetRegToken(dataStore dataservices.DataStore, registry *portainer.Registry) (err error) { +func doGetRegToken(dataStore dataservices.DataStore, registry *registry.Registry) (err error) { ecrClient := ecr.NewService(registry.Username, registry.Password, registry.Ecr.Region) accessToken, expiryAt, err := ecrClient.GetAuthorizationToken() if err != nil { @@ -29,12 +30,12 @@ func doGetRegToken(dataStore dataservices.DataStore, registry *portainer.Registr return } -func parseRegToken(registry *portainer.Registry) (username, password string, err error) { +func parseRegToken(registry *registry.Registry) (username, password string, err error) { ecrClient := ecr.NewService(registry.Username, registry.Password, registry.Ecr.Region) return ecrClient.ParseAuthorizationToken(registry.AccessToken) } -func EnsureRegTokenValid(dataStore dataservices.DataStore, registry *portainer.Registry) (err error) { +func EnsureRegTokenValid(dataStore dataservices.DataStore, registry *registry.Registry) (err error) { if registry.Type == portainer.EcrRegistry { if isRegTokenValid(registry) { log.Println("[DEBUG] [registry, GetEcrAccessToken] [message: curretn ECR token is still valid]") @@ -49,7 +50,7 @@ func EnsureRegTokenValid(dataStore dataservices.DataStore, registry *portainer.R return } -func GetRegEffectiveCredential(registry *portainer.Registry) (username, password string, err error) { +func GetRegEffectiveCredential(registry *registry.Registry) (username, password string, err error) { if registry.Type == portainer.EcrRegistry { username, password, err = parseRegToken(registry) } else { diff --git a/api/internal/testhelpers/datastore.go b/api/internal/testhelpers/datastore.go index 403150698..dadbb7a90 100644 --- a/api/internal/testhelpers/datastore.go +++ b/api/internal/testhelpers/datastore.go @@ -129,15 +129,15 @@ type stubUserService struct { } func (s *stubUserService) BucketName() string { return "users" } -func (s *stubUserService) User(ID portainer.UserID) (*portainer.User, error) { return nil, nil } +func (s *stubUserService) User(ID database.UserID) (*portainer.User, error) { return nil, nil } func (s *stubUserService) UserByUsername(username string) (*portainer.User, error) { return nil, nil } func (s *stubUserService) Users() ([]portainer.User, error) { return s.users, nil } func (s *stubUserService) UsersByRole(role portainer.UserRole) ([]portainer.User, error) { return s.users, nil } -func (s *stubUserService) Create(user *portainer.User) error { return nil } -func (s *stubUserService) UpdateUser(ID portainer.UserID, user *portainer.User) error { return nil } -func (s *stubUserService) DeleteUser(ID portainer.UserID) error { return nil } +func (s *stubUserService) Create(user *portainer.User) error { return nil } +func (s *stubUserService) UpdateUser(ID database.UserID, user *portainer.User) error { return nil } +func (s *stubUserService) DeleteUser(ID database.UserID) error { return nil } // WithUsers testDatastore option that will instruct testDatastore to return provided users func WithUsers(us []portainer.User) datastoreOption { diff --git a/api/jwt/jwt.go b/api/jwt/jwt.go index 283bff1b1..c910d26b8 100644 --- a/api/jwt/jwt.go +++ b/api/jwt/jwt.go @@ -3,6 +3,7 @@ package jwt import ( "errors" "fmt" + "github.com/portainer/portainer/api/database" "time" "github.com/dgrijalva/jwt-go" @@ -122,7 +123,7 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData, if err == nil && parsedToken != nil { if cl, ok := parsedToken.Claims.(*claims); ok && parsedToken.Valid { - user, err := service.dataStore.User().User(portainer.UserID(cl.UserID)) + user, err := service.dataStore.User().User(database.UserID(cl.UserID)) if err != nil { return nil, errInvalidJWTToken } @@ -130,7 +131,7 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData, return nil, errInvalidJWTToken } return &portainer.TokenData{ - ID: portainer.UserID(cl.UserID), + ID: database.UserID(cl.UserID), Username: cl.Username, Role: portainer.UserRole(cl.Role), }, nil diff --git a/api/kubernetes/cli/access.go b/api/kubernetes/cli/access.go index a510c73d8..c4edb67f0 100644 --- a/api/kubernetes/cli/access.go +++ b/api/kubernetes/cli/access.go @@ -3,6 +3,7 @@ package cli import ( "context" "encoding/json" + "github.com/portainer/portainer/api/database" "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" @@ -84,13 +85,13 @@ func (kcl *KubeClient) setupNamespaceAccesses(userID int, teamIDs []int, service } func hasUserAccessToNamespace(userID int, teamIDs []int, policies portainer.K8sNamespaceAccessPolicy) bool { - _, userAccess := policies.UserAccessPolicies[portainer.UserID(userID)] + _, userAccess := policies.UserAccessPolicies[database.UserID(userID)] if userAccess { return true } for _, teamID := range teamIDs { - _, teamAccess := policies.TeamAccessPolicies[portainer.TeamID(teamID)] + _, teamAccess := policies.TeamAccessPolicies[database.TeamID(teamID)] if teamAccess { return true } diff --git a/api/kubernetes/cli/access_test.go b/api/kubernetes/cli/access_test.go index db250546c..f3f28da19 100644 --- a/api/kubernetes/cli/access_test.go +++ b/api/kubernetes/cli/access_test.go @@ -2,6 +2,7 @@ package cli import ( "context" + "github.com/portainer/portainer/api/database" "sync" "testing" @@ -22,15 +23,15 @@ func Test_NamespaceAccessPoliciesDeleteNamespace_updatesPortainerConfig_whenConf name: "doesn't change config, when designated namespace absent", namespaceToDelete: "missing-namespace", expectedConfig: map[string]portainer.K8sNamespaceAccessPolicy{ - "ns1": {UserAccessPolicies: portainer.UserAccessPolicies{2: {RoleID: 0}}}, - "ns2": {UserAccessPolicies: portainer.UserAccessPolicies{2: {RoleID: 0}}}, + "ns1": {UserAccessPolicies: database.UserAccessPolicies{2: {RoleID: 0}}}, + "ns2": {UserAccessPolicies: database.UserAccessPolicies{2: {RoleID: 0}}}, }, }, { name: "removes designated namespace from config, when namespace is present", namespaceToDelete: "ns2", expectedConfig: map[string]portainer.K8sNamespaceAccessPolicy{ - "ns1": {UserAccessPolicies: portainer.UserAccessPolicies{2: {RoleID: 0}}}, + "ns1": {UserAccessPolicies: database.UserAccessPolicies{2: {RoleID: 0}}}, }, }, } diff --git a/api/kubernetes/cli/namespace_test.go b/api/kubernetes/cli/namespace_test.go index 9d3647877..8fbf9b536 100644 --- a/api/kubernetes/cli/namespace_test.go +++ b/api/kubernetes/cli/namespace_test.go @@ -2,6 +2,7 @@ package cli import ( "context" + "github.com/portainer/portainer/api/database" "strconv" "sync" "testing" @@ -173,7 +174,7 @@ func Test_ToggleSystemState(t *testing.T) { assert.Equal(t, "true", labelValue) expectedPolicies := map[string]portainer.K8sNamespaceAccessPolicy{ - "ns2": {UserAccessPolicies: portainer.UserAccessPolicies{2: {RoleID: 0}}}, + "ns2": {UserAccessPolicies: database.UserAccessPolicies{2: {RoleID: 0}}}, } actualPolicies, err := kcl.GetNamespaceAccessPolicies() assert.NoError(t, err, "failed to fetch policies") diff --git a/api/kubernetes/cli/registries.go b/api/kubernetes/cli/registries.go index ed6fb736c..daad042e9 100644 --- a/api/kubernetes/cli/registries.go +++ b/api/kubernetes/cli/registries.go @@ -4,10 +4,10 @@ import ( "context" "encoding/json" "fmt" + "github.com/portainer/portainer/api/dataservices/registry" "strconv" "github.com/pkg/errors" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/internal/registryutils" v1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -32,7 +32,7 @@ type ( } ) -func (kcl *KubeClient) DeleteRegistrySecret(registry *portainer.Registry, namespace string) error { +func (kcl *KubeClient) DeleteRegistrySecret(registry *registry.Registry, namespace string) error { err := kcl.cli.CoreV1().Secrets(namespace).Delete(context.TODO(), registrySecretName(registry), metav1.DeleteOptions{}) if err != nil && !k8serrors.IsNotFound(err) { return errors.Wrap(err, "failed removing secret") @@ -41,7 +41,7 @@ func (kcl *KubeClient) DeleteRegistrySecret(registry *portainer.Registry, namesp return nil } -func (kcl *KubeClient) CreateRegistrySecret(registry *portainer.Registry, namespace string) (err error) { +func (kcl *KubeClient) CreateRegistrySecret(registry *registry.Registry, namespace string) (err error) { username, password, err := registryutils.GetRegEffectiveCredential(registry) if err != nil { return @@ -103,6 +103,6 @@ func (cli *KubeClient) IsRegistrySecret(namespace, secretName string) (bool, err } -func registrySecretName(registry *portainer.Registry) string { +func registrySecretName(registry *registry.Registry) string { return fmt.Sprintf("registry-%d", registry.ID) } diff --git a/api/portainer.go b/api/portainer.go index b926c6477..20193cbbc 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -4,6 +4,7 @@ import ( "context" "github.com/portainer/portainer/api/database" "github.com/portainer/portainer/api/dataservices/edgejob" + "github.com/portainer/portainer/api/dataservices/registry" "io" "time" @@ -12,11 +13,6 @@ import ( ) type ( - // AccessPolicy represent a policy that can be associated to a user or team - AccessPolicy struct { - // Role identifier. Reference the role that will be associated to this access policy - RoleID RoleID `json:"RoleId" example:"1"` - } // AgentPlatform represents a platform type for an Agent AgentPlatform int @@ -142,7 +138,7 @@ type ( // Path to the Stack file EntryPoint string `json:"EntryPoint" example:"docker-compose.yml"` // User identifier who created this template - CreatedByUserID UserID `json:"CreatedByUserId" example:"3"` + CreatedByUserID database.UserID `json:"CreatedByUserId" example:"3"` // A note that will be displayed in the UI. Supports HTML content Note string `json:"Note" example:"This is my custom template"` // Platform associated to the template. @@ -263,9 +259,9 @@ type ( // Environment(Endpoint) group identifier GroupID EndpointGroupID `json:"GroupId" example:"1"` // URL or IP address where exposed containers will be reachable - PublicURL string `json:"PublicURL" example:"docker.mydomain.tld:2375"` - TLSConfig TLSConfiguration `json:"TLSConfig"` - AzureCredentials AzureCredentials `json:"AzureCredentials,omitempty" example:""` + PublicURL string `json:"PublicURL" example:"docker.mydomain.tld:2375"` + TLSConfig database.TLSConfiguration `json:"TLSConfig"` + AzureCredentials AzureCredentials `json:"AzureCredentials,omitempty" example:""` // List of tag identifiers to which this environment(endpoint) is associated TagIDs []TagID `json:"TagIds"` // The status of the environment(endpoint) (1 - up, 2 - down) @@ -273,9 +269,9 @@ type ( // List of snapshots Snapshots []DockerSnapshot `json:"Snapshots" example:""` // List of user identifiers authorized to connect to this environment(endpoint) - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` + UserAccessPolicies database.UserAccessPolicies `json:"UserAccessPolicies"` // List of team identifiers authorized to connect to this environment(endpoint) - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies" example:""` + TeamAccessPolicies database.TeamAccessPolicies `json:"TeamAccessPolicies" example:""` // The identifier of the edge agent associated with this environment(endpoint) EdgeID string `json:"EdgeID,omitempty" example:""` // The key which is used to map the agent to Portainer @@ -305,8 +301,8 @@ type ( TLSKeyPath string `json:"TLSKey,omitempty"` // Deprecated in DBVersion == 18 - AuthorizedUsers []UserID `json:"AuthorizedUsers"` - AuthorizedTeams []TeamID `json:"AuthorizedTeams"` + AuthorizedUsers []database.UserID `json:"AuthorizedUsers"` + AuthorizedTeams []database.TeamID `json:"AuthorizedTeams"` // Deprecated in DBVersion == 22 Tags []string `json:"Tags"` @@ -322,9 +318,9 @@ type ( // Environment(Endpoint) group name Name string `json:"Name" example:"my-environment-group"` // Description associated to the environment(endpoint) group - Description string `json:"Description" example:"Environment(Endpoint) group description"` - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies" example:""` - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies" example:""` + Description string `json:"Description" example:"Environment(Endpoint) group description"` + UserAccessPolicies database.UserAccessPolicies `json:"UserAccessPolicies" example:""` + TeamAccessPolicies database.TeamAccessPolicies `json:"TeamAccessPolicies" example:""` // List of tags associated to this environment(endpoint) group TagIDs []TagID `json:"TagIds"` @@ -332,8 +328,8 @@ type ( Labels []Pair `json:"Labels"` // Deprecated in DBVersion == 18 - AuthorizedUsers []UserID `json:"AuthorizedUsers"` - AuthorizedTeams []TeamID `json:"AuthorizedTeams"` + AuthorizedUsers []database.UserID `json:"AuthorizedUsers"` + AuthorizedTeams []database.TeamID `json:"AuthorizedTeams"` // Deprecated in DBVersion == 22 Tags []string `json:"Tags"` @@ -407,13 +403,6 @@ type ( // Feature represents a feature that can be enabled or disabled via feature flags Feature string - // GitlabRegistryData represents data required for gitlab registry to work - GitlabRegistryData struct { - ProjectID int `json:"ProjectId"` - InstanceURL string `json:"InstanceURL"` - ProjectPath string `json:"ProjectPath"` - } - HelmUserRepositoryID int // HelmUserRepositories stores a Helm repository URL for the given user @@ -421,22 +410,11 @@ type ( // Membership Identifier ID HelmUserRepositoryID `json:"Id" example:"1"` // User identifier - UserID UserID `json:"UserId" example:"1"` + UserID database.UserID `json:"UserId" example:"1"` // Helm repository URL URL string `json:"URL" example:"https://charts.bitnami.com/bitnami"` } - // QuayRegistryData represents data required for Quay registry to work - QuayRegistryData struct { - UseOrganisation bool `json:"UseOrganisation"` - OrganisationName string `json:"OrganisationName"` - } - - // EcrData represents data required for ECR registry - EcrData struct { - Region string `json:"Region" example:"ap-southeast-2"` - } - // JobType represents a job type JobType int @@ -448,8 +426,8 @@ type ( K8sNodesLimits map[string]*K8sNodeLimits K8sNamespaceAccessPolicy struct { - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"` + UserAccessPolicies database.UserAccessPolicies `json:"UserAccessPolicies"` + TeamAccessPolicies database.TeamAccessPolicies `json:"TeamAccessPolicies"` } // KubernetesData contains all the Kubernetes related environment(endpoint) information @@ -527,8 +505,8 @@ type ( // Password of the account that will be used to search users Password string `json:"Password,omitempty" example:"readonly-password"` // URL or IP address of the LDAP server - URL string `json:"URL" example:"myldap.domain.tld:389"` - TLSConfig TLSConfiguration `json:"TLSConfig"` + URL string `json:"URL" example:"myldap.domain.tld:389"` + TLSConfig database.TLSConfiguration `json:"TLSConfig"` // Whether LDAP connection should use StartTLS StartTLS bool `json:"StartTLS" example:"true"` SearchSettings []LDAPSearchSettings `json:"SearchSettings"` @@ -556,19 +534,19 @@ type ( // OAuthSettings represents the settings used to authorize with an authorization server OAuthSettings struct { - ClientID string `json:"ClientID"` - ClientSecret string `json:"ClientSecret,omitempty"` - AccessTokenURI string `json:"AccessTokenURI"` - AuthorizationURI string `json:"AuthorizationURI"` - ResourceURI string `json:"ResourceURI"` - RedirectURI string `json:"RedirectURI"` - UserIdentifier string `json:"UserIdentifier"` - Scopes string `json:"Scopes"` - OAuthAutoCreateUsers bool `json:"OAuthAutoCreateUsers"` - DefaultTeamID TeamID `json:"DefaultTeamID"` - SSO bool `json:"SSO"` - LogoutURI string `json:"LogoutURI"` - KubeSecretKey []byte `json:"KubeSecretKey"` + ClientID string `json:"ClientID"` + ClientSecret string `json:"ClientSecret,omitempty"` + AccessTokenURI string `json:"AccessTokenURI"` + AuthorizationURI string `json:"AuthorizationURI"` + ResourceURI string `json:"ResourceURI"` + RedirectURI string `json:"RedirectURI"` + UserIdentifier string `json:"UserIdentifier"` + Scopes string `json:"Scopes"` + OAuthAutoCreateUsers bool `json:"OAuthAutoCreateUsers"` + DefaultTeamID database.TeamID `json:"DefaultTeamID"` + SSO bool `json:"SSO"` + LogoutURI string `json:"LogoutURI"` + KubeSecretKey []byte `json:"KubeSecretKey"` } // Pair defines a key/value string pair @@ -577,74 +555,6 @@ type ( Value string `json:"value" example:"value"` } - // Registry represents a Docker registry with all the info required - // to connect to it - Registry struct { - // Registry Identifier - ID RegistryID `json:"Id" example:"1"` - // Registry Type (1 - Quay, 2 - Azure, 3 - Custom, 4 - Gitlab, 5 - ProGet, 6 - DockerHub, 7 - ECR) - Type RegistryType `json:"Type" enums:"1,2,3,4,5,6,7"` - // Registry Name - Name string `json:"Name" example:"my-registry"` - // URL or IP address of the Docker registry - URL string `json:"URL" example:"registry.mydomain.tld:2375"` - // Base URL, introduced for ProGet registry - BaseURL string `json:"BaseURL" example:"registry.mydomain.tld:2375"` - // Is authentication against this registry enabled - Authentication bool `json:"Authentication" example:"true"` - // Username or AccessKeyID used to authenticate against this registry - Username string `json:"Username" example:"registry user"` - // Password or SecretAccessKey used to authenticate against this registry - Password string `json:"Password,omitempty" example:"registry_password"` - ManagementConfiguration *RegistryManagementConfiguration `json:"ManagementConfiguration"` - Gitlab GitlabRegistryData `json:"Gitlab"` - Quay QuayRegistryData `json:"Quay"` - Ecr EcrData `json:"Ecr"` - RegistryAccesses RegistryAccesses `json:"RegistryAccesses"` - - // Deprecated fields - // Deprecated in DBVersion == 31 - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` - // Deprecated in DBVersion == 31 - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"` - - // Deprecated in DBVersion == 18 - AuthorizedUsers []UserID `json:"AuthorizedUsers"` - // Deprecated in DBVersion == 18 - AuthorizedTeams []TeamID `json:"AuthorizedTeams"` - - // Stores temporary access token - AccessToken string `json:"AccessToken,omitempty"` - AccessTokenExpiry int64 `json:"AccessTokenExpiry,omitempty"` - } - - RegistryAccesses map[database.EndpointID]RegistryAccessPolicies - - RegistryAccessPolicies struct { - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"` - Namespaces []string `json:"Namespaces"` - } - - // RegistryID represents a registry identifier - RegistryID int - - // RegistryManagementConfiguration represents a configuration that can be used to query - // the registry API via the registry management extension. - RegistryManagementConfiguration struct { - Type RegistryType `json:"Type"` - Authentication bool `json:"Authentication"` - Username string `json:"Username"` - Password string `json:"Password"` - TLSConfig TLSConfiguration `json:"TLSConfig"` - Ecr EcrData `json:"Ecr"` - AccessToken string `json:"AccessToken,omitempty"` - AccessTokenExpiry int64 `json:"AccessTokenExpiry,omitempty"` - } - - // RegistryType represents a type of registry - RegistryType int - // ResourceAccessLevel represents the level of control associated to a resource ResourceAccessLevel int @@ -670,7 +580,7 @@ type ( // Deprecated fields // Deprecated in DBVersion == 2 - OwnerID UserID `json:"OwnerId,omitempty"` + OwnerID database.UserID `json:"OwnerId,omitempty"` AccessLevel ResourceAccessLevel `json:"AccessLevel,omitempty"` } @@ -684,7 +594,7 @@ type ( // to a team. Role struct { // Role Identifier - ID RoleID `json:"Id" example:"1"` + ID database.RoleID `json:"Id" example:"1"` // Role name Name string `json:"Name" example:"HelpDesk"` // Role description @@ -694,21 +604,18 @@ type ( Priority int `json:"Priority"` } - // RoleID represents a role identifier - RoleID int - // APIKeyID represents an API key identifier APIKeyID int // APIKey represents an API key APIKey struct { - ID APIKeyID `json:"id" example:"1"` - UserID UserID `json:"userId" example:"1"` - Description string `json:"description" example:"portainer-api-key"` - Prefix string `json:"prefix"` // API key identifier (7 char prefix) - DateCreated int64 `json:"dateCreated"` // Unix timestamp (UTC) when the API key was created - LastUsed int64 `json:"lastUsed"` // Unix timestamp (UTC) when the API key was last used - Digest []byte `json:"digest,omitempty"` // Digest represents SHA256 hash of the raw API key + ID APIKeyID `json:"id" example:"1"` + UserID database.UserID `json:"userId" example:"1"` + Description string `json:"description" example:"portainer-api-key"` + Prefix string `json:"prefix"` // API key identifier (7 char prefix) + DateCreated int64 `json:"dateCreated"` // Unix timestamp (UTC) when the API key was created + LastUsed int64 `json:"lastUsed"` // Unix timestamp (UTC) when the API key was last used + Digest []byte `json:"digest,omitempty"` // Digest represents SHA256 hash of the raw API key } // Schedule represents a scheduled job. @@ -894,25 +801,19 @@ type ( // Team represents a list of user accounts Team struct { // Team Identifier - ID TeamID `json:"Id" example:"1"` + ID database.TeamID `json:"Id" example:"1"` // Team name Name string `json:"Name" example:"developers"` } - // TeamAccessPolicies represent the association of an access policy and a team - TeamAccessPolicies map[TeamID]AccessPolicy - - // TeamID represents a team identifier - TeamID int - // TeamMembership represents a membership association between a user and a team TeamMembership struct { // Membership Identifier ID TeamMembershipID `json:"Id" example:"1"` // User identifier - UserID UserID `json:"UserID" example:"1"` + UserID database.UserID `json:"UserID" example:"1"` // Team identifier - TeamID TeamID `json:"TeamID" example:"1"` + TeamID database.TeamID `json:"TeamID" example:"1"` // Team role (1 for team leader and 2 for team member) Role MembershipRole `json:"Role" example:"1"` } @@ -922,7 +823,7 @@ type ( // TeamResourceAccess represents the level of control on a resource for a specific team TeamResourceAccess struct { - TeamID TeamID `json:"TeamId"` + TeamID database.TeamID `json:"TeamId"` AccessLevel ResourceAccessLevel `json:"AccessLevel"` } @@ -1042,27 +943,13 @@ type ( ReadOnly bool `json:"readonly,omitempty" example:"true"` } - // TLSConfiguration represents a TLS configuration - TLSConfiguration struct { - // Use TLS - TLS bool `json:"TLS" example:"true"` - // Skip the verification of the server TLS certificate - TLSSkipVerify bool `json:"TLSSkipVerify" example:"false"` - // Path to the TLS CA certificate file - TLSCACertPath string `json:"TLSCACert,omitempty" example:"/data/tls/ca.pem"` - // Path to the TLS client certificate file - TLSCertPath string `json:"TLSCert,omitempty" example:"/data/tls/cert.pem"` - // Path to the TLS client key file - TLSKeyPath string `json:"TLSKey,omitempty" example:"/data/tls/key.pem"` - } - // TLSFileType represents a type of TLS file required to connect to a Docker environment(endpoint). // It can be either a TLS CA file, a TLS certificate file or a TLS key file TLSFileType int // TokenData represents the data embedded in a JWT token TokenData struct { - ID UserID + ID database.UserID Username string Role UserRole } @@ -1084,9 +971,9 @@ type ( // User represents a user account User struct { // User Identifier - ID UserID `json:"Id" example:"1"` - Username string `json:"Username" example:"bob"` - Password string `json:"Password,omitempty" swaggerignore:"true"` + ID database.UserID `json:"Id" example:"1"` + Username string `json:"Username" example:"bob"` + Password string `json:"Password,omitempty" swaggerignore:"true"` // User Theme UserTheme string `example:"dark"` // User role (1 for administrator account and 2 for regular account) @@ -1099,15 +986,9 @@ type ( EndpointAuthorizations EndpointAuthorizations `json:"EndpointAuthorizations"` } - // UserAccessPolicies represent the association of an access policy and a user - UserAccessPolicies map[UserID]AccessPolicy - - // UserID represents a user identifier - UserID int - // UserResourceAccess represents the level of control on a resource for a specific user UserResourceAccess struct { - UserID UserID `json:"UserId"` + UserID database.UserID `json:"UserId"` AccessLevel ResourceAccessLevel `json:"AccessLevel"` } @@ -1122,7 +1003,7 @@ type ( Token string `json:"Token"` ResourceID string `json:"ResourceId"` EndpointID database.EndpointID `json:"EndpointId"` - RegistryID RegistryID `json:"RegistryId"` + RegistryID registry.RegistryID `json:"RegistryId"` WebhookType WebhookType `json:"Type"` } @@ -1228,16 +1109,16 @@ type ( GetNodesLimits() (K8sNodesLimits, error) GetNamespaceAccessPolicies() (map[string]K8sNamespaceAccessPolicy, error) UpdateNamespaceAccessPolicies(accessPolicies map[string]K8sNamespaceAccessPolicy) error - DeleteRegistrySecret(registry *Registry, namespace string) error - CreateRegistrySecret(registry *Registry, namespace string) error + DeleteRegistrySecret(registry *registry.Registry, namespace string) error + CreateRegistrySecret(registry *registry.Registry, namespace string) error IsRegistrySecret(namespace, secretName string) (bool, error) ToggleSystemState(namespace string, isSystem bool) error } // KubernetesDeployer represents a service to deploy a manifest inside a Kubernetes environment(endpoint) KubernetesDeployer interface { - Deploy(userID UserID, endpoint *Endpoint, manifestFiles []string, namespace string) (string, error) - Remove(userID UserID, endpoint *Endpoint, manifestFiles []string, namespace string) (string, error) + Deploy(userID database.UserID, endpoint *Endpoint, manifestFiles []string, namespace string) (string, error) + Remove(userID database.UserID, endpoint *Endpoint, manifestFiles []string, namespace string) (string, error) ConvertCompose(data []byte) ([]byte, error) } @@ -1290,7 +1171,7 @@ type ( // SwarmStackManager represents a service to manage Swarm stacks SwarmStackManager interface { - Login(registries []Registry, endpoint *Endpoint) error + Login(registries []registry.Registry, endpoint *Endpoint) error Logout(endpoint *Endpoint) error Deploy(stack *Stack, prune bool, endpoint *Endpoint) error Remove(stack *Stack, endpoint *Endpoint) error @@ -1453,7 +1334,7 @@ const ( ) const ( - _ RegistryType = iota + _ registry.RegistryType = iota // QuayRegistry represents a Quay.io registry QuayRegistry // AzureRegistry represents an ACR registry diff --git a/api/stacks/deploy.go b/api/stacks/deploy.go index 8e8371279..0ad5835a5 100644 --- a/api/stacks/deploy.go +++ b/api/stacks/deploy.go @@ -3,6 +3,7 @@ package stacks import ( "fmt" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "strings" "time" @@ -118,7 +119,7 @@ func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, data return nil } -func getUserRegistries(datastore dataservices.DataStore, user *portainer.User, endpointID database.EndpointID) ([]portainer.Registry, error) { +func getUserRegistries(datastore dataservices.DataStore, user *portainer.User, endpointID database.EndpointID) ([]registry.Registry, error) { registries, err := datastore.Registry().Registries() if err != nil { return nil, errors.WithMessage(err, "unable to retrieve registries from the database") @@ -133,7 +134,7 @@ func getUserRegistries(datastore dataservices.DataStore, user *portainer.User, e return nil, errors.WithMessagef(err, "failed to fetch memberships of the stack author [%s]", user.Username) } - filteredRegistries := make([]portainer.Registry, 0, len(registries)) + filteredRegistries := make([]registry.Registry, 0, len(registries)) for _, registry := range registries { if security.AuthorizedRegistryAccess(®istry, user, userMemberships, endpointID) { filteredRegistries = append(filteredRegistries, registry) diff --git a/api/stacks/deploy_test.go b/api/stacks/deploy_test.go index 9cba28993..38dfec4dd 100644 --- a/api/stacks/deploy_test.go +++ b/api/stacks/deploy_test.go @@ -3,6 +3,7 @@ package stacks import ( "errors" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/dataservices/registry" "io/ioutil" "strings" "testing" @@ -29,11 +30,11 @@ func (g *gitService) LatestCommitID(repositoryURL, referenceName, username, pass type noopDeployer struct{} -func (s *noopDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool) error { +func (s *noopDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []registry.Registry, prune bool) error { return nil } -func (s *noopDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forceRereate bool) error { +func (s *noopDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []registry.Registry, forceRereate bool) error { return nil } @@ -188,13 +189,13 @@ func Test_getUserRegistries(t *testing.T) { Role: portainer.TeamMember, }) - registryReachableByUser := portainer.Registry{ + registryReachableByUser := registry.Registry{ ID: 1, Name: "registryReachableByUser", - RegistryAccesses: portainer.RegistryAccesses{ + RegistryAccesses: registry.RegistryAccesses{ database.EndpointID(endpointID): { - UserAccessPolicies: map[portainer.UserID]portainer.AccessPolicy{ - user.ID: {RoleID: portainer.RoleID(portainer.StandardUserRole)}, + UserAccessPolicies: map[database.UserID]database.AccessPolicy{ + user.ID: {RoleID: database.RoleID(portainer.StandardUserRole)}, }, }, }, @@ -202,13 +203,13 @@ func Test_getUserRegistries(t *testing.T) { err = store.Registry().Create(®istryReachableByUser) assert.NoError(t, err, "couldn't create a registry") - registryReachableByTeam := portainer.Registry{ + registryReachableByTeam := registry.Registry{ ID: 2, Name: "registryReachableByTeam", - RegistryAccesses: portainer.RegistryAccesses{ + RegistryAccesses: registry.RegistryAccesses{ database.EndpointID(endpointID): { - TeamAccessPolicies: map[portainer.TeamID]portainer.AccessPolicy{ - team.ID: {RoleID: portainer.RoleID(portainer.StandardUserRole)}, + TeamAccessPolicies: map[database.TeamID]database.AccessPolicy{ + team.ID: {RoleID: database.RoleID(portainer.StandardUserRole)}, }, }, }, @@ -216,13 +217,13 @@ func Test_getUserRegistries(t *testing.T) { err = store.Registry().Create(®istryReachableByTeam) assert.NoError(t, err, "couldn't create a registry") - registryRestricted := portainer.Registry{ + registryRestricted := registry.Registry{ ID: 3, Name: "registryRestricted", - RegistryAccesses: portainer.RegistryAccesses{ + RegistryAccesses: registry.RegistryAccesses{ database.EndpointID(endpointID): { - UserAccessPolicies: map[portainer.UserID]portainer.AccessPolicy{ - user.ID + 100: {RoleID: portainer.RoleID(portainer.StandardUserRole)}, + UserAccessPolicies: map[database.UserID]database.AccessPolicy{ + user.ID + 100: {RoleID: database.RoleID(portainer.StandardUserRole)}, }, }, }, @@ -233,12 +234,12 @@ func Test_getUserRegistries(t *testing.T) { t.Run("admin should has access to all registries", func(t *testing.T) { registries, err := getUserRegistries(store, admin, database.EndpointID(endpointID)) assert.NoError(t, err) - assert.ElementsMatch(t, []portainer.Registry{registryReachableByUser, registryReachableByTeam, registryRestricted}, registries) + assert.ElementsMatch(t, []registry.Registry{registryReachableByUser, registryReachableByTeam, registryRestricted}, registries) }) t.Run("regular user has access to registries allowed to him and/or his team", func(t *testing.T) { registries, err := getUserRegistries(store, user, database.EndpointID(endpointID)) assert.NoError(t, err) - assert.ElementsMatch(t, []portainer.Registry{registryReachableByUser, registryReachableByTeam}, registries) + assert.ElementsMatch(t, []registry.Registry{registryReachableByUser, registryReachableByTeam}, registries) }) } diff --git a/api/stacks/deployer.go b/api/stacks/deployer.go index 80bd86384..ec411508f 100644 --- a/api/stacks/deployer.go +++ b/api/stacks/deployer.go @@ -2,6 +2,7 @@ package stacks import ( "context" + "github.com/portainer/portainer/api/dataservices/registry" "os" "sync" @@ -13,8 +14,8 @@ import ( ) type StackDeployer interface { - DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool) error - DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forceRereate bool) error + DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []registry.Registry, prune bool) error + DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []registry.Registry, forceRereate bool) error DeployKubernetesStack(stack *portainer.Stack, endpoint *portainer.Endpoint, user *portainer.User) error } @@ -35,7 +36,7 @@ func NewStackDeployer(swarmStackManager portainer.SwarmStackManager, composeStac } } -func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool) error { +func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []registry.Registry, prune bool) error { d.lock.Lock() defer d.lock.Unlock() @@ -45,7 +46,7 @@ func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *porta return d.swarmStackManager.Deploy(stack, prune, endpoint) } -func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forceRereate bool) error { +func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []registry.Registry, forceRereate bool) error { d.lock.Lock() defer d.lock.Unlock()