skyline/src/stores/nova/instance.js
Jingwei.Zhang 46a7742aa2 feat: support quota info when instance create snapshot
1. Support quota info when bfv instance create snapshot
2. Disable click submit button when snapshot quota or each type quota is insufficient

Change-Id: I8647aa9e9e8a7669eda6549ef9ab4dcdba2e3dec
2022-07-18 11:04:23 +08:00

485 lines
11 KiB
JavaScript

// 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 { action, observable } from 'mobx';
import { get } from 'lodash';
import client from 'client';
import Base from 'stores/base';
import { mapperRule } from 'resources/neutron/security-group-rule';
import { RecycleBinStore } from '../skyline/recycle-server';
export class ServerStore extends Base {
@observable
interface = {};
@observable
securityGroups = {};
@observable
interfaces = [];
@observable
serverSnapshots = [];
@observable
volumesForSnapshot = [];
get client() {
return client.nova.servers;
}
get imageClient() {
return client.glance.images;
}
get portClient() {
return client.neutron.ports;
}
get networkClient() {
return client.neutron.networks;
}
get sgClient() {
return client.neutron.securityGroups;
}
get mapper() {
return (item) => {
item.status = item.status.toLowerCase();
if (!item.flavor_info) {
item.flavor_info = item.flavor;
}
return item;
};
}
get mapperSecurityGroupRule() {
return (data) => {
const { security_group_rules = [] } = data;
return {
...data,
security_group_rules: security_group_rules.map(mapperRule),
};
};
}
listFetchByClient(params) {
return this.skylineClient.extension.servers(params);
}
get paramsFuncPage() {
return (params) => {
const { current, noReminder, ...rest } = params;
return rest;
};
}
updateParamsSortPage = (params, sortKey, sortOrder) => {
if (sortKey && sortOrder) {
params.sort_keys = sortKey;
params.sort_dirs = sortOrder === 'descend' ? 'desc' : 'asc';
}
};
@action
async fetchDetailWithoutExpiration({ id, all_projects }) {
this.isLoading = true;
const result = await this.client.show(
id,
this.getDetailParams({ all_projects })
);
const originData = get(result, this.responseKey) || result;
this.detail = this.mapperBeforeFetchProject(originData);
this.isLoading = false;
return this.detail;
}
async detailDidFetch(item, all_projects, filters) {
const { id } = item;
const { isRecycleBinDetail } = filters;
try {
if (!isRecycleBinDetail) {
const result = await this.fetchList({
uuid: id,
noReminder: true,
all_projects,
});
item.itemInList = result[0];
} else {
const store = new RecycleBinStore();
const result = await store.fetchList({ uuid: id, all_projects });
item.itemInList = result[0];
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
return item;
}
async requestList(params, originParams = {}) {
const { members, isServerGroup } = originParams;
if (members && isServerGroup && members.length === 0) {
return [];
}
const data = !this.fetchListByLimit
? await this.requestListAll(params)
: await this.requestListAllByLimit(params, 100);
return data;
}
async listDidFetch(newData, allProjects, filters) {
if (newData.length === 0) {
return newData;
}
const { members, isServerGroup, host } = filters;
const isoImages = await this.imageClient.list({ disk_format: 'iso' });
const { images } = isoImages;
if (images[0]) {
const imageId = images.map((it) => it.id);
newData.map((server) => {
if (imageId.indexOf(server.image) !== -1) {
server.iso_server = true;
}
server.tags = (server.origin_data || {}).tags || [];
return server;
});
}
if (isServerGroup) {
return newData
.filter((it) => members.indexOf(it.id) >= 0)
.map((it) => ({
...it,
tags: (it.origin_data || {}).tags || [],
}));
}
if (host) {
return newData
.filter((it) => it.host === host)
.map((it) => ({
...it,
tags: (it.origin_data || {}).tags || [],
}));
}
return newData.map((it) => ({
...it,
tags: (it.origin_data || {}).tags || [],
}));
}
@action
async fetchInterface({ id }) {
this.interface.isLoading = true;
const params = { device_id: id };
const [resData, networks] = await Promise.all([
this.portClient.list(params),
this.networkClient.list(),
]);
const interfaces = resData.ports;
const interfaceAll = [];
networks.networks.forEach((network) => {
const interfaceItem = [];
interfaces.forEach((it) => {
if (it.network_id === network.id) {
it.network_name = network.name;
interfaceItem.push(it);
}
});
if (interfaceItem.length !== 0) {
interfaceAll.push(interfaceItem);
}
});
this.interface = {
data: interfaceAll || [],
total: resData.total_count || resData.length || 0,
isLoading: false,
};
}
@action
async fetchSecurityGroup({ id }) {
this.securityGroups.isLoading = true;
const portResult = await this.portClient.list({
device_id: id,
});
const { ports = [] } = portResult;
const sgs = [];
ports.forEach((it) => sgs.push(...it.security_groups));
const sgIds = Array.from(new Set(sgs));
let sgItems = [];
try {
const result = await Promise.all(
sgIds.map((it) => this.sgClient.show(it))
);
sgItems = result.map((it) =>
this.mapperSecurityGroupRule(it.security_group)
);
} catch (e) {}
this.securityGroups = {
data: sgItems || [],
interfaces: ports,
isLoading: false,
};
}
@action
delete = async ({ id }) => {
return this.client.delete(id);
};
@action
async create(body) {
return this.submitting(this.client.create(body));
}
@action
async getConsole({ id }) {
const body = {
remote_console: {
protocol: 'vnc',
type: 'novnc',
},
};
const result = await this.client.createConsole(id, body);
this.isSubmitting = false;
return result;
}
@action
async getConsoleIronic({ id }) {
const body = {
remote_console: {
protocol: 'serial',
type: 'serial',
},
};
const result = await this.client.createConsole(id, body);
this.isSubmitting = false;
return result;
}
@action
update(id, body) {
return this.submitting(this.client.action(id, body));
}
@action
async operation({ body, id, key }) {
// set timeout to delay to fresh
let reqBody = body;
if (!reqBody) {
reqBody = {};
reqBody[key] = null;
}
return this.update(id, reqBody);
}
@action
async lock({ id }) {
return this.operation({ key: 'lock', id });
}
@action
async unlock({ id }) {
return this.operation({ key: 'unlock', id });
}
@action
async pause({ id }) {
return this.operation({ key: 'pause', id });
}
@action
async unpause({ id }) {
return this.operation({ key: 'unpause', id });
}
@action
async suspend({ id }) {
return this.operation({ key: 'suspend', id });
}
@action
async resume({ id }) {
return this.operation({ key: 'resume', id });
}
@action
async start({ id }) {
return this.operation({ key: 'os-start', id });
}
@action
async stop({ id }) {
return this.operation({ key: 'os-stop', id });
}
@action
async restore({ id }) {
return this.operation({ key: 'restore', id });
}
@action
async forceDelete({ id }) {
const body = {
forceDelete: null,
};
return this.client.action(id, body);
}
@action
async softReboot({ id }) {
const body = {
reboot: {
type: 'SOFT',
},
};
return this.operation({ body, id });
}
@action
async reboot({ id }) {
const body = {
reboot: {
type: 'HARD',
},
};
return this.operation({ body, id });
}
@action
async changePassword({ id, password }) {
const body = {
changePassword: {
adminPass: password,
},
};
return this.operation({ body, id });
}
@action
async createImage({ id, image }) {
const body = {
createImage: {
name: image,
metadata: {
usage_type: 'common',
image_type: 'snapshot',
instance_id: id,
},
},
};
return this.operation({ body, id });
}
@action
async rebuild({ id, image }) {
const body = {
rebuild: {
imageRef: image,
},
};
return this.operation({ body, id });
}
@action
async resize({ id, flavor }) {
const body = {
resize: {
flavorRef: flavor,
},
};
return this.operation({ body, id });
}
@action
async migrate({ id, body }) {
if (body) {
const newBody = {
migrate: body,
};
return this.operation({ body: newBody, id });
}
return this.operation({ key: 'migrate', id });
}
@action
async shelve({ id }) {
return this.operation({ key: 'shelve', id });
}
@action
async unshelve({ id }) {
return this.operation({ key: 'unshelve', id });
}
@action
async migrateLive({ id, body }) {
const newBody = {
'os-migrateLive': body,
};
return this.operation({ body: newBody, id });
}
@action
async removeFloatingIp({ id, body }) {
const newBody = {
removeFloatingIp: body,
};
return this.operation({ body: newBody, id });
}
@action
async addInterface({ id, body }) {
return this.submitting(this.client.interfaces.create(id, body));
}
@action
async fetchInterfaceList({ id }) {
const result = await this.client.interfaces.list(id);
this.interfaces = result.interfaceAttachments;
return result.interfaceAttachments;
}
@action
async detachInterface({ id, ports }) {
return this.submitting(
Promise.all(ports.map((port) => this.client.interfaces.delete(id, port)))
);
}
@action
async attachVolume({ id, body }) {
return this.submitting(this.client.volumeAttachments.create(id, body));
}
@action
async detachVolume({ id, volumes }) {
return this.submitting(
Promise.all(
volumes.map((item) => this.client.volumeAttachments.delete(id, item))
)
);
}
@action
setVolumesForSnapshot(volumes) {
this.volumesForSnapshot = volumes;
}
}
const globalServerStore = new ServerStore();
export default globalServerStore;