feat: Support more functions for zun containers

1. Add some operations of zun containers
2. Support zun containers in administrator paltform

Change-Id: Ia8a7a483e72176d595f6e527979485bf322ed279
This commit is contained in:
xusongfu 2022-06-13 18:13:15 +08:00
parent e15dc5f0d6
commit 3c24d74ba2
19 changed files with 498 additions and 18 deletions

View File

@ -109,6 +109,10 @@ export const apiVersionMaps = {
key: 'X-OpenStack-Manila-API-Version',
value: '2.55',
},
zun: {
key: 'OpenStack-API-Version',
value: 'container 1.7',
},
};
export const getOpenstackApiVersion = (url) => {

View File

@ -52,6 +52,18 @@ export class ZunClient extends Base {
key: 'unpause',
method: 'post',
},
{
key: 'rebuild',
method: 'post',
},
{
key: 'kill',
method: 'post',
},
{
key: 'execute',
method: 'post',
},
],
},
];

View File

@ -23,6 +23,7 @@ import {
HomeOutlined,
AppstoreOutlined,
SwitcherOutlined,
ContainerOutlined,
} from '@ant-design/icons';
const renderMenu = (t) => {
@ -790,6 +791,30 @@ const renderMenu = (t) => {
},
],
},
{
path: '/container',
name: t('Container'),
key: 'containerAdmin',
icon: <ContainerOutlined />,
children: [
{
path: '/container/containers-admin',
name: t('Containers'),
key: 'zunContainersAdmin',
endpoints: 'zun',
level: 1,
children: [
{
path: /^\/container\/containers-admin\/detail\/.[^/]+$/,
name: t('Container Detail'),
key: 'zunContainerDetailAdmin',
level: 2,
routePath: '/container/containers-admin/detail/:id',
},
],
},
],
},
];
return menu;
};

View File

