Compare commits
7 Commits
fix/EE-187
...
fork_branc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca26799a2e | ||
|
|
8727e1a3c4 | ||
|
|
4278aebef9 | ||
|
|
4d250a63b5 | ||
|
|
588ce549ad | ||
|
|
edb25ee10d | ||
|
|
12e7aa6b60 |
@@ -32,12 +32,13 @@ func (factory *ProxyFactory) newDockerLocalProxy(endpoint *portainer.Endpoint) (
|
||||
}
|
||||
|
||||
func (factory *ProxyFactory) newDockerHTTPProxy(endpoint *portainer.Endpoint) (http.Handler, error) {
|
||||
rawURL := endpoint.URL
|
||||
if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment {
|
||||
tunnel := factory.reverseTunnelService.GetTunnelDetails(endpoint.ID)
|
||||
endpoint.URL = fmt.Sprintf("http://127.0.0.1:%d", tunnel.Port)
|
||||
rawURL = fmt.Sprintf("http://127.0.0.1:%d", tunnel.Port)
|
||||
}
|
||||
|
||||
endpointURL, err := url.Parse(endpoint.URL)
|
||||
endpointURL, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ func (factory *ProxyFactory) newKubernetesLocalProxy(endpoint *portainer.Endpoin
|
||||
|
||||
func (factory *ProxyFactory) newKubernetesEdgeHTTPProxy(endpoint *portainer.Endpoint) (http.Handler, error) {
|
||||
tunnel := factory.reverseTunnelService.GetTunnelDetails(endpoint.ID)
|
||||
endpoint.URL = fmt.Sprintf("http://localhost:%d", tunnel.Port)
|
||||
rawURL := fmt.Sprintf("http://localhost:%d", tunnel.Port)
|
||||
|
||||
endpointURL, err := url.Parse(endpoint.URL)
|
||||
endpointURL, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -46,5 +46,19 @@ func (transport *baseTransport) proxyNamespaceDeleteOperation(request *http.Requ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stacks, err := transport.dataStore.Stack().Stacks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, s := range stacks {
|
||||
if s.Namespace == namespace && s.EndpointID == transport.endpoint.ID {
|
||||
if err := transport.dataStore.Stack().DeleteStack(s.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return transport.executeKubernetesRequest(request)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class ContainerInstanceDetailsController {
|
||||
this.container = await this.ContainerGroupService.containerGroup(subscriptionId, resourceGroupId, containerGroupId);
|
||||
this.resourceGroup = await this.ResourceGroupService.resourceGroup(subscriptionId, resourceGroupId);
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to retrive container instance details');
|
||||
this.Notifications.error('Failure', err, 'Unable to retrieve container instance details');
|
||||
}
|
||||
this.state.loading = false;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,14 @@ class porImageRegistryController {
|
||||
this.Notifications = Notifications;
|
||||
|
||||
this.onRegistryChange = this.onRegistryChange.bind(this);
|
||||
this.onImageChange = this.onImageChange.bind(this);
|
||||
|
||||
this.registries = [];
|
||||
this.images = [];
|
||||
this.defaultRegistry = new DockerHubViewModel();
|
||||
|
||||
this.$scope.$watch(() => this.model.Registry, this.onRegistryChange);
|
||||
this.$scope.$watch(() => this.model.Image, this.onImageChange);
|
||||
}
|
||||
|
||||
isKnownRegistry(registry) {
|
||||
@@ -62,6 +64,12 @@ class porImageRegistryController {
|
||||
}
|
||||
}
|
||||
|
||||
async onImageChange() {
|
||||
if (!this.isDockerHubRegistry()) {
|
||||
this.setValidity(true);
|
||||
}
|
||||
}
|
||||
|
||||
displayedRegistryURL() {
|
||||
return this.getRegistryURL(this.model.Registry) || 'docker.io';
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
uib-typeahead="image for image in $ctrl.availableImages | filter:$viewValue | limitTo:5"
|
||||
ng-model="$ctrl.model.Image"
|
||||
name="image_name"
|
||||
placeholder="e.g. myImage:myTag"
|
||||
placeholder="e.g. my-image:my-tag"
|
||||
ng-change="$ctrl.onImageChange()"
|
||||
required
|
||||
data-cy="component-imageInput"
|
||||
@@ -54,7 +54,7 @@
|
||||
</span>
|
||||
<label for="image_name" ng-class="$ctrl.labelClass" class="control-label text-left">Image </label>
|
||||
<div ng-class="$ctrl.inputClass">
|
||||
<input type="text" class="form-control" ng-model="$ctrl.model.Image" name="image_name" placeholder="e.g. registry:port/myImage:myTag" required />
|
||||
<input type="text" class="form-control" ng-model="$ctrl.model.Image" name="image_name" placeholder="e.g. registry:port/my-image:my-tag" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -90,11 +90,22 @@ angular.module('portainer.docker').factory('ContainerService', [
|
||||
};
|
||||
|
||||
service.updateRestartPolicy = updateRestartPolicy;
|
||||
service.updateLimits = updateLimits;
|
||||
|
||||
function updateRestartPolicy(id, restartPolicy, maximumRetryCounts) {
|
||||
return Container.update({ id: id }, { RestartPolicy: { Name: restartPolicy, MaximumRetryCount: maximumRetryCounts } }).$promise;
|
||||
}
|
||||
|
||||
function updateLimits(id, config) {
|
||||
return Container.update({ id: id },
|
||||
{
|
||||
//MemorySwap: must be set, -1: non limits, 0: treated as unset(cause update error).
|
||||
MemoryReservation: config.HostConfig.MemoryReservation, "Memory": config.HostConfig.Memory, "MemorySwap": -1,
|
||||
NanoCpus: config.HostConfig.NanoCpus
|
||||
}
|
||||
).$promise;
|
||||
}
|
||||
|
||||
service.createContainer = function (configuration) {
|
||||
var deferred = $q.defer();
|
||||
Container.create(configuration)
|
||||
|
||||
@@ -61,6 +61,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||
endpoint
|
||||
) {
|
||||
$scope.create = create;
|
||||
$scope.update = update;
|
||||
$scope.endpoint = endpoint;
|
||||
|
||||
$scope.formValues = {
|
||||
@@ -580,7 +581,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||
$scope.formValues.RegistryModel = model;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrive registry');
|
||||
Notifications.error('Failure', err, 'Unable to retrieve registry');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -758,6 +759,26 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateLimits(config) {
|
||||
return ContainerService.updateLimits($transition$.params().from, config).then(onUpdateSuccess).catch(notifyOnError);
|
||||
|
||||
function onUpdateSuccess() {
|
||||
Notifications.success('Limits updated');
|
||||
}
|
||||
|
||||
function notifyOnError(err) {
|
||||
Notifications.error('Failure', err, 'Update Limits fail');
|
||||
return $q.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var config = angular.copy($scope.config);
|
||||
prepareResources(config);
|
||||
updateLimits(config);
|
||||
return
|
||||
}
|
||||
|
||||
function create() {
|
||||
var oldContainer = null;
|
||||
HttpRequestHelper.setPortainerAgentTargetHeader($scope.formValues.NodeName);
|
||||
|
||||
@@ -762,6 +762,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- !cpu-limit-input -->
|
||||
|
||||
<!-- update-limit-btn -->
|
||||
<div class="form-group" ng-if="state.mode == 'duplicate'">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
ng-disabled="state.actionInProgress || !formValues.RegistryModel.Image || (!formValues.RegistryModel.Registry && fromContainer)"
|
||||
ng-click="update()"
|
||||
button-spinner="state.actionInProgress"
|
||||
>
|
||||
<span ng-hide="state.actionInProgress">Update Limits</span>
|
||||
<span ng-show="state.actionInProgress">Update in progress...</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- !update-limit-btn -->
|
||||
</form>
|
||||
</div>
|
||||
<!-- !tab-runtime-resources -->
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<!-- name-input -->
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">name</span>
|
||||
<input type="text" class="form-control" ng-model="item.Name" placeholder="e.g. myImage:myTag" auto-focus />
|
||||
<input type="text" class="form-control" ng-model="item.Name" placeholder="e.g. my-image:my-tag" auto-focus />
|
||||
<span class="input-group-addon"
|
||||
><i ng-class="{ true: 'fa fa-check green-icon', false: 'fa fa-times red-icon' }[item.Name !== '']" aria-hidden="true"></i
|
||||
></span>
|
||||
|
||||
@@ -53,6 +53,7 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
'clipboard',
|
||||
'WebhookHelper',
|
||||
'NetworkService',
|
||||
'RegistryService',
|
||||
'endpoint',
|
||||
function (
|
||||
$q,
|
||||
@@ -84,6 +85,7 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
clipboard,
|
||||
WebhookHelper,
|
||||
NetworkService,
|
||||
RegistryService,
|
||||
endpoint
|
||||
) {
|
||||
$scope.endpoint = endpoint;
|
||||
@@ -353,22 +355,22 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
$('#copyNotification').fadeOut(2000);
|
||||
};
|
||||
|
||||
$scope.cancelChanges = function cancelChanges(service, keys) {
|
||||
$scope.cancelChanges = async function cancelChanges(service, keys) {
|
||||
if (keys) {
|
||||
// clean out the keys only from the list of modified keys
|
||||
keys.forEach(function (key) {
|
||||
for (const key of keys) {
|
||||
if (key === 'Image') {
|
||||
$scope.formValues.RegistryModel.Image = '';
|
||||
$scope.formValues.RegistryModel = await RegistryService.retrievePorRegistryModelFromRepository(originalService.Image, endpoint.Id);
|
||||
} else {
|
||||
var index = previousServiceValues.indexOf(key);
|
||||
if (index >= 0) {
|
||||
previousServiceValues.splice(index, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// clean out all changes
|
||||
$scope.formValues.RegistryModel.Image = '';
|
||||
$scope.formValues.RegistryModel = await RegistryService.retrievePorRegistryModelFromRepository(originalService.Image, endpoint.Id);
|
||||
keys = Object.keys(service);
|
||||
previousServiceValues = [];
|
||||
}
|
||||
@@ -382,7 +384,9 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
var hasChanges = false;
|
||||
elements.forEach(function (key) {
|
||||
if (key === 'Image') {
|
||||
hasChanges = hasChanges || $scope.formValues.RegistryModel.Image ? true : false;
|
||||
const originalImage = service ? service.Model.Spec.TaskTemplate.ContainerSpec.Image : null;
|
||||
const currentImage = ImageHelper.createImageConfigForContainer($scope.formValues.RegistryModel).fromImage;
|
||||
hasChanges = hasChanges || originalImage !== currentImage;
|
||||
} else {
|
||||
hasChanges = hasChanges || previousServiceValues.indexOf(key) >= 0;
|
||||
}
|
||||
@@ -763,6 +767,11 @@ angular.module('portainer.docker').controller('ServiceController', [
|
||||
$scope.state.sliderMaxCpu = 32;
|
||||
}
|
||||
|
||||
const image = $scope.service.Model.Spec.TaskTemplate.ContainerSpec.Image;
|
||||
RegistryService.retrievePorRegistryModelFromRepository(image, endpoint.Id).then((model) => {
|
||||
$scope.formValues.RegistryModel = model;
|
||||
});
|
||||
|
||||
// Default values
|
||||
$scope.state.addSecret = { override: false };
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ angular.module('portainer.app').factory('ResourceControlService', [
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive users and team details for ResourceControlViewModel
|
||||
* Retrieve users and team details for ResourceControlViewModel
|
||||
* @param {ResourceControlViewModel} resourceControl ResourceControl view model
|
||||
*/
|
||||
function retrieveOwnershipDetails(resourceControl) {
|
||||
|
||||
Reference in New Issue
Block a user