1668 lines
76 KiB
HTML
1668 lines
76 KiB
HTML
<div class="config-setup-tool-element">
|
|
<div class="cor-loader" ng-if="!config"></div>
|
|
<div ng-show="config && config['SUPER_USERS']">
|
|
<form id="configform" name="configform">
|
|
|
|
<!-- Custom SSL certificates -->
|
|
<div class="co-panel" id="custom-ssl">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-certificate"></i> Custom SSL Certificates
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="config-certificates-field"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Basic Configuration -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-gears"></i> Basic Configuration
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<table class="config-table">
|
|
<tr>
|
|
<td>Enterprise Logo URL:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.ENTERPRISE_LOGO_URL"
|
|
placeholder="http://example.com/logo.png"></span>
|
|
<div class="help-text">
|
|
Enter the full URL to your company's logo.
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<img class="registry-logo-preview" ng-src="{{ config.ENTERPRISE_LOGO_URL }}">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">Contact Information:</td>
|
|
<td colspan="2">
|
|
<span class="config-contacts-field" binding="config.CONTACT_INFO"></span>
|
|
<div class="help-text" style="margin-top: 10px;">
|
|
Information to show in the Contact Page. If none specified, CoreOS contact information
|
|
is displayed.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Server Configuration -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-cloud"></i> Server Configuration
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<table class="config-table">
|
|
<tr>
|
|
<td>Server Hostname:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.SERVER_HOSTNAME"
|
|
placeholder="Hostname (and optional port if non-standard)"
|
|
pattern="{{ HOSTNAME_REGEX }}"></span>
|
|
<div class="help-text">
|
|
The HTTP host (and optionally the port number if a non-standard HTTP/HTTPS port) of the location
|
|
where the registry will be accessible on the network
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>TLS:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="mapped.TLS_SETTING">
|
|
<option value="internal-tls">Quay Enterprise handles TLS</option>
|
|
<option value="external-tls">My own load balancer handles TLS (Not Recommended)</option>
|
|
<option value="none">None (Not For Production)</option>
|
|
</select>
|
|
|
|
<div class="co-alert co-alert-danger" ng-if="mapped.TLS_SETTING == 'none'" style="margin-bottom: 20px">
|
|
Running without TLS should not be used for production workloads!
|
|
</div>
|
|
|
|
<div class="co-alert co-alert-warning" ng-if="mapped.TLS_SETTING == 'external-tls'" style="margin-bottom: 20px">
|
|
Terminating TLS outside of Quay Enterprise can result in unusual behavior if the external load balancer is not
|
|
configured properly. <strong>This option is not recommended for simple setups</strong>. Please contact support
|
|
if you encounter problems while using this option.
|
|
</div>
|
|
|
|
<div class="co-alert co-alert-info" ng-if="mapped.TLS_SETTING == 'internal-tls'" style="margin-bottom: 20px">
|
|
Enabling TLS also enables <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HTTP Strict Transport Security</a>.<br/>
|
|
This prevents downgrade attacks and cookie theft, but browsers will reject all future insecure connections on this hostname.
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="mapped.TLS_SETTING == 'internal-tls'">
|
|
<tr>
|
|
<td class="non-input">Certificate:</td>
|
|
<td>
|
|
<span class="config-file-field" filename="ssl.cert" has-file="hasfile.SSLCert"></span>
|
|
<div class="help-text">
|
|
The certificate must be in PEM format.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">Private key:</td>
|
|
<td>
|
|
<span class="config-file-field" filename="ssl.key" has-file="hasfile.SSLKey"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Consistency Settings -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa ci-shared-database"></i> Data Consistency Settings
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>Relax constraints on consistency guarantees for specific operations
|
|
to enable higher performance and availability.
|
|
</p>
|
|
</div>
|
|
<table class="config-table">
|
|
<tr>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.ALLOW_PULLS_WITHOUT_STRICT_LOGGING">
|
|
Allow repository pulls even if audit logging fails.
|
|
<div class="help-text">
|
|
If enabled, failures to write to the audit log will fallback from
|
|
the database to the standard logger for registry pulls.
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /Consistency Settings -->
|
|
|
|
<!-- Time Machine -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-history"></i> Time Machine
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>Time machine keeps older copies of tags within a repository for the configured period
|
|
of time, after which they are garbage collected. This allows users to
|
|
revert tags to older images in case they accidentally pushed a broken image. It is
|
|
highly recommended to have time machine enabled, but it does take a bit more space
|
|
in storage.
|
|
</p>
|
|
</div>
|
|
<table class="config-table">
|
|
<!-- This `ng-if` true is *required* to create a new scope so that the <form> inside
|
|
the config-list-field doesn't try to submit the *outer* form when the Add button
|
|
is clicked. This is highly stupid, but until we figure out a better way, such it
|
|
shall be.
|
|
-->
|
|
<tr ng-if="true">
|
|
<td>Allowed expiration periods:</td>
|
|
<td>
|
|
<span class="config-list-field" item-title="Tag Expiration Period" binding="config.TAG_EXPIRATION_OPTIONS" item-pattern="[0-9]+(m|w|h|d|s)"></span>
|
|
<div class="help-text">
|
|
The expiration periods allowed for configuration. The default tag expiration *must* be in this list.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Default expiration period:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.DEFAULT_TAG_EXPIRATION"
|
|
pattern="[0-9]+(m|w|h|d|s)"></span>
|
|
<div class="help-text">
|
|
The default tag expiration period for all namespaces (users and organizations). Must be expressed in a duration string form: <code>30m</code>, <code>1h</code>, <code>1d</code>, <code>2w</code>.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Allow users to select expiration:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.FEATURE_CHANGE_TAG_EXPIRATION">
|
|
Enable Expiration Configuration
|
|
<div class="help-text">
|
|
If enabled, users will be able to select the tag expiration duration for the namespace(s) they
|
|
administrate, from the configured list of options.
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /Time Machine -->
|
|
|
|
<!-- Redis -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<img src="/static/img/redis-small.png"> redis
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>A <a href="http://redis.io" ng-safenewtab>redis</a> key-value store is required for real-time events and build logs.</p>
|
|
</div>
|
|
|
|
<table class="config-table">
|
|
<tr>
|
|
<td>Redis Hostname:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="mapped.redis.host"
|
|
placeholder="The redis server hostname"
|
|
pattern="{{ HOSTNAME_REGEX }}"
|
|
validator="validateHostname(value)"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Redis port:</td>
|
|
<td>
|
|
<span class="config-numeric-field" binding="mapped.redis.port" default-value="6379"></span>
|
|
<div class="help-text">
|
|
Access to this port and hostname must be allowed from all hosts running
|
|
the enterprise registry
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Redis password:</td>
|
|
<td>
|
|
<input class="form-control" type="password" ng-model="mapped.redis.password"
|
|
placeholder="Optional password for connecting to redis">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /Redis -->
|
|
|
|
<!-- Registry Storage -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-download"></i> Registry Storage
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
Registry images can be stored either locally or in a remote storage system.
|
|
<strong>A remote storage system is required for high-availability systems.</strong>
|
|
</p>
|
|
|
|
<div class="config-bool-field feature-storage-replication" binding="config.FEATURE_STORAGE_REPLICATION">
|
|
Enable Storage Replication
|
|
<div class="help-text">
|
|
If enabled, replicates storage to other regions. See <a href="https://tectonic.com/quay-enterprise/docs/latest/geo-replication.html" ng-safenewtab>documentation</a> for more information.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="storage-config" ng-class="$last ? 'last' : ''" ng-repeat="sc in storageConfig">
|
|
<table class="config-table">
|
|
<tr>
|
|
<td class="non-input">Location ID:</td>
|
|
<td>
|
|
<input class="form-control" ng-if="allowChangeLocationStorageConfig(sc.location)" ng-class="storageConfigError[$index].location ? 'ng-invalid' : ''" ng-model="sc.location" ng-pattern="/^[a-zA-Z0-9_-]+$/" required>
|
|
<div ng-if="!allowChangeLocationStorageConfig(sc.location)">
|
|
{{ sc.location }}
|
|
</div>
|
|
<div class="co-alert co-alert-danger" ng-show="storageConfigError[$index].location">
|
|
{{ storageConfigError[$index].location }}
|
|
</div>
|
|
<div class="input-util" ng-if="allowRemoveStorageConfig(sc.location)"><a class="remove-link" ng-click="removeStorageConfig(sc)">Remove</a></div>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr ng-if="config.FEATURE_STORAGE_REPLICATION">
|
|
<td class="non-input">Set Default:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="sc.defaultLocation">
|
|
Replicate to storage engine by default
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="non-input">Storage Engine:</td>
|
|
<td>
|
|
<select class="form-control" ng-class="storageConfigError[$index].engine ? 'ng-invalid' : ''" ng-model="sc.data[0]">
|
|
<option value="LocalStorage">Locally mounted directory</option>
|
|
<option value="S3Storage">Amazon S3</option>
|
|
<option value="AzureStorage">Azure Blob Storage</option>
|
|
<option value="GoogleCloudStorage">Google Cloud Storage</option>
|
|
<option value="RadosGWStorage">Ceph Object Gateway (RADOS)</option>
|
|
<option value="SwiftStorage">OpenStack Storage (Swift)</option>
|
|
<option value="CloudFrontedS3Storage">CloudFront + Amazon S3</option>
|
|
</select>
|
|
|
|
<div class="co-alert co-alert-danger" ng-if="storageConfigError[$index].engine">
|
|
{{ storageConfigError[$index].engine }}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Fields -->
|
|
<tr ng-repeat="field in STORAGE_CONFIG_FIELDS[sc.data[0]]">
|
|
<td>{{ field.title }}:</td>
|
|
<td>
|
|
<span class="config-map-field"
|
|
binding="sc.data[1][field.name]"
|
|
ng-if="field.kind == 'map'"
|
|
keys="field.keys"></span>
|
|
<span class="config-string-field"
|
|
binding="sc.data[1][field.name]"
|
|
placeholder="{{ field.placeholder }}"
|
|
pattern="{{ field.pattern }}"
|
|
ng-if="field.kind == 'text'"
|
|
is-optional="field.optional"></span>
|
|
<span class="config-bool-field"
|
|
binding="sc.data[1][field.name]"
|
|
ng-if="field.kind == 'bool'">
|
|
{{ field.placeholder }}
|
|
</span>
|
|
<span class="config-file-field"
|
|
filename="{{ sc.location + '-' + field.filesuffix }}"
|
|
binding="sc.data[1][field.name]"
|
|
has-file="hasfile['contact-' + sc.location + '-' + field.filesuffix]"
|
|
ng-if="field.kind == 'file'"></span>
|
|
<div ng-if="field.kind == 'option'">
|
|
<select class="form-control" ng-model="sc.data[1][field.name]">
|
|
<option ng-repeat="value in field.values" value="{{ value }}"
|
|
ng-selected="sc.data[1][field.name] == value">{{ value }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="help-text" ng-if="field.help_text">
|
|
{{ field.help_text }}
|
|
</div>
|
|
<div class="help-text" ng-if="field.help_url">
|
|
See <a href="{{ field.help_url }}" ng-safenewtab>Documentation</a> for more information
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="add-storage-link" ng-if="canAddStorageConfig()">
|
|
<a ng-click="addStorageConfig()">Add Additional Storage Engine</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action log archiving -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-archive"></i> Action Log Rotation and Archiving
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
All actions performed in <span class="registry-name"></span> are automatically logged. These logs are stored in a database table, which can become quite large.
|
|
Enabling log rotation and archiving will move all logs older than 30 days into storage.
|
|
</p>
|
|
</div>
|
|
<div class="config-bool-field" binding="config.FEATURE_ACTION_LOG_ROTATION">
|
|
Enable Action Log Rotation
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_ACTION_LOG_ROTATION">
|
|
<tr>
|
|
<td>Storage location:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="config.ACTION_LOG_ARCHIVE_LOCATION">
|
|
<option ng-repeat="sc in storageConfig" value="{{ sc['location'] }}">{{ sc['location'] }}</option>
|
|
</select>
|
|
<div class="help-text">
|
|
The storage location in which to place archived action logs. Logs will only be archived to this single location.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Storage path:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.ACTION_LOG_ARCHIVE_PATH"
|
|
placeholder="Path under storage to place archived logs"></span>
|
|
<div class="help-text">
|
|
The path under the configured storage engine in which to place the archived logs in JSON form.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Security Scanner -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-bug"></i> Security Scanner
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>If enabled, all images pushed to Quay will be scanned via the external security scanning service, with vulnerability information available in the UI and API, as well
|
|
as async notification support.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_SECURITY_SCANNER">
|
|
Enable Security Scanning
|
|
</div>
|
|
<div class="co-alert co-alert-info" ng-if="config.FEATURE_SECURITY_SCANNER" style="margin-top: 20px;">
|
|
A scanner compliant with the Quay Security Scanning API must be running to use this feature. Documentation on running <a href="https://github.com/coreos/clair" ng-safenewtab>Clair</a> can be found at <a href="https://tectonic.com/quay-enterprise/docs/latest/clair.html" ng-safenewtab>Running Clair Security Scanner</a>.
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_SECURITY_SCANNER">
|
|
<tr>
|
|
<td>Authentication Key:</td>
|
|
<td>
|
|
<span class="config-service-key-field" service-name="{{ config.SECURITY_SCANNER_ISSUER_NAME || 'secscan' }}"></span>
|
|
<div class="help-text">
|
|
The security scanning service requires an authorized service key to speak to Quay. Once setup, the key
|
|
can be managed in the Service Keys panel under the Super User Admin Panel.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Security Scanner Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.SECURITY_SCANNER_ENDPOINT"
|
|
placeholder="Security Scanner API endpoint (Example: http://myhost:6060)"
|
|
pattern="http(s)?://.+"></span>
|
|
<div class="help-text">
|
|
The HTTP URL at which the security scanner is running.
|
|
</div>
|
|
<div class="co-alert co-alert-info" ng-if="config.SECURITY_SCANNER_ENDPOINT.indexOf('https:') == 0" style="margin-top: 20px;">
|
|
Is the security scanner behind a domain signed with a <strong>self-signed TLS certificate</strong>? If so, please make sure to register your SSL CA in the <a href="#custom-ssl">custom certificates panel</a> above.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- App Registry -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa ci-appcube"></i> Application Registry
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>If enabled, an additional registry API will be available for managing applications (Kubernetes manifests, Helm charts) via the <a href="https://github.com/app-registry">App Registry specification</a>. A great place to get started is to install the <a href="https://github.com/app-registry/appr-helm-plugin">Helm Registry Plugin</a>.
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_APP_REGISTRY">
|
|
Enable App Registry
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- BitTorrent pull -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-cloud-download"></i> BitTorrent-based download
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>If enabled, all images in the registry can be downloaded using the <a href="http://github.com/coreos/quayctl" ng-safenewtab>quayctl</a> tool via the BitTorrent protocol. A JWT-compatible BitTorrent tracker such as <a href="https://tectonic.com/quay-enterprise/docs/latest/running-chihaya.html">Chihaya</a> must be run.
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_BITTORRENT">
|
|
Enable BitTorrent downloads
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_BITTORRENT">
|
|
<tr>
|
|
<td>Announce URL:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.BITTORRENT_ANNOUNCE_URL"
|
|
placeholder="Announce URL for the torrent tracker (Example: http://mytracker/announce)"
|
|
pattern="http(s)?://.+"></span>
|
|
<div class="help-text">
|
|
The HTTP URL at which the torrents should be announced. A JWT-compatible tracker such as <a href="https://github.com/chihaya/chihaya" ng-safenewtab>Chihaya</a> must be run to ensure proper security. Documentation on running Chihaya with
|
|
this support can be found at <a href="https://tectonic.com/quay-enterprise/docs/latest/running-chihaya.html">Running Chihaya for Quay Enterprise</a>.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ACI Conversion -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa rocket-icon" style="width: 20px; height: 20px; background-size: cover; vertical-align: middle;"></i> <a href="http://github.com/coreos/rkt" ng-safenewtab>rkt</a> Conversion
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>If enabled, all images in the registry can be fetched via <code>rkt fetch</code> or any other <a href="https://github.com/appc/spec/blob/master/spec/discovery.md" ng-safenewtab>AppC discovery</a>-compliant implementation.</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_ACI_CONVERSION">
|
|
Enable ACI Conversion
|
|
</div>
|
|
|
|
<div class="co-alert co-alert-info" ng-if="config.FEATURE_ACI_CONVERSION" style="margin-top: 20px;">
|
|
Documentation on generating these keys can be found at <a href="https://tectonic.com/quay-enterprise/docs/latest/aci-signing-keys.html" ng-safenewtab>Generating ACI Signing Keys</a>.
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_ACI_CONVERSION">
|
|
<tr>
|
|
<td class="non-input">GPG2 Public Key File:</td>
|
|
<td>
|
|
<span class="config-file-field" filename="signing-public.gpg" has-file="hasfile.gpgSigningPublic"></span>
|
|
<div class="help-text">
|
|
The certificate must be in PEM format.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">GPG2 Private Key File:</td>
|
|
<td>
|
|
<span class="config-file-field" filename="signing-private.gpg" has-file="hasfile.gpgSigningPrivate"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">GPG2 Private Key Name:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GPG2_PRIVATE_KEY_NAME"
|
|
placeholder="Name of the private key in the private key file (Example: EAB32227)"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- E-mail -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-envelope"></i> E-mail
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>Valid e-mail server configuration is required for notification e-mails and the ability of
|
|
users to reset their passwords.</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_MAILING">
|
|
Enable E-mails
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_MAILING">
|
|
<tr>
|
|
<td>SMTP Server:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.MAIL_SERVER"
|
|
placeholder="SMTP server for sending e-mail"
|
|
pattern="{{ HOSTNAME_REGEX }}"
|
|
validator="validateHostname(value)">></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>SMTP Server Port:</td>
|
|
<td>
|
|
<span class="config-numeric-field" binding="config.MAIL_PORT"
|
|
default-value="587"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>TLS:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.MAIL_USE_TLS">
|
|
Require TLS
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Mail Sender:</td>
|
|
<td>
|
|
<input class="form-control" type="email" ng-model="config.MAIL_DEFAULT_SENDER"
|
|
placeholder="E-mail address"></span>
|
|
<div class="help-text">
|
|
E-mail address from which all e-mails are sent. If not specified,
|
|
<code>support@quay.io</code> will be used.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Authentication:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.MAIL_USE_AUTH">
|
|
Requires Authentication
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.MAIL_USE_AUTH">
|
|
<tr>
|
|
<td>Username:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.MAIL_USERNAME"
|
|
placeholder="Username for authentication"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Password:</td>
|
|
<td>
|
|
<input class="form-control" type="password"
|
|
ng-model="config.MAIL_PASSWORD"
|
|
placeholder="Password for authentication"></span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
</div>
|
|
</div> <!-- /E-mail -->
|
|
|
|
<!-- Internal Authentication -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-users"></i> Internal Authentication
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
Authentication for the registry can be handled by either the registry itself, LDAP, Keystone, or external JWT endpoint.
|
|
</p>
|
|
<p>
|
|
Additional <strong>external</strong> authentication providers (such as GitHub) can be used in addition for <strong>login into the UI</strong>.
|
|
</p>
|
|
</div>
|
|
|
|
<div ng-if="config.AUTHENTICATION_TYPE != 'AppToken'">
|
|
<div class="co-alert co-alert-warning" ng-if="config.AUTHENTICATION_TYPE != 'Database' && !config.FEATURE_REQUIRE_ENCRYPTED_BASIC_AUTH">
|
|
It is <strong>highly recommended</strong> to require encrypted client passwords. External passwords used in the Docker client will be stored in <strong>plaintext</strong>!
|
|
<a ng-click="config.FEATURE_REQUIRE_ENCRYPTED_BASIC_AUTH = true">Enable this requirement now</a>.
|
|
</div>
|
|
|
|
<div class="co-alert co-alert-success" ng-if="config.AUTHENTICATION_TYPE != 'Database' && config.FEATURE_REQUIRE_ENCRYPTED_BASIC_AUTH">
|
|
Note: The "Require Encrypted Client Passwords" feature is currently enabled which will
|
|
prevent passwords from being saved as plaintext by the Docker client.
|
|
</div>
|
|
</div>
|
|
|
|
<table class="config-table" style="margin-bottom: 20px;">
|
|
<tr>
|
|
<td class="non-input">Authentication:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="config.AUTHENTICATION_TYPE">
|
|
<option value="Database">Local Database</option>
|
|
<option value="LDAP">LDAP</option>
|
|
<option value="Keystone">Keystone (OpenStack Identity)</option>
|
|
<option value="JWT">JWT Custom Authentication</option>
|
|
<option value="AppToken" ng-if="config.FEATURE_APP_SPECIFIC_TOKENS">External Application Token</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr ng-if="config.AUTHENTICATION_TYPE == 'LDAP' || config.AUTHENTICATION_TYPE == 'Keystone'">
|
|
<td>Team synchronization:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.FEATURE_TEAM_SYNCING">
|
|
Enable Team Synchronization Support
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, organization administrators who are also superusers can set teams to have their membership synchronized with a backing group in {{ config.AUTHENTICATION_TYPE }}.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="(config.AUTHENTICATION_TYPE == 'LDAP' || config.AUTHENTICATION_TYPE == 'Keystone') && config.FEATURE_TEAM_SYNCING">
|
|
<td>Resynchronization duration:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.TEAM_RESYNC_STALE_TIME"
|
|
pattern="[0-9]+(m|h|d|s)"></span>
|
|
<div class="help-text">
|
|
The duration before a team must be re-synchronized. Must be expressed in a duration string form: <code>30m</code>, <code>1h</code>, <code>1d</code>.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="(config.AUTHENTICATION_TYPE == 'LDAP' || config.AUTHENTICATION_TYPE == 'Keystone') && config.FEATURE_TEAM_SYNCING">
|
|
<td>Self-service team syncing setup:</td>
|
|
<td>
|
|
<div class="co-alert co-alert-warning" style="margin-bottom: 20px;">If enabled, this feature will allow *any organization administrator* to read the membership of any {{ config.AUTHENTICATION_TYPE }} group.</div>
|
|
<div class="config-bool-field" binding="config.FEATURE_NONSUPERUSER_TEAM_SYNCING_SETUP">
|
|
Allow non-superusers to enable and manage team syncing
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, non-superusers will be able to enable and manage team sycning on teams under organizations in which they are administrators.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- Keystone Authentication -->
|
|
<table class="config-table" ng-if="config.AUTHENTICATION_TYPE == 'Keystone'">
|
|
<tr>
|
|
<td>Keystone API Version:</td>
|
|
<td>
|
|
<select ng-model="config.KEYSTONE_AUTH_VERSION">
|
|
<option value="2">2.0</option>
|
|
<option value="3">V3</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Keystone Authentication URL:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.KEYSTONE_AUTH_URL"
|
|
pattern="http(s)?://.+"></span>
|
|
<div class="help-text">
|
|
The URL (starting with http or https) of the Keystone Server endpoint for auth.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Keystone Administrator Username:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.KEYSTONE_ADMIN_USERNAME"></span>
|
|
<div class="help-text">
|
|
The username for the Keystone admin.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Keystone Administrator Password:</td>
|
|
<td>
|
|
<input type="password" ng-model="config.KEYSTONE_ADMIN_PASSWORD"
|
|
class="form-control" required></span>
|
|
<div class="help-text">
|
|
The password for the Keystone admin.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Keystone Administrator Tenant:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.KEYSTONE_ADMIN_TENANT"></span>
|
|
<div class="help-text">
|
|
The tenant (project/group) that contains the administrator user.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- JWT Custom Authentication -->
|
|
<div class="co-alert co-alert-info" ng-if="config.AUTHENTICATION_TYPE == 'JWT'">
|
|
JSON Web Token authentication allows your organization to provide an HTTP endpoint that
|
|
verifies user credentials on behalf of <span class="registry-name"></span>.
|
|
<br>
|
|
Documentation
|
|
on the API required can be found here: <a href="https://github.com/coreos/jwt-auth-example" ng-safenewtab>https://github.com/coreos/jwt-auth-example</a>.
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.AUTHENTICATION_TYPE == 'JWT'">
|
|
<tr>
|
|
<td>Authentication Issuer:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.JWT_AUTH_ISSUER"></span>
|
|
<div class="help-text">
|
|
The id of the issuer signing the JWT token. Must be unique to your organization.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Public Key:</td>
|
|
<td>
|
|
<span class="config-file-field" filename="jwt-authn.cert" has-file="hasfile.JWTCert"></span>
|
|
<div class="help-text">
|
|
A certificate containing the public key portion of the key pair used to sign
|
|
the JSON Web Tokens. This file must be in PEM format.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>User Verification Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.JWT_VERIFY_ENDPOINT"
|
|
pattern="http(s)?://.+"></span>
|
|
<div class="help-text">
|
|
The URL (starting with http or https) on the JWT authentication server for verifying username and password credentials.
|
|
</div>
|
|
|
|
<div class="help-text" style="margin-top: 6px;">
|
|
Credentials will be sent in the <code>Authorization</code> header as Basic Auth, and this endpoint should return <code>200 OK</code> on success (or a <code>4**</code> otherwise).
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>User Query Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.JWT_QUERY_ENDPOINT"
|
|
pattern="http(s)?://.+" is-optional="true"></span>
|
|
<div class="help-text">
|
|
The URL (starting with http or https) on the JWT authentication server for looking up
|
|
users based on a prefix query. This is optional.
|
|
</div>
|
|
|
|
<div class="help-text" style="margin-top: 6px;">
|
|
The prefix query will be sent as a query parameter with name <code>query</code>.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>User Lookup Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.JWT_GETUSER_ENDPOINT"
|
|
pattern="http(s)?://.+" is-optional="true"></span>
|
|
<div class="help-text">
|
|
The URL (starting with http or https) on the JWT authentication server for looking up
|
|
a user by username or email address.
|
|
</div>
|
|
|
|
<div class="help-text" style="margin-top: 6px;">
|
|
The username or email address will be sent as a query parameter with name <code>username</code>.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- LDAP Authentication -->
|
|
<table class="config-table" ng-if="config.AUTHENTICATION_TYPE == 'LDAP'">
|
|
<tr>
|
|
<td>LDAP URI:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.LDAP_URI"
|
|
pattern="ldap(s)?://.+"></span>
|
|
<div class="help-text">
|
|
The full LDAP URI, including the ldap:// or ldaps:// prefix.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Base DN:</td>
|
|
<td>
|
|
<span class="config-string-list-field" item-title="DN piece" item-delimiter="," binding="config.LDAP_BASE_DN"></span>
|
|
<div class="help-text">
|
|
A Distinguished Name path which forms the base path for looking up all LDAP records.
|
|
</div>
|
|
<div class="help-text">
|
|
Example: dc=my,dc=domain,dc=com
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>User Relative DN:</td>
|
|
<td>
|
|
<span class="config-string-list-field" item-title="RDN piece" item-delimiter="," binding="config.LDAP_USER_RDN"></span>
|
|
<div class="help-text">
|
|
A Distinguished Name path which forms the base path for looking up all user LDAP records,
|
|
relative to the Base DN defined above.
|
|
</div>
|
|
<div class="help-text">
|
|
Example: ou=employees
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Secondary User Relative DNs:</td>
|
|
<td>
|
|
<span class="config-list-field" item-title="RDN" binding="config.LDAP_SECONDARY_USER_RDNS"></span>
|
|
<div class="help-text">
|
|
A list of Distinguished Name path(s) which forms the secondary base path(s) for
|
|
looking up all user LDAP records, relative to the Base DN defined above. These path(s)
|
|
will be tried if the user is not found via the primary relative DN.
|
|
</div>
|
|
<div class="help-text">
|
|
Example: [ou=employees]
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Administrator DN:</td>
|
|
<td><span class="config-string-field" binding="config.LDAP_ADMIN_DN"></span>
|
|
<div class="help-text">
|
|
The Distinguished Name for the Administrator account. This account must be able to login and view the records for all user accounts.
|
|
</div>
|
|
<div class="help-text">
|
|
Example: uid=admin,ou=employees,dc=my,dc=domain,dc=com
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Administrator DN Password:</td>
|
|
<td>
|
|
<div class="co-alert co-alert-warning" style="margin-bottom: 10px;">
|
|
Note: This will be stored in
|
|
<strong>plaintext</strong> inside the config.yaml, so setting up a dedicated account or using
|
|
<a href="http://tools.ietf.org/id/draft-stroeder-hashed-userpassword-values-01.html" ng-safenewtab>a password hash</a> is <strong>highly</strong> recommended.
|
|
</div>
|
|
<input class="form-control" type="password" ng-model="config.LDAP_ADMIN_PASSWD">
|
|
<div class="help-text">
|
|
The password for the Administrator DN.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>UID Attribute:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.LDAP_UID_ATTR" default-value="uid"></span>
|
|
<div class="help-text">
|
|
The name of the property field in your LDAP user records that stores your
|
|
users' username. Typically "uid".
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Mail Attribute:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.LDAP_EMAIL_ATTR" default-value="mail"></span>
|
|
<div class="help-text">
|
|
The name of the property field in your LDAP user records that stores your
|
|
users' e-mail address(es). Typically "mail".
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="config.LDAP_URI.indexOf('ldaps://') == 0">
|
|
<td class="non-input">Custom TLS Certificate:</td>
|
|
<td>
|
|
<span class="config-file-field" filename="ldap.crt" has-file="hasfile.LDAPTLSCert"></span>
|
|
<div class="help-text">
|
|
If specified, the certificate (in PEM format) for the LDAP TLS connection.
|
|
</div
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="config.LDAP_URI.indexOf('ldaps://') == 0">
|
|
<td class="non-input">Allow insecure:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.LDAP_ALLOW_INSECURE_FALLBACK">
|
|
Allow fallback to non-TLS connections
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, LDAP will fallback to <strong>insecure non-TLS connections</strong> if TLS does not succeed.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- / Internal Authentication -->
|
|
|
|
<div class="co-panel"> <!-- External Authentication -->
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-id-card"></i> External Authorization (OAuth)
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<!-- GitHub Authentication -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-github"></i> GitHub (Enterprise) Authentication
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
If enabled, users can use GitHub or GitHub Enterprise to authenticate to the registry.
|
|
</p>
|
|
<p>
|
|
<strong>Note:</strong> A registered GitHub (Enterprise) OAuth application is required.
|
|
View instructions on how to
|
|
<a href="https://coreos.com/docs/enterprise-registry/github-app/" ng-safenewtab>
|
|
Create an OAuth Application in GitHub
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_GITHUB_LOGIN">
|
|
Enable GitHub Authentication
|
|
</div>
|
|
|
|
<div class="co-alert co-alert-warning" ng-if="config.FEATURE_GITHUB_LOGIN && config.AUTHENTICATION_TYPE && config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken' && !config.GITHUB_LOGIN_CONFIG.LOGIN_BINDING_FIELD">
|
|
Warning: This provider is not bound to your <strong>{{ config.AUTHENTICATION_TYPE }}</strong> authentication. Logging in via this provider will create a <strong><span class="registry-name"></span>-only user</strong>, which is not the recommended approach. It is <strong>highly</strong> recommended to choose a "Binding Field" below.
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_GITHUB_LOGIN">
|
|
<tr>
|
|
<td>GitHub:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="mapped.GITHUB_LOGIN_KIND">
|
|
<option value="hosted">GitHub.com</option>
|
|
<option value="enterprise">GitHub Enterprise</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="mapped.GITHUB_LOGIN_KIND == 'enterprise'">
|
|
<td>GitHub Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field"
|
|
binding="config.GITHUB_LOGIN_CONFIG.GITHUB_ENDPOINT"
|
|
placeholder="https://my.githubserver"
|
|
pattern="{{ GITHOST_REGEX }}">
|
|
</span>
|
|
<div class="help-text">
|
|
The GitHub Enterprise endpoint. Must start with http:// or https://.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OAuth Client ID:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GITHUB_LOGIN_CONFIG.CLIENT_ID">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OAuth Client Secret:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GITHUB_LOGIN_CONFIG.CLIENT_SECRET">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Organization Filtering:</td>
|
|
<td>
|
|
<div class="config-bool-field" binding="config.GITHUB_LOGIN_CONFIG.ORG_RESTRICT">
|
|
Restrict By Organization Membership
|
|
</div>
|
|
|
|
<div class="help-text" style="margin-bottom: 20px;">
|
|
If enabled, only members of specified GitHub
|
|
<span ng-if="mapped.GITHUB_LOGIN_KIND == 'enterprise'">Enterprise</span> organizations will be allowed to login via GitHub
|
|
<span ng-if="mapped.GITHUB_LOGIN_KIND == 'enterprise'">Enterprise</span>.
|
|
</div>
|
|
|
|
<span class="config-list-field"
|
|
item-title="Organization ID"
|
|
binding="config.GITHUB_LOGIN_CONFIG.ALLOWED_ORGANIZATIONS"
|
|
ng-if="config.GITHUB_LOGIN_CONFIG.ORG_RESTRICT">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken'">
|
|
<td>Binding Field:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="config.GITHUB_LOGIN_CONFIG.LOGIN_BINDING_FIELD">
|
|
<option value="">(None)</option>
|
|
<option value="sub">Subject (User ID)</option>
|
|
<option value="username">Username</option>
|
|
<option value="email">E-mail address</option>
|
|
</select>
|
|
<div class="help-text">
|
|
If selected, when a user logs in via this provider, they will be automatically bound to their user in <strong>{{ config.AUTHENTICATION_TYPE }}</strong> by matching the selected field from the provider to the associated user in {{ config.AUTHENTICATION_TYPE }}.
|
|
</div>
|
|
<div class="help-text">
|
|
For example, selecting <code>Subject</code> here with a backing authentication system of LDAP means that a user logging in via this provider will also be bound to their user in LDAP by username.
|
|
</div>
|
|
<div class="help-text">
|
|
If none selected, a <strong>user unique to <span class="registry-name"></span></strong> will be created on initial login with this provider. <strong>This is not the recommended setup.</strong>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /GitHub Authentication -->
|
|
|
|
<!-- Google Authentication -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-google"></i> Google Authentication
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
If enabled, users can use Google to authenticate to the registry.
|
|
</p>
|
|
<p>
|
|
<strong>Note:</strong> A registered Google OAuth application is required.
|
|
Visit the
|
|
<a href="https://console.developers.google.com" ng-safenewtab>
|
|
Google Developer Console
|
|
</a>
|
|
to register an application.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_GOOGLE_LOGIN">
|
|
Enable Google Authentication
|
|
</div>
|
|
|
|
<div class="co-alert co-alert-warning" ng-if="config.FEATURE_GOOGLE_LOGIN && config.AUTHENTICATION_TYPE && config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken' && !config.GOOGLE_LOGIN_CONFIG.LOGIN_BINDING_FIELD">
|
|
Warning: This provider is not bound to your <strong>{{ config.AUTHENTICATION_TYPE }}</strong> authentication. Logging in via this provider will create a <strong><span class="registry-name"></span>-only user</strong>, which is not the recommended approach. It is <strong>highly</strong> recommended to choose a "Binding Field" below.
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_GOOGLE_LOGIN">
|
|
<tr>
|
|
<td>OAuth Client ID:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GOOGLE_LOGIN_CONFIG.CLIENT_ID">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OAuth Client Secret:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GOOGLE_LOGIN_CONFIG.CLIENT_SECRET">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken'">
|
|
<td>Binding Field:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="config.GOOGLE_LOGIN_CONFIG.LOGIN_BINDING_FIELD">
|
|
<option value="">(None)</option>
|
|
<option value="sub">Subject (User ID)</option>
|
|
<option value="username">Username</option>
|
|
<option value="email">E-mail address</option>
|
|
</select>
|
|
<div class="help-text">
|
|
If selected, when a user logs in via this provider, they will be automatically bound to their user in <strong>{{ config.AUTHENTICATION_TYPE }}</strong> by matching the selected field from the provider to the associated user in {{ config.AUTHENTICATION_TYPE }}.
|
|
</div>
|
|
<div class="help-text">
|
|
For example, selecting <code>Subject</code> here with a backing authentication system of LDAP means that a user logging in via this provider will also be bound to their user in LDAP by username.
|
|
</div>
|
|
<div class="help-text">
|
|
If none selected, a <strong>user unique to <span class="registry-name"></span></strong> will be created on initial login with this provider. <strong>This is not the recommended setup.</strong>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /Google Authentication -->
|
|
|
|
<!-- Custom OIDC providers -->
|
|
<div class="co-panel" ng-repeat="provider in getOIDCProviders(config)">
|
|
<div class="co-panel-heading">
|
|
<span class="icon-image-view" value="{{ config[provider]['SERVICE_ICON'] || 'fa-user-circle' }}" style="margin-right: 6px;"></span>
|
|
{{ config[provider]['SERVICE_NAME'] || (getOIDCProviderId(provider) + ' Authentication') }}
|
|
<span style="display: inline-block; margin-left: 10px">(<a href="javascript:void(0)" ng-click="removeOIDCProvider(provider)">Delete</a>)</span>
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="co-alert co-alert-warning" ng-if="config.AUTHENTICATION_TYPE && config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken' && !(config[provider].LOGIN_BINDING_FIELD)">
|
|
Warning: This OIDC provider is not bound to your <strong>{{ config.AUTHENTICATION_TYPE }}</strong> authentication. Logging in via this provider will create a <strong><span class="registry-name"></span>-only user</strong>, which is not the recommended approach. It is <strong>highly</strong> recommended to choose a "Binding Field" below.
|
|
</div>
|
|
|
|
<table class="config-table">
|
|
<tr>
|
|
<td class="non-input">Service ID:</td>
|
|
<td>
|
|
<code>{{ getOIDCProviderId(provider) }}</code>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OIDC Server:</td>
|
|
<td>
|
|
<span class="config-string-field"
|
|
binding="config[provider].OIDC_SERVER"
|
|
placeholder="https://path/to/oidc/compliant/server"
|
|
pattern="https://.+">
|
|
</span>
|
|
<div class="help-text">
|
|
The URL of an OIDC-compliant server.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Client ID:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config[provider].CLIENT_ID"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Client Secret:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config[provider].CLIENT_SECRET"></span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Service Name:</td>
|
|
<td>
|
|
<span class="config-string-field"
|
|
binding="config[provider].SERVICE_NAME"
|
|
placeholder="My Authentication Service">
|
|
</span>
|
|
<div class="help-text">
|
|
The user friendly name to display for the service on the login page.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Service Icon (optional):</td>
|
|
<td>
|
|
<span class="config-string-field"
|
|
binding="config[provider].SERVICE_ICON"
|
|
placeholder="URL of the icon to use for this service OR a font awesome CSS name"
|
|
is-optional="true">
|
|
</span>
|
|
<div class="help-text">
|
|
If specified, the icon to display for this login service on the login page. Can be either a URL to an icon or a CSS class name from <a href="http://fontawesome.io" ng-safenewtab>Font Awesome</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken'">
|
|
<td>Binding Field:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="config[provider].LOGIN_BINDING_FIELD">
|
|
<option value="">(None)</option>
|
|
<option value="sub">Subject (User ID)</option>
|
|
<option value="username">Username</option>
|
|
<option value="email">E-mail address</option>
|
|
</select>
|
|
<div class="help-text">
|
|
If selected, when a user logs in via this OIDC provider, they will be automatically bound to their user in <strong>{{ config.AUTHENTICATION_TYPE }}</strong> by matching the selected field from the OIDC provider to the associated user in {{ config.AUTHENTICATION_TYPE }}.
|
|
</div>
|
|
<div class="help-text">
|
|
For example, selecting <code>Subject</code> here with a backing authentication system of LDAP means that a user logging in via this OIDC provider will also be bound to their user in LDAP by username.
|
|
</div>
|
|
<div class="help-text">
|
|
If none selected, a <strong>user unique to <span class="registry-name"></span></strong> will be created on initial login with this OIDC provider. <strong>This is not the recommended setup.</strong>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Login Scopes:</td>
|
|
<td>
|
|
<span class="config-list-field" item-title="Login Scope" binding="config[provider].LOGIN_SCOPES"></span>
|
|
<div class="help-text">
|
|
If specified, the scopes to send to the OIDC provider when performing the login flow. Note that, <strong>if specified</strong>, these scopes will
|
|
<strong>override</strong> those set by default, so this list <strong>must</strong> include a scope for OpenID Connect
|
|
(typically the <code>openid</code> scope) or this provider will fail.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<div>
|
|
<h4>Callback URLs for this service:</h4>
|
|
<ul>
|
|
<li><code>{{ mapped.TLS_SETTING == 'none' ? 'http' : 'https' }}://{{ config.SERVER_HOSTNAME || '(configure server hostname)' }}/oauth2/{{ getOIDCProviderId(provider).toLowerCase() }}/callback</code></li>
|
|
<li><code>{{ mapped.TLS_SETTING == 'none' ? 'http' : 'https' }}://{{ config.SERVER_HOSTNAME || '(configure server hostname)' }}/oauth2/{{ getOIDCProviderId(provider).toLowerCase() }}/callback/attach</code></li>
|
|
<li><code>{{ mapped.TLS_SETTING == 'none' ? 'http' : 'https' }}://{{ config.SERVER_HOSTNAME || '(configure server hostname)' }}/oauth2/{{ getOIDCProviderId(provider).toLowerCase() }}/callback/cli</code></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Provider -->
|
|
<a class="btn btn-default" ng-click="addOIDCProvider()" style="margin-right: 6px;">Add OIDC Provider</a>
|
|
<a href="http://openid.net/connect/" ng-safenewtab>What is OIDC?</a>
|
|
</div>
|
|
</div> <!-- /External Authentication -->
|
|
|
|
<!-- Access settings -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-user-circle"></i> Access Settings
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>Various settings around access and authentication to the registry.</p>
|
|
</div>
|
|
|
|
<table class="config-table">
|
|
<tr>
|
|
<td class="non-input">Basic Credentials Login:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_DIRECT_LOGIN" ng-if="getOIDCProviders(config).length || config.FEATURE_GITHUB_LOGIN || config.FEATURE_GOOGLE_LOGIN">
|
|
Login to User Interface via credentials
|
|
</div>
|
|
<div ng-if="!getOIDCProviders(config).length && !config.FEATURE_GITHUB_LOGIN && !config.FEATURE_GOOGLE_LOGIN">
|
|
<div ng-if="!config.FEATURE_DIRECT_LOGIN" class="co-alert co-alert-danger">
|
|
Login to User Interface via credentials must be enabled. <a ng-click="enableFeature(config, 'FEATURE_DIRECT_LOGIN')">Click here to enable</a>.
|
|
</div>
|
|
<div ng-if="config.FEATURE_DIRECT_LOGIN">
|
|
Login to User Interface via credentials is <strong>enabled</strong> (requires at least one OIDC provider to disable)
|
|
</div>
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, users will be able to login to the <strong>user interface</strong> via their username and password credentials.
|
|
</div>
|
|
<div class="help-text">
|
|
If <strong>disabled</strong>, users will only be able to login to the <strong>user interface</strong> via one of the configured External Authentication providers.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">External Application tokens</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_APP_SPECIFIC_TOKENS">
|
|
Allow external application tokens
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, users will be able to generate external application tokens for use on the Docker and rkt CLI. Note
|
|
that these tokens will <strong>not be required</strong> unless "App Token" is chosen as the Internal Authentication method above.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="config.FEATURE_APP_SPECIFIC_TOKENS">
|
|
<td>External application token expiration</td>
|
|
<td colspan="2">
|
|
<span class="config-string-field" binding="config.APP_SPECIFIC_TOKEN_EXPIRATION"
|
|
pattern="[0-9]+(m|w|h|d|s)" is-optional="true"></span>
|
|
<div class="help-text">
|
|
The expiration time for user generated external application tokens. If none, tokens will never expire.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">Anonymous Access:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_ANONYMOUS_ACCESS">
|
|
Enable Anonymous Access
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, public repositories and search can be accessed by anyone that can
|
|
reach the registry, even if they are not authenticated. Disable to only allow
|
|
authenticated users to view and pull "public" resources.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">User Creation:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_USER_CREATION">
|
|
Enable Open User Creation
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, user accounts can be created by anyone (unless restricted below to invited users).
|
|
Users can always be created in the users panel in this superuser tool, even if this feature is disabled.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-show="config.FEATURE_USER_CREATION && config.FEATURE_MAILING">
|
|
<td class="non-input">Invite-only User Creation:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_INVITE_ONLY_USER_CREATION">
|
|
Enable Invite-only User Creation
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, user accounts can only be created when a user has been invited, by e-mail address, to join a team.
|
|
Users can always be created in the users panel in this superuser tool, even if this feature is enabled.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">Encrypted Client Password:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_REQUIRE_ENCRYPTED_BASIC_AUTH">
|
|
Require Encrypted Client Passwords
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, users will not be able to login from the Docker command
|
|
line with a non-encrypted password and must generate an encrypted
|
|
password to use.
|
|
</div>
|
|
<div class="help-text" ng-if="config.AUTHENTICATION_TYPE != 'Database'">
|
|
This feature is <strong>highly recommended</strong> for setups with external authentication, as Docker currently stores passwords in <strong>plaintext</strong> on user's machines.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">Prefix username autocompletion:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_PARTIAL_USER_AUTOCOMPLETE">
|
|
Allow prefix username autocompletion
|
|
</div>
|
|
<div class="help-text">
|
|
If disabled, autocompletion for users will only match on exact usernames.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="non-input">Allow username confirmation:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_USERNAME_CONFIRMATION">
|
|
Allow username confirmation
|
|
</div>
|
|
<div class="help-text">
|
|
If disabled, users logging in will be locked into the username granted by
|
|
the registry.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr ng-show="config.FEATURE_MAILING">
|
|
<td class="non-input">Team Invitations:</td>
|
|
<td colspan="2">
|
|
<div class="config-bool-field" binding="config.FEATURE_REQUIRE_TEAM_INVITE">
|
|
Require Team Invitations
|
|
</div>
|
|
<div class="help-text">
|
|
If enabled, when adding a new user to a team, they will receive an invitation to join the team, with the option to decline.
|
|
Otherwise, users will be immediately part of a team when added by a team administrator.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /Access settings -->
|
|
|
|
<!-- Build Support -->
|
|
<div class="co-panel">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-tasks"></i> Dockerfile Build Support
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
If enabled, users can submit Dockerfiles to be built and pushed by <span class="registry-name"></span>.
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_BUILD_SUPPORT">
|
|
Enable Dockerfile Build
|
|
</div>
|
|
|
|
<div ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 10px">
|
|
<strong>Note: Build workers are required for this feature.</strong>
|
|
See <a href="https://coreos.com/docs/enterprise-registry/build-support/" ng-safenewtab>Adding Build Workers</a> for instructions on how to setup build workers.
|
|
</div>
|
|
</div>
|
|
</div> <!-- /Build Support -->
|
|
|
|
<!-- GitHub Trigger -->
|
|
<div class="co-panel" ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 20px;">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-github"></i> GitHub (Enterprise) Build Triggers
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
If enabled, users can setup GitHub or GitHub Enterprise triggers to invoke Registry builds.
|
|
</p>
|
|
<p>
|
|
<strong>Note:</strong> A registered GitHub (Enterprise) OAuth application (<strong>separate from GitHub Authentication</strong>) is required.
|
|
View instructions on how to
|
|
<a href="https://coreos.com/docs/enterprise-registry/github-app/" ng-safenewtab>
|
|
Create an OAuth Application in GitHub
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_GITHUB_BUILD">
|
|
Enable GitHub Triggers
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_GITHUB_BUILD">
|
|
<tr>
|
|
<td>GitHub:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="mapped.GITHUB_TRIGGER_KIND">
|
|
<option value="hosted">GitHub.com</option>
|
|
<option value="enterprise">GitHub Enterprise</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="mapped.GITHUB_TRIGGER_KIND == 'enterprise'">
|
|
<td>GitHub Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field"
|
|
binding="config.GITHUB_TRIGGER_CONFIG.GITHUB_ENDPOINT"
|
|
placeholder="https://my.githubserver"
|
|
pattern="{{ GITHOST_REGEX }}">
|
|
</span>
|
|
<div class="help-text">
|
|
The GitHub Enterprise endpoint. Must start with http:// or https://.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OAuth Client ID:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GITHUB_TRIGGER_CONFIG.CLIENT_ID">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OAuth Client Secret:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GITHUB_TRIGGER_CONFIG.CLIENT_SECRET">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /GitHub Trigger -->
|
|
|
|
<!-- BitBucket Trigger -->
|
|
<div class="co-panel" ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 20px;">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-bitbucket"></i> BitBucket Build Triggers
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
If enabled, users can setup BitBucket triggers to invoke Registry builds.
|
|
</p>
|
|
<p>
|
|
<strong>Note:</strong> A registered BitBucket OAuth application is required.
|
|
View instructions on how to
|
|
<a href="https://coreos.com/docs/enterprise-registry/bitbucket-app/" ng-safenewtab>
|
|
Create an OAuth Application in BitBucket
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_BITBUCKET_BUILD">
|
|
Enable BitBucket Triggers
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_BITBUCKET_BUILD">
|
|
<tr>
|
|
<td>OAuth Consumer Key:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.BITBUCKET_TRIGGER_CONFIG.CONSUMER_KEY">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>OAuth Consumer Secret:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.BITBUCKET_TRIGGER_CONFIG.CONSUMER_SECRET">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /BitBucket Trigger -->
|
|
|
|
<!-- GitLab Trigger -->
|
|
<div class="co-panel" ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 20px;">
|
|
<div class="co-panel-heading">
|
|
<i class="fa fa-gitlab"></i> GitLab Build Triggers
|
|
</div>
|
|
<div class="co-panel-body">
|
|
<div class="description">
|
|
<p>
|
|
If enabled, users can setup GitLab triggers to invoke Registry builds.
|
|
</p>
|
|
<p>
|
|
<strong>Note:</strong> A registered GitLab OAuth application is required.
|
|
Visit the
|
|
<a href="{{ config.GITLAB_TRIGGER_CONFIG.GITLAB_ENDPOINT || 'https://gitlab.com' }}/profile/applications" ng-safenewtab>
|
|
GitLab applications admin panel
|
|
</a>
|
|
to create a new application.
|
|
</p>
|
|
<p>The callback URL to use is:
|
|
<code>{{ config.PREFERRED_URL_SCHEME || 'http' }}://{{ config.SERVER_HOSTNAME || 'localhost' }}/oauth2/gitlab/callback/trigger</code>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="config-bool-field" binding="config.FEATURE_GITLAB_BUILD">
|
|
Enable GitLab Triggers
|
|
</div>
|
|
|
|
<table class="config-table" ng-if="config.FEATURE_GITLAB_BUILD">
|
|
<tr>
|
|
<td>GitLab:</td>
|
|
<td>
|
|
<select class="form-control" ng-model="mapped.GITLAB_TRIGGER_KIND">
|
|
<option value="hosted">GitLab.com</option>
|
|
<option value="enterprise">GitLab CE/EE</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="mapped.GITLAB_TRIGGER_KIND == 'enterprise'">
|
|
<td>GitLab Endpoint:</td>
|
|
<td>
|
|
<span class="config-string-field"
|
|
binding="config.GITLAB_TRIGGER_CONFIG.GITLAB_ENDPOINT"
|
|
placeholder="https://my.gitlabserver"
|
|
pattern="{{ GITHOST_REGEX }}">
|
|
</span>
|
|
<div class="help-text">
|
|
The GitLab Enterprise endpoint. Must start with http:// or https://.
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Application Id:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GITLAB_TRIGGER_CONFIG.CLIENT_ID">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Secret:</td>
|
|
<td>
|
|
<span class="config-string-field" binding="config.GITLAB_TRIGGER_CONFIG.CLIENT_SECRET">
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div> <!-- /GitLab Trigger -->
|
|
|
|
</form>
|
|
|
|
<!-- Save Bar -->
|
|
<div class="cor-floating-bottom-bar">
|
|
<button class="btn" ng-class="mapped.$hasChanges ? 'btn-primary' : 'btn-success'"
|
|
ng-click="checkValidateAndSave()" ng-show="configform.$valid">
|
|
<i class="fa fa-lg" ng-class="mapped.$hasChanges ? 'fa-dot-circle-o' : 'fa-check-circle'"></i>
|
|
<span ng-if="mapped.$hasChanges">Save Configuration Changes</span>
|
|
<span ng-if="!mapped.$hasChanges">Configuration Saved</span>
|
|
</button>
|
|
<button class="btn btn-warning" ng-click="checkValidateAndSave()" ng-show="!configform.$valid"
|
|
ng-click="checkValidateAndSave()">
|
|
<i class="fa fa-lg fa-sort"></i>
|
|
<span ng-if="configform.$error['required'].length">
|
|
{{ configform.$error['required'].length }} configuration field<span ng-show="configform.$error['required'].length != 1">s</span> remaining
|
|
</span>
|
|
<span ng-if="!configform.$error['required'].length">
|
|
Invalid configuration field
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Modal message dialog -->
|
|
<div class="modal co-dialog fade initial-setup-modal" id="validateAndSaveModal">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">
|
|
Checking your settings
|
|
</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="service-verification">
|
|
<div class="service-verification-row" ng-repeat="serviceInfo in validating">
|
|
<span class="quay-spinner" ng-show="serviceInfo.status == 'validating'"></span>
|
|
<i class="fa fa-lg fa-check-circle" ng-show="serviceInfo.status == 'success'"></i>
|
|
<i class="fa fa-lg fa-warning" ng-show="serviceInfo.status == 'error'"></i>
|
|
<span class="service-title">{{ serviceInfo.service.title }}</span>
|
|
|
|
<div class="service-verification-error" ng-show="serviceInfo.status == 'error'">{{ serviceInfo.errorMessage }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer: Saving configuration -->
|
|
<div class="modal-footer working" ng-show="savingConfiguration">
|
|
<span class="cor-loader-inline"></span> Saving Configuration...
|
|
</div>
|
|
|
|
<!-- Footer: Validating -->
|
|
<div class="modal-footer working"
|
|
ng-show="!savingConfiguration && validationStatus(validating) == 'validating'">
|
|
<span class="cor-loader-inline"></span> Validating settings...
|
|
|
|
<button class="btn btn-default" ng-click="cancelValidation()">
|
|
Stop Validating
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Footer: Valid Config -->
|
|
<div class="modal-footer"
|
|
ng-show="!savingConfiguration && validationStatus(validating) == 'success'">
|
|
<span class="left-align">
|
|
<i class="fa fa-check"></i>
|
|
Configuration Validated
|
|
</span>
|
|
|
|
<button class="btn btn-primary"
|
|
ng-click="saveConfiguration()"
|
|
ng-disabled="savingConfiguration">
|
|
<i class="fa fa-upload" style="margin-right: 10px;"></i>Save Configuration
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Footer: Invalid Config -->
|
|
<div class="modal-footer"
|
|
ng-show="!savingConfiguration && validationStatus(validating) == 'failed'">
|
|
<span class="left-align">
|
|
<i class="fa fa-warning"></i>
|
|
Problem Detected
|
|
</span>
|
|
|
|
<button class="btn btn-default" data-dismiss="modal">
|
|
Continue Editing
|
|
</button>
|
|
</div>
|
|
|
|
</div><!-- /.modal-content -->
|
|
</div><!-- /.modal-dialog -->
|
|
</div><!-- /.modal -->
|
|
|
|
</div>
|
|
</div>
|