Merge branch 'release/2.5' into develop

pull/5084/head
yi-portainer 2021-05-18 17:02:31 +12:00
commit af03d91e39
11 changed files with 46 additions and 15 deletions

View File

@ -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 { 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 { if composeWrapper != nil {
return composeWrapper return composeWrapper
} }

View File

@ -16,17 +16,19 @@ import (
// ComposeWrapper is a wrapper for docker-compose binary // ComposeWrapper is a wrapper for docker-compose binary
type ComposeWrapper struct { type ComposeWrapper struct {
binaryPath string binaryPath string
dataPath string
proxyManager *proxy.Manager proxyManager *proxy.Manager
} }
// NewComposeWrapper returns a docker-compose wrapper if corresponding binary present, otherwise nil // 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")) { if !IsBinaryPresent(programPath(binaryPath, "docker-compose")) {
return nil return nil
} }
return &ComposeWrapper{ return &ComposeWrapper{
binaryPath: binaryPath, binaryPath: binaryPath,
dataPath: dataPath,
proxyManager: proxyManager, proxyManager: proxyManager,
} }
} }
@ -84,6 +86,8 @@ func (w *ComposeWrapper) command(command []string, stack *portainer.Stack, endpo
var stderr bytes.Buffer var stderr bytes.Buffer
cmd := exec.Command(program, args...) cmd := exec.Command(program, args...)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("DOCKER_CONFIG=%s", w.dataPath))
cmd.Stderr = &stderr cmd.Stderr = &stderr
out, err := cmd.Output() out, err := cmd.Output()

View File

@ -42,7 +42,7 @@ func Test_UpAndDown(t *testing.T) {
stack, endpoint := setup(t) stack, endpoint := setup(t)
w := NewComposeWrapper("", nil) w := NewComposeWrapper("", "", nil)
err := w.Up(stack, endpoint) err := w.Up(stack, endpoint)
if err != nil { if err != nil {

View File

@ -23,6 +23,36 @@ 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
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) response, err := http.DefaultTransport.RoundTrip(request)
if err != nil { if err != nil {
return response, err return response, err

View File

@ -336,7 +336,7 @@ type (
// Whether non-administrator should be able to use container capabilities // Whether non-administrator should be able to use container capabilities
AllowContainerCapabilitiesForRegularUsers bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"` AllowContainerCapabilitiesForRegularUsers bool `json:"allowContainerCapabilitiesForRegularUsers" example:"true"`
// Whether non-administrator should be able to use sysctl settings // 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 // Whether host management features are enabled
EnableHostManagementFeatures bool `json:"enableHostManagementFeatures" example:"true"` EnableHostManagementFeatures bool `json:"enableHostManagementFeatures" example:"true"`
} }

View File

@ -1,6 +1,6 @@
<!-- use registry --> <!-- use registry -->
<div ng-if="$ctrl.model.UseRegistry"> <div>
<div class="form-group"> <div class="form-group" ng-if="$ctrl.model.UseRegistry">
<label for="image_registry" class="control-label text-left" ng-class="$ctrl.labelClass"> <label for="image_registry" class="control-label text-left" ng-class="$ctrl.labelClass">
Registry Registry
</label> </label>

View File

@ -972,9 +972,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
} }
async function shouldShowSysctls() { async function shouldShowSysctls() {
const { allowSysctlSettingForRegularUsers } = $scope.applicationState.application; return endpoint.SecuritySettings.allowSysctlSettingForRegularUsers || Authentication.isAdmin();
return allowSysctlSettingForRegularUsers || Authentication.isAdmin();
} }
async function checkIfContainerCapabilitiesEnabled() { async function checkIfContainerCapabilitiesEnabled() {

View File

@ -499,7 +499,7 @@ angular.module('portainer.docker').controller('CreateServiceController', [
const resourceControl = data.Portainer.ResourceControl; const resourceControl = data.Portainer.ResourceControl;
const userId = Authentication.getUserDetails().ID; const userId = Authentication.getUserDetails().ID;
const rcPromise = ResourceControlService.applyResourceControl(userId, accessControlData, resourceControl); 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]); return $q.all([rcPromise, webhookPromise]);
}) })
.then(function success() { .then(function success() {

View File

@ -77,12 +77,11 @@ export function KubernetesIngressService($async, KubernetesIngresses) {
}); });
} }
function _delete(ingress) { function _delete(namespace, ingressClassName) {
return $async(async () => { return $async(async () => {
try { try {
const params = new KubernetesCommonParams(); const params = new KubernetesCommonParams();
params.id = ingress.Name; params.id = ingressClassName;
const namespace = ingress.Namespace;
await KubernetesIngresses(namespace).delete(params).$promise; await KubernetesIngresses(namespace).delete(params).$promise;
} catch (err) { } catch (err) {
throw new PortainerError('Unable to delete ingress', err); throw new PortainerError('Unable to delete ingress', err);

View File

@ -93,7 +93,7 @@ export function KubernetesResourcePoolService($async, KubernetesNamespaceService
const patch = _.without(newIngresses, ...create); const patch = _.without(newIngresses, ...create);
const createPromises = _.map(create, (i) => KubernetesIngressService.create(i)); 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 patchPromises = _.map(patch, (ing) => {
const old = _.find(oldIngresses, { Name: ing.Name }); const old = _.find(oldIngresses, { Name: ing.Name });
ing.Paths = angular.copy(old.Paths); ing.Paths = angular.copy(old.Paths);

View File

@ -152,7 +152,7 @@ class KubernetesConfigureController {
ingressesToDel.forEach((ingress) => { ingressesToDel.forEach((ingress) => {
resourcePools.forEach((resourcePool) => { resourcePools.forEach((resourcePool) => {
promises.push(this.KubernetesIngressService.delete({ IngressClass: ingress, Namespace: resourcePool.Namespace.Name })); promises.push(this.KubernetesIngressService.delete(resourcePool.Namespace.Name, ingress.Name));
}); });
}); });