Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Commit

Permalink
Add add NIC functionality to VM NIC details
Browse files Browse the repository at this point in the history
- withResources handles unknown k8s models
  • Loading branch information
rawagner authored and mareklibra committed Jan 8, 2019
1 parent 699fa67 commit 15ea589
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 45 deletions.
20 changes: 9 additions & 11 deletions frontend/public/kubevirt/components/disk.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,16 @@ export class Disk extends React.Component {
const vm = this.props.obj;
const storages = this.getStorages(vm);
const alert = _.get(this.state.newStorage, 'error') && <Alert onDismiss={this._errorDismissHandler}>{this.state.newStorage.error}</Alert>;
return <React.Fragment>
<div className="co-m-list">
<div className="co-m-pane__filter-bar">
<div className="co-m-pane__filter-bar-group">
<Button bsStyle="primary" id="create-disk-btn" onClick={this._createStorageHandler} disabled={!!this.state.newStorage}>Create Disk</Button>
</div>
</div>
<div className="co-m-pane__body">
{alert}
<List data={storages} Header={DiskHeader} Row={this.DiskRow} loaded={true} />
return <div className="co-m-list">
<div className="co-m-pane__filter-bar">
<div className="co-m-pane__filter-bar-group">
<Button bsStyle="primary" id="create-disk-btn" onClick={this._createStorageHandler} disabled={!!this.state.newStorage}>Create Disk</Button>
</div>
</div>
</React.Fragment>;
<div className="co-m-pane__body">
{alert}
<List data={storages} Header={DiskHeader} Row={this.DiskRow} loaded={true} />
</div>
</div>;
}
}
188 changes: 164 additions & 24 deletions frontend/public/kubevirt/components/nic.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import React from 'react';
import * as _ from 'lodash-es';
import { Kebab } from './utils/okdutils';
import { Alert, Button } from 'patternfly-react';

import { Kebab, LoadingInline } from './utils/okdutils';
import { List, ColHead, ListHeader, ResourceRow } from './factory/okdfactory';
import { DASHES, BUS_VIRTIO, NETWORK_TYPE_MULTUS, NETWORK_TYPE_POD, NIC } from './utils/constants';
import { DASHES, BUS_VIRTIO, NIC } from './utils/constants';
import { deleteDeviceModal } from './modals/delete-device-modal';
import { getNetworks, CreateNicRow, getAddNicPatch, POD_NETWORK } from 'kubevirt-web-ui-components';
import { NetworkAttachmentDefinitionModel, VirtualMachineModel } from '../models';
import { getResourceKind } from './utils/resources';
import { WithResources } from './utils/withResources';
import { k8sPatch } from '../module/okdk8s';

