mirror of https://github.com/rancher/ui.git
commit
a893f2433a
|
|
@ -4,16 +4,7 @@ import { inject as service } from '@ember/service';
|
|||
import ViewNewEdit from 'shared/mixins/view-new-edit';
|
||||
import OptionallyNamespaced from 'shared/mixins/optionally-namespaced';
|
||||
import layout from './template';
|
||||
|
||||
const BEGIN_CERTIFICATE = [
|
||||
'-----BEGIN CERTIFICATE-----'
|
||||
];
|
||||
|
||||
const BEGIN_KEY = [
|
||||
'-----BEGIN PRIVATE KEY-----',
|
||||
'-----BEGIN EC PRIVATE KEY-----',
|
||||
'-----BEGIN RSA PRIVATE KEY-----',
|
||||
]
|
||||
import { validateCertWeakly, validateKeyWeakly } from 'shared/utils/util';
|
||||
|
||||
export default Component.extend(ViewNewEdit, OptionallyNamespaced, {
|
||||
intl: service(),
|
||||
|
|
@ -51,15 +42,7 @@ export default Component.extend(ViewNewEdit, OptionallyNamespaced, {
|
|||
const key = get(this, 'model.key');
|
||||
|
||||
if ( key ) {
|
||||
let ok = false;
|
||||
|
||||
BEGIN_KEY.forEach((prefix) => {
|
||||
if ( key.trim().startsWith(prefix) ) {
|
||||
ok = true;
|
||||
}
|
||||
});
|
||||
|
||||
if ( !ok ) {
|
||||
if ( !validateKeyWeakly(key) ) {
|
||||
errors.push(intl.t('newCertificate.errors.key.invalidFormat'));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -69,15 +52,7 @@ export default Component.extend(ViewNewEdit, OptionallyNamespaced, {
|
|||
const certs = get(this, 'model.certs');
|
||||
|
||||
if ( certs ) {
|
||||
let ok = false;
|
||||
|
||||
BEGIN_CERTIFICATE.forEach((prefix) => {
|
||||
if ( certs.trim().startsWith(prefix) ) {
|
||||
ok = true;
|
||||
}
|
||||
});
|
||||
|
||||
if ( !ok ) {
|
||||
if ( !validateCertWeakly(certs) ) {
|
||||
errors.push(intl.t('newCertificate.errors.cert.invalidFormat'));
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import { get, set, setProperties } from '@ember/object';
|
||||
import { get, set, setProperties, computed } from '@ember/object';
|
||||
import Component from '@ember/component';
|
||||
import ModalBase from 'shared/mixins/modal-base';
|
||||
import layout from './template';
|
||||
|
|
@ -12,41 +12,23 @@ export default Component.extend(ModalBase, {
|
|||
layout,
|
||||
classNames: ['large-modal'],
|
||||
backupId: null,
|
||||
availableBackups: null,
|
||||
loadingBackups: false,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
setProperties(this, {
|
||||
backupId: '',
|
||||
errors: [],
|
||||
});
|
||||
},
|
||||
|
||||
didReceiveAttrs() {
|
||||
const etcdBackUps = get(this, 'modalOpts.cluster.etcdbackups');
|
||||
const out = [];
|
||||
|
||||
etcdBackUps.forEach((backup) => {
|
||||
let time = moment(get(backup, 'created'));
|
||||
|
||||
out.pushObject({
|
||||
id: backup.id,
|
||||
label: `${ backup.displayName } ( ${ time.format('MMMM Do YYYY, H:mm:ss') })`,
|
||||
created: backup.created,
|
||||
});
|
||||
});
|
||||
|
||||
set(this, 'availableBackups', out.sortBy('created'));
|
||||
this.initOwnProperties();
|
||||
this.fetchAllBackupsForCluster();
|
||||
},
|
||||
|
||||
actions: {
|
||||
restore(cb) {
|
||||
const { backupId } = this;
|
||||
const out = {};
|
||||
const out = {};
|
||||
|
||||
if (backupId) {
|
||||
set(out, 'etcdBackupId', backupId);
|
||||
|
||||
this.modalOpts.cluster.doAction('restoreFromEtcdBackup', out).then(() => {
|
||||
this.send('cancel');
|
||||
})
|
||||
|
|
@ -62,4 +44,32 @@ export default Component.extend(ModalBase, {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
availableBackups: computed('modalOpts.cluster.etcdbackups.[]', function() {
|
||||
return get(this, 'modalOpts.cluster.etcdbackups').map((backup) => {
|
||||
let time = moment(get(backup, 'created'));
|
||||
|
||||
return {
|
||||
id: backup.id,
|
||||
label: `${ backup.displayName } ( ${ time.format('MMMM Do YYYY, H:mm:ss') })`,
|
||||
created: backup.created,
|
||||
}
|
||||
}).sortBy('created');
|
||||
}),
|
||||
|
||||
initOwnProperties() {
|
||||
setProperties(this, {
|
||||
backupId: '',
|
||||
errors: [],
|
||||
});
|
||||
},
|
||||
|
||||
fetchAllBackupsForCluster() {
|
||||
set(this, 'loadingBackups', true);
|
||||
|
||||
this.modalOpts.cluster.store.findAll('etcdbackup')
|
||||
.finally(() => {
|
||||
set(this, 'loadingBackups', false);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,28 +12,33 @@
|
|||
>
|
||||
{{t "modalRestoreBackup.backups"}}{{field-required}}
|
||||
</label>
|
||||
<select
|
||||
id="available-backups"
|
||||
class="form-control"
|
||||
onchange={{action (mut backupId) value="target.value"}}
|
||||
>
|
||||
{{#unless (eq backupId value)}}
|
||||
<option
|
||||
value=""
|
||||
selected=true
|
||||
>
|
||||
{{t "modalRestoreBackup.select.all"}}
|
||||
</option>
|
||||
{{/unless}}
|
||||
{{#each availableBackups as |backup|}}
|
||||
<option
|
||||
value={{backup.id}}
|
||||
selected={{eq backup.id value}}
|
||||
>
|
||||
{{backup.label}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
{{#if loadingBackups}}
|
||||
<i class="icon icon-spinner icon-spin"></i>
|
||||
{{t "modalRestoreBackup.fetching"}}
|
||||
{{else}}
|
||||
<select
|
||||
id="available-backups"
|
||||
class="form-control"
|
||||
onchange={{action (mut backupId) value="target.value"}}
|
||||
>
|
||||
{{#unless (eq backupId value)}}
|
||||
<option
|
||||
value=""
|
||||
selected=true
|
||||
>
|
||||
{{t "modalRestoreBackup.select.all"}}
|
||||
</option>
|
||||
{{/unless}}
|
||||
{{#each availableBackups as |backup|}}
|
||||
<option
|
||||
value={{backup.id}}
|
||||
selected={{eq backup.id value}}
|
||||
>
|
||||
{{backup.label}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -77,12 +77,6 @@ export default Controller.extend({
|
|||
];
|
||||
}),
|
||||
|
||||
showWarning: computed('filteredDrivers.[]', function() {
|
||||
const providers = get(this, 'globalStore').all('authconfig').filterBy('enabled');
|
||||
|
||||
return providers.length > 1 ? true : false;
|
||||
}),
|
||||
|
||||
filteredDrivers: computed(function() {
|
||||
// this is a soft disable of allowing multiple auth configs being active, we need to disable it right now but it will come back post 2.1
|
||||
// when it does just itterate over the drivers again and remove filteredDrivers
|
||||
|
|
|
|||
|
|
@ -5,22 +5,26 @@
|
|||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
{{#if showWarning}}
|
||||
{{#banner-message color="bg-warning"}}
|
||||
{{t "nav.admin.security.authWarning"}}
|
||||
{{/banner-message}}
|
||||
{{/if}}
|
||||
|
||||
<section class="mb-20">
|
||||
<div class="row nav nav-boxes checked-active">
|
||||
{{#each filteredDrivers as |driver|}}
|
||||
{{#if driver.available }}
|
||||
{{#link-to driver.route alt=driver.label classNames="col span-2 nav-box-item driver" href=false}}
|
||||
{{#link-to
|
||||
driver.route
|
||||
alt=driver.label
|
||||
classNames="col span-2 nav-box-item driver"
|
||||
href=false
|
||||
}}
|
||||
{{#if driver.providerType }}
|
||||
<span class="badge bg-info driver-badge">{{driver.providerType}}</span>
|
||||
<span class="badge bg-info driver-badge">
|
||||
{{driver.providerType}}
|
||||
</span>
|
||||
{{/if}}
|
||||
<div class="auth-driver {{driver.css}}"></div>
|
||||
<p>{{driver.label}}</p>
|
||||
<p>
|
||||
{{driver.label}}
|
||||
</p>
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
underlineToCamel, removeEmpty, keysToCamel, validateEndpoint, randomStr
|
||||
} from 'shared/utils/util';
|
||||
import { validateHostname } from '@rancher/ember-api-store/utils/validate';
|
||||
|
||||
import { validateCertWeakly } from 'shared/utils/util';
|
||||
import C from 'shared/utils/constants';
|
||||
import YAML from 'yamljs';
|
||||
import json2yaml from 'json2yaml';
|
||||
|
|
@ -436,8 +436,7 @@ export default InputTextFile.extend(ClusterDriver, {
|
|||
return out;
|
||||
}),
|
||||
|
||||
value: computed('pasteOrUpload', {
|
||||
|
||||
yamlValue: computed('pasteOrUpload', {
|
||||
get() {
|
||||
const intl = get(this, 'intl');
|
||||
|
||||
|
|
@ -536,7 +535,7 @@ export default InputTextFile.extend(ClusterDriver, {
|
|||
validate() {
|
||||
this._super(...arguments);
|
||||
|
||||
let errors = get(this, 'errors') || [];
|
||||
let errors = [];
|
||||
let config = get(this, `cluster.rancherKubernetesEngineConfig`);
|
||||
|
||||
if ( !get(this, 'isCustom') ) {
|
||||
|
|
@ -561,6 +560,10 @@ export default InputTextFile.extend(ClusterDriver, {
|
|||
errors = this.validateEtcdService(errors);
|
||||
}
|
||||
|
||||
if ( get(this, 'cluster.localClusterAuthEndpoint.enabled') ) {
|
||||
errors = this.validateAuthorizedClusterEndpoint(errors);
|
||||
}
|
||||
|
||||
const clusterOptErrors = get(this, 'clusterOptErrors') || [];
|
||||
|
||||
if ( get(config, 'cloudProvider.name') === 'azure' ) {
|
||||
|
|
@ -578,6 +581,25 @@ export default InputTextFile.extend(ClusterDriver, {
|
|||
return errors.length === 0 && clusterOptErrors.length === 0;
|
||||
},
|
||||
|
||||
validateAuthorizedClusterEndpoint(errors) {
|
||||
let { localClusterAuthEndpoint } = get(this, 'cluster');
|
||||
let { caCerts, fqdn } = localClusterAuthEndpoint;
|
||||
|
||||
if (caCerts) {
|
||||
if (!validateCertWeakly(caCerts) ) {
|
||||
errors.push(this.intl.t('newCertificate.errors.cert.invalidFormat'));
|
||||
}
|
||||
} else {
|
||||
errors.push(this.intl.t('newCertificate.errors.cert.required'));
|
||||
}
|
||||
|
||||
if (fqdn) {
|
||||
errors = validateHostname(fqdn, 'FQDN', get(this, 'intl'), { restricted: true }, errors);
|
||||
}
|
||||
|
||||
return errors;
|
||||
},
|
||||
|
||||
validateEtcdService(errors) {
|
||||
const etcdService = get(this, 'cluster.rancherKubernetesEngineConfig.services.etcd') || {};
|
||||
const { creation, retention } = etcdService;
|
||||
|
|
|
|||
|
|
@ -49,13 +49,13 @@
|
|||
showDownload=false
|
||||
canChangeName=false
|
||||
autoResize=true
|
||||
value=value
|
||||
value=yamlValue
|
||||
}}
|
||||
</div>
|
||||
{{copy-to-clipboard
|
||||
tooltipText=""
|
||||
buttonText="copyToClipboard.tooltip"
|
||||
clipboardText=value
|
||||
clipboardText=yamlValue
|
||||
class="with-clip"
|
||||
}}
|
||||
</div>
|
||||
|
|
@ -706,6 +706,7 @@
|
|||
{{top-errors errors=clusterErrors}}
|
||||
{{top-errors errors=otherErrors}}
|
||||
{{top-errors errors=clusterOptErrors}}
|
||||
|
||||
{{#if (or isEdit (eq step 1))}}
|
||||
{{save-cancel
|
||||
createLabel=(if isCustom "saveCancel.next" "saveCancel.create")
|
||||
|
|
|
|||
|
|
@ -162,11 +162,6 @@ export function absoluteUrl(url) {
|
|||
return parseUrl(url).href;
|
||||
}
|
||||
|
||||
export function validateEndpoint(str) {
|
||||
// credit to https://stackoverflow.com/questions/4460586/javascript-regular-expression-to-check-for-ip-addresses
|
||||
return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(str);
|
||||
}
|
||||
|
||||
export function addAuthorization(url, user, pass) {
|
||||
url = absoluteUrl(url);
|
||||
var pos = url.indexOf('//');
|
||||
|
|
@ -481,6 +476,35 @@ export function deepCopy(obj) {
|
|||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
export function validateEndpoint(str) {
|
||||
// credit to https://stackoverflow.com/questions/4460586/javascript-regular-expression-to-check-for-ip-addresses
|
||||
return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(str);
|
||||
}
|
||||
|
||||
export function validateCertWeakly(certs) {
|
||||
const BEGIN_CERTIFICATE = [
|
||||
'-----BEGIN CERTIFICATE-----'
|
||||
];
|
||||
|
||||
return certs.trim().startsWith(BEGIN_CERTIFICATE[0]);
|
||||
}
|
||||
|
||||
export function validateKeyWeakly(key) {
|
||||
const BEGIN_KEY = [
|
||||
'-----BEGIN PRIVATE KEY-----',
|
||||
'-----BEGIN EC PRIVATE KEY-----',
|
||||
'-----BEGIN RSA PRIVATE KEY-----',
|
||||
]
|
||||
|
||||
BEGIN_KEY.forEach((prefix) => {
|
||||
if ( key.trim().startsWith(prefix) ) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var Util = {
|
||||
absoluteUrl,
|
||||
addAuthorization,
|
||||
|
|
|
|||
|
|
@ -5322,6 +5322,7 @@ modalRestoreBackup:
|
|||
title: Restore From Backup
|
||||
backups: Available Backups
|
||||
error: A backup is required
|
||||
fetching: Fetching new backups
|
||||
select:
|
||||
all: Select an available backup
|
||||
|
||||
|
|
@ -6729,7 +6730,6 @@ nav:
|
|||
members: Members
|
||||
podSecurityPolicies: Pod Security Policies
|
||||
authentication: Authentication
|
||||
authWarning: "Note: Only a single authentication provider, in additon to local authentication, may be enabled at any time. If you had multiple authentication providers enabled prior to 2.1, you may still edit or disable these providers but you can not enable additonal providers. Nor will you be able re-enable a provider you previously disabled. Proceed with caution when disabling because you can not get them back."
|
||||
settings:
|
||||
tab: Settings
|
||||
auth: Access Control
|
||||
|
|
|
|||
Loading…
Reference in New Issue