Skip to content

Commit

Permalink
F #5655: Implement Guacamole remote console (#1849)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio Betanzos authored Mar 17, 2022
1 parent 9afe48b commit 1154d56
Show file tree
Hide file tree
Showing 60 changed files with 2,778 additions and 612 deletions.
888 changes: 448 additions & 440 deletions src/fireedge/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/fireedge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"fast-xml-parser": "3.19.0",
"fs-extra": "9.0.1",
"fuse.js": "6.4.1",
"guacamole-common-js": "1.3.1",
"helmet": "4.1.1",
"http": "0.0.1-security",
"http-proxy-middleware": "1.0.5",
Expand Down
4 changes: 2 additions & 2 deletions src/fireedge/src/client/apps/sunstone/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ const Sunstone = ({ store = {}, location = '' }) => (

Sunstone.propTypes = {
location: PropTypes.string,
context: PropTypes.shape({}),
store: PropTypes.shape({}),
context: PropTypes.object,
store: PropTypes.object,
}

Sunstone.displayName = 'SunstoneApp'
Expand Down
10 changes: 10 additions & 0 deletions src/fireedge/src/client/apps/sunstone/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ const Dashboard = loadable(
const Settings = loadable(() => import('client/containers/Settings'), {
ssr: false,
})
const Guacamole = loadable(() => import('client/containers/Guacamole'), {
ssr: false,
})

export const PATH = {
DASHBOARD: '/dashboard',
SETTINGS: '/settings',
GUACAMOLE: '/guacamole/:id/:type',
}

export const ENDPOINTS = [
Expand All @@ -50,6 +54,12 @@ export const ENDPOINTS = [
position: -1,
Component: Settings,
},
{
label: 'Guacamole',
disabledSidebar: true,
path: PATH.GUACAMOLE,
Component: Guacamole,
},
]

/**
Expand Down
108 changes: 108 additions & 0 deletions src/fireedge/src/client/components/Buttons/ConsoleAction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* ------------------------------------------------------------------------- *
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
* *
* 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 { memo, useMemo, useCallback, ReactElement } from 'react'
import PropTypes from 'prop-types'
import { useHistory, generatePath } from 'react-router-dom'

import {
AppleImac2021 as VncIcon,
TerminalOutline as SshIcon,
Windows as RdpIcon,
} from 'iconoir-react'
import { SubmitButton } from 'client/components/FormControl'

import { useViews } from 'client/features/Auth'
import { useLazyGetGuacamoleSessionQuery } from 'client/features/OneApi/vm'
import {
nicsIncludesTheConnectionType,
isAvailableAction,
} from 'client/models/VirtualMachine'
import { Translate } from 'client/components/HOC'
import { T, VM, RESOURCE_NAMES, VM_ACTIONS } from 'client/constants'
import { PATH } from 'client/apps/sunstone/routes'

const GUACAMOLE_BUTTON = {
vnc: { tooltip: T.Vnc, icon: <VncIcon /> },
ssh: { tooltip: T.Ssh, icon: <SshIcon /> },
rdp: { tooltip: T.Rdp, icon: <RdpIcon /> },
}

const GuacamoleButton = memo(
/**
* @param {object} options - Options
* @param {VM} options.vm - Virtual machine
* @param {'vnc'|'ssh'|'rdp'} options.connectionType - Connection type
* @param {Function} [options.onClick] - Handle click for button
* @returns {ReactElement} - Guacamole button
*/
({ vm, connectionType, onClick }) => {
const history = useHistory()
const { view, [RESOURCE_NAMES.VM]: vmView } = useViews()
const [getSession, { isLoading }] = useLazyGetGuacamoleSessionQuery()

const isDisabled = useMemo(() => {
const noAction = vmView?.actions?.[connectionType] !== true
const noAvailable = isAvailableAction(connectionType)(vm)

return noAction || noAvailable
}, [view, vm])

const { tooltip, icon } = GUACAMOLE_BUTTON[connectionType]

const goToConsole =
onClick ??
useCallback(
async (evt) => {
try {
evt.stopPropagation()

const params = { id: vm?.ID, type: connectionType }
await getSession(params)
history.push(generatePath(PATH.GUACAMOLE, params))
} catch {}
},
[vm?.ID, connectionType, history]
)

if (
isDisabled ||
(connectionType !== VM_ACTIONS.VNC &&
!nicsIncludesTheConnectionType(vm, connectionType))
) {
return null
}

return (
<SubmitButton
data-cy={`${vm?.ID}-${connectionType}`}
icon={icon}
tooltip={<Translate word={tooltip} />}
isSubmitting={isLoading}
onClick={goToConsole}
/>
)
}
)

GuacamoleButton.propTypes = {
vm: PropTypes.object,
connectionType: PropTypes.string,
onClick: PropTypes.func,
}

GuacamoleButton.displayName = 'GuacamoleButton'

export { GuacamoleButton }
1 change: 1 addition & 0 deletions src/fireedge/src/client/components/Buttons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
* ------------------------------------------------------------------------- */

export * from 'client/components/Buttons/ScheduleAction'
export * from 'client/components/Buttons/ConsoleAction'
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ const VirtualMachineCard = memo(
* @param {object} props - Props
* @param {VM} props.vm - Virtual machine resource
* @param {object} props.rootProps - Props to root component
* @param {ReactElement} [props.actions] - Actions
* @returns {ReactElement} - Card
*/
({ vm, rootProps }) => {
({ vm, rootProps, actions }) => {
const classes = rowStyles()
const { ID, NAME, UNAME, GNAME, IPS, STIME, ETIME, LOCK } = vm

Expand Down Expand Up @@ -89,6 +90,7 @@ const VirtualMachineCard = memo(
</Stack>
</div>
)}
{actions && <div className={classes.actions}>{actions}</div>}
</div>
)
}
Expand All @@ -99,6 +101,7 @@ VirtualMachineCard.propTypes = {
rootProps: PropTypes.shape({
className: PropTypes.string,
}),
actions: PropTypes.any,
}

VirtualMachineCard.displayName = 'VirtualMachineCard'
Expand Down
Loading

0 comments on commit 1154d56

Please sign in to comment.