diff --git a/src/client/client/constants.js b/src/client/client/constants.js index de36d96b..c62888b4 100644 --- a/src/client/client/constants.js +++ b/src/client/client/constants.js @@ -33,6 +33,7 @@ export const endpointVersionMap = { trove: 'v1.0', manilav2: 'v2', barbican: 'v1', + zun: 'v1', magnum : 'v1', }; @@ -72,6 +73,7 @@ export const swiftBase = () => getOpenstackEndpoint('swift'); export const troveBase = () => getOpenstackEndpoint('trove'); export const manilaBase = () => getOpenstackEndpoint('manilav2'); export const barbicanBase = () => getOpenstackEndpoint('barbican'); +export const zunBase = () => getOpenstackEndpoint('zun'); export const magnumBase = () => getOpenstackEndpoint('magnum'); export const ironicOriginEndpoint = () => getOriginEndpoint('ironic'); diff --git a/src/client/index.js b/src/client/index.js index a161cf61..260ba416 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -26,6 +26,7 @@ import swift from './swift'; import trove from './trove'; import manila from './manila'; import barbican from './barbican'; +import zun from './zun'; import magnum from './magnum'; const client = { @@ -43,6 +44,7 @@ const client = { trove, manila, barbican, + zun, magnum }; diff --git a/src/client/zun/index.js b/src/client/zun/index.js new file mode 100644 index 00000000..902629eb --- /dev/null +++ b/src/client/zun/index.js @@ -0,0 +1,62 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { zunBase } from 'client/client/constants'; +import Base from '../client/base'; + +class ZunClient extends Base { + get baseUrl() { + return zunBase(); + } + + get resources() { + return [ + { + name: 'capsules', + key: 'capsules', + responseKey: 'capsule', + }, + { + name: 'containers', + key: 'containers', + responseKey: 'container', + extendOperations: [ + { + key: 'start', + method: 'post', + }, + { + key: 'stop', + method: 'post', + }, + { + key: 'pause', + method: 'post', + }, + { + key: 'reboot', + method: 'post', + }, + { + key: 'unpause', + method: 'post', + }, + ], + }, + ]; + } +} + +const zunClient = new ZunClient(); +export default zunClient; \ No newline at end of file diff --git a/src/components/FormItem/ZunVolume/index.jsx b/src/components/FormItem/ZunVolume/index.jsx new file mode 100644 index 00000000..20033eed --- /dev/null +++ b/src/components/FormItem/ZunVolume/index.jsx @@ -0,0 +1,169 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { Select, Row, Col, Form, Input } from 'antd'; +import PropTypes from 'prop-types'; +import styles from './index.less'; +import InputInt from '../InputInt'; + +export default class ZunVolume extends React.Component { + static propTypes = { + onChange: PropTypes.func, + value: PropTypes.any, + }; + + constructor(props) { + super(props); + this.state = { + type: [], + source: [], + destination: "", + cinderVolumeSize: 0, + isCinderVolume: false + }; + } + + static getDerivedStateFromProps(nextProps, prevState) { + const { type, source, cinderVolumeSize, destination } = nextProps.value || {}; + if (type !== prevState.type || source !== prevState.source || cinderVolumeSize !== prevState.cinderVolumeSize || destination !== prevState.destination) { + return { + type, + source, + cinderVolumeSize, + destination, + }; + } + return null; + } + + onChange = (value) => { + const { onChange } = this.props; + if (onChange) { + onChange(value); + } + }; + + onTypeChange = (value) => { + if (value === "cinder-new") { + this.setState( + { + isCinderVolume: true, + }, + ); + } + if (value === "cinder-available") { + this.setState( + { + isCinderVolume: false, + }, + ); + } + this.onChange({ + ...this.state, + type: value, + }); + }; + + onSourceChange = (value) => { + this.onChange({ + ...this.state, + source: value, + }); + }; + + onCinderVolumeSizeChange = (e) => { + this.onChange({ + ...this.state, + cinderVolumeSize: e + }); + }; + + onDestinationChange = (e) => { + this.onChange({ + ...this.state, + destination: e.target.value + }); + }; + + render() { + const { + type, + source, + destination, + cinderVolumeSize, + isCinderVolume + } = this.state; + const { name } = this.props; + const selectType = ( + + ); + const inputSize = ( + + ); + const inputDestination = ( + + ); + + return ( + + + + {t('Type')} + {selectType} + + + {t('Source')} + {selectSource} + + + {t('Size(GB)')} + {inputSize} + + + {t('Destination')} + {inputDestination} + + + + ); + } +} diff --git a/src/components/FormItem/ZunVolume/index.less b/src/components/FormItem/ZunVolume/index.less new file mode 100644 index 00000000..da5ea000 --- /dev/null +++ b/src/components/FormItem/ZunVolume/index.less @@ -0,0 +1,13 @@ +.zun-volume { + display: block; + margin-bottom: 8px; +} + +.label { + margin-right: 10px; + max-width: 20%; +} + +.select { + max-width: 80%; +} \ No newline at end of file diff --git a/src/layouts/menu.jsx b/src/layouts/menu.jsx index d4779b5c..44ee09e4 100644 --- a/src/layouts/menu.jsx +++ b/src/layouts/menu.jsx @@ -582,11 +582,47 @@ const renderMenu = (t) => { ], }, { - path: '/container-infra', - name: t('Container Infra'), - key: 'containerInfra', + path: '/container', + name: t('Container'), + key: 'container', icon: , children: [ + { + path: '/container/containers', + name: t('Containers'), + key: 'containers', + level: 1, + children: [ + { + path: '/container/containers/create', + name: t('Create Container'), + key: 'containersCreateContainer', + level: 2, + }, + { + path: /^\/container\/containers\/detail\/.[^/]+$/, + name: t('Containers Detail'), + key: 'containersDetail', + level: 2, + routePath: '/container/containers/detail/:id', + }, + ], + }, + { + path: '/container/capsules', + name: t('Capsules'), + key: 'capsules', + level: 1, + children: [ + { + path: /^\/container\/capsules\/detail\/.[^/]+$/, + name: t('Capsules Detail'), + key: 'capsulesDetail', + level: 2, + routePath: '/container/capsules/detail/:id', + }, + ], + }, { path: '/container-infra/clusters', name: t('Clusters'), diff --git a/src/pages/basic/routes/index.js b/src/pages/basic/routes/index.js index 32bc811d..01e6c2db 100644 --- a/src/pages/basic/routes/index.js +++ b/src/pages/basic/routes/index.js @@ -53,6 +53,9 @@ const Share = lazy(() => const ContainerInfra = lazy(() => import(/* webpackChunkName: "container-infra" */ 'pages/container-infra/App') ); +const Containers = lazy(() => + import(/* webpackChunkName: "Container" */ 'pages/container-service/App') +); const E404 = lazy(() => import(/* webpackChunkName: "E404" */ 'pages/base/containers/404') ); @@ -109,6 +112,10 @@ export default [ path: `/container-infra`, component: ContainerInfra, }, + { + path: `/container`, + component: Containers, + }, { path: '*', component: E404 }, ], }, diff --git a/src/pages/container-service/App.jsx b/src/pages/container-service/App.jsx new file mode 100644 index 00000000..014bcad1 --- /dev/null +++ b/src/pages/container-service/App.jsx @@ -0,0 +1,21 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import renderRoutes from 'utils/RouterConfig'; + +import routes from './routes'; + +const App = (props) => renderRoutes(routes, props); + +export default App; diff --git a/src/pages/container-service/containers/Capsules/Detail/BaseDetail.jsx b/src/pages/container-service/containers/Capsules/Detail/BaseDetail.jsx new file mode 100644 index 00000000..e7d64587 --- /dev/null +++ b/src/pages/container-service/containers/Capsules/Detail/BaseDetail.jsx @@ -0,0 +1,136 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from 'containers/BaseDetail'; +import React from 'react'; +import { inject, observer } from 'mobx-react'; + +export class BaseDetail extends Base { + get leftCards() { + const cards = [this.baseInfoCard, this.containersCard]; + return cards; + } + + get rightCards() { + return [this.specCard]; + } + + get baseInfoCard() { + const options = [ + { + label: t('ID'), + dataIndex: 'uuid', + }, + { + label: t('Name'), + dataIndex: 'meta_name', + }, + { + label: t('Status'), + dataIndex: 'status', + }, + { + label: t('Status Reason'), + dataIndex: 'status_reason', + }, + { + label: t('Created'), + dataIndex: 'created_at', + }, + { + label: t('Updated'), + dataIndex: 'updated_at', + }, + { + label: t('Project ID'), + dataIndex: 'project_id', + }, + { + label: t('User ID'), + dataIndex: 'user_id', + }, + ]; + + return { + title: t('Cluster Type'), + options, + }; + } + + get containersCard() { + const options = [ + { + label: t('Containers'), + dataIndex: 'containers', + render: (value) => + value.map((it) => { + return ( + + Name : {it.name}
Container ID : {it.uuid} +
+ ); + }), + }, + ]; + + return { + title: t('Containers'), + options, + }; + } + + get specCard() { + const options = [ + { + label: t('CPU'), + dataIndex: 'cpu', + }, + { + label: t('Memory'), + dataIndex: 'memory', + }, + { + label: t('Restart Policy'), + dataIndex: 'restart_policy', + }, + { + label: t('Labels'), + dataIndex: 'labels', + render: (value) => value || ' - ', + }, + { + label: t('Links'), + dataIndex: 'links', + render: (value) => + value.map((it) => { + return ( +
+ {it.href} : {it.rel} +
+ ); + }), + }, + { + label: t('Addresses'), + dataIndex: 'addresses', + render: (value) => (value.length != null ? value : '-'), + }, + ]; + + return { + title: t('Spec'), + options, + }; + } +} + +export default inject("rootStore")(observer(BaseDetail)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Capsules/Detail/index.jsx b/src/pages/container-service/containers/Capsules/Detail/index.jsx new file mode 100644 index 00000000..3fad79a0 --- /dev/null +++ b/src/pages/container-service/containers/Capsules/Detail/index.jsx @@ -0,0 +1,57 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { inject, observer } from 'mobx-react'; +import Base from 'containers/TabDetail'; +import BaseDetail from './BaseDetail'; +import globalCapsulesStore from 'src/stores/zun/capsules'; + +export class CapsulesDetail extends Base { + init() { + this.store = globalCapsulesStore; + } + + get name() { + return t('Cluster Template Detail'); + } + + get listUrl() { + return this.getRoutePath('capsules'); + } + + get policy() { + return 'container:capsule:get_one_all_projects'; + } + + get detailInfos() { + return [ + { + title: t('Name'), + dataIndex: 'name', + }, + ]; + } + + get tabs() { + return [ + { + title: t('General Info'), + key: 'general_info', + component: BaseDetail, + }, + ]; + } +} + +export default inject("rootStore")(observer(CapsulesDetail)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Capsules/actions/Create.jsx b/src/pages/container-service/containers/Capsules/actions/Create.jsx new file mode 100644 index 00000000..44fc8663 --- /dev/null +++ b/src/pages/container-service/containers/Capsules/actions/Create.jsx @@ -0,0 +1,79 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unles //required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { inject, observer } from 'mobx-react'; +import { ModalAction } from 'src/containers/Action'; +import { getYaml } from 'src/resources/heat/stack'; +import globalCapsulesStore from 'src/stores/zun/capsules'; + +export class Create extends ModalAction { + static id = 'create-capsules'; + + static title = t('Create Capsule'); + + init() { + this.store = globalCapsulesStore; + this.maxSize = 1; + } + + static allowed = () => Promise.resolve(true); + + static buttonText = t('Create Capsule'); + + static get modalSize() { + return 'middle'; + } + + get name() { + return t('Create Capsules'); + } + + static policy = 'container:capsule:create'; + + sizeValidate = (rule, value) => { + if (!value) { + return Promise.reject(t('Please select a file')); + } + const { size } = value; + if (size <= this.maxSize * 1024 * 1024 * 1024) { + return Promise.resolve(); + } + return Promise.reject( + t( + 'Please upload files smaller than { size }G on the page. It is recommended to upload files over { size }G using API.', + { size: this.maxSize } + ) + ); + }; + + get formItems() { + return [ + { + name: 'template_file', + label: t('Load Template from a file'), + type: 'textarea-from-file', + }, + ]; + } + + onSubmit = (values) => { + const y = getYaml(values.template_file); + + return this.store.create({ + template: y, + }); + }; +} + +export default inject("rootStore")(observer(Create)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Capsules/actions/Delete.jsx b/src/pages/container-service/containers/Capsules/actions/Delete.jsx new file mode 100644 index 00000000..bf5019b1 --- /dev/null +++ b/src/pages/container-service/containers/Capsules/actions/Delete.jsx @@ -0,0 +1,41 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { inject, observer } from 'mobx-react'; +import { ConfirmAction } from 'containers/Action'; +import globalCapsulesStore from 'src/stores/zun/capsules'; + +export class DeleteCapsules extends ConfirmAction { + get id() { + return 'delete'; + } + + get title() { + return t('Delete Capsules'); + } + + get actionName() { + return t('Delete Capsules'); + } + + get buttonType() { + return 'danger'; + } + + policy = 'container:capsule:delete'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => globalCapsulesStore.delete({ id: data.uuid }); +} + +export default inject("rootStore")(observer(DeleteCapsules)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Capsules/actions/index.jsx b/src/pages/container-service/containers/Capsules/actions/index.jsx new file mode 100644 index 00000000..4e5e9dc2 --- /dev/null +++ b/src/pages/container-service/containers/Capsules/actions/index.jsx @@ -0,0 +1,25 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import Create from './Create'; +import DeleteCapsules from './Delete'; + +const actionConfigs = { + rowActions: { + firstAction: DeleteCapsules, + }, + batchActions: [DeleteCapsules], + primaryActions: [Create], +}; + +export default actionConfigs; diff --git a/src/pages/container-service/containers/Capsules/index.jsx b/src/pages/container-service/containers/Capsules/index.jsx new file mode 100644 index 00000000..c6fa6fba --- /dev/null +++ b/src/pages/container-service/containers/Capsules/index.jsx @@ -0,0 +1,64 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from 'containers/List'; +import { inject, observer } from 'mobx-react'; +import actionConfigs from './actions'; +import globalCapsulesStore from 'src/stores/zun/capsules'; + +export class Capsules extends Base { + init() { + this.store = globalCapsulesStore; + this.downloadStore = globalCapsulesStore; + } + + get name() { + return t('capsules'); + } + + get policy() { + return 'container:capsule:get_all'; + } + + get actionConfigs() { + return actionConfigs; + } + + getColumns = () => [ + { + title: t('ID/Name'), + dataIndex: 'meta_name', + isLink: true, + routeName: this.getRouteName('capsulesDetail'), + idKey: 'uuid', + }, + { + title: t('Status'), + isHideable: true, + dataIndex: 'status', + }, + { + title: t('CPU'), + isHideable: true, + dataIndex: 'cpu', + }, + { + title: t('Memory'), + isHideable: true, + dataIndex: 'memory', + }, + ]; +} + +export default inject("rootStore")(observer(Capsules)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx b/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx new file mode 100644 index 00000000..7750b530 --- /dev/null +++ b/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx @@ -0,0 +1,183 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from 'containers/BaseDetail'; +import React from 'react'; +import { inject, observer } from 'mobx-react'; + +export class BaseDetail extends Base { + get leftCards() { + const cards = [this.baseInfoCard, this.miscellaneousCard]; + return cards; + } + + get rightCards() { + return [this.specCard]; + } + + get baseInfoCard() { + const options = [ + { + label: t('ID'), + dataIndex: 'uuid', + }, + { + label: t('Name'), + dataIndex: 'name', + }, + { + label: t('Status'), + dataIndex: 'status', + }, + { + label: t('Status Detail'), + dataIndex: 'status_detail', + }, + { + label: t('Status Reason'), + dataIndex: 'status_reason', + }, + { + label: t('Task State'), + dataIndex: 'task_state', + }, + { + label: t('Command'), + dataIndex: 'command', + }, + ]; + + return { + title: t('Base Info'), + options, + }; + } + + get miscellaneousCard() { + const content = ( +
+
{JSON.stringify(this.detailData.environment, null, 4)}
+
+ ); + + const options = [ + { + label: t('Host'), + dataIndex: 'host', + }, + { + label: t('Workdir'), + dataIndex: 'workdir', + }, + { + label: t('Environment'), + dataIndex: 'environment', + content + }, + { + label: t('Interactive'), + dataIndex: 'interactive', + valueRender: 'yesNo', + }, + { + label: t('Labels'), + dataIndex: 'labels', + render: (value) => value['cloud-shell'] || '-', + }, + { + label: t('Links'), + dataIndex: 'links', + render: (value) =>
{JSON.stringify(value, null, 4)}
+ }, + ]; + + return { + title: t('Miscellaneous'), + options, + }; + } + + get specCard() { + const options = [ + { + label: t('Image'), + dataIndex: 'image', + }, + { + label: t('Image Driver'), + dataIndex: 'image_driver', + }, + { + label: t('Image Pull Policy'), + dataIndex: 'image_pull_policy', + }, + { + label: t('Hostname'), + dataIndex: 'hostname', + }, + { + label: t('Runtime'), + dataIndex: 'runtime', + }, + { + label: t('CPU'), + dataIndex: 'cpu', + }, + { + label: t('Memory'), + dataIndex: 'memory', + }, + { + label: t('Disk'), + dataIndex: 'disk', + }, + { + label: t('Restart Policy'), + dataIndex: 'restart_policy', + render: (value) =>
{JSON.stringify(value, null, 4)}
+ }, + { + label: t('Auto Remove'), + dataIndex: 'auto_remove', + }, + { + label: t('Auto Heal'), + dataIndex: 'auto_heal', + }, + { + label: t('Addresses'), + dataIndex: 'addresses', + render: (value) =>
{JSON.stringify(value, null, 4)}
+ }, + { + label: t('Ports'), + dataIndex: 'ports', + render: (value) =>
{JSON.stringify(value, null, 4)}
+ }, + { + label: t('Security Groups'), + dataIndex: 'security_groups', + render: (value) =>
{JSON.stringify(value, null, 4)}
+ }, + ]; + + return { + title: t('Spec'), + labelCol: 4, + options, + }; + } +} + +export default inject("rootStore")(observer(BaseDetail)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/Detail/index.jsx b/src/pages/container-service/containers/Containers/Detail/index.jsx new file mode 100644 index 00000000..fffc4370 --- /dev/null +++ b/src/pages/container-service/containers/Containers/Detail/index.jsx @@ -0,0 +1,55 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { inject, observer } from 'mobx-react'; +import Base from 'containers/TabDetail'; +import BaseDetail from './BaseDetail'; +import globalContainersStore from 'src/stores/zun/containers'; + +export class ContainersDetail extends Base { + init() { + this.store = globalContainersStore; + } + + get name() { + return t('Containers Detail'); + } + + get listUrl() { + return this.getRoutePath('containers'); + } + + get policy() { + return 'container:container:get_one'; + } + + get detailInfos() { + return [ + { + title: t('Name'), + dataIndex: 'name', + }, + ]; + } + + get tabs() { + return [ + { + title: t('General Info'), + key: 'general_info', + component: BaseDetail, + }, + ]; + } +} + +export default inject("rootStore")(observer(ContainersDetail)) \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/actions/Delete.jsx b/src/pages/container-service/containers/Containers/actions/Delete.jsx new file mode 100644 index 00000000..1c143bd7 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/Delete.jsx @@ -0,0 +1,45 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ConfirmAction } from 'containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export default class DeleteContainers extends ConfirmAction { + get id() { + return 'delete'; + } + + get title() { + return t('Delete Container') + } + + get actionName() { + return t('Delete Container'); + } + + get buttonType() { + return 'danger'; + } + + get buttonText() { + return t('Delete'); + } + + policy = 'container:container:delete'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => + globalContainersStore.delete({ id: data.uuid }); +} diff --git a/src/pages/container-service/containers/Containers/actions/Pause.jsx b/src/pages/container-service/containers/Containers/actions/Pause.jsx new file mode 100644 index 00000000..6c2bd7dd --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/Pause.jsx @@ -0,0 +1,34 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ConfirmAction } from 'containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export default class PauseContainers extends ConfirmAction { + get id() { + return 'pause'; + } + + get title() { + return t('Pause Container') + } + + get actionName() { + return t('Pause Container'); + } + + policy = 'container:container:pause'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => globalContainersStore.pause({ id: data.uuid }); +} diff --git a/src/pages/container-service/containers/Containers/actions/Reboot.jsx b/src/pages/container-service/containers/Containers/actions/Reboot.jsx new file mode 100644 index 00000000..f3bb8771 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/Reboot.jsx @@ -0,0 +1,34 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ConfirmAction } from 'containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export default class RebootContainers extends ConfirmAction { + get id() { + return 'reboot'; + } + + get title() { + return t('Reboot Container') + } + + get actionName() { + return t('Reboot Container'); + } + + policy = 'container:container:reboot'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => globalContainersStore.reboot({ id: data.uuid }); +} diff --git a/src/pages/container-service/containers/Containers/actions/Start.jsx b/src/pages/container-service/containers/Containers/actions/Start.jsx new file mode 100644 index 00000000..d15365ce --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/Start.jsx @@ -0,0 +1,34 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ConfirmAction } from 'containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export default class StartContainers extends ConfirmAction { + get id() { + return 'start'; + } + + get title() { + return t('Start Container') + } + + get actionName() { + return t('Start Container'); + } + + policy = 'container:container:start'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => globalContainersStore.start({ id: data.uuid }); +} 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 new file mode 100644 index 00000000..5ff841da --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx @@ -0,0 +1,68 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from "components/Form"; +import { inject, observer } from "mobx-react"; + +export class StepInfo extends Base { + get title() { + return t("Info") + } + + get name() { + return t("Info") + } + + get formItems() { + return [ + { + name: "clusterName", + label: t("Cluster Name"), + type: "input", + placeholder: t("Cluster Name"), + required: true + }, + { + name: "image", + label: t("Image"), + type: "input", + placeholder: t("Name or ID og the container image"), + required: true + }, + { + name: "imageDriver", + label: t("Image Driver"), + placeholder: t("Image Driver"), + type: "select", + options: [ + { + label: t("Docker"), + value: "docker" + }, + { + label: t("Glance"), + value: "glance" + } + ], + allowClear: true + }, + { + name: "command", + label: t("Command"), + type: "input", + placeholder: t("A command that will be sent to the container"), + }, + ] + } +} + +export default inject('rootStore')(observer(StepInfo)); \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepMiscellaneous/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepMiscellaneous/index.jsx new file mode 100644 index 00000000..07b21866 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepMiscellaneous/index.jsx @@ -0,0 +1,71 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from "components/Form"; +import { inject, observer } from "mobx-react"; +import KeyValueInput from 'components/FormItem/KeyValueInput'; + +export class StepMiscellaneous extends Base { + + get title() { + return t("Miscellaneous") + } + + get name() { + return t("Miscellaneous") + } + + get formItems() { + return [ + { + name: "workingDirectory", + label: t("Working Directory"), + type: "input", + placeholder: t("The working directory for commands to run in") + }, + { + name: "environmentVariables", + label: t("Environment Variables"), + type: 'add-select', + itemComponent: KeyValueInput, + addText: t('Add Environment Variable'), + }, + { + name: "enableInteractiveMode", + label: t("Enable interactive mode"), + type: "check" + }, + { + type: "divider" + }, + { + name: "labels", + label: t("Labels"), + type: 'add-select', + itemComponent: KeyValueInput, + addText: t('Add Label'), + }, + { + type: "divider" + }, + { + name: "hints", + label: t("Scheduler Hints"), + type: "select", + mode: "tags", + placeholder: t("Type to Scheduler Hints and press enter") + } + ] + } +} + +export default inject('rootStore')(observer(StepMiscellaneous)); \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepNetworks/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepNetworks/index.jsx new file mode 100644 index 00000000..9560b6d4 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepNetworks/index.jsx @@ -0,0 +1,80 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { SecurityGroupStore } from 'stores/neutron/security-group'; +import { VirtualAdapterStore } from 'stores/neutron/virtual-adapter'; +import Base from "components/Form"; +import { inject, observer } from "mobx-react"; +import globalNetworkStore from 'src/stores/neutron/network'; +import { portColumns, portFilters } from 'src/resources/neutron/port'; +import { securityGroupColumns, securityGroupFilter } from 'src/resources/neutron/security-group'; + +export class StepNetworks extends Base { + + init() { + this.getNetworkStore(); + this.portStore = new VirtualAdapterStore(); + this.securityGroupStore = new SecurityGroupStore(); + } + + get title() { + return t("Networks") + } + + get name() { + return t("Networks") + } + + async getNetworkStore() { + await globalNetworkStore.fetchList({ project_id: this.currentProjectId }); + } + + get networking() { + return (globalNetworkStore.list.data || []).map((it) => ({ + label: it.name, + value: it.id, + })); + } + + get formItems() { + return [ + { + name: 'networkSelect', + label: t('Networks'), + type: 'network-select-table', + isMulti: true, + }, + { + name: 'ports', + type: 'select-table', + label: t('Ports'), + isMulti: true, + columns: portColumns, + filterParams: portFilters, + backendPageStore: this.portStore, + extraParams: { project_id: this.currentProjectId, device_owner: [''], admin_state_up: [true] } + }, + { + name: 'securityGroup', + label: t('Security Group'), + type: 'select-table', + backendPageStore: this.securityGroupStore, + extraParams: { project_id: this.currentProjectId }, + columns: securityGroupColumns, + filterParams: securityGroupFilter, + isMulti: true + } + ] + } +} + +export default inject('rootStore')(observer(StepNetworks)); \ No newline at end of file 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 new file mode 100644 index 00000000..3a2578a1 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx @@ -0,0 +1,136 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from "components/Form"; +import { inject, observer } from "mobx-react"; +import globalAvailabilityZoneStore from "src/stores/nova/zone"; + +export class StepSpec extends Base { + init() { + this.getAvailabilityZones(); + this.state.isMaxRetry = true; + } + + get title() { + return t("Spec"); + } + + get name() { + return t("Spec"); + } + + async getAvailabilityZones() { + await globalAvailabilityZoneStore.fetchListWithoutDetail(); + } + + get getAvailabilityZoneList() { + return (globalAvailabilityZoneStore.list.data || []).filter((it) => it.zoneState.available) + .map((it) => ({ + value: it.zoneName, + label: it.zoneName, + })); + } + + onExitPolicyChange(value) { + this.setState({ isMaxRetry: value === "on-failure" ? false : true }) + } + + get formItems() { + return [ + { + name: "hostname", + label: t("Hostname"), + type: "input", + placeholder: t("The host name of this container"), + }, + { + name: "runtime", + label: t("Runtime"), + type: "input", + placeholder: t("The runtime to create container with"), + }, + { + name: "cpu", + label: t("CPU"), + type: "input-number", + placeholder: t("The number of virtual cpu for this container"), + min: 1, + width: 300 + }, + { + name: "memory", + label: t("Memory"), + type: "input-number", + placeholder: t("The container memory size in MiB"), + min: 4, + width: 300 + }, + { + name: "disk", + label: t("Disk"), + type: "input-number", + placeholder: t("The disk size in GİB for per container"), + min: 1, + width: 300 + }, + { + name: "availableZone", + label: t("Availability Zone"), + type: "select", + options: this.getAvailabilityZoneList, + allowClear: true, + showSearch: true + }, + { + 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" + }, + ], + onChange: (val) => this.onExitPolicyChange(val), + allowClear: true, + showSearch: true + }, + { + name: "maxRetry", + label: t("Max Retry"), + type: "input-number", + placeholder: t("Retry times for 'Restart on failure' policy"), + min: 1, + disabled: this.state.isMaxRetry + }, + { + name: "enableAutoHeal", + label: t("Enable auto heal"), + type: "check" + } + ] + } +} + +export default inject('rootStore')(observer(StepSpec)); \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepVolumes/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepVolumes/index.jsx new file mode 100644 index 00000000..6605acaf --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepVolumes/index.jsx @@ -0,0 +1,52 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from "components/Form"; +import { inject, observer } from "mobx-react"; +import ZunVolume from "src/components/FormItem/ZunVolume"; +import globalVolumeStore from "src/stores/cinder/volume"; + +export class StepVolumes extends Base { + + init() { + this.globalVolumeStore = globalVolumeStore; + this.getVolumeStore(); + } + + get cinderVolume() { + return (this.globalVolumeStore.list.data || []) + .filter((it) => it.status === 'available') + .map((it) => ({ + value: it.id, + label: it.name === '' ? it.id : it.name, + })); + } + + getVolumeStore() { + this.globalVolumeStore.fetchList(); + } + + get formItems() { + return [ + { + name: "mounts", + label: t("Type"), + type: 'add-select', + optionsType: [{ label: "Existing Cinder Volume", value: "cinder-available" }, { label: "New Cinder Volume", value: "cinder-new" }], + optionsSource: this.cinderVolume, + itemComponent: ZunVolume, + }, + ] + } +} + +export default inject('rootStore')(observer(StepVolumes)); \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx new file mode 100644 index 00000000..b7e073cb --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx @@ -0,0 +1,153 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import StepInfo from './StepInfo'; +import StepSpec from './StepSpec'; +import StepVolumes from './StepVolumes'; +import StepNetworks from './StepNetworks'; +import { inject, observer } from 'mobx-react'; +import StepMiscellaneous from './StepMiscellaneous'; +import { StepAction } from 'src/containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export class StepCreate extends StepAction { + init() { + this.store = globalContainersStore; + } + + static id = "create-container"; + + static title = t("Create Container (Step)"); + + static path = "/container/containers/create"; + + static policy = "container:container:create"; + + static allowed() { + return Promise.resolve(true); + } + + get name() { + return t("Create Container"); + } + + get listUrl() { + return this.getRoutePath("containers"); + } + + get hasConfirmStep() { + return false; + } + + get steps() { + return [ + { + title: t("Info"), + component: StepInfo + }, + { + title: t("Spec"), + component: StepSpec + }, + { + title: t("Volumes"), + component: StepVolumes + }, + { + title: t("Network Config"), + component: StepNetworks + }, + { + title: t("Miscellaneous"), + component: StepMiscellaneous + } + ] + } + + onSubmit = (values) => { + const { environmentVariables, labels, mounts } = values + + const requestEnviranment = {}; + const requestLabels = {}; + const requestValumes = []; + + environmentVariables !== null ? environmentVariables.forEach((item) => { + const labelKey = item.value.key.toLowerCase().trim(); + const labelValue = item.value.value.toLowerCase().trim(); + requestEnviranment[labelKey] = labelValue; + }) : null; + + labels !== null ? labels.forEach((item) => { + const key = item.value.key.toLowerCase().trim(); + const value = item.value.value.toLowerCase().trim(); + requestLabels[key] = value; + }) : null; + + mounts !== null ? mounts.forEach((item) => { + const destination = item.value.destination; + const source = item.value.source; + const type = item.value.type; + const cinderVolumeSize = item.value.cinderVolumeSize; + item.value.isCinderVolume !== true ? requestValumes.push({ + destination: destination, + source: source, + type: type + }) : requestValumes.push({ + destination: destination, + cinderVolumeSize: cinderVolumeSize, + type: type + }) + }) : null; + + const networks = []; + const securityGroups = []; + + values.networkSelect.selectedRowKeys.forEach((item) => { + networks.push({ network: item }) + }) + + values.ports.selectedRowKeys.forEach((item) => { + networks.push({ port: item }) + }) + + values.securityGroup.selectedRowKeys.forEach((item) => { + securityGroups.push(item) + }) + + return this.store.create({ + name: values.clusterName, + image: values.image, + command: values.command, + cpu: values.cpu, + memory: values.memory, + workdir: values.workingDirectory, + labels: requestLabels, + environment: requestEnviranment, + restart_policy: { + Name: values.exitPolicy === null ? 'no' : values.exitPolicy, + MaximumRetryCount: values.maxRetry === null ? 0 : values.maxRetry, + }, + interactive: values.enableInteractiveMode, + image_driver: values.imageDriver, + security_groups: securityGroups, + nets: networks, + runtime: values.runtime, + hostname: values.hostname, + auto_heal: values.enableAutoHeal, + availability_zone: values.availableZone, + hints: values.hints, + mounts: values.mounts, + }) + } +} + +export default inject('rootStore')(observer(StepCreate)); \ No newline at end of file diff --git a/src/pages/container-service/containers/Containers/actions/Stop.jsx b/src/pages/container-service/containers/Containers/actions/Stop.jsx new file mode 100644 index 00000000..a51126e7 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/Stop.jsx @@ -0,0 +1,36 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ConfirmAction } from 'containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export default class StopContainers extends ConfirmAction { + get id() { + return 'start'; + } + + get title() { + return t('Stop Container') + } + + get actionName() { + return t('Stop Container'); + } + + policy = 'container:container:stop'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => globalContainersStore.stop({ id: data.uuid }); +} diff --git a/src/pages/container-service/containers/Containers/actions/Unpause.jsx b/src/pages/container-service/containers/Containers/actions/Unpause.jsx new file mode 100644 index 00000000..7c73a120 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/Unpause.jsx @@ -0,0 +1,36 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ConfirmAction } from 'containers/Action'; +import globalContainersStore from 'src/stores/zun/containers'; + +export default class UnpauseContainers extends ConfirmAction { + get id() { + return 'Unpause'; + } + + get title() { + return t('Unpause Container') + } + + get actionName() { + return t('Unpause Container'); + } + + policy = 'container:container:unpause'; + + allowedCheckFunc = () => true; + + onSubmit = (data) => globalContainersStore.unpause({ id: data.uuid }); +} diff --git a/src/pages/container-service/containers/Containers/actions/index.jsx b/src/pages/container-service/containers/Containers/actions/index.jsx new file mode 100644 index 00000000..356a2e29 --- /dev/null +++ b/src/pages/container-service/containers/Containers/actions/index.jsx @@ -0,0 +1,36 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import CreateStep from './StepCreate'; +import DeleteContainer from './Delete'; +import PauseContainer from './Pause'; +import RebootContainer from './Reboot'; +import StartContainer from './Start'; +import StopContainer from './Stop'; +import UnpauseContainer from './Unpause'; + +const actionConfigs = { + rowActions: { + moreActions: [ + { action: StartContainer }, + { action: DeleteContainer }, + { action: StopContainer }, + { action: PauseContainer }, + { action: RebootContainer }, + { action: UnpauseContainer }, + ], + }, + batchActions: [DeleteContainer], + primaryActions: [CreateStep], +}; +export default actionConfigs; diff --git a/src/pages/container-service/containers/Containers/index.jsx b/src/pages/container-service/containers/Containers/index.jsx new file mode 100644 index 00000000..c9bace7b --- /dev/null +++ b/src/pages/container-service/containers/Containers/index.jsx @@ -0,0 +1,68 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from 'containers/List'; +import { inject, observer } from 'mobx-react'; +import actionConfigs from './actions'; +import globalContainersStore from 'src/stores/zun/containers'; + +export class Containers extends Base { + init() { + this.store = globalContainersStore; + this.downloadStore = globalContainersStore; + } + + get name() { + return t('containers'); + } + + get policy() { + return 'container:container:get_all'; + } + + get actionConfigs() { + return actionConfigs; + } + + get rowKey() { + return 'uuid'; + } + + getColumns = () => [ + { + title: t('ID/Name'), + dataIndex: 'name', + isLink: true, + routeName: this.getRouteName('containerDetail'), + idKey: 'uuid', + }, + { + title: t('Status'), + isHideable: true, + dataIndex: 'status', + }, + { + title: t('Image'), + isHideable: true, + dataIndex: 'image', + }, + { + title: t('Task State'), + isHideable: true, + dataIndex: 'task_state', + }, + ]; +} + +export default inject("rootStore")(observer(Containers)) \ No newline at end of file diff --git a/src/pages/container-service/routes/index.js b/src/pages/container-service/routes/index.js new file mode 100644 index 00000000..5b46458d --- /dev/null +++ b/src/pages/container-service/routes/index.js @@ -0,0 +1,51 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import BaseLayout from 'layouts/Basic'; +import E404 from 'pages/base/containers/404'; +import Containers from '../containers/Containers'; +import Capsules from '../containers/Capsules'; +import ContainersDetail from '../containers/Containers/Detail'; +import CapsulesDetail from '../containers/Capsules/Detail'; +import StepCreateContainer from '../containers/Containers/actions/StepCreate'; + +const PATH = '/container'; +export default [ + { + path: PATH, + component: BaseLayout, + routes: [ + // Containers + { path: `${PATH}/containers`, component: Containers, exact: true }, + { path: `${PATH}/containers/create`, component: StepCreateContainer, exact: true }, + { + path: `${PATH}/containers/detail/:id`, + component: ContainersDetail, + exact: true, + }, + { + path: `${PATH}/capsules`, + component: Capsules, + exact: true, + }, + { + path: `${PATH}/capsules/detail/:id`, + component: CapsulesDetail, + exact: true, + }, + // All + { path: '*', component: E404 }, + ], + }, +]; diff --git a/src/stores/zun/capsules.js b/src/stores/zun/capsules.js new file mode 100644 index 00000000..b787ce65 --- /dev/null +++ b/src/stores/zun/capsules.js @@ -0,0 +1,36 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from 'stores/base'; +import client from 'client'; +import { action } from 'mobx'; + +export class CapsulesStore extends Base { + get client() { + return client.zun.capsules; + } + + @action + async create(newbody) { + return this.client.create(newbody); + } + + @action + async delete({ id }) { + return this.client.delete(id); + } +} + +const globalCapsulesStore = new CapsulesStore(); +export default globalCapsulesStore; diff --git a/src/stores/zun/containers.js b/src/stores/zun/containers.js new file mode 100644 index 00000000..3ad667ac --- /dev/null +++ b/src/stores/zun/containers.js @@ -0,0 +1,61 @@ +// Copyright 2021 99cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Base from 'stores/base'; +import client from 'client'; +import { action } from 'mobx'; + +export class ContainersStore extends Base { + get client() { + return client.zun.containers; + } + + @action + async create(newbody) { + return this.submitting(this.client.create(newbody)); + } + + @action + async delete({ id }) { + return this.client.delete(id); + } + + @action + async start({ id }) { + return this.client.start(id); + } + + @action + async stop({ id }) { + return this.client.stop(id); + } + + @action + async pause({ id }) { + return this.client.pause(id); + } + + @action + async reboot({ id }) { + return this.client.reboot(id); + } + + @action + async unpause({ id }) { + return this.client.unpause(id); + } +} + +const globalContainersStore = new ContainersStore(); +export default globalContainersStore; \ No newline at end of file