Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kubevirt VmTemplateList #1673

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import * as React from 'react';
import * as _ from 'lodash';
import * as classNames from 'classnames';
import { sortable } from '@patternfly/react-table';

import {
TemplateSource,
getTemplateOperatingSystems,
getTemplateFlavors,
TEMPLATE_TYPE_LABEL,
} from 'kubevirt-web-ui-components';

import { ListPage, Table, TableRow, TableData } from '@console/internal/components/factory';
import { Kebab, ResourceLink, ResourceKebab } from '@console/internal/components/utils';
import { getName, getNamespace, DASH, getUid } from '@console/shared';
import { TemplateModel } from '@console/internal/models';
import { TemplateKind } from '../../../../../public/module/k8s/index';

export const menuActions = Kebab.factory.common;

const { kind } = TemplateModel;
const selector = {
matchLabels: { [TEMPLATE_TYPE_LABEL]: 'vm' },
};
const labelPlural = 'Virtual Machine Templates';

const tableColumnClass = classNames('col-lg-2', 'col-sm-4', 'col-xs-4');
const tableColumnClassHiddenOnSmall = classNames('col-lg-2', 'hidden-sm', 'hidden-xs');

const tableColumnClasses = [
tableColumnClass,
tableColumnClass,
tableColumnClass,
tableColumnClassHiddenOnSmall,
tableColumnClassHiddenOnSmall,
tableColumnClassHiddenOnSmall,
Kebab.columnClass,
];

const VmTemplateTableHeader = () => {
return [
{
title: 'Name',
sortField: 'metadata.name',
transforms: [sortable],
props: { className: tableColumnClasses[0] },
},
{
title: 'Namespace',
sortField: 'metadata.namespace',
transforms: [sortable],
props: { className: tableColumnClasses[1] },
},
{
title: 'Description',
sortField: 'metadata.annotations.description',
transforms: [sortable],
props: { className: tableColumnClasses[2] },
},
{
title: 'Source',
props: { className: tableColumnClasses[3] },
},
{
title: 'OS',
props: { className: tableColumnClasses[4] },
},
{
title: 'Flavor',
props: { className: tableColumnClasses[5] },
},
{
title: '',
props: { className: tableColumnClasses[6] },
},
];
};
VmTemplateTableHeader.displayName = 'VmTemplateTableHeader';

const VmTemplateTableRow = ({ obj: template, index, key, style }: VmTemplateTableRowProps) => {
const os = getTemplateOperatingSystems([template])[0];

return (
<TableRow id={template.metadata.uid} index={index} trKey={key} style={style}>
<TableData className={tableColumnClasses[0]}>
<ResourceLink
kind={kind}
name={getName(template)}
namespace={getNamespace(template)}
title={getUid(template)}
/>
</TableData>
<TableData className={tableColumnClasses[1]}>
<ResourceLink
kind="Namespace"
name={getNamespace(template)}
title={getNamespace(template)}
/>
</TableData>
<TableData className={tableColumnClasses[2]}>
{_.get(template.metadata, 'annotations.description', DASH)}
</TableData>
<TableData className={tableColumnClasses[3]}>
<TemplateSource template={template} />
</TableData>
<TableData className={tableColumnClasses[4]}>{os ? os.name || os.id : DASH}</TableData>
<TableData className={tableColumnClasses[5]}>{getTemplateFlavors([template])[0]}</TableData>
<TableData className={tableColumnClasses[6]}>
<ResourceKebab actions={menuActions} kind={kind} resource={template} />
</TableData>
</TableRow>
);
};
VmTemplateTableRow.displayName = 'VmTemplateTableRow';

const VirtualMachineTemplates = (props: React.ComponentProps<typeof Table>) => {
return (
<Table
{...props}
aria-label={labelPlural}
Header={VmTemplateTableHeader}
Row={VmTemplateTableRow}
/>
);
};

const VirtualMachineTemplatesPage = (props: React.ComponentProps<typeof ListPage>) => (
<ListPage
{...props}
title={labelPlural}
ListComponent={VirtualMachineTemplates}
kind={kind}
selector={selector}
canCreate
/>
);

type VmTemplateTableRowProps = {
obj: TemplateKind;
index: number;
key: string;
style: any;
};

export { VirtualMachineTemplates, VirtualMachineTemplatesPage };
18 changes: 0 additions & 18 deletions frontend/packages/kubevirt-plugin/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,6 @@ export const VirtualMachineInstanceReplicaSetModel: K8sKind = {
id: 'virtualmachineinstancereplicaset',
};

/* TODO(mlibra): migrate templates
export const VmTemplateModel: K8sKind = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

label: 'Template',
labelPlural: 'Templates',
apiVersion: 'v1',
path: 'templates',
apiGroup: 'template.openshift.io',
plural: 'vmtemplates',
namespaced: true,
abbr: 'VMT',
kind: 'Template',
id: 'vmtemplate',
selector: {
matchLabels: {[TEMPLATE_TYPE_LABEL]: 'vm'},
},
};
*/

export const NetworkAttachmentDefinitionModel: K8sKind = {
label: 'Network Attachment Definition',
labelPlural: 'Network Attachment Definitions',
Expand Down
39 changes: 38 additions & 1 deletion frontend/packages/kubevirt-plugin/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
ModelFeatureFlag,
YAMLTemplate,
ModelDefinition,
RoutePage,
} from '@console/plugin-sdk';
import { TemplateModel } from '@console/internal/models';

import * as models from './models';
import { yamlTemplates } from './yaml-templates';
Expand All @@ -20,7 +22,8 @@ type ConsumedExtensions =
| ResourceDetailsPage
| ModelFeatureFlag
| YAMLTemplate
| ModelDefinition;
| ModelDefinition
| RoutePage;

