mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-09-10 22:14:48 -05:00
feat(xo5/hub): open Hub to all plans and gate recipes individually (#10117)
This commit is contained in:
@@ -24,6 +24,9 @@
|
||||
- [Pool] XO now reconnects to a surviving pool member when the master becomes unreachable (e.g. HA promoted a new master after the old one died), instead of staying stuck on the dead master, including after an XO restart (PR [#10016](https://github.com/vatesfr/xen-orchestra/pull/10016))
|
||||
- [XO6/VIF] Add possibility to create VIF from network tab in VM page (PR [#9677](https://github.com/vatesfr/xen-orchestra/pull/9677))
|
||||
- [vm stats] Reduce the memory consumption of the rrd stats (PR [#10039](https://github.com/vatesfr/xen-orchestra/pull/10039))
|
||||
- [XO6/Site] Add "New VM" and "Connect pool" actions to the site infrastructure tree (PR [#10047](https://github.com/vatesfr/xen-orchestra/pull/10047))
|
||||
- [XO5/Hub] Recipes are now available to all plans, not just Premium (PR [#10117](https://github.com/vatesfr/xen-orchestra/pull/10117))
|
||||
- [Hub] Kubernetes cluster recipe no longer requires the XOA plugin to work (PR [#10127](https://github.com/vatesfr/xen-orchestra/pull/10127))
|
||||
- [XO6/Host] Add possibilty to enable or disable an host (PR [#10074](https://github.com/vatesfr/xen-orchestra/pull/10074))
|
||||
- [XO6/Site] Add "Connect pool" action to the site infrastructure tree (PR [#10047](https://github.com/vatesfr/xen-orchestra/pull/10047))
|
||||
- [VM]: Add possibility to duplicate a VM (PR [#9580](https://github.com/vatesfr/xen-orchestra/pull/9580))
|
||||
@@ -97,5 +100,6 @@
|
||||
- xo-server minor
|
||||
- xo-server-openmetrics minor
|
||||
- xo-server-perf-alert patch
|
||||
- xo-web minor
|
||||
|
||||
<!--packages-end-->
|
||||
|
||||
@@ -151,7 +151,8 @@
|
||||
"xo-collection": "^0.6.1",
|
||||
"xo-common": "^0.10.0",
|
||||
"xo-remote-parser": "^0.10.1",
|
||||
"xo-vmdk-to-vhd": "^2.5.10"
|
||||
"xo-vmdk-to-vhd": "^2.5.10",
|
||||
"yaml": "^2.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.29.0",
|
||||
|
||||
1068
packages/xo-server/src/_hubKubernetesCluster.mjs
Normal file
1068
packages/xo-server/src/_hubKubernetesCluster.mjs
Normal file
File diff suppressed because it is too large
Load Diff
62
packages/xo-server/src/api/hub.mjs
Normal file
62
packages/xo-server/src/api/hub.mjs
Normal file
@@ -0,0 +1,62 @@
|
||||
import { createCluster } from '../_hubKubernetesCluster.mjs'
|
||||
|
||||
createCluster.description = 'Creates a Kubernetes cluster'
|
||||
createCluster.params = {
|
||||
clusterName: { type: 'string' },
|
||||
controlPlaneIpAddress: { type: 'string', optional: true },
|
||||
controlPlaneIpAddresses: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
},
|
||||
gatewayIpAddress: { type: 'string', optional: true },
|
||||
controlPlanePoolSize: {
|
||||
type: 'integer',
|
||||
default: 1,
|
||||
enum: [1, 3, 5, 7],
|
||||
},
|
||||
k8sVersion: {
|
||||
type: 'string',
|
||||
pattern: '[0-9a-zA-Z.]+',
|
||||
optional: true,
|
||||
},
|
||||
nameservers: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
optional: true,
|
||||
},
|
||||
nbNodes: { type: 'integer' },
|
||||
network: { type: 'string' },
|
||||
searches: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
optional: true,
|
||||
},
|
||||
sr: { type: 'string' },
|
||||
sshKey: { type: 'string' },
|
||||
vipAddress: { type: 'string', optional: true },
|
||||
workerNodeIpAddresses: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
optional: true,
|
||||
},
|
||||
xoUrl: { type: 'string' },
|
||||
useInsecureXoConnection: { type: 'boolean', default: false },
|
||||
customClusterPodCIDR: {
|
||||
type: 'string',
|
||||
optional: true,
|
||||
default: '10.1.0.0/16',
|
||||
},
|
||||
customClusterServiceCIDR: {
|
||||
type: 'string',
|
||||
optional: true,
|
||||
default: '10.152.183.0/24',
|
||||
},
|
||||
}
|
||||
createCluster.resolve = { sr: ['sr', 'SR', 'administrate'] }
|
||||
createCluster.permission = 'admin'
|
||||
|
||||
export const recipe = {
|
||||
createKubernetesCluster: createCluster,
|
||||
}
|
||||
@@ -1847,7 +1847,7 @@ export const editVmNotes = async vm => {
|
||||
await _call('vm.set', { id: resolveId(vm), notes: notes || null })
|
||||
}
|
||||
|
||||
export const createKubernetesCluster = params => _call('xoa.recipe.createKubernetesCluster', params)
|
||||
export const createKubernetesCluster = params => _call('hub.recipe.createKubernetesCluster', params)
|
||||
|
||||
export const createEasyVirtVm = params => _call('xoa.recipe.createEasyVirtVm', params)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import Icon from 'icon'
|
||||
import React from 'react'
|
||||
|
||||
import { Container, Col, Row } from 'grid'
|
||||
import { getXoaPlan, routes, TryXoa } from 'utils'
|
||||
import { routes } from 'utils'
|
||||
import { NavLink, NavTabs } from 'nav'
|
||||
|
||||
import Page from '../page'
|
||||
@@ -39,16 +39,7 @@ const Hub = routes('hub', {
|
||||
recipes: Recipes,
|
||||
})(({ children }) => (
|
||||
<Page header={Header} title='hubPage' formatTitle>
|
||||
{getXoaPlan() === 'Community' ? (
|
||||
<Container>
|
||||
<h2 className='text-info'>{_('hubCommunity')}</h2>
|
||||
<p>
|
||||
<TryXoa page='hub' />
|
||||
</p>
|
||||
</Container>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
{children}
|
||||
</Page>
|
||||
))
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import React from 'react'
|
||||
import { adminOnly } from 'utils'
|
||||
import { Container, Col, Row } from 'grid'
|
||||
|
||||
import RecipeKub from './recipe-kub'
|
||||
import RecipeEasyVirt from './recipe-ev'
|
||||
import RECIPES from './recipes'
|
||||
|
||||
// ==================================================================
|
||||
|
||||
@@ -13,12 +12,11 @@ export default decorate([
|
||||
() => (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col mediumSize={4}>
|
||||
<RecipeKub />
|
||||
</Col>
|
||||
<Col mediumSize={4}>
|
||||
<RecipeEasyVirt />
|
||||
</Col>
|
||||
{RECIPES.filter(({ isAvailable }) => isAvailable()).map(({ id, component: Recipe }) => (
|
||||
<Col key={id} mediumSize={4}>
|
||||
<Recipe />
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Container>
|
||||
),
|
||||
|
||||
@@ -70,11 +70,16 @@ export default decorate([
|
||||
},
|
||||
onChangeFaultTolerance(__, faultTolerance) {
|
||||
const { onChange, value } = this.props
|
||||
const willUseHa = faultTolerance.value > 0
|
||||
onChange({
|
||||
...value,
|
||||
faultTolerance: faultTolerance.value,
|
||||
// n * 2 + 1 is the formula to meet the quorum of RAFT consensus algorithm
|
||||
controlPlanePoolSize: faultTolerance.value * 2 + 1,
|
||||
// clear the fields of the mode we're leaving so both aren't sent to the API at submit time
|
||||
controlPlaneIpAddress: willUseHa ? undefined : value.controlPlaneIpAddress,
|
||||
controlPlaneIpAddresses: willUseHa ? value.controlPlaneIpAddresses : undefined,
|
||||
vipAddress: willUseHa ? value.vipAddress : undefined,
|
||||
})
|
||||
},
|
||||
onChangeK8sVersion(__, k8sVersion) {
|
||||
|
||||
18
packages/xo-web/src/xo-app/hub/recipes/recipes.js
Normal file
18
packages/xo-web/src/xo-app/hub/recipes/recipes.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { getXoaPlan } from 'utils'
|
||||
import RecipeEasyVirt from './recipe-ev'
|
||||
import RecipeKub from './recipe-kub'
|
||||
|
||||
const RECIPES = [
|
||||
{
|
||||
id: 'kubernetes',
|
||||
component: RecipeKub,
|
||||
isAvailable: () => true,
|
||||
},
|
||||
{
|
||||
id: 'easyvirt',
|
||||
component: RecipeEasyVirt,
|
||||
isAvailable: () => getXoaPlan() !== 'Community',
|
||||
},
|
||||
]
|
||||
|
||||
export default RECIPES
|
||||
@@ -2,7 +2,7 @@ import _ from 'intl'
|
||||
import decorate from 'apply-decorators'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import { addSubscriptions, adminOnly } from 'utils'
|
||||
import { addSubscriptions, adminOnly, getXoaPlan, TryXoa } from 'utils'
|
||||
import { Container, Col, Row } from 'grid'
|
||||
import { injectState, provideState } from 'reaclette'
|
||||
import { isEmpty, map, omit, orderBy } from 'lodash'
|
||||
@@ -31,24 +31,32 @@ export default decorate([
|
||||
},
|
||||
}),
|
||||
injectState,
|
||||
({ state: { resources } }) => (
|
||||
<Container>
|
||||
<Row>
|
||||
{isEmpty(resources) ? (
|
||||
<Col>
|
||||
<h2 className='text-muted'>
|
||||
{_('vmNoAvailable')}
|
||||
<Icon icon='alarm' color='yellow' />
|
||||
</h2>
|
||||
</Col>
|
||||
) : (
|
||||
resources.map(data => (
|
||||
<Col key={data.namespace} mediumSize={6} largeSize={4}>
|
||||
<Resource {...data} />
|
||||
({ state: { resources } }) =>
|
||||
getXoaPlan() === 'Community' ? (
|
||||
<Container>
|
||||
<h2 className='text-info'>{_('hubCommunity')}</h2>
|
||||
<p>
|
||||
<TryXoa page='hub' />
|
||||
</p>
|
||||
</Container>
|
||||
) : (
|
||||
<Container>
|
||||
<Row>
|
||||
{isEmpty(resources) ? (
|
||||
<Col>
|
||||
<h2 className='text-muted'>
|
||||
{_('vmNoAvailable')}
|
||||
<Icon icon='alarm' color='yellow' />
|
||||
</h2>
|
||||
</Col>
|
||||
))
|
||||
)}
|
||||
</Row>
|
||||
</Container>
|
||||
),
|
||||
) : (
|
||||
resources.map(data => (
|
||||
<Col key={data.namespace} mediumSize={6} largeSize={4}>
|
||||
<Resource {...data} />
|
||||
</Col>
|
||||
))
|
||||
)}
|
||||
</Row>
|
||||
</Container>
|
||||
),
|
||||
])
|
||||
|
||||
@@ -20274,7 +20274,7 @@ yaml-types@^0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/yaml-types/-/yaml-types-0.3.0.tgz#b077f34496e12dc709d97f2c3bad3fff11089680"
|
||||
integrity sha512-i9RxAO/LZBiE0NJUy9pbN5jFz5EasYDImzRkj8Y81kkInTi1laia3P3K/wlMKzOxFQutZip8TejvQP/DwgbU7A==
|
||||
|
||||
yaml@^2.0.0, yaml@^2.4.1, yaml@^2.6.1, yaml@^2.7.0, yaml@^2.8.0, yaml@^2.8.2:
|
||||
yaml@^2.0.0, yaml@^2.4.1, yaml@^2.6.1, yaml@^2.7.0, yaml@^2.8.0, yaml@^2.8.2, yaml@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.9.0.tgz#78274afd93598a1dfdd6130df6a566defcbf9aa4"
|
||||
integrity sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==
|
||||
|
||||
Reference in New Issue
Block a user