From bfa4c8e332f6be7512df75d614500ca8dd0db5de Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Tue, 9 Oct 2018 15:56:25 +0200 Subject: [PATCH 1/3] Add @patternfly/react-console dependency --- frontend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/package.json b/frontend/package.json index 366912298ab..3b10ee7661b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,6 +53,7 @@ ] }, "dependencies": { + "@patternfly/react-console": "^1.4.3", "brace": "0.11.x", "classnames": "2.x", "core-js": "2.x", From caf5fd3e519fa116475aeccba81410ab4ce96654 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Tue, 9 Oct 2018 15:56:58 +0200 Subject: [PATCH 2/3] Add in-browser VNC console Reuses VncConsole from pf-react. --- .../kubevirt/components/utils/resources.js | 47 +++++++++++++++ frontend/public/kubevirt/components/vm.jsx | 58 +++++++------------ .../public/kubevirt/components/vmconsoles.jsx | 52 +++++++++++++++++ frontend/public/kubevirt/module/okdk8s.ts | 3 + 4 files changed, 124 insertions(+), 36 deletions(-) create mode 100644 frontend/public/kubevirt/components/utils/resources.js create mode 100644 frontend/public/kubevirt/components/vmconsoles.jsx create mode 100644 frontend/public/kubevirt/module/okdk8s.ts diff --git a/frontend/public/kubevirt/components/utils/resources.js b/frontend/public/kubevirt/components/utils/resources.js new file mode 100644 index 00000000000..ce48ecf55a1 --- /dev/null +++ b/frontend/public/kubevirt/components/utils/resources.js @@ -0,0 +1,47 @@ +import * as _ from 'lodash-es'; +import { getCSRFToken } from '../../../co-fetch'; +import { k8sBasePath } from '../../module/okdk8s'; + +import { VirtualMachineInstanceModel } from '../../models'; + +export const getResourceKind = (model, name, namespaced, namespace, isList, matchLabels, matchExpressions) => { + let res = { kind:model.kind, namespaced, namespace, isList, prop: model.kind}; + if (name) { + res.name = name; + } + if (matchLabels) { + res.selector = {matchLabels}; + } + if (matchExpressions) { + res.selector = {matchExpressions}; + } + return res; +}; + +export const getLabelMatcher = (vm) => _.get(vm, 'spec.template.metadata.labels'); + +export const findPod = (data, name) => data.find(p => p.metadata.name.startsWith(`virt-launcher-${name}-`)); +export const findVMI = (data, name) => data.find(vmi => vmi.metadata.name === name); + +export const getFlattenForKind = (kind) => { + return resources => _.get(resources, kind, {}).data; +}; + +export const isVmiRunning = (vmi) => _.get(vmi, 'status.phase') === 'Running'; + +export const getVncConnectionDetails = vmi => { + // Example: ws://localhost:9000/api/kubernetes/apis/subresources.kubevirt.io/v1alpha2/namespaces/kube-system/virtualmachineinstances/vm-cirros1/vnc + let base = k8sBasePath; + base = base[0] === '/' ? base.substring(1) : base; // avpid the extra slash when compose the URL by VncConsole + const context = `${base}/apis/subresources.${VirtualMachineInstanceModel.apiGroup}`; + const apiPath = `${VirtualMachineInstanceModel.apiVersion}/namespaces/${vmi.metadata.namespace}/${VirtualMachineInstanceModel.path}/${vmi.metadata.name}`; + const query = `?x-csrf-token=${encodeURIComponent(getCSRFToken())}`; + const encrypt = window.location.protocol === 'https:'; + // the novnc library requires protocol to be specified so the URL must be absolute - including host:port + return { + encrypt, // whether ws or wss to be used + host: window.location.hostname, + port: window.location.port || (encrypt ? '443' : '80'), + path: `${context}/${apiPath}/vnc${query}` + }; +}; diff --git a/frontend/public/kubevirt/components/vm.jsx b/frontend/public/kubevirt/components/vm.jsx index e51d607c060..a17f10ae28b 100644 --- a/frontend/public/kubevirt/components/vm.jsx +++ b/frontend/public/kubevirt/components/vm.jsx @@ -4,17 +4,17 @@ import React, { Component, Fragment } from 'react'; import { ListHeader, ColHead, List, ListPage, ResourceRow, DetailsPage } from './factory/okdfactory'; import { breadcrumbsForOwnerRefs, Firehose, ResourceLink, navFactory, ResourceCog, Cog } from './utils/okdutils'; import { VirtualMachineInstanceModel, VirtualMachineModel, PodModel, NamespaceModel, TemplateModel } from '../models'; -import { k8sCreate } from '../../module/k8s'; -import actions from '../../module/k8s/k8s-actions'; +import { k8sCreate, actions } from '../module/okdk8s'; import { connect } from 'react-redux'; import { startStopVmModal } from './modals/start-stop-vm-modal'; import { restartVmModal } from './modals/restart-vm-modal'; +import { getResourceKind, getLabelMatcher, findVMI, findPod, getFlattenForKind } from './utils/resources'; import { CreateVmWizard, TEMPLATE_TYPE_LABEL } from 'kubevirt-web-ui-components/dist/js'; +import VmConsolesConnected from './vmconsoles'; const dashes = '---'; -const getLabelMatcher = (vm) => _.get(vm, 'spec.template.metadata.labels'); const VMHeader = props => Name @@ -88,27 +88,6 @@ const FirehoseResourceLink = props => { return dashes; }; -const findPod = (data, name) => data.find(p => p.metadata.name.startsWith(`virt-launcher-${name}-`)); -const findVMI = (data, name) => data.find(vmi => vmi.metadata.name === name); - -const getResourceKind = (model, name, namespaced, namespace, isList, matchLabels, matchExpressions) => { - let res = { kind:model.kind, namespaced, namespace, isList, prop: model.kind}; - if (name) { - res.name = name; - } - if (matchLabels) { - res.selector = {matchLabels}; - } - if (matchExpressions) { - res.selector = {matchExpressions}; - } - return res; -}; - -const getFlattenForKind = (kind) => { - return resources => _.get(resources, kind, {}).data; -}; - export const VMRow = ({obj: vm}) => { const vmResource = getResourceKind(VirtualMachineModel, vm.metadata.name, true, vm.metadata.namespace, false); const vmiResources = getResourceKind(VirtualMachineInstanceModel, vm.metadata.name, true, vm.metadata.namespace, true, getLabelMatcher(vm)); @@ -263,18 +242,25 @@ const Details = ({obj: vm}) => { ; }; -export const VirtualMachinesDetailsPage = props => breadcrumbsForOwnerRefs(obj).concat({ - name: 'Virtual Machine Details', - path: props.match.url, - })} - menuActions={menuActions} - pages={[ - navFactory.details(Details), - navFactory.editYaml() - ]} -/>; +export const VirtualMachinesDetailsPage = props => { + const pages = [navFactory.details(Details)]; + pages.push({ // TODO: might be moved based on review; or display conditionally if VM is running? + href: 'consoles', + name: 'Consoles', + component: VmConsolesConnected + }); + pages.push(navFactory.editYaml()); + return ( + breadcrumbsForOwnerRefs(obj).concat({ + name: 'Virtual Machine Details', + path: props.match.url, + })} + menuActions={menuActions} + pages={pages} + />); +}; const mapStateToProps = ({k8s}) => ({ k8s diff --git a/frontend/public/kubevirt/components/vmconsoles.jsx b/frontend/public/kubevirt/components/vmconsoles.jsx new file mode 100644 index 00000000000..35002ace3c2 --- /dev/null +++ b/frontend/public/kubevirt/components/vmconsoles.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { VncConsole } from '@patternfly/react-console'; + +import { getLabelMatcher, getResourceKind, getVncConnectionDetails, getFlattenForKind, findVMI, isVmiRunning } from './utils/resources'; +import { Firehose } from './utils/okdutils'; + +import { VirtualMachineInstanceModel } from '../models'; + +const VmIsNotRunning = () => ( +
+ Please start the VM prior accessing its console. +
+); + +/** + * Actual component for consoles. + */ +const VmConsoles = ({ vmi }) => { + if (!isVmiRunning(vmi)) { + return ; + } + + const vncConDetails = getVncConnectionDetails(vmi); + return ( +
+ +
+ ); +}; + +/** + * Helper component to keep VmConsoles dependent on VMI only. + */ +const FirehoseVmConsoles = props => { + const data = props.flatten(props.resources); + const vmi = props.filter(data); + return ; +}; + +/** + * Wrapper for VmConsoles performing asynchronous loading of API resources. + */ +const VmConsolesConnected = ({ obj: vm }) => { + const vmiResources = getResourceKind(VirtualMachineInstanceModel, vm.metadata.name, true, vm.metadata.namespace, true, getLabelMatcher(vm)); + return ( + + findVMI(data, vm.metadata.name)} /> + + ); +}; + +export default VmConsolesConnected; diff --git a/frontend/public/kubevirt/module/okdk8s.ts b/frontend/public/kubevirt/module/okdk8s.ts new file mode 100644 index 00000000000..aaaf30e888c --- /dev/null +++ b/frontend/public/kubevirt/module/okdk8s.ts @@ -0,0 +1,3 @@ +// kubevirt uses indirect references to OKD-core +export * from '../../module/k8s'; +export { default as actions } from '../../module/k8s/k8s-actions'; From 2187f0da3fc5ae29b72cd9f878b6721b4f3d0484 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Wed, 10 Oct 2018 11:03:46 +0200 Subject: [PATCH 3/3] VncConsole: render console type Text "Console: VNC" is rendered on top of the VncCOnsole component. Once design of console componenents is stabilized in pf-react, esp. around the ConsolleSwitcher component, this change will be moved to pf-react. --- frontend/public/kubevirt/_style.scss | 4 +++- frontend/public/kubevirt/components/_vmconsoles.scss | 9 +++++++++ frontend/public/kubevirt/components/vmconsoles.jsx | 10 ++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 frontend/public/kubevirt/components/_vmconsoles.scss diff --git a/frontend/public/kubevirt/_style.scss b/frontend/public/kubevirt/_style.scss index 071af6b9d96..93957b198d8 100644 --- a/frontend/public/kubevirt/_style.scss +++ b/frontend/public/kubevirt/_style.scss @@ -1,4 +1,6 @@ -@import "components/vm"; @import '~kubevirt-web-ui-components/dist/sass/components'; @import '~patternfly/dist/sass/patternfly/wizard'; @import '~patternfly/dist/sass/patternfly/forms'; + +@import 'components/vm'; +@import 'components/vmconsoles'; diff --git a/frontend/public/kubevirt/components/_vmconsoles.scss b/frontend/public/kubevirt/components/_vmconsoles.scss new file mode 100644 index 00000000000..0b340bf490a --- /dev/null +++ b/frontend/public/kubevirt/components/_vmconsoles.scss @@ -0,0 +1,9 @@ +.vnc-console .toolbar-pf-results { + border-top: none; /** Override PF default. Once approved, this should get into pf-react VncConsole*/ +} + +.vmconsoles-type { + /*position: absolute; + left: 3.5em; + */ +} diff --git a/frontend/public/kubevirt/components/vmconsoles.jsx b/frontend/public/kubevirt/components/vmconsoles.jsx index 35002ace3c2..a3f9bff0b09 100644 --- a/frontend/public/kubevirt/components/vmconsoles.jsx +++ b/frontend/public/kubevirt/components/vmconsoles.jsx @@ -12,6 +12,15 @@ const VmIsNotRunning = () => ( ); +/** + * Once design is stabilized, this will go to pf-react's VncConsole. + */ +const ConsoleType = ({ type }) => ( +
+ Console {type} +
+); + /** * Actual component for consoles. */ @@ -23,6 +32,7 @@ const VmConsoles = ({ vmi }) => { const vncConDetails = getVncConnectionDetails(vmi); return (
+
);