chore(code): reduce divergence with EE EE-4344 (#7748)

pull/7752/head
andres-portainer 2022-09-28 14:56:32 -03:00 committed by GitHub
parent e9384a6987
commit cb79dc18f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
102 changed files with 259 additions and 180 deletions

View File

@ -25,7 +25,7 @@ type Monitor struct {
adminInitDisabled bool adminInitDisabled bool
} }
// New creates a monitor that when started will wait for the timeout duration and then sends the timeout signal to disable the application // New creates a monitor that when started will wait for the timeout duration and then shutdown the application unless it has been initialized.
func New(timeout time.Duration, datastore dataservices.DataStore, shutdownCtx context.Context) *Monitor { func New(timeout time.Duration, datastore dataservices.DataStore, shutdownCtx context.Context) *Monitor {
return &Monitor{ return &Monitor{
timeout: timeout, timeout: timeout,
@ -105,13 +105,11 @@ func (m *Monitor) WasInstanceDisabled() bool {
// Otherwise, it will pass through the request to next // Otherwise, it will pass through the request to next
func (m *Monitor) WithRedirect(next http.Handler) http.Handler { func (m *Monitor) WithRedirect(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if m.WasInstanceDisabled() { if m.WasInstanceDisabled() && strings.HasPrefix(r.RequestURI, "/api") && r.RequestURI != "/api/status" && r.RequestURI != "/api/settings/public" {
if strings.HasPrefix(r.RequestURI, "/api") && r.RequestURI != "/api/status" && r.RequestURI != "/api/settings/public" {
w.Header().Set("redirect-reason", RedirectReasonAdminInitTimeout) w.Header().Set("redirect-reason", RedirectReasonAdminInitTimeout)
httperror.WriteError(w, http.StatusSeeOther, "Administrator initialization timeout", nil) httperror.WriteError(w, http.StatusSeeOther, "Administrator initialization timeout", nil)
return return
} }
}
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })

View File

@ -6,10 +6,10 @@ import (
"fmt" "fmt"
"time" "time"
"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/pkg/errors"
) )
const portainerAPIKeyPrefix = "ptr_" const portainerAPIKeyPrefix = "ptr_"

View File

@ -2,6 +2,7 @@ package apikey
import ( import (
"crypto/sha256" "crypto/sha256"
"fmt"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -170,11 +171,9 @@ func Test_UpdateAPIKey(t *testing.T) {
_, apiKeyGot, err := service.GetDigestUserAndKey(apiKey.Digest) _, apiKeyGot, err := service.GetDigestUserAndKey(apiKey.Digest)
is.NoError(err) is.NoError(err)
log.Debug().Msgf("%+v", apiKey) log.Debug().Str("wanted", fmt.Sprintf("%+v", apiKey)).Str("got", fmt.Sprintf("%+v", apiKeyGot)).Msg("")
log.Debug().Msgf("%+v", apiKeyGot)
is.Equal(apiKey.LastUsed, apiKeyGot.LastUsed) is.Equal(apiKey.LastUsed, apiKeyGot.LastUsed)
}) })
t.Run("Successfully updates api-key in cache upon api-key update", func(t *testing.T) { t.Run("Successfully updates api-key in cache upon api-key update", func(t *testing.T) {

View File

@ -246,9 +246,8 @@ func (service *Service) checkTunnels() {
err := service.snapshotEnvironment(endpointID, tunnel.Port) err := service.snapshotEnvironment(endpointID, tunnel.Port)
if err != nil { if err != nil {
log.Error(). log.Error().
Int("endpoint_id", int(endpointID)).Err( Int("endpoint_id", int(endpointID)).
Err(err).
err).
Msg("unable to snapshot Edge environment") Msg("unable to snapshot Edge environment")
} }
} }

View File

@ -1,10 +1,10 @@
package cli package cli
import ( import (
portainer "github.com/portainer/portainer/api"
"strings" "strings"
portainer "github.com/portainer/portainer/api"
"gopkg.in/alecthomas/kingpin.v2" "gopkg.in/alecthomas/kingpin.v2"
) )

View File

@ -186,6 +186,10 @@ func initAPIKeyService(datastore dataservices.DataStore) apikey.APIKeyService {
} }
func initJWTService(userSessionTimeout string, dataStore dataservices.DataStore) (dataservices.JWTService, error) { func initJWTService(userSessionTimeout string, dataStore dataservices.DataStore) (dataservices.JWTService, error) {
if userSessionTimeout == "" {
userSessionTimeout = portainer.DefaultUserSessionTimeout
}
jwtService, err := jwt.NewService(userSessionTimeout, dataStore) jwtService, err := jwt.NewService(userSessionTimeout, dataStore)
if err != nil { if err != nil {
return nil, err return nil, err
@ -239,7 +243,13 @@ func initKubernetesClientFactory(signatureService portainer.DigitalSignatureServ
return kubecli.NewClientFactory(signatureService, reverseTunnelService, instanceID, dataStore) return kubecli.NewClientFactory(signatureService, reverseTunnelService, instanceID, dataStore)
} }
func initSnapshotService(snapshotIntervalFromFlag string, dataStore dataservices.DataStore, dockerClientFactory *docker.ClientFactory, kubernetesClientFactory *kubecli.ClientFactory, shutdownCtx context.Context) (portainer.SnapshotService, error) { func initSnapshotService(
snapshotIntervalFromFlag string,
dataStore dataservices.DataStore,
dockerClientFactory *docker.ClientFactory,
kubernetesClientFactory *kubecli.ClientFactory,
shutdownCtx context.Context,
) (portainer.SnapshotService, error) {
dockerSnapshotter := docker.NewSnapshotter(dockerClientFactory) dockerSnapshotter := docker.NewSnapshotter(dockerClientFactory)
kubernetesSnapshotter := kubernetes.NewSnapshotter(kubernetesClientFactory) kubernetesSnapshotter := kubernetes.NewSnapshotter(kubernetesClientFactory)
@ -580,6 +590,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
ldapService := initLDAPService() ldapService := initLDAPService()
oauthService := initOAuthService() oauthService := initOAuthService()
gitService := initGitService(shutdownCtx) gitService := initGitService(shutdownCtx)
openAMTService := openamt.NewService() openAMTService := openamt.NewService()
@ -704,15 +715,15 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
log.Fatal().Err(err).Msg("failed starting tunnel server") log.Fatal().Err(err).Msg("failed starting tunnel server")
} }
scheduler := scheduler.NewScheduler(shutdownCtx)
stackDeployer := stacks.NewStackDeployer(swarmStackManager, composeStackManager, kubernetesDeployer)
stacks.StartStackSchedules(scheduler, stackDeployer, dataStore, gitService)
sslDBSettings, err := dataStore.SSLSettings().Settings() sslDBSettings, err := dataStore.SSLSettings().Settings()
if err != nil { if err != nil {
log.Fatal().Msg("failed to fetch SSL settings from DB") log.Fatal().Msg("failed to fetch SSL settings from DB")
} }
scheduler := scheduler.NewScheduler(shutdownCtx)
stackDeployer := stacks.NewStackDeployer(swarmStackManager, composeStackManager, kubernetesDeployer)
stacks.StartStackSchedules(scheduler, stackDeployer, dataStore, gitService)
return &http.Server{ return &http.Server{
AuthorizationService: authorizationService, AuthorizationService: authorizationService,
ReverseTunnelService: reverseTunnelService, ReverseTunnelService: reverseTunnelService,
@ -726,8 +737,8 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
ComposeStackManager: composeStackManager, ComposeStackManager: composeStackManager,
KubernetesDeployer: kubernetesDeployer, KubernetesDeployer: kubernetesDeployer,
HelmPackageManager: helmPackageManager, HelmPackageManager: helmPackageManager,
CryptoService: cryptoService,
APIKeyService: apiKeyService, APIKeyService: apiKeyService,
CryptoService: cryptoService,
JWTService: jwtService, JWTService: jwtService,
FileService: fileService, FileService: fileService,
LDAPService: ldapService, LDAPService: ldapService,

View File

@ -8,6 +8,7 @@ import (
"github.com/portainer/portainer/api/cli" "github.com/portainer/portainer/api/cli"
"github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/datastore" "github.com/portainer/portainer/api/datastore"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/alecthomas/kingpin.v2" "gopkg.in/alecthomas/kingpin.v2"
) )

View File

@ -1,6 +1,7 @@
package boltdb package boltdb
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
@ -162,7 +163,7 @@ func (connection *DbConnection) ExportRaw(filename string) error {
return fmt.Errorf("stat on %s failed: %s", databasePath, err) return fmt.Errorf("stat on %s failed: %s", databasePath, err)
} }
b, err := connection.ExportJson(databasePath, true) b, err := connection.ExportJSON(databasePath, true)
if err != nil { if err != nil {
return err return err
} }
@ -369,6 +370,27 @@ func (connection *DbConnection) GetAllWithJsoniter(bucketName string, obj interf
return err return err
} }
func (connection *DbConnection) GetAllWithKeyPrefix(bucketName string, keyPrefix []byte, obj interface{}, append func(o interface{}) (interface{}, error)) error {
return connection.View(func(tx *bolt.Tx) error {
cursor := tx.Bucket([]byte(bucketName)).Cursor()
for k, v := cursor.Seek(keyPrefix); k != nil && bytes.HasPrefix(k, keyPrefix); k, v = cursor.Next() {
err := connection.UnmarshalObjectWithJsoniter(v, obj)
if err != nil {
return err
}
obj, err = append(obj)
if err != nil {
return err
}
}
return nil
})
}
// BackupMetadata will return a copy of the boltdb sequence numbers for all buckets.
func (connection *DbConnection) BackupMetadata() (map[string]interface{}, error) { func (connection *DbConnection) BackupMetadata() (map[string]interface{}, error) {
buckets := map[string]interface{}{} buckets := map[string]interface{}{}
@ -387,6 +409,7 @@ func (connection *DbConnection) BackupMetadata() (map[string]interface{}, error)
return buckets, err return buckets, err
} }
// RestoreMetadata will restore the boltdb sequence numbers for all buckets.
func (connection *DbConnection) RestoreMetadata(s map[string]interface{}) error { func (connection *DbConnection) RestoreMetadata(s map[string]interface{}) error {
var err error var err error

View File

@ -31,7 +31,7 @@ func backupMetadata(connection *bolt.DB) (map[string]interface{}, error) {
// using this function. // using this function.
// inspired by github.com/konoui/boltdb-exporter (which has no license) // inspired by github.com/konoui/boltdb-exporter (which has no license)
// but very much simplified, based on how we use boltdb // but very much simplified, based on how we use boltdb
func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, error) { func (c *DbConnection) ExportJSON(databasePath string, metadata bool) ([]byte, error) {
log.Debug().Str("databasePath", databasePath).Msg("exportJson") log.Debug().Str("databasePath", databasePath).Msg("exportJson")
connection, err := bolt.Open(databasePath, 0600, &bolt.Options{Timeout: 1 * time.Second, ReadOnly: true}) connection, err := bolt.Open(databasePath, 0600, &bolt.Options{Timeout: 1 * time.Second, ReadOnly: true})

View File

@ -16,5 +16,6 @@ func NewDatabase(storeType, storePath string, encryptionKey []byte) (connection
EncryptionKey: encryptionKey, EncryptionKey: encryptionKey,
}, nil }, nil
} }
return nil, fmt.Errorf("unknown storage database: %s", storeType)
return nil, fmt.Errorf("Unknown storage database: %s", storeType)
} }

View File

@ -85,7 +85,7 @@ func (service *Service) List() ([]edgetypes.UpdateSchedule, error) {
item, ok := obj.(*edgetypes.UpdateSchedule) item, ok := obj.(*edgetypes.UpdateSchedule)
if !ok { if !ok {
logrus.WithField("obj", obj).Errorf("Failed to convert to EdgeUpdateSchedule object") logrus.WithField("obj", obj).Errorf("Failed to convert to EdgeUpdateSchedule object")
return nil, fmt.Errorf("failed to convert to EdgeUpdateSchedule object: %s", obj) return nil, fmt.Errorf("Failed to convert to EdgeUpdateSchedule object: %s", obj)
} }
list = append(list, *item) list = append(list, *item)
return &edgetypes.UpdateSchedule{}, nil return &edgetypes.UpdateSchedule{}, nil

View File

@ -24,7 +24,6 @@ type (
BackupTo(w io.Writer) error BackupTo(w io.Writer) error
Export(filename string) (err error) Export(filename string) (err error)
IsErrObjectNotFound(err error) bool IsErrObjectNotFound(err error) bool
CustomTemplate() CustomTemplateService CustomTemplate() CustomTemplateService
EdgeGroup() EdgeGroupService EdgeGroup() EdgeGroupService
EdgeJob() EdgeJobService EdgeJob() EdgeJobService

View File

@ -156,6 +156,7 @@ func (store *Store) encryptDB() error {
if err != nil { if err != nil {
// Remove the new encrypted file that we failed to import // Remove the new encrypted file that we failed to import
os.Remove(store.connection.GetDatabaseFilePath()) os.Remove(store.connection.GetDatabaseFilePath())
log.Fatal().Err(portainerErrors.ErrDBImportFailed).Msg("") log.Fatal().Err(portainerErrors.ErrDBImportFailed).Msg("")
} }

View File

@ -36,6 +36,7 @@ func (store *Store) checkOrCreateInstanceID() error {
instanceID := uid.String() instanceID := uid.String()
return store.VersionService.StoreInstanceID(instanceID) return store.VersionService.StoreInstanceID(instanceID)
} }
return err return err
} }
@ -88,7 +89,6 @@ func (store *Store) checkOrCreateDefaultSettings() error {
func (store *Store) checkOrCreateDefaultSSLSettings() error { func (store *Store) checkOrCreateDefaultSSLSettings() error {
_, err := store.SSLSettings().Settings() _, err := store.SSLSettings().Settings()
if store.IsErrObjectNotFound(err) { if store.IsErrObjectNotFound(err) {
defaultSSLSettings := &portainer.SSLSettings{ defaultSSLSettings := &portainer.SSLSettings{
HTTPEnabled: true, HTTPEnabled: true,
@ -96,6 +96,7 @@ func (store *Store) checkOrCreateDefaultSSLSettings() error {
return store.SSLSettings().UpdateSettings(defaultSSLSettings) return store.SSLSettings().UpdateSettings(defaultSSLSettings)
} }
return err return err
} }

View File

@ -259,7 +259,7 @@ func migrateDBTestHelper(t *testing.T, srcPath, wantPath string) error {
return fmt.Errorf("stat on %s failed: %s", databasePath, err) return fmt.Errorf("stat on %s failed: %s", databasePath, err)
} }
gotJSON, err := con.ExportJson(databasePath, false) gotJSON, err := con.ExportJSON(databasePath, false)
if err != nil { if err != nil {
t.Logf( t.Logf(
"failed re-exporting database %s to JSON: %v", "failed re-exporting database %s to JSON: %v",

View File

@ -1,13 +1,12 @@
package migrator package migrator
import ( import (
"errors"
"reflect" "reflect"
"runtime" "runtime"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
werrors "github.com/pkg/errors" "github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -17,7 +16,7 @@ type migration struct {
} }
func migrationError(err error, context string) error { func migrationError(err error, context string) error {
return werrors.Wrap(err, "failed in "+context) return errors.Wrap(err, "failed in "+context)
} }
func newMigration(dbversion int, migrate func() error) migration { func newMigration(dbversion int, migrate func() error) migration {

View File

@ -15,6 +15,7 @@ func (m *Migrator) updateUsersToDBVersion20() error {
} }
func (m *Migrator) updateSettingsToDBVersion20() error { func (m *Migrator) updateSettingsToDBVersion20() error {
log.Info().Msg("updating settings")
legacySettings, err := m.settingsService.Settings() legacySettings, err := m.settingsService.Settings()
if err != nil { if err != nil {
return err return err

View File

@ -22,6 +22,7 @@ func (m *Migrator) updateTagsToDBVersion23() error {
return err return err
} }
} }
return nil return nil
} }

View File

@ -19,5 +19,6 @@ func (m *Migrator) MigrateSettingsToDB30() error {
legacySettings.OAuthSettings.SSO = false legacySettings.OAuthSettings.SSO = false
legacySettings.OAuthSettings.LogoutURI = "" legacySettings.OAuthSettings.LogoutURI = ""
return m.settingsService.UpdateSettings(legacySettings) return m.settingsService.UpdateSettings(legacySettings)
} }

View File

@ -13,6 +13,7 @@ func (m *Migrator) migrateDBVersionToDB33() error {
} }
func (m *Migrator) migrateSettingsToDB33() error { func (m *Migrator) migrateSettingsToDB33() error {
log.Info().Msg("setting default kubctl shell")
settings, err := m.settingsService.Settings() settings, err := m.settingsService.Settings()
if err != nil { if err != nil {
return err return err

View File

@ -14,6 +14,8 @@ func (m *Migrator) migrateDBVersionToDB36() error {
} }
func (m *Migrator) migrateUsersToDB36() error { func (m *Migrator) migrateUsersToDB36() error {
log.Info().Msg("updating user authorizations")
users, err := m.userService.Users() users, err := m.userService.Users()
if err != nil { if err != nil {
return err return err

View File

@ -2,6 +2,7 @@ package migrator
import ( import (
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )

View File

@ -518,7 +518,7 @@ func (store *Store) Export(filename string) (err error) {
if snapshot, err := store.Snapshot().Snapshots(); err != nil { if snapshot, err := store.Snapshot().Snapshots(); err != nil {
if !store.IsErrObjectNotFound(err) { if !store.IsErrObjectNotFound(err) {
log.Err(err).Msg("Exporting Snapshots") log.Error().Err(err).Msg("exporting Snapshots")
} }
} else { } else {
backup.Snapshot = snapshot backup.Snapshot = snapshot
@ -707,7 +707,7 @@ func (store *Store) Import(filename string) (err error) {
for _, user := range backup.User { for _, user := range backup.User {
if err := store.User().UpdateUser(user.ID, &user); err != nil { if err := store.User().UpdateUser(user.ID, &user); err != nil {
log.Debug().Str("user", fmt.Sprintf("%+v", user)).Err(err).Msg("user: failed to Update Database") log.Debug().Str("user", fmt.Sprintf("%+v", user)).Err(err).Msg("failed to update the user in the database")
} }
} }

6
api/docker/labels.go Normal file
View File

@ -0,0 +1,6 @@
package docker
const (
ComposeStackNameLabel = "com.docker.compose.project"
SwarmStackNameLabel = "com.docker.stack.namespace"
)

View File

@ -194,7 +194,7 @@ func snapshotContainers(snapshot *portainer.DockerSnapshot, cli *client.Client)
} }
for k, v := range container.Labels { for k, v := range container.Labels {
if k == "com.docker.compose.project" { if k == ComposeStackNameLabel {
stacks[v] = struct{}{} stacks[v] = struct{}{}
} }
} }

View File

@ -8,15 +8,14 @@ import (
"path" "path"
"strings" "strings"
"github.com/pkg/errors"
libstack "github.com/portainer/docker-compose-wrapper" libstack "github.com/portainer/docker-compose-wrapper"
"github.com/portainer/docker-compose-wrapper/compose" "github.com/portainer/docker-compose-wrapper/compose"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/http/proxy" "github.com/portainer/portainer/api/http/proxy"
"github.com/portainer/portainer/api/http/proxy/factory" "github.com/portainer/portainer/api/http/proxy/factory"
"github.com/portainer/portainer/api/internal/stackutils" "github.com/portainer/portainer/api/internal/stackutils"
"github.com/pkg/errors"
) )
// ComposeStackManager is a wrapper for docker-compose binary // ComposeStackManager is a wrapper for docker-compose binary

View File

@ -6,6 +6,7 @@ import (
type kubernetesMockDeployer struct{} type kubernetesMockDeployer struct{}
// NewKubernetesDeployer creates a mock kubernetes deployer
func NewKubernetesDeployer() portainer.KubernetesDeployer { func NewKubernetesDeployer() portainer.KubernetesDeployer {
return &kubernetesMockDeployer{} return &kubernetesMockDeployer{}
} }

View File

@ -9,14 +9,14 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/pkg/errors" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/http/proxy" "github.com/portainer/portainer/api/http/proxy"
"github.com/portainer/portainer/api/http/proxy/factory" "github.com/portainer/portainer/api/http/proxy/factory"
"github.com/portainer/portainer/api/http/proxy/factory/kubernetes" "github.com/portainer/portainer/api/http/proxy/factory/kubernetes"
"github.com/portainer/portainer/api/kubernetes/cli" "github.com/portainer/portainer/api/kubernetes/cli"
portainer "github.com/portainer/portainer/api" "github.com/pkg/errors"
) )
// KubernetesDeployer represents a service to deploy resources inside a Kubernetes environment(endpoint). // KubernetesDeployer represents a service to deploy resources inside a Kubernetes environment(endpoint).
@ -73,6 +73,7 @@ func (deployer *KubernetesDeployer) getToken(userID portainer.UserID, endpoint *
if token == "" { if token == "" {
return "", fmt.Errorf("can not get a valid user service account token") return "", fmt.Errorf("can not get a valid user service account token")
} }
return token, nil return token, nil
} }

View File

@ -1,7 +1,6 @@
package auth package auth
import ( import (
"errors"
"net/http" "net/http"
"strings" "strings"
@ -13,6 +12,7 @@ import (
"github.com/portainer/portainer/api/internal/authorization" "github.com/portainer/portainer/api/internal/authorization"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )

View File

@ -22,6 +22,7 @@ func (payload *oauthPayload) Validate(r *http.Request) error {
if govalidator.IsNull(payload.Code) { if govalidator.IsNull(payload.Code) {
return errors.New("Invalid OAuth authorization code") return errors.New("Invalid OAuth authorization code")
} }
return nil return nil
} }

View File

@ -3,13 +3,14 @@ package auth
import ( import (
"net/http" "net/http"
"github.com/gorilla/mux"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
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/http/proxy" "github.com/portainer/portainer/api/http/proxy"
"github.com/portainer/portainer/api/http/proxy/factory/kubernetes" "github.com/portainer/portainer/api/http/proxy/factory/kubernetes"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/gorilla/mux"
) )
// Handler is the HTTP handler used to handle authentication operations. // Handler is the HTTP handler used to handle authentication operations.

View File

@ -56,6 +56,7 @@ func Test_backupHandlerWithoutPassword_shouldCreateATarballArchive(t *testing.T)
body, _ := io.ReadAll(response.Body) body, _ := io.ReadAll(response.Body)
tmpdir := t.TempDir() tmpdir := t.TempDir()
archivePath := filepath.Join(tmpdir, "archive.tar.gz") archivePath := filepath.Join(tmpdir, "archive.tar.gz")
err := ioutil.WriteFile(archivePath, body, 0600) err := ioutil.WriteFile(archivePath, body, 0600)
if err != nil { if err != nil {
@ -91,6 +92,7 @@ func Test_backupHandlerWithPassword_shouldCreateEncryptedATarballArchive(t *test
body, _ := io.ReadAll(response.Body) body, _ := io.ReadAll(response.Body)
tmpdir := t.TempDir() tmpdir := t.TempDir()
dr, err := crypto.AesDecrypt(bytes.NewReader(body), []byte("secret")) dr, err := crypto.AesDecrypt(bytes.NewReader(body), []byte("secret"))
if err != nil { if err != nil {
t.Fatal("Failed to decrypt archive") t.Fatal("Failed to decrypt archive")

View File

@ -3,6 +3,7 @@ package customtemplates
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"net/http" "net/http"
"os" "os"
"regexp" "regexp"
@ -13,6 +14,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/filesystem" "github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/api/git"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/internal/authorization" "github.com/portainer/portainer/api/internal/authorization"
@ -290,6 +292,9 @@ func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) (
err = handler.GitService.CloneRepository(projectPath, payload.RepositoryURL, payload.RepositoryReferenceName, repositoryUsername, repositoryPassword) err = handler.GitService.CloneRepository(projectPath, payload.RepositoryURL, payload.RepositoryReferenceName, repositoryUsername, repositoryPassword)
if err != nil { if err != nil {
if err == git.ErrAuthenticationFailure {
return nil, fmt.Errorf("invalid git credential")
}
return nil, err return nil, err
} }

View File

@ -4,11 +4,13 @@ import (
"errors" "errors"
"net/http" "net/http"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"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/internal/endpointutils"
"github.com/asaskevich/govalidator"
) )
type edgeGroupCreatePayload struct { type edgeGroupCreatePayload struct {
@ -81,7 +83,7 @@ func (handler *Handler) edgeGroupCreate(w http.ResponseWriter, r *http.Request)
return httperror.InternalServerError("Unable to retrieve environment from the database", err) return httperror.InternalServerError("Unable to retrieve environment from the database", err)
} }
if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment { if endpointutils.IsEdgeEndpoint(endpoint) {
endpointIDs = append(endpointIDs, endpoint.ID) endpointIDs = append(endpointIDs, endpoint.ID)
} }
} }

View File

@ -53,5 +53,4 @@ func (handler *Handler) edgeGroupDelete(w http.ResponseWriter, r *http.Request)
} }
return response.Empty(w) return response.Empty(w)
} }

View File

@ -81,7 +81,7 @@ func getEndpointTypes(endpointService dataservices.EndpointService, endpointIds
for _, endpointID := range endpointIds { for _, endpointID := range endpointIds {
endpoint, err := endpointService.Endpoint(endpointID) endpoint, err := endpointService.Endpoint(endpointID)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed fetching endpoint: %w", err) return nil, fmt.Errorf("failed fetching environment: %w", err)
} }
typeSet[endpoint.Type] = true typeSet[endpoint.Type] = true

View File

@ -4,12 +4,14 @@ import (
"errors" "errors"
"net/http" "net/http"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"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/internal/edge" "github.com/portainer/portainer/api/internal/edge"
"github.com/portainer/portainer/api/internal/endpointutils"
"github.com/asaskevich/govalidator"
) )
type edgeGroupUpdatePayload struct { type edgeGroupUpdatePayload struct {
@ -102,7 +104,7 @@ func (handler *Handler) edgeGroupUpdate(w http.ResponseWriter, r *http.Request)
return httperror.InternalServerError("Unable to retrieve environment from the database", err) return httperror.InternalServerError("Unable to retrieve environment from the database", err)
} }
if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment { if endpointutils.IsEdgeEndpoint(endpoint) {
endpointIDs = append(endpointIDs, endpoint.ID) endpointIDs = append(endpointIDs, endpoint.ID)
} }
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"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/internal/endpointutils"
) )
// @id EdgeJobCreate // @id EdgeJobCreate
@ -200,7 +201,7 @@ func (handler *Handler) addAndPersistEdgeJob(edgeJob *portainer.EdgeJob, file []
return err return err
} }
if endpoint.Type != portainer.EdgeAgentOnDockerEnvironment && endpoint.Type != portainer.EdgeAgentOnKubernetesEnvironment { if !endpointutils.IsEdgeEndpoint(endpoint) {
delete(edgeJob.Endpoints, ID) delete(edgeJob.Endpoints, ID)
} }
} }

View File

@ -5,11 +5,12 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response" "github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/asaskevich/govalidator"
) )
type edgeJobUpdatePayload struct { type edgeJobUpdatePayload struct {

View File

@ -1,14 +1,12 @@
package edgestacks package edgestacks
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response" "github.com/portainer/libhttp/response"
@ -16,6 +14,9 @@ import (
"github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/filesystem" "github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/api/internal/edge" "github.com/portainer/portainer/api/internal/edge"
"github.com/asaskevich/govalidator"
"github.com/pkg/errors"
) )
// @id EdgeStackCreate // @id EdgeStackCreate
@ -271,7 +272,7 @@ func (handler *Handler) createSwarmStackFromGitRepository(r *http.Request) (*por
err = updateEndpointRelations(handler.DataStore.EndpointRelation(), stack.ID, relatedEndpointIds) err = updateEndpointRelations(handler.DataStore.EndpointRelation(), stack.ID, relatedEndpointIds)
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to update endpoint relations: %w", err) return nil, fmt.Errorf("Unable to update environment relations: %w", err)
} }
err = handler.DataStore.EdgeStack().Create(stack.ID, stack) err = handler.DataStore.EdgeStack().Create(stack.ID, stack)
@ -378,7 +379,7 @@ func (handler *Handler) createSwarmStackFromFileUpload(r *http.Request) (*portai
err = updateEndpointRelations(handler.DataStore.EndpointRelation(), stack.ID, relatedEndpointIds) err = updateEndpointRelations(handler.DataStore.EndpointRelation(), stack.ID, relatedEndpointIds)
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to update endpoint relations: %w", err) return nil, fmt.Errorf("Unable to update environment relations: %w", err)
} }
err = handler.DataStore.EdgeStack().Create(stack.ID, stack) err = handler.DataStore.EdgeStack().Create(stack.ID, stack)
@ -408,14 +409,14 @@ func updateEndpointRelations(endpointRelationService dataservices.EndpointRelati
for _, endpointID := range relatedEndpointIds { for _, endpointID := range relatedEndpointIds {
relation, err := endpointRelationService.EndpointRelation(endpointID) relation, err := endpointRelationService.EndpointRelation(endpointID)
if err != nil { if err != nil {
return fmt.Errorf("unable to find endpoint relation in database: %w", err) return fmt.Errorf("unable to find environment relation in database: %w", err)
} }
relation.EdgeStacks[edgeStackID] = true relation.EdgeStacks[edgeStackID] = true
err = endpointRelationService.UpdateEndpointRelation(endpointID, relation) err = endpointRelationService.UpdateEndpointRelation(endpointID, relation)
if err != nil { if err != nil {
return fmt.Errorf("unable to persist endpoint relation in database: %w", err) return fmt.Errorf("unable to persist environment relation in database: %w", err)
} }
} }

View File

@ -5,6 +5,7 @@ import (
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/testhelpers" "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -42,7 +42,7 @@ func (handler *Handler) edgeStackDelete(w http.ResponseWriter, r *http.Request)
relationConfig, err := fetchEndpointRelationsConfig(handler.DataStore) relationConfig, err := fetchEndpointRelationsConfig(handler.DataStore)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to retrieve environments relations config from database", err) return httperror.InternalServerError("Unable to find environment relations in database", err)
} }
relatedEndpointIds, err := edge.EdgeStackRelatedEndpoints(edgeStack.EdgeGroups, relationConfig.endpoints, relationConfig.endpointGroups, relationConfig.edgeGroups) relatedEndpointIds, err := edge.EdgeStackRelatedEndpoints(edgeStack.EdgeGroups, relationConfig.endpoints, relationConfig.endpointGroups, relationConfig.edgeGroups)

View File

@ -46,7 +46,7 @@ func (handler *Handler) edgeStackFile(w http.ResponseWriter, r *http.Request) *h
stackFileContent, err := handler.FileService.GetFileContent(stack.ProjectPath, fileName) stackFileContent, err := handler.FileService.GetFileContent(stack.ProjectPath, fileName)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to retrieve Compose file from disk", err) return httperror.InternalServerError("Unable to retrieve stack file from disk", err)
} }
return response.JSON(w, &stackFileResponse{StackFileContent: string(stackFileContent)}) return response.JSON(w, &stackFileResponse{StackFileContent: string(stackFileContent)})

View File

@ -3,7 +3,6 @@ package edgestacks
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -19,6 +18,8 @@ import (
"github.com/portainer/portainer/api/filesystem" "github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/jwt" "github.com/portainer/portainer/api/jwt"
"github.com/pkg/errors"
) )
type gitService struct { type gitService struct {

View File

@ -2,7 +2,6 @@ package edgestacks
import ( import (
"errors" "errors"
"github.com/portainer/portainer/api/internal/endpointutils"
"net/http" "net/http"
"strconv" "strconv"
@ -12,6 +11,7 @@ import (
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem" "github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/api/internal/edge" "github.com/portainer/portainer/api/internal/edge"
"github.com/portainer/portainer/api/internal/endpointutils"
) )
type updateEdgeStackPayload struct { type updateEdgeStackPayload struct {

View File

@ -31,14 +31,14 @@ func (payload *createPayload) Validate(r *http.Request) error {
return errors.New("Required to choose at least one group") return errors.New("Required to choose at least one group")
} }
if payload.Type != edgetypes.UpdateScheduleRollback && payload.Type != edgetypes.UpdateScheduleUpdate {
return errors.New("Invalid schedule type")
}
if len(payload.Environments) == 0 { if len(payload.Environments) == 0 {
return errors.New("No Environment is scheduled for update") return errors.New("No Environment is scheduled for update")
} }
if payload.Type != edgetypes.UpdateScheduleRollback && payload.Type != edgetypes.UpdateScheduleUpdate {
return errors.New("Invalid schedule type")
}
if payload.Time < time.Now().Unix() { if payload.Time < time.Now().Unix() {
return errors.New("Invalid time") return errors.New("Invalid time")
} }

View File

@ -3,14 +3,13 @@ package endpointedge
import ( import (
"net/http" "net/http"
"github.com/portainer/portainer/api/http/middlewares"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/gorilla/mux"
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/http/middlewares"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/gorilla/mux"
) )
// Handler is the HTTP handler used to handle edge environment(endpoint) operations. // Handler is the HTTP handler used to handle edge environment(endpoint) operations.

View File

@ -2,13 +2,13 @@ package endpointproxy
import ( import (
"errors" "errors"
httperror "github.com/portainer/libhttp/error" "net/http"
"github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api"
"strconv" "strconv"
"strings" "strings"
"net/http" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api"
) )
func (handler *Handler) proxyRequestsToDockerAPI(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { func (handler *Handler) proxyRequestsToDockerAPI(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {

View File

@ -3,12 +3,12 @@ package endpointproxy
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/http"
"strings"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"strings"
"net/http"
) )
func (handler *Handler) proxyRequestsToKubernetesAPI(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { func (handler *Handler) proxyRequestsToKubernetesAPI(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {

View File

@ -102,7 +102,6 @@ func Test_EndpointList_AgentVersion(t *testing.T) {
is.ElementsMatch(test.expected, respIds) is.ElementsMatch(test.expected, respIds)
}) })
} }
} }
func Test_endpointList_edgeDeviceFilter(t *testing.T) { func Test_endpointList_edgeDeviceFilter(t *testing.T) {

View File

@ -32,6 +32,10 @@ func (handler *Handler) endpointSnapshots(w http.ResponseWriter, r *http.Request
continue continue
} }
if endpoint.URL == "" {
continue
}
snapshotError := handler.SnapshotService.SnapshotEndpoint(&endpoint) snapshotError := handler.SnapshotService.SnapshotEndpoint(&endpoint)
latestEndpointReference, err := handler.DataStore.Endpoint().Endpoint(endpoint.ID) latestEndpointReference, err := handler.DataStore.Endpoint().Endpoint(endpoint.ID)

View File

@ -38,8 +38,6 @@ func (handler *Handler) helmList(w http.ResponseWriter, r *http.Request) *httper
KubernetesClusterAccess: clusterAccess, KubernetesClusterAccess: clusterAccess,
} }
params := r.URL.Query()
// optional namespace. The library defaults to "default" // optional namespace. The library defaults to "default"
namespace, _ := request.RetrieveQueryParameter(r, "namespace", true) namespace, _ := request.RetrieveQueryParameter(r, "namespace", true)
if namespace != "" { if namespace != "" {
@ -47,12 +45,12 @@ func (handler *Handler) helmList(w http.ResponseWriter, r *http.Request) *httper
} }
// optional filter // optional filter
if filter := params.Get("filter"); filter != "" { if filter, _ := request.RetrieveQueryParameter(r, "filter", true); filter != "" {
listOpts.Filter = filter listOpts.Filter = filter
} }
// optional selector // optional selector
if selector := params.Get("selector"); selector != "" { if selector, _ := request.RetrieveQueryParameter(r, "selector", true); selector != "" {
listOpts.Selector = selector listOpts.Selector = selector
} }

View File

@ -9,7 +9,6 @@ import (
"testing" "testing"
"github.com/portainer/libhelm/binary/test" "github.com/portainer/libhelm/binary/test"
helper "github.com/portainer/portainer/api/internal/testhelpers" helper "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -32,6 +31,7 @@ func Test_helmRepoSearch(t *testing.T) {
h.ServeHTTP(rr, req) h.ServeHTTP(rr, req)
is.Equal(http.StatusOK, rr.Code, "Status should be 200 OK") is.Equal(http.StatusOK, rr.Code, "Status should be 200 OK")
body, err := io.ReadAll(rr.Body) body, err := io.ReadAll(rr.Body)
is.NoError(err, "ReadAll should not return error") is.NoError(err, "ReadAll should not return error")
is.NotEmpty(body, "Body should not be empty") is.NotEmpty(body, "Body should not be empty")

View File

@ -5,11 +5,11 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"github.com/pkg/errors"
"github.com/portainer/libhelm/options" "github.com/portainer/libhelm/options"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )

View File

@ -56,6 +56,7 @@ func (handler *Handler) userCreateHelmRepo(w http.ResponseWriter, r *http.Reques
if err != nil { if err != nil {
return httperror.BadRequest("Invalid Helm repository URL", err) return httperror.BadRequest("Invalid Helm repository URL", err)
} }
// lowercase, remove trailing slash // lowercase, remove trailing slash
p.URL = strings.TrimSuffix(strings.ToLower(p.URL), "/") p.URL = strings.TrimSuffix(strings.ToLower(p.URL), "/")

View File

@ -89,7 +89,7 @@ func (handler *Handler) fdoConfigure(w http.ResponseWriter, r *http.Request) *ht
err := request.DecodeAndValidateJSONPayload(r, &payload) err := request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Invalid request payload") log.Error().Err(err).Msg("invalid request payload")
return httperror.BadRequest("Invalid request payload", err) return httperror.BadRequest("Invalid request payload", err)
} }

View File

@ -3,13 +3,14 @@ package fdo
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/http"
"strconv"
"time"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response" "github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"net/http"
"strconv"
"time"
) )
// @id duplicate // @id duplicate

View File

@ -38,7 +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)
} }
@ -75,7 +75,7 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
return nil, httperror.InternalServerError("Unable to retrieve info from request context", err) return nil, httperror.InternalServerError("Unable to retrieve info from request context", err)
} }
endpointGroups, err := handler.dataStore.EndpointGroup().EndpointGroups() endpointGroups, err := handler.DataStore.EndpointGroup().EndpointGroups()
if err != nil { if err != nil {
return nil, httperror.InternalServerError("Unable to retrieve environment groups from the database", err) return nil, httperror.InternalServerError("Unable to retrieve environment groups from the database", err)
} }
@ -83,7 +83,7 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
if len(endpointIDs) > 0 { if len(endpointIDs) > 0 {
var endpoints []portainer.Endpoint var endpoints []portainer.Endpoint
for _, endpointID := range endpointIDs { for _, endpointID := range endpointIDs {
endpoint, err := handler.dataStore.Endpoint().Endpoint(endpointID) endpoint, err := handler.DataStore.Endpoint().Endpoint(endpointID)
if err != nil { if err != nil {
return nil, httperror.InternalServerError("Unable to retrieve environment from the database", err) return nil, httperror.InternalServerError("Unable to retrieve environment from the database", err)
} }
@ -97,7 +97,7 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
} }
var kubeEndpoints []portainer.Endpoint var kubeEndpoints []portainer.Endpoint
endpoints, err := handler.dataStore.Endpoint().Endpoints() endpoints, err := handler.DataStore.Endpoint().Endpoints()
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)
} }
@ -122,7 +122,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
authInfosSet := make(map[string]bool) authInfosSet := make(map[string]bool)
for idx, endpoint := range endpoints { for idx, endpoint := range endpoints {
instanceID := handler.kubernetesClientFactory.GetInstanceID() instanceID := handler.KubernetesClientFactory.GetInstanceID()
serviceAccountName := kcli.UserServiceAccountName(int(tokenData.ID), instanceID) serviceAccountName := kcli.UserServiceAccountName(int(tokenData.ID), instanceID)
configClusters[idx] = handler.buildCluster(r, endpoint) configClusters[idx] = handler.buildCluster(r, endpoint)
@ -145,6 +145,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
func (handler *Handler) buildCluster(r *http.Request, endpoint portainer.Endpoint) clientV1.NamedCluster { func (handler *Handler) buildCluster(r *http.Request, endpoint portainer.Endpoint) clientV1.NamedCluster {
kubeConfigInternal := handler.kubeClusterAccessService.GetData(r.Host, endpoint.ID) kubeConfigInternal := handler.kubeClusterAccessService.GetData(r.Host, endpoint.ID)
return clientV1.NamedCluster{ return clientV1.NamedCluster{
Name: buildClusterName(endpoint.Name), Name: buildClusterName(endpoint.Name),
Cluster: clientV1.Cluster{ Cluster: clientV1.Cluster{

View File

@ -23,10 +23,10 @@ import (
type Handler struct { type Handler struct {
*mux.Router *mux.Router
authorizationService *authorization.Service authorizationService *authorization.Service
dataStore dataservices.DataStore DataStore dataservices.DataStore
KubernetesClient portainer.KubeClient KubernetesClient portainer.KubeClient
kubernetesClientFactory *cli.ClientFactory KubernetesClientFactory *cli.ClientFactory
jwtService dataservices.JWTService JwtService dataservices.JWTService
kubeClusterAccessService kubernetes.KubeClusterAccessService kubeClusterAccessService kubernetes.KubeClusterAccessService
} }
@ -35,10 +35,10 @@ func NewHandler(bouncer *security.RequestBouncer, authorizationService *authoriz
h := &Handler{ h := &Handler{
Router: mux.NewRouter(), Router: mux.NewRouter(),
authorizationService: authorizationService, authorizationService: authorizationService,
dataStore: dataStore, DataStore: dataStore,
jwtService: jwtService, JwtService: jwtService,
kubeClusterAccessService: kubeClusterAccessService, kubeClusterAccessService: kubeClusterAccessService,
kubernetesClientFactory: kubernetesClientFactory, KubernetesClientFactory: kubernetesClientFactory,
KubernetesClient: kubernetesClient, KubernetesClient: kubernetesClient,
} }
@ -90,7 +90,7 @@ func kubeOnlyMiddleware(next http.Handler) http.Handler {
} }
if !endpointutils.IsKubernetesEndpoint(endpoint) { if !endpointutils.IsKubernetesEndpoint(endpoint) {
errMessage := "Environment is not a kubernetes environment" errMessage := "environment is not a Kubernetes environment"
httperror.WriteError(rw, http.StatusBadRequest, errMessage, errors.New(errMessage)) httperror.WriteError(rw, http.StatusBadRequest, errMessage, errors.New(errMessage))
return return
} }
@ -111,7 +111,7 @@ func (handler *Handler) kubeClient(next http.Handler) http.Handler {
) )
} }
endpoint, err := handler.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
if err == portainerDsErrors.ErrObjectNotFound { if err == portainerDsErrors.ErrObjectNotFound {
httperror.WriteError( httperror.WriteError(
w, w,
@ -128,11 +128,11 @@ func (handler *Handler) kubeClient(next http.Handler) http.Handler {
) )
} }
if handler.kubernetesClientFactory == nil { if handler.KubernetesClientFactory == nil {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} }
kubeCli, err := handler.kubernetesClientFactory.GetKubeClient(endpoint) kubeCli, err := handler.KubernetesClientFactory.GetKubeClient(endpoint)
if err != nil { if err != nil {
httperror.WriteError( httperror.WriteError(
w, w,

View File

@ -20,7 +20,7 @@ func (handler *Handler) getKubernetesIngressControllers(w http.ResponseWriter, r
) )
} }
endpoint, err := handler.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
if err == portainerDsErrors.ErrObjectNotFound { if err == portainerDsErrors.ErrObjectNotFound {
return httperror.NotFound( return httperror.NotFound(
"Unable to find an environment with the specified identifier inside the database", "Unable to find an environment with the specified identifier inside the database",
@ -41,7 +41,7 @@ func (handler *Handler) getKubernetesIngressControllers(w http.ResponseWriter, r
) )
} }
cli, err := handler.kubernetesClientFactory.GetKubeClient(endpoint) cli, err := handler.KubernetesClientFactory.GetKubeClient(endpoint)
if err != nil { if err != nil {
return httperror.InternalServerError( return httperror.InternalServerError(
"Unable to create Kubernetes client", "Unable to create Kubernetes client",
@ -86,7 +86,7 @@ func (handler *Handler) getKubernetesIngressControllers(w http.ResponseWriter, r
newClasses = append(newClasses, class) newClasses = append(newClasses, class)
} }
endpoint.Kubernetes.Configuration.IngressClasses = newClasses endpoint.Kubernetes.Configuration.IngressClasses = newClasses
err = handler.dataStore.Endpoint().UpdateEndpoint( err = handler.DataStore.Endpoint().UpdateEndpoint(
portainer.EndpointID(endpointID), portainer.EndpointID(endpointID),
endpoint, endpoint,
) )
@ -120,8 +120,8 @@ func (handler *Handler) getKubernetesIngressControllersByNamespace(w http.Respon
) )
} }
endpoint, err := handler.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
if err == portainerDsErrors.ErrObjectNotFound { if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.NotFound( return httperror.NotFound(
"Unable to find an environment with the specified identifier inside the database", "Unable to find an environment with the specified identifier inside the database",
err, err,
@ -183,7 +183,7 @@ func (handler *Handler) getKubernetesIngressControllersByNamespace(w http.Respon
// Update the database to match the list of found controllers. // Update the database to match the list of found controllers.
// This includes pruning out controllers which no longer exist. // This includes pruning out controllers which no longer exist.
endpoint.Kubernetes.Configuration.IngressClasses = updatedClasses endpoint.Kubernetes.Configuration.IngressClasses = updatedClasses
err = handler.dataStore.Endpoint().UpdateEndpoint( err = handler.DataStore.Endpoint().UpdateEndpoint(
portainer.EndpointID(endpointID), portainer.EndpointID(endpointID),
endpoint, endpoint,
) )
@ -205,8 +205,8 @@ func (handler *Handler) updateKubernetesIngressControllers(w http.ResponseWriter
) )
} }
endpoint, err := handler.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
if err == portainerDsErrors.ErrObjectNotFound { if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.NotFound( return httperror.NotFound(
"Unable to find an environment with the specified identifier inside the database", "Unable to find an environment with the specified identifier inside the database",
err, err,
@ -227,7 +227,7 @@ func (handler *Handler) updateKubernetesIngressControllers(w http.ResponseWriter
) )
} }
cli, err := handler.kubernetesClientFactory.GetKubeClient(endpoint) cli, err := handler.KubernetesClientFactory.GetKubeClient(endpoint)
if err != nil { if err != nil {
return httperror.InternalServerError( return httperror.InternalServerError(
"Unable to create Kubernetes client", "Unable to create Kubernetes client",
@ -269,7 +269,7 @@ func (handler *Handler) updateKubernetesIngressControllers(w http.ResponseWriter
} }
endpoint.Kubernetes.Configuration.IngressClasses = newClasses endpoint.Kubernetes.Configuration.IngressClasses = newClasses
err = handler.dataStore.Endpoint().UpdateEndpoint( err = handler.DataStore.Endpoint().UpdateEndpoint(
portainer.EndpointID(endpointID), portainer.EndpointID(endpointID),
endpoint, endpoint,
) )
@ -291,8 +291,8 @@ func (handler *Handler) updateKubernetesIngressControllersByNamespace(w http.Res
) )
} }
endpoint, err := handler.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
if err == portainerDsErrors.ErrObjectNotFound { if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.NotFound( return httperror.NotFound(
"Unable to find an environment with the specified identifier inside the database", "Unable to find an environment with the specified identifier inside the database",
err, err,
@ -369,7 +369,7 @@ PayloadLoop:
} }
endpoint.Kubernetes.Configuration.IngressClasses = updatedClasses endpoint.Kubernetes.Configuration.IngressClasses = updatedClasses
err = handler.dataStore.Endpoint().UpdateEndpoint( err = handler.DataStore.Endpoint().UpdateEndpoint(
portainer.EndpointID(endpointID), portainer.EndpointID(endpointID),
endpoint, endpoint,
) )

View File

@ -73,20 +73,12 @@ func (handler *Handler) updateKubernetesNamespace(w http.ResponseWriter, r *http
var payload models.K8sNamespaceDetails var payload models.K8sNamespaceDetails
err := request.DecodeAndValidateJSONPayload(r, &payload) err := request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil { if err != nil {
return &httperror.HandlerError{ return httperror.BadRequest("Invalid request payload", err)
StatusCode: http.StatusBadRequest,
Message: "Invalid request payload",
Err: err,
}
} }
err = cli.UpdateNamespace(payload) err = cli.UpdateNamespace(payload)
if err != nil { if err != nil {
return &httperror.HandlerError{ return httperror.InternalServerError("Unable to retrieve nodes limits", err)
StatusCode: http.StatusInternalServerError,
Message: "Unable to retrieve nodes limits",
Err: err,
}
} }
return nil return nil
} }

View File

@ -32,14 +32,14 @@ func (handler *Handler) getKubernetesNodesLimits(w http.ResponseWriter, r *http.
return httperror.BadRequest("Invalid environment identifier route variable", err) return httperror.BadRequest("Invalid environment identifier route variable", err)
} }
endpoint, err := handler.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
if handler.dataStore.IsErrObjectNotFound(err) { if handler.DataStore.IsErrObjectNotFound(err) {
return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err) return httperror.NotFound("Unable to find an environment with the specified identifier inside the database", err)
} else if err != nil { } else if err != nil {
return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err) return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err)
} }
cli, err := handler.kubernetesClientFactory.GetKubeClient(endpoint) cli, err := handler.KubernetesClientFactory.GetKubeClient(endpoint)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to create Kubernetes client", err) return httperror.InternalServerError("Unable to create Kubernetes client", err)
} }

View File

@ -51,7 +51,7 @@ func (handler *Handler) namespacesToggleSystem(rw http.ResponseWriter, r *http.R
return httperror.BadRequest("Invalid request payload", err) return httperror.BadRequest("Invalid request payload", err)
} }
kubeClient, err := handler.kubernetesClientFactory.GetKubeClient(endpoint) kubeClient, err := handler.KubernetesClientFactory.GetKubeClient(endpoint)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to create kubernetes client", err) return httperror.InternalServerError("Unable to create kubernetes client", err)
} }

View File

@ -119,9 +119,7 @@ func (handler *Handler) registryCreate(w http.ResponseWriter, r *http.Request) *
Ecr: payload.Ecr, Ecr: payload.Ecr,
} }
rs := handler.DataStore.Registry() registries, err := handler.DataStore.Registry().Registries()
registries, err := rs.Registries()
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to retrieve registries from the database", err) return httperror.InternalServerError("Unable to retrieve registries from the database", err)
} }
@ -134,7 +132,7 @@ func (handler *Handler) registryCreate(w http.ResponseWriter, r *http.Request) *
} }
} }
err = rs.Create(registry) err = handler.DataStore.Registry().Create(registry)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to persist the registry inside the database", err) return httperror.InternalServerError("Unable to persist the registry inside the database", err)
} }

