1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-23 22:50:09 +03:00

F #5422: Add virtual network state (#2003)

This commit is contained in:
Sergio Betanzos 2022-05-10 19:06:09 +02:00 committed by GitHub
parent 652d364b55
commit c3dd4124e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 403 additions and 102 deletions

View File

@ -40,6 +40,11 @@ actions:
filters:
label: true
state: true
owner: true
group: true
locked: true
vn_mad: true
# Info Tabs - Which info tabs are used to show extended information

View File

@ -13,57 +13,133 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { memo, ReactElement } from 'react'
import { memo, useMemo, ReactElement } from 'react'
import PropTypes from 'prop-types'
import { Typography } from '@mui/material'
import { User, Group, Lock, Server, Cloud } from 'iconoir-react'
import {
User,
Group,
Lock,
Server,
Cloud,
WarningCircledOutline as WarningIcon,
} from 'iconoir-react'
import { Box, Typography, Tooltip } from '@mui/material'
import { LinearProgressWithLabel } from 'client/components/Status'
import { getLeasesInfo, getTotalLeases } from 'client/models/VirtualNetwork'
import { useViews } from 'client/features/Auth'
import MultipleTags from 'client/components/MultipleTags'
import {
StatusCircle,
StatusChip,
LinearProgressWithLabel,
} from 'client/components/Status'
import { Tr } from 'client/components/HOC'
import { rowStyles } from 'client/components/Tables/styles'
import {
getState,
getLeasesInfo,
getVNManager,
} from 'client/models/VirtualNetwork'
import {
getColorFromString,
getUniqueLabels,
getErrorMessage,
} from 'client/models/Helper'
import {
VirtualNetwork,
T,
ACTIONS,
RESOURCE_NAMES,
VNET_THRESHOLD,
} from 'client/constants'
const NetworkCard = memo(
/**
* @param {object} props - Props
* @param {object} props.network - Network resource
* @param {VirtualNetwork} props.network - Network resource
* @param {object} props.rootProps - Props to root component
* @param {ReactElement} props.actions - Actions
* @param {function(string):Promise} [props.onDeleteLabel] - Callback to delete label
* @param {ReactElement} [props.actions] - Actions
* @returns {ReactElement} - Card
*/
({ network, rootProps, actions }) => {
({ network, rootProps, actions, onDeleteLabel }) => {
const classes = rowStyles()
const { [RESOURCE_NAMES.VM]: vmView } = useViews()
const { ID, NAME, UNAME, GNAME, LOCK, CLUSTERS, USED_LEASES, TEMPLATE } =
network
const enableEditLabels =
vmView?.actions?.[ACTIONS.EDIT_LABELS] === true && !!onDeleteLabel
const totalLeases = getTotalLeases(network)
const { percentOfUsed, percentLabel } = getLeasesInfo(network)
const totalClusters = [CLUSTERS?.ID ?? []].flat().length || 0
const provisionId = TEMPLATE?.PROVISION?.ID
const {
ID,
NAME,
UNAME,
GNAME,
LOCK,
CLUSTERS,
TEMPLATE: { PROVISION, LABELS } = {},
} = network
const provisionId = PROVISION?.ID
const { color: stateColor, name: stateName } = getState(network)
const error = useMemo(() => getErrorMessage(network), [network])
const vnMad = useMemo(() => getVNManager(network), [network?.VN_MAD])
const leasesInfo = useMemo(() => getLeasesInfo(network), [network])
const { percentOfUsed, percentLabel } = leasesInfo
const totalClusters = useMemo(
() => [CLUSTERS?.ID ?? []].flat().length || 0,
[CLUSTERS?.ID]
)
const labels = useMemo(
() =>
getUniqueLabels(LABELS).map((label) => ({
text: label,
stateColor: getColorFromString(label),
onDelete: enableEditLabels && onDeleteLabel,
})),
[LABELS, enableEditLabels, onDeleteLabel]
)
return (
<div {...rootProps} data-cy={`network-${ID}`}>
<div className={classes.main}>
<div className={classes.title}>
<StatusCircle color={stateColor} tooltip={stateName} />
<Typography component="span">{NAME}</Typography>
<span className={classes.labels}>{LOCK && <Lock />}</span>
{error && (
<Tooltip
arrow
placement="bottom"
title={<Typography variant="subtitle2">{error}</Typography>}
>
<Box color="error.dark" component="span">
<WarningIcon />
</Box>
</Tooltip>
)}
<span className={classes.labels}>
{vnMad && <StatusChip text={vnMad} />}
{LOCK && <Lock />}
<MultipleTags tags={labels} />
</span>
</div>
<div className={classes.caption}>
<span>{`#${ID}`}</span>
<span title={`Owner: ${UNAME}`}>
<span title={`${Tr(T.Owner)}: ${UNAME}`}>
<User />
<span>{` ${UNAME}`}</span>
</span>
<span title={`Group: ${GNAME}`}>
<span title={`${Tr(T.Group)}: ${GNAME}`}>
<Group />
<span>{` ${GNAME}`}</span>
</span>
<span title={`Total Clusters: ${totalClusters}`}>
<span title={`${Tr(T.TotalClusters)}: ${totalClusters}`}>
<Server />
<span>{` ${totalClusters}`}</span>
</span>
{provisionId && (
<span title={`Provision ID: #${provisionId}`}>
<span title={`${Tr(T.ProvisionId)}: #${provisionId}`}>
<Cloud />
<span>{` ${provisionId}`}</span>
</span>
@ -72,9 +148,11 @@ const NetworkCard = memo(
</div>
<div className={classes.secondary}>
<LinearProgressWithLabel
title={`Used / Total Leases: ${USED_LEASES} / ${totalLeases}`}
value={percentOfUsed}
high={VNET_THRESHOLD.LEASES.high}
low={VNET_THRESHOLD.LEASES.low}
label={percentLabel}
title={`${Tr(T.Used)} / ${Tr(T.TotalLeases)}`}
/>
</div>
{actions && <div className={classes.actions}>{actions}</div>}
@ -88,6 +166,7 @@ NetworkCard.propTypes = {
rootProps: PropTypes.shape({
className: PropTypes.string,
}),
onDeleteLabel: PropTypes.func,
actions: PropTypes.any,
}

View File

@ -33,15 +33,11 @@ import { StatusCircle, StatusChip } from 'client/components/Status'
import { Tr } from 'client/components/HOC'
import { rowStyles } from 'client/components/Tables/styles'
import {
getState,
getLastHistory,
getIps,
getErrorMessage,
} from 'client/models/VirtualMachine'
import { getState, getLastHistory, getIps } from 'client/models/VirtualMachine'
import {
timeFromMilliseconds,
getUniqueLabels,
getErrorMessage,
getColorFromString,
} from 'client/models/Helper'
import { prettyBytes } from 'client/utils'

View File

@ -13,39 +13,64 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
/* eslint-disable jsdoc/require-jsdoc */
import * as VirtualNetworkModel from 'client/models/VirtualNetwork'
import { Column } from 'react-table'
import {
getState,
getTotalLeases,
getVNManager,
} from 'client/models/VirtualNetwork'
import { T } from 'client/constants'
const getTotalOfResources = (resources) =>
[resources?.ID ?? []].flat().length || 0
export default [
{ Header: 'ID', accessor: 'ID', sortType: 'number' },
{ Header: 'Name', accessor: 'NAME' },
{ Header: 'Owner', accessor: 'UNAME' },
{ Header: 'Group', accessor: 'GNAME' },
{ Header: 'Locked', accessor: 'LOCK' },
/** @type {Column[]} VM columns */
const COLUMNS = [
{ Header: T.ID, id: 'id', accessor: 'ID', sortType: 'number' },
{ Header: T.Name, id: 'name', accessor: 'NAME' },
{
Header: 'Total Clusters',
id: 'CLUSTERS',
Header: T.State,
id: 'state',
accessor: (row) => getState(row)?.name,
},
{ Header: T.Owner, id: 'owner', accessor: 'UNAME' },
{ Header: T.Group, id: 'group', accessor: 'GNAME' },
{ Header: T.Locked, id: 'locked', accessor: 'LOCK' },
{ Header: T.Driver, id: 'vn_mad', accessor: getVNManager },
{
Header: T.TotalClusters,
id: 'clusters',
accessor: (row) => getTotalOfResources(row?.CLUSTERS),
sortType: 'number',
},
{
Header: 'Used Leases',
Header: T.UsedLeases,
id: 'used_leases',
accessor: 'USED_LEASES',
sortType: 'number',
},
{
Header: 'Total Leases',
id: 'TOTAL_LEASES',
accessor: (row) => VirtualNetworkModel.getTotalLeases(row),
Header: T.TotalLeases,
id: 'total_leases',
accessor: getTotalLeases,
sortType: 'number',
},
{
Header: 'Provision ID',
id: 'PROVISION_ID',
Header: T.ProvisionId,
id: 'provision_id',
accessor: (row) => row?.TEMPLATE?.PROVISION?.ID,
disableSortBy: true,
},
]
COLUMNS.noFilterIds = [
'id',
'name',
'clusters',
'used_leases',
'total_leases',
'provision_id',
]
export default COLUMNS

View File

@ -28,7 +28,7 @@ import {
Ownership,
AttributePanel,
} from 'client/components/Tabs/Common'
import Information from 'client/components/Tabs/VNetworkTemplate/Info/information'
import Information from 'client/components/Tabs/VNetwork/Info/information'
import { Tr } from 'client/components/HOC'
import { T } from 'client/constants'
@ -42,7 +42,7 @@ import { cloneObject, set } from 'client/utils'
const LXC_ATTRIBUTES_REG = /^LXC_/
const VCENTER_ATTRIBUTES_REG = /^VCENTER_/
const HIDDEN_ATTRIBUTES_REG =
/^(SECURITY_GROUPS|INBOUND_AVG_BW|INBOUND_PEAK_BW|INBOUND_PEAK_KB|OUTBOUND_AVG_BW|OUTBOUND_PEAK_BW|OUTBOUND_PEAK_KB)$/
/^(ERROR|SECURITY_GROUPS|INBOUND_AVG_BW|INBOUND_PEAK_BW|INBOUND_PEAK_KB|OUTBOUND_AVG_BW|OUTBOUND_PEAK_BW|OUTBOUND_PEAK_KB)$/
/**
* Renders mainly information tab.

View File

@ -17,8 +17,12 @@ import { ReactElement } from 'react'
import PropTypes from 'prop-types'
import { useRenameVNTemplateMutation } from 'client/features/OneApi/networkTemplate'
import { StatusChip } from 'client/components/Status'
import { List } from 'client/components/Tabs/Common'
import { T, VNetwork, VNET_ACTIONS } from 'client/constants'
import { getState } from 'client/models/VirtualNetwork'
import { T, VNetwork, VN_ACTIONS } from 'client/constants'
/**
* Renders mainly information tab.
@ -32,6 +36,8 @@ const InformationPanel = ({ vnet = {}, actions }) => {
const [rename] = useRenameVNTemplateMutation()
const { ID, NAME } = vnet
const { name: stateName, color: stateColor } = getState(vnet)
const handleRename = async (_, newName) => {
await rename({ id: ID, name: newName })
}
@ -42,9 +48,15 @@ const InformationPanel = ({ vnet = {}, actions }) => {
name: T.Name,
value: NAME,
dataCy: 'name',
canEdit: actions?.includes?.(VNET_ACTIONS.RENAME),
canEdit: actions?.includes?.(VN_ACTIONS.RENAME),
handleEdit: handleRename,
},
{
name: T.State,
value: (
<StatusChip dataCy="state" text={stateName} stateColor={stateColor} />
),
},
]
return (

View File

@ -34,11 +34,12 @@ import { SubmitButton } from 'client/components/FormControl'
import { Tr, Translate } from 'client/components/HOC'
import { T } from 'client/constants'
import { getHypervisor, getErrorMessage } from 'client/models/VirtualMachine'
import { getHypervisor } from 'client/models/VirtualMachine'
import {
getActionsAvailable,
filterAttributes,
jsonToXml,
getErrorMessage,
} from 'client/models/Helper'
import { cloneObject, set } from 'client/utils'

View File

@ -18,6 +18,7 @@ import COLOR from 'client/constants/color'
export const APPLICATION_STATES = [
{
// 0
name: STATES.PENDING,
color: COLOR.info.main,
meaning: `
@ -25,26 +26,31 @@ export const APPLICATION_STATES = [
it until the LCM decides to deploy it`,
},
{
// 1
name: STATES.DEPLOYING,
color: COLOR.info.main,
meaning: 'Some Tiers are being deployed',
},
{
// 2
name: STATES.RUNNING,
color: COLOR.success.main,
meaning: 'All Tiers are deployed successfully',
},
{
// 3
name: STATES.UNDEPLOYING,
color: COLOR.error.light,
meaning: 'Some Tiers are being undeployed',
},
{
// 4
name: STATES.WARNING,
color: COLOR.error.light,
meaning: 'A VM was found in a failure state',
},
{
// 5
name: STATES.DONE,
color: COLOR.error.dark,
meaning: `
@ -52,30 +58,59 @@ export const APPLICATION_STATES = [
a successful undeployment. It can be deleted`,
},
{
// 6
name: STATES.FAILED_UNDEPLOYING,
color: COLOR.error.dark,
meaning: 'An error occurred while undeploying the Application',
},
{
// 7
name: STATES.FAILED_DEPLOYING,
color: COLOR.error.dark,
meaning: 'An error occurred while deploying the Application',
},
{
// 8
name: STATES.SCALING,
color: COLOR.error.light,
meaning: 'A Tier is scaling up or down',
},
{
// 9
name: STATES.FAILED_SCALING,
color: COLOR.error.dark,
meaning: 'An error occurred while scaling the Application',
},
{
// 10
name: STATES.COOLDOWN,
color: COLOR.error.light,
meaning: 'A Tier is in the cooldown period after a scaling operation',
},
{
// 11
name: STATES.DEPLOYING_NETS,
color: COLOR.info.main,
meaning: '',
},
{
// 12
name: STATES.UNDEPLOYING_NETS,
color: COLOR.error.light,
meaning: '',
},
{
// 13
name: STATES.FAILED_DEPLOYING_NETS,
color: COLOR.error.dark,
meaning: '',
},
{
// 14
name: STATES.FAILED_UNDEPLOYING_NETS,
color: COLOR.error.dark,
meaning: '',
},
]
export const TIER_STATES = [

View File

@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import * as STATES from 'client/constants/states'
import COLOR from 'client/constants/color'
// eslint-disable-next-line no-unused-vars
import { Permissions, LockInfo } from 'client/constants/common'
import * as ACTIONS from 'client/constants/actions'
@ -21,7 +23,7 @@ import * as ACTIONS from 'client/constants/actions'
* @typedef ARLease
* @property {string} [IP] - IP
* @property {string} [IP6] - IP6
* @property {string} [IP6_GLOBAL] - IP6 globa
* @property {string} [IP6_GLOBAL] - IP6 global
* @property {string} [IP6_LINK] - IP6 link
* @property {string} [IP6_ULA] - IP6 ULA
* @property {string} MAC - MAC
@ -64,6 +66,8 @@ import * as ACTIONS from 'client/constants/actions'
* @property {string} GID - Group id
* @property {string} GNAME - Group name
* @property {Permissions} PERMISSIONS - Permissions
* @property {string|number} STATE - Current state
* @property {string|number} PREV_STATE - Previous state
* @property {LockInfo} [LOCK] - Lock information
* @property {{ ID: string|string[] }} CLUSTERS - Clusters
* @property {{ ID: string|string[] }} VROUTERS - Virtual routers
@ -97,6 +101,79 @@ import * as ACTIONS from 'client/constants/actions'
* @property {string} [TEMPLATE.VCENTER_TEMPLATE_REF] - vCenter information
*/
/** @type {STATES.StateInfo[]} Virtual Network states */
export const VN_STATES = [
{
// 0
name: STATES.INIT,
color: COLOR.info.light,
meaning: 'Initialization state, the Virtual Network object was created',
},
{
// 1
name: STATES.READY,
color: COLOR.success.main,
meaning: 'Virtual Network is ready, can execute any action',
},
{
// 2
name: STATES.LOCK_CREATE,
color: COLOR.error.light,
meaning: 'The driver initialization action is in progress',
},
{
// 3
name: STATES.LOCK_DELETE,
color: COLOR.error.light,
meaning: 'The driver delete action is in progress',
},
{
// 4
name: STATES.DONE,
color: COLOR.debug.light,
meaning: 'Network driver delete successful',
},
{
// 5
name: STATES.ERROR,
color: COLOR.error.dark,
meaning: 'Driver action failed.',
},
]
/** @enum {string} Virtual network actions */
export const VN_ACTIONS = {
CREATE_DIALOG: 'create_dialog',
DELETE: 'delete',
RECOVER: 'recover',
UPDATE: 'update',
// INFORMATION
RENAME: ACTIONS.RENAME,
CHANGE_MODE: ACTIONS.CHANGE_MODE,
CHANGE_OWNER: ACTIONS.CHANGE_OWNER,
CHANGE_GROUP: ACTIONS.CHANGE_GROUP,
}
/** @enum {string} Virtual network actions by state */
export const VN_ACTIONS_BY_STATE = {
[VN_ACTIONS.DELETE]: [STATES.READY],
[VN_ACTIONS.RECOVER]: [
STATES.INIT,
STATES.LOCK_CREATE,
STATES.LOCK_DELETE,
STATES.LOCKED,
STATES.ERROR,
],
[VN_ACTIONS.UPDATE]: [STATES.READY],
// INFORMATION
[VN_ACTIONS.RENAME]: [],
[VN_ACTIONS.CHANGE_MODE]: [],
[VN_ACTIONS.CHANGE_OWNER]: [],
[VN_ACTIONS.CHANGE_GROUP]: [],
}
/** @enum {string} Type of Addresses defined by this address range */
export const AR_TYPES = {
NONE: 'NONE',
@ -123,14 +200,10 @@ export const VN_DRIVERS = {
nodeport: 'nodeport',
}
/** @enum {string} Virtual network actions */
export const VN_ACTIONS = {
CREATE_DIALOG: 'create_dialog',
DELETE: 'delete',
// INFORMATION
RENAME: ACTIONS.RENAME,
CHANGE_MODE: ACTIONS.CHANGE_MODE,
CHANGE_OWNER: ACTIONS.CHANGE_OWNER,
CHANGE_GROUP: ACTIONS.CHANGE_GROUP,
/**
* @enum {{ high: number, low: number }}
* Virtual Network threshold to specify the maximum and minimum of the bar range
*/
export const VNET_THRESHOLD = {
LEASES: { high: 66, low: 33 },
}

View File

@ -45,6 +45,7 @@ export const COOLDOWN = 'COOLDOWN'
export const DELETE = 'DELETE'
export const DELETING = 'DELETING'
export const DEPLOYING = 'DEPLOYING'
export const DEPLOYING_NETS = 'DEPLOYING_NETS'
export const DISABLED = 'DISABLED'
export const DISK_RESIZE = 'DISK_RESIZE'
export const DISK_RESIZE_POWEROFF = 'DISK_RESIZE_POWEROFF'
@ -69,8 +70,10 @@ export const EPILOG_UNDEPLOY_FAILURE = 'EPILOG_UNDEPLOY_FAILURE'
export const ERROR = 'ERROR'
export const FAILED = 'FAILED'
export const FAILED_DEPLOYING = 'FAILED_DEPLOYING'
export const FAILED_DEPLOYING_NETS = 'FAILED_DEPLOYING_NETS'
export const FAILED_SCALING = 'FAILED_SCALING'
export const FAILED_UNDEPLOYING = 'FAILED_UNDEPLOYING'
export const FAILED_UNDEPLOYING_NETS = 'FAILED_UNDEPLOYING_NETS'
export const FAILURE = 'FAILURE'
export const HOLD = 'HOLD'
export const HOTPLUG = 'HOTPLUG'
@ -87,6 +90,8 @@ export const HOTPLUG_SAVEAS_UNDEPLOYED = 'HOTPLUG_SAVEAS_UNDEPLOYED'
export const HOTPLUG_SNAPSHOT = 'HOTPLUG_SNAPSHOT'
export const INIT = 'INIT'
export const LCM_INIT = 'LCM_INIT'
export const LOCK_CREATE = 'LOCK_CREATE'
export const LOCK_DELETE = 'LOCK_DELETE'
export const LOCKED = 'LOCKED'
export const LOCKED_USED = 'LOCKED_USED'
export const LOCKED_USED_PERS = 'LOCKED_USED_PERS'
@ -123,9 +128,11 @@ export const SHUTDOWN = 'SHUTDOWN'
export const SHUTDOWN_POWEROFF = 'SHUTDOWN_POWEROFF'
export const SHUTDOWN_UNDEPLOY = 'SHUTDOWN_UNDEPLOY'
export const STOPPED = 'STOPPED'
export const SUCCESS = 'SUCCESS'
export const SUSPENDED = 'SUSPENDED'
export const UNDEPLOYED = 'UNDEPLOYED'
export const UNDEPLOYING = 'UNDEPLOYING'
export const UNDEPLOYING_NETS = 'UNDEPLOYING_NETS'
export const UNKNOWN = 'UNKNOWN'
export const USED = 'USED'
export const USED_PERS = 'USED_PERS'

View File

@ -749,6 +749,7 @@ module.exports = {
be unshared with the group's users. Permission changed: GROUP USE`,
/* Virtual Network schema - network */
Driver: 'Driver',
IP: 'IP',
IPv4Concept: 'First IP in the range in dot notation',
IPv6Concept: 'First IP6 (full 128 bits) in the range',
@ -786,6 +787,9 @@ module.exports = {
GuestOptions: 'Guest options',
GuestMTU: 'GuestMTU',
GuestMTUConcept: 'Sets the MTU for the NICs in this network',
UsedLeases: 'Used leases',
TotalLeases: 'Total leases',
TotalClusters: 'Total clusters',
/* security group schema */
TCP: 'TCP',
@ -888,6 +892,10 @@ module.exports = {
Can be used only if IOTHREADS > 0. If this input is disabled
please first configure IOTHREADS value on OS & CPU -> Features`,
/* Provision schema */
/* Provision - general */
ProvisionId: 'Provision ID',
/* User inputs */
UserInputs: 'User Inputs',
UserInputsConcept: `

View File

@ -33,7 +33,7 @@ function VirtualNetworks() {
{selectedRows?.length > 0 && (
<Stack overflow="auto" data-cy={'detail'}>
{selectedRows?.length === 1 ? (
<VNetworkTabs id={selectedRows[0]?.values.ID} />
<VNetworkTabs id={selectedRows[0]?.original.ID} />
) : (
<Stack
direction="row"

View File

@ -14,11 +14,13 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { Actions, Commands } from 'server/utils/constants/commands/vn'
import {
oneApi,
ONE_RESOURCES,
ONE_RESOURCES_POOL,
} from 'client/features/OneApi'
import { UpdateFromSocket } from 'client/features/OneApi/socket'
import {
LockLevel,
FilterFlag,
@ -75,6 +77,40 @@ const vNetworkApi = oneApi.injectEndpoints({
},
transformResponse: (data) => data?.VNET ?? {},
providesTags: (_, __, { id }) => [{ type: VNET, id }],
async onQueryStarted({ id }, { dispatch, queryFulfilled }) {
try {
const { data: queryVNet } = await queryFulfilled
dispatch(
vNetworkApi.util.updateQueryData(
'getVNetworks',
undefined,
(draft) => {
const index = draft.findIndex(({ ID }) => +ID === +id)
index !== -1 && (draft[index] = queryVNet)
}
)
)
} catch {
dispatch(
vNetworkApi.util.updateQueryData(
'getVNetworks',
undefined,
(draft) => draft.filter(({ ID }) => +ID !== +id)
)
)
}
},
onCacheEntryAdded: ({ id }, baseQueryApi) =>
UpdateFromSocket({
updateQueryData: (updateFn) =>
vNetworkApi.util.updateQueryData(
'getVNetworks',
undefined,
updateFn
),
resource: 'net',
})(id, baseQueryApi),
}),
allocateVnet: builder.mutation({
/**

View File

@ -25,7 +25,7 @@ import { WEBSOCKET_URL, SOCKETS } from 'client/constants'
/**
* @typedef {object} HookStateMessage - Hook message from OpenNebula API
* @property {'STATE'} HOOK_TYPE - Type of event API
* @property {('VM'|'HOST'|'IMAGE')} HOOK_OBJECT - Type name of the resource
* @property {('VM'|'HOST'|'IMAGE'|'NET')} HOOK_OBJECT - Type name of the resource
* @property {string} STATE - The state that triggers the hook.
* @property {string} [LCM_STATE]
* - The LCM state that triggers the hook (Only for VM hooks)
@ -37,6 +37,7 @@ import { WEBSOCKET_URL, SOCKETS } from 'client/constants'
* @property {object} [VM] - New data of the VM
* @property {object} [HOST] - New data of the HOST
* @property {object} [IMAGE] - New data of the IMAGE
* @property {object} [VNET] - New data of the VNET
*/
/**
@ -57,13 +58,20 @@ const createWebsocket = (path, query) =>
/**
* @param {HookStateData} data - Event data from hook event STATE
* @returns {{name: ('vm'|'host'|'image'), value: object}}
* @returns {{name: ('vm'|'host'|'image'|'net'), value: object}}
* - Name and new value of resource
*/
const getResourceFromEventState = (data) => {
const { HOOK_OBJECT: name, [name]: value } = data?.HOOK_MESSAGE ?? {}
const { HOOK_OBJECT: name } = data?.HOOK_MESSAGE ?? {}
return { name: String(name).toLowerCase(), value }
const ensuredValue =
data?.HOOK_MESSAGE?.[name] ??
data?.HOOK_MESSAGE?.VM ??
data?.HOOK_MESSAGE?.HOST ??
data?.HOOK_MESSAGE?.IMAGE ??
data?.HOOK_MESSAGE?.VNET
return { name: String(name).toLowerCase(), value: ensuredValue }
}
/**

View File

@ -14,7 +14,7 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { prettyBytes } from 'client/utils'
import { DATASTORE_STATES, DATASTORE_TYPES, StateInfo } from 'client/constants'
import { DATASTORE_STATES, DATASTORE_TYPES, STATES } from 'client/constants'
/**
* Returns the datastore type name.
@ -30,7 +30,7 @@ export const getType = ({ TYPE } = {}) => DATASTORE_TYPES[TYPE]
*
* @param {object} datastore - Datastore
* @param {number} datastore.STATE - Datastore state ID
* @returns {StateInfo} - Datastore state object
* @returns {STATES.StateInfo} - Datastore state object
*/
export const getState = ({ STATE = 0 } = {}) => DATASTORE_STATES[STATE]

View File

@ -531,3 +531,15 @@ export const getColorFromString = (text, options = {}) => {
return `#${hex.padEnd(6, hex)}`
}
/**
* @param {object} resource - OpenNebula resource
* @returns {string} Error message from resource
*/
export const getErrorMessage = (resource) => {
const { USER_TEMPLATE, TEMPLATE } = resource ?? {}
const { ERROR, SCHED_MESSAGE } = USER_TEMPLATE ?? {}
const { ERROR: templateError } = TEMPLATE ?? {}
return [ERROR, SCHED_MESSAGE, templateError].filter(Boolean)[0]
}

View File

@ -19,10 +19,10 @@ import {
CUSTOM_HOST_HYPERVISOR,
Host,
HOST_STATES,
STATES,
HYPERVISORS,
NumaNode,
PciDevice,
StateInfo,
} from 'client/constants'
import { useGetOneConfigQuery } from 'client/features/OneApi/system'
@ -30,7 +30,7 @@ import { useGetOneConfigQuery } from 'client/features/OneApi/system'
* Returns information about the host state.
*
* @param {Host} host - Host
* @returns {StateInfo} Host state object
* @returns {STATES.StateInfo} Host state object
*/
export const getState = (host) => HOST_STATES[+host?.STATE ?? 0]

View File

@ -17,7 +17,7 @@ import {
IMAGE_TYPES,
DISK_TYPES,
IMAGE_STATES,
StateInfo,
STATES,
Image,
} from 'client/constants'
import { prettyBytes } from 'client/utils'
@ -35,7 +35,7 @@ export const getType = ({ TYPE } = {}) =>
* Returns the image state.
*
* @param {Image} image - Image
* @returns {StateInfo} - Image state information
* @returns {STATES.StateInfo} - Image state information
*/
export const getState = ({ STATE } = {}) => IMAGE_STATES[+STATE]

View File

@ -14,13 +14,13 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { prettyBytes } from 'client/utils'
import { MARKETPLACE_STATES, StateInfo, Marketplace } from 'client/constants'
import { MARKETPLACE_STATES, STATES, Marketplace } from 'client/constants'
/**
* Returns the marketplace state.
*
* @param {Marketplace} marketplace - Marketplace
* @returns {StateInfo} Marketplace state information
* @returns {STATES.StateInfo} Marketplace state information
*/
export const getState = ({ STATE } = {}) => MARKETPLACE_STATES[+STATE]

View File

@ -14,9 +14,9 @@
* limitations under the License. *
* ------------------------------------------------------------------------- */
import {
STATES,
MARKETPLACE_APP_STATES,
MARKETPLACE_APP_TYPES,
StateInfo,
} from 'client/constants'
/**
@ -33,6 +33,6 @@ export const getType = ({ TYPE = 0 } = {}) => MARKETPLACE_APP_TYPES[+TYPE]
*
* @param {object} marketplaceApp - Marketplace app
* @param {number|string} marketplaceApp.STATE - State
* @returns {StateInfo} Marketplace app state information
* @returns {STATES.StateInfo} Marketplace app state information
*/
export const getState = ({ STATE = 0 } = {}) => MARKETPLACE_APP_STATES[+STATE]

View File

@ -29,7 +29,6 @@ import {
EXTERNAL_IP_ATTRS,
HISTORY_ACTIONS,
HYPERVISORS,
StateInfo,
VM,
Disk,
Nic,
@ -97,7 +96,7 @@ export const isVCenter = (vm) => getHypervisor(vm) === HYPERVISORS.vcenter
/**
* @param {VM} vm - Virtual machine
* @returns {StateInfo} State information from resource
* @returns {STATES.StateInfo} State information from resource
*/
export const getState = (vm) => {
const { STATE, LCM_STATE } = vm ?? {}
@ -106,28 +105,6 @@ export const getState = (vm) => {
return state?.name === STATES.ACTIVE ? VM_LCM_STATES[+LCM_STATE] : state
}
/**
* @param {VM} vm - Virtual machine
* @returns {string[]} Labels from resource
*/
export const getLabels = (vm) => {
const { USER_TEMPLATE } = vm ?? {}
const { LABELS } = USER_TEMPLATE ?? {}
return LABELS?.split(',') ?? []
}
/**
* @param {VM} vm - Virtual machine
* @returns {string} Error message from resource
*/
export const getErrorMessage = (vm) => {
const { USER_TEMPLATE } = vm ?? {}
const { ERROR, SCHED_MESSAGE } = USER_TEMPLATE ?? {}
return [ERROR, SCHED_MESSAGE].filter(Boolean)[0]
}
/**
* @param {VM} vm - Virtual machine
* @returns {Disk[]} List of disks from resource

View File

@ -13,7 +13,23 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { VirtualNetwork } from 'client/constants'
import { VirtualNetwork, VN_STATES, STATES } from 'client/constants'
/**
* Returns the state of the virtual network.
*
* @param {VirtualNetwork} virtualNetwork - Virtual network
* @returns {STATES.StateInfo} State information from resource
*/
export const getState = ({ STATE = 0 } = {}) => VN_STATES[+STATE]
/**
* Returns the Virtual Network Manager name.
*
* @param {VirtualNetwork} virtualNetwork - Virtual network
* @returns {string} Virtual Network Manager
*/
export const getVNManager = (virtualNetwork) => virtualNetwork?.VN_MAD
/**
* Returns the total number of leases in the virtual network.

View File

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { ZONE_STATES, StateInfo } from 'client/constants'
import { STATES, ZONE_STATES } from 'client/constants'
/**
* Returns state information about the zone.
*
* @param {object} zone - Zone
* @param {number|string} zone.STATE - State
* @returns {StateInfo} State information
* @returns {STATES.StateInfo} State information
*/
export const getState = ({ STATE = 0 } = {}) => ZONE_STATES[+STATE]

View File

@ -137,7 +137,7 @@ module.exports = {
},
replace: {
from: postBody,
default: 1,
default: 0,
},
},
},

View File

@ -183,6 +183,11 @@ const defaults = {
'oneprovision_optional_create_command',
],
},
/** HOOK OBJECT NAMES */
hookObjectNames: {
vn: 'net',
},
}
module.exports = defaults

View File

@ -30,6 +30,7 @@ const {
defaultEmptyFunction,
defaultNamespace,
defaultMessageProblemOpennebula,
hookObjectNames,
} = defaults
const { getFireedgeConfig } = require('server/utils/yml')
@ -91,7 +92,11 @@ const fillResourceforHookConnection = (
if (!global.users[username].resourcesHooks) {
global.users[username].resourcesHooks = {}
}
global.users[username].resourcesHooks[match[1]] = parameters[0]
const resourceName = match[1]
const ensuredName = hookObjectNames[resourceName] || resourceName
global.users[username].resourcesHooks[ensuredName] = parameters[0]
}
}

View File

@ -204,6 +204,7 @@ const middlewareValidateResourceForHookConnection = (
next = () => undefined
) => {
const { id, resource, username } = getResourceDataForRequest(server)
if (
id &&
resource &&