const getNetworkType = network => {
const getNetworkName = network => {
if (network) {
if (network.hasOwnProperty('pod')){
return NETWORK_TYPE_POD;
return POD_NETWORK;
} else if (network.hasOwnProperty('multus')){
return NETWORK_TYPE_MULTUS;
return network.multus.networkName;
}
}
return DASHES;
Expand All @@ -33,22 +40,27 @@ const getActions = (vm, nic) => {
const visibleRowStyle = 'col-lg-3 col-md-3 col-sm-3 col-xs-4';
const hiddenRowStyle = 'col-lg-3 col-md-3 col-sm-3 hidden-xs';

const getVmNicModel = vm => {
const networks = getNetworks(vm);
return networks.length > 0 ? _.get(networks[0], 'model', BUS_VIRTIO) : BUS_VIRTIO;
};

const NicHeader = props => <ListHeader>
<ColHead {...props} className={visibleRowStyle} sortField="name">Name</ColHead>
<ColHead {...props} className={visibleRowStyle} sortField="model">Model</ColHead>
<ColHead {...props} className={visibleRowStyle} sortField="network">Network</ColHead>
<ColHead {...props} className={hiddenRowStyle} sortField="macAddress">MAC Address</ColHead>
</ListHeader>;

export const NicRow = ({obj: nic}) => <ResourceRow obj={nic}>
<div className={visibleRowStyle} co-resource-link-wrapper>
export const VmNicRow = ({ nic }) => <ResourceRow obj={nic}>
<div className={visibleRowStyle}>
{nic.name}
</div>
<div className={visibleRowStyle}>
{nic.model || BUS_VIRTIO}
</div>
<div className={visibleRowStyle}>
{getNetworkType(nic.network)}
{getNetworkName(nic.network)}
</div>
<div className={hiddenRowStyle}>
{nic.macAddress || DASHES}
Expand All @@ -63,21 +75,149 @@ export const NicRow = ({obj: nic}) => <ResourceRow obj={nic}>
</div>
</ResourceRow>;

export const Nic = ({obj: vm}) => {
const interfaces = _.get(vm,'spec.template.spec.domain.devices.interfaces',[]);
const networks = _.get(vm,'spec.template.spec.networks',[]);
const nics = interfaces.map(i => {
const network = networks.find(n => n.name === i.name);
return {
...i,
network,
vm,
};
});
return <div className="co-m-list">
<div className="co-m-pane__body">
<List data={nics} Header={NicHeader} Row={NicRow} loaded={true} />
</div>
</div>;
const NIC_TYPE_VM = 'nic-type-vm';
const NIC_TYPE_CREATE = 'nic-type-create';

export const NicRow = (onChange, onAccept, onCancel) => ({obj: nic}) => {
const networks = {
resource: getResourceKind(NetworkAttachmentDefinitionModel, undefined, true, undefined, true),
};
switch (nic.nicType) {
case NIC_TYPE_VM:
return <VmNicRow nic={nic} />;
case NIC_TYPE_CREATE:
return <div className="row co-resource-list__item">
<WithResources resourceMap={{networks}}>
<CreateNicRow
nic={nic}
onAccept={onAccept}
onCancel={onCancel}
onChange={onChange}
LoadingComponent={LoadingInline}
/>
</WithResources>
</div>;
default:
// eslint-disable-next-line
console.warn(`Unknown nic type ${nic.nicType}`);
break;
}
};

export class Nic extends React.Component {

constructor(props) {
super(props);
this.state = {
newNic: null,
};
this._getNics = this.getNics.bind(this);
this._createNicHandler = this.createNicHandler.bind(this);
this._onChange = this.onChange.bind(this);
this._onCancel = this.onCancel.bind(this);
this._onAccept = this.onAccept.bind(this);
this._errorDismissHandler = this.errorDismissHandler.bind(this);
this.NicRow = NicRow(this._onChange, this._onAccept, this._onCancel);
}

getNics(vm) {
const nics = this.state.newNic ? [{...this.state.newNic}] : [];
const interfaces = _.get(vm,'spec.template.spec.domain.devices.interfaces',[]);
const networks = _.get(vm,'spec.template.spec.networks',[]);
nics.push(...interfaces.map(nic => {
const network = networks.find(n => n.name === nic.name);
return {
...nic,
vm,
network,
nicType: NIC_TYPE_VM,
};
}));
return nics;
}

createNicHandler() {
this.setState({
newNic: {
nicType: NIC_TYPE_CREATE,
model: {
value: getVmNicModel(this.props.obj),
},
vm: this.props.obj,
},
});
}

onChange(value, key) {
const newNic = {
...this.state.newNic,
[key]: value,
};
this.setState({
newNic,
});
}

onAccept() {
const newNic = {
...this.state.newNic,
error: null,
creating: true,
};
const nic = {
name: _.get(newNic, 'name.value'),
model: _.get(newNic, 'model.value'),
network: _.get(newNic, 'network.value'),
mac: _.get(newNic, 'mac.value'),
};

const addNicPatch = getAddNicPatch(this.props.obj, nic);
const patch = k8sPatch(VirtualMachineModel, this.props.obj, addNicPatch);
patch.then(() => {
this.setState({newNic: null});
}).catch(error => {
this.setState({
newNic: {
...this.state.newNic,
error: error.message || 'Error occured, please try again',
creating: false,
},
});
});
this.setState({
newNic,
});
}

onCancel() {
this.setState({
newNic: null,
});
}

errorDismissHandler() {
this.setState({
newNic: {
...this.state.newNic,
error: null,
},
});
}

render() {
const vm = this.props.obj;
const nics = this.getNics(vm);
const alert = _.get(this.state.newNic, 'error') && <Alert onDismiss={this._errorDismissHandler}>{this.state.newNic.error}</Alert>;
return <div className="co-m-list">
<div className="co-m-pane__filter-bar">
<div className="co-m-pane__filter-bar-group">
<Button bsStyle="primary" id="create-nic-btn" onClick={this._createNicHandler} disabled={!!this.state.newNic}>Create NIC</Button>
</div>
</div>
<div className="co-m-pane__body">
{alert}
<List data={nics} Header={NicHeader} Row={this.NicRow} loaded={true} />
</div>
</div>;
}
}
3 changes: 0 additions & 3 deletions frontend/public/kubevirt/components/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ export const DASHES = '---';

export const BUS_VIRTIO = 'virtio';

export const NETWORK_TYPE_MULTUS = 'Multus';
export const NETWORK_TYPE_POD = 'Pod Networking';

export const NIC = 'NIC';
export const DISK = 'Disk';

Expand Down
27 changes: 20 additions & 7 deletions frontend/public/kubevirt/components/utils/withResources.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import * as _ from 'lodash-es';
import { connect } from 'react-redux';
import { Map as ImmutableMap } from 'immutable';

import { Firehose } from '../utils/okdutils';
import { inject } from '../../../components/utils';
Expand Down Expand Up @@ -97,14 +99,25 @@ Resources.propTypes = {
showLoader: PropTypes.bool,
};

const stateToProps = ({k8s}, {resourceMap}) => {
const resources = Object.keys(resourceMap).map(k => resourceMap[k].resource);
return {
k8sModels: resources.reduce((models, {kind}) => models.set(kind, k8s.getIn(['RESOURCES', 'models', kind])), ImmutableMap()),
};
};


export const WithResources = connect(stateToProps)(({ resourceMap, k8sModels, children, ...rest }) => {
const kindExists = Object.keys(resourceMap).some(key => k8sModels.get(resourceMap[key].resource.kind));

export const WithResources = ({resourceMap, children, ...rest}) => (
<Firehose resources={Object.keys(resourceMap).map(k => resourceMap[k].resource)}>
<Resources resourceMap={resourceMap} {...rest}>
{children}
</Resources>
</Firehose>
);
const resourceComponent = <Resources resourceMap={resourceMap} {...rest}>{children}</Resources>;
// firehose renders null if kind does not exist
return kindExists
? (<Firehose resources={Object.keys(resourceMap).map(k => resourceMap[k].resource)}>
{resourceComponent}
</Firehose>)
: resourceComponent;
});

WithResources.defaultProps = {
showLoader: false,
Expand Down

0 comments on commit 15ea589

Please sign in to comment.