1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-19 05:19:39 +02:00

chore(portainer): clean up the code EE-5188 (#8660)

This commit is contained in:
andres-portainer 2023-03-13 13:18:28 -03:00 committed by GitHub
parent 621a01ba3b
commit 15cbdb8af9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 111 additions and 65 deletions

View file

@ -72,6 +72,7 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
*flags.Assets = filepath.Join(filepath.Dir(ex), *flags.Assets) *flags.Assets = filepath.Join(filepath.Dir(ex), *flags.Assets)
} }
@ -80,7 +81,6 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
// ValidateFlags validates the values of the flags. // ValidateFlags validates the values of the flags.
func (*Service) ValidateFlags(flags *portainer.CLIFlags) error { func (*Service) ValidateFlags(flags *portainer.CLIFlags) error {
displayDeprecationWarnings(flags) displayDeprecationWarnings(flags)
err := validateEndpointURL(*flags.EndpointURL) err := validateEndpointURL(*flags.EndpointURL)
@ -111,31 +111,38 @@ func displayDeprecationWarnings(flags *portainer.CLIFlags) {
} }
func validateEndpointURL(endpointURL string) error { func validateEndpointURL(endpointURL string) error {
if endpointURL != "" { if endpointURL == "" {
if !strings.HasPrefix(endpointURL, "unix://") && !strings.HasPrefix(endpointURL, "tcp://") && !strings.HasPrefix(endpointURL, "npipe://") { return nil
return errInvalidEndpointProtocol }
}
if strings.HasPrefix(endpointURL, "unix://") || strings.HasPrefix(endpointURL, "npipe://") { if !strings.HasPrefix(endpointURL, "unix://") && !strings.HasPrefix(endpointURL, "tcp://") && !strings.HasPrefix(endpointURL, "npipe://") {
socketPath := strings.TrimPrefix(endpointURL, "unix://") return errInvalidEndpointProtocol
socketPath = strings.TrimPrefix(socketPath, "npipe://") }
if _, err := os.Stat(socketPath); err != nil {
if os.IsNotExist(err) { if strings.HasPrefix(endpointURL, "unix://") || strings.HasPrefix(endpointURL, "npipe://") {
return errSocketOrNamedPipeNotFound socketPath := strings.TrimPrefix(endpointURL, "unix://")
} socketPath = strings.TrimPrefix(socketPath, "npipe://")
return err if _, err := os.Stat(socketPath); err != nil {
if os.IsNotExist(err) {
return errSocketOrNamedPipeNotFound
} }
return err
} }
} }
return nil return nil
} }
func validateSnapshotInterval(snapshotInterval string) error { func validateSnapshotInterval(snapshotInterval string) error {
if snapshotInterval != "" { if snapshotInterval == "" {
_, err := time.ParseDuration(snapshotInterval) return nil
if err != nil {
return errInvalidSnapshotInterval
}
} }
_, err := time.ParseDuration(snapshotInterval)
if err != nil {
return errInvalidSnapshotInterval
}
return nil return nil
} }

View file

@ -12,13 +12,14 @@ func Confirm(message string) (bool, error) {
fmt.Printf("%s [y/N]", message) fmt.Printf("%s [y/N]", message)
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
answer, err := reader.ReadString('\n') answer, err := reader.ReadString('\n')
if err != nil { if err != nil {
return false, err return false, err
} }
answer = strings.Replace(answer, "\n", "", -1)
answer = strings.ReplaceAll(answer, "\n", "")
answer = strings.ToLower(answer) answer = strings.ToLower(answer)
return answer == "y" || answer == "yes", nil return answer == "y" || answer == "yes", nil
} }

View file

@ -7,7 +7,6 @@ import (
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"math/big"
"github.com/portainer/libcrypto" "github.com/portainer/libcrypto"
) )
@ -115,9 +114,6 @@ func (service *ECDSAService) CreateSignature(message string) (string, error) {
hash := libcrypto.HashFromBytes([]byte(message)) hash := libcrypto.HashFromBytes([]byte(message))
r := big.NewInt(0)
s := big.NewInt(0)
r, s, err := ecdsa.Sign(rand.Reader, service.privateKey, hash) r, s, err := ecdsa.Sign(rand.Reader, service.privateKey, hash)
if err != nil { if err != nil {
return "", err return "", err

View file

@ -129,7 +129,7 @@ func Test_UnMarshalObjectUnencrypted(t *testing.T) {
var object string var object string
err := conn.UnmarshalObject(test.object, &object) err := conn.UnmarshalObject(test.object, &object)
is.NoError(err) is.NoError(err)
is.Equal(test.expected, string(object)) is.Equal(test.expected, object)
}) })
} }
} }

