fix: certificate expired change

1. Use metadata to instead of actual expired time
2. Delete disabled if the certificate was used for a listener

Change-Id: I8a16c4c1cc6f104c85835906405aba7ae9a3bf02
This commit is contained in:
xusongfu 2022-06-08 18:45:51 +08:00
parent d133705f6f
commit efaeac8453
10 changed files with 151 additions and 35 deletions

View File

@ -94,11 +94,29 @@ export class Certificate extends Base {
}, },
{ {
title: t('Domain Name'), title: t('Domain Name'),
dataIndex: 'algorithm', dataIndex: 'domain',
render: (value) => value || '-', render: (value) => value || '-',
hidden: this.currentMode === 'CA', hidden: this.currentMode === 'CA',
isHideable: true, isHideable: true,
}, },
{
title: t('Listener'),
dataIndex: 'listener',
render: (value) => {
return value
? this.getLinkRender(
'lbListenerDetail',
value.name,
{
loadBalancerId: value.lb,
id: value.id,
},
null
)
: '-';
},
isHideable: true,
},
{ {
title: t('Status'), title: t('Status'),
dataIndex: 'status', dataIndex: 'status',

View File

@ -15,7 +15,7 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import Base from 'containers/TabDetail'; import Base from 'containers/TabDetail';
import { ContainersStore } from 'stores/barbican/containers'; import { ContainersStore } from 'stores/barbican/containers';
import { certificateColumns } from 'resources/octavia/lb'; import { getCertificateColumns } from 'resources/octavia/lb';
import BaseDetail from './BaseDetail'; import BaseDetail from './BaseDetail';
import actionConfigs from '../../actions'; import actionConfigs from '../../actions';
@ -41,7 +41,7 @@ export class Detail extends Base {
} }
get detailInfos() { get detailInfos() {
return certificateColumns; return getCertificateColumns(this);
} }
get tabs() { get tabs() {

View File

@ -15,7 +15,7 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import Base from 'containers/TabDetail'; import Base from 'containers/TabDetail';
import { SecretsStore } from 'stores/barbican/secrets'; import { SecretsStore } from 'stores/barbican/secrets';
import { certificateColumns } from 'resources/octavia/lb'; import { getCertificateColumns } from 'resources/octavia/lb';
import BaseDetail from './BaseDetail'; import BaseDetail from './BaseDetail';
import actionConfigs from '../../actions'; import actionConfigs from '../../actions';
@ -41,7 +41,9 @@ export class Detail extends Base {
} }
get detailInfos() { get detailInfos() {
return certificateColumns.filter((it) => it.dataIndex !== 'algorithm'); return getCertificateColumns(this).filter(
(it) => it.dataIndex !== 'domain'
);
} }
get tabs() { get tabs() {

View File

@ -38,7 +38,7 @@ export default class DeleteAction extends ConfirmAction {
policy = ['barbican:secret:delete', 'barbican:container:delete']; policy = ['barbican:secret:delete', 'barbican:container:delete'];
allowedCheckFunc = () => true; allowedCheckFunc = (item) => !item.listener;
onSubmit = (data) => { onSubmit = (data) => {
return globalContainersStore.delete(data); return globalContainersStore.delete(data);

View File

@ -38,7 +38,7 @@ export default class DeleteAction extends ConfirmAction {
policy = 'barbican:secret:delete'; policy = 'barbican:secret:delete';
allowedCheckFunc = () => true; allowedCheckFunc = (item) => !item.listener;
onSubmit = (data) => { onSubmit = (data) => {
return globalSecretsStore.delete(data); return globalSecretsStore.delete(data);

View File

@ -18,7 +18,7 @@ import { ListenerStore } from 'stores/octavia/listener';
import { ContainersStore } from 'stores/barbican/containers'; import { ContainersStore } from 'stores/barbican/containers';
import { SecretsStore } from 'stores/barbican/secrets'; import { SecretsStore } from 'stores/barbican/secrets';
import { import {
certificateColumns, getCertificateColumns,
listenerProtocols, listenerProtocols,
sslParseMethod, sslParseMethod,
} from 'resources/octavia/lb'; } from 'resources/octavia/lb';
@ -74,9 +74,7 @@ export class Create extends ModalAction {
} }
get SNICertificate() { get SNICertificate() {
return (this.containersStore.list.data || []).filter( return (this.containersStore.list.data || []).filter((it) => !!it.domain);
(it) => !!it.algorithm
);
} }
get isEdit() { get isEdit() {
@ -140,7 +138,7 @@ export class Create extends ModalAction {
name: 'name', name: 'name',
}, },
], ],
columns: certificateColumns, columns: getCertificateColumns(this),
display: protocol === 'TERMINATED_HTTPS', display: protocol === 'TERMINATED_HTTPS',
}, },
{ {
@ -157,8 +155,8 @@ export class Create extends ModalAction {
name: 'name', name: 'name',
}, },
], ],
columns: certificateColumns.filter( columns: getCertificateColumns(this).filter(
(it) => it.dataIndex !== 'algorithm' (it) => it.dataIndex !== 'domain'
), ),
display: display:
protocol === 'TERMINATED_HTTPS' && ssl_parsing_method === 'two-way', protocol === 'TERMINATED_HTTPS' && ssl_parsing_method === 'two-way',
@ -183,7 +181,7 @@ export class Create extends ModalAction {
name: 'name', name: 'name',
}, },
], ],
columns: certificateColumns, columns: getCertificateColumns(this),
display: protocol === 'TERMINATED_HTTPS' && sni_enabled, display: protocol === 'TERMINATED_HTTPS' && sni_enabled,
}, },
{ {

View File

@ -15,7 +15,7 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import Base from 'components/Form'; import Base from 'components/Form';
import { import {
certificateColumns, getCertificateColumns,
listenerProtocols, listenerProtocols,
sslParseMethod, sslParseMethod,
} from 'resources/octavia/lb'; } from 'resources/octavia/lb';
@ -59,9 +59,7 @@ export class ListenerStep extends Base {
} }
get SNISecrets() { get SNISecrets() {
return (this.containersStore.list.data || []).filter( return (this.containersStore.list.data || []).filter((it) => !!it.domain);
(it) => !!it.algorithm
);
} }
get defaultValue() { get defaultValue() {
@ -135,7 +133,7 @@ export class ListenerStep extends Base {
name: 'name', name: 'name',
}, },
], ],
columns: certificateColumns, columns: getCertificateColumns(this),
display: listener_protocol === 'TERMINATED_HTTPS', display: listener_protocol === 'TERMINATED_HTTPS',
}, },
{ {
@ -152,8 +150,8 @@ export class ListenerStep extends Base {
name: 'name', name: 'name',
}, },
], ],
columns: certificateColumns.filter( columns: getCertificateColumns(this).filter(
(it) => it.dataIndex !== 'algorithm' (it) => it.dataIndex !== 'domain'
), ),
display: display:
listener_protocol === 'TERMINATED_HTTPS' && listener_protocol === 'TERMINATED_HTTPS' &&
@ -179,7 +177,7 @@ export class ListenerStep extends Base {
name: 'name', name: 'name',
}, },
], ],
columns: certificateColumns, columns: getCertificateColumns(this),
display: display:
listener_protocol === 'TERMINATED_HTTPS' && listener_sni_enabled, listener_protocol === 'TERMINATED_HTTPS' && listener_sni_enabled,
}, },