@ -370,6 +370,7 @@
"Cold Migrate": "Cold Migrate",
"Colombia": "Colombia",
"Command": "Command",
"Command was successfully executed at container {name}.": "Command was successfully executed at container {name}.",
"Commas , are not allowed to be in a tag name in order to simplify requests that specify lists of tags": "Commas , are not allowed to be in a tag name in order to simplify requests that specify lists of tags",
"Commit Latency(ms)": "Commit Latency(ms)",
"Common Server": "Common Server",
@ -425,9 +426,11 @@
"Container Detail": "Container Detail",
"Container Format": "Container Format",
"Container ID": "Container ID",
"Container Killing": "Container Killing",
"Container Name": "Container Name",
"Container Orchestration Engine": "Container Orchestration Engine",
"Container Rebooting": "Container Rebooting",
"Container Rebuilding": "Container Rebuilding",
"Container Starting": "Container Starting",
"Container Stopping": "Container Stopping",
"Container Version": "Container Version",
@ -763,6 +766,7 @@
"Edit Bandwidth Ingress Limit Rule": "Edit Bandwidth Ingress Limit Rule",
"Edit Bare Metal Node": "Edit Bare Metal Node",
"Edit Consumer": "Edit Consumer",
"Edit Container": "Edit Container",
"Edit DNAT Rule": "Edit DNAT Rule",
"Edit DSCP Marking Rule": "Edit DSCP Marking Rule",
"Edit Default Pool": "Edit Default Pool",
@ -855,6 +859,7 @@
"Ethiopia": "Ethiopia",
"Event Time": "Event Time",
"Evictions": "Evictions",
"Execute Command": "Execute Command",
"Execution Result": "Execution Result",
"Exit Policy": "Exit Policy",
"Expand": "Expand",
@ -935,6 +940,7 @@
"Forbidden User": "Forbidden User",
"Forbidden the domain will have a negative impact, all project and user in domain will be forbidden": "Forbidden the domain will have a negative impact, all project and user in domain will be forbidden",
"Force Delete": "Force Delete",
"Force Delete Container": "Force Delete Container",
"Force Delete Share Instance": "Force Delete Share Instance",
"Force release": "Force release",
"Forced Shutdown": "Forced Shutdown",
@ -1253,6 +1259,9 @@
"Keypair Detail": "Keypair Detail",
"Keypair Info": "Keypair Info",
"Keystone token is expired.": "token has expired, please check whether the server time is correct and confirm whether the token is valid",
"Kill": "Kill",
"Kill Container": "Kill Container",
"Kill Signal": "Kill Signal",
"Killed": "Killed",
"Kubernetes": "Kubernetes",
"Kuwait": "Kuwait",
@ -1384,6 +1393,7 @@
"Members": "Members",
"Memory": "Memory",
"Memory (GiB)": "Memory (GiB)",
"Memory (MiB)": "Memory (MiB)",
"Memory Optimized": "Memory Optimized",
"Memory Page": "Memory Page",
"Memory Page Size": "Memory Page Size",
@ -1489,6 +1499,7 @@
"No": "No",
"No Console": "No Console",
"No Monitor": "No Monitor",
"No Outputs": "No Outputs",
"No Proxy": "No Proxy",
"No Raid": "No Raid",
"No State": "No State",
@ -1830,6 +1841,7 @@
"Rebooting": "Rebooting",
"Rebuild": "Rebuild",
"Rebuild Block Device Mapping": "Rebuild Block Device Mapping",
"Rebuild Container": "Rebuild Container",
"Rebuild Instance": "Rebuild Instance",
"Rebuild Spawning": "Rebuild Spawning",
"Rebuilding": "Rebuilding",
@ -2031,6 +2043,7 @@
"Sierra Leone": "Sierra Leone",
"Sign Out": "Sign Out",
"Sign up": "Sign up",
"Signal to send to the container: integer or string like SIGINT. When not set, SIGKILL is set as default value and the container will exit. The supported signals varies between platform. Besides, you can omit \"SIG\" prefix.": "Signal to send to the container: integer or string like SIGINT. When not set, SIGKILL is set as default value and the container will exit. The supported signals varies between platform. Besides, you can omit \"SIG\" prefix.",
"Singapore": "Singapore",
"Size": "Size",
"Size (GiB)": "Size (GiB)",
@ -2192,13 +2205,14 @@
"The amphora instance is required for load balancing service setup and is not recommended": "The amphora instance is required for load balancing service setup and is not recommended",
"The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.",
"The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.",
"The command to execute": "The command to execute",
"The container memory size in MiB": "The container memory size in MiB",
"The creation instruction has been issued, please refresh to see the actual situation in the list.": "The creation instruction has been issued, please refresh to see the actual situation in the list.",
"The creation instruction was issued successfully, instance: {name}. \n You can wait for a few seconds to follow the changes of the list data or manually refresh the data to get the final display result.": "The creation instruction was issued successfully, instance: {name}. \n You can wait for a few seconds to follow the changes of the list data or manually refresh the data to get the final display result.",
"The current operation can be performed when the instance is online:": "The current operation can be performed when the instance is online:",
"The current operation requires the instance to be shut down:": "The current operation requires the instance to be shut down:",
"The description can be up to 255 characters long.": "The description can be up to 255 characters long.",
"The disk size in GİB for per container": "The disk size in GİB for per container",
"The disk size in GiB for per container": "The disk size in GiB for per container",
"The domain name can only be composed of letters, numbers, dashes, in A dash cannot be at the beginning or end, and a single string cannot exceed more than 63 characters, separated by dots; At most can support 30 domain names, separated by commas;The length of a single domain name does not exceed 100 characters, and the total length degree does not exceed 1024 characters.": "The domain name can only be composed of letters, numbers, dashes, in A dash cannot be at the beginning or end, and a single string cannot exceed more than 63 characters, separated by dots; At most can support 30 domain names, separated by commas;The length of a single domain name does not exceed 100 characters, and the total length degree does not exceed 1024 characters.",
"The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.": "The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.",
"The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.": "The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.",
@ -2216,6 +2230,7 @@
"The instances in the anti-affinity group are strictly allocated to different physical machines. When there are no more physical machines to allocate, the allocation fails.": "The instances in the anti-affinity group are strictly allocated to different physical machines. When there are no more physical machines to allocate, the allocation fails.",
"The ip is not within the allocated pool!": "The ip is not within the allocated pool!",
"The ip of external members can be any, including the public network ip.": "The ip of external members can be any, including the public network ip.",
"The kill signal to send": "The kill signal to send",
"The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.",
"The name cannot be modified after creation": "The name cannot be modified after creation",
"The name of the physical network to which a port is connected": "The name of the physical network to which a port is connected",

View File

