mirror of https://github.com/portainer/portainer
Merge branch 'release/2.5' into develop
commit
af03d91e39
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue