feat(endpoints): UX enhancements (#1943)

* feat(endpoints): add details about endpoints in datatable

* feat(endpoint-details): add the ability to inspect/update azure endpoint

* feat(endpoint-selector): disable placeholder selection
pull/1944/head
Anthony Lapenna 7 years ago committed by GitHub
parent bfc49574b7
commit 9bb885629a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -68,13 +68,16 @@ type (
}
putEndpointsRequest struct {
Name string `valid:"-"`
URL string `valid:"-"`
PublicURL string `valid:"-"`
GroupID int `valid:"-"`
TLS bool `valid:"-"`
TLSSkipVerify bool `valid:"-"`
TLSSkipClientVerify bool `valid:"-"`
Name string `valid:"-"`
URL string `valid:"-"`
PublicURL string `valid:"-"`
GroupID int `valid:"-"`
TLS bool `valid:"-"`
TLSSkipVerify bool `valid:"-"`
TLSSkipClientVerify bool `valid:"-"`
AzureApplicationID string `valid:"-"`
AzureTenantID string `valid:"-"`
AzureAuthenticationKey string `valid:"-"`
}
postEndpointPayload struct {
@ -143,7 +146,7 @@ func (handler *EndpointHandler) createAzureEndpoint(payload *postEndpointPayload
endpoint := &portainer.Endpoint{
Name: payload.name,
URL: payload.url,
URL: proxy.AzureAPIBaseURL,
Type: portainer.AzureEnvironment,
GroupID: portainer.EndpointGroupID(payload.groupID),
PublicURL: payload.publicURL,
@ -405,8 +408,6 @@ func (handler *EndpointHandler) handleGetEndpoint(w http.ResponseWriter, r *http
return
}
endpoint.AzureCredentials = portainer.AzureCredentials{}
encodeJSON(w, endpoint, handler.Logger)
}
@ -518,6 +519,18 @@ func (handler *EndpointHandler) handlePutEndpoint(w http.ResponseWriter, r *http
endpoint.GroupID = portainer.EndpointGroupID(req.GroupID)
}
if endpoint.Type == portainer.AzureEnvironment {
if req.AzureApplicationID != "" {
endpoint.AzureCredentials.ApplicationID = req.AzureApplicationID
}
if req.AzureTenantID != "" {
endpoint.AzureCredentials.TenantID = req.AzureTenantID
}
if req.AzureAuthenticationKey != "" {
endpoint.AzureCredentials.AuthenticationKey = req.AzureAuthenticationKey
}
}
folder := strconv.Itoa(int(endpoint.ID))
if req.TLS {
endpoint.TLSConfig.TLS = true

@ -10,7 +10,8 @@ import (
"github.com/portainer/portainer/crypto"
)
const azureAPIBaseURL = "https://management.azure.com"
// AzureAPIBaseURL is the URL where Azure API requests will be proxied.
const AzureAPIBaseURL = "https://management.azure.com"
// proxyFactory is a factory to create reverse proxies to Docker endpoints
type proxyFactory struct {
@ -28,7 +29,7 @@ func (factory *proxyFactory) newHTTPProxy(u *url.URL) http.Handler {
}
func newAzureProxy(credentials *portainer.AzureCredentials) (http.Handler, error) {
url, err := url.Parse(azureAPIBaseURL)
url, err := url.Parse(AzureAPIBaseURL)
if err != nil {
return nil, err
}

@ -0,0 +1,8 @@
angular.module('portainer.azure').component('azureEndpointConfig', {
bindings: {
applicationId: '=',
tenantId: '=',
authenticationKey: '='
},
templateUrl: 'app/azure/components/azure-endpoint-config/azureEndpointConfig.html'
});

@ -0,0 +1,29 @@
<div>
<div class="col-sm-12 form-section-title">
Azure configuration
</div>
<!-- applicationId-input -->
<div class="form-group">
<label for="azure_credential_appid" class="col-sm-3 col-lg-2 control-label text-left">Application ID</label>
<div class="col-sm-9 col-lg-10">
<input type="text" class="form-control" name="azure_credential_appid" ng-model="$ctrl.applicationId" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" required>
</div>
</div>
<!-- !applicationId-input -->
<!-- tenantId-input -->
<div class="form-group">
<label for="azure_credential_tenantid" class="col-sm-3 col-lg-2 control-label text-left">Tenant ID</label>
<div class="col-sm-9 col-lg-10">
<input type="text" class="form-control" name="azure_credential_tenantid" ng-model="$ctrl.tenantId" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" required>
</div>
</div>
<!-- !tenantId-input -->
<!-- authenticationkey-input -->
<div class="form-group">
<label for="azure_credential_authkey" class="col-sm-3 col-lg-2 control-label text-left">Authentication key</label>
<div class="col-sm-9 col-lg-10">
<input type="text" class="form-control" name="azure_credential_authkey" ng-model="$ctrl.authenticationKey" placeholder="cOrXoK/1D35w8YQ8nH1/8ZGwzz45JIYD5jxHKXEQknk=" required>
</div>
</div>
<!-- !authenticationkey-input -->
</div>

@ -39,6 +39,13 @@
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Type')">
Type
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Type' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Type' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('URL')">
URL
@ -66,6 +73,12 @@
<a ui-sref="portainer.endpoints.endpoint({id: item.Id})" ng-if="$ctrl.endpointManagement">{{ item.Name }}</a>
<span ng-if="!$ctrl.endpointManagement">{{ item.Name }}</span>
</td>
<td>
<span>
<i ng-class="item.Type | endpointtypeicon" aria-hidden="true" style="margin-right: 2px;"></i>
{{ item.Type | endpointtypename }}
</span>
</td>
<td>{{ item.URL | stripprotocol }}</td>
<td>{{ item.GroupName }}</td>
<td>

@ -11,7 +11,7 @@
<li class="sidebar-title"><span>Group</span></li>
<li class="sidebar-title">
<select class="select-endpoint form-control" ng-options="group.Name for group in $ctrl.availableGroups" ng-model="$ctrl.state.selectedGroup" ng-change="$ctrl.selectGroup()">
<option value="">Select a group</option>
<option value="" disabled selected>Select a group</option>
</select>
</li>
</div>
@ -19,7 +19,7 @@
<li class="sidebar-title"><span>Endpoint</span></li>
<li class="sidebar-title">
<select class="select-endpoint form-control" ng-options="endpoint.Name for endpoint in $ctrl.availableEndpoints" ng-model="$ctrl.state.selectedEndpoint" ng-change="$ctrl.selectEndpoint($ctrl.state.selectedEndpoint)">
<option value="">Select an endpoint</option>
<option value="" disabled selected>Select an endpoint</option>
</select>
</li>
</div>

@ -102,6 +102,28 @@ angular.module('portainer.app')
return '';
};
})
.filter('endpointtypename', function () {
'use strict';
return function (type) {
if (type === 1) {
return 'Docker';
} else if (type === 2) {
return 'Agent';
} else if (type === 3) {
return 'Azure ACI';
}
return '';
};
})
.filter('endpointtypeicon', function () {
'use strict';
return function (type) {
if (type === 3) {
return 'fab fa-microsoft';
}
return 'fab fa-docker';
};
})
.filter('ownershipicon', function () {
'use strict';
return function (ownership) {

@ -33,25 +33,12 @@ function EndpointServiceFactory($q, Endpoints, FileUploadService) {
return Endpoints.updateAccess({id: id}, {authorizedUsers: authorizedUserIDs, authorizedTeams: authorizedTeamIDs}).$promise;
};
service.updateEndpoint = function(id, endpointParams) {
var query = {
name: endpointParams.name,
PublicURL: endpointParams.PublicURL,
GroupId: endpointParams.GroupId,
TLS: endpointParams.TLS,
TLSSkipVerify: endpointParams.TLSSkipVerify,
TLSSkipClientVerify: endpointParams.TLSSkipClientVerify,
authorizedUsers: endpointParams.authorizedUsers
};
if (endpointParams.type && endpointParams.URL) {
query.URL = endpointParams.type === 'local' ? ('unix://' + endpointParams.URL) : ('tcp://' + endpointParams.URL);
}
service.updateEndpoint = function(id, payload) {
var deferred = $q.defer();
FileUploadService.uploadTLSFilesForEndpoint(id, endpointParams.TLSCACert, endpointParams.TLSCert, endpointParams.TLSKey)
FileUploadService.uploadTLSFilesForEndpoint(id, payload.TLSCACert, payload.TLSCert, payload.TLSKey)
.then(function success() {
deferred.notify({upload: false});
return Endpoints.update({id: id}, query).$promise;
return Endpoints.update({id: id}, payload).$promise;
})
.then(function success(data) {
deferred.resolve(data);

@ -28,12 +28,12 @@
<portainer-tooltip position="bottom" message="URL or IP address of a Docker host. The Docker API must be exposed over a TCP port. Please refer to the Docker documentation to configure it."></portainer-tooltip>
</label>
<div class="col-sm-9 col-lg-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">
<input ng-disabled="endpointType === 'local' || endpoint.Type === 3" 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 -->
<!-- endpoint-public-url-input -->
<div class="form-group">
<div class="form-group" ng-if="endpoint.Type !== 3">
<label for="endpoint_public_url" class="col-sm-3 col-lg-2 control-label text-left">
Public IP
<portainer-tooltip position="bottom" message="URL or IP address where exposed containers will be reachable. This field is optional and will default to the endpoint URL."></portainer-tooltip>
@ -42,6 +42,11 @@
<input type="text" class="form-control" id="endpoint_public_url" ng-model="endpoint.PublicURL" placeholder="e.g. 10.0.0.10 or mydocker.mydomain.com">
</div>
</div>
<azure-endpoint-config ng-if="endpoint.Type === 3"
application-id="endpoint.AzureCredentials.ApplicationID"
tenant-id="endpoint.AzureCredentials.TenantID"
authentication-key="endpoint.AzureCredentials.AuthenticationKey"
></azure-endpoint-config>
<!-- !endpoint-public-url-input -->
<div class="col-sm-12 form-section-title">
Grouping
@ -57,7 +62,7 @@
</div>
<!-- !group -->
<!-- endpoint-security -->
<div ng-if="endpointType === 'remote'">
<div ng-if="endpointType === 'remote' && endpoint.Type !== 3">
<div class="col-sm-12 form-section-title">
Security
</div>

@ -23,22 +23,27 @@ function ($q, $scope, $state, $transition$, $filter, EndpointService, GroupServi
var TLSSkipVerify = TLS && (TLSMode === 'tls_client_noca' || TLSMode === 'tls_only');
var TLSSkipClientVerify = TLS && (TLSMode === 'tls_ca' || TLSMode === 'tls_only');
var endpointParams = {
name: endpoint.Name,
URL: endpoint.URL,
var payload = {
Name: endpoint.Name,
PublicURL: endpoint.PublicURL,
GroupId: endpoint.GroupId,
GroupID: endpoint.GroupId,
TLS: TLS,
TLSSkipVerify: TLSSkipVerify,
TLSSkipClientVerify: TLSSkipClientVerify,
TLSCACert: TLSSkipVerify || securityData.TLSCACert === endpoint.TLSConfig.TLSCACert ? null : securityData.TLSCACert,
TLSCert: TLSSkipClientVerify || securityData.TLSCert === endpoint.TLSConfig.TLSCert ? null : securityData.TLSCert,
TLSKey: TLSSkipClientVerify || securityData.TLSKey === endpoint.TLSConfig.TLSKey ? null : securityData.TLSKey,
type: $scope.endpointType
AzureApplicationID: endpoint.AzureCredentials.ApplicationID,
AzureTenantID: endpoint.AzureCredentials.TenantID,
AzureAuthenticationKey: endpoint.AzureCredentials.AuthenticationKey
};
if ($scope.endpointType !== 'local' && endpoint.Type !== 3) {
payload.URL = 'tcp://' + endpoint.URL;
}
$scope.state.actionInProgress = true;
EndpointService.updateEndpoint(endpoint.Id, endpointParams)
EndpointService.updateEndpoint(endpoint.Id, payload)
.then(function success(data) {
Notifications.success('Endpoint updated', $scope.endpoint.Name);
EndpointProvider.setEndpointPublicURL(endpoint.PublicURL);

Loading…
Cancel
Save