@ -370,6 +370,7 @@
"Cold Migrate": "冷迁移",
"Colombia": "哥伦比亚",
"Command": "命令",
"Command was successfully executed at container {name}.": "命令已在容器 {name} 上成功执行。",
"Commas , are not allowed to be in a tag name in order to simplify requests that specify lists of tags": "标记名称中不允许使用英文逗号“,”,以简化指定标记列表的请求",
"Commit Latency(ms)": "提交延迟(毫秒)",
"Common Server": "云主机",
@ -425,9 +426,11 @@
"Container Detail": "容器详情",
"Container Format": "容器格式",
"Container ID": "容器ID",
"Container Killing": "容器终止中",
"Container Name": "容器名称",
"Container Orchestration Engine": "容器编排引擎",
"Container Rebooting": "容器重启中",
"Container Rebuilding": "容器重建中",
"Container Starting": "容器启动中",
"Container Stopping": "容器关闭中",
"Container Version": "容器版本",
@ -763,6 +766,7 @@
"Edit Bandwidth Ingress Limit Rule": "编辑带宽入方向限制",
"Edit Bare Metal Node": "编辑裸机节点",
"Edit Consumer": "编辑消费者",
"Edit Container": "编辑容器",
"Edit DNAT Rule": "编辑DNAT规则",
"Edit DSCP Marking Rule": "编辑DSCP标记规则",
"Edit Default Pool": "编辑资源池",
@ -855,6 +859,7 @@
"Ethiopia": "埃塞俄比亚",
"Event Time": "发生时间",
"Evictions": "",
"Execute Command": "执行命令",
"Execution Result": "执行结果",
"Exit Policy": "退出策略",
"Expand": "展开",
@ -935,6 +940,7 @@
"Forbidden User": "禁用用户",
"Forbidden the domain will have a negative impact, all project and user in domain will be forbidden": "禁用域后,该域下面的项目和用户都会被禁止,用户将无法登陆",
"Force Delete": "强制删除",
"Force Delete Container": "强制删除容器",
"Force Delete Share Instance": "强制删除共享实例",
"Force release": "强制释放",
"Forced Shutdown": "强制关机",
@ -1253,6 +1259,9 @@
"Keypair Detail": "密钥详情",
"Keypair Info": "密钥信息",
"Keystone token is expired.": "token已过期请检查服务器时间是否正确确认token是否有效",
"Kill": "终止",
"Kill Container": "终止容器",
"Kill Signal": "终止信号",
"Killed": "终止",
"Kubernetes": "Kubernetes",
"Kuwait": "科威特",
@ -1384,6 +1393,7 @@
"Members": "成员",
"Memory": "内存",
"Memory (GiB)": "内存 (GiB)",
"Memory (MiB)": "内存 (MiB)",
"Memory Optimized": "内存型",
"Memory Page": "内存页",
"Memory Page Size": "内存页大小",
@ -1489,6 +1499,7 @@
"No": "否",
"No Console": "",
"No Monitor": "无监控",
"No Outputs": "无输出",
"No Proxy": "无代理",
"No Raid": "",
"No State": "无状态",
@ -1830,6 +1841,7 @@
"Rebooting": "重启中",
"Rebuild": "重建",
"Rebuild Block Device Mapping": "重建块设备映射中",
"Rebuild Container": "重建容器",
"Rebuild Instance": "重建云主机",
"Rebuild Spawning": "重建孵化中",
"Rebuilding": "重建中",
@ -2031,6 +2043,7 @@
"Sierra Leone": "塞拉利昂",
"Sign Out": "退出登录",
"Sign up": "注册",
"Signal to send to the container: integer or string like SIGINT. When not set, SIGKILL is set as default value and the container will exit. The supported signals varies between platform. Besides, you can omit \"SIG\" prefix.": "发送到容器的信号:整数或字符串,如 SIGINT。未设置时SIGKILL 设置为默认值,容器将退出。支持的信号因平台而异。此外,您可以省略 \"SIG\" 前缀。",
"Singapore": "新加坡",
"Size": "容量",
"Size (GiB)": "容量 (GiB)",
@ -2192,13 +2205,14 @@
"The amphora instance is required for load balancing service setup and is not recommended": "amphora 相关的云主机为负载均衡服务搭建所需,不建议选择",
"The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "绑定的浮动IP、网卡、云硬盘等资源将自动解绑。",
"The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "证书包含证书的公钥和签名等信息证书扩展名为”pem”或”crt”您可直接输入证书内容或上传证书文件。",
"The command to execute": "要执行的命令",
"The container memory size in MiB": "以 MiB 为单位的容器内存大小",
"The creation instruction has been issued, please refresh to see the actual situation in the list.": "创建指令已下发,请刷新查看云主机列表中的实际情况。",
"The creation instruction was issued successfully, instance: {name}. \n You can wait for a few seconds to follow the changes of the list data or manually refresh the data to get the final display result.": "创建指令下发成功,实例名称:{name}。 \n 您可等待几秒关注列表数据的变更或是手动刷新数据,以获取最终展示结果。",
"The current operation can be performed when the instance is online:": "当前操作可在云主机在线状态下进行:",
"The current operation requires the instance to be shut down:": "当前操作需要云主机在关机状态下进行:",
"The description can be up to 255 characters long.": "描述最长为255字符",
"The disk size in GİB for per container": "以 GiB 为单位的容器磁盘大小",
"The disk size in GiB for per container": "以 GiB 为单位的容器磁盘大小",
"The domain name can only be composed of letters, numbers, dashes, in A dash cannot be at the beginning or end, and a single string cannot exceed more than 63 characters, separated by dots; At most can support 30 domain names, separated by commas;The length of a single domain name does not exceed 100 characters, and the total length degree does not exceed 1024 characters.": "域名只能由字母数字中划线组成中划线不能在开头或末尾单个字符串不超过63个字符字符串间以点分隔最多可支持30个域名域名间以英文逗号分隔单个域名长度不超过100个字符且总长度不超过1024个字符。",
"The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.": "检查的整个过程需要耗费 5 到 10 分钟时间,您需要耐心等待。在完成注册后,节点配置状态会重新回到可管理状态。",
"The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.": "镜像中的cloud-init或cloudbase-init服务的预制配置未同步至镜像属性, 登录名未知",
@ -2216,6 +2230,7 @@
"The instances in the anti-affinity group are strictly allocated to different physical machines. When there are no more physical machines to allocate, the allocation fails.": "将反亲和组内的云主机严格分配到不同物理机上,当没有更多物理机可分配时,则分配失败。",
"The ip is not within the allocated pool!": "该ip不在分配的资源池范围内",
"The ip of external members can be any, including the public network ip.": "外部成员的IP可以是任何IP包括公网IP。",
"The kill signal to send": "要发送的终止信号",
"The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "地址片段的最大传输单位。IPv4最小68IPv6最小1280。",
"The name cannot be modified after creation": "名称创建后不可修改",
"The name of the physical network to which a port is connected": "端口连接到的物理网络的名称",

