mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29:41 +02:00
chore(code): clean up the code EE-5719 (#9183)
This commit is contained in:
parent
979af5301e
commit
64b227b2e1
24 changed files with 93 additions and 87 deletions
|
@ -18,6 +18,7 @@ func (service *Service) AddEdgeJob(endpoint *portainer.Endpoint, edgeJob *portai
|
||||||
for idx, existingJob := range tunnel.Jobs {
|
for idx, existingJob := range tunnel.Jobs {
|
||||||
if existingJob.ID == edgeJob.ID {
|
if existingJob.ID == edgeJob.ID {
|
||||||
existingJobIndex = idx
|
existingJobIndex = idx
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService port
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
func initComposeStackManager(composeDeployer libstack.Deployer, reverseTunnelService portainer.ReverseTunnelService, proxyManager *proxy.Manager) portainer.ComposeStackManager {
|
func initComposeStackManager(composeDeployer libstack.Deployer, proxyManager *proxy.Manager) portainer.ComposeStackManager {
|
||||||
composeWrapper, err := exec.NewComposeStackManager(composeDeployer, proxyManager)
|
composeWrapper, err := exec.NewComposeStackManager(composeDeployer, proxyManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("failed creating compose manager")
|
log.Fatal().Err(err).Msg("failed creating compose manager")
|
||||||
|
@ -458,7 +458,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
|
||||||
log.Fatal().Err(err).Msg("failed initializing compose deployer")
|
log.Fatal().Err(err).Msg("failed initializing compose deployer")
|
||||||
}
|
}
|
||||||
|
|
||||||
composeStackManager := initComposeStackManager(composeDeployer, reverseTunnelService, proxyManager)
|
composeStackManager := initComposeStackManager(composeDeployer, proxyManager)
|
||||||
|
|
||||||
swarmStackManager, err := initSwarmStackManager(*flags.Assets, dockerConfigPath, digitalSignatureService, fileService, reverseTunnelService, dataStore)
|
swarmStackManager, err := initSwarmStackManager(*flags.Assets, dockerConfigPath, digitalSignatureService, fileService, reverseTunnelService, dataStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -66,6 +66,7 @@ func (service ServiceTx) DeleteEndpoint(ID portainer.EndpointID) error {
|
||||||
for edgeID, endpointID := range service.service.idxEdgeID {
|
for edgeID, endpointID := range service.service.idxEdgeID {
|
||||||
if endpointID == ID {
|
if endpointID == ID {
|
||||||
delete(service.service.idxEdgeID, edgeID)
|
delete(service.service.idxEdgeID, edgeID)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,6 @@ func (m *Migrator) migrateDockerDesktopExtentionSetting() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.IsDockerDesktopExtension = isDDExtension
|
settings.IsDockerDesktopExtension = isDDExtension
|
||||||
err = m.settingsService.UpdateSettings(settings)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return m.settingsService.UpdateSettings(settings)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,11 @@ package migrator
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/portainer/portainer/api/dataservices/edgejob"
|
|
||||||
"github.com/portainer/portainer/api/dataservices/edgestack"
|
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/database/models"
|
"github.com/portainer/portainer/api/database/models"
|
||||||
"github.com/portainer/portainer/api/dataservices/dockerhub"
|
"github.com/portainer/portainer/api/dataservices/dockerhub"
|
||||||
|
"github.com/portainer/portainer/api/dataservices/edgejob"
|
||||||
|
"github.com/portainer/portainer/api/dataservices/edgestack"
|
||||||
"github.com/portainer/portainer/api/dataservices/endpoint"
|
"github.com/portainer/portainer/api/dataservices/endpoint"
|
||||||
"github.com/portainer/portainer/api/dataservices/endpointgroup"
|
"github.com/portainer/portainer/api/dataservices/endpointgroup"
|
||||||
"github.com/portainer/portainer/api/dataservices/endpointrelation"
|
"github.com/portainer/portainer/api/dataservices/endpointrelation"
|
||||||
|
@ -29,6 +25,9 @@ import (
|
||||||
"github.com/portainer/portainer/api/dataservices/user"
|
"github.com/portainer/portainer/api/dataservices/user"
|
||||||
"github.com/portainer/portainer/api/dataservices/version"
|
"github.com/portainer/portainer/api/dataservices/version"
|
||||||
"github.com/portainer/portainer/api/internal/authorization"
|
"github.com/portainer/portainer/api/internal/authorization"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
|
@ -4,22 +4,19 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/patrickmn/go-cache"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/dataservices"
|
"github.com/portainer/portainer/api/dataservices"
|
||||||
"github.com/portainer/portainer/api/internal/registryutils"
|
"github.com/portainer/portainer/api/internal/registryutils"
|
||||||
|
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var registriesCache = cache.New(5*time.Minute, 5*time.Minute)
|
||||||
_registriesCache = cache.New(5*time.Minute, 5*time.Minute)
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
type RegistryClient struct {
|
||||||
RegistryClient struct {
|
dataStore dataservices.DataStore
|
||||||
dataStore dataservices.DataStore
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewRegistryClient(dataStore dataservices.DataStore) *RegistryClient {
|
func NewRegistryClient(dataStore dataservices.DataStore) *RegistryClient {
|
||||||
return &RegistryClient{dataStore: dataStore}
|
return &RegistryClient{dataStore: dataStore}
|
||||||
|
@ -130,12 +127,14 @@ func findBestMatchRegistry(repository string, registries []portainer.Registry) (
|
||||||
if match == nil {
|
if match == nil {
|
||||||
return nil, errors.New("no registries matched")
|
return nil, errors.New("no registries matched")
|
||||||
}
|
}
|
||||||
_registriesCache.Set(repository, match, 0)
|
|
||||||
|
registriesCache.Set(repository, match, 0)
|
||||||
|
|
||||||
return match, nil
|
return match, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cachedRegistry(cacheKey string) (*portainer.Registry, error) {
|
func cachedRegistry(cacheKey string) (*portainer.Registry, error) {
|
||||||
r, ok := _registriesCache.Get(cacheKey)
|
r, ok := registriesCache.Get(cacheKey)
|
||||||
if ok {
|
if ok {
|
||||||
registry, ok := r.(portainer.Registry)
|
registry, ok := r.(portainer.Registry)
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
@ -7,12 +7,12 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/opencontainers/go-digest"
|
|
||||||
"github.com/patrickmn/go-cache"
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
consts "github.com/portainer/portainer/api/docker/consts"
|
consts "github.com/portainer/portainer/api/docker/consts"
|
||||||
"github.com/portainer/portainer/api/internal/slices"
|
"github.com/portainer/portainer/api/internal/slices"
|
||||||
|
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
@ -40,6 +40,7 @@ func (c *DigestClient) ContainersImageStatus(ctx context.Context, containers []t
|
||||||
cli, err := c.clientFactory.CreateClient(endpoint, "", nil)
|
cli, err := c.clientFactory.CreateClient(endpoint, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("cannot create docker client")
|
log.Error().Err(err).Msg("cannot create docker client")
|
||||||
|
|
||||||
return Error
|
return Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,15 @@ import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
"io"
|
"github.com/gofrs/uuid"
|
||||||
"os"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -327,7 +327,7 @@ func (service *Service) GetEdgeStackProjectPathByVersion(edgeStackIdentifier str
|
||||||
}
|
}
|
||||||
|
|
||||||
if commitHash != "" {
|
if commitHash != "" {
|
||||||
versionStr = fmt.Sprintf("%s", commitHash)
|
versionStr = commitHash
|
||||||
}
|
}
|
||||||
|
|
||||||
return JoinPaths(service.wrapFileStore(EdgeStackStorePath), edgeStackIdentifier, versionStr)
|
return JoinPaths(service.wrapFileStore(EdgeStackStorePath), edgeStackIdentifier, versionStr)
|
||||||
|
@ -367,7 +367,7 @@ func (service *Service) FormProjectPathByVersion(path string, version int, commi
|
||||||
}
|
}
|
||||||
|
|
||||||
if commitHash != "" {
|
if commitHash != "" {
|
||||||
versionStr = fmt.Sprintf("%s", commitHash)
|
versionStr = commitHash
|
||||||
}
|
}
|
||||||
|
|
||||||
return JoinPaths(path, versionStr)
|
return JoinPaths(path, versionStr)
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var content = []byte("content")
|
||||||
|
|
||||||
func Test_movePath_shouldFailIfSourceDirDoesNotExist(t *testing.T) {
|
func Test_movePath_shouldFailIfSourceDirDoesNotExist(t *testing.T) {
|
||||||
sourceDir := "missing"
|
sourceDir := "missing"
|
||||||
destinationDir := t.TempDir()
|
destinationDir := t.TempDir()
|
||||||
|
@ -52,8 +54,6 @@ func Test_movePath_successWhenSourceExistsAndDestinationIsMissing(t *testing.T)
|
||||||
assertFileContent(t, path.Join(destinationDir, "dir", "file"))
|
assertFileContent(t, path.Join(destinationDir, "dir", "file"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var content []byte = []byte("content")
|
|
||||||
|
|
||||||
func addFile(fileParts ...string) (filepath string) {
|
func addFile(fileParts ...string) (filepath string) {
|
||||||
if len(fileParts) > 2 {
|
if len(fileParts) > 2 {
|
||||||
dir := path.Join(fileParts[:len(fileParts)-1]...)
|
dir := path.Join(fileParts[:len(fileParts)-1]...)
|
||||||
|
@ -62,6 +62,7 @@ func addFile(fileParts ...string) (filepath string) {
|
||||||
|
|
||||||
p := path.Join(fileParts...)
|
p := path.Join(fileParts...)
|
||||||
os.WriteFile(p, content, 0766)
|
os.WriteFile(p, content, 0766)
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/portainer/portainer/api/archive"
|
||||||
|
gittypes "github.com/portainer/portainer/api/git/types"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/portainer/portainer/api/archive"
|
|
||||||
gittypes "github.com/portainer/portainer/api/git/types"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/portainer/libhttp/response"
|
"github.com/portainer/libhttp/response"
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/stacks/stackutils"
|
"github.com/portainer/portainer/api/stacks/stackutils"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,10 +69,12 @@ func (handler *Handler) customTemplateGitFetch(w http.ResponseWriter, r *http.Re
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msg("failed to download git repository")
|
log.Warn().Err(err).Msg("failed to download git repository")
|
||||||
rbErr := rollbackCustomTemplate(backupPath, customTemplate.ProjectPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
rbErr := rollbackCustomTemplate(backupPath, customTemplate.ProjectPath)
|
||||||
return httperror.InternalServerError("Failed to rollback the custom template folder", rbErr)
|
return httperror.InternalServerError("Failed to rollback the custom template folder", rbErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return httperror.InternalServerError("Failed to download git repository", err)
|
return httperror.InternalServerError("Failed to download git repository", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,11 +107,7 @@ func backupCustomTemplate(projectPath string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Mkdir(projectPath, stat.Mode())
|
return backupPath, os.Mkdir(projectPath, stat.Mode())
|
||||||
if err != nil {
|
|
||||||
return backupPath, err
|
|
||||||
}
|
|
||||||
return backupPath, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func rollbackCustomTemplate(backupPath, projectPath string) error {
|
func rollbackCustomTemplate(backupPath, projectPath string) error {
|
||||||
|
@ -116,6 +115,7 @@ func rollbackCustomTemplate(backupPath, projectPath string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.Rename(backupPath, projectPath)
|
return os.Rename(backupPath, projectPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testFileContent string = "abcdefg"
|
var testFileContent = "abcdefg"
|
||||||
|
|
||||||
type TestGitService struct {
|
type TestGitService struct {
|
||||||
portainer.GitService
|
portainer.GitService
|
||||||
|
@ -32,6 +32,7 @@ type TestGitService struct {
|
||||||
|
|
||||||
func (g *TestGitService) CloneRepository(destination string, repositoryURL, referenceName string, username, password string, tlsSkipVerify bool) error {
|
func (g *TestGitService) CloneRepository(destination string, repositoryURL, referenceName string, username, password string, tlsSkipVerify bool) error {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
return createTestFile(g.targetFilePath)
|
return createTestFile(g.targetFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +54,9 @@ func createTestFile(targetPath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
_, err = f.WriteString(testFileContent)
|
_, err = f.WriteString(testFileContent)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +155,7 @@ func Test_customTemplateGitFetch(t *testing.T) {
|
||||||
wg.Add(10)
|
wg.Add(10)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
go func(j int) {
|
go func(j int) {
|
||||||
if j%1 == 0 {
|
if j%2 == 0 {
|
||||||
singleAPIRequest(h, jwt1, is, "abcdefg")
|
singleAPIRequest(h, jwt1, is, "abcdefg")
|
||||||
} else {
|
} else {
|
||||||
singleAPIRequest(h, jwt2, is, "abcdefg")
|
singleAPIRequest(h, jwt2, is, "abcdefg")
|
||||||
|
|
|
@ -38,6 +38,7 @@ func (handler *Handler) getKubernetesConfig(w http.ResponseWriter, r *http.Reque
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperror.Forbidden("Permission denied to access environment", err)
|
return httperror.Forbidden("Permission denied to access environment", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bearerToken, err := handler.JwtService.GenerateTokenForKubeconfig(tokenData)
|
bearerToken, err := handler.JwtService.GenerateTokenForKubeconfig(tokenData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperror.InternalServerError("Unable to generate JWT token", err)
|
return httperror.InternalServerError("Unable to generate JWT token", err)
|
||||||
|
@ -47,14 +48,12 @@ func (handler *Handler) getKubernetesConfig(w http.ResponseWriter, r *http.Reque
|
||||||
if handlerErr != nil {
|
if handlerErr != nil {
|
||||||
return handlerErr
|
return handlerErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(endpoints) == 0 {
|
if len(endpoints) == 0 {
|
||||||
return httperror.BadRequest("empty endpoints list", errors.New("empty endpoints list"))
|
return httperror.BadRequest("empty endpoints list", errors.New("empty endpoints list"))
|
||||||
}
|
}
|
||||||
|
|
||||||
config, handlerErr := handler.buildConfig(r, tokenData, bearerToken, endpoints, false)
|
config := handler.buildConfig(r, tokenData, bearerToken, endpoints, false)
|
||||||
if handlerErr != nil {
|
|
||||||
return handlerErr
|
|
||||||
}
|
|
||||||
|
|
||||||
return writeFileContent(w, r, endpoints, tokenData, config)
|
return writeFileContent(w, r, endpoints, tokenData, config)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +91,9 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
|
||||||
}
|
}
|
||||||
endpoints = append(endpoints, *endpoint)
|
endpoints = append(endpoints, *endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredEndpoints := security.FilterEndpoints(endpoints, endpointGroups, securityContext)
|
filteredEndpoints := security.FilterEndpoints(endpoints, endpointGroups, securityContext)
|
||||||
|
|
||||||
return filteredEndpoints, nil
|
return filteredEndpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +102,12 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httperror.InternalServerError("Unable to retrieve environments from the database", err)
|
return nil, httperror.InternalServerError("Unable to retrieve environments from the database", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, endpoint := range endpoints {
|
for _, endpoint := range endpoints {
|
||||||
if !endpointutils.IsKubernetesEndpoint(&endpoint) {
|
if !endpointutils.IsKubernetesEndpoint(&endpoint) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeEndpoints = append(kubeEndpoints, endpoint)
|
kubeEndpoints = append(kubeEndpoints, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,13 +115,15 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
|
||||||
if len(excludeEndpointIDs) > 0 {
|
if len(excludeEndpointIDs) > 0 {
|
||||||
filteredEndpoints = endpointutils.FilterByExcludeIDs(filteredEndpoints, excludeEndpointIDs)
|
filteredEndpoints = endpointutils.FilterByExcludeIDs(filteredEndpoints, excludeEndpointIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredEndpoints, nil
|
return filteredEndpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenData, bearerToken string, endpoints []portainer.Endpoint, isInternal bool) (*clientV1.Config, *httperror.HandlerError) {
|
func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenData, bearerToken string, endpoints []portainer.Endpoint, isInternal bool) *clientV1.Config {
|
||||||
|
var configAuthInfos []clientV1.NamedAuthInfo
|
||||||
|
|
||||||
configClusters := make([]clientV1.NamedCluster, len(endpoints))
|
configClusters := make([]clientV1.NamedCluster, len(endpoints))
|
||||||
configContexts := make([]clientV1.NamedContext, len(endpoints))
|
configContexts := make([]clientV1.NamedContext, len(endpoints))
|
||||||
var configAuthInfos []clientV1.NamedAuthInfo
|
|
||||||
authInfosSet := make(map[string]bool)
|
authInfosSet := make(map[string]bool)
|
||||||
|
|
||||||
for idx, endpoint := range endpoints {
|
for idx, endpoint := range endpoints {
|
||||||
|
@ -127,6 +132,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
|
||||||
|
|
||||||
configClusters[idx] = handler.buildCluster(r, endpoint, isInternal)
|
configClusters[idx] = handler.buildCluster(r, endpoint, isInternal)
|
||||||
configContexts[idx] = buildContext(serviceAccountName, endpoint)
|
configContexts[idx] = buildContext(serviceAccountName, endpoint)
|
||||||
|
|
||||||
if !authInfosSet[serviceAccountName] {
|
if !authInfosSet[serviceAccountName] {
|
||||||
configAuthInfos = append(configAuthInfos, buildAuthInfo(serviceAccountName, bearerToken))
|
configAuthInfos = append(configAuthInfos, buildAuthInfo(serviceAccountName, bearerToken))
|
||||||
authInfosSet[serviceAccountName] = true
|
authInfosSet[serviceAccountName] = true
|
||||||
|
@ -140,7 +146,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
|
||||||
Contexts: configContexts,
|
Contexts: configContexts,
|
||||||
CurrentContext: configContexts[0].Name,
|
CurrentContext: configContexts[0].Name,
|
||||||
AuthInfos: configAuthInfos,
|
AuthInfos: configAuthInfos,
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildCluster builds a Kubernetes cluster configuration based on the endpoint and if it's used internally or externally.
|
// buildCluster builds a Kubernetes cluster configuration based on the endpoint and if it's used internally or externally.
|
||||||
|
|
|
@ -166,22 +166,13 @@ func (handler *Handler) kubeClient(next http.Handler) http.Handler {
|
||||||
singleEndpointList := []portainer.Endpoint{
|
singleEndpointList := []portainer.Endpoint{
|
||||||
*endpoint,
|
*endpoint,
|
||||||
}
|
}
|
||||||
config, handlerErr := handler.buildConfig(
|
config := handler.buildConfig(
|
||||||
r,
|
r,
|
||||||
tokenData,
|
tokenData,
|
||||||
bearerToken,
|
bearerToken,
|
||||||
singleEndpointList,
|
singleEndpointList,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
httperror.WriteError(
|
|
||||||
w,
|
|
||||||
http.StatusInternalServerError,
|
|
||||||
"Unable to build endpoint kubeconfig",
|
|
||||||
handlerErr.Err,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(config.Clusters) == 0 {
|
if len(config.Clusters) == 0 {
|
||||||
httperror.WriteError(
|
httperror.WriteError(
|
||||||
|
|
|
@ -59,9 +59,11 @@ func (r K8sIngressInfo) Validate(request *http.Request) error {
|
||||||
if r.Name == "" {
|
if r.Name == "" {
|
||||||
return errors.New("missing ingress name from the request payload")
|
return errors.New("missing ingress name from the request payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Namespace == "" {
|
if r.Namespace == "" {
|
||||||
return errors.New("missing ingress Namespace from the request payload")
|
return errors.New("missing ingress Namespace from the request payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +71,12 @@ func (r K8sIngressDeleteRequests) Validate(request *http.Request) error {
|
||||||
if len(r) == 0 {
|
if len(r) == 0 {
|
||||||
return errors.New("missing deletion request list in payload")
|
return errors.New("missing deletion request list in payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
for ns := range r {
|
for ns := range r {
|
||||||
if len(ns) == 0 {
|
if len(ns) == 0 {
|
||||||
return errors.New("deletion given with empty namespace")
|
return errors.New("deletion given with empty namespace")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,15 @@ func (s *K8sServiceInfo) Validate(request *http.Request) error {
|
||||||
if s.Name == "" {
|
if s.Name == "" {
|
||||||
return errors.New("missing service name from the request payload")
|
return errors.New("missing service name from the request payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Namespace == "" {
|
if s.Namespace == "" {
|
||||||
return errors.New("missing service namespace from the request payload")
|
return errors.New("missing service namespace from the request payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Ports == nil {
|
if s.Ports == nil {
|
||||||
return errors.New("missing service ports from the request payload")
|
return errors.New("missing service ports from the request payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,10 +64,12 @@ func (r K8sServiceDeleteRequests) Validate(request *http.Request) error {
|
||||||
if len(r) == 0 {
|
if len(r) == 0 {
|
||||||
return errors.New("missing deletion request list in payload")
|
return errors.New("missing deletion request list in payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
for ns := range r {
|
for ns := range r {
|
||||||
if len(ns) == 0 {
|
if len(ns) == 0 {
|
||||||
return errors.New("deletion given with empty namespace")
|
return errors.New("deletion given with empty namespace")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ func (transport *baseTransport) proxyDeploymentsRequest(request *http.Request, n
|
||||||
switch request.Method {
|
switch request.Method {
|
||||||
case http.MethodPost, http.MethodPatch:
|
case http.MethodPost, http.MethodPatch:
|
||||||
transport.refreshRegistry(request, namespace)
|
transport.refreshRegistry(request, namespace)
|
||||||
return transport.executeKubernetesRequest(request)
|
|
||||||
default:
|
|
||||||
return transport.executeKubernetesRequest(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return transport.executeKubernetesRequest(request)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (transport *baseTransport) proxyPodsRequest(request *http.Request, namespace, requestPath string) (*http.Response, error) {
|
func (transport *baseTransport) proxyPodsRequest(request *http.Request, namespace, requestPath string) (*http.Response, error) {
|
||||||
switch request.Method {
|
if request.Method == http.MethodDelete {
|
||||||
case "DELETE":
|
|
||||||
transport.refreshRegistry(request, namespace)
|
transport.refreshRegistry(request, namespace)
|
||||||
return transport.executeKubernetesRequest(request)
|
|
||||||
default:
|
|
||||||
return transport.executeKubernetesRequest(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return transport.executeKubernetesRequest(request)
|
||||||
}
|
}
|
||||||
|
|
|
@ -508,18 +508,21 @@ func getUserEndpointAuthorizations(user *portainer.User, endpoints []portainer.E
|
||||||
authorizations := getAuthorizationsFromUserEndpointPolicy(user, &endpoint, roles)
|
authorizations := getAuthorizationsFromUserEndpointPolicy(user, &endpoint, roles)
|
||||||
if len(authorizations) > 0 {
|
if len(authorizations) > 0 {
|
||||||
endpointAuthorizations[endpoint.ID] = authorizations
|
endpointAuthorizations[endpoint.ID] = authorizations
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizations = getAuthorizationsFromUserEndpointGroupPolicy(user, &endpoint, roles, groupUserAccessPolicies)
|
authorizations = getAuthorizationsFromUserEndpointGroupPolicy(user, &endpoint, roles, groupUserAccessPolicies)
|
||||||
if len(authorizations) > 0 {
|
if len(authorizations) > 0 {
|
||||||
endpointAuthorizations[endpoint.ID] = authorizations
|
endpointAuthorizations[endpoint.ID] = authorizations
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizations = getAuthorizationsFromTeamEndpointPolicies(userMemberships, &endpoint, roles)
|
authorizations = getAuthorizationsFromTeamEndpointPolicies(userMemberships, &endpoint, roles)
|
||||||
if len(authorizations) > 0 {
|
if len(authorizations) > 0 {
|
||||||
endpointAuthorizations[endpoint.ID] = authorizations
|
endpointAuthorizations[endpoint.ID] = authorizations
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +590,7 @@ func getAuthorizationsFromRoles(roleIdentifiers []portainer.RoleID, roles []port
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if role.ID == id {
|
if role.ID == id {
|
||||||
associatedRoles = append(associatedRoles, role)
|
associatedRoles = append(associatedRoles, role)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -609,6 +613,7 @@ func (service *Service) UserIsAdminOrAuthorized(userID portainer.UserID, endpoin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Role == portainer.AdministratorRole {
|
if user.Role == portainer.AdministratorRole {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -619,5 +624,6 @@ func (service *Service) UserIsAdminOrAuthorized(userID portainer.UserID, endpoin
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,20 +74,11 @@ func (service *Service) getUserEndpointAccessWithPolicies(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if userAccess(tx, userID, endpoint.UserAccessPolicies, endpoint.TeamAccessPolicies, memberships) {
|
return userAccess(userID, endpoint.UserAccessPolicies, endpoint.TeamAccessPolicies, memberships) ||
|
||||||
return true, nil
|
userAccess(userID, endpointGroup.UserAccessPolicies, endpointGroup.TeamAccessPolicies, memberships), nil
|
||||||
}
|
|
||||||
|
|
||||||
if userAccess(tx, userID, endpointGroup.UserAccessPolicies, endpointGroup.TeamAccessPolicies, memberships) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func userAccess(
|
func userAccess(
|
||||||
tx dataservices.DataStoreTx,
|
|
||||||
userID portainer.UserID,
|
userID portainer.UserID,
|
||||||
userAccessPolicies portainer.UserAccessPolicies,
|
userAccessPolicies portainer.UserAccessPolicies,
|
||||||
teamAccessPolicies portainer.TeamAccessPolicies,
|
teamAccessPolicies portainer.TeamAccessPolicies,
|
||||||
|
|
|
@ -7,10 +7,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/patrickmn/go-cache"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/dataservices"
|
"github.com/portainer/portainer/api/dataservices"
|
||||||
|
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
@ -116,7 +117,7 @@ func (factory *ClientFactory) SetProxyKubeClient(endpointID, token string, cli *
|
||||||
// CreateKubeClientFromKubeConfig creates a KubeClient from a clusterID, and
|
// CreateKubeClientFromKubeConfig creates a KubeClient from a clusterID, and
|
||||||
// Kubernetes config.
|
// Kubernetes config.
|
||||||
func (factory *ClientFactory) CreateKubeClientFromKubeConfig(clusterID string, kubeConfig []byte) (*KubeClient, error) {
|
func (factory *ClientFactory) CreateKubeClientFromKubeConfig(clusterID string, kubeConfig []byte) (*KubeClient, error) {
|
||||||
config, err := clientcmd.NewClientConfigFromBytes([]byte(kubeConfig))
|
config, err := clientcmd.NewClientConfigFromBytes(kubeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -76,8 +77,8 @@ func newPods() *v1.PodList {
|
||||||
Name: "test-container-1",
|
Name: "test-container-1",
|
||||||
Resources: v1.ResourceRequirements{
|
Resources: v1.ResourceRequirements{
|
||||||
Requests: v1.ResourceList{
|
Requests: v1.ResourceList{
|
||||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse("2"),
|
v1.ResourceCPU: resource.MustParse("2"),
|
||||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("3M"),
|
v1.ResourceMemory: resource.MustParse("3M"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -85,7 +85,7 @@ func Test_GenerateYAML(t *testing.T) {
|
||||||
t.Errorf("generateYamlConfig failed; err=%s", err)
|
t.Errorf("generateYamlConfig failed; err=%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if compareYAMLStrings(string(yaml), ryt.wantYAML) != 0 {
|
if compareYAMLStrings(yaml, ryt.wantYAML) != 0 {
|
||||||
t.Errorf("generateYamlConfig failed;\ngot=\n%s\nwant=\n%s", yaml, ryt.wantYAML)
|
t.Errorf("generateYamlConfig failed;\ngot=\n%s\nwant=\n%s", yaml, ryt.wantYAML)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/dataservices"
|
"github.com/portainer/portainer/api/dataservices"
|
||||||
"github.com/portainer/portainer/api/stacks/deployments"
|
"github.com/portainer/portainer/api/stacks/deployments"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ func (b *StackBuilder) SaveStack() (*portainer.Stack, *httperror.HandlerError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
b.doCleanUp = false
|
b.doCleanUp = false
|
||||||
|
|
||||||
return b.stack, b.err
|
return b.stack, b.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue