]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/CephInstallWizard.js
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" },
57 Ext
. define ( 'PVE.ceph.CephHighestVersionDisplay' , {
58 extend
: 'Ext.form.field.Display' ,
59 xtype
: 'pveCephHighestVersionDisplay' ,
61 fieldLabel
: gettext ( 'Ceph in the cluster' ),
65 // called on success with (release, versionTxt, versionParts)
66 gotNewestVersion
: Ext
. emptyFn
,
68 initComponent : function () {
71 me
. callParent ( arguments
);
73 Proxmox
. Utils
. API2Request ({
75 url
: '/cluster/ceph/metadata' ,
80 success
: ( response
) => {
81 let res
= response
. result
;
82 if (! res
|| ! res
. data
|| ! res
. data
. node
) {
84 gettext ( 'Could not detect a ceph installation in the cluster' ),
88 let nodes
= res
. data
. node
;
90 // can happen on ceph purge, we do not yet cleanup old version data
91 delete nodes
[ me
. nodename
];
95 let maxversiontext
= "" ;
96 for ( const [ _nodename
, data
] of Object
. entries ( nodes
)) {
97 let version
= data
. version
. parts
;
98 if ( PVE
. Utils
. compare_ceph_versions ( version
, maxversion
) > 0 ) {
100 maxversiontext
= data
. version
. str
;
103 // FIXME: get from version selector store
104 const major2release
= {
112 let release
= major2release
[ maxversion
[ 0 ]] || 'unknown' ;
113 let newestVersionTxt
= ` ${Ext.String.capitalize(release)} ( ${maxversiontext} )` ;
115 if ( release
=== 'unknown' ) {
117 gettext ( 'Could not detect a ceph installation in the cluster' ),
120 me
. setValue ( Ext
. String
. format (
121 gettext ( 'Newest ceph version in cluster is {0}' ),
125 me
. gotNewestVersion ( release
, maxversiontext
, maxversion
);
127 failure : function ( response
, opts
) {
128 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
134 Ext
. define ( 'PVE.ceph.CephInstallWizard' , {
135 extend
: 'PVE.window.Wizard' ,
136 alias
: 'widget.pveCephInstallWizard' ,
137 mixins
: [ 'Proxmox.Mixin.CBind' ],
148 cephRelease
: 'quincy' ,
149 cephRepo
: 'enterprise' ,
152 nodeHasSubscription
: true , // avoid warning hint until fully loaded
153 allHaveSubscription
: true , // avoid warning hint until fully loaded
156 repoHintHidden
: get => get ( 'allHaveSubscription' ) && get ( 'cephRepo' ) === 'enterprise' ,
157 repoHint : function ( get ) {
158 let repo
= get ( 'cephRepo' );
159 let nodeSub
= get ( 'nodeHasSubscription' ), allSub
= get ( 'allHaveSubscription' );
161 if ( repo
=== 'enterprise' ) {
163 return gettext ( 'The enterprise repository is enabled, but there is no active subscription!' );
164 } else if (! allSub
) {
165 return gettext ( 'Not all nodes have an active subscription, which is required for cluster-wide enterprise repo access' );
167 return '' ; // should be hidden
168 } else if ( repo
=== 'no-subscription' ) {
170 ? gettext ( "Cluster has active subscriptions and would be elligible for using the enterprise repository." )
171 : gettext ( "The no-subscription repository is not the best choice for production setups." );
173 return gettext ( 'The test repository should only be used for test setups or after consulting the official Proxmox support!' );
182 title
: gettext ( 'Setup' ),
183 navigateNext : function () {
184 var tp
= this . down ( '#wizcontent' );
185 var atab
= tp
. getActiveTab ();
187 var next
= tp
. items
. indexOf ( atab
) + 1 ;
188 var ntab
= tp
. items
. getAt ( next
);
191 tp
. setActiveTab ( ntab
);
194 setInitialTab : function ( index
) {
195 var tp
= this . down ( '#wizcontent' );
196 var initialTab
= tp
. items
. getAt ( index
);
198 tp
. setActiveTab ( initialTab
);
201 this . callParent ( arguments
);
202 let viewModel
= this . getViewModel ();
203 var isInstalled
= this . getViewModel (). get ( 'isInstalled' );
205 viewModel
. set ( 'configuration' , false );
206 this . setInitialTab ( 2 );
209 PVE
. Utils
. getClusterSubscriptionLevel (). then ( subcriptionMap
=> {
210 viewModel
. set ( 'nodeHasSubscription' , !! subcriptionMap
[ this . nodename
]);
212 let allHaveSubscription
= Object
. values ( subcriptionMap
). every ( level
=> !! level
);
213 viewModel
. set ( 'allHaveSubscription' , allHaveSubscription
);
219 title
: gettext ( 'Info' ),
220 viewModel
: {}, // needed to inherit parent viewModel data
223 onlineHelp
: 'chapter_pveceph' ,
234 xtype
: 'pveCephInstallWizardInfo' ,
240 xtype
: 'displayfield' ,
241 fieldLabel
: gettext ( 'Hint' ),
242 labelClsExtra
: 'pmx-hint' ,
247 hidden
: '{repoHintHidden}' ,
251 xtype
: 'pveCephHighestVersionDisplay' ,
254 nodename
: '{nodename}' ,
256 gotNewestVersion : function ( release
, maxversiontext
, maxversion
) {
257 if ( release
=== 'unknown' ) {
260 let wizard
= this . up ( 'pveCephInstallWizard' );
261 wizard
. getViewModel (). set ( 'cephRelease' , release
);
273 xtype
: 'pveCephVersionSelector' ,
278 value
: '{cephRelease}' ,
281 change : function ( field
, release
) {
282 let wizard
= this . up ( 'pveCephInstallWizard' );
283 wizard
. down ( '#next' ). setText (
284 Ext
. String
. format ( gettext ( 'Start {0} installation' ), release
),
290 xtype
: 'proxmoxKVComboBox' ,
291 fieldLabel
: gettext ( 'Repository' ),
294 [ 'enterprise' , gettext ( 'Enterprise (recommended)' )],
295 [ 'no-subscription' , gettext ( 'No-Subscription' )],
296 [ 'test' , gettext ( 'Test' )],
308 activate : function () {
309 // notify owning container that it should display a help button
310 if ( this . onlineHelp
) {
311 Ext
. GlobalEvents
. fireEvent ( 'proxmoxShowHelp' , this . onlineHelp
);
313 let wizard
= this . up ( 'pveCephInstallWizard' );
314 let release
= wizard
. getViewModel (). get ( 'cephRelease' );
315 wizard
. down ( '#back' ). hide ( true );
316 wizard
. down ( '#next' ). setText (
317 Ext
. String
. format ( gettext ( 'Start {0} installation' ), release
),
320 deactivate : function () {
321 if ( this . onlineHelp
) {
322 Ext
. GlobalEvents
. fireEvent ( 'proxmoxHideHelp' , this . onlineHelp
);
324 this . up ( 'pveCephInstallWizard' ). down ( '#next' ). setText ( gettext ( 'Next' ));
329 title
: gettext ( 'Installation' ),
333 nodename
: '{nodename}' ,
335 viewModel
: {}, // needed to inherit parent viewModel data
337 afterrender : function () {
339 if ( this . getViewModel (). get ( 'isInstalled' )) {
340 this . mask ( "Ceph is already installed, click next to create your configuration." , [ 'pve-static-mask' ]);
342 me
. down ( 'pveNoVncConsole' ). fireEvent ( 'activate' );
345 activate : function () {
347 const nodename
= me
. nodename
;
348 me
. updateStore
= Ext
. create ( 'Proxmox.data.UpdateStore' , {
349 storeid
: 'ceph-status-' + nodename
,
353 url
: '/api2/json/nodes/' + nodename
+ '/ceph/status' ,
356 load : function ( rec
, response
, success
, operation
) {
358 me
. updateStore
. stopUpdate ();
359 me
. down ( 'textfield' ). setValue ( 'success' );
360 } else if ( operation
. error
. statusText
. match ( "not initialized" , "i" )) {
361 me
. updateStore
. stopUpdate ();
362 me
. up ( 'pveCephInstallWizard' ). getViewModel (). set ( 'configuration' , false );
363 me
. down ( 'textfield' ). setValue ( 'success' );
364 } else if ( operation
. error
. statusText
. match ( "rados_connect failed" , "i" )) {
365 me
. updateStore
. stopUpdate ();
366 me
. up ( 'pveCephInstallWizard' ). getViewModel (). set ( 'configuration' , true );
367 me
. down ( 'textfield' ). setValue ( 'success' );
368 } else if (! operation
. error
. statusText
. match ( "not installed" , "i" )) {
369 Proxmox
. Utils
. setErrorMask ( me
, operation
. error
. statusText
);
374 me
. updateStore
. startUpdate ();
376 destroy : function () {
378 if ( me
. updateStore
) {
379 me
. updateStore
. stopUpdate ();
385 xtype
: 'pveNoVncConsole' ,
390 nodename
: '{nodename}' ,
392 beforeLoad : function () {
394 let wizard
= me
. up ( 'pveCephInstallWizard' );
395 let release
= wizard
. getViewModel (). get ( 'cephRelease' );
396 let repo
= wizard
. getViewModel (). get ( 'cephRepo' );
397 me
. cmdOpts
= `--version\0 ${release} \0--repository\0 ${repo} ` ;
403 name
: 'installSuccess' ,
413 title
: gettext ( 'Configuration' ),
414 onlineHelp
: 'chapter_pveceph' ,
417 nodename
: '{nodename}' ,
422 minreplicas
: undefined ,
426 activate : function () {
427 this . up ( 'pveCephInstallWizard' ). down ( '#submit' ). setText ( gettext ( 'Next' ));
429 afterrender : function () {
430 if ( this . up ( 'pveCephInstallWizard' ). getViewModel (). get ( 'configuration' )) {
431 this . mask ( "Configuration already initialized" , [ 'pve-static-mask' ]);
436 deactivate : function () {
437 this . up ( 'pveCephInstallWizard' ). down ( '#submit' ). setText ( gettext ( 'Finish' ));
442 xtype
: 'displayfield' ,
443 value
: gettext ( 'Ceph cluster configuration' ) + ':' ,
446 xtype
: 'proxmoxNetworkSelector' ,
449 fieldLabel
: 'Public Network IP/CIDR' ,
452 allowBlank
: '{configuration}' ,
455 nodename
: '{nodename}' ,
459 xtype
: 'proxmoxNetworkSelector' ,
460 name
: 'cluster-network' ,
461 fieldLabel
: 'Cluster Network IP/CIDR' ,
464 emptyText
: gettext ( 'Same as Public Network' ),
466 nodename
: '{nodename}' ,
469 // FIXME: add hint about cluster network and/or reference user to docs??
473 xtype
: 'displayfield' ,
474 value
: gettext ( 'First Ceph monitor' ) + ':' ,
477 xtype
: 'displayfield' ,
478 fieldLabel
: gettext ( 'Monitor node' ),
484 xtype
: 'displayfield' ,
485 value
: gettext ( 'Additional monitors are recommended. They can be created at any time in the Monitor tab.' ),
491 xtype
: 'numberfield' ,
493 fieldLabel
: 'Number of replicas' ,
502 xtype
: 'numberfield' ,
504 fieldLabel
: 'Minimum replicas' ,
506 maxValue
: '{replicas}' ,
507 value
: '{minreplicas}' ,
511 setMaxValue : function ( value
) {
512 this . maxValue
= Ext
. Number
. from ( value
, 2 );
513 // allow enough to avoid split brains with max 'size', but more makes simply no sense
514 if ( this . maxValue
> 4 ) {
517 this . toggleSpinners ();
523 onGetValues : function ( values
) {
524 [ 'cluster-network' , 'size' , 'min_size' ]. forEach ( function ( field
) {
525 if (! values
[ field
]) {
526 delete values
[ field
];
531 onSubmit : function () {
533 if (! this . up ( 'pveCephInstallWizard' ). getViewModel (). get ( 'configuration' )) {
534 var wizard
= me
. up ( 'window' );
535 var kv
= wizard
. getValues ();
537 var nodename
= me
. nodename
;
539 Proxmox
. Utils
. API2Request ({
540 url
: `/nodes/ ${nodename} /ceph/init` ,
541 waitMsgTarget
: wizard
,
544 success : function () {
545 Proxmox
. Utils
. API2Request ({
546 url
: `/nodes/ ${nodename} /ceph/mon/ ${nodename} ` ,
547 waitMsgTarget
: wizard
,
549 success : function () {
550 me
. up ( 'pveCephInstallWizard' ). navigateNext ();
552 failure : function ( response
, opts
) {
553 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
557 failure : function ( response
, opts
) {
558 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
562 me
. up ( 'pveCephInstallWizard' ). navigateNext ();
567 title
: gettext ( 'Success' ),
571 onlineHelp
: 'pve_ceph_install' ,
572 html
: '<h3>Installation successful!</h3>' +
573 '<p>The basic installation and configuration is complete. Depending on your setup, some of the following steps are required to start using Ceph:</p>' +
574 '<ol><li>Install Ceph on other nodes</li>' +
575 '<li>Create additional Ceph Monitors</li>' +
576 '<li>Create Ceph OSDs</li>' +
577 '<li>Create Ceph Pools</li></ol>' +
578 '<p>To learn more, click on the help button below.</p>' ,
580 activate : function () {
581 // notify owning container that it should display a help button
582 if ( this . onlineHelp
) {
583 Ext
. GlobalEvents
. fireEvent ( 'proxmoxShowHelp' , this . onlineHelp
);
586 var tp
= this . up ( '#wizcontent' );
587 var idx
= tp
. items
. indexOf ( this )- 1 ;
588 for (; idx
>= 0 ; idx
--) {
589 var nc
= tp
. items
. getAt ( idx
);
595 deactivate : function () {
596 if ( this . onlineHelp
) {
597 Ext
. GlobalEvents
. fireEvent ( 'proxmoxHideHelp' , this . onlineHelp
);
601 onSubmit : function () {
602 var wizard
= this . up ( 'pveCephInstallWizard' );