View File

@ -14,6 +14,7 @@ import { inject, observer } from 'mobx-react';
import Base from 'containers/TabDetail';
import globalContainersStore from 'src/stores/zun/containers';
import { containerStatus } from 'resources/zun/container';
import actionConfigs from '../actions';
import BaseDetail from './BaseDetail';
export class ContainerDetail extends Base {
@ -33,6 +34,13 @@ export class ContainerDetail extends Base {
return 'container:container:get_one';
}
get actionConfigs() {
if (this.isAdminPage) {
return actionConfigs.actionConfigsAdmin;
}
return actionConfigs.actionConfigs;
}
get detailInfos() {
return [
{

View File

@ -0,0 +1,74 @@
// 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 { ModalAction } from 'containers/Action';
import globalContainersStore from 'src/stores/zun/containers';
import { checkItemAction } from 'resources/zun/container';
export class EditContainer extends ModalAction {
static id = 'edit';
static title = t('Edit Container');
static buttonText = t('Edit');
static policy = 'container:container:update';
static allowed = (item) => checkItemAction(item, 'update');
get name() {
return t('Edit Container');
}
get defaultValue() {
const { name, memory, cpu } = this.item;
return {
name,
cpu,
memory,
};
}
get formItems() {
return [
{
name: 'name',
label: t('Container Name'),
type: 'input',
placeholder: t('Container Name'),
required: true,
},
{
name: 'cpu',
label: t('CPU'),
type: 'input-int',
placeholder: t('The number of virtual cpu for this container'),
min: 1,
},
{
name: 'memory',
label: t('Memory (MiB)'),
type: 'input-int',
placeholder: t('The container memory size in MiB'),
min: 4,
},
];
}
onSubmit = (values) => {
const { uuid } = this.item;
return globalContainersStore.patch({ id: uuid }, values);
};
}
export default inject('rootStore')(observer(EditContainer));

View File

@ -0,0 +1,89 @@
// 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 { Typography } from 'antd';
import { inject, observer } from 'mobx-react';
import { ModalAction } from 'containers/Action';
import globalContainersStore from 'src/stores/zun/containers';
import { checkItemAction } from 'resources/zun/container';
import Notify from 'src/components/Notify';
export class ExecuteCommandContainer extends ModalAction {
static id = 'execute-command';
static title = t('Execute Command');
static buttonText = t('Execute Command');
static policy = 'container:container:execute';
static allowed = (item) => checkItemAction(item, 'execute');
get name() {
return t('Execute Command');
}
get showNotice() {
return false;
}
get defaultValue() {
const { name } = this.item;
return {
name,
};
}
get formItems() {
return [
{
name: 'name',
label: t('Container Name'),
type: 'label',
},
{
name: 'command',
label: t('Command'),
type: 'input',
placeholder: t('The command to execute'),
},
];
}
onSubmit = async (values) => {
const { uuid, name } = this.item;
const { command } = values;
const { Title, Paragraph } = Typography;
try {
const cb = await globalContainersStore.execute(uuid, { command });
Notify.warn(
t('Command was successfully executed at container {name}.', {
name,
}),
<>
<Title level={5}>{`${t('Command')}: ${command}`}</Title>
<Title level={5}>{`${t('Outputs')}:`}</Title>
<Paragraph>
{cb.output ? <pre>{cb.output}</pre> : t('No Outputs')}
</Paragraph>
</>
);
return Promise.resolve();
} catch (error) {
Notify.errorWithDetail(error);
return Promise.reject(error);
}
};
}
export default inject('rootStore')(observer(ExecuteCommandContainer));

View File

@ -0,0 +1,39 @@
// 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';
import { checkItemAction } from 'resources/zun/container';
export default class ForceDeleteContainer extends ConfirmAction {
get id() {
return 'force-delete';
}
get title() {
return t('Force Delete Container');
}
get actionName() {
return t('Force Delete Container');
}
get buttonText() {
return t('Force Delete');
}
policy = 'container:container:delete_force';
allowedCheckFunc = (item) => checkItemAction(item, 'delete_force');
onSubmit = (data) => globalContainersStore.forceDelete({ id: data.uuid });
}

View File

@ -0,0 +1,66 @@
// 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 { ModalAction } from 'containers/Action';
import globalContainersStore from 'src/stores/zun/containers';
import { checkItemAction } from 'resources/zun/container';
export class KillContainer extends ModalAction {
static id = 'kill';
static title = t('Kill Container');
static buttonText = t('Kill');
static policy = 'container:container:kill';
static allowed = (item) => checkItemAction(item, 'kill');
get name() {
return t('Kill Container');
}
get defaultValue() {
const { name } = this.item;
return {
name,
};
}
get formItems() {
return [
{
name: 'name',
label: t('Container Name'),
type: 'label',
},
{
name: 'signal',
label: t('Kill Signal'),
type: 'input',
placeholder: t('The kill signal to send'),
tip: t(
'Signal to send to the container: integer or string like SIGINT. When not set, SIGKILL is set as default value and the container will exit. The supported signals varies between platform. Besides, you can omit "SIG" prefix.'
),
},
];
}
onSubmit = (values) => {
const { uuid } = this.item;
const { signal } = values;
return globalContainersStore.kill(uuid, { signal });
};
}
export default inject('rootStore')(observer(KillContainer));

View File

@ -0,0 +1,83 @@
// 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 { ModalAction } from 'containers/Action';
import globalContainersStore from 'src/stores/zun/containers';
import { checkItemAction } from 'resources/zun/container';
export class RebuildContainer extends ModalAction {
static id = 'rebuild';
static title = t('Rebuild Container');
static buttonText = t('Rebuild');
static policy = 'container:container:rebuild';
static allowed = (item) => checkItemAction(item, 'rebuild');
get name() {
return t('Rebuild Container');
}
get defaultValue() {
const { name, image, image_driver } = this.item;
return {
name,
image,
image_driver,
};
}
get formItems() {
return [
{
name: 'name',
label: t('Container Name'),
type: 'label',
},
{
name: 'image',
label: t('Image'),
type: 'input',
placeholder: t('Name or ID og the container image'),
required: true,
},
{
name: 'image_driver',
label: t('Image Driver'),
placeholder: t('Image Driver'),
type: 'select',
options: [
{
label: t('Docker'),
value: 'docker',
},
{
label: t('Glance'),
value: 'glance',
},
],
allowClear: true,
},
];
}
onSubmit = (values) => {
const { uuid } = this.item;
const { name, ...rest } = values;
return globalContainersStore.rebuild(uuid, rest);
};
}
export default inject('rootStore')(observer(RebuildContainer));

View File

@ -62,26 +62,23 @@ export class StepSpec extends Base {
{
name: 'cpu',
label: t('CPU'),
type: 'input-number',
type: 'input-int',
placeholder: t('The number of virtual cpu for this container'),
min: 1,
width: 300,
},
{
name: 'memory',
label: t('Memory'),
type: 'input-number',
label: t('Memory (MiB)'),
type: 'input-int',
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'),
type: 'input-int',
placeholder: t('The disk size in GiB for per container'),
min: 1,
width: 300,
},
{
name: 'availableZone',

View File

@ -18,19 +18,41 @@ import RebootContainer from './Reboot';
import StartContainer from './Start';
import StopContainer from './Stop';
import UnpauseContainer from './Unpause';
import RebuildContainer from './Rebuild';
import EditContainer from './Edit';
import KillContainer from './Kill';
import ForceDeleteContainer from './ForceDelete';
import ExecuteCommandContainer from './ExecuteCommand';
const moreActions = [
{ action: StartContainer },
{ action: StopContainer },
{ action: RebootContainer },
{ action: KillContainer },
{ action: RebuildContainer },
{ action: DeleteContainer },
{ action: ForceDeleteContainer },
];
const actionConfigs = {
rowActions: {
firstAction: DeleteContainer,
firstAction: EditContainer,
moreActions: [
{ action: StartContainer },
{ action: StopContainer },
{ action: PauseContainer },
{ action: RebootContainer },
{ action: UnpauseContainer },
{ action: ExecuteCommandContainer },
...moreActions,
],
},
batchActions: [DeleteContainer],
primaryActions: [CreateStep],
};
export default actionConfigs;
const actionConfigsAdmin = {
rowActions: {
firstAction: EditContainer,
moreActions,
},
batchActions: [DeleteContainer],
primaryActions: [],
};
export default { actionConfigs, actionConfigsAdmin };

View File

@ -33,7 +33,10 @@ export class Containers extends Base {
}
get actionConfigs() {
return actionConfigs;
if (this.isAdminPage) {
return actionConfigs.actionConfigsAdmin;
}
return actionConfigs.actionConfigs;
}
get rowKey() {

View File

@ -38,6 +38,12 @@ export default [
component: ContainersDetail,
exact: true,
},
{ path: `${PATH}/containers-admin`, component: Containers, exact: true },
{
path: `${PATH}/containers-admin/detail/:id`,
component: ContainersDetail,
exact: true,
},
{
path: `${PATH}/capsules`,
component: Capsules,

View File

@ -106,7 +106,7 @@ export class Certificate extends Base {
render: (value) => {
return value
? value.map((it) => (
<div>
<div key={it.id}>
{this.getLinkRender(
'lbListenerDetail',
it.name,

View File

@ -68,7 +68,7 @@ export const getCertificateColumns = (self) => [
render: (value) => {
return value
? value.map((it) => (
<div>
<div key={it.id}>
{self.getLinkRender(
'lbListenerDetail',
it.name,

View File

@ -32,6 +32,8 @@ export const containerTaskStatus = {
container_stopping: t('Container Stopping'),
container_rebooting: t('Container Rebooting'),
container_deleting: t('Container Deleting'),
container_rebuilding: t('Container Rebuilding'),
container_killing: t('Container Killing'),
};
const states = {

View File

@ -55,6 +55,26 @@ export class ContainersStore extends Base {
async unpause({ id }) {
return this.client.unpause(id);
}
@action
async rebuild(id, data) {
return this.client.rebuild(id, data);
}
@action
async kill(id, data) {
return this.client.kill(id, data);
}
@action
async forceDelete({ id }) {
return this.client.delete(id, null, { force: true });
}
@action
async execute(id, data) {
return this.client.execute(id, data);
}
}
const globalContainersStore = new ContainersStore();