View file

@ -92,7 +92,7 @@ func (tx *DbTransaction) CreateObject(bucketName string, fn func(uint64) (int, i
return err return err
} }
return bucket.Put(tx.conn.ConvertToKey(int(id)), data) return bucket.Put(tx.conn.ConvertToKey(id), data)
} }
func (tx *DbTransaction) CreateObjectWithId(bucketName string, id int, obj interface{}) error { func (tx *DbTransaction) CreateObjectWithId(bucketName string, id int, obj interface{}) error {

View file

@ -9,8 +9,7 @@ import (
// NewDatabase should use config options to return a connection to the requested database // NewDatabase should use config options to return a connection to the requested database
func NewDatabase(storeType, storePath string, encryptionKey []byte) (connection portainer.Connection, err error) { func NewDatabase(storeType, storePath string, encryptionKey []byte) (connection portainer.Connection, err error) {
switch storeType { if storeType == "boltdb" {
case "boltdb":
return &boltdb.DbConnection{ return &boltdb.DbConnection{
Path: storePath, Path: storePath,
EncryptionKey: encryptionKey, EncryptionKey: encryptionKey,

View file

@ -8,6 +8,7 @@ import (
"github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/docker" "github.com/portainer/portainer/api/docker"
"github.com/portainer/portainer/api/kubernetes/cli" "github.com/portainer/portainer/api/kubernetes/cli"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -17,11 +18,7 @@ type PostInitMigrator struct {
dataStore dataservices.DataStore dataStore dataservices.DataStore
} }
func NewPostInitMigrator( func NewPostInitMigrator(kubeFactory *cli.ClientFactory, dockerFactory *docker.ClientFactory, dataStore dataservices.DataStore) *PostInitMigrator {
kubeFactory *cli.ClientFactory,
dockerFactory *docker.ClientFactory,
dataStore dataservices.DataStore,
) *PostInitMigrator {
return &PostInitMigrator{ return &PostInitMigrator{
kubeFactory: kubeFactory, kubeFactory: kubeFactory,
dockerFactory: dockerFactory, dockerFactory: dockerFactory,
@ -44,9 +41,10 @@ func (migrator *PostInitMigrator) PostInitMigrateIngresses() error {
if err != nil { if err != nil {
return err return err
} }
for i := range endpoints { for i := range endpoints {
// Early exit if we do not need to migrate! // Early exit if we do not need to migrate!
if endpoints[i].PostInitMigrations.MigrateIngresses == false { if !endpoints[i].PostInitMigrations.MigrateIngresses {
return nil return nil
} }
@ -67,10 +65,11 @@ func (migrator *PostInitMigrator) PostInitMigrateGPUs() {
log.Err(err).Msg("failure getting endpoints") log.Err(err).Msg("failure getting endpoints")
return return
} }
for i := range environments { for i := range environments {
if environments[i].Type == portainer.DockerEnvironment { if environments[i].Type == portainer.DockerEnvironment {
// // Early exit if we do not need to migrate! // // Early exit if we do not need to migrate!
if environments[i].PostInitMigrations.MigrateGPUs == false { if !environments[i].PostInitMigrations.MigrateGPUs {
return return
} }
@ -102,11 +101,13 @@ func (migrator *PostInitMigrator) PostInitMigrateGPUs() {
log.Err(err).Msg("failed to inspect container") log.Err(err).Msg("failed to inspect container")
return return
} }
deviceRequests := containerDetails.HostConfig.Resources.DeviceRequests deviceRequests := containerDetails.HostConfig.Resources.DeviceRequests
for _, deviceRequest := range deviceRequests { for _, deviceRequest := range deviceRequests {
if deviceRequest.Driver == "nvidia" { if deviceRequest.Driver == "nvidia" {
environments[i].EnableGPUManagement = true environments[i].EnableGPUManagement = true
migrator.dataStore.Endpoint().UpdateEndpoint(environments[i].ID, &environments[i]) migrator.dataStore.Endpoint().UpdateEndpoint(environments[i].ID, &environments[i])
break containersLoop break containersLoop
} }
} }

View file

@ -38,17 +38,19 @@ func NewClientFactory(signatureService portainer.DigitalSignatureService, revers
// with an agent enabled environment(endpoint) to target a specific node in an agent cluster. // with an agent enabled environment(endpoint) to target a specific node in an agent cluster.
// The underlying http client timeout may be specified, a default value is used otherwise. // The underlying http client timeout may be specified, a default value is used otherwise.
func (factory *ClientFactory) CreateClient(endpoint *portainer.Endpoint, nodeName string, timeout *time.Duration) (*client.Client, error) { func (factory *ClientFactory) CreateClient(endpoint *portainer.Endpoint, nodeName string, timeout *time.Duration) (*client.Client, error) {
if endpoint.Type == portainer.AzureEnvironment { switch endpoint.Type {
case portainer.AzureEnvironment:
return nil, errUnsupportedEnvironmentType return nil, errUnsupportedEnvironmentType
} else if endpoint.Type == portainer.AgentOnDockerEnvironment { case portainer.AgentOnDockerEnvironment:
return createAgentClient(endpoint, factory.signatureService, nodeName, timeout) return createAgentClient(endpoint, factory.signatureService, nodeName, timeout)
} else if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment { case portainer.EdgeAgentOnDockerEnvironment:
return createEdgeClient(endpoint, factory.signatureService, factory.reverseTunnelService, nodeName, timeout) return createEdgeClient(endpoint, factory.signatureService, factory.reverseTunnelService, nodeName, timeout)
} }
if strings.HasPrefix(endpoint.URL, "unix://") || strings.HasPrefix(endpoint.URL, "npipe://") { if strings.HasPrefix(endpoint.URL, "unix://") || strings.HasPrefix(endpoint.URL, "npipe://") {
return createLocalClient(endpoint) return createLocalClient(endpoint)
} }
return createTCPClient(endpoint, timeout) return createTCPClient(endpoint, timeout)
} }

View file

@ -59,6 +59,7 @@ func (manager *SwarmStackManager) Login(registries []portainer.Registry, endpoin
if err != nil { if err != nil {
return err return err
} }
for _, registry := range registries { for _, registry := range registries {
if registry.Authentication { if registry.Authentication {
err = registryutils.EnsureRegTokenValid(manager.dataStore, &registry) err = registryutils.EnsureRegTokenValid(manager.dataStore, &registry)
@ -75,6 +76,7 @@ func (manager *SwarmStackManager) Login(registries []portainer.Registry, endpoin
runCommandAndCaptureStdErr(command, registryArgs, nil, "") runCommandAndCaptureStdErr(command, registryArgs, nil, "")
} }
} }
return nil return nil
} }
@ -84,7 +86,9 @@ func (manager *SwarmStackManager) Logout(endpoint *portainer.Endpoint) error {
if err != nil { if err != nil {
return err return err
} }
args = append(args, "logout") args = append(args, "logout")
return runCommandAndCaptureStdErr(command, args, nil, "") return runCommandAndCaptureStdErr(command, args, nil, "")
} }
@ -101,6 +105,7 @@ func (manager *SwarmStackManager) Deploy(stack *portainer.Stack, prune bool, pul
} else { } else {
args = append(args, "stack", "deploy", "--with-registry-auth") args = append(args, "stack", "deploy", "--with-registry-auth")
} }
if !pullImage { if !pullImage {
args = append(args, "--resolve-image=never") args = append(args, "--resolve-image=never")
} }
@ -112,6 +117,7 @@ func (manager *SwarmStackManager) Deploy(stack *portainer.Stack, prune bool, pul
for _, envvar := range stack.Env { for _, envvar := range stack.Env {
env = append(env, envvar.Name+"="+envvar.Value) env = append(env, envvar.Name+"="+envvar.Value)
} }
return runCommandAndCaptureStdErr(command, args, env, stack.ProjectPath) return runCommandAndCaptureStdErr(command, args, env, stack.ProjectPath)
} }
@ -121,7 +127,9 @@ func (manager *SwarmStackManager) Remove(stack *portainer.Stack, endpoint *porta
if err != nil { if err != nil {
return err return err
} }
args = append(args, "stack", "rm", stack.Name) args = append(args, "stack", "rm", stack.Name)
return runCommandAndCaptureStdErr(command, args, nil, "") return runCommandAndCaptureStdErr(command, args, nil, "")
} }
@ -198,6 +206,7 @@ func (manager *SwarmStackManager) updateDockerCLIConfiguration(configPath string
if config["HttpHeaders"] == nil { if config["HttpHeaders"] == nil {
config["HttpHeaders"] = make(map[string]interface{}) config["HttpHeaders"] = make(map[string]interface{})
} }
headersObject := config["HttpHeaders"].(map[string]interface{}) headersObject := config["HttpHeaders"].(map[string]interface{})
headersObject["X-PortainerAgent-ManagerOperation"] = "1" headersObject["X-PortainerAgent-ManagerOperation"] = "1"
headersObject["X-PortainerAgent-Signature"] = signature headersObject["X-PortainerAgent-Signature"] = signature
@ -230,5 +239,6 @@ func configureFilePaths(args []string, filePaths []string) []string {
for _, path := range filePaths { for _, path := range filePaths {
args = append(args, "--compose-file", path) args = append(args, "--compose-file", path)
} }
return args return args
} }

View file

@ -75,6 +75,7 @@ func newHttpClientForAzure() *http.Client {
} }
client.InstallProtocol("https", githttp.NewClient(httpsCli)) client.InstallProtocol("https", githttp.NewClient(httpsCli))
return httpsCli return httpsCli
} }
@ -98,10 +99,12 @@ func (a *azureClient) downloadZipFromAzureDevOps(ctx context.Context, opt cloneO
if err != nil { if err != nil {
return "", errors.WithMessage(err, "failed to parse url") return "", errors.WithMessage(err, "failed to parse url")
} }
downloadUrl, err := a.buildDownloadUrl(config, opt.referenceName) downloadUrl, err := a.buildDownloadUrl(config, opt.referenceName)
if err != nil { if err != nil {
return "", errors.WithMessage(err, "failed to build download url") return "", errors.WithMessage(err, "failed to build download url")
} }
zipFile, err := os.CreateTemp("", "azure-git-repo-*.zip") zipFile, err := os.CreateTemp("", "azure-git-repo-*.zip")
if err != nil { if err != nil {
return "", errors.WithMessage(err, "failed to create temp file") return "", errors.WithMessage(err, "failed to create temp file")
@ -133,6 +136,7 @@ func (a *azureClient) downloadZipFromAzureDevOps(ctx context.Context, opt cloneO
if err != nil { if err != nil {
return "", errors.WithMessage(err, "failed to save HTTP response to a file") return "", errors.WithMessage(err, "failed to save HTTP response to a file")
} }
return zipFile.Name(), nil return zipFile.Name(), nil
} }
@ -141,6 +145,7 @@ func (a *azureClient) latestCommitID(ctx context.Context, opt fetchOption) (stri
if err != nil { if err != nil {
return "", err return "", err
} }
return rootItem.CommitId, nil return rootItem.CommitId, nil
} }
@ -187,6 +192,7 @@ func (a *azureClient) getRootItem(ctx context.Context, opt fetchOption) (*azureI
if len(items.Value) == 0 || items.Value[0].CommitId == "" { if len(items.Value) == 0 || items.Value[0].CommitId == "" {
return nil, errors.Errorf("failed to get latest commitID in the repository") return nil, errors.Errorf("failed to get latest commitID in the repository")
} }
return &items.Value[0], nil return &items.Value[0], nil
} }
@ -205,7 +211,7 @@ func parseUrl(rawUrl string) (*azureOptions, error) {
return nil, errors.Errorf("supported url schemes are https and ssh; recevied URL %s rawUrl", rawUrl) return nil, errors.Errorf("supported url schemes are https and ssh; recevied URL %s rawUrl", rawUrl)
} }
var expectedSshUrl = "git@ssh.dev.azure.com:v3/Organisation/Project/Repository" const expectedSshUrl = "git@ssh.dev.azure.com:v3/Organisation/Project/Repository"
func parseSshUrl(rawUrl string) (*azureOptions, error) { func parseSshUrl(rawUrl string) (*azureOptions, error) {
path := strings.Split(rawUrl, "/") path := strings.Split(rawUrl, "/")
@ -343,6 +349,7 @@ func (a *azureClient) buildTreeUrl(config *azureOptions, rootObjectHash string)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "failed to parse list tree url path %s", rawUrl) return "", errors.Wrapf(err, "failed to parse list tree url path %s", rawUrl)
} }
q := u.Query() q := u.Query()
// projectId={projectId}&recursive=true&fileName={fileName}&$format={$format}&api-version=6.0 // projectId={projectId}&recursive=true&fileName={fileName}&$format={$format}&api-version=6.0
q.Set("recursive", "true") q.Set("recursive", "true")
@ -361,9 +368,11 @@ func formatReferenceName(name string) string {
if strings.HasPrefix(name, branchPrefix) { if strings.HasPrefix(name, branchPrefix) {
return strings.TrimPrefix(name, branchPrefix) return strings.TrimPrefix(name, branchPrefix)
} }
if strings.HasPrefix(name, tagPrefix) { if strings.HasPrefix(name, tagPrefix) {
return strings.TrimPrefix(name, tagPrefix) return strings.TrimPrefix(name, tagPrefix)
} }
return name return name
} }
@ -371,9 +380,11 @@ func getVersionType(name string) string {
if strings.HasPrefix(name, branchPrefix) { if strings.HasPrefix(name, branchPrefix) {
return "branch" return "branch"
} }
if strings.HasPrefix(name, tagPrefix) { if strings.HasPrefix(name, tagPrefix) {
return "tag" return "tag"
} }
return "commit" return "commit"
} }
@ -490,5 +501,6 @@ func checkAzureStatusCode(err error, code int) error {
} else if code == http.StatusUnauthorized || code == http.StatusNonAuthoritativeInfo { } else if code == http.StatusUnauthorized || code == http.StatusNonAuthoritativeInfo {
return gittypes.ErrAuthenticationFailure return gittypes.ErrAuthenticationFailure
} }
return err return err
} }

View file

@ -8,14 +8,13 @@ import (
"testing" "testing"
"time" "time"
_ "github.com/joho/godotenv/autoload"
gittypes "github.com/portainer/portainer/api/git/types" gittypes "github.com/portainer/portainer/api/git/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
var ( const privateAzureRepoURL = "https://portainer.visualstudio.com/gitops-test/_git/gitops-test"
privateAzureRepoURL = "https://portainer.visualstudio.com/gitops-test/_git/gitops-test"
)
func TestService_ClonePublicRepository_Azure(t *testing.T) { func TestService_ClonePublicRepository_Azure(t *testing.T) {
ensureIntegrationTest(t) ensureIntegrationTest(t)
@ -107,7 +106,7 @@ func TestService_ListRefs_Azure_Concurrently(t *testing.T) {
accessToken := getRequiredValue(t, "AZURE_DEVOPS_PAT") accessToken := getRequiredValue(t, "AZURE_DEVOPS_PAT")
username := getRequiredValue(t, "AZURE_DEVOPS_USERNAME") username := getRequiredValue(t, "AZURE_DEVOPS_USERNAME")
service := newService(context.TODO(), REPOSITORY_CACHE_SIZE, 200*time.Millisecond) service := newService(context.TODO(), repositoryCacheSize, 200*time.Millisecond)
go service.ListRefs(privateAzureRepoURL, username, accessToken, false) go service.ListRefs(privateAzureRepoURL, username, accessToken, false)
service.ListRefs(privateAzureRepoURL, username, accessToken, false) service.ListRefs(privateAzureRepoURL, username, accessToken, false)
@ -269,7 +268,7 @@ func TestService_ListFiles_Azure_Concurrently(t *testing.T) {
accessToken := getRequiredValue(t, "AZURE_DEVOPS_PAT") accessToken := getRequiredValue(t, "AZURE_DEVOPS_PAT")
username := getRequiredValue(t, "AZURE_DEVOPS_USERNAME") username := getRequiredValue(t, "AZURE_DEVOPS_USERNAME")
service := newService(context.TODO(), REPOSITORY_CACHE_SIZE, 200*time.Millisecond) service := newService(context.TODO(), repositoryCacheSize, 200*time.Millisecond)
go service.ListFiles(privateAzureRepoURL, "refs/heads/main", username, accessToken, false, []string{}) go service.ListFiles(privateAzureRepoURL, "refs/heads/main", username, accessToken, false, []string{})
service.ListFiles(privateAzureRepoURL, "refs/heads/main", username, accessToken, false, []string{}) service.ListFiles(privateAzureRepoURL, "refs/heads/main", username, accessToken, false, []string{})

View file

@ -60,7 +60,7 @@ func TestService_ListRefs_Github_Concurrently(t *testing.T) {
accessToken := getRequiredValue(t, "GITHUB_PAT") accessToken := getRequiredValue(t, "GITHUB_PAT")
username := getRequiredValue(t, "GITHUB_USERNAME") username := getRequiredValue(t, "GITHUB_USERNAME")
service := newService(context.TODO(), REPOSITORY_CACHE_SIZE, 200*time.Millisecond) service := newService(context.TODO(), repositoryCacheSize, 200*time.Millisecond)
repositoryUrl := privateGitRepoURL repositoryUrl := privateGitRepoURL
go service.ListRefs(repositoryUrl, username, accessToken, false) go service.ListRefs(repositoryUrl, username, accessToken, false)
@ -224,7 +224,7 @@ func TestService_ListFiles_Github_Concurrently(t *testing.T) {
repositoryUrl := privateGitRepoURL repositoryUrl := privateGitRepoURL
accessToken := getRequiredValue(t, "GITHUB_PAT") accessToken := getRequiredValue(t, "GITHUB_PAT")
username := getRequiredValue(t, "GITHUB_USERNAME") username := getRequiredValue(t, "GITHUB_USERNAME")
service := newService(context.TODO(), REPOSITORY_CACHE_SIZE, 200*time.Millisecond) service := newService(context.TODO(), repositoryCacheSize, 200*time.Millisecond)
go service.ListFiles(repositoryUrl, "refs/heads/main", username, accessToken, false, []string{}) go service.ListFiles(repositoryUrl, "refs/heads/main", username, accessToken, false, []string{})
service.ListFiles(repositoryUrl, "refs/heads/main", username, accessToken, false, []string{}) service.ListFiles(repositoryUrl, "refs/heads/main", username, accessToken, false, []string{})

View file

@ -95,10 +95,12 @@ func getCommitHistoryLength(t *testing.T, err error, dir string) int {
if err != nil { if err != nil {
t.Fatalf("can't open a git repo at %s with error %v", dir, err) t.Fatalf("can't open a git repo at %s with error %v", dir, err)
} }
iter, err := repo.Log(&git.LogOptions{All: true}) iter, err := repo.Log(&git.LogOptions{All: true})
if err != nil { if err != nil {
t.Fatalf("can't get a commit history iterator with error %v", err) t.Fatalf("can't get a commit history iterator with error %v", err)
} }
count := 0 count := 0
err = iter.ForEach(func(_ *object.Commit) error { err = iter.ForEach(func(_ *object.Commit) error {
count++ count++
@ -107,6 +109,7 @@ func getCommitHistoryLength(t *testing.T, err error, dir string) int {
if err != nil { if err != nil {
t.Fatalf("can't iterate over the commit history with error %v", err) t.Fatalf("can't iterate over the commit history with error %v", err)
} }
return count return count
} }

View file

@ -10,9 +10,9 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
var ( const (
REPOSITORY_CACHE_SIZE = 4 repositoryCacheSize = 4
REPOSITORY_CACHE_TTL = 5 * time.Minute repositoryCacheTTL = 5 * time.Minute
) )
// baseOption provides a minimum group of information to operate a git repository, like git-remote // baseOption provides a minimum group of information to operate a git repository, like git-remote
@ -58,7 +58,7 @@ type Service struct {
// NewService initializes a new service. // NewService initializes a new service.
func NewService(ctx context.Context) *Service { func NewService(ctx context.Context) *Service {
return newService(ctx, REPOSITORY_CACHE_SIZE, REPOSITORY_CACHE_TTL) return newService(ctx, repositoryCacheSize, repositoryCacheTTL)
} }
func newService(ctx context.Context, cacheSize int, cacheTTL time.Duration) *Service { func newService(ctx context.Context, cacheSize int, cacheTTL time.Duration) *Service {

View file

@ -34,7 +34,7 @@ func UpdateGitObject(gitService portainer.GitService, dataStore dataservices.Dat
return false, "", errors.WithMessagef(err, "failed to fetch latest commit id of %v", objId) return false, "", errors.WithMessagef(err, "failed to fetch latest commit id of %v", objId)
} }
hashChanged := !strings.EqualFold(newHash, string(gitConfig.ConfigHash)) hashChanged := !strings.EqualFold(newHash, gitConfig.ConfigHash)
forceUpdate := autoUpdateConfig != nil && autoUpdateConfig.ForceUpdate forceUpdate := autoUpdateConfig != nil && autoUpdateConfig.ForceUpdate
if !hashChanged && !forceUpdate { if !hashChanged && !forceUpdate {
log.Debug(). log.Debug().

View file

@ -48,15 +48,16 @@ func (handler *Handler) createProfile(w http.ResponseWriter, r *http.Request) *h
return httperror.BadRequest("Invalid query parameter: method", err) return httperror.BadRequest("Invalid query parameter: method", err)
} }
switch method { if method == "editor" {
case "editor":
return handler.createFDOProfileFromFileContent(w, r) return handler.createFDOProfileFromFileContent(w, r)
} }
return httperror.BadRequest("Invalid method. Value must be one of: editor", errors.New("invalid method")) return httperror.BadRequest("Invalid method. Value must be one of: editor", errors.New("invalid method"))
} }
func (handler *Handler) createFDOProfileFromFileContent(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { func (handler *Handler) createFDOProfileFromFileContent(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
var payload createProfileFromFileContentPayload var payload createProfileFromFileContentPayload
err := request.DecodeAndValidateJSONPayload(r, &payload) err := request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil { if err != nil {
return httperror.BadRequest("Invalid request payload", err) return httperror.BadRequest("Invalid request payload", err)
@ -66,6 +67,7 @@ func (handler *Handler) createFDOProfileFromFileContent(w http.ResponseWriter, r
if err != nil { if err != nil {
return httperror.InternalServerError(err.Error(), err) return httperror.InternalServerError(err.Error(), err)
} }
if !isUnique { if !isUnique {
return &httperror.HandlerError{StatusCode: http.StatusConflict, Message: fmt.Sprintf("A profile with the name '%s' already exists", payload.Name), Err: errors.New("a profile already exists with this name")} return &httperror.HandlerError{StatusCode: http.StatusConflict, Message: fmt.Sprintf("A profile with the name '%s' already exists", payload.Name), Err: errors.New("a profile already exists with this name")}
} }
@ -80,6 +82,7 @@ func (handler *Handler) createFDOProfileFromFileContent(w http.ResponseWriter, r
if err != nil { if err != nil {
return httperror.InternalServerError("Unable to persist profile file on disk", err) return httperror.InternalServerError("Unable to persist profile file on disk", err)
} }
profile.FilePath = filePath profile.FilePath = filePath
profile.DateCreated = time.Now().Unix() profile.DateCreated = time.Now().Unix()

View file

@ -63,6 +63,7 @@ func (handler *Handler) ifRequestedTemplateExists(payload *filePayload) *httperr
return nil return nil
} }
} }
return httperror.InternalServerError("Invalid template", errors.New("requested template does not exist")) return httperror.InternalServerError("Invalid template", errors.New("requested template does not exist"))
} }
@ -82,6 +83,7 @@ func (handler *Handler) ifRequestedTemplateExists(payload *filePayload) *httperr
// @router /templates/file [post] // @router /templates/file [post]
func (handler *Handler) templateFile(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { func (handler *Handler) templateFile(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
var payload filePayload var payload filePayload
err := request.DecodeAndValidateJSONPayload(r, &payload) err := request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil { if err != nil {
return httperror.BadRequest("Invalid request payload", err) return httperror.BadRequest("Invalid request payload", err)
@ -112,11 +114,9 @@ func (handler *Handler) templateFile(w http.ResponseWriter, r *http.Request) *ht
} }
func (handler *Handler) cleanUp(projectPath string) error { func (handler *Handler) cleanUp(projectPath string) {
err := handler.FileService.RemoveDirectory(projectPath) err := handler.FileService.RemoveDirectory(projectPath)
if err != nil { if err != nil {
log.Debug().Err(err).Msg("HTTP error: unable to cleanup stack creation") log.Debug().Err(err).Msg("HTTP error: unable to cleanup stack creation")
} }
return nil
} }

View file

@ -14,30 +14,35 @@ func streamFromWebsocketToWriter(websocketConn *websocket.Conn, writer io.Writer
_, in, err := websocketConn.ReadMessage() _, in, err := websocketConn.ReadMessage()
if err != nil { if err != nil {
errorChan <- err errorChan <- err
break break
} }
_, err = writer.Write(in) _, err = writer.Write(in)
if err != nil { if err != nil {
errorChan <- err errorChan <- err
break break
} }
} }
} }
func streamFromReaderToWebsocket(websocketConn *websocket.Conn, reader io.Reader, errorChan chan error) { func streamFromReaderToWebsocket(websocketConn *websocket.Conn, reader io.Reader, errorChan chan error) {
out := make([]byte, readerBufferSize)
for { for {
out := make([]byte, readerBufferSize)
_, err := reader.Read(out) _, err := reader.Read(out)
if err != nil { if err != nil {
errorChan <- err errorChan <- err
break break
} }
processedOutput := validString(string(out[:])) processedOutput := validString(string(out))
err = websocketConn.WriteMessage(websocket.TextMessage, []byte(processedOutput)) err = websocketConn.WriteMessage(websocket.TextMessage, []byte(processedOutput))
if err != nil { if err != nil {
errorChan <- err errorChan <- err
break break
} }
} }
@ -46,6 +51,7 @@ func streamFromReaderToWebsocket(websocketConn *websocket.Conn, reader io.Reader
func validString(s string) string { func validString(s string) string {
if !utf8.ValidString(s) { if !utf8.ValidString(s) {
v := make([]rune, 0, len(s)) v := make([]rune, 0, len(s))
for i, r := range s { for i, r := range s {
if r == utf8.RuneError { if r == utf8.RuneError {
_, size := utf8.DecodeRuneInString(s[i:]) _, size := utf8.DecodeRuneInString(s[i:])
@ -53,9 +59,12 @@ func validString(s string) string {
continue continue
} }
} }
v = append(v, r) v = append(v, r)
} }
s = string(v) s = string(v)
} }
return s return s
} }

View file

@ -26,6 +26,7 @@ func (transport *Transport) applyPortainerContainers(resources []interface{}) ([
responseObject, _ = transport.applyPortainerContainer(responseObject) responseObject, _ = transport.applyPortainerContainer(responseObject)
decoratedResourceData = append(decoratedResourceData, responseObject) decoratedResourceData = append(decoratedResourceData, responseObject)
} }
return decoratedResourceData, nil return decoratedResourceData, nil
} }
@ -34,8 +35,10 @@ func (transport *Transport) applyPortainerContainer(resourceObject map[string]in
if !ok { if !ok {
return resourceObject, nil return resourceObject, nil
} }
if len(resourceId) >= 12 && resourceId[0:12] == portainerContainerId { if len(resourceId) >= 12 && resourceId[0:12] == portainerContainerId {
resourceObject["IsPortainer"] = true resourceObject["IsPortainer"] = true
} }
return resourceObject, nil return resourceObject, nil
} }

View file

@ -150,8 +150,7 @@ func (transport *baseTransport) getRoundTripToken(request *http.Request, tokenMa
func decorateAgentRequest(r *http.Request, dataStore dataservices.DataStore) error { func decorateAgentRequest(r *http.Request, dataStore dataservices.DataStore) error {
requestPath := strings.TrimPrefix(r.URL.Path, "/v2") requestPath := strings.TrimPrefix(r.URL.Path, "/v2")
switch { if strings.HasPrefix(requestPath, "/dockerhub") {
case strings.HasPrefix(requestPath, "/dockerhub"):
return decorateAgentDockerHubRequest(r, dataStore) return decorateAgentDockerHubRequest(r, dataStore)
} }

View file

@ -8,13 +8,14 @@ import (
"strings" "strings"
"time" "time"
"github.com/cbroglie/mustache"
"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/docker/docker/client" "github.com/docker/docker/client"
"github.com/pkg/errors"
libstack "github.com/portainer/docker-compose-wrapper" libstack "github.com/portainer/docker-compose-wrapper"
"github.com/portainer/portainer/api/filesystem" "github.com/portainer/portainer/api/filesystem"
"github.com/cbroglie/mustache"
"github.com/pkg/errors"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -65,7 +66,7 @@ func (service *service) upgradeDocker(licenseKey, version, envType string) error
projectName := fmt.Sprintf( projectName := fmt.Sprintf(
"portainer-upgrade-%d-%s", "portainer-upgrade-%d-%s",
timeId, timeId,
strings.Replace(version, ".", "-", -1)) strings.ReplaceAll(version, ".", "-"))
err = service.composeDeployer.Deploy( err = service.composeDeployer.Deploy(
ctx, ctx,

View file

@ -98,7 +98,7 @@ func (service *kubeClusterAccessService) GetData(hostURL string, endpointID port
// When the api call is internal, the baseURL should not be used. // When the api call is internal, the baseURL should not be used.
if hostURL == "localhost" { if hostURL == "localhost" {
hostURL = hostURL + service.httpsBindAddr hostURL += service.httpsBindAddr
baseURL = "/" baseURL = "/"
} }

View file

@ -24,6 +24,7 @@ func GetStackFilePaths(stack *portainer.Stack, absolute bool) []string {
for _, file := range append([]string{stack.EntryPoint}, stack.AdditionalFiles...) { for _, file := range append([]string{stack.EntryPoint}, stack.AdditionalFiles...) {
filePaths = append(filePaths, filesystem.JoinPaths(stack.ProjectPath, file)) filePaths = append(filePaths, filesystem.JoinPaths(stack.ProjectPath, file))
} }
return filePaths return filePaths
} }