feat(VM creation): support automatic networks (#3958)

Fixes #3916
This commit is contained in:
Enishowk 2019-03-06 14:46:22 +01:00 committed by Julien Fontanet
parent 5ba170bf1f
commit 08ddfe0649
7 changed files with 81 additions and 37 deletions

View File

@ -3,6 +3,7 @@
### Enhancements ### Enhancements
- [SR/Disk] Disable actions on unmanaged VDIs [#3988](https://github.com/vatesfr/xen-orchestra/issues/3988) (PR [#4000](https://github.com/vatesfr/xen-orchestra/pull/4000)) - [SR/Disk] Disable actions on unmanaged VDIs [#3988](https://github.com/vatesfr/xen-orchestra/issues/3988) (PR [#4000](https://github.com/vatesfr/xen-orchestra/pull/4000))
- [Pool] Specify automatic networks on a Pool [#3916](https://github.com/vatesfr/xen-orchestra/issues/3916) (PR [#3958](https://github.com/vatesfr/xen-orchestra/pull/3958))
### Bug fixes ### Bug fixes

View File

@ -85,34 +85,35 @@ createBonded.description =
// =================================================================== // ===================================================================
export async function set({ export async function set({
network, automatic,
defaultIsLocked,
name_description: nameDescription, name_description: nameDescription,
name_label: nameLabel, name_label: nameLabel,
defaultIsLocked, network,
id,
}) { }) {
await this.getXapi(network).setNetworkProperties(network._xapiId, { await this.getXapi(network).setNetworkProperties(network._xapiId, {
automatic,
defaultIsLocked,
nameDescription, nameDescription,
nameLabel, nameLabel,
defaultIsLocked,
}) })
} }
set.params = { set.params = {
id: { automatic: {
type: 'string', type: 'boolean',
optional: true,
}, },
name_label: { defaultIsLocked: {
type: 'string', type: 'boolean',
optional: true, optional: true,
}, },
name_description: { name_description: {
type: 'string', type: 'string',
optional: true, optional: true,
}, },
defaultIsLocked: { name_label: {
type: 'boolean', type: 'string',
optional: true, optional: true,
}, },
} }

View File

@ -578,6 +578,7 @@ const TRANSFORMS = {
network(obj) { network(obj) {
return { return {
automatic: obj.other_config?.automatic === 'true',
bridge: obj.bridge, bridge: obj.bridge,
defaultIsLocked: obj.default_locking_mode === 'disabled', defaultIsLocked: obj.default_locking_mode === 'disabled',
MTU: +obj.MTU, MTU: +obj.MTU,

View File

@ -305,17 +305,23 @@ export default class Xapi extends XapiBase {
async setNetworkProperties( async setNetworkProperties(
id, id,
{ nameLabel, nameDescription, defaultIsLocked } { automatic, defaultIsLocked, nameDescription, nameLabel }
) { ) {
let defaultLockingMode let defaultLockingMode
if (defaultIsLocked != null) { if (defaultIsLocked != null) {
defaultLockingMode = defaultIsLocked ? 'disabled' : 'unlocked' defaultLockingMode = defaultIsLocked ? 'disabled' : 'unlocked'
} }
await this._setObjectProperties(this.getObject(id), { const network = this.getObject(id)
nameLabel, await Promise.all([
nameDescription, this._setObjectProperties(network, {
defaultLockingMode, defaultLockingMode,
}) nameDescription,
nameLabel,
}),
this._updateObjectMapProperty(network, 'other_config', {
automatic: automatic === undefined ? undefined : automatic ? 'true' : null,
}),
])
} }
// ================================================================= // =================================================================

View File

@ -733,6 +733,7 @@ const messages = {
memoryLeftTooltip: '{used}% used ({free} free)', memoryLeftTooltip: '{used}% used ({free} free)',
// ----- Pool network tab ----- // ----- Pool network tab -----
pif: 'PIF', pif: 'PIF',
poolNetworkAutomatic: 'Automatic',
poolNetworkNameLabel: 'Name', poolNetworkNameLabel: 'Name',
poolNetworkDescription: 'Description', poolNetworkDescription: 'Description',
poolNetworkPif: 'PIFs', poolNetworkPif: 'PIFs',

View File

@ -81,6 +81,7 @@ import {
resolveResourceSet, resolveResourceSet,
} from 'utils' } from 'utils'
import { import {
createFilter,
createSelector, createSelector,
createGetObject, createGetObject,
createGetObjectsOfType, createGetObjectsOfType,
@ -485,20 +486,19 @@ export default class NewVm extends BaseComponent {
} }
}) })
const VIFs = [] let VIFs = []
const defaultNetworkIds = this._getDefaultNetworkIds(template)
forEach(template.VIFs, vifId => { forEach(template.VIFs, vifId => {
const vif = getObject(storeState, vifId, resourceSet) const vif = getObject(storeState, vifId, resourceSet)
VIFs.push({ VIFs.push({
network: network:
pool || isInResourceSet(vif.$network) pool || isInResourceSet(vif.$network)
? vif.$network ? vif.$network
: this._getDefaultNetworkId(template), : defaultNetworkIds[0],
}) })
}) })
if (VIFs.length === 0) { if (VIFs.length === 0) {
VIFs.push({ VIFs = defaultNetworkIds.map(id => ({ network: id }))
network: this._getDefaultNetworkId(template),
})
} }
const name_label = const name_label =
state.name_label === '' || !state.name_labelHasChanged state.name_label === '' || !state.name_labelHasChanged
@ -631,21 +631,38 @@ export default class NewVm extends BaseComponent {
) )
} }
) )
_getDefaultNetworkId = template => {
_getAutomaticNetworks = createSelector(
createFilter(this._getPoolNetworks, [network => network.automatic]),
networks => networks.map(_ => _.id)
)
_getDefaultNetworkIds = template => {
if (template === undefined) { if (template === undefined) {
return return []
} }
const network = if (this.props.pool === undefined) {
this.props.pool === undefined const network = find(
? find(this._getResolvedResourceSet().objectsByType.network, { this._getResolvedResourceSet().objectsByType.network,
$pool: template.$pool, {
}) $pool: template.$pool,
: find(this._getPoolNetworks(), network => { }
const pif = getObject(store.getState(), network.PIFs[0]) )
return pif && pif.management return network !== undefined ? [network.id] : []
}) }
return network && network.id
const automaticNetworks = this._getAutomaticNetworks()
if (automaticNetworks.length !== 0) {
return automaticNetworks
}
const network = find(this._getPoolNetworks(), network => {
const pif = getObject(store.getState(), network.PIFs[0])
return pif && pif.management
})
return network !== undefined ? [network.id] : []
} }
_buildVmsNameTemplate = createSelector( _buildVmsNameTemplate = createSelector(
@ -788,9 +805,7 @@ export default class NewVm extends BaseComponent {
this._setState({ this._setState({
VIFs: [ VIFs: [
...state.VIFs, ...state.VIFs,
{ { network: this._getDefaultNetworkIds(state.template)[0] },
network: this._getDefaultNetworkId(state.template),
},
], ],
}) })
} }

View File

@ -79,6 +79,21 @@ class Name extends Component {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
class AutomaticNetwork extends Component {
_editAutomaticNetwork = automatic =>
editNetwork(this.props.network, { automatic })
render() {
const { network } = this.props
return (
<Toggle onChange={this._editAutomaticNetwork} value={network.automatic} />
)
}
}
// -----------------------------------------------------------------------------
class Description extends Component { class Description extends Component {
_editDescription = value => _editDescription = value =>
editNetwork(this.props.network, { name_description: value }) editNetwork(this.props.network, { name_description: value })
@ -343,6 +358,10 @@ const NETWORKS_COLUMNS = [
itemRenderer: network => itemRenderer: network =>
!isEmpty(network.PIFs) && <PifsItem network={network} />, !isEmpty(network.PIFs) && <PifsItem network={network} />,
}, },
{
name: _('poolNetworkAutomatic'),
itemRenderer: network => <AutomaticNetwork network={network} />,
},
{ {
name: '', name: '',
itemRenderer: network => <NetworkActions network={network} />, itemRenderer: network => <NetworkActions network={network} />,