Skip to content

Commit

Permalink
Merge pull request #832 from DanaOrr/adding-option-to-enable-rdp-service
Browse files Browse the repository at this point in the history
Bug 2099556: Adding the option to enable Rdp service in one click to windows vm
  • Loading branch information
openshift-merge-robot committed Aug 11, 2022
2 parents 059e783 + c5d1e99 commit af4e4ec
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 70 deletions.
5 changes: 4 additions & 1 deletion locales/en/plugin__kubevirt-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"<0>List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.</0><1><0>Template</0><1>metadata</1><2>ownerReferences</2></1>": "<0>List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.</0><1><0>Template</0><1>metadata</1><2>ownerReferences</2></1>",
"<0>Store the key in a project secret.</0><1>The key will be stored after the machine is created</1>": "<0>Store the key in a project secret.</0><1>The key will be stored after the machine is created</1>",
"<0>The descheduler can be used to evict a running pod to allow the pod to be rescheduled onto a more suitable node.</0><1></1><2>Note: if VirtualMachine have LiveMigration=False condition, edit is disabled.</2>": "<0>The descheduler can be used to evict a running pod to allow the pod to be rescheduled onto a more suitable node.</0><1></1><2>Note: if VirtualMachine have LiveMigration=False condition, edit is disabled.</2>",
"<0>This is a Windows VirtualMachine but no Service for the RDP (Remote Desktop Protocol) can be found.</0><1></1><2>For better experience accessing Windows console, it is recommended to use the RDP. To do so, create a service:<1><0>exposing the <2>{DEFAULT_RDP_PORT}/tcp</2> port of the VirtualMachine</0><1>using selector: <2>{TEMPLATE_VM_NAME_LABEL}: {name}</2></1><2>Example: virtctl expose VirtualMachine {name} --name {name}-rdp --port [UNIQUE_PORT] --target-port {DEFAULT_RDP_PORT} --type NodePort</2></1>Make sure, the VirtualMachine object has <3>spec.template.metadata.labels</3> set to <6>{TEMPLATE_VM_NAME_LABEL}: {name}</6></2>": "<0>This is a Windows VirtualMachine but no Service for the RDP (Remote Desktop Protocol) can be found.</0><1></1><2>For better experience accessing Windows console, it is recommended to use the RDP. To do so, create a service:<1><0>exposing the <2>{DEFAULT_RDP_PORT}/tcp</2> port of the VirtualMachine</0><1>using selector: <2>{TEMPLATE_VM_NAME_LABEL}: {name}</2></1><2>Example: virtctl expose VirtualMachine {name} --name {name}-rdp --port [UNIQUE_PORT] --target-port {DEFAULT_RDP_PORT} --type NodePort</2></1>Make sure, the VirtualMachine object has <3>spec.template.metadata.labels</3> set to <6>{TEMPLATE_VM_NAME_LABEL}: {name}</6></2>",
"<0>This is a Windows VirtualMachine but no Service for the RDP (Remote Desktop Protocol) can be found.</0><1></1><2>For better experience accessing Windows console, it is recommended to use the RDP.<1>Create RDP Service</1></2>": "<0>This is a Windows VirtualMachine but no Service for the RDP (Remote Desktop Protocol) can be found.</0><1></1><2>For better experience accessing Windows console, it is recommended to use the RDP.<1>Create RDP Service</1></2>",
"<0>Unattend.xml</0><1>Unattend can be used to configure windows setup and can be picked up several times during windows setup/configuration.</1><2><0>{t('Learn more')}</0></2>": "<0>Unattend.xml</0><1>Unattend can be used to configure windows setup and can be picked up several times during windows setup/configuration.</1><2><0>{t('Learn more')}</0></2>",
"3 (default)": "3 (default)",
"5 min": "5 min",
Expand Down Expand Up @@ -366,6 +366,7 @@
"Example: For Windows, get a link to the ": "Example: For Windows, get a link to the ",
"Example: your company name": "Example: your company name",
"Explore {{kind}} list": "Explore {{kind}} list",
"Expose RDP Service": "Expose RDP Service",
"Expose SSH access": "Expose SSH access",
"Feature highlights": "Feature highlights",
"Fedora cloud image list ": "Fedora cloud image list ",
Expand Down Expand Up @@ -646,6 +647,8 @@
"Quick Starts": "Quick Starts",
"RDP Address": "RDP Address",
"RDP Port": "RDP Port",
"RDP Service": "RDP Service",
"RDP Service is using a node port. Node port requires additional port resources.": "RDP Service is using a node port. Node port requires additional port resources.",
"Read about the latest information and key virtualization features on the Virtualization highlights.": "Read about the latest information and key virtualization features on the Virtualization highlights.",
"Read more": "Read more",
"Read only (ROX)": "Read only (ROX)",
Expand Down
12 changes: 9 additions & 3 deletions src/utils/components/Charts/ComponentReady/ComponentReady.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import React from 'react';
import MutedTextSpan from '@kubevirt-utils/components/MutedTextSpan/MutedTextSpan';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { Bullseye } from '@patternfly/react-core';
import Loading from '@kubevirt-utils/components/Loading/Loading';

