diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 6ae3368d6..91bfce5f3 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -76,7 +76,7 @@ func initDataStore(dataStorePath string, fileService portainer.FileService) port } func initComposeStackManager(assetsPath string, dataStorePath string, reverseTunnelService portainer.ReverseTunnelService, proxyManager *proxy.Manager) portainer.ComposeStackManager { - composeWrapper := exec.NewComposeWrapper(assetsPath, proxyManager) + composeWrapper := exec.NewComposeWrapper(assetsPath, dataStorePath, proxyManager) if composeWrapper != nil { return composeWrapper } diff --git a/api/exec/compose_wrapper.go b/api/exec/compose_wrapper.go index 918411685..87aef1724 100644 --- a/api/exec/compose_wrapper.go +++ b/api/exec/compose_wrapper.go @@ -16,17 +16,19 @@ import ( // ComposeWrapper is a wrapper for docker-compose binary type ComposeWrapper struct { binaryPath string + dataPath string proxyManager *proxy.Manager } // NewComposeWrapper returns a docker-compose wrapper if corresponding binary present, otherwise nil -func NewComposeWrapper(binaryPath string, proxyManager *proxy.Manager) *ComposeWrapper { +func NewComposeWrapper(binaryPath, dataPath string, proxyManager *proxy.Manager) *ComposeWrapper { if !IsBinaryPresent(programPath(binaryPath, "docker-compose")) { return nil } return &ComposeWrapper{ binaryPath: binaryPath, + dataPath: dataPath, proxyManager: proxyManager, } } @@ -84,6 +86,8 @@ func (w *ComposeWrapper) command(command []string, stack *portainer.Stack, endpo var stderr bytes.Buffer cmd := exec.Command(program, args...) + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, fmt.Sprintf("DOCKER_CONFIG=%s", w.dataPath)) cmd.Stderr = &stderr out, err := cmd.Output() diff --git a/api/exec/compose_wrapper_integration_test.go b/api/exec/compose_wrapper_integration_test.go index 766622614..42c4af1c1 100644 --- a/api/exec/compose_wrapper_integration_test.go +++ b/api/exec/compose_wrapper_integration_test.go @@ -42,7 +42,7 @@ func Test_UpAndDown(t *testing.T) { stack, endpoint := setup(t) - w := NewComposeWrapper("", nil) + w := NewComposeWrapper("", "", nil) err := w.Up(stack, endpoint) if err != nil { diff --git a/api/http/proxy/factory/azure/containergroup.go b/api/http/proxy/factory/azure/containergroup.go index c3383035c..242968de5 100644 --- a/api/http/proxy/factory/azure/containergroup.go +++ b/api/http/proxy/factory/azure/containergroup.go @@ -23,6 +23,36 @@ func (transport *Transport) proxyContainerGroupRequest(request *http.Request) (* } func (transport *Transport) proxyContainerGroupPutRequest(request *http.Request) (*http.Response, error) { + //add a lock before processing existense check + transport.mutex.Lock() + defer transport.mutex.Unlock() + + //generate a temp http GET request based on the current PUT request + validationRequest := &http.Request{ + Method: http.MethodGet, + URL: request.URL, + Header: http.Header{ + "Authorization": []string{request.Header.Get("Authorization")}, + }, + } + + //fire the request to Azure API to validate if there is an existing container instance with the same name + //positive - reject the request + //negative - continue the process + validationResponse, err := http.DefaultTransport.RoundTrip(validationRequest) + if err != nil { + return validationResponse, err + } + + if validationResponse.StatusCode >= 200 && validationResponse.StatusCode < 300 { + resp := &http.Response{} + errObj := map[string]string{ + "message": "A container instance with the same name already exists inside the selected resource group", + } + err = responseutils.RewriteResponse(resp, errObj, http.StatusConflict) + return resp, err + } + response, err := http.DefaultTransport.RoundTrip(request) if err != nil { return response, err diff --git a/api/portainer.go b/api/portainer.go index f134eb26a..282a8b5f4 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -336,7 +336,7 @@ type ( // Whether non-administrator should be able to use container capabilities AllowContainerCapabilitiesForRegularUsers bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"` // Whether non-administrator should be able to use sysctl settings - AllowSysctlSettingForRegularUsers bool `json:"AllowSysctlSettingForRegularUsers" example:"true"` + AllowSysctlSettingForRegularUsers bool `json:"allowSysctlSettingForRegularUsers" example:"true"` // Whether host management features are enabled EnableHostManagementFeatures bool `json:"enableHostManagementFeatures" example:"true"` } diff --git a/app/docker/components/imageRegistry/por-image-registry.html b/app/docker/components/imageRegistry/por-image-registry.html index 77ca79c82..97b5c07e4 100644 --- a/app/docker/components/imageRegistry/por-image-registry.html +++ b/app/docker/components/imageRegistry/por-image-registry.html @@ -1,6 +1,6 @@ -
-
+
+
diff --git a/app/docker/views/containers/create/createContainerController.js b/app/docker/views/containers/create/createContainerController.js index 768d1e589..19965b7ae 100644 --- a/app/docker/views/containers/create/createContainerController.js +++ b/app/docker/views/containers/create/createContainerController.js @@ -972,9 +972,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [ } async function shouldShowSysctls() { - const { allowSysctlSettingForRegularUsers } = $scope.applicationState.application; - - return allowSysctlSettingForRegularUsers || Authentication.isAdmin(); + return endpoint.SecuritySettings.allowSysctlSettingForRegularUsers || Authentication.isAdmin(); } async function checkIfContainerCapabilitiesEnabled() { diff --git a/app/docker/views/services/create/createServiceController.js b/app/docker/views/services/create/createServiceController.js index 6e766602d..6aa70264c 100644 --- a/app/docker/views/services/create/createServiceController.js +++ b/app/docker/views/services/create/createServiceController.js @@ -499,7 +499,7 @@ angular.module('portainer.docker').controller('CreateServiceController', [ const resourceControl = data.Portainer.ResourceControl; const userId = Authentication.getUserDetails().ID; const rcPromise = ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); - const webhookPromise = $q.when(endpoint.Type !== 4 && $scope.formValues.Webhook && WebhookService.createServiceWebhook(serviceId, endpoint.ID)); + const webhookPromise = $q.when(endpoint.Type !== 4 && $scope.formValues.Webhook && WebhookService.createServiceWebhook(serviceId, endpoint.Id)); return $q.all([rcPromise, webhookPromise]); }) .then(function success() { diff --git a/app/kubernetes/ingress/service.js b/app/kubernetes/ingress/service.js index 01fc26b44..dae395870 100644 --- a/app/kubernetes/ingress/service.js +++ b/app/kubernetes/ingress/service.js @@ -77,12 +77,11 @@ export function KubernetesIngressService($async, KubernetesIngresses) { }); } - function _delete(ingress) { + function _delete(namespace, ingressClassName) { return $async(async () => { try { const params = new KubernetesCommonParams(); - params.id = ingress.Name; - const namespace = ingress.Namespace; + params.id = ingressClassName; await KubernetesIngresses(namespace).delete(params).$promise; } catch (err) { throw new PortainerError('Unable to delete ingress', err); diff --git a/app/kubernetes/services/resourcePoolService.js b/app/kubernetes/services/resourcePoolService.js index f492c6ef4..ac38e2d4f 100644 --- a/app/kubernetes/services/resourcePoolService.js +++ b/app/kubernetes/services/resourcePoolService.js @@ -93,7 +93,7 @@ export function KubernetesResourcePoolService($async, KubernetesNamespaceService const patch = _.without(newIngresses, ...create); const createPromises = _.map(create, (i) => KubernetesIngressService.create(i)); - const delPromises = _.map(del, (i) => KubernetesIngressService.delete(i)); + const delPromises = _.map(del, (i) => KubernetesIngressService.delete(i.Namespace, i.Name)); const patchPromises = _.map(patch, (ing) => { const old = _.find(oldIngresses, { Name: ing.Name }); ing.Paths = angular.copy(old.Paths); diff --git a/app/kubernetes/views/configure/configureController.js b/app/kubernetes/views/configure/configureController.js index 6cef0781d..33ae56394 100644 --- a/app/kubernetes/views/configure/configureController.js +++ b/app/kubernetes/views/configure/configureController.js @@ -152,7 +152,7 @@ class KubernetesConfigureController { ingressesToDel.forEach((ingress) => { resourcePools.forEach((resourcePool) => { - promises.push(this.KubernetesIngressService.delete({ IngressClass: ingress, Namespace: resourcePool.Namespace.Name })); + promises.push(this.KubernetesIngressService.delete(resourcePool.Namespace.Name, ingress.Name)); }); });