View File

@ -74,7 +74,7 @@ func delete_TestHandler_registryUpdate(t *testing.T) {
}, },
} }
handler.Router.ServeHTTP(w, r) handler.ServeHTTP(w, r)
assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, http.StatusOK, w.Code)
// Registry type should remain intact // Registry type should remain intact
assert.Equal(t, registry.Type, updatedRegistry.Type) assert.Equal(t, registry.Type, updatedRegistry.Type)
@ -85,5 +85,4 @@ func delete_TestHandler_registryUpdate(t *testing.T) {
assert.Equal(t, *payload.Authentication, updatedRegistry.Authentication) assert.Equal(t, *payload.Authentication, updatedRegistry.Authentication)
assert.Equal(t, *payload.Username, updatedRegistry.Username) assert.Equal(t, *payload.Username, updatedRegistry.Username)
assert.Equal(t, *payload.Password, updatedRegistry.Password) assert.Equal(t, *payload.Password, updatedRegistry.Password)
} }

View File

@ -141,7 +141,6 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
if err != nil { if err != nil {
return httperror.BadRequest("Invalid Helm repository URL. Must correspond to a valid URL format", err) return httperror.BadRequest("Invalid Helm repository URL. Must correspond to a valid URL format", err)
} }
} }
settings.HelmRepositoryURL = newHelmRepo settings.HelmRepositoryURL = newHelmRepo
@ -161,12 +160,15 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
if payload.LDAPSettings != nil { if payload.LDAPSettings != nil {
ldapReaderDN := settings.LDAPSettings.ReaderDN ldapReaderDN := settings.LDAPSettings.ReaderDN
ldapPassword := settings.LDAPSettings.Password ldapPassword := settings.LDAPSettings.Password
if payload.LDAPSettings.ReaderDN != "" { if payload.LDAPSettings.ReaderDN != "" {
ldapReaderDN = payload.LDAPSettings.ReaderDN ldapReaderDN = payload.LDAPSettings.ReaderDN
} }
if payload.LDAPSettings.Password != "" { if payload.LDAPSettings.Password != "" {
ldapPassword = payload.LDAPSettings.Password ldapPassword = payload.LDAPSettings.Password
} }
settings.LDAPSettings = *payload.LDAPSettings settings.LDAPSettings = *payload.LDAPSettings
settings.LDAPSettings.ReaderDN = ldapReaderDN settings.LDAPSettings.ReaderDN = ldapReaderDN
settings.LDAPSettings.Password = ldapPassword settings.LDAPSettings.Password = ldapPassword

View File

@ -6,8 +6,6 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/asaskevich/govalidator"
"github.com/pkg/errors"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
@ -16,6 +14,8 @@ import (
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/internal/stackutils" "github.com/portainer/portainer/api/internal/stackutils"
"github.com/asaskevich/govalidator"
"github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -438,6 +438,7 @@ func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portai
if err != nil { if err != nil {
return nil, httperror.InternalServerError("Unable to retrieve registries from the database", err) return nil, httperror.InternalServerError("Unable to retrieve registries from the database", err)
} }
filteredRegistries := security.FilterRegistries(registries, user, securityContext.UserMemberships, endpoint.ID) filteredRegistries := security.FilterRegistries(registries, user, securityContext.UserMemberships, endpoint.ID)
config := &composeStackDeploymentConfig{ config := &composeStackDeploymentConfig{

View File

@ -8,9 +8,8 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/pkg/errors"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/pkg/errors"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
@ -133,6 +132,7 @@ func (handler *Handler) createKubernetesStackFromFileContent(w http.ResponseWrit
} }
stackFolder := strconv.Itoa(int(stack.ID)) stackFolder := strconv.Itoa(int(stack.ID))
projectPath, err := handler.FileService.StoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent)) projectPath, err := handler.FileService.StoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent))
if err != nil { if err != nil {
fileType := "Manifest" fileType := "Manifest"
@ -274,7 +274,7 @@ func (handler *Handler) createKubernetesStackFromGitRepository(w http.ResponseWr
err = handler.DataStore.Stack().Create(stack) err = handler.DataStore.Stack().Create(stack)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to persist the stack inside the database", err) return httperror.InternalServerError("Unable to persist the Kubernetes stack inside the database", err)
} }
resp := &createKubernetesStackResponse{ resp := &createKubernetesStackResponse{

View File

@ -6,9 +6,9 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/asaskevich/govalidator"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
@ -378,6 +378,7 @@ func (handler *Handler) createSwarmDeployConfig(r *http.Request, stack *portaine
if err != nil { if err != nil {
return nil, httperror.InternalServerError("Unable to retrieve registries from the database", err) return nil, httperror.InternalServerError("Unable to retrieve registries from the database", err)
} }
filteredRegistries := security.FilterRegistries(registries, user, securityContext.UserMemberships, endpoint.ID) filteredRegistries := security.FilterRegistries(registries, user, securityContext.UserMemberships, endpoint.ID)
config := &swarmStackDeploymentConfig{ config := &swarmStackDeploymentConfig{

View File

@ -199,7 +199,7 @@ func (handler *Handler) deleteStack(userID portainer.UserID, stack *portainer.St
//then process the remove operation //then process the remove operation
if stack.IsComposeFormat { if stack.IsComposeFormat {
fileNames := append([]string{stack.EntryPoint}, stack.AdditionalFiles...) fileNames := append([]string{stack.EntryPoint}, stack.AdditionalFiles...)
tmpDir, err := ioutil.TempDir("", "kub_delete") tmpDir, err := ioutil.TempDir("", "kube_delete")
if err != nil { if err != nil {
return errors.Wrap(err, "failed to create temp directory for deleting kub stack") return errors.Wrap(err, "failed to create temp directory for deleting kub stack")
} }

View File

@ -1,12 +1,12 @@
package teammemberships package teammemberships
import ( import (
"net/http"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"net/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )

View File

@ -5,13 +5,14 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response" "github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
httperrors "github.com/portainer/portainer/api/http/errors" httperrors "github.com/portainer/portainer/api/http/errors"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/asaskevich/govalidator"
) )
type userUpdatePayload struct { type userUpdatePayload struct {
@ -122,5 +123,6 @@ func (handler *Handler) userUpdate(w http.ResponseWriter, r *http.Request) *http
// remove all of the users persisted API keys // remove all of the users persisted API keys
handler.apiKeyService.InvalidateUserKeyCache(user.ID) handler.apiKeyService.InvalidateUserKeyCache(user.ID)
return response.JSON(w, user) return response.JSON(w, user)
} }

View File

@ -5,13 +5,14 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response" "github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
httperrors "github.com/portainer/portainer/api/http/errors" httperrors "github.com/portainer/portainer/api/http/errors"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/asaskevich/govalidator"
) )
type userUpdatePasswordPayload struct { type userUpdatePasswordPayload struct {

View File

@ -5,11 +5,12 @@ import (
"github.com/portainer/portainer/api/internal/authorization" "github.com/portainer/portainer/api/internal/authorization"
"net/http" "net/http"
"github.com/gorilla/mux"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/docker" "github.com/portainer/portainer/api/docker"
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/gorilla/mux"
) )
// Handler is the HTTP handler used to handle webhook operations. // Handler is the HTTP handler used to handle webhook operations.

View File

@ -7,12 +7,13 @@ import (
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/internal/registryutils/access" "github.com/portainer/portainer/api/internal/registryutils/access"
"github.com/asaskevich/govalidator"
"github.com/gofrs/uuid"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response" "github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/asaskevich/govalidator"
"github.com/gofrs/uuid"
) )
type webhookCreatePayload struct { type webhookCreatePayload struct {

View File

@ -6,11 +6,12 @@ import (
"net/http/httputil" "net/http/httputil"
"time" "time"
"github.com/asaskevich/govalidator"
"github.com/gorilla/websocket"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/asaskevich/govalidator"
"github.com/gorilla/websocket"
) )
// @summary Attach a websocket // @summary Attach a websocket

View File

@ -8,11 +8,12 @@ import (
"net/http/httputil" "net/http/httputil"
"time" "time"
"github.com/asaskevich/govalidator"
"github.com/gorilla/websocket"
httperror "github.com/portainer/libhttp/error" httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request" "github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/asaskevich/govalidator"
"github.com/gorilla/websocket"
) )
type execStartOperationPayload struct { type execStartOperationPayload struct {

View File

@ -2,10 +2,11 @@ package websocket
import ( import (
"crypto/tls" "crypto/tls"
"github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/crypto"
"net" "net"
"net/url" "net/url"
"github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/crypto"
) )
func initDial(endpoint *portainer.Endpoint) (net.Conn, error) { func initDial(endpoint *portainer.Endpoint) (net.Conn, error) {

View File

@ -91,12 +91,14 @@ func (handler *Handler) websocketPodExec(w http.ResponseWriter, r *http.Request)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to proxy websocket request to agent", err) return httperror.InternalServerError("Unable to proxy websocket request to agent", err)
} }
return nil return nil
} else if endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment { } else if endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment {
err := handler.proxyEdgeAgentWebsocketRequest(w, r, params) err := handler.proxyEdgeAgentWebsocketRequest(w, r, params)
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to proxy websocket request to Edge agent", err) return httperror.InternalServerError("Unable to proxy websocket request to Edge agent", err)
} }
return nil return nil
} }

View File

@ -1,8 +1,6 @@
package websocket package websocket
import ( import "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api"
)
type webSocketRequestParams struct { type webSocketRequestParams struct {
ID string ID string

View File

@ -23,7 +23,7 @@ func (transport *Transport) proxyContainerGroupRequest(request *http.Request) (*
} }
func (transport *Transport) proxyContainerGroupPutRequest(request *http.Request) (*http.Response, error) { func (transport *Transport) proxyContainerGroupPutRequest(request *http.Request) (*http.Response, error) {
//add a lock before processing existense check //add a lock before processing existence check
transport.mutex.Lock() transport.mutex.Lock()
defer transport.mutex.Unlock() defer transport.mutex.Unlock()

View File

@ -24,7 +24,6 @@ func (transport *Transport) applyPortainerContainers(resources []interface{}) ([
continue continue
} }
responseObject, _ = transport.applyPortainerContainer(responseObject) responseObject, _ = transport.applyPortainerContainer(responseObject)
decoratedResourceData = append(decoratedResourceData, responseObject) decoratedResourceData = append(decoratedResourceData, responseObject)
} }
return decoratedResourceData, nil return decoratedResourceData, nil

View File

@ -18,6 +18,8 @@ type edgeTransport struct {
// NewAgentTransport returns a new transport that can be used to send signed requests to a Portainer Edge agent // NewAgentTransport returns a new transport that can be used to send signed requests to a Portainer Edge agent
func NewEdgeTransport(dataStore dataservices.DataStore, signatureService portainer.DigitalSignatureService, reverseTunnelService portainer.ReverseTunnelService, endpoint *portainer.Endpoint, tokenManager *tokenManager, k8sClientFactory *cli.ClientFactory) *edgeTransport { func NewEdgeTransport(dataStore dataservices.DataStore, signatureService portainer.DigitalSignatureService, reverseTunnelService portainer.ReverseTunnelService, endpoint *portainer.Endpoint, tokenManager *tokenManager, k8sClientFactory *cli.ClientFactory) *edgeTransport {
transport := &edgeTransport{ transport := &edgeTransport{
reverseTunnelService: reverseTunnelService,
signatureService: signatureService,
baseTransport: newBaseTransport( baseTransport: newBaseTransport(
&http.Transport{}, &http.Transport{},
tokenManager, tokenManager,
@ -25,8 +27,6 @@ func NewEdgeTransport(dataStore dataservices.DataStore, signatureService portain
k8sClientFactory, k8sClientFactory,
dataStore, dataStore,
), ),
reverseTunnelService: reverseTunnelService,
signatureService: signatureService,
} }
return transport return transport

View File

@ -1,8 +1,9 @@
package kubernetes package kubernetes
import ( import (
"github.com/portainer/portainer/api/internal/registryutils"
"net/http" "net/http"
"github.com/portainer/portainer/api/internal/registryutils"
) )
func (transport *baseTransport) refreshRegistry(request *http.Request, namespace string) (err error) { func (transport *baseTransport) refreshRegistry(request *http.Request, namespace string) (err error) {

View File

@ -4,7 +4,7 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/orcaman/concurrent-map" cmap "github.com/orcaman/concurrent-map"
) )
type ( type (

View File

@ -3,7 +3,6 @@ package kubernetes
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -17,6 +16,7 @@ import (
"github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/kubernetes/cli" "github.com/portainer/portainer/api/kubernetes/cli"
"github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )

View File

@ -87,7 +87,7 @@ func marshal(contentType string, data interface{}) ([]byte, error) {
} }
func unmarshal(contentType string, body []byte, returnBody interface{}) error { func unmarshal(contentType string, body []byte, returnBody interface{}) error {
// Note: contentType can look look like: "application/json" or "application/json; charset=utf-8" // Note: contentType can look like: "application/json" or "application/json; charset=utf-8"
mediaType, _, err := mime.ParseMediaType(contentType) mediaType, _, err := mime.ParseMediaType(contentType)
if err != nil { if err != nil {
return err return err

View File

@ -2,12 +2,12 @@ package utils
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv" "strconv"
"github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -18,7 +18,10 @@ func GetResponseAsJSONObject(response *http.Response) (map[string]interface{}, e
return nil, err return nil, err
} }
responseObject := responseData.(map[string]interface{}) responseObject, ok := responseData.(map[string]interface{})
if !ok {
return nil, nil
}
return responseObject, nil return responseObject, nil
} }
@ -28,6 +31,9 @@ func GetResponseAsJSONArray(response *http.Response) ([]interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if responseData == nil {
return nil, nil
}
switch responseObject := responseData.(type) { switch responseObject := responseData.(type) {
case []interface{}: case []interface{}:

View File

@ -16,7 +16,7 @@ import (
) )
type ( type (
// Manager represents a service used to manage proxies to environments (endpoints). // Manager represents a service used to manage proxies to environments (endpoints) and extensions.
Manager struct { Manager struct {
proxyFactory *factory.ProxyFactory proxyFactory *factory.ProxyFactory
endpointProxies cmap.ConcurrentMap endpointProxies cmap.ConcurrentMap

View File

@ -42,7 +42,7 @@ func AuthorizedResourceControlAccess(resourceControl *portainer.ResourceControl,
// AuthorizedResourceControlUpdate ensure that the user can update a resource control object. // AuthorizedResourceControlUpdate ensure that the user can update a resource control object.
// A non-administrator user cannot create a resource control where: // A non-administrator user cannot create a resource control where:
// * the Public flag is set false // * the Public flag is set false
// * the AdministatorsOnly flag is set to true // * the AdministratorsOnly flag is set to true
// * he wants to create a resource control without any user/team accesses // * he wants to create a resource control without any user/team accesses
// * he wants to add more than one user in the user accesses // * he wants to add more than one user in the user accesses
// * he wants to add a user in the user accesses that is not corresponding to its id // * he wants to add a user in the user accesses that is not corresponding to its id

View File

@ -409,7 +409,7 @@ func (bouncer *RequestBouncer) newRestrictedContextRequest(userID portainer.User
}, nil }, nil
} }
// EdgeComputeOperation defines a restriced edge compute operation. // EdgeComputeOperation defines a restricted edge compute operation.
// Use of this operation will only be authorized if edgeCompute is enabled in settings // Use of this operation will only be authorized if edgeCompute is enabled in settings
func (bouncer *RequestBouncer) EdgeComputeOperation(next http.Handler) http.Handler { func (bouncer *RequestBouncer) EdgeComputeOperation(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@ -12,6 +12,7 @@ import (
"github.com/portainer/portainer/api/datastore" "github.com/portainer/portainer/api/datastore"
httperrors "github.com/portainer/portainer/api/http/errors" httperrors "github.com/portainer/portainer/api/http/errors"
"github.com/portainer/portainer/api/jwt" "github.com/portainer/portainer/api/jwt"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -74,7 +74,6 @@ func FilterRegistries(registries []portainer.Registry, user *portainer.User, tea
} }
filteredRegistries := []portainer.Registry{} filteredRegistries := []portainer.Registry{}
for _, registry := range registries { for _, registry := range registries {
if AuthorizedRegistryAccess(&registry, user, teamMemberships, endpointID) { if AuthorizedRegistryAccess(&registry, user, teamMemberships, endpointID) {
filteredRegistries = append(filteredRegistries, registry) filteredRegistries = append(filteredRegistries, registry)

View File

@ -1,7 +1,8 @@
package edge package edge
import ( import (
"github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/endpointutils"
"github.com/portainer/portainer/api/internal/tag" "github.com/portainer/portainer/api/internal/tag"
) )
@ -13,7 +14,7 @@ func EdgeGroupRelatedEndpoints(edgeGroup *portainer.EdgeGroup, endpoints []porta
endpointIDs := []portainer.EndpointID{} endpointIDs := []portainer.EndpointID{}
for _, endpoint := range endpoints { for _, endpoint := range endpoints {
if endpoint.Type != portainer.EdgeAgentOnDockerEnvironment && endpoint.Type != portainer.EdgeAgentOnKubernetesEnvironment { if !endpointutils.IsEdgeEndpoint(&endpoint) {
continue continue
} }

View File

@ -2,6 +2,7 @@ package edge
import ( import (
"errors" "errors"
"github.com/portainer/portainer/api" "github.com/portainer/portainer/api"
) )

View File

@ -23,5 +23,4 @@ func EndpointRelatedEdgeStacks(endpoint *portainer.Endpoint, endpointGroup *port
} }
return relatedEdgeStacks return relatedEdgeStacks
} }

View File

@ -3,6 +3,7 @@ package registryutils
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
) )

View File

@ -213,6 +213,10 @@ func (service *Service) snapshotEndpoints() error {
continue continue
} }
if endpoint.URL == "" {
continue
}
snapshotError := service.SnapshotEndpoint(&endpoint) snapshotError := service.SnapshotEndpoint(&endpoint)
latestEndpointReference, err := service.dataStore.Endpoint().Endpoint(endpoint.ID) latestEndpointReference, err := service.dataStore.Endpoint().Endpoint(endpoint.ID)

View File

@ -11,7 +11,6 @@ import (
// to prevent an error when url has port but no protocol prefix // to prevent an error when url has port but no protocol prefix
// we add `//` prefix if needed // we add `//` prefix if needed
func ParseURL(endpointURL string) (*url.URL, error) { func ParseURL(endpointURL string) (*url.URL, error) {
if !strings.HasPrefix(endpointURL, "http") && if !strings.HasPrefix(endpointURL, "http") &&
!strings.HasPrefix(endpointURL, "tcp") && !strings.HasPrefix(endpointURL, "tcp") &&
!strings.HasPrefix(endpointURL, "//") && !strings.HasPrefix(endpointURL, "//") &&

View File

@ -1,8 +1,9 @@
package jwt package jwt
import ( import (
portainer "github.com/portainer/portainer/api"
"time" "time"
portainer "github.com/portainer/portainer/api"
) )
// GenerateTokenForKubeconfig generates a new JWT token for Kubeconfig // GenerateTokenForKubeconfig generates a new JWT token for Kubeconfig

Some files were not shown because too many files have changed in this diff Show More