View File

@ -26,7 +26,7 @@ export const certificateStatus = {
ERROR: t('Error'), ERROR: t('Error'),
}; };
export const certificateColumns = [ export const getCertificateColumns = (self) => [
{ {
title: t('Name'), title: t('Name'),
dataIndex: 'name', dataIndex: 'name',
@ -43,9 +43,26 @@ export const certificateColumns = [
}, },
{ {
title: t('Domain Name'), title: t('Domain Name'),
dataIndex: 'algorithm', dataIndex: 'domain',
render: (value) => value || '-', render: (value) => value || '-',
}, },
{
title: t('Listener'),
dataIndex: 'listener',
render: (value) => {
return value
? self.getLinkRender(
'lbListenerDetail',
value.name,
{
loadBalancerId: value.lb,
id: value.id,
},
null
)
: '-';
},
},
{ {
title: t('Status'), title: t('Status'),
dataIndex: 'status', dataIndex: 'status',

View File

@ -16,6 +16,7 @@ import Base from 'stores/base';
import client from 'client'; import client from 'client';
import { action } from 'mobx'; import { action } from 'mobx';
import { SecretsStore } from './secrets'; import { SecretsStore } from './secrets';
import globalListenerStore from '../octavia/listener';
export class ContainersStore extends Base { export class ContainersStore extends Base {
get client() { get client() {
@ -42,11 +43,14 @@ export class ContainersStore extends Base {
get mapper() { get mapper() {
return (data) => { return (data) => {
const { container_ref } = data; const { container_ref, algorithm } = data;
const [, uuid] = container_ref.split('/containers/'); const [, uuid] = container_ref.split('/containers/');
const { domain, expiration } = algorithm ? JSON.parse(algorithm) : {};
return { return {
...data, ...data,
id: uuid, id: uuid,
domain,
expiration,
}; };
}; };
} }
@ -67,9 +71,32 @@ export class ContainersStore extends Base {
return data; return data;
} }
updateItem(item, listeners) {
const { container_ref } = item;
const enabledLs = listeners.find((ls) => {
const refs = [
ls.default_tls_container_ref,
ls.client_ca_tls_container_ref,
...ls.sni_container_refs,
];
return refs.includes(container_ref);
});
if (enabledLs) {
item.listener = {
id: enabledLs.id,
name: enabledLs.name,
lb: enabledLs.lbIds[0],
};
}
return item;
}
async listDidFetch(items) { async listDidFetch(items) {
if (items.length === 0) return items; if (items.length === 0) return items;
const secrets = await this.secretStore.fetchList({ mode: 'SERVER' }); const [secrets, listeners] = await Promise.all([
this.secretStore.fetchList({ mode: 'SERVER' }),
globalListenerStore.fetchList(),
]);
const newItems = items.map((it) => { const newItems = items.map((it) => {
const { secret_refs = [] } = it; const { secret_refs = [] } = it;
if (secret_refs.length === 0) { if (secret_refs.length === 0) {
@ -85,12 +112,13 @@ export class ContainersStore extends Base {
Object.assign(it, { Object.assign(it, {
algorithm: theSecret.algorithm, algorithm: theSecret.algorithm,
mode: theSecret.mode, mode: theSecret.mode,
expiration: theSecret.expiration,
}); });
} else { } else {
it.hidden = true; it.hidden = true;
} }
}); });
// Determine if the certificate is used in the listener
this.updateItem(it, listeners);
} }
return { return {
...it, ...it,
@ -101,7 +129,10 @@ export class ContainersStore extends Base {
async detailDidFetch(item) { async detailDidFetch(item) {
const { secret_refs = [] } = item; const { secret_refs = [] } = item;
const secrets = await this.secretStore.fetchList({ mode: 'SERVER' }); const [secrets, listeners] = await Promise.all([
this.secretStore.fetchList({ mode: 'SERVER' }),
globalListenerStore.fetchList(),
]);
const secretIds = []; const secretIds = [];
// Filter available secrets // Filter available secrets
secret_refs.forEach(async (secret) => { secret_refs.forEach(async (secret) => {
@ -114,10 +145,11 @@ export class ContainersStore extends Base {
Object.assign(item, { Object.assign(item, {
algorithm: theSecret.algorithm, algorithm: theSecret.algorithm,
mode: theSecret.mode, mode: theSecret.mode,
expiration: theSecret.expiration,
}); });
} }
}); });
// Determine if the certificate is used in the listener
this.updateItem(item, listeners);
// Fetch secrets payload // Fetch secrets payload
const payloads = await Promise.all( const payloads = await Promise.all(
secretIds.map((id) => secretIds.map((id) =>
@ -138,8 +170,10 @@ export class ContainersStore extends Base {
mode: values.mode, mode: values.mode,
payload_content_type: 'text/plain', payload_content_type: 'text/plain',
secret_type: 'certificate', secret_type: 'certificate',
expiration: values.expiration, algorithm: JSON.stringify({
algorithm: values.domain, domain: values.domain,
expiration: values.expiration,
}),
}; };
const contentData = { const contentData = {
...commonData, ...commonData,

View File

@ -15,6 +15,7 @@
import Base from 'stores/base'; import Base from 'stores/base';
import client from 'client'; import client from 'client';
import { action } from 'mobx'; import { action } from 'mobx';
import globalListenerStore from '../octavia/listener';
export class SecretsStore extends Base { export class SecretsStore extends Base {
get client() { get client() {
@ -42,11 +43,14 @@ export class SecretsStore extends Base {
get mapper() { get mapper() {
return (data) => { return (data) => {
const { secret_ref } = data; const { secret_ref, algorithm } = data;
const [, uuid] = secret_ref.split('/secrets/'); const [, uuid] = secret_ref.split('/secrets/');
const { domain, expiration } = algorithm ? JSON.parse(algorithm) : {};
return { return {
...data, ...data,
id: uuid, id: uuid,
domain,
expiration,
}; };
}; };
} }
@ -67,25 +71,70 @@ export class SecretsStore extends Base {
return data; return data;
} }
updateItem(item, listeners) {
const { secret_ref } = item;
const enabledLs = listeners.find((ls) => {
const refs = [
ls.default_tls_container_ref,
ls.client_ca_tls_container_ref,
...ls.sni_container_refs,
];
return refs.includes(secret_ref);
});
if (enabledLs) {
item.listener = {
id: enabledLs.id,
name: enabledLs.name,
lb: enabledLs.lbIds[0],
};
}
return item;
}
@action @action
async fetchDetail({ id, silent }) { async fetchDetail({ id, silent }) {
if (!silent) { if (!silent) {
this.isLoading = true; this.isLoading = true;
} }
const [item, payload] = await Promise.all([ const [item, payload, listeners] = await Promise.all([
this.client.show(id, {}, { headers: { Accept: 'application/json' } }), this.client.show(id, {}, { headers: { Accept: 'application/json' } }),
this.payloadClient.list(id, {}, { headers: { Accept: 'text/plain' } }), this.payloadClient.list(id, {}, { headers: { Accept: 'text/plain' } }),
globalListenerStore.fetchList(),
]); ]);
item.payload = payload; item.payload = payload;
// Determine if the certificate is used in the listener
this.updateItem(item, listeners);
const detail = this.mapper(item || {}); const detail = this.mapper(item || {});
this.detail = detail; this.detail = detail;
this.isLoading = false; this.isLoading = false;
return detail; return detail;
} }
async listDidFetch(items) {
if (items.length === 0) return items;
const listeners = await globalListenerStore.fetchList();
return items.map((it) => {
// Determine if the certificate is used in the listener
this.updateItem(it, listeners);
return {
...it,
};
});
}
@action @action
async create(data) { async create(data) {
return this.client.create(data); const { expiration, domain, algorithm, ...rest } = data;
const body = {
...rest,
algorithm:
algorithm ||
JSON.stringify({
domain,
expiration,
}),
};
return this.client.create(body);
} }
} }