1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 05:45:22 +02:00

feat(global): multi endpoint management (#407)

This commit is contained in:
Anthony Lapenna 2016-12-26 09:34:02 +13:00 committed by GitHub
parent a08ea134fc
commit d54d30a7be
47 changed files with 1837 additions and 161 deletions

View file

@ -5,6 +5,7 @@ angular.module('portainer', [
'ui.select',
'ngCookies',
'ngSanitize',
'ngFileUpload',
'angularUtils.directives.dirPagination',
'LocalStorageModule',
'angular-jwt',
@ -19,6 +20,9 @@ angular.module('portainer', [
'containers',
'createContainer',
'docker',
'endpoint',
'endpointInit',
'endpoints',
'events',
'images',
'image',
@ -270,6 +274,50 @@ angular.module('portainer', [
requiresLogin: true
}
})
.state('endpoints', {
url: '/endpoints/',
views: {
"content": {
templateUrl: 'app/components/endpoints/endpoints.html',
controller: 'EndpointsController'
},
"sidebar": {
templateUrl: 'app/components/sidebar/sidebar.html',
controller: 'SidebarController'
}
},
data: {
requiresLogin: true
}
})
.state('endpoint', {
url: '^/endpoints/:id',
views: {
"content": {
templateUrl: 'app/components/endpoint/endpoint.html',
controller: 'EndpointController'
},
"sidebar": {
templateUrl: 'app/components/sidebar/sidebar.html',
controller: 'SidebarController'
}
},
data: {
requiresLogin: true
}
})
.state('endpointInit', {
url: '/init/endpoint',
views: {
"content": {
templateUrl: 'app/components/endpointInit/endpointInit.html',
controller: 'EndpointInitController'
}
},
data: {
requiresLogin: true
}
})
.state('events', {
url: '/events/',
views: {
@ -491,18 +539,19 @@ angular.module('portainer', [
});
$rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams) {
if ((fromState.name === 'auth' || fromState.name === '') && Authentication.isAuthenticated()) {
if (toState.name !== 'endpointInit' && (fromState.name === 'auth' || fromState.name === '' || fromState.name === 'endpointInit') && Authentication.isAuthenticated()) {
EndpointMode.determineEndpointMode();
}
});
}])
// This is your docker url that the api will use to make requests
// You need to set this to the api endpoint without the port i.e. http://192.168.1.9
.constant('DOCKER_ENDPOINT', '/api/docker')
.constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is required. If you have a port, prefix it with a ':' i.e. :4243
.constant('CONFIG_ENDPOINT', '/api/settings')
.constant('DOCKER_ENDPOINT', '/api/docker')
.constant('CONFIG_ENDPOINT', '/api/settings')
.constant('AUTH_ENDPOINT', '/api/auth')
.constant('USERS_ENDPOINT', '/api/users')
.constant('ENDPOINTS_ENDPOINT', '/api/endpoints')
.constant('TEMPLATES_ENDPOINT', '/api/templates')
.constant('PAGINATION_MAX_ITEMS', 10)
.constant('UI_VERSION', 'v1.10.2');

View file

@ -1,11 +1,11 @@
<div class="login-wrapper">
<div class="page-wrapper">
<!-- login box -->
<div class="container login-box">
<div class="container simple-box">
<div class="col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3">
<!-- login box logo -->
<div class="row">
<img ng-if="logo" ng-src="{{ logo }}" class="login-logo">
<img ng-if="!logo" src="images/logo_alt.png" class="login-logo" alt="Portainer">
<img ng-if="logo" ng-src="{{ logo }}" class="simple-box-logo">
<img ng-if="!logo" src="images/logo_alt.png" class="simple-box-logo" alt="Portainer">
</div>
<!-- !login box logo -->
<!-- init password panel -->

View file

@ -1,6 +1,6 @@
angular.module('auth', [])
.controller('AuthenticationController', ['$scope', '$state', '$stateParams', '$window', '$timeout', '$sanitize', 'Config', 'Authentication', 'Users', 'Messages',
function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Config, Authentication, Users, Messages) {
.controller('AuthenticationController', ['$scope', '$state', '$stateParams', '$window', '$timeout', '$sanitize', 'Config', 'Authentication', 'Users', 'EndpointService', 'Messages',
function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Config, Authentication, Users, EndpointService, Messages) {
$scope.authData = {
username: 'admin',
@ -58,10 +58,17 @@ function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Config, Au
$scope.authenticationError = false;
var username = $sanitize($scope.authData.username);
var password = $sanitize($scope.authData.password);
Authentication.login(username, password)
.then(function() {
$state.go('dashboard');
}, function() {
Authentication.login(username, password).then(function success() {
EndpointService.getActive().then(function success(data) {
$state.go('dashboard');
}, function error(err) {
if (err.status === 404) {
$state.go('endpointInit');
} else {
Messages.error("Failure", err, 'Unable to verify Docker endpoint existence');
}
});
}, function error() {
$scope.authData.error = 'Invalid credentials';
});
};

View file

@ -152,7 +152,7 @@ function ($scope, $filter, Container, ContainerHelper, Info, Settings, Messages,
Config.$promise.then(function (c) {
$scope.containersToHideLabels = c.hiddenLabels;
if (c.swarm && $scope.endpointMode.provider === 'DOCKER_SWARM') {
if ($scope.endpointMode.provider === 'DOCKER_SWARM') {
Info.get({}, function (d) {
$scope.swarm_hosts = retrieveSwarmHostsInfo(d);
update({all: Settings.displayAll ? 1 : 0});

View file

@ -62,7 +62,6 @@ function ($scope, $state, $stateParams, $filter, Config, Info, Container, Contai
};
Config.$promise.then(function (c) {
$scope.swarm = c.swarm;
var containersToHideLabels = c.hiddenLabels;
Volume.query({}, function (d) {
@ -73,7 +72,7 @@ function ($scope, $state, $stateParams, $filter, Config, Info, Container, Contai
Network.query({}, function (d) {
var networks = d;
if ($scope.swarm) {
if ($scope.endpointMode.provider === 'DOCKER_SWARM' || $scope.endpointMode.provider === 'DOCKER_SWARM_MODE') {
networks = d.filter(function (network) {
if (network.Scope === 'global') {
return network;
@ -221,7 +220,7 @@ function ($scope, $state, $stateParams, $filter, Config, Info, Container, Contai
var containerName = container;
if (container && typeof container === 'object') {
containerName = $filter('trimcontainername')(container.Names[0]);
if ($scope.swarm && $scope.endpointMode.provider === 'DOCKER_SWARM') {
if ($scope.endpointMode.provider === 'DOCKER_SWARM') {
containerName = $filter('swarmcontainername')(container);
}
}

View file

@ -80,7 +80,7 @@
<input type="text" class="form-control" ng-model="portBinding.containerPort" placeholder="e.g. 80">
</div>
<div class="input-group col-sm-1 input-group-sm">
<select class="selectpicker form-control" ng-model="portBinding.protocol">
<select class="form-control" ng-model="portBinding.protocol">
<option value="tcp">tcp</option>
<option value="udp">udp</option>
</select>
@ -243,7 +243,7 @@
</div>
<div class="input-group col-sm-5 input-group-sm">
<span class="input-group-addon"><input type="checkbox" ng-model="volume.isPath" ng-click="resetVolumePath($index)">Path</span>
<select class="selectpicker form-control" ng-model="volume.name" ng-if="!volume.isPath">
<select class="form-control" ng-model="volume.name" ng-if="!volume.isPath">
<option selected disabled hidden value="">Select a volume</option>
<option ng-repeat="vol in availableVolumes" ng-value="vol.Name">{{ vol.Name|truncate:30}}</option>
</select>
@ -278,7 +278,7 @@
<div class="form-group">
<label for="container_network" class="col-sm-1 control-label text-left">Network</label>
<div class="col-sm-9">
<select class="selectpicker form-control" ng-model="config.HostConfig.NetworkMode" id="container_network">
<select class="form-control" ng-model="config.HostConfig.NetworkMode" id="container_network">
<option selected disabled hidden value="">Select a network</option>
<option ng-repeat="net in availableNetworks" ng-value="net.Name">{{ net.Name }}</option>
</select>
@ -289,10 +289,10 @@
<div class="form-group" ng-if="config.HostConfig.NetworkMode == 'container'">
<label for="container_network_container" class="col-sm-1 control-label text-left">Container</label>
<div class="col-sm-9">
<select ng-if="endpointMode.provider !== 'DOCKER_SWARM'" ng-options="container|containername for container in runningContainers" class="selectpicker form-control" ng-model="formValues.NetworkContainer">
<select ng-if="endpointMode.provider !== 'DOCKER_SWARM'" ng-options="container|containername for container in runningContainers" class="form-control" ng-model="formValues.NetworkContainer">
<option selected disabled hidden value="">Select a container</option>
</select>
<select ng-if="endpointMode.provider === 'DOCKER_SWARM'" ng-options="container|swarmcontainername for container in runningContainers" class="selectpicker form-control" ng-model="formValues.NetworkContainer">
<select ng-if="endpointMode.provider === 'DOCKER_SWARM'" ng-options="container|swarmcontainername for container in runningContainers" class="form-control" ng-model="formValues.NetworkContainer">
<option selected disabled hidden value="">Select a container</option>
</select>
</div>

View file

@ -72,7 +72,7 @@
<input type="text" class="form-control" ng-model="portBinding.TargetPort" placeholder="e.g. 80">
</div>
<div class="input-group col-sm-1 input-group-sm">
<select class="selectpicker form-control" ng-model="portBinding.Protocol">
<select class="form-control" ng-model="portBinding.Protocol">
<option value="tcp">tcp</option>
<option value="udp">udp</option>
</select>
@ -192,7 +192,7 @@
</div>
<div class="input-group col-sm-5 input-group-sm">
<span class="input-group-addon"><input type="checkbox" ng-model="volume.Bind">bind</span>
<select class="selectpicker form-control" ng-model="volume.Source" ng-if="!volume.Bind">
<select class="form-control" ng-model="volume.Source" ng-if="!volume.Bind">
<option selected disabled hidden value="">Select a volume</option>
<option ng-repeat="vol in availableVolumes" ng-value="vol.Name">{{ vol.Name|truncate:30}}</option>
</select>
@ -222,7 +222,7 @@
<div class="form-group">
<label for="container_network" class="col-sm-1 control-label text-left">Network</label>
<div class="col-sm-9">
<select class="selectpicker form-control" ng-model="formValues.Network">
<select class="form-control" ng-model="formValues.Network">
<option selected disabled hidden value="">Select a network</option>
<option ng-repeat="net in availableNetworks" ng-value="net.Name">{{ net.Name }}</option>
</select>
@ -247,7 +247,7 @@
<i class="fa fa-minus" aria-hidden="true"></i>
</button>
</span>
<select class="selectpicker form-control" ng-model="network.Name">
<select class="form-control" ng-model="network.Name">
<option selected disabled hidden value="">Select a network</option>
<option ng-repeat="net in availableNetworks" ng-value="net.Name">{{ net.Name }}</option>
</select>

View file

@ -87,7 +87,6 @@ function ($scope, $q, Config, Container, ContainerHelper, Image, Network, Volume
}
Config.$promise.then(function (c) {
$scope.swarm = c.swarm;
fetchDashboardData(c.hiddenLabels);
});
}]);

View file

@ -0,0 +1,99 @@
<rd-header>
<rd-header-title title="Endpoint details">
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content>
<a ui-sref="endpoints">Endpoints</a> > <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a>
</rd-header-content>
</rd-header>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-body>
<form class="form-horizontal">
<!-- name-input -->
<div class="form-group">
<label for="container_name" class="col-sm-2 control-label text-left">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="container_name" ng-model="endpoint.Name" placeholder="e.g. docker-prod01">
</div>
</div>
<!-- !name-input -->
<!-- endpoint-url-input -->
<div class="form-group">
<label for="endpoint_url" class="col-sm-2 control-label text-left">Endpoint URL</label>
<div class="col-sm-10">
<input ng-disabled="endpointType === 'local'" type="text" class="form-control" id="endpoint_url" ng-model="endpoint.URL" placeholder="e.g. 10.0.0.10:2375 or mydocker.mydomain.com:2375">
</div>
</div>
<!-- !endpoint-url-input -->
<!-- tls-checkbox -->
<div class="form-group" ng-if="endpointType === 'remote'">
<label for="tls" class="col-sm-2 control-label text-left">TLS</label>
<div class="col-sm-10">
<input type="checkbox" name="tls" ng-model="endpoint.TLS">
</div>
</div>
<!-- !tls-checkbox -->
<!-- tls-certs -->
<div ng-if="endpoint.TLS">
<!-- ca-input -->
<div class="form-group">
<label class="col-sm-2 control-label text-left">TLS CA certificate</label>
<div class="col-sm-10">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSCACert">Select file</button>
<span style="margin-left: 5px;">
<span ng-if="formValues.TLSCACert !== endpoint.TLSCACert">{{ formValues.TLSCACert.name }}</span>
<i class="fa fa-check green-icon" ng-if="formValues.TLSCACert && formValues.TLSCACert === endpoint.TLSCACert" aria-hidden="true"></i>
<i class="fa fa-times red-icon" ng-if="!formValues.TLSCACert" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !ca-input -->
<!-- cert-input -->
<div class="form-group">
<label for="tls_cert" class="col-sm-2 control-label text-left">TLS certificate</label>
<div class="col-sm-10">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSCert">Select file</button>
<span style="margin-left: 5px;">
<span ng-if="formValues.TLSCert !== endpoint.TLSCert">{{ formValues.TLSCert.name }}</span>
<i class="fa fa-check green-icon" ng-if="formValues.TLSCert && formValues.TLSCert === endpoint.TLSCert" aria-hidden="true"></i>
<i class="fa fa-times red-icon" ng-if="!formValues.TLSCert" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !cert-input -->
<!-- key-input -->
<div class="form-group">
<label class="col-sm-2 control-label text-left">TLS key</label>
<div class="col-sm-10">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSKey">Select file</button>
<span style="margin-left: 5px;">
<span ng-if="formValues.TLSKey !== endpoint.TLSKey">{{ formValues.TLSKey.name }}</span>
<i class="fa fa-check green-icon" ng-if="formValues.TLSKey && formValues.TLSKey === endpoint.TLSKey" aria-hidden="true"></i>
<i class="fa fa-times red-icon" ng-if="!formValues.TLSKey" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !key-input -->
</div>
<!-- !tls-certs -->
<div class="form-group">
<div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!endpoint.Name || !endpoint.URL || (endpoint.TLS && (!formValues.TLSCACert || !formValues.TLSCert || !formValues.TLSKey))" ng-click="updateEndpoint()">Update endpoint</button>
<a type="button" class="btn btn-default btn-sm" ui-sref="endpoints">Cancel</a>
<i id="updateEndpointSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
<span class="text-danger" ng-if="state.error" style="margin: 5px;">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.error }}
</span>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>

View file

@ -0,0 +1,55 @@
angular.module('endpoint', [])
.controller('EndpointController', ['$scope', '$state', '$stateParams', '$filter', 'EndpointService', 'Messages',
function ($scope, $state, $stateParams, $filter, EndpointService, Messages) {
$scope.state = {
error: '',
uploadInProgress: false
};
$scope.formValues = {
TLSCACert: null,
TLSCert: null,
TLSKey: null
};
$scope.updateEndpoint = function() {
var ID = $scope.endpoint.Id;
var name = $scope.endpoint.Name;
var URL = $scope.endpoint.URL;
var TLS = $scope.endpoint.TLS;
var TLSCACert = $scope.formValues.TLSCACert !== $scope.endpoint.TLSCACert ? $scope.formValues.TLSCACert : null;
var TLSCert = $scope.formValues.TLSCert !== $scope.endpoint.TLSCert ? $scope.formValues.TLSCert : null;
var TLSKey = $scope.formValues.TLSKey !== $scope.endpoint.TLSKey ? $scope.formValues.TLSKey : null;
EndpointService.updateEndpoint(ID, name, URL, TLS, TLSCACert, TLSCert, TLSKey).then(function success(data) {
Messages.send("Endpoint updated", $scope.endpoint.Name);
$state.go('endpoints');
}, function error(err) {
$scope.state.error = err.msg;
}, function update(evt) {
if (evt.upload) {
$scope.state.uploadInProgress = evt.upload;
}
});
};
function getEndpoint(endpointID) {
$('#loadingViewSpinner').show();
EndpointService.endpoint($stateParams.id).then(function success(data) {
$('#loadingViewSpinner').hide();
$scope.endpoint = data;
if (data.URL.indexOf("unix://") === 0) {
$scope.endpointType = 'local';
} else {
$scope.endpointType = 'remote';
}
$scope.endpoint.URL = $filter('stripprotocol')(data.URL);
$scope.formValues.TLSCACert = data.TLSCACert;
$scope.formValues.TLSCert = data.TLSCert;
$scope.formValues.TLSKey = data.TLSKey;
}, function error(err) {
$('#loadingViewSpinner').hide();
Messages.error("Failure", err, "Unable to retrieve endpoint details");
});
}
getEndpoint($stateParams.id);
}]);

View file

@ -0,0 +1,139 @@
<div class="page-wrapper">
<!-- simple box -->
<div class="container simple-box">
<div class="col-md-8 col-md-offset-2 col-sm-8 col-sm-offset-2">
<!-- simple box logo -->
<div class="row">
<img ng-if="logo" ng-src="{{ logo }}" class="simple-box-logo">
<img ng-if="!logo" src="images/logo_alt.png" class="simple-box-logo" alt="Portainer">
</div>
<!-- !simple box logo -->
<!-- init-endpoint panel -->
<div class="panel panel-default">
<div class="panel-body">
<!-- init-endpoint form -->
<form class="form-horizontal" style="margin: 20px;" enctype="multipart/form-data" method="POST">
<!-- comment -->
<div class="form-group">
<p>Connect Portainer to a Docker engine or Swarm cluster endpoint.</p>
</div>
<!-- !comment input -->
<!-- endpoin-type radio -->
<div class="form-group">
<div class="radio">
<label><input type="radio" name="endpointType" value="local" ng-model="formValues.endpointType">Manage the Docker instance where Portainer is running</label>
</div>
<div class="radio">
<label><input type="radio" name="endpointType" value="remote" ng-model="formValues.endpointType">Manage a remote Docker instance</label>
</div>
</div>
<!-- endpoint-type radio -->
<!-- local-endpoint -->
<div ng-if="formValues.endpointType === 'local'" style="margin-top: 25px;">
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">Note: ensure that the Docker socket is bind mounted in the Portainer container at <code>/var/run/docker.sock</code></span>
</div>
</div>
<!-- connect button -->
<div class="form-group" style="margin-top: 10px;">
<div class="col-sm-12 controls">
<p class="pull-left text-danger" ng-if="state.error" style="margin: 5px;">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.error }}
</p>
<button type="submit" class="btn btn-primary pull-right" ng-click="createLocalEndpoint()"><i class="fa fa-plug" aria-hidden="true"></i> Connect</button>
</div>
</div>
<!-- !connect button -->
</div>
<!-- !local-endpoint -->
<!-- remote-endpoint -->
<div ng-if="formValues.endpointType === 'remote'" style="margin-top: 25px;">
<!-- name-input -->
<div class="form-group">
<label for="container_name" class="col-sm-3 control-label text-left">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="container_name" ng-model="formValues.Name" placeholder="e.g. docker-prod01">
</div>
</div>
<!-- !name-input -->
<!-- endpoint-url-input -->
<div class="form-group">
<label for="endpoint_url" class="col-sm-3 control-label text-left">Endpoint URL</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="endpoint_url" ng-model="formValues.URL" placeholder="e.g. 10.0.0.10:2375 or mydocker.mydomain.com:2375">
</div>
</div>
<!-- !endpoint-url-input -->
<!-- tls-checkbox -->
<div class="form-group">
<label for="tls" class="col-sm-3 control-label text-left">TLS</label>
<div class="col-sm-9">
<input type="checkbox" name="tls" ng-model="formValues.TLS">
</div>
</div>
<!-- !tls-checkbox -->
<!-- tls-certs -->
<div ng-if="formValues.TLS">
<!-- ca-input -->
<div class="form-group">
<label class="col-sm-3 control-label text-left">TLS CA certificate</label>
<div class="col-sm-9">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSCACert">Select file</button>
<span style="margin-left: 5px;">
{{ formValues.TLSCACert.name }}
<i class="fa fa-times red-icon" ng-if="!formValues.TLSCACert" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !ca-input -->
<!-- cert-input -->
<div class="form-group">
<label for="tls_cert" class="col-sm-3 control-label text-left">TLS certificate</label>
<div class="col-sm-9">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSCert">Select file</button>
<span style="margin-left: 5px;">
{{ formValues.TLSCert.name }}
<i class="fa fa-times red-icon" ng-if="!formValues.TLSCert" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !cert-input -->
<!-- key-input -->
<div class="form-group">
<label class="col-sm-3 control-label text-left">TLS key</label>
<div class="col-sm-9">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSKey">Select file</button>
<span style="margin-left: 5px;">
{{ formValues.TLSKey.name }}
<i class="fa fa-times red-icon" ng-if="!formValues.TLSKey" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !key-input -->
</div>
<!-- !tls-certs -->
<!-- connect button -->
<div class="form-group" style="margin-top: 10px;">
<div class="col-sm-12 controls">
<p class="pull-left text-danger" ng-if="state.error" style="margin: 5px;">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.error }}
</p>
<button type="submit" class="btn btn-primary pull-right" ng-disabled="!formValues.Name || !formValues.URL || (formValues.TLS && (!formValues.TLSCACert || !formValues.TLSCert || !formValues.TLSKey))" ng-click="createRemoteEndpoint()"><i class="fa fa-plug" aria-hidden="true"></i> Connect</button>
</div>
</div>
<!-- !connect button -->
</div>
<!-- !remote-endpoint -->
</form>
<!-- !init-endpoint form -->
</div>
</div>
<!-- !init-endpoint panel -->
</div>
</div>
<!-- !simple box -->
</div>

View file

@ -0,0 +1,57 @@
angular.module('endpointInit', [])
.controller('EndpointInitController', ['$scope', '$state', 'EndpointService', 'Messages',
function ($scope, $state, EndpointService, Messages) {
$scope.state = {
error: '',
uploadInProgress: false
};
$scope.formValues = {
endpointType: "remote",
Name: '',
URL: '',
TLS: false,
TLSCACert: null,
TLSCert: null,
TLSKey: null
};
EndpointService.getActive().then(function success(data) {
$state.go('dashboard');
}, function error(err) {
if (err.status !== 404) {
Messages.error("Failure", err, 'Unable to verify Docker endpoint existence');
}
});
$scope.createLocalEndpoint = function() {
$scope.state.error = '';
var name = "local";
var URL = "unix:///var/run/docker.sock";
var TLS = false;
EndpointService.createLocalEndpoint(name, URL, TLS, true).then(function success(data) {
$state.go('dashboard');
}, function error(err) {
$scope.state.error = 'Unable to create endpoint';
});
};
$scope.createRemoteEndpoint = function() {
$scope.state.error = '';
var name = $scope.formValues.Name;
var URL = $scope.formValues.URL;
var TLS = $scope.formValues.TLS;
var TLSCAFile = $scope.formValues.TLSCACert;
var TLSCertFile = $scope.formValues.TLSCert;
var TLSKeyFile = $scope.formValues.TLSKey;
EndpointService.createRemoteEndpoint(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, TLS ? false : true).then(function success(data) {
$state.go('dashboard');
}, function error(err) {
$scope.state.uploadInProgress = false;
$scope.state.error = err.msg;
}, function update(evt) {
if (evt.upload) {
$scope.state.uploadInProgress = evt.upload;
}
});
};
}]);

View file

@ -0,0 +1,175 @@
<rd-header>
<rd-header-title title="Endpoints">
<a data-toggle="tooltip" title="Refresh" ui-sref="endpoints" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i>
</a>
</rd-header-title>
<rd-header-content>Endpoint management</rd-header-content>
</rd-header>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-plus" title="Add a new endpoint">
</rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<!-- name-input -->
<div class="form-group">
<label for="container_name" class="col-sm-2 control-label text-left">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="container_name" ng-model="formValues.Name" placeholder="e.g. docker-prod01">
</div>
</div>
<!-- !name-input -->
<!-- endpoint-url-input -->
<div class="form-group">
<label for="endpoint_url" class="col-sm-2 control-label text-left">Endpoint URL</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="endpoint_url" ng-model="formValues.URL" placeholder="e.g. 10.0.0.10:2375 or mydocker.mydomain.com:2375">
</div>
</div>
<!-- !endpoint-url-input -->
<!-- tls-checkbox -->
<div class="form-group">
<label for="tls" class="col-sm-2 control-label text-left">TLS</label>
<div class="col-sm-10">
<input type="checkbox" name="tls" ng-model="formValues.TLS">
</div>
</div>
<!-- !tls-checkbox -->
<!-- tls-certs -->
<div ng-if="formValues.TLS">
<!-- ca-input -->
<div class="form-group">
<label class="col-sm-2 control-label text-left">TLS CA certificate</label>
<div class="col-sm-10">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSCACert">Select file</button>
<span style="margin-left: 5px;">
{{ formValues.TLSCACert.name }}
<i class="fa fa-times red-icon" ng-if="!formValues.TLSCACert" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !ca-input -->
<!-- cert-input -->
<div class="form-group">
<label for="tls_cert" class="col-sm-2 control-label text-left">TLS certificate</label>
<div class="col-sm-10">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSCert">Select file</button>
<span style="margin-left: 5px;">
{{ formValues.TLSCert.name }}
<i class="fa fa-times red-icon" ng-if="!formValues.TLSCert" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !cert-input -->
<!-- key-input -->
<div class="form-group">
<label class="col-sm-2 control-label text-left">TLS key</label>
<div class="col-sm-10">
<button class="btn btn-sm btn-primary" ngf-select ng-model="formValues.TLSKey">Select file</button>
<span style="margin-left: 5px;">
{{ formValues.TLSKey.name }}
<i class="fa fa-times red-icon" ng-if="!formValues.TLSKey" aria-hidden="true"></i>
<i class="fa fa-circle-o-notch fa-spin" ng-if="state.uploadInProgress"></i>
</span>
</div>
</div>
<!-- !key-input -->
</div>
<!-- !tls-certs -->
<div class="form-group">
<div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name || !formValues.URL || (formValues.TLS && (!formValues.TLSCACert || !formValues.TLSCert || !formValues.TLSKey))" ng-click="addEndpoint()">Add endpoint</button>
<i id="createEndpointSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
<span class="text-danger" ng-if="state.error" style="margin: 5px;">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.error }}
</span>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-plug" title="Endpoints">
<div class="pull-right">
<i id="loadEndpointsSpinner" class="fa fa-cog fa-2x fa-spin" style="margin-top: 5px;"></i>
</div>
</rd-widget-header>
<rd-widget-taskbar classes="col-lg-12">
<div class="pull-left">
<button type="button" class="btn btn-danger" ng-click="removeAction()" ng-disabled="!state.selectedItemCount"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button>
</div>
<div class="pull-right">
<input type="text" id="filter" ng-model="state.filter" placeholder="Filter..." class="form-control input-sm" />
</div>
</rd-widget-taskbar>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th></th>
<th>
<a ui-sref="endpoints" ng-click="order('Name')">
Name
<span ng-show="sortType == 'Name' && !sortReverse" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortType == 'Name' && sortReverse" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
<th>
<a ui-sref="endpoints" ng-click="order('URL')">
URL
<span ng-show="sortType == 'URL' && !sortReverse" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortType == 'URL' && sortReverse" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
<th>
<a ui-sref="endpoints" ng-click="order('TLS')">
TLS
<span ng-show="sortType == 'TLS' && !sortReverse" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortType == 'TLS' && sortReverse" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr dir-paginate="endpoint in (state.filteredEndpoints = (endpoints | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: pagination_count))">
<td><input type="checkbox" ng-model="endpoint.Checked" ng-change="selectItem(endpoint)" /></td>
<td><i class="fa fa-star" aria-hidden="true" ng-if="endpoint.Id === activeEndpoint.Id"></i> {{ endpoint.Name }}</td>
<td>{{ endpoint.URL | stripprotocol }}</td>
<td><i class="fa fa-shield" aria-hidden="true" ng-if="endpoint.TLS"></i></td>
<td>
<span ng-if="endpoint.Id !== activeEndpoint.Id">
<a ui-sref="endpoint({id: endpoint.Id})"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> Edit</a>
</span>
<span class="small text-muted" ng-if="endpoint.Id === activeEndpoint.Id">
<i class="fa fa-lock" aria-hidden="true"></i> You cannot edit the active endpoint
</span>
</td>
</tr>
<tr ng-if="!endpoints">
<td colspan="5" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="endpoints.length == 0">
<td colspan="5" class="text-center text-muted">No endpoints available.</td>
</tr>
</tbody>
</table>
<div ng-if="endpoints" class="pull-left pagination-controls">
<dir-pagination-controls></dir-pagination-controls>
</div>
</div>
</rd-widget-body>
<rd-widget>
</div>
</div>

View file

@ -0,0 +1,100 @@
angular.module('endpoints', [])
.controller('EndpointsController', ['$scope', '$state', 'EndpointService', 'Settings', 'Messages',
function ($scope, $state, EndpointService, Settings, Messages) {
$scope.state = {
error: '',
uploadInProgress: false,
selectedItemCount: 0
};
$scope.sortType = 'Name';
$scope.sortReverse = true;
$scope.pagination_count = Settings.pagination_count;
$scope.formValues = {
Name: '',
URL: '',
TLS: false,
TLSCACert: null,
TLSCert: null,
TLSKey: null
};
$scope.order = function(sortType) {
$scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
$scope.sortType = sortType;
};
$scope.selectItem = function (item) {
if (item.Checked) {
$scope.state.selectedItemCount++;
} else {
$scope.state.selectedItemCount--;
}
};
$scope.addEndpoint = function() {
$scope.state.error = '';
var name = $scope.formValues.Name;
var URL = $scope.formValues.URL;
var TLS = $scope.formValues.TLS;
var TLSCAFile = $scope.formValues.TLSCACert;
var TLSCertFile = $scope.formValues.TLSCert;
var TLSKeyFile = $scope.formValues.TLSKey;
EndpointService.createRemoteEndpoint(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, false).then(function success(data) {
Messages.send("Endpoint created", name);
$state.reload();
}, function error(err) {
$scope.state.uploadInProgress = false;
$scope.state.error = err.msg;
}, function update(evt) {
if (evt.upload) {
$scope.state.uploadInProgress = evt.upload;
}
});
};
$scope.removeAction = function () {
$('#loadEndpointsSpinner').show();
var counter = 0;
var complete = function () {
counter = counter - 1;
if (counter === 0) {
$('#loadEndpointsSpinner').hide();
}
};
angular.forEach($scope.endpoints, function (endpoint) {
if (endpoint.Checked) {
counter = counter + 1;
EndpointService.deleteEndpoint(endpoint.Id).then(function success(data) {
Messages.send("Endpoint deleted", endpoint.Name);
var index = $scope.endpoints.indexOf(endpoint);
$scope.endpoints.splice(index, 1);
complete();
}, function error(err) {
Messages.error("Failure", err, 'Unable to remove endpoint');
complete();
});
}
});
};
function fetchEndpoints() {
$('#loadEndpointsSpinner').show();
EndpointService.endpoints().then(function success(data) {
$scope.endpoints = data;
EndpointService.getActive().then(function success(data) {
$scope.activeEndpoint = data;
$('#loadEndpointsSpinner').hide();
}, function error(err) {
$('#loadEndpointsSpinner').hide();
Messages.error("Failure", err, "Unable to retrieve active endpoint");
});
}, function error(err) {
$('#loadEndpointsSpinner').hide();
Messages.error("Failure", err, "Unable to retrieve endpoints");
$scope.endpoints = [];
});
}
fetchEndpoints();
}]);

View file

@ -38,7 +38,7 @@ function ($scope, $state, Config, Image, ImageHelper, Messages, Settings) {
Messages.error('Error', {}, detail.error);
} else {
$('#pullImageSpinner').hide();
$state.go('images', {}, {reload: true});
$state.reload();
}
}, function (e) {
$('#pullImageSpinner').hide();

View file

@ -13,7 +13,7 @@ function ($scope, $state, Network, Config, Messages, Settings) {
function prepareNetworkConfiguration() {
var config = angular.copy($scope.config);
if ($scope.swarm) {
if ($scope.endpointMode.provider === 'DOCKER_SWARM' || $scope.endpointMode.provider === 'DOCKER_SWARM_MODE') {
config.Driver = 'overlay';
// Force IPAM Driver to 'default', should not be required.
// See: https://github.com/docker/docker/issues/25735
@ -34,7 +34,7 @@ function ($scope, $state, Network, Config, Messages, Settings) {
} else {
Messages.send("Network created", d.Id);
$('#createNetworkSpinner').hide();
$state.go('networks', {}, {reload: true});
$state.reload();
}
}, function (e) {
$('#createNetworkSpinner').hide();
@ -97,7 +97,6 @@ function ($scope, $state, Network, Config, Messages, Settings) {
}
Config.$promise.then(function (c) {
$scope.swarm = c.swarm;
fetchNetworks();
});
}]);

View file

@ -14,7 +14,7 @@ function ($scope, $stateParams, $state, Service, ServiceHelper, Messages, Settin
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
$('#loadServicesSpinner').hide();
Messages.send("Service successfully scaled", "New replica count: " + service.Replicas);
$state.go('services', {}, {reload: true});
$state.reload();
}, function (e) {
$('#loadServicesSpinner').hide();
service.Scale = false;

View file

@ -16,7 +16,7 @@ function ($scope, $state, $sanitize, Users, Messages) {
var newPassword = $sanitize($scope.formValues.newPassword);
Users.update({ username: $scope.username, password: newPassword }, function (d) {
Messages.send("Success", "Password successfully updated");
$state.go('settings', {}, {reload: true});
$state.reload();
}, function (e) {
Messages.error("Failure", e, "Unable to update password");
});

View file

@ -8,7 +8,14 @@
<span class="menu-icon glyphicon glyphicon-transfer"></span>
</a>
</li>
<li class="sidebar-title"><span>NAVIGATION</span></li>
<li class="sidebar-title">
<span>Active endpoint</span>
</li>
<li class="sidebar-title">
<select class="select-endpoint form-control" ng-options="endpoint.Name for endpoint in endpoints" ng-model="activeEndpoint" ng-change="switchEndpoint(activeEndpoint)">
</select>
</li>
<li class="sidebar-title"><span>Endpoint actions</span></li>
<li class="sidebar-list">
<a ui-sref="dashboard">Dashboard <span class="menu-icon fa fa-tachometer"></span></a>
</li>
@ -39,8 +46,12 @@
<li class="sidebar-list" ng-if="endpointMode.provider === 'DOCKER_STANDALONE'">
<a ui-sref="docker">Docker <span class="menu-icon fa fa-th"></span></a>
</li>
<li class="sidebar-title"><span>Portainer settings</span></li>
<li class="sidebar-list">
<a ui-sref="settings">Settings <span class="menu-icon fa fa-wrench"></span></a>
<a ui-sref="settings">Password <span class="menu-icon fa fa-lock"></span></a>
</li>
<li class="sidebar-list">
<a ui-sref="endpoints">Endpoints <span class="menu-icon fa fa-plug"></span></a>
</li>
</ul>
<div class="sidebar-footer">

View file

@ -1,10 +1,38 @@
angular.module('sidebar', [])
.controller('SidebarController', ['$scope', 'Settings', 'Config', 'Info',
function ($scope, Settings, Config, Info) {
.controller('SidebarController', ['$scope', '$state', 'Settings', 'Config', 'EndpointService', 'EndpointMode', 'Messages',
function ($scope, $state, Settings, Config, EndpointService, EndpointMode, Messages) {
Config.$promise.then(function (c) {
$scope.logo = c.logo;
});
$scope.uiVersion = Settings.uiVersion;
$scope.switchEndpoint = function(endpoint) {
EndpointService.setActive(endpoint.Id).then(function success(data) {
EndpointMode.determineEndpointMode();
$state.reload();
}, function error(err) {
Messages.error("Failure", err, "Unable to switch to new endpoint");
});
};
function fetchEndpoints() {
EndpointService.endpoints().then(function success(data) {
$scope.endpoints = data;
EndpointService.getActive().then(function success(data) {
angular.forEach($scope.endpoints, function (endpoint) {
if (endpoint.Id === data.Id) {
$scope.activeEndpoint = endpoint;
}
});
}, function error(err) {
Messages.error("Failure", err, "Unable to retrieve active endpoint");
});
}, function error(err) {
$scope.endpoints = [];
});
}
fetchEndpoints();
}]);

View file

@ -32,7 +32,7 @@
</div>
<label for="container_network" class="col-sm-2 control-label text-right">Network</label>
<div class="col-sm-4">
<select class="selectpicker form-control" ng-options="net.Name for net in availableNetworks" ng-model="formValues.network">
<select class="form-control" ng-options="net.Name for net in availableNetworks" ng-model="formValues.network">
<option disabled hidden value="">Select a network</option>
</select>
</div>
@ -41,10 +41,10 @@
<div ng-repeat="var in state.selectedTemplate.env" ng-if="!var.set" class="form-group">
<label for="field_{{ $index }}" class="col-sm-2 control-label text-left">{{ var.label }}</label>
<div class="col-sm-10">
<select ng-if="endpointMode.provider !== 'DOCKER_SWARM' && var.type === 'container'" ng-options="container|containername for container in runningContainers" class="selectpicker form-control" ng-model="var.value">
<select ng-if="endpointMode.provider !== 'DOCKER_SWARM' && var.type === 'container'" ng-options="container|containername for container in runningContainers" class="form-control" ng-model="var.value">
<option selected disabled hidden value="">Select a container</option>
</select>
<select ng-if="endpointMode.provider === 'DOCKER_SWARM' && var.type === 'container'" ng-options="container|swarmcontainername for container in runningContainers" class="selectpicker form-control" ng-model="var.value">
<select ng-if="endpointMode.provider === 'DOCKER_SWARM' && var.type === 'container'" ng-options="container|swarmcontainername for container in runningContainers" class="form-control" ng-model="var.value">
<option selected disabled hidden value="">Select a container</option>
</select>
<input ng-if="!var.type || !var.type === 'container'" type="text" class="form-control" ng-model="var.value" id="field_{{ $index }}">
@ -79,7 +79,7 @@
<input type="text" class="form-control" ng-model="portBinding.containerPort" placeholder="e.g. 80">
</div>
<div class="input-group col-sm-1 input-group-sm">
<select class="selectpicker form-control" ng-model="portBinding.protocol">
<select class="form-control" ng-model="portBinding.protocol">
<option value="tcp">tcp</option>
<option value="udp">udp</option>
</select>

View file

@ -115,7 +115,7 @@ function ($scope, $q, $state, $filter, $anchorScroll, Config, Info, Container, C
if (v.value || v.set) {
var val;
if (v.type && v.type === 'container') {
if ($scope.swarm && $scope.formValues.network.Scope === 'global') {
if ($scope.endpointMode.provider === 'DOCKER_SWARM' && $scope.formValues.network.Scope === 'global') {
val = $filter('swarmcontainername')(v.value);
} else {
var container = v.value;
@ -203,11 +203,10 @@ function ($scope, $q, $state, $filter, $anchorScroll, Config, Info, Container, C
}
Config.$promise.then(function (c) {
$scope.swarm = c.swarm;
var containersToHideLabels = c.hiddenLabels;
Network.query({}, function (d) {
var networks = d;
if ($scope.swarm) {
if ($scope.endpointMode.provider === 'DOCKER_SWARM' || $scope.endpointMode.provider === 'DOCKER_SWARM_MODE') {
networks = d.filter(function (network) {
if (network.Scope === 'global') {
return network;

View file

@ -106,6 +106,12 @@ angular.module('portainer.filters', [])
return 'Stopped';
};
})
.filter('stripprotocol', function() {
'use strict';
return function (url) {
return url.replace(/.*?:\/\//g, '');
};
})
.filter('getstatelabel', function () {
'use strict';
return function (state) {

View file

@ -189,12 +189,12 @@ angular.module('portainer.services', ['ngResource', 'ngSanitize'])
'use strict';
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-5-networks
return $resource(Settings.url + '/volumes/:name/:action', {name: '@name'}, {
query: {method: 'GET'},
get: {method: 'GET'},
create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler},
remove: {
method: 'DELETE', transformResponse: genericHandler
}
query: {method: 'GET'},
get: {method: 'GET'},
create: {method: 'POST', params: {action: 'create'}, transformResponse: genericHandler},
remove: {
method: 'DELETE', transformResponse: genericHandler
}
});
}])
.factory('Config', ['$resource', 'CONFIG_ENDPOINT', function ConfigFactory($resource, CONFIG_ENDPOINT) {
@ -233,11 +233,11 @@ angular.module('portainer.services', ['ngResource', 'ngSanitize'])
'use strict';
return $resource(USERS_ENDPOINT + '/:username/:action', {}, {
create: { method: 'POST' },
get: {method: 'GET', params: { username: '@username' } },
get: { method: 'GET', params: { username: '@username' } },
update: { method: 'PUT', params: { username: '@username' } },
checkPassword: { method: 'POST', params: { username: '@username', action: 'passwd' } },
checkAdminUser: {method: 'GET', params: { username: 'admin', action: 'check' }},
initAdminUser: {method: 'POST', params: { username: 'admin', action: 'init' }}
checkAdminUser: { method: 'GET', params: { username: 'admin', action: 'check' } },
initAdminUser: { method: 'POST', params: { username: 'admin', action: 'init' } }
});
}])
.factory('EndpointMode', ['$rootScope', 'Info', function EndpointMode($rootScope, Info) {
@ -304,6 +304,144 @@ angular.module('portainer.services', ['ngResource', 'ngSanitize'])
}
};
}])
.factory('FileUploadService', ['$q', 'Upload', function FileUploadFactory($q, Upload) {
'use strict';
function uploadFile(url, file) {
var deferred = $q.defer();
Upload.upload({
url: url,
data: { file: file }
}).then(function success(data) {
deferred.resolve(data);
}, function error(e) {
deferred.reject(e);
}, function progress(evt) {
});
return deferred.promise;
}
return {
uploadTLSFilesForEndpoint: function(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile) {
var deferred = $q.defer();
var queue = [];
if (TLSCAFile !== null) {
var uploadTLSCA = uploadFile('api/upload/tls/' + endpointID + '/ca', TLSCAFile);
queue.push(uploadTLSCA);
}
if (TLSCertFile !== null) {
var uploadTLSCert = uploadFile('api/upload/tls/' + endpointID + '/cert', TLSCertFile);
queue.push(uploadTLSCert);
}
if (TLSKeyFile !== null) {
var uploadTLSKey = uploadFile('api/upload/tls/' + endpointID + '/key', TLSKeyFile);
queue.push(uploadTLSKey);
}
$q.all(queue).then(function (data) {
deferred.resolve(data);
}, function (err) {
deferred.reject(err);
}, function update(evt) {
deferred.notify(evt);
});
return deferred.promise;
}
};
}])
.factory('Endpoints', ['$resource', 'ENDPOINTS_ENDPOINT', function EndpointsFactory($resource, ENDPOINTS_ENDPOINT) {
'use strict';
return $resource(ENDPOINTS_ENDPOINT + '/:id/:action', {}, {
create: { method: 'POST' },
query: { method: 'GET', isArray: true },
get: { method: 'GET', params: { id: '@id' } },
update: { method: 'PUT', params: { id: '@id' } },
remove: { method: 'DELETE', params: { id: '@id'} },
getActiveEndpoint: { method: 'GET', params: { id: '0' } },
setActiveEndpoint: { method: 'POST', params: { id: '@id', action: 'active' } }
});
}])
.factory('EndpointService', ['$q', '$timeout', 'Endpoints', 'FileUploadService', function EndpointServiceFactory($q, $timeout, Endpoints, FileUploadService) {
'use strict';
return {
getActive: function() {
return Endpoints.getActiveEndpoint().$promise;
},
setActive: function(endpointID) {
return Endpoints.setActiveEndpoint({id: endpointID}).$promise;
},
endpoint: function(endpointID) {
return Endpoints.get({id: endpointID}).$promise;
},
endpoints: function() {
return Endpoints.query({}).$promise;
},
updateEndpoint: function(ID, name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile) {
var endpoint = {
id: ID,
Name: name,
URL: "tcp://" + URL,
TLS: TLS
};
var deferred = $q.defer();
Endpoints.update({}, endpoint, function success(data) {
FileUploadService.uploadTLSFilesForEndpoint(ID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
deferred.notify({upload: false});
deferred.resolve(data);
}, function error(err) {
deferred.notify({upload: false});
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
});
}, function error(err) {
deferred.reject({msg: 'Unable to update endpoint', err: err});
});
return deferred.promise;
},
deleteEndpoint: function(endpointID) {
return Endpoints.remove({id: endpointID}).$promise;
},
createLocalEndpoint: function(name, URL, TLS, active) {
var endpoint = {
Name: "local",
URL: "unix:///var/run/docker.sock",
TLS: false
};
return Endpoints.create({active: active}, endpoint).$promise;
},
createRemoteEndpoint: function(name, URL, TLS, TLSCAFile, TLSCertFile, TLSKeyFile, active) {
var endpoint = {
Name: name,
URL: 'tcp://' + URL,
TLS: TLS
};
var deferred = $q.defer();
Endpoints.create({active: active}, endpoint, function success(data) {
var endpointID = data.Id;
if (TLS) {
deferred.notify({upload: true});
FileUploadService.uploadTLSFilesForEndpoint(endpointID, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
deferred.notify({upload: false});
if (active) {
Endpoints.setActiveEndpoint({}, {id: endpointID}, function success(data) {
deferred.resolve(data);
}, function error(err) {
deferred.reject({msg: 'Unable to create endpoint', err: err});
});
} else {
deferred.resolve(data);
}
}, function error(err) {
deferred.notify({upload: false});
deferred.reject({msg: 'Unable to upload TLS certs', err: err});
});
} else {
deferred.resolve(data);
}
}, function error(err) {
deferred.reject({msg: 'Unable to create endpoint', err: err});
});
return deferred.promise;
}
};
}])
.factory('Messages', ['$rootScope', '$sanitize', function MessagesFactory($rootScope, $sanitize) {
'use strict';
return {