kubernetes: Add Virtual machines side tab
It lists VMs of Kubevirt. The tab is only shown if connected cluster has Kubevirt installed. It uses standard React + Redux + Saga approach. Nested in angular environment. Redux store is garbage collected when Virtual Machines view is left. Changed dependencies: * react-redux, redux-saga - React state management dependencies * babel-plugin-transform-regenerator - support for JS generator functions * eslint-plugin-flowtype, flow-bin, flow-webpack-plugin - JS type annotation Closes #7830
This commit is contained in:
parent
0218d776ca
commit
2a7622d28a
|
@ -4,6 +4,7 @@
|
|||
"es6": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
|
@ -11,7 +12,7 @@
|
|||
},
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["react"],
|
||||
"plugins": ["flowtype", "react"],
|
||||
"rules": {
|
||||
"react/jsx-uses-vars": "error",
|
||||
"no-console": "off",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[ignore]
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
|
||||
[lints]
|
||||
|
||||
[options]
|
||||
module.name_mapper='.*cockpit$' -> '<PROJECT_ROOT>/src/base1/cockpit.js'
|
||||
|
||||
[strict]
|
|
@ -165,6 +165,7 @@ po*.js.gz
|
|||
/pkg/*/manifest.json
|
||||
|
||||
.idea
|
||||
.vscode/
|
||||
|
||||
# Test output
|
||||
Test*.log
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
"qunit-tap": "1.5.1",
|
||||
"qunitjs": "1.23.1",
|
||||
"react-lite": "0.15.39",
|
||||
"react-redux": "5.0.6",
|
||||
"redux": "3.7.2",
|
||||
"redux-saga": "0.16.0",
|
||||
"registry-image-widgets": "0.0.16",
|
||||
"requirejs": "2.1.22",
|
||||
"term.js-cockpit": "0.0.10"
|
||||
|
@ -34,6 +36,7 @@
|
|||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "~7.1.1",
|
||||
"babel-loader": "^6.4.1",
|
||||
"babel-plugin-transform-regenerator": "6.26.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"chrome-remote-interface": "^0.25.2",
|
||||
|
@ -42,13 +45,14 @@
|
|||
"css-loader": "~0.23.1",
|
||||
"eslint": "^3.0.0",
|
||||
"eslint-loader": "~1.6.1",
|
||||
"eslint-plugin-flowtype": "2.39.1",
|
||||
"eslint-plugin-react": "~6.9.0",
|
||||
"exports-loader": "~0.6.3",
|
||||
"extend": "~3.0.0",
|
||||
"extract-text-webpack-plugin": "~1.0.1",
|
||||
"htmlparser": "~1.7.7",
|
||||
"html-minifier": "~0.7.2",
|
||||
"html-webpack-plugin": "~2.22.0",
|
||||
"htmlparser": "~1.7.7",
|
||||
"imports-loader": "~0.6.5",
|
||||
"jed": "~1.1.0",
|
||||
"jshint": "~2.9.1",
|
||||
|
|
|
@ -36,7 +36,7 @@ along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
|||
<div class="nav-item-pf-header">
|
||||
<span translate>Cluster</span>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<ul class="list-group" id="kubernetes-navigation">
|
||||
<li class="list-group-item" ng-class="{ active: viewActive(null)}">
|
||||
<a ng-href="#{{ viewUrl(null) }}">
|
||||
<i class="fa fa-dashboard fa-fw" title="Overview"></i>
|
||||
|
@ -55,6 +55,12 @@ along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
|||
<span class="list-group-item-value" translate>Containers</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="list-group-item" ng-class="{ active: viewActive('vms')}" ng-if="settings.kubevirtEnabled">
|
||||
<a ng-href="#{{ viewUrl('vms') }}" id="vms-menu-link">
|
||||
<i class="fa pficon-virtual-machine fa-fw" title="Virtual Machines"></i>
|
||||
<span class="list-group-item-value" translate>Virtual Machines</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="list-group-item" ng-class="{ active: viewActive('topology')}">
|
||||
<a ng-href="#{{ viewUrl('topology') }}">
|
||||
<i class="pficon pficon-topology fa-fw" title="Topology"></i>
|
||||
|
|
|
@ -1110,8 +1110,9 @@
|
|||
"CockpitEnvironment",
|
||||
'kubeLoader',
|
||||
'cockpitConnectionInfo',
|
||||
'KubevirtPrefix',
|
||||
function($q, CockpitKubeRequest, cockpitKubeDiscover,
|
||||
CockpitEnvironment, loader, info) {
|
||||
CockpitEnvironment, loader, info, kubevirtPrefix) {
|
||||
var promise = null;
|
||||
return function kubeDiscoverSettings(force) {
|
||||
if (!force && promise)
|
||||
|
@ -1126,6 +1127,7 @@
|
|||
isAdmin: false,
|
||||
currentUser: null,
|
||||
canChangeConnection: false,
|
||||
kubevirtEnabled: false,
|
||||
};
|
||||
|
||||
var env_p = CockpitEnvironment()
|
||||
|
@ -1171,7 +1173,18 @@
|
|||
return $q.all([watch, req]);
|
||||
});
|
||||
|
||||
promise = $q.all([discover_p, env_p])
|
||||
var kubevirt_p = new CockpitKubeRequest('GET', kubevirtPrefix)
|
||||
.then(function(response) {
|
||||
settings.kubevirtEnabled = true;
|
||||
}, function(errorResponse) {
|
||||
if (errorResponse.status === 404) {
|
||||
settings.kubevirtEnabled = false;
|
||||
return;
|
||||
}
|
||||
debug('Kubevirt check request failed:', errorResponse);
|
||||
});
|
||||
|
||||
promise = $q.all([discover_p, env_p, kubevirt_p])
|
||||
.then(function() {
|
||||
settings.canChangeConnection = info.type == "kubectl";
|
||||
return settings;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
var KUBE = "/api/v1";
|
||||
var OPENSHIFT = "/oapi/v1";
|
||||
var KUBEVIRT = "/apis/kubevirt.io/v1alpha1";
|
||||
var DEFAULT = { api: KUBE, create: 0 };
|
||||
var SCHEMA = flatSchema([
|
||||
{ kind: "DeploymentConfig", type: "deploymentconfigs", api: OPENSHIFT },
|
||||
|
@ -62,6 +63,7 @@
|
|||
{ kind: "Service", type: "services", api: KUBE, create: -80 },
|
||||
{ kind: "SubjectAccessReview", type: "subjectaccessreviews", api: OPENSHIFT },
|
||||
{ kind: "User", type: "users", api: OPENSHIFT, global: true },
|
||||
{ kind: "VirtualMachine", type: "virtualmachines", api: KUBEVIRT },
|
||||
]);
|
||||
|
||||
var NAME_RE = /^[a-z0-9]([-a-z0-9_.]*[a-z0-9])?$/;
|
||||
|
@ -306,6 +308,8 @@
|
|||
|
||||
.value("KUBE_SCHEMA", SCHEMA)
|
||||
|
||||
.constant("KubevirtPrefix", KUBEVIRT)
|
||||
|
||||
/**
|
||||
* KUBE_NAME_RE
|
||||
*
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
require('./nodes');
|
||||
require('./topology');
|
||||
require('./volumes');
|
||||
require('./virtual-machines.js');
|
||||
|
||||
/* And the actual application */
|
||||
require('./app');
|
||||
|
@ -63,6 +64,7 @@
|
|||
'kubernetes.volumes',
|
||||
'kubernetes.nodes',
|
||||
'kubernetes.date',
|
||||
'kubernetes.virtualMachines',
|
||||
'registry.images',
|
||||
'registry.policy',
|
||||
'registry.projects',
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2018 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var angular = require('angular');
|
||||
require('angular-route');
|
||||
require('angular-dialog.js');
|
||||
require('./kube-client');
|
||||
require('./listing');
|
||||
var vmsReact = require('./virtual-machines/index.jsx');
|
||||
|
||||
require('../views/virtual-machines-page.html');
|
||||
|
||||
angular.module('kubernetes.virtualMachines', [
|
||||
'ngRoute',
|
||||
'ui.cockpit',
|
||||
'kubernetesUI',
|
||||
'kubeClient',
|
||||
'kubernetes.listing'
|
||||
])
|
||||
|
||||
.config([
|
||||
'$routeProvider',
|
||||
'$locationProvider',
|
||||
function($routeProvider, $locationProvider) {
|
||||
$routeProvider
|
||||
.when('/vms', {
|
||||
templateUrl: 'views/virtual-machines-page.html',
|
||||
controller: 'VirtualMachinesCtrl'
|
||||
});
|
||||
/*
|
||||
Links rewriting is enabled by default. It does two things:
|
||||
* It changes links href in older browsers.
|
||||
* It handles the navigation instead of the browser.
|
||||
|
||||
The link rewriting code runs in 'click' event handler registered
|
||||
to the `document` element to bubbling phase. It calls `preventDefault()`
|
||||
event method and instructs browser to go to the destination.
|
||||
|
||||
Such behavior breaks event handling in React since:
|
||||
* React always gets event with flag `defaultPrevented` set.
|
||||
* Navigation is performed no matter if `event.preventDefault()` is called
|
||||
in React handler.
|
||||
|
||||
@see https://docs.angularjs.org/api/ng/provider/$locationProvider
|
||||
@see https://docs.angularjs.org/guide/$location#html5-mode
|
||||
*/
|
||||
$locationProvider.html5Mode({ rewriteLinks: false });
|
||||
}
|
||||
])
|
||||
|
||||
.controller('VirtualMachinesCtrl', [
|
||||
'$scope',
|
||||
'kubeLoader',
|
||||
'kubeSelect',
|
||||
function($scope, loader, select) {
|
||||
vmsReact.init($scope, loader, select);
|
||||
}]
|
||||
);
|
||||
|
||||
}());
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as actionConstants from './action-types.jsx'
|
||||
|
||||
export function setVms(vms) {
|
||||
return {
|
||||
type: actionConstants.SET_VMS,
|
||||
payload: vms
|
||||
}
|
||||
}
|
||||
|
||||
export function setSettings(settings) {
|
||||
return {
|
||||
type: actionConstants.SET_SETTINGS,
|
||||
payload: settings
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const SET_VMS = 'SET_VMS'
|
||||
export const SET_SETTINGS = 'SET_SETTINGS'
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// @flow
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { gettext as _ } from 'cockpit'
|
||||
|
||||
import { Listing } from '../../../../lib/cockpit-components-listing.jsx'
|
||||
import VmsListingRow from './VmsListingRow.jsx'
|
||||
|
||||
const VmsListing = ({ vms, settings }) => {
|
||||
const isOpenshift = settings.flavor === 'openshift'
|
||||
const namespaceLabel = isOpenshift ? _("Project") : _("Namespace")
|
||||
const rows = vms.map(vm => (<VmsListingRow vm={vm} key={vm.metadata.uid} />))
|
||||
return (
|
||||
<Listing title={_("Virtual Machines")}
|
||||
emptyCaption={_("No virtual machines")}
|
||||
columnTitles={[_("Name"), namespaceLabel, _("Node"), _("State")]}>
|
||||
{rows}
|
||||
</Listing>
|
||||
)
|
||||
}
|
||||
|
||||
VmsListing.propTypes = {
|
||||
vms: React.PropTypes.object.isRequired,
|
||||
setting: React.PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export default connect(({ vms, settings }) => ({
|
||||
vms,
|
||||
settings
|
||||
}))(VmsListing)
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// @flow
|
||||
|
||||
import React from 'react'
|
||||
import { gettext as _ } from 'cockpit'
|
||||
|
||||
import { ListingRow } from '../../../../lib/cockpit-components-listing.jsx'
|
||||
import type { Vm } from '../types.jsx'
|
||||
import { getPairs } from '../utils.jsx'
|
||||
|
||||
const NODE_LABEL = 'kubevirt.io/nodeName'
|
||||
function getNodeName(vm: Vm) {
|
||||
return (vm.metadata.labels && vm.metadata.labels[NODE_LABEL]) || null
|
||||
}
|
||||
|
||||
const GeneralTab = ({ vm }: { vm: Vm }) => {
|
||||
const nodeName = getNodeName(vm)
|
||||
const nodeLink = nodeName ? (<a href={`#/nodes/${nodeName}`}>{nodeName}</a>) : '-'
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-xs-12 col-md-6">
|
||||
<dl>
|
||||
<dt>{_("Node")}</dt>
|
||||
<dd className="vm-node">{nodeLink}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div className="col-xs-12 col-md-6">
|
||||
<dl className="full-width">
|
||||
<dt>{_("Labels")}</dt>
|
||||
{vm.metadata.labels && getPairs(vm.metadata.labels).map(pair => {
|
||||
const printablePair = pair.key + '=' + pair.value
|
||||
return (<dd key={printablePair}>{printablePair}</dd>)
|
||||
})}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const VmsListingRow = ({ vm }: { vm: Vm }) => {
|
||||
const node = (vm.metadata.labels && vm.metadata.labels[NODE_LABEL]) || '-'
|
||||
const phase = (vm.status && vm.status.phase) || _("n/a")
|
||||
const generalTabRenderer = {
|
||||
name: _("General"),
|
||||
renderer: GeneralTab,
|
||||
data: { vm },
|
||||
presence: 'always',
|
||||
}
|
||||
return (
|
||||
<ListingRow
|
||||
rowId={`vm-${vm.metadata.name}`}
|
||||
columns={[
|
||||
{name: vm.metadata.name, 'header': true},
|
||||
vm.metadata.namespace,
|
||||
node,
|
||||
phase // phases description https://github.com/kubevirt/kubevirt/blob/master/pkg/api/v1/types.go
|
||||
]}
|
||||
tabRenderers={[generalTabRenderer]}/>
|
||||
)
|
||||
}
|
||||
|
||||
VmsListingRow.propTypes = {
|
||||
vm: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default VmsListingRow
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'regenerator-runtime/runtime' // required for library initialization
|
||||
import React from 'react'
|
||||
import { createStore, applyMiddleware, compose } from 'redux'
|
||||
import createSagaMiddleware from 'redux-saga'
|
||||
import { Provider } from 'react-redux'
|
||||
|
||||
import reducers from './reducers.jsx'
|
||||
import rootSaga from './sagas.jsx'
|
||||
import * as actionCreators from './action-creators.jsx'
|
||||
import VmsListing from './components/VmsListing.jsx'
|
||||
|
||||
const sagaMiddleware = createSagaMiddleware()
|
||||
let reduxStore
|
||||
|
||||
function initReduxStore() {
|
||||
const initialState = {
|
||||
vms: []
|
||||
}
|
||||
const middleware = [ sagaMiddleware ]
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
|
||||
const storeEnhancers = composeEnhancers(applyMiddleware(...middleware))
|
||||
reduxStore = createStore(reducers, initialState, storeEnhancers)
|
||||
}
|
||||
|
||||
function addKubeLoaderListener ($scope, kubeLoader, kubeSelect) {
|
||||
// register load callback( callback, until )
|
||||
kubeLoader.listen(function() {
|
||||
const vms = kubeSelect().kind('VirtualMachine')
|
||||
reduxStore.dispatch(actionCreators.setVms(Object.values(vms)))
|
||||
}, $scope);
|
||||
|
||||
// enable watching( watched-entity-type, until )
|
||||
kubeLoader.watch('VirtualMachine', $scope);
|
||||
}
|
||||
|
||||
const VmsPlugin = () => (
|
||||
<Provider store={reduxStore} >
|
||||
<VmsListing />
|
||||
</Provider>
|
||||
)
|
||||
|
||||
function addScopeVarsToStore ($scope) {
|
||||
$scope.$watch(
|
||||
(scope => scope.settings),
|
||||
(newSettings => reduxStore.dispatch(actionCreators.setSettings(newSettings))))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {$rootScope.Scope} $scope 'VirtualMachinesCtrl' controller scope
|
||||
* @param {kubeLoader} kubeLoader
|
||||
* @param {kubeSelect} kubeSelect
|
||||
*/
|
||||
function init($scope, kubeLoader, kubeSelect) {
|
||||
initReduxStore()
|
||||
sagaMiddleware.run(rootSaga)
|
||||
addKubeLoaderListener($scope, kubeLoader, kubeSelect)
|
||||
addScopeVarsToStore($scope)
|
||||
const rootElement = document.querySelector('#kubernetes-virtual-machines-root')
|
||||
React.render(<VmsPlugin />, rootElement)
|
||||
}
|
||||
|
||||
export { init };
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { combineReducers } from 'redux'
|
||||
|
||||
import * as actionTypes from './action-types.jsx'
|
||||
|
||||
const createReducer = (initialState, actionHandlerMap) => (state = initialState, action) => {
|
||||
if (actionHandlerMap[action.type]) {
|
||||
return actionHandlerMap[action.type](state, action)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
const vmsReducer = createReducer([], {
|
||||
[actionTypes.SET_VMS]: (state = [], { payload }) => payload ? payload : []
|
||||
})
|
||||
|
||||
const settingsReducer = createReducer([], {
|
||||
[actionTypes.SET_SETTINGS]: (state = [], { payload }) => payload ? payload : {}
|
||||
})
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
vms: vmsReducer,
|
||||
settings: settingsReducer
|
||||
})
|
||||
|
||||
export default rootReducer
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
function* rootSaga() {
|
||||
}
|
||||
|
||||
export default rootSaga;
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// @flow
|
||||
|
||||
export type Vm = {
|
||||
apiVersion: string,
|
||||
kind: 'VirtualMachine',
|
||||
metadata: {
|
||||
clusterName: string,
|
||||
creationTimestamp: string,
|
||||
generation: number,
|
||||
labels: {[string]: string},
|
||||
name: string,
|
||||
namespace: string,
|
||||
resourceVersion: string,
|
||||
selfLink: string,
|
||||
uid: string
|
||||
},
|
||||
spec: {
|
||||
domain: {
|
||||
devices: {
|
||||
console: Array<Object>,
|
||||
disks: Array<Object>,
|
||||
graphics: Array<Object>,
|
||||
interfaces: Array<Object>,
|
||||
video: Array<Object>,
|
||||
[string]: any
|
||||
},
|
||||
memory: {
|
||||
unit: string,
|
||||
value: number
|
||||
},
|
||||
os: {
|
||||
bootOrder?: mixed,
|
||||
type: Object
|
||||
},
|
||||
type: string
|
||||
}
|
||||
},
|
||||
status: ?{
|
||||
graphics?: mixed,
|
||||
nodeName: string,
|
||||
phase: ?string
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2018 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return {Array<{key: *, value: *}>} all own enumerable key-value pairs
|
||||
*/
|
||||
export function getPairs(object) {
|
||||
return Object.keys(object).map(key => ({
|
||||
key,
|
||||
value: object[key]
|
||||
}))
|
||||
}
|
|
@ -23,7 +23,8 @@
|
|||
width: unit(@sidebar-width-xl, px) !important;
|
||||
}
|
||||
.list-group-item-value {
|
||||
max-width: unit(@sidebar-width-xl - 80, px) !important;
|
||||
max-width: unit(@sidebar-width-xl - 60, px) !important;
|
||||
padding-right: 10px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@import "/variables.less";
|
||||
|
||||
@sidebar-width-sm: 40;
|
||||
@sidebar-width-md: 115;
|
||||
@sidebar-width-xl: 180;
|
||||
@sidebar-width-md: 145;
|
||||
@sidebar-width-xl: 185;
|
||||
|
||||
@command-bg-color: #eee;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<filter-bar class="content-filter">
|
||||
</filter-bar>
|
||||
|
||||
<div id="kubernetes-virtual-machines-root"></div>
|
|
@ -61,6 +61,8 @@ class TestOpenshift(MachineCase, OpenshiftCommonTests):
|
|||
def setUp(self):
|
||||
super(TestOpenshift, self).setUp()
|
||||
|
||||
print "======= done setUp"
|
||||
|
||||
self.openshift = self.machines['openshift']
|
||||
self.openshift.upload(["verify/files/mock-app-openshift.json"], "/tmp")
|
||||
self.kubeconfig = os.path.join(self.tmpdir, "config")
|
||||
|
@ -406,6 +408,70 @@ LABEL io.projectatomic.nulecule.atomicappversion="0.1.11" \
|
|||
wait(lambda: "virt-launcher-testvm" in o.execute("oc get pods"))
|
||||
wait(lambda: "Running" in o.execute("oc get pods | grep virt-launcher-testvm"))
|
||||
|
||||
def testVirtualMachinesTabPresent(self):
|
||||
self.bootstrapKubevirt()
|
||||
|
||||
b = self.browser
|
||||
self.login_and_go("/kubernetes")
|
||||
b.wait_present("#kubernetes-navigation")
|
||||
self.assertTrue(b.is_present("#vms-menu-link"))
|
||||
|
||||
def testVirtualMachinesListed(self):
|
||||
self.bootstrapKubevirt()
|
||||
|
||||
o = self.openshift
|
||||
# *.yaml files comes from kubevirt distribution, see tarball extraction in bots/images/script/lib/kubevirt.setup
|
||||
o.execute("oc create -f /kubevirt/iscsi-demo-target.yaml") # disk for test VM
|
||||
o.execute("oc create -f /kubevirt/vm.yaml") # let's create a VM
|
||||
wait(lambda: "testvm" in o.execute("oc get vm"), msg='Deployment of virtual machine "testvm" failed.')
|
||||
|
||||
b = self.browser
|
||||
self.login_and_go("/kubernetes")
|
||||
b.wait_present("#vms-menu-link")
|
||||
b.click("#vms-menu-link")
|
||||
b.wait_present("tr[data-row-id='vm-testvm']")
|
||||
self.assertTrue(b.text("tr[data-row-id='vm-testvm'] th") == 'testvm')
|
||||
|
||||
def testVirtualMachineRowExpansion(self):
|
||||
self.bootstrapKubevirt()
|
||||
|
||||
o = self.openshift
|
||||
o.execute("oc create -f /kubevirt/iscsi-demo-target.yaml") # disk for test VM
|
||||
o.execute("oc create -f /kubevirt/vm.yaml") # let's create a VM
|
||||
wait(lambda: "testvm" in o.execute("oc get vm"), msg='Deployment of virtual machine "testvm" failed.')
|
||||
|
||||
b = self.browser
|
||||
self.login_and_go("/kubernetes")
|
||||
b.wait_present("#vms-menu-link")
|
||||
b.click("#vms-menu-link")
|
||||
b.wait_present("tr[data-row-id='vm-testvm']")
|
||||
b.click("tr[data-row-id='vm-testvm']")
|
||||
b.wait_present("tr[data-row-id='vm-testvm'] + tr.listing-ct-panel")
|
||||
self.assertTrue('Node' in b.text("tr[data-row-id='vm-testvm'] + tr.listing-ct-panel"))
|
||||
|
||||
def testVirtualMachineLinkToNode(self):
|
||||
print 'start'
|
||||
self.bootstrapKubevirt()
|
||||
print 'kubevirt installed'
|
||||
|
||||
o = self.openshift
|
||||
o.execute("oc create -f /kubevirt/iscsi-demo-target.yaml") # disk for test VM
|
||||
o.execute("oc create -f /kubevirt/vm.yaml") # let's create a VM
|
||||
wait(lambda: "testvm" in o.execute("oc get vm"), msg='Deployment of virtual machine "testvm" failed.')
|
||||
|
||||
b = self.browser
|
||||
self.login_and_go("/kubernetes")
|
||||
b.wait_present("#vms-menu-link")
|
||||
b.click("#vms-menu-link")
|
||||
b.wait_present("tr[data-row-id='vm-testvm']")
|
||||
b.click("tr[data-row-id='vm-testvm']")
|
||||
b.wait_present("tr[data-row-id='vm-testvm'] + tr.listing-ct-panel .vm-node")
|
||||
node_not_assigned = '-'
|
||||
node_name = b.text("tr[data-row-id='vm-testvm'] + tr.listing-ct-panel .vm-node").strip()
|
||||
if node_name != node_not_assigned:
|
||||
b.click("tr[data-row-id='vm-testvm'] + tr.listing-ct-panel .vm-node a")
|
||||
b.wait_js_cond('window.location.hash === "#/nodes/%s"' % (node_name,))
|
||||
|
||||
|
||||
@skipImage("Kubernetes not packaged", "debian-stable", "debian-testing", "ubuntu-1604", "ubuntu-stable", "fedora-i386")
|
||||
@skipImage("No cockpit-kubernetes packaged", "continuous-atomic", "fedora-atomic", "rhel-atomic")
|
||||
|
|
|
@ -356,7 +356,7 @@ var plugins = [
|
|||
}
|
||||
}),
|
||||
new copy(info.files),
|
||||
new extract("[name].css")
|
||||
new extract("[name].css"),
|
||||
];
|
||||
|
||||
var output = {
|
||||
|
|
Loading…
Reference in New Issue