diff --git a/src/locales/en.json b/src/locales/en.json index 0b68de03..66b5f738 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -2352,7 +2352,7 @@ "The name of the physical network to which a port is connected": "The name of the physical network to which a port is connected", "The name should contain letter or number, the length is 1 to 16, characters can only contain \"0-9, a-z, A-Z, -, _.\"": "The name should contain letter or number, the length is 1 to 16, characters can only contain \"0-9, a-z, A-Z, -, _.\"", "The name should contain letter or number, the length is 2 to 64, characters can only contain \"0-9, a-z, A-Z, -, _.\"": "The name should contain letter or number, the length is 2 to 64, characters can only contain \"0-9, a-z, A-Z, -, _.\"", - "The name should start with letter or number, characters can only contain \"0-9, a-z, A-Z, -, _, .\"": "The name should start with letter or number, characters can only contain \"0-9, a-z, A-Z, -, _, .\"", + "The name should start with letter or number, and be a string of 2 to 255, characters can only contain \"0-9, a-z, A-Z, -, _, .\"": "The name should start with letter or number, and be a string of 2 to 255, characters can only contain \"0-9, a-z, A-Z, -, _, .\"", "The name should start with upper letter or lower letter, and be a string of 1 to 128, characters can only contain \"0-9, a-z, A-Z, \"-'_()[].:^\".": "The name should start with upper letter or lower letter, and be a string of 1 to 128, characters can only contain \"0-9, a-z, A-Z, \"-'_()[].:^\".", "The name should start with upper letter or lower letter, characters can only contain \"0-9, a-z, A-Z, -, _, .\"": "The name should start with upper letter or lower letter, characters can only contain \"0-9, a-z, A-Z, -, _, .\"", "The name should start with upper letter, lower letter or chinese, and be a string of 1 to 128, characters can only contain \"0-9, a-z, A-Z, \"-'_()[].\".": "The name should start with upper letter, lower letter or chinese, and be a string of 1 to 128, characters can only contain \"0-9, a-z, A-Z, \"-'_()[].\".", diff --git a/src/locales/zh.json b/src/locales/zh.json index d704eb60..c8f72544 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -2352,7 +2352,7 @@ "The name of the physical network to which a port is connected": "端口连接到的物理网络的名称", "The name should contain letter or number, the length is 1 to 16, characters can only contain \"0-9, a-z, A-Z, -, _.\"": "名称应包含字母或数字,长度为 1 到 16,且字符只能包含“0-9、a-z、A-Z、-、_”。", "The name should contain letter or number, the length is 2 to 64, characters can only contain \"0-9, a-z, A-Z, -, _.\"": "名称应包含字母或数字,长度为 2 到 64,且字符只能包含“0-9、a-z、A-Z、-、_”。", - "The name should start with letter or number, characters can only contain \"0-9, a-z, A-Z, -, _, .\"": "名称应以字母或数字开头,且只包含“0-9, a-z, A-Z, -, _, .”。", + "The name should start with letter or number, and be a string of 2 to 255, characters can only contain \"0-9, a-z, A-Z, -, _, .\"": "名称应以字母或数字开头,长度为 2 到 255,且只包含“0-9, a-z, A-Z, -, _, .”。", "The name should start with upper letter or lower letter, and be a string of 1 to 128, characters can only contain \"0-9, a-z, A-Z, \"-'_()[].:^\".": "名称应以大写字母或小写字母开头,最长为128字符,且只包含“0-9, a-z, A-Z, \"'-_()[].:^”。", "The name should start with upper letter or lower letter, characters can only contain \"0-9, a-z, A-Z, -, _, .\"": "名称应以大写字母或小写字母开头,且字符只能包含“0-9、a-z、A-Z、-、_、.”。", "The name should start with upper letter, lower letter or chinese, and be a string of 1 to 128, characters can only contain \"0-9, a-z, A-Z, \"-'_()[].\".": "名称应以大写字母,小写字母或中文开头,最长为128字符,且只包含“0-9, a-z, A-Z, \"'-_()[].”。", diff --git a/src/pages/container-service/containers/Capsules/index.jsx b/src/pages/container-service/containers/Capsules/index.jsx index 029d3afb..663a60c1 100644 --- a/src/pages/container-service/containers/Capsules/index.jsx +++ b/src/pages/container-service/containers/Capsules/index.jsx @@ -16,6 +16,7 @@ import Base from 'containers/List'; import { inject, observer } from 'mobx-react'; import globalCapsulesStore from 'stores/zun/capsules'; import { capsuleStatus } from 'resources/zun/capsule'; +import { getOptions } from 'utils'; import actionConfigs from './actions'; export class Capsules extends Base { @@ -63,6 +64,20 @@ export class Capsules extends Base { }, ]; } + + get searchFilters() { + return [ + { + label: t('Name'), + name: 'name', + }, + { + label: t('Status'), + name: 'status', + options: getOptions(capsuleStatus), + }, + ]; + } } export default inject('rootStore')(observer(Capsules)); diff --git a/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx b/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx index 524ce49d..8ecf7f00 100644 --- a/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx +++ b/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx @@ -15,7 +15,11 @@ import Base from 'containers/BaseDetail'; import React from 'react'; import { inject, observer } from 'mobx-react'; -import { containerStatus } from 'resources/zun/container'; +import { + containerStatus, + imageDrivers, + exitPolicies, +} from 'resources/zun/container'; import { stringifyContent } from 'utils/content'; import { isEmpty } from 'lodash'; @@ -34,14 +38,22 @@ export class BaseDetail extends Base { } get baseInfoCard() { + const { image, imageInfo } = this.detailData || {}; + const imageUrl = imageInfo + ? this.getLinkRender('imageDetail', imageInfo.name, { + id: imageInfo.id, + }) + : image; + const options = [ { label: t('Image'), - dataIndex: 'image', + content: imageUrl, }, { label: t('Image Driver'), dataIndex: 'image_driver', + valueMap: imageDrivers, }, { label: t('Status Detail'), @@ -135,7 +147,7 @@ export class BaseDetail extends Base { return (

- {t('Name')}: {Name} + {t('Name')}: {exitPolicies[Name]}

{t('Max Retry')}: {MaximumRetryCount} diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx index 973f5e19..0bb652cf 100644 --- a/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx @@ -12,13 +12,13 @@ import Base from 'components/Form'; import { inject, observer } from 'mobx-react'; -import globalImageStore from 'src/stores/glance/image'; +import { ImageStore } from 'stores/glance/image'; import { getImageColumns } from 'resources/glance/image'; -import { toJS } from 'mobx'; +import { imageDrivers } from 'resources/zun/container'; export class StepInfo extends Base { init() { - this.getImageList(); + this.imageStore = new ImageStore(); } get title() { @@ -29,24 +29,21 @@ export class StepInfo extends Base { return t('Info'); } - async getImageList() { - await globalImageStore.fetchList(); - } - - get imageList() { - return toJS(globalImageStore.list.data || []).filter( - (it) => it.container_format === 'docker' - ); - } - get imageColumns() { return getImageColumns(this).filter( (it) => !['project_name', 'owner'].includes(it.dataIndex) ); } + get imageDriverOptions() { + return Object.entries(imageDrivers).map(([k, v]) => ({ + label: v, + value: k, + })); + } + get formItems() { - const { imageDriver } = this.state; + const { context: { image_driver } = {} } = this.props; return [ { @@ -61,7 +58,7 @@ export class StepInfo extends Base { return Promise.reject( value ? t( - 'The name should start with letter or number, characters can only contain "0-9, a-z, A-Z, -, _, ."' + 'The name should start with letter or number, and be a string of 2 to 255, characters can only contain "0-9, a-z, A-Z, -, _, ."' ) : '' ); @@ -74,38 +71,29 @@ export class StepInfo extends Base { label: t('Image Driver'), placeholder: t('Please select image driver'), type: 'select', - options: [ - { - label: t('Docker Hub'), - value: 'docker', - }, - { - label: t('Glance Image'), - value: 'glance', - }, - ], - onChange: (value) => { - this.setState({ - imageDriver: value, - }); - }, + options: this.imageDriverOptions, + onChange: (value) => + this.updateContext({ + image_driver: value, + }), required: true, }, { - name: 'image', + name: 'imageDocker', label: t('Image'), type: 'input', placeholder: t('Please input image'), required: true, - display: imageDriver === 'docker', + display: image_driver === 'docker', }, { - name: 'image', + name: 'imageGlance', label: t('Image'), type: 'select-table', - data: this.imageList, required: true, - isLoading: globalImageStore.list.isLoading, + backendPageStore: this.imageStore, + extraParams: { container_format: 'docker' }, + isLoading: this.imageStore.list.isLoading, filterParams: [ { label: t('Name'), @@ -113,7 +101,7 @@ export class StepInfo extends Base { }, ], columns: this.imageColumns, - display: imageDriver === 'glance', + display: image_driver === 'glance', }, ]; } diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx index d707674e..8e73c9fe 100644 --- a/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx @@ -13,6 +13,7 @@ import Base from 'components/Form'; import { inject, observer } from 'mobx-react'; import globalAvailabilityZoneStore from 'stores/nova/zone'; +import { exitPolicies } from 'resources/zun/container'; import ExposedPorts from '../../../components/ExposedPorts'; export class StepSpec extends Base { @@ -42,6 +43,13 @@ export class StepSpec extends Base { })); } + get exitPoliciesOptions() { + return Object.entries(exitPolicies).map(([k, v]) => ({ + label: v, + value: k, + })); + } + exposedPortValidator = (rule, value) => { const ifHaveEmpty = (value || []).some((it) => { const { value: innerValue } = it; @@ -57,7 +65,8 @@ export class StepSpec extends Base { }; get formItems() { - const { disableRetry, healthcheck } = this.state; + const { context: { exitPolicy, healthcheck } = {} } = this.props; + const disableRetry = exitPolicy !== 'on-failure'; return [ { @@ -103,27 +112,10 @@ export class StepSpec extends Base { name: 'exitPolicy', label: t('Exit Policy'), type: 'select', - options: [ - { - label: t('No'), - value: 'no', - }, - { - label: t('On failure'), - value: 'on-failure', - }, - { - label: t('Always'), - value: 'always', - }, - { - label: t('Unless Stopped'), - value: 'unless-stopped', - }, - ], + options: this.exitPoliciesOptions, onChange: (value) => - this.setState({ - disableRetry: value !== 'on-failure', + this.updateContext({ + exitPolicy: value, }), }, { @@ -153,11 +145,10 @@ export class StepSpec extends Base { name: 'healthcheck', label: t('Enable Health Check'), type: 'check', - onChange: (value) => { - this.setState({ + onChange: (value) => + this.updateContext({ healthcheck: value, - }); - }, + }), }, { name: 'healthcheck_cmd', diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx index 0b1f0519..b7726aa6 100644 --- a/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx @@ -15,7 +15,7 @@ import { message as $message } from 'antd'; import { StepAction } from 'src/containers/Action'; import globalContainersStore from 'stores/zun/containers'; import globalProjectStore from 'stores/keystone/project'; -import { isEmpty, isObject } from 'lodash'; +import { isEmpty } from 'lodash'; import StepInfo from './StepInfo'; import StepSpec from './StepSpec'; import StepVolumes from './StepVolumes'; @@ -227,7 +227,9 @@ export class StepCreate extends StepAction { environmentVariables, labels, mounts, - image, + image_driver, + imageDocker, + imageGlance, exitPolicy, maxRetry, networks, @@ -245,6 +247,7 @@ export class StepCreate extends StepAction { } = values; const body = { + image_driver, ...rest, }; @@ -359,8 +362,12 @@ export class StepCreate extends StepAction { body.entrypoint = [entrypoint]; } - if (image) { - body.image = isObject(image) ? (image.selectedRows[0] || {}).name : image; + if (imageDocker && image_driver === 'docker') { + body.image = imageDocker; + } + + if (imageGlance && image_driver === 'glance') { + body.image = imageGlance.selectedRowKeys[0]; } if (exitPolicy) { diff --git a/src/pages/container-service/containers/Containers/index.jsx b/src/pages/container-service/containers/Containers/index.jsx index f5c51f38..23badd3d 100644 --- a/src/pages/container-service/containers/Containers/index.jsx +++ b/src/pages/container-service/containers/Containers/index.jsx @@ -15,7 +15,12 @@ import Base from 'containers/List'; import { inject, observer } from 'mobx-react'; import globalContainersStore from 'src/stores/zun/containers'; -import { containerStatus, containerTaskStatus } from 'resources/zun/container'; +import { + containerStatus, + containerTaskStatus, + imageDrivers, +} from 'resources/zun/container'; +import { getOptions } from 'utils'; import actionConfigs from './actions'; export class Containers extends Base { @@ -48,17 +53,18 @@ export class Containers extends Base { routeName: this.getRouteName('zunContainerDetail'), idKey: 'uuid', }, + { + title: t('Image Driver'), + isHideable: true, + dataIndex: 'image_driver', + valueMap: imageDrivers, + }, { title: t('Status'), isHideable: true, dataIndex: 'status', valueMap: containerStatus, }, - { - title: t('Image'), - isHideable: true, - dataIndex: 'image', - }, { title: t('Task State'), isHideable: true, @@ -67,6 +73,25 @@ export class Containers extends Base { }, ]; } + + get searchFilters() { + return [ + { + label: t('Name'), + name: 'name', + }, + { + label: t('Status'), + name: 'status', + options: getOptions(containerStatus), + }, + { + label: t('Task State'), + name: 'task_state', + options: getOptions(containerTaskStatus), + }, + ]; + } } export default inject('rootStore')(observer(Containers)); diff --git a/src/pages/container-service/containers/Hosts/index.jsx b/src/pages/container-service/containers/Hosts/index.jsx index dc83982c..8b83e579 100644 --- a/src/pages/container-service/containers/Hosts/index.jsx +++ b/src/pages/container-service/containers/Hosts/index.jsx @@ -96,6 +96,15 @@ export class Hosts extends Base { }, ]; } + + get searchFilters() { + return [ + { + label: t('Name'), + name: 'name', + }, + ]; + } } export default inject('rootStore')(observer(Hosts)); diff --git a/src/pages/container-service/containers/Services/index.jsx b/src/pages/container-service/containers/Services/index.jsx index 92a9cc9d..ea27f9dd 100644 --- a/src/pages/container-service/containers/Services/index.jsx +++ b/src/pages/container-service/containers/Services/index.jsx @@ -17,6 +17,7 @@ import Base from 'containers/List'; import { inject, observer } from 'mobx-react'; import globalServicesStore from 'src/stores/zun/services'; import { serviceState } from 'resources/nova/service'; +import { getOptions } from 'utils'; export class Services extends Base { init() { @@ -78,6 +79,20 @@ export class Services extends Base { }, ]; } + + get searchFilters() { + return [ + { + label: t('Name'), + name: 'name', + }, + { + label: t('Service State'), + name: 'state', + options: getOptions(serviceState), + }, + ]; + } } export default inject('rootStore')(observer(Services)); diff --git a/src/resources/zun/container.js b/src/resources/zun/container.js index 6b64550e..67d56552 100644 --- a/src/resources/zun/container.js +++ b/src/resources/zun/container.js @@ -26,7 +26,7 @@ export const containerStatus = { }; export const containerTaskStatus = { - null: t('No Task'), + free: t('No Task'), container_creating: t('Container Creating'), container_starting: t('Container Starting'), container_stopping: t('Container Stopping'), @@ -102,3 +102,15 @@ export const checkItemAction = (item, actionName) => { const { status } = item; return validStates[actionName].includes(status); }; + +export const imageDrivers = { + docker: t('Docker Hub'), + glance: t('Glance Image'), +}; + +export const exitPolicies = { + no: t('No'), + 'on-failure': t('On failure'), + always: t('Always'), + 'unless-stopped': t('Unless Stopped'), +}; diff --git a/src/stores/zun/containers.js b/src/stores/zun/containers.js index 8039b4ac..b75251cf 100644 --- a/src/stores/zun/containers.js +++ b/src/stores/zun/containers.js @@ -22,10 +22,15 @@ export class ContainersStore extends Base { return client.zun.containers; } + get imageClient() { + return client.glance.images; + } + get mapper() { return (data) => ({ ...data, id: data.uuid, + task_state: data.task_state === null ? 'free' : data.task_state, }); } @@ -85,7 +90,7 @@ export class ContainersStore extends Base { } async detailDidFetch(item) { - const { uuid, status, addresses = {} } = item; + const { uuid, status, addresses = {}, image_driver, image } = item; let stats = {}; if (status === 'Running') { stats = (await this.client.stats.list(uuid)) || {}; @@ -100,6 +105,10 @@ export class ContainersStore extends Base { }, []) .map((it) => it.port); } + if (image_driver === 'glance') { + const info = await this.imageClient.show(image); + item.imageInfo = info; + } return { ...item, stats, networks, ports }; }