]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/CephInstallWizard.js
63dec054cb540f2023199e4a6c1a0cab44abab4f
1 Ext
. define ( 'PVE.ceph.CephInstallWizardInfo' , {
2 extend
: 'Ext.panel.Panel' ,
3 xtype
: 'pveCephInstallWizardInfo' ,
6 <blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified,
7 distributed storage system, designed for excellent performance, reliability,
8 and scalability."</p></blockquote>
10 <b>Ceph</b> is currently <b>not installed</b> on this node. This wizard
11 will guide you through the installation. Click on the next button below
12 to begin. After the initial installation, the wizard will offer to create
13 an initial configuration. This configuration step is only
14 needed once per cluster and will be skipped if a config is already present.
17 Before starting the installation, please take a look at our documentation,
18 by clicking the help button below. If you want to gain deeper knowledge about
19 Ceph, visit <a target="_blank" href="https://docs.ceph.com/en/latest/">ceph.com</a>.
23 Ext
. define ( 'PVE.ceph.CephVersionSelector' , {
24 extend
: 'Ext.form.field.ComboBox' ,
25 xtype
: 'pveCephVersionSelector' ,
27 fieldLabel
: gettext ( 'Ceph version to install' ),
29 displayField
: 'display' ,
30 valueField
: 'release' ,
42 calculate
: d
=> ` ${d.release} ( ${d.version} )` ,
52 { release
: "quincy" , version
: "17.2" },
53 { release
: "reef" , version
: "18.2" },
58 Ext
. define ( 'PVE.ceph.CephHighestVersionDisplay' , {
59 extend
: 'Ext.form.field.Display' ,
60 xtype
: 'pveCephHighestVersionDisplay' ,
62 fieldLabel
: gettext ( 'Ceph in the cluster' ),
66 // called on success with (release, versionTxt, versionParts)
67 gotNewestVersion
: Ext
. emptyFn
,
69 initComponent : function () {
72 me
. callParent ( arguments
);
74 Proxmox
. Utils
. API2Request ({
76 url
: '/cluster/ceph/metadata' ,
81 success
: ( response
) => {
82 let res
= response
. result
;
83 if (! res
|| ! res
. data
|| ! res
. data
. node
) {
85 gettext ( 'Could not detect a ceph installation in the cluster' ),
89 let nodes
= res
. data
. node
;
91 // can happen on ceph purge, we do not yet cleanup old version data
92 delete nodes
[ me
. nodename
];
96 let maxversiontext
= "" ;
97 for ( const [ _nodename
, data
] of Object
. entries ( nodes
)) {
98 let version
= data
. version
. parts
;
99 if ( PVE
. Utils
. compare_ceph_versions ( version
, maxversion
) > 0 ) {
100 maxversion
= version
;
101 maxversiontext
= data
. version
. str
;
104 // FIXME: get from version selector store
105 const major2release
= {
114 let release
= major2release
[ maxversion
[ 0 ]] || 'unknown' ;
115 let newestVersionTxt
= ` ${Ext.String.capitalize(release)} ( ${maxversiontext} )` ;
117 if ( release
=== 'unknown' ) {
119 gettext ( 'Could not detect a ceph installation in the cluster' ),
122 me
. setValue ( Ext
. String
. format (
123 gettext ( 'Newest ceph version in cluster is {0}' ),
127 me
. gotNewestVersion ( release
, maxversiontext
, maxversion
);
129 failure : function ( response
, opts
) {
130 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
136 Ext
. define ( 'PVE.ceph.CephInstallWizard' , {
137 extend
: 'PVE.window.Wizard' ,
138 alias
: 'widget.pveCephInstallWizard' ,
139 mixins
: [ 'Proxmox.Mixin.CBind' ],
150 cephRelease
: 'quincy' ,
151 cephRepo
: 'enterprise' ,
154 nodeHasSubscription
: true , // avoid warning hint until fully loaded
155 allHaveSubscription
: true , // avoid warning hint until fully loaded
158 repoHintHidden
: get => get ( 'allHaveSubscription' ) && get ( 'cephRepo' ) === 'enterprise' ,
159 repoHint : function ( get ) {
160 let repo
= get ( 'cephRepo' );
161 let nodeSub
= get ( 'nodeHasSubscription' ), allSub
= get ( 'allHaveSubscription' );
163 if ( repo
=== 'enterprise' ) {
165 return gettext ( 'The enterprise repository is enabled, but there is no active subscription!' );
166 } else if (! allSub
) {
167 return gettext ( 'Not all nodes have an active subscription, which is required for cluster-wide enterprise repo access' );
169 return '' ; // should be hidden
170 } else if ( repo
=== 'no-subscription' ) {
172 ? gettext ( "Cluster has active subscriptions and would be elligible for using the enterprise repository." )
173 : gettext ( "The no-subscription repository is not the best choice for production setups." );
175 return gettext ( 'The test repository should only be used for test setups or after consulting the official Proxmox support!' );
184 title
: gettext ( 'Setup' ),
185 navigateNext : function () {
186 var tp
= this . down ( '#wizcontent' );
187 var atab
= tp
. getActiveTab ();
189 var next
= tp
. items
. indexOf ( atab
) + 1 ;
190 var ntab
= tp
. items
. getAt ( next
);
193 tp
. setActiveTab ( ntab
);
196 setInitialTab : function ( index
) {
197 var tp
= this . down ( '#wizcontent' );
198 var initialTab
= tp
. items
. getAt ( index
);
200 tp
. setActiveTab ( initialTab
);
203 this . callParent ( arguments
);
204 let viewModel
= this . getViewModel ();
205 var isInstalled
= this . getViewModel (). get ( 'isInstalled' );
207 viewModel
. set ( 'configuration' , false );
208 this . setInitialTab ( 2 );
211 PVE
. Utils
. getClusterSubscriptionLevel (). then ( subcriptionMap
=> {
212 viewModel
. set ( 'nodeHasSubscription' , !! subcriptionMap
[ this . nodename
]);
214 let allHaveSubscription
= Object
. values ( subcriptionMap
). every ( level
=> !! level
);
215 viewModel
. set ( 'allHaveSubscription' , allHaveSubscription
);
221 title
: gettext ( 'Info' ),
222 viewModel
: {}, // needed to inherit parent viewModel data
225 onlineHelp
: 'chapter_pveceph' ,
236 xtype
: 'pveCephInstallWizardInfo' ,
242 xtype
: 'displayfield' ,
243 fieldLabel
: gettext ( 'Hint' ),
244 labelClsExtra
: 'pmx-hint' ,
249 hidden
: '{repoHintHidden}' ,
253 xtype
: 'pveCephHighestVersionDisplay' ,
256 nodename
: '{nodename}' ,
258 gotNewestVersion : function ( release
, maxversiontext
, maxversion
) {
259 if ( release
=== 'unknown' ) {
262 let wizard
= this . up ( 'pveCephInstallWizard' );
263 wizard
. getViewModel (). set ( 'cephRelease' , release
);
275 xtype
: 'pveCephVersionSelector' ,
280 value
: '{cephRelease}' ,
283 change : function ( field
, release
) {
284 let wizard
= this . up ( 'pveCephInstallWizard' );
285 wizard
. down ( '#next' ). setText (
286 Ext
. String
. format ( gettext ( 'Start {0} installation' ), release
),
292 xtype
: 'proxmoxKVComboBox' ,
293 fieldLabel
: gettext ( 'Repository' ),
296 [ 'enterprise' , gettext ( 'Enterprise (recommended)' )],
297 [ 'no-subscription' , gettext ( 'No-Subscription' )],
298 [ 'test' , gettext ( 'Test' )],
310 activate : function () {
311 // notify owning container that it should display a help button
312 if ( this . onlineHelp
) {
313 Ext
. GlobalEvents
. fireEvent ( 'proxmoxShowHelp' , this . onlineHelp
);
315 let wizard
= this . up ( 'pveCephInstallWizard' );
316 let release
= wizard
. getViewModel (). get ( 'cephRelease' );
317 wizard
. down ( '#back' ). hide ( true );
318 wizard
. down ( '#next' ). setText (
319 Ext
. String
. format ( gettext ( 'Start {0} installation' ), release
),
322 deactivate : function () {
323 if ( this . onlineHelp
) {
324 Ext
. GlobalEvents
. fireEvent ( 'proxmoxHideHelp' , this . onlineHelp
);
326 this . up ( 'pveCephInstallWizard' ). down ( '#next' ). setText ( gettext ( 'Next' ));
331 title
: gettext ( 'Installation' ),
335 nodename
: '{nodename}' ,
337 viewModel
: {}, // needed to inherit parent viewModel data
339 afterrender : function () {
341 if ( this . getViewModel (). get ( 'isInstalled' )) {
342 this . mask ( "Ceph is already installed, click next to create your configuration." , [ 'pve-static-mask' ]);
344 me
. down ( 'pveNoVncConsole' ). fireEvent ( 'activate' );
347 activate : function () {
349 const nodename
= me
. nodename
;
350 me
. updateStore
= Ext
. create ( 'Proxmox.data.UpdateStore' , {
351 storeid
: 'ceph-status-' + nodename
,
355 url
: '/api2/json/nodes/' + nodename
+ '/ceph/status' ,
358 load : function ( rec
, response
, success
, operation
) {
360 me
. updateStore
. stopUpdate ();
361 me
. down ( 'textfield' ). setValue ( 'success' );
362 } else if ( operation
. error
. statusText
. match ( "not initialized" , "i" )) {
363 me
. updateStore
. stopUpdate ();
364 me
. up ( 'pveCephInstallWizard' ). getViewModel (). set ( 'configuration' , false );
365 me
. down ( 'textfield' ). setValue ( 'success' );
366 } else if ( operation
. error
. statusText
. match ( "rados_connect failed" , "i" )) {
367 me
. updateStore
. stopUpdate ();
368 me
. up ( 'pveCephInstallWizard' ). getViewModel (). set ( 'configuration' , true );
369 me
. down ( 'textfield' ). setValue ( 'success' );
370 } else if (! operation
. error
. statusText
. match ( "not installed" , "i" )) {
371 Proxmox
. Utils
. setErrorMask ( me
, operation
. error
. statusText
);
376 me
. updateStore
. startUpdate ();
378 destroy : function () {
380 if ( me
. updateStore
) {
381 me
. updateStore
. stopUpdate ();
387 xtype
: 'pveNoVncConsole' ,
392 nodename
: '{nodename}' ,
394 beforeLoad : function () {
396 let wizard
= me
. up ( 'pveCephInstallWizard' );
397 let release
= wizard
. getViewModel (). get ( 'cephRelease' );
398 let repo
= wizard
. getViewModel (). get ( 'cephRepo' );
399 me
. cmdOpts
= `--version\0 ${release} \0--repository\0 ${repo} ` ;
405 name
: 'installSuccess' ,
415 title
: gettext ( 'Configuration' ),
416 onlineHelp
: 'chapter_pveceph' ,
419 nodename
: '{nodename}' ,
424 minreplicas
: undefined ,
428 activate : function () {
429 this . up ( 'pveCephInstallWizard' ). down ( '#submit' ). setText ( gettext ( 'Next' ));
431 afterrender : function () {
432 if ( this . up ( 'pveCephInstallWizard' ). getViewModel (). get ( 'configuration' )) {
433 this . mask ( "Configuration already initialized" , [ 'pve-static-mask' ]);
438 deactivate : function () {
439 this . up ( 'pveCephInstallWizard' ). down ( '#submit' ). setText ( gettext ( 'Finish' ));
444 xtype
: 'displayfield' ,
445 value
: gettext ( 'Ceph cluster configuration' ) + ':' ,
448 xtype
: 'proxmoxNetworkSelector' ,
451 fieldLabel
: 'Public Network IP/CIDR' ,
454 allowBlank
: '{configuration}' ,
457 nodename
: '{nodename}' ,
461 xtype
: 'proxmoxNetworkSelector' ,
462 name
: 'cluster-network' ,
463 fieldLabel
: 'Cluster Network IP/CIDR' ,
466 emptyText
: gettext ( 'Same as Public Network' ),
468 nodename
: '{nodename}' ,
471 // FIXME: add hint about cluster network and/or reference user to docs??
475 xtype
: 'displayfield' ,
476 value
: gettext ( 'First Ceph monitor' ) + ':' ,
479 xtype
: 'displayfield' ,
480 fieldLabel
: gettext ( 'Monitor node' ),
486 xtype
: 'displayfield' ,
487 value
: gettext ( 'Additional monitors are recommended. They can be created at any time in the Monitor tab.' ),
493 xtype
: 'numberfield' ,
495 fieldLabel
: 'Number of replicas' ,
504 xtype
: 'numberfield' ,
506 fieldLabel
: 'Minimum replicas' ,
508 maxValue
: '{replicas}' ,
509 value
: '{minreplicas}' ,
513 setMaxValue : function ( value
) {
514 this . maxValue
= Ext
. Number
. from ( value
, 2 );
515 // allow enough to avoid split brains with max 'size', but more makes simply no sense
516 if ( this . maxValue
> 4 ) {
519 this . toggleSpinners ();
525 onGetValues : function ( values
) {
526 [ 'cluster-network' , 'size' , 'min_size' ]. forEach ( function ( field
) {
527 if (! values
[ field
]) {
528 delete values
[ field
];
533 onSubmit : function () {
535 if (! this . up ( 'pveCephInstallWizard' ). getViewModel (). get ( 'configuration' )) {
536 var wizard
= me
. up ( 'window' );
537 var kv
= wizard
. getValues ();
539 var nodename
= me
. nodename
;
541 Proxmox
. Utils
. API2Request ({
542 url
: `/nodes/ ${nodename} /ceph/init` ,
543 waitMsgTarget
: wizard
,
546 success : function () {
547 Proxmox
. Utils
. API2Request ({
548 url
: `/nodes/ ${nodename} /ceph/mon/ ${nodename} ` ,
549 waitMsgTarget
: wizard
,
551 success : function () {
552 me
. up ( 'pveCephInstallWizard' ). navigateNext ();
554 failure : function ( response
, opts
) {
555 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
559 failure : function ( response
, opts
) {
560 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
564 me
. up ( 'pveCephInstallWizard' ). navigateNext ();
569 title
: gettext ( 'Success' ),
573 onlineHelp
: 'pve_ceph_install' ,
574 html
: '<h3>Installation successful!</h3>' +
575 '<p>The basic installation and configuration is complete. Depending on your setup, some of the following steps are required to start using Ceph:</p>' +
576 '<ol><li>Install Ceph on other nodes</li>' +
577 '<li>Create additional Ceph Monitors</li>' +
578 '<li>Create Ceph OSDs</li>' +
579 '<li>Create Ceph Pools</li></ol>' +
580 '<p>To learn more, click on the help button below.</p>' ,
582 activate : function () {
583 // notify owning container that it should display a help button
584 if ( this . onlineHelp
) {
585 Ext
. GlobalEvents
. fireEvent ( 'proxmoxShowHelp' , this . onlineHelp
);
588 var tp
= this . up ( '#wizcontent' );
589 var idx
= tp
. items
. indexOf ( this )- 1 ;
590 for (; idx
>= 0 ; idx
--) {
591 var nc
= tp
. items
. getAt ( idx
);
597 deactivate : function () {
598 if ( this . onlineHelp
) {
599 Ext
. GlobalEvents
. fireEvent ( 'proxmoxHideHelp' , this . onlineHelp
);
603 onSubmit : function () {
604 var wizard
= this . up ( 'pveCephInstallWizard' );