portainer/app/docker/views/services/create/createServiceController.js

537 lines
17 KiB
JavaScript
Raw Normal View History

refactor(app): introduce webpack and babel (#2407) * feat(agent): add new host page * feat(agent): convert volume-browser to files-datatable * fix(agent): browse folders in file-datatable * feat(engine-details): replace engine view with host view * feat(engine-details): remove old panels * feat(engine-details): add basic engine-details-panel component * feat(engine-details): pass details to the different components * feat(engine-details): replace host-view with host-overview * feat(engine-details): add commaseperated filter * feat(engine-details): add host-view container component * feat(engine-details): add host-details component * feat(engine-details): build host details object * feat(engine-details): format engine version * feat(engine-details): get details for one node * feat(engine-details): pass is-agent from view * feat(engine-details): replace old node view with a new component * feat(engine-details): add swarm-node-details component * feat(engine-details): remove isSwarm binding * feat(engine-details): remove node-details and include in parent * feat(engine-details): add labels-table component * feat(engine-details): add update node service * feat(engine-details): add update label functionality * style(engine-details): remove whitespaces * feat(engine-details): remove old node page * feat(engine-details): pass is agent to host details * feat(host-details): hide missing info * feat(host-details): update node availability * style(host-details): remove obsolete event object * feat(host-details): fix labels not sending * feat(host-details): remove flags for hiding data * feat(host-details): create mock call to server for agent host info * style(host-details): fix spelling mistake in filter's name * feat(host-details): get info from agent * feat(host-details): hide engine labels when empty * feat(node-details): move labels table and save button * feat(host-info): add different urls for refresh * feat(host-details): show disk/devices info for agent * feat(host-view): add loading indicator to devices-panel * feat(host-details): add loading indicator to disks panel * feat(agent): fix browse volume * feat(agent): browse files * feat(agent): enable rename * feat(agent): download file * fix(agent): download file from root * feat(agent): delete file * style(agent): remove whitespaces * fix(agent): fix link on node browser * feat(agent): basic file uploader * feat(agent): add basic file upload * fix(volume-browser): move volume id to query params * feat(node-browser): moved uploader into browser * feat(node-browser): add upload spinner * feat(agent): browse files relative to root * feat(build): add webpack build config * feat(build): add missing imports * feat(webpack): add missing imports * feat(build): enable eslint on build * feat(build): add webpack notifier * feat(build): clean terminal on build * feat(build): import all globals * feat(build): add angular import * feat(build): fix styles * feat(build): load favicons * feat(build): load css before script * feat(webpack): split vendors css and js to a different bundle * feat(webpack): import angular in all files * feat(webpack): remove eslint global config * feat(webpack): add webpack clean dist * feat(webpack): fix styling issues * refactor(webpack): remove empty controllers * refactor(webpack): optimize moment * refactor(webpack): add bundle analyzer * feat(webpack): add babel * refactor(webpack): optimize lodash * refactor(toastr): update toastr * feat(webpack): create basic production and dev config * fix(webpack): fix production config * fix(webpack): fix html templates url * refactor(webpack): remove angular imports * refactor(webpack): remove more angular imports * refactor(webpack): return angular to entry file * style(webpack): remove comments from config * fix(hosts): remove browse button * fix(webpack): import lodash * fix(webpack): import missing htmls * feat(webpack): reduce lodash size * feat(webpack): config grunt to use webpack * feat(webpack): add postcss * chore(codeclimate): use eslint-5 channel * feat(deps): upgrade from lodash to lodash-es * fix(webpack): fix bug with lodash * chore(build): add build client script * fix(webpack): fix missing jsyaml reference * refactor(webpack): seperate builds of img files * chore(build): add a way to check times of webpack build * feat(webpack): add dev server * fix(webpack): fix css output name * chore(webpack): optimize images * chore(webpack): add node env * fix(build): copy templates on release * chore(webpack): set env NODE_ENV * feat(webpack): set NODE_ENV on production builds * fix(extensions): set image path * refactor(css): move vendor css to js import * style(app): remove whitespaces * fix(build-system): allow DevOps pipeline to leverage webpack (#2670) * Update devopsbuild task to use webpack & remove AppVeyor environment var * Added -Force to replace the existing dist folder * Removed Test-Path * dep(build-system): add angularjs-annotate to webpack + fix on imports * Merge branch 'develop' into webpack * refactor(app): webpack aliases for imports + async / await dep + start refactor * style(extensions): use develop version of the view * fix(app): fix several issues introduced by webpack migration * fix(webpack): fix ng-include not loading templates with webpack * Fix Windows CI with Webpack (#2782) * fix(configs): refactor broke configs creation and list views * fix(build-system): update build_binary_devops for Windows
2019-03-21 05:46:49 +00:00
import _ from 'lodash-es';
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel';
require('./includes/update-restart.html')
require('./includes/secret.html')
require('./includes/config.html')
require('./includes/resources-placement.html')
angular.module('portainer.docker')
feat(webhooks): add support for service update webhooks (#2161) * Initial pass at adding webhook controller and routes * Moving some objects around * Cleaning up comments * Fixing syntax, switching to using the docker sdk over building an http client * Adding delete and list functionality * Updating the handler to use the correct permissions. Updating some comments * Fixing some comments * Code cleanup per pull request comments * Cleanup per PR feedback. Syntax error fix * Initial creation of webhook app code * Moving ClientFactory creation out of handler code and instead using the one created by the main process. Removing webhookInspect method and updating the list function to use json filters * Delete now works on the webhook ID vs service ID * WIP - Service creates a webhook. Display will show an existing webhook URL. * Adding the webhook field to the service view. There is now the ability to add or remove a webhook from a service * Moving all api calls to be webhooks vs webhook * Code cleanup. Moving all api calls to be webhooks vs webhook * More conversion of webhook to webhooks? * Moving UI elements around. Starting function for copying to clipboard * Finalizing function for copying to clipboard. Adding button that calls function and copies webhook to clipboard. * Fixing UI issues. Hiding field entirely when there is no webhook * Moving URL crafting to a helper method. The edit pane for service now creates/deletes webhooks immidiately. * style(service-details): update webhook line * feat(api): strip sha when updating an image via the update webhook * Fixing up some copy. Only displying the port if it is not http or https * Fixing tooltip copy. Setting the forceupdate to be true to require an update to occur * Fixing code climate errors * Adding WebhookType field and setting to ServiceWebhook for new webhooks. Renaming ServiceID to resourceID so future work can add new types of webhooks in other resource areas. * Adding the webhook type to the payload to support more types of webhooks in the future. Setting the type correctly when creating one for a service * feat(webhooks): changes related to webhook management * API code cleanup, removing unneeded functions, and updating validation logic * Incorrectly ignoring the error that the webhook did not exist * Re-adding missing error handling. Changing error response to be a 404 vs 500 when token can't find an object * fix(webhooks): close Docker client after service webhook execution
2018-09-03 10:08:03 +00:00
.controller('CreateServiceController', ['$q', '$scope', '$state', '$timeout', 'Service', 'ServiceHelper', 'ConfigService', 'ConfigHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'LabelHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'FormValidator', 'PluginService', 'RegistryService', 'HttpRequestHelper', 'NodeService', 'SettingsService', 'WebhookService','EndpointProvider',
function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, ConfigHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, LabelHelper, Authentication, ResourceControlService, Notifications, FormValidator, PluginService, RegistryService, HttpRequestHelper, NodeService, SettingsService, WebhookService,EndpointProvider) {
$scope.formValues = {
Name: '',
Image: '',
Registry: {},
Mode: 'replicated',
Replicas: 1,
Command: '',
EntryPoint: '',
WorkingDir: '',
User: '',
Env: [],
Labels: [],
ContainerLabels: [],
Volumes: [],
Network: '',
ExtraNetworks: [],
HostsEntries: [],
Ports: [],
Parallelism: 1,
PlacementConstraints: [],
PlacementPreferences: [],
UpdateDelay: '0s',
UpdateOrder: 'stop-first',
FailureAction: 'pause',
Secrets: [],
Configs: [],
AccessControlData: new AccessControlFormData(),
CpuLimit: 0,
CpuReservation: 0,
MemoryLimit: 0,
MemoryReservation: 0,
MemoryLimitUnit: 'MB',
MemoryReservationUnit: 'MB',
RestartCondition: 'any',
RestartDelay: '5s',
RestartMaxAttempts: 0,
RestartWindow: '0s',
LogDriverName: '',
feat(webhooks): add support for service update webhooks (#2161) * Initial pass at adding webhook controller and routes * Moving some objects around * Cleaning up comments * Fixing syntax, switching to using the docker sdk over building an http client * Adding delete and list functionality * Updating the handler to use the correct permissions. Updating some comments * Fixing some comments * Code cleanup per pull request comments * Cleanup per PR feedback. Syntax error fix * Initial creation of webhook app code * Moving ClientFactory creation out of handler code and instead using the one created by the main process. Removing webhookInspect method and updating the list function to use json filters * Delete now works on the webhook ID vs service ID * WIP - Service creates a webhook. Display will show an existing webhook URL. * Adding the webhook field to the service view. There is now the ability to add or remove a webhook from a service * Moving all api calls to be webhooks vs webhook * Code cleanup. Moving all api calls to be webhooks vs webhook * More conversion of webhook to webhooks? * Moving UI elements around. Starting function for copying to clipboard * Finalizing function for copying to clipboard. Adding button that calls function and copies webhook to clipboard. * Fixing UI issues. Hiding field entirely when there is no webhook * Moving URL crafting to a helper method. The edit pane for service now creates/deletes webhooks immidiately. * style(service-details): update webhook line * feat(api): strip sha when updating an image via the update webhook * Fixing up some copy. Only displying the port if it is not http or https * Fixing tooltip copy. Setting the forceupdate to be true to require an update to occur * Fixing code climate errors * Adding WebhookType field and setting to ServiceWebhook for new webhooks. Renaming ServiceID to resourceID so future work can add new types of webhooks in other resource areas. * Adding the webhook type to the payload to support more types of webhooks in the future. Setting the type correctly when creating one for a service * feat(webhooks): changes related to webhook management * API code cleanup, removing unneeded functions, and updating validation logic * Incorrectly ignoring the error that the webhook did not exist * Re-adding missing error handling. Changing error response to be a 404 vs 500 when token can't find an object * fix(webhooks): close Docker client after service webhook execution
2018-09-03 10:08:03 +00:00
LogDriverOpts: [],
Webhook: false
};
$scope.state = {
2017-11-12 19:27:28 +00:00
formValidationError: '',
actionInProgress: false
};
$scope.refreshSlider = function () {
$timeout(function () {
$scope.$broadcast('rzSliderForceRender');
});
};
$scope.addPortBinding = function() {
$scope.formValues.Ports.push({ PublishedPort: '', TargetPort: '', Protocol: 'tcp', PublishMode: 'ingress' });
};
$scope.removePortBinding = function(index) {
$scope.formValues.Ports.splice(index, 1);
};
$scope.addExtraNetwork = function() {
$scope.formValues.ExtraNetworks.push({ Name: '' });
};
$scope.removeExtraNetwork = function(index) {
$scope.formValues.ExtraNetworks.splice(index, 1);
};
$scope.addHostsEntry = function() {
$scope.formValues.HostsEntries.push({});
};
$scope.removeHostsEntry = function(index) {
$scope.formValues.HostsEntries.splice(index, 1);
};
$scope.addVolume = function() {
$scope.formValues.Volumes.push({ Source: '', Target: '', ReadOnly: false, Type: 'volume' });
};
$scope.removeVolume = function(index) {
$scope.formValues.Volumes.splice(index, 1);
};
$scope.addConfig = function() {
$scope.formValues.Configs.push({});
};
$scope.removeConfig = function(index) {
$scope.formValues.Configs.splice(index, 1);
};
$scope.addSecret = function() {
$scope.formValues.Secrets.push({ overrideTarget: false });
};
$scope.removeSecret = function(index) {
$scope.formValues.Secrets.splice(index, 1);
};
$scope.addEnvironmentVariable = function() {
$scope.formValues.Env.push({ name: '', value: ''});
};
$scope.removeEnvironmentVariable = function(index) {
$scope.formValues.Env.splice(index, 1);
};
$scope.addPlacementConstraint = function() {
$scope.formValues.PlacementConstraints.push({ key: '', operator: '==', value: '' });
};
$scope.removePlacementConstraint = function(index) {
$scope.formValues.PlacementConstraints.splice(index, 1);
};
$scope.addPlacementPreference = function() {
$scope.formValues.PlacementPreferences.push({ strategy: 'spread', value: '' });
};
$scope.removePlacementPreference = function(index) {
$scope.formValues.PlacementPreferences.splice(index, 1);
};
$scope.addLabel = function() {
$scope.formValues.Labels.push({ key: '', value: ''});
};
$scope.removeLabel = function(index) {
$scope.formValues.Labels.splice(index, 1);
};
$scope.addContainerLabel = function() {
$scope.formValues.ContainerLabels.push({ key: '', value: ''});
};
$scope.removeContainerLabel = function(index) {
$scope.formValues.ContainerLabels.splice(index, 1);
};
$scope.addLogDriverOpt = function() {
$scope.formValues.LogDriverOpts.push({ name: '', value: ''});
};
$scope.removeLogDriverOpt = function(index) {
$scope.formValues.LogDriverOpts.splice(index, 1);
};
function prepareImageConfig(config, input) {
var imageConfig = ImageHelper.createImageConfigForContainer(input.Image, input.Registry.URL);
config.TaskTemplate.ContainerSpec.Image = imageConfig.fromImage + ':' + imageConfig.tag;
}
function preparePortsConfig(config, input) {
var ports = [];
input.Ports.forEach(function (binding) {
var port = {
Protocol: binding.Protocol,
PublishMode: binding.PublishMode
};
if (binding.TargetPort) {
port.TargetPort = +binding.TargetPort;
if (binding.PublishedPort) {
port.PublishedPort = +binding.PublishedPort;
}
ports.push(port);
}
});
config.EndpointSpec.Ports = ports;
}
function prepareSchedulingConfig(config, input) {
if (input.Mode === 'replicated') {
config.Mode.Replicated = {
Replicas: input.Replicas
};
} else {
config.Mode.Global = {};
}
}
function commandToArray(cmd) {
var tokens = [].concat.apply([], cmd.split('\'').map(function(v,i) {
return i%2 ? v : v.split(' ');
})).filter(Boolean);
return tokens;
}
function prepareCommandConfig(config, input) {
if (input.EntryPoint) {
config.TaskTemplate.ContainerSpec.Command = commandToArray(input.EntryPoint);
}
if (input.Command) {
config.TaskTemplate.ContainerSpec.Args = commandToArray(input.Command);
}
if (input.User) {
config.TaskTemplate.ContainerSpec.User = input.User;
}
if (input.WorkingDir) {
config.TaskTemplate.ContainerSpec.Dir = input.WorkingDir;
}
}
function prepareEnvConfig(config, input) {
var env = [];
input.Env.forEach(function (v) {
if (v.name) {
env.push(v.name + '=' + v.value);
}
});
config.TaskTemplate.ContainerSpec.Env = env;
}
function prepareLabelsConfig(config, input) {
config.Labels = LabelHelper.fromKeyValueToLabelHash(input.Labels);
config.TaskTemplate.ContainerSpec.Labels = LabelHelper.fromKeyValueToLabelHash(input.ContainerLabels);
}
function createMountObjectFromVolume(volumeObject, target, readonly) {
return {
Target: target,
Source: volumeObject.Id,
Type: 'volume',
ReadOnly: readonly,
VolumeOptions: {
Labels: volumeObject.Labels,
DriverConfig: {
Name: volumeObject.Driver,
Options: volumeObject.Options
}
}
};
}
function prepareVolumes(config, input) {
input.Volumes.forEach(function (volume) {
if (volume.Source && volume.Target) {
if (volume.Type !== 'volume') {
config.TaskTemplate.ContainerSpec.Mounts.push(volume);
} else {
var volumeObject = volume.Source;
var mount = createMountObjectFromVolume(volumeObject, volume.Target, volume.ReadOnly);
config.TaskTemplate.ContainerSpec.Mounts.push(mount);
}
}
});
}
function prepareNetworks(config, input) {
var networks = [];
if (input.Network) {
networks.push({ Target: input.Network });
}
input.ExtraNetworks.forEach(function (network) {
networks.push({ Target: network.Name });
});
config.Networks = _.uniqWith(networks, _.isEqual);
}
function prepareHostsEntries(config, input) {
var hostsEntries = [];
if (input.HostsEntries) {
input.HostsEntries.forEach(function (host_ip) {
if (host_ip.value && host_ip.value.indexOf(':') && host_ip.value.split(':').length === 2) {
var keyVal = host_ip.value.split(':');
// Hosts file format, IP_address canonical_hostname
hostsEntries.push(keyVal[1] + ' ' + keyVal[0]);
}
});
if (hostsEntries.length > 0) {
config.TaskTemplate.ContainerSpec.Hosts = hostsEntries;
}
}
}
function prepareUpdateConfig(config, input) {
config.UpdateConfig = {
Parallelism: input.Parallelism || 0,
Delay: ServiceHelper.translateHumanDurationToNanos(input.UpdateDelay) || 0,
FailureAction: input.FailureAction,
Order: input.UpdateOrder
};
}
function prepareRestartPolicy(config, input) {
config.TaskTemplate.RestartPolicy = {
Condition: input.RestartCondition || 'any',
Delay: ServiceHelper.translateHumanDurationToNanos(input.RestartDelay) || 5000000000,
MaxAttempts: input.RestartMaxAttempts || 0,
Window: ServiceHelper.translateHumanDurationToNanos(input.RestartWindow) || 0
};
}
function preparePlacementConfig(config, input) {
config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(input.PlacementConstraints);
config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(input.PlacementPreferences);
}
function prepareConfigConfig(config, input) {
if (input.Configs) {
var configs = [];
angular.forEach(input.Configs, function(config) {
if (config.model) {
var s = ConfigHelper.configConfig(config.model);
s.File.Name = config.FileName || s.File.Name;
configs.push(s);
}
});
config.TaskTemplate.ContainerSpec.Configs = configs;
}
}
function prepareSecretConfig(config, input) {
if (input.Secrets) {
var secrets = [];
angular.forEach(input.Secrets, function(secret) {
if (secret.model) {
var s = SecretHelper.secretConfig(secret.model);
s.File.Name = s.SecretName;
if (secret.overrideTarget && secret.target && secret.target !== '') {
s.File.Name = secret.target;
}
secrets.push(s);
}
});
config.TaskTemplate.ContainerSpec.Secrets = secrets;
}
}
function prepareResourcesCpuConfig(config, input) {
// CPU Limit
if (input.CpuLimit > 0) {
config.TaskTemplate.Resources.Limits.NanoCPUs = input.CpuLimit * 1000000000;
}
// CPU Reservation
if (input.CpuReservation > 0) {
config.TaskTemplate.Resources.Reservations.NanoCPUs = input.CpuReservation * 1000000000;
}
}
function prepareResourcesMemoryConfig(config, input) {
// Memory Limit - Round to 0.125
var memoryLimit = (Math.round(input.MemoryLimit * 8) / 8).toFixed(3);
memoryLimit *= 1024 * 1024;
if (input.MemoryLimitUnit === 'GB') {
memoryLimit *= 1024;
}
if (memoryLimit > 0) {
config.TaskTemplate.Resources.Limits.MemoryBytes = memoryLimit;
}
// Memory Resevation - Round to 0.125
var memoryReservation = (Math.round(input.MemoryReservation * 8) / 8).toFixed(3);
memoryReservation *= 1024 * 1024;
if (input.MemoryReservationUnit === 'GB') {
memoryReservation *= 1024;
}
if (memoryReservation > 0) {
config.TaskTemplate.Resources.Reservations.MemoryBytes = memoryReservation;
}
}
function prepareLogDriverConfig(config, input) {
var logOpts = {};
if (input.LogDriverName) {
config.TaskTemplate.LogDriver = { Name: input.LogDriverName };
if (input.LogDriverName !== 'none') {
input.LogDriverOpts.forEach(function (opt) {
if (opt.name) {
logOpts[opt.name] = opt.value;
}
});
if (Object.keys(logOpts).length !== 0 && logOpts.constructor === Object) {
config.TaskTemplate.LogDriver.Options = logOpts;
}
}
}
}
function prepareConfiguration() {
var input = $scope.formValues;
var config = {
Name: input.Name,
TaskTemplate: {
ContainerSpec: {
Mounts: []
},
Placement: {},
Resources: {
Limits: {},
Reservations: {}
}
},
Mode: {},
EndpointSpec: {}
};
prepareSchedulingConfig(config, input);
prepareImageConfig(config, input);
preparePortsConfig(config, input);
prepareCommandConfig(config, input);
prepareEnvConfig(config, input);
prepareLabelsConfig(config, input);
prepareVolumes(config, input);
prepareNetworks(config, input);
prepareHostsEntries(config, input);
prepareUpdateConfig(config, input);
prepareConfigConfig(config, input);
prepareSecretConfig(config, input);
preparePlacementConfig(config, input);
prepareResourcesCpuConfig(config, input);
prepareResourcesMemoryConfig(config, input);
prepareRestartPolicy(config, input);
prepareLogDriverConfig(config, input);
return config;
}
function createNewService(config, accessControlData) {
var registry = $scope.formValues.Registry;
var authenticationDetails = registry.Authentication ? RegistryService.encodedCredentials(registry) : '';
HttpRequestHelper.setRegistryAuthenticationHeader(authenticationDetails);
feat(webhooks): add support for service update webhooks (#2161) * Initial pass at adding webhook controller and routes * Moving some objects around * Cleaning up comments * Fixing syntax, switching to using the docker sdk over building an http client * Adding delete and list functionality * Updating the handler to use the correct permissions. Updating some comments * Fixing some comments * Code cleanup per pull request comments * Cleanup per PR feedback. Syntax error fix * Initial creation of webhook app code * Moving ClientFactory creation out of handler code and instead using the one created by the main process. Removing webhookInspect method and updating the list function to use json filters * Delete now works on the webhook ID vs service ID * WIP - Service creates a webhook. Display will show an existing webhook URL. * Adding the webhook field to the service view. There is now the ability to add or remove a webhook from a service * Moving all api calls to be webhooks vs webhook * Code cleanup. Moving all api calls to be webhooks vs webhook * More conversion of webhook to webhooks? * Moving UI elements around. Starting function for copying to clipboard * Finalizing function for copying to clipboard. Adding button that calls function and copies webhook to clipboard. * Fixing UI issues. Hiding field entirely when there is no webhook * Moving URL crafting to a helper method. The edit pane for service now creates/deletes webhooks immidiately. * style(service-details): update webhook line * feat(api): strip sha when updating an image via the update webhook * Fixing up some copy. Only displying the port if it is not http or https * Fixing tooltip copy. Setting the forceupdate to be true to require an update to occur * Fixing code climate errors * Adding WebhookType field and setting to ServiceWebhook for new webhooks. Renaming ServiceID to resourceID so future work can add new types of webhooks in other resource areas. * Adding the webhook type to the payload to support more types of webhooks in the future. Setting the type correctly when creating one for a service * feat(webhooks): changes related to webhook management * API code cleanup, removing unneeded functions, and updating validation logic * Incorrectly ignoring the error that the webhook did not exist * Re-adding missing error handling. Changing error response to be a 404 vs 500 when token can't find an object * fix(webhooks): close Docker client after service webhook execution
2018-09-03 10:08:03 +00:00
var serviceIdentifier;
Service.create(config).$promise
.then(function success(data) {
feat(webhooks): add support for service update webhooks (#2161) * Initial pass at adding webhook controller and routes * Moving some objects around * Cleaning up comments * Fixing syntax, switching to using the docker sdk over building an http client * Adding delete and list functionality * Updating the handler to use the correct permissions. Updating some comments * Fixing some comments * Code cleanup per pull request comments * Cleanup per PR feedback. Syntax error fix * Initial creation of webhook app code * Moving ClientFactory creation out of handler code and instead using the one created by the main process. Removing webhookInspect method and updating the list function to use json filters * Delete now works on the webhook ID vs service ID * WIP - Service creates a webhook. Display will show an existing webhook URL. * Adding the webhook field to the service view. There is now the ability to add or remove a webhook from a service * Moving all api calls to be webhooks vs webhook * Code cleanup. Moving all api calls to be webhooks vs webhook * More conversion of webhook to webhooks? * Moving UI elements around. Starting function for copying to clipboard * Finalizing function for copying to clipboard. Adding button that calls function and copies webhook to clipboard. * Fixing UI issues. Hiding field entirely when there is no webhook * Moving URL crafting to a helper method. The edit pane for service now creates/deletes webhooks immidiately. * style(service-details): update webhook line * feat(api): strip sha when updating an image via the update webhook * Fixing up some copy. Only displying the port if it is not http or https * Fixing tooltip copy. Setting the forceupdate to be true to require an update to occur * Fixing code climate errors * Adding WebhookType field and setting to ServiceWebhook for new webhooks. Renaming ServiceID to resourceID so future work can add new types of webhooks in other resource areas. * Adding the webhook type to the payload to support more types of webhooks in the future. Setting the type correctly when creating one for a service * feat(webhooks): changes related to webhook management * API code cleanup, removing unneeded functions, and updating validation logic * Incorrectly ignoring the error that the webhook did not exist * Re-adding missing error handling. Changing error response to be a 404 vs 500 when token can't find an object * fix(webhooks): close Docker client after service webhook execution
2018-09-03 10:08:03 +00:00
serviceIdentifier = data.ID;
return $q.when($scope.formValues.Webhook && WebhookService.createServiceWebhook(serviceIdentifier, EndpointProvider.endpointID()));
})
.then(function success() {
var userId = Authentication.getUserDetails().ID;
return ResourceControlService.applyResourceControl('service', serviceIdentifier, userId, accessControlData, []);
})
.then(function success() {
Notifications.success('Service successfully created');
$state.go('docker.services', {}, {reload: true});
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to create service');
})
.finally(function final() {
$scope.state.actionInProgress = false;
});
}
function validateForm(accessControlData, isAdmin) {
$scope.state.formValidationError = '';
var error = '';
error = FormValidator.validateAccessControl(accessControlData, isAdmin);
if (error) {
$scope.state.formValidationError = error;
return false;
}
return true;
}
$scope.create = function createService() {
var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
if (!validateForm(accessControlData, isAdmin)) {
return;
}
$scope.state.actionInProgress = true;
var config = prepareConfiguration();
createNewService(config, accessControlData);
};
function initSlidersMaxValuesBasedOnNodeData(nodes) {
var maxCpus = 0;
var maxMemory = 0;
for (var n in nodes) {
if (nodes[n].CPUs && nodes[n].CPUs > maxCpus) {
maxCpus = nodes[n].CPUs;
}
if (nodes[n].Memory && nodes[n].Memory > maxMemory) {
maxMemory = nodes[n].Memory;
}
}
if (maxCpus > 0) {
$scope.state.sliderMaxCpu = maxCpus / 1000000000;
} else {
$scope.state.sliderMaxCpu = 32;
}
if (maxMemory > 0) {
$scope.state.sliderMaxMemory = Math.floor(maxMemory / 1000 / 1000);
} else {
$scope.state.sliderMaxMemory = 32768;
}
}
function initView() {
var apiVersion = $scope.applicationState.endpoint.apiVersion;
$q.all({
volumes: VolumeService.volumes(),
networks: NetworkService.networks(true, true, false),
secrets: apiVersion >= 1.25 ? SecretService.secrets() : [],
configs: apiVersion >= 1.30 ? ConfigService.configs() : [],
nodes: NodeService.nodes(),
settings: SettingsService.publicSettings(),
availableLoggingDrivers: PluginService.loggingPlugins(apiVersion < 1.25)
})
.then(function success(data) {
$scope.availableVolumes = data.volumes;
$scope.availableNetworks = data.networks;
$scope.availableSecrets = data.secrets;
$scope.availableConfigs = data.configs;
$scope.availableLoggingDrivers = data.availableLoggingDrivers;
initSlidersMaxValuesBasedOnNodeData(data.nodes);
$scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers;
var userDetails = Authentication.getUserDetails();
$scope.isAdmin = userDetails.role === 1;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to initialize view');
});
}
initView();
}]);