feat(service): add hosts file entries in service create/update (#1511)

pull/1497/merge
Miguel A. C 7 years ago committed by Anthony Lapenna
parent c9e060d574
commit 8e40eb1844

@ -20,6 +20,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
Volumes: [],
Network: '',
ExtraNetworks: [],
HostsEntries: [],
Ports: [],
Parallelism: 1,
PlacementConstraints: [],
@ -69,6 +70,14 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
$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' });
};
@ -244,6 +253,22 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
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,
@ -355,6 +380,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
prepareLabelsConfig(config, input);
prepareVolumes(config, input);
prepareNetworks(config, input);
prepareHostsEntries(config, input);
prepareUpdateConfig(config, input);
prepareConfigConfig(config, input);
prepareSecretConfig(config, input);

@ -308,6 +308,29 @@
<!-- !network-input-list -->
</div>
<!-- !extra-networks -->
<!-- extra-hosts-variables -->
<div class="form-group" ng-if="applicationState.endpoint.apiVersion >= 1.25">
<div class="col-sm-12" style="margin-top: 5px;">
<label class="control-label text-left">Hosts file entries</label>
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addHostsEntry()">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add additional entry
</span>
</div>
<!-- hosts-input-list -->
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
<div ng-repeat="variable in formValues.HostsEntries" style="margin-top: 2px;">
<div class="input-group col-sm-5 input-group-sm">
<span class="input-group-addon">value</span>
<input type="text" class="form-control" ng-model="variable.value" placeholder="e.g. host:IP">
</div>
<button class="btn btn-sm btn-danger" type="button" ng-click="removeHostsEntry($index)">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
<!-- !hosts-input-list -->
</div>
<!-- !extra-hosts-variables -->
</form>
</div>
<!-- !tab-network -->

@ -0,0 +1,57 @@
<div>
<rd-widget>
<rd-widget-header icon="fa-tasks" title="Hosts file entries">
<div class="nopadding">
<a class="btn btn-default btn-sm pull-right" ng-click="isUpdating ||addHostsEntry(service)" ng-disabled="isUpdating">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add host entry
</a>
</div>
</rd-widget-header>
<rd-widget-body ng-if="!service.Hosts || service.Hosts.length === 0">
<p>The Hosts file has no extra entries.</p>
</rd-widget-body>
<rd-widget-body ng-if="service.Hosts.length > 0" classes="no-padding">
<table class="table" >
<thead>
<tr>
<th>Hostname</th>
<th>IP</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="entry in service.Hosts">
<td>
<div class="input-group input-group-sm">
<input type="text" class="form-control" ng-model="entry.hostname" placeholder="e.g. example.com" ng-change="updateHostsEntry(service, entry)" ng-disabled="isUpdating">
</div>
</td>
<td>
<div class="input-group input-group-sm">
<input type="text" class="form-control" ng-model="entry.ip" placeholder="e.g. 10.0.1.1" ng-change="updateHostsEntry(service, entry)" ng-disabled="isUpdating">
<span class="input-group-btn">
<button class="btn btn-sm btn-danger" type="button" ng-click="removeHostsEntry(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
</span>
</div>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['Hosts'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['Hosts'])">Reset changes</a></li>
<li><a ng-click="cancelChanges(service)">Reset all changes</a></li>
</ul>
</div>
</div>
</rd-widget-footer>
</rd-widget>
</div>

@ -152,6 +152,7 @@
<h3 id="service-network-specs">Networks &amp; ports</h3>
<div id="service-networks" class="padding-top" ng-include="'app/components/service/includes/networks.html'"></div>
<div id="service-published-ports" class="padding-top" ng-include="'app/components/service/includes/ports.html'"></div>
<div id="service-hosts-entries" class="padding-top" ng-include="'app/components/service/includes/hosts.html'"></div>
</div>
</div>

@ -168,6 +168,22 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
}
};
$scope.addHostsEntry = function (service) {
if (!service.Hosts) {
service.Hosts = [];
}
service.Hosts.push({ hostname: '', ip: '' });
};
$scope.removeHostsEntry = function(service, index) {
var removedElement = service.Hosts.splice(index, 1);
if (removedElement !== null) {
updateServiceArray(service, 'Hosts', service.Hosts);
}
};
$scope.updateHostsEntry = function(service, entry) {
updateServiceArray(service, 'Hosts', service.Hosts);
};
$scope.cancelChanges = function cancelChanges(service, keys) {
if (keys) { // clean out the keys only from the list of modified keys
keys.forEach(function(key) {
@ -203,6 +219,7 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
config.TaskTemplate.ContainerSpec.Image = service.Image;
config.TaskTemplate.ContainerSpec.Secrets = service.ServiceSecrets ? service.ServiceSecrets.map(SecretHelper.secretConfig) : [];
config.TaskTemplate.ContainerSpec.Configs = service.ServiceConfigs ? service.ServiceConfigs.map(ConfigHelper.configConfig) : [];
config.TaskTemplate.ContainerSpec.Hosts = service.Hosts ? ServiceHelper.translateHostnameIPToHostsEntries(service.Hosts) : [];
if (service.Mode === 'replicated') {
config.Mode.Replicated.Replicas = service.Replicas;
@ -300,6 +317,7 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
service.ServiceMounts = angular.copy(service.Mounts);
service.ServiceConstraints = ServiceHelper.translateConstraintsToKeyValue(service.Constraints);
service.ServicePreferences = ServiceHelper.translatePreferencesToKeyValue(service.Preferences);
service.Hosts = ServiceHelper.translateHostsEntriesToHostnameIP(service.Hosts);
}
function transformResources(service) {

@ -191,5 +191,31 @@ angular.module('portainer.helpers').factory('ServiceHelper', [function ServiceHe
return humanDuration;
};
helper.translateHostsEntriesToHostnameIP = function(entries) {
var ipHostEntries = [];
if (entries) {
entries.forEach(function(entry) {
if (entry.indexOf(' ') && entry.split(' ').length === 2) {
var keyValue = entry.split(' ');
ipHostEntries.push({ hostname: keyValue[1], ip: keyValue[0]});
}
});
}
return ipHostEntries;
};
helper.translateHostnameIPToHostsEntries = function(entries) {
var ipHostEntries = [];
if (entries) {
entries.forEach(function(entry) {
if (entry.ip && entry.hostname) {
ipHostEntries.push(entry.ip + ' ' + entry.hostname);
}
});
}
return ipHostEntries;
};
return helper;
}]);

Loading…
Cancel
Save