type ComponentReadyProps = React.PropsWithChildren<{ isReady: boolean; text?: string }>;
type ComponentReadyProps = React.PropsWithChildren<{
isReady: boolean;
text?: string;
spinner?: boolean;
}>;

const ComponentReady: React.FC<ComponentReadyProps> = ({ isReady, children, text }) => {
const ComponentReady: React.FC<ComponentReadyProps> = ({ isReady, children, text, spinner }) => {
const { t } = useKubevirtTranslation();
return isReady ? (
<>{children}</>
) : (
<Bullseye className="ComponentReady">
<MutedTextSpan text={text || t('No data available')} />
{(!spinner || text) && <MutedTextSpan text={text || t('No data available')} />}
{spinner && <Loading />}
</Bullseye>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import ComponentReady from '@kubevirt-utils/components/Charts/ComponentReady/ComponentReady';
import React from 'react';

import { RDPConnectorProps } from '../utils/types';

import RDP from './RDP';
import RdpServiceNotConfigured from './RdpServiceNotConfigured';
import RDPServiceNotConfigured from './RDPServiceNotConfigured';

const RDPConnector: React.FC<RDPConnectorProps> = ({ rdpServiceAddressPort, vm }) => {
return rdpServiceAddressPort ? (
<RDP rdp={rdpServiceAddressPort} />
) : (
<RdpServiceNotConfigured vm={vm} />
const RDPConnector: React.FC<RDPConnectorProps> = ({
rdpServiceAddressPort,
vm,
vmi,
isLoading,
}) => {
return (
<ComponentReady isReady={!isLoading} spinner>
{rdpServiceAddressPort ? (
<RDP rdp={rdpServiceAddressPort} />
) : (
<RDPServiceNotConfigured vm={vm} vmi={vmi} />
)}
</ComponentReady>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from 'react';

import { V1VirtualMachine, V1VirtualMachineInstance } from '@kubevirt-ui/kubevirt-api/kubevirt';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { Alert, Checkbox, ModalVariant, Stack, StackItem } from '@patternfly/react-core';
import TabModal from '@kubevirt-utils/components/TabModal/TabModal';
import ExternalLink from '@kubevirt-utils/components/ExternalLink/ExternalLink';
import { NODE_PORTS_LINK } from '../utils/constants';
import { createRDPService } from '../utils/utils';

type RDPServiceModalProps = {
vmi: V1VirtualMachineInstance;
vm: V1VirtualMachine;
isOpen: boolean;
onClose: () => void;
};

const RDPServiceModal: React.FC<RDPServiceModalProps> = ({ vmi, vm, isOpen, onClose }) => {
const { t } = useKubevirtTranslation();
const [isChecked, setChecked] = React.useState<boolean>(false);

return (
<TabModal
isOpen={isOpen}
isDisabled={!isChecked}
onClose={onClose}
onSubmit={() => createRDPService(vm, vmi)}
headerText={t('RDP Service')}
modalVariant={ModalVariant.medium}
>
<Stack hasGutter>
<StackItem>
<Checkbox
id="rdp-service-checkbox"
className="kv-rdp-service-checkbox--main"
label={t('Expose RDP Service')}
isChecked={isChecked}
data-checked-state={isChecked}
onChange={setChecked}
/>
</StackItem>
<StackItem>
<Alert variant="info" isInline title={t('Node port')}>
<div>
{t('RDP Service is using a node port. Node port requires additional port resources.')}
<div>
<ExternalLink text={t('Learn more')} href={NODE_PORTS_LINK} />
</div>
</div>
</Alert>
</StackItem>
</Stack>
</TabModal>
);
};

export default RDPServiceModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { Trans } from 'react-i18next';

import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { RDPServiceNotConfiguredProps } from '../utils/types';
import { Button, ButtonVariant } from '@patternfly/react-core';
import RDPServiceModal from './RDPServiceModal';
import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider';
import './rdp-service.scss';
const RDPServiceNotConfigured: React.FC<RDPServiceNotConfiguredProps> = ({ vm, vmi }) => {
const { t } = useKubevirtTranslation();
const { createModal } = useModal();
return (
<Trans t={t} ns="plugin__kubevirt-plugin">
<span>
This is a Windows VirtualMachine but no Service for the RDP (Remote Desktop Protocol) can be
found.
</span>
<br />
<span>
For better experience accessing Windows console, it is recommended to use the RDP.
<Button
className="kv-create-rdp-service-button"
variant={ButtonVariant.secondary}
onClick={() => createModal((props) => <RDPServiceModal vm={vm} vmi={vmi} {...props} />)}
>
Create RDP Service
</Button>
</span>
</Trans>
);
};

export default RDPServiceNotConfigured;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.kv-create-rdp-service-button {
display: block;
margin-top: var(--pf-global--spacer--md)
;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useMemo } from 'react';

import { modelToGroupVersionKind, PodModel, ServiceModel } from '@kubevirt-ui/kubevirt-api/console';
import { IoK8sApiCoreV1Pod, IoK8sApiCoreV1Service } from '@kubevirt-ui/kubevirt-api/kubernetes';
Expand All @@ -15,19 +15,19 @@ import { getDefaultNetwork, getRdpAddressPort, getVmRdpNetworks } from './utils/
const DesktopViewer: React.FC<DesktopViewerProps> = ({ vm, vmi }) => {
const { t } = useKubevirtTranslation();
const [isDropdownOpen, setIsDropdownOpen] = React.useState<boolean>(false);
const [pods] = useK8sWatchResource<IoK8sApiCoreV1Pod[]>({
const [pods, podsLoaded] = useK8sWatchResource<IoK8sApiCoreV1Pod[]>({
groupVersionKind: modelToGroupVersionKind(PodModel),
isList: true,
namespace: vm.metadata.namespace,
});

const vmPod = getVMIPod(vmi, pods);
const vmPod = useMemo(() => getVMIPod(vmi, pods), [vmi, pods]);

const [services] = useK8sWatchResource<IoK8sApiCoreV1Service[]>({
const [services, servicesLoaded] = useK8sWatchResource<IoK8sApiCoreV1Service[]>({
groupVersionKind: modelToGroupVersionKind(ServiceModel),
isList: true,
namespace: vm?.metadata?.namespace,
});

const rdpServiceAddressPort = getRdpAddressPort(vmi, services, vmPod);
const networks = getVmRdpNetworks(vm, vmi);
const [selectedNetwork, setSelectedNetwork] = React.useState<Network>(
Expand Down Expand Up @@ -72,7 +72,12 @@ const DesktopViewer: React.FC<DesktopViewerProps> = ({ vm, vmi }) => {
</FormGroup>
</Form>
{networkType === 'POD' && (
<RDPConnector rdpServiceAddressPort={rdpServiceAddressPort} vm={vm} />
<RDPConnector
rdpServiceAddressPort={rdpServiceAddressPort}
isLoading={!podsLoaded || !servicesLoaded}
vm={vm}
vmi={vmi}
/>
)}
{networkType === 'MULTUS' && <MultusNetwork vmi={vmi} selectedNetwork={selectedNetwork} />}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ export const DEFAULT_VV_FILENAME = 'console.vv';
export const DEFAULT_VV_MIMETYPE = 'application/x-virt-viewer';
export const DEFAULT_RDP_FILENAME = 'console.rdp';
export const DEFAULT_RDP_MIMETYPE = 'application/rdp';
export const VMI_LABEL_AS_RDP_SERVICE_SELECTOR = 'vm.kubevirt.io/name';
export const NODE_PORTS_LINK =
'https://access.redhat.com/documentation/en-us/openshift_container_platform/4.10/html/networking/configuring-ingress-cluster-traffic#nw-using-nodeport_configuring-ingress-cluster-traffic-nodeport';
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export type RDPProps = ConnectWithRemoteViewerProps & {
textMoreRDPInfo?: string;
/** The information content appearing above the description list for guidelines to install virt-viewer */
textMoreRDPInfoContent?: string | React.ReactNode;
isLoading?: boolean;
};

export type ManualConnectionProps = React.HTMLProps<HTMLDivElement> & {
Expand Down Expand Up @@ -157,8 +158,9 @@ export type DesktopViewerProps = {
type: string;
};

export type RdpServiceNotConfiguredProps = {
export type RDPServiceNotConfiguredProps = {
vm: V1VirtualMachine;
vmi: V1VirtualMachineInstance;
};

export type Network = {
Expand All @@ -170,6 +172,8 @@ export type Network = {
export type RDPConnectorProps = {
rdpServiceAddressPort: ConsoleDetailPropType;
vm: V1VirtualMachine;
vmi: V1VirtualMachineInstance;
isLoading: boolean;
};

export type MultusNetworkProps = {
Expand Down

0 comments on commit af4e4ec

Please sign in to comment.