const FLAG_KUBEVIRT = 'KUBEVIRT';

Expand Down Expand Up @@ -50,6 +53,21 @@ const plugin: Plugin<ConsumedExtensions> = [
mergeAfter: 'Pods',
},
},
{
// NOTE(yaacov): vmtemplates is a template resource with a selector.
// 'NavItem/ResourceNS' is used, and not 'NavItem/Href', because it injects
// the namespace needed to get the correct link to a resource ( template with selector ) in our case.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory, NavItem/Href should only be used for URLs outside of Console 😄

So using NavItem/ResourceNS pointing to VM template resource is self-explanatory, I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is here because of #1754 (comment)

May be an over kill 😄 I can remove it if you go not think someone may refactor it into an href in the future 🌷

type: 'NavItem/ResourceNS',
properties: {
section: 'Workloads',
componentProps: {
name: 'Virtual Machine Templates',
resource: 'vmtemplates',
required: FLAG_KUBEVIRT,
},
mergeAfter: 'Virtual Machines',
},
},
{
type: 'Page/Resource/List',
properties: {
Expand All @@ -67,6 +85,14 @@ const plugin: Plugin<ConsumedExtensions> = [
template: yamlTemplates.getIn([models.VirtualMachineModel, 'default']),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be yaml template customized as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I forgot it 😎 , added.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, when defining a template we override the TemplateModel yaml template, so if we want to support a different yaml for templates we will have to write a new page renderer for ~new.

Copy link
Contributor

@vojtechszocs vojtechszocs Jun 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, when defining a template we override the TemplateModel yaml template

YAML templates are keyed by model & template name (using default if not specified).

In this case, we should do something like:

{
  type: 'YAMLTemplate',
  properties: {
    model: TemplateModel,
    template: 'VM template YAML goes here',
    templateName: 'vm-template',
  },
},

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks !

},
},
{
type: 'YAMLTemplate',
properties: {
model: TemplateModel,
template: yamlTemplates.getIn([TemplateModel, 'vm-template']),
templateName: 'vm-template',
},
},
{
type: 'Page/Resource/Details',
properties: {
Expand All @@ -77,6 +103,17 @@ const plugin: Plugin<ConsumedExtensions> = [
).then((m) => m.VirtualMachinesDetailsPage),
},
},
{
type: 'Page/Route',
properties: {
exact: true,
path: ['/k8s/ns/:ns/vmtemplates', '/k8s/all-namespaces/vmtemplates'],
loader: () =>
import(
'./components/vm-templates/vm-template' /* webpackChunkName: "kubevirt-vmtemplates" */
).then((m) => m.VirtualMachineTemplatesPage),
},
},
];

export default plugin;
82 changes: 78 additions & 4 deletions frontend/packages/kubevirt-plugin/src/yaml-templates.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Map as ImmutableMap } from 'immutable';

import { TemplateModel } from '@console/internal/models';
import { VirtualMachineModel } from './models';

export const yamlTemplates = ImmutableMap().setIn(
[VirtualMachineModel, 'default'],
`
export const yamlTemplates = ImmutableMap()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move this file to a special folder to not to polute the src?

Copy link
Member Author

@yaacov yaacov Jun 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@suomiy this yaml const is used by vms, vm-templates and in the future, all other resources.

I agree about moving this file, but because moving it impacts existing vms resources ( and future resources we will import from web-ui ) , moving it should be done in a separate PR and inform all people working on the that we intend to move this file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok it can be done later if you think this is a hassle (even though the conflicts should be resolvable in each PR)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on that.

I'd suggest to create src/models and git mv src/models.ts src/models/index.ts.

YAML templates are inherently related to models, so I'd add src/models/yaml-templates.ts.

.setIn(
[VirtualMachineModel, 'default'],
`
apiVersion: ${VirtualMachineModel.apiGroup}/${VirtualMachineModel.apiVersion}
kind: ${VirtualMachineModel.kind}
metadata:
Expand Down Expand Up @@ -39,4 +41,76 @@ spec:
cloudInitNoCloud:
userDataBase64: SGkuXG4=
`,
);
)
.setIn(
[TemplateModel, 'vm-template'],
`
apiVersion: ${TemplateModel.apiGroup}/${TemplateModel.apiVersion}
kind: ${TemplateModel.kind}
metadata:
name: vm-template-example
labels:
kubevirt.io/os: fedora27
miq.github.io/kubevirt-is-vm-template: 'true'
template.kubevirt.io/type: vm
annotations:
description: VM template example
iconClass: icon-fedora
tags: 'kubevirt,ocp,template,linux,virtualmachine'
objects:
- apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachine
metadata:
creationTimestamp: null
labels:
kubevirt-vm: 'vm-\${NAME}'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably missing something but where does NAME (and other uppercase-labeled variables) come from?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yaacov Thank you for clarification.

kubevirt.io/os: fedora27
name: '\${NAME}'
spec:
running: false
template:
metadata:
creationTimestamp: null
labels:
kubevirt-vm: 'vm-\${NAME}'
kubevirt.io/os: fedora27
spec:
domain:
cpu:
cores: '\${CPU_CORES}'
devices:
disks:
- disk:
bus: virtio
name: containerdisk
- disk:
bus: virtio
name: cloudinitdisk
machine:
type: ''
resources:
requests:
memory: '\${MEMORY}'
terminationGracePeriodSeconds: 0
volumes:
- containerDisk:
image: 'registry:5000/kubevirt/fedora-cloud-container-disk-demo:devel'
name: containerdisk
- cloudInitNoCloud:
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk
status: {}
parameters:
- name: NAME
description: Name for the new VM
- name: MEMORY
description: Amount of memory
value: 4096Mi
- name: CPU_CORES
description: Amount of cores
value: '4'
`,
);