home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
boot
/
i386
/
root
/
usr
/
share
/
YaST2
/
include
/
partitioning
/
raid_ui.ycp
< prev
next >
Wrap
Text File
|
2006-11-29
|
32KB
|
1,179 lines
/**
* File:
* raid_ui.ycp
*
* Module:
* Configuration of raid
*
* Summary:
* User interface functions.
*
* Authors:
* Michael Hager <mike@suse.de>
*
* $Id: raid_ui.ycp 33346 2006-10-12 10:47:02Z fehr $
*
* All user interface functions for RAID.
*
*/
{
textdomain "storage";
import "Wizard";
import "Storage";
import "FileSystems";
import "Partitions";
import "Label";
import "Popup";
include "partitioning/raid_lib.ycp";
include "partitioning/partition_defines.ycp";
include "partitioning/custom_part_lib.ycp";
/**
* AbortDialog
**/
define symbol AbortDialog()
``{
if( Popup::ReallyAbort(true))
return `yes;
else
return `back;
}
define boolean CheckRaidNumbers( integer raidnr )
``{
integer max_raid = 27;
list<map> parts = get_possible_rds( Storage::GetTargetMap() );
string dev = sformat("md%1", raidnr);
parts = filter( map e, parts, ``(e["used_by"]:""==dev));
y2milestone( "CheckRaidNumbers size %1 parts %2", size(parts), parts );
if( size(parts) >= max_raid )
{
// popup text
string text = sformat(_("
The maximum number of partitions in a software raid is %1.
You want to add more partitions to the raid than can be
handled by the current version of software raid.
"), max_raid);
Popup::Error(text);
}
return( size(parts) < max_raid );
}
/**
* Help for RaidTypeDialog
* @return string
*/
define string ChooseRaidTypeHelp()
``{
// help text
string help = _("<p><b>RAID 0:</b> This level increases your disk performance.
There is <b>NO</b> redundancy in this mode. If one of the drives crashes, data recovery will not be possible.</p>
");
// help text
help = help + _("<p><b>RAID 1:</b> <br>This mode has the best redundancy. It can be
used with two or more disks. This mode maintains an exact copy of all data on all
disks. As long as at least one disk is still working, no data is lost. The partitions
used for this type of RAID should have approximately the same size.</p>
");
// help text
help = help + _("<p><b>RAID 5:</b> <br>This mode combines management of a larger number
of disks and still maintains some redundancy. This mode can be used on three disks or more.
If one disk fails, all data is still intact. If two disks fail simultaneously, all data is lost</p>
");
// help text
help = help + _("<p><b>Multipath:</b> <br>This mode allow access to the same physical device
over multiple controllers for redundancy against a fault in a controller card. This mode can be used with at least two devices<p>
");
return help;
};
/**
* Contents for dialog ChooseRaidType
* @return term
**/
define term get_choose_raid_type_contents( string raid, symbol what )
``{
integer space = 0;
term MpDetect = `Empty();
if( what == `settings )
{
space = 5;
}
else
{
MpDetect = `Left( `HBox( `HSpacing(7),
`PushButton(`id(`mp_auto),
// button text
_("Auto&detect Multipath"))));
}
// Translators, 'Striping' is a technical term here. Translate only if
// you are sure!! If in doubt, leave it in English.
string str_text = _("RAID &0 (Striping)");
// Translators, 'Mirroring' is a technical term here. Translate only if
// you are sure!! If in doubt, leave it in English.
string mir_text = _("RAID &1 (Mirroring)");
// Translators, 'Redundant Striping' is a technical term here. Translate
// only if you are sure!! If in doubt, leave it in English.
string r5_text = _("RAID &5 (Redundant Striping)");
// label text
string mp_text = _("&Multipath (Redundant access over two controllers)");
return
`VBox(
`VSpacing(space),
// popup text
`Heading (_("What type of RAID would you like to create?")),
`VSpacing(1),
`RadioButtonGroup(
`id("raid_type"),
`HSquash(
`VBox(
`Left(`RadioButton(`id("raid0"), str_text,
raid=="raid0")),
`VSpacing (1),
`Left(`RadioButton(`id("raid1"), mir_text,
raid=="raid1")),
`VSpacing (1),
`Left(`RadioButton(`id("raid5"), r5_text,
raid=="raid5"))
/*
`VSpacing (1),
`Left(`RadioButton(`id("multipath"), mp_text,
raid=="multipath")),
MpDetect
*/
)
)
),
`VSpacing(space)
);
};
define string RaidMultipathAutoHelp()
``{
// help text
string help = _("<p>The list contains the devices that could be automatically
detected for multipath setup. Disable the devices not to
have activated by double-clicking the table line and continue when
finished. If you go back, none of the autodetected multipath raid devices
are created.</p>
<p>If you deselect lines, the names of the raid devices
after the deselected lines will be changed.</p>
");
return( help );
};
/**
* RaidMultipathAuto Dialog
* @return symbol
*/
define symbol RaidMultipathAuto()
``{
// Choose Raid Type ...
/////////////////////////////////////////////////////////////////
y2milestone( "enter" );
// heading text
string caption = _("RAID Wizard: Multipath Autodetection");
map<string,map> tg = Storage::GetTargetMap();
list<map> raids = tg["/dev/md","partitions"]:[];
list<map> mp_raids = filter( map p, raids,
``(p["create"]:false &&
p["raid_type"]:""=="multipath"));
foreach( map p, mp_raids,
``{
foreach( string dev, map disk, tg,
``{
list new_part = [];
foreach( map pt, disk["partitions"]:[],
``{
if( pt["used_by"]:""==substring(p["device"]:"",5) )
{
pt = filter( string k, any value, (map<string,any>)pt,
``( k != "used_by" && k != "used_by_type" ));
if( pt["change_fsid"]:false )
{
pt["fsid"] = pt["ori_fsid"]:0;
pt["fstype"] = pt["ori_fstype"]:"";
pt = filter( string key, any value, (map<string,any>)pt,
``( key != "ori_fsid" &&
key != "change_fsid" &&
key != "ori_fstype" ));
}
}
new_part = add( new_part, pt );
});
tg[dev,"partitions"] = new_part;
});
raids = filter( map part, raids, ``(part["nr"]:0 != p["nr"]:0));
});
if( haskey( tg, "/dev/md" ))
{
tg["/dev/md","partitions"] = raids;
}
map<integer,list<string> > at = $[];
list raid_list = [];
list raid_enab = [];
integer raid_num = -1;
integer i=0;
foreach(list<string> entry, Storage::AutodetectMultipathRaid( tg ),
``{
raid_num = get_free_raid_nr( tg, raid_num+1 );
raid_list = add( raid_list, raid_num );
raid_enab = add( raid_enab, true );
string dev = Storage::GetDeviceName( "/dev/md", raid_num );
at[i] = entry;
i = i+1;
});
y2milestone( "at=%1", at );
y2milestone( "rl=%1", raid_list );
term contents =
// popup text
`Label(_("No automatically configurable\nmultipath devices detected"));
if( size(at)>0 )
{
integer i = 0;
list ct = maplist( integer key, list content, at,
``{
term a = `item( `id(i) );
// label text
a = add( a, _("Yes") );
a = add( a, Storage::GetDeviceName( "/dev/md",
raid_list[key]:255 ));
a = add( a, content[0]:"" );
a = add( a, content[1]:"" );
string rest = "";
if( size(content)>2 )
{
rest = mergestring( (list<string>)remove(remove(content,0),0),
" ");
}
a = add( a, rest );
i = i + 1;
return( a );
});
term header = `header();
// heading text
header = add( header, _("Create") );
// heading text
header = add( header, _("Raid Device") );
// heading text
header = add( header, _("Partition 1") );
// heading text
header = add( header, _("Partition 2") );
// heading text
header = add( header, _("Other...") );
contents = `HBox(`HSpacing(8),
`VBox(`VSpacing(2),
`Table( `id(`mp_table), `opt(`notify),
header, ct ),
`VSpacing(2) ),
`HSpacing(8));
}
Wizard::SetContentsButtons(caption, contents, RaidMultipathAutoHelp(),
Label::BackButton(), Label::NextButton());
symbol ret = `next;
do
{
ret = (symbol)UI::UserInput();
y2milestone( "ret %1", ret );
if( ret == `mp_table )
{
integer cur = (integer) UI::QueryWidget( `id(`mp_table),
`CurrentItem );
integer sel_num = 0;
integer i = 0;
while( i<cur )
{
if( raid_enab[i]:false )
{
sel_num = sel_num + 1;
}
i=i+1;
}
string dev = "";
if( !raid_enab[i]:false )
{
dev = Storage::GetDeviceName( "/dev/md",
raid_list[sel_num]:255 );
sel_num = sel_num + 1;
}
raid_enab[i] = !raid_enab[i]:false;
UI::ChangeWidget(`id(`mp_table), `Item(cur, 1), dev );
UI::ChangeWidget(`id(`mp_table), `Item(cur, 0),
// label text
size(dev)==0?_("No"):_("Yes") );
i = cur+1;
while( i<size(raid_enab) )
{
if( raid_enab[i]:false )
{
dev = Storage::GetDeviceName( "/dev/md",
raid_list[sel_num]:255 );
sel_num = sel_num + 1;
UI::ChangeWidget(`id(`mp_table), `Item(i, 1), dev );
}
i = i+1;
}
}
if( ret == `next )
{
integer i = 0;
list md_part = [];
while( i<size(raid_enab) )
{
if( raid_enab[i]:false )
{
string dev = sformat( "/dev/md%1", raid_list[i]:255 );
map rp = $[ "nr" : raid_list[i]:255,
"device" : dev,
"raid_type" : "multipath",
"type" : `sw_raid,
"fsid" : Partitions::fsid_native,
"size_k" : 0, // dummy
"create" : true,
"used_fs" : Partitions::DefaultFs() ];
map p = $[];
foreach( string device, (list<string>)at[i]:[],
``{
p = Storage::GetPartition( tg, device );
p["used_by_type"] = `UB_MD;
p["used_by"] = substring(dev,5);
if( p["fsid"]:0 != Partitions::fsid_raid )
{
if( !p["change_fsid"]:false )
{
p["change_fsid"] = true;
p["ori_fsid"] = p["fsid"]:0;
p["ori_fstype"] = p["fstype"]:"";
}
p["fsid"] = Partitions::fsid_raid;
p["fstype"] =
Partitions::FsIdToString(Partitions::fsid_raid);
}
y2debug( "p1 %1", p );
tg = (map<string,map>)Storage::SetPartition( tg, p );
});
integer mdsize = raid_size_byte(rp);
y2milestone( "mdsize=%1", mdsize );
rp["size_k"] = mdsize / 1024;
md_part = add( md_part, rp );
y2milestone( "enabled %1 num:%2 entry:%3", i,
raid_list[i]:255, at[i]:[] );
y2milestone( "rp %1", rp );
}
i = i+1;
}
if( size(md_part)>0 )
{
tg = Storage::GetTargetMap();
tg["/dev/md","partitions"] =
merge( tg["/dev/md","partitions"]:[], md_part );
Storage::SetTargetMap( tg );
}
}
}
while( ret != `back && ret !=`next && ret !=`abort );
y2milestone( "ret %1", ret );
return ret;
}
/**
* ChooseRaidType Dialog
* @parm what -> `settings or `wizard
* @return symbol
*/
define symbol ChooseRaidType(symbol what)
``{
integer raidnr = 0;
map raidp = $[];
Storage::CreateTargetBackup("raid");
y2milestone( "ChooseRaidType what:%1", what );
map<string,map> tg = Storage::GetTargetMap();
string rdev = Storage::GetWizardKey();
if( size(rdev)==0 )
{
raidnr = get_free_raid_nr( tg, 0 );
rdev = sformat( "/dev/md%1", raidnr );
Storage::SetWizardKey(rdev);
}
else
{
raidp = Storage::GetPartition( tg, rdev );
raidnr = raidp["nr"]:0;
}
y2milestone( "ChooseRaidType raidp raidp=%1", raidp );
y2milestone( "ChooseRaidType nr=%1 dev:%2", raidnr, rdev );
/////////////////////////////////////////////////////////////////
// Choose Raid Type ...
/////////////////////////////////////////////////////////////////
// heading text
string caption = _("RAID Wizard: Step 1.");
term contents =
get_choose_raid_type_contents(raidp["raid_type"]:"raid1", what );
if( what == `wizard )
{
Wizard::SetContentsButtons(caption, contents,
ChooseRaidTypeHelp(),
Label::BackButton(),
Label::NextButton());
}
else if ( what == `settings )
{
contents = add( contents,
`HBox(
// popup create partition:
`PushButton(`id(`ok), `opt(`default),
Label::OKButton() ),
// popup create partition:
`PushButton(`id(`cancel), Label::CancelButton() )
));
UI::OpenDialog( `opt(`decorated ),
`HBox(
`HWeight(50, `RichText( ChooseRaidTypeHelp() )),
`HStretch(),
`HSpacing(1),
`HWeight(70, contents ),
`HSpacing(1),
`HStretch()
));
}
else
{
y2error( " Error what in ChooseRaidType must be symbol `wizard or `settings");
}
boolean new_raid = size(raidp)==0;
symbol ret = `none;
y2milestone( "ChooseRaidType new_raid:%1", new_raid );
do
{
ret = (symbol)UI::UserInput();
if( contains( [ `next, `ok, `accept ], ret ))
{
////////////////////////////////////////////////////////////
// Create initial raid datastructure, which comes to
// /dev/md[partitions]
string raidtype = (string)UI::QueryWidget( `id("raid_type"),
`CurrentButton );
y2milestone( "ChooseRaidType raidtype:%1", raidtype );
integer chunk_size = 4;
if( raidtype == "raid5" ) chunk_size = 128;
if( raidtype == "raid0" ) chunk_size = 32;
if( raidp == $[] || what == `settings )
{
string mprop = GetMountPointProposal( tg, [] );
symbol used_fs = Partitions::DefaultFs();
if( mprop == Partitions::BootMount() )
{
used_fs = Partitions::DefaultBootFs();
}
Storage::CreateMd( raidnr, raidtype );
raidp = $[ "device" : rdev,
"format" : true,
"mount" : mprop,
"used_fs" : used_fs ];
Storage::ChangeVolumeProperties( raidp );
raidp = Storage::GetPartition( Storage::GetTargetMap(), rdev );
y2milestone( "ChooseRaidType raidp:%1", raidp );
}
else
Storage::ChangeMdType( raidnr, raidtype );
Storage::ChangeMdChunk( raidnr, chunk_size );
ret = `next;
}
else if( ret == `back && what==`wizard && !new_raid )
{
// popup text %1 will be replaces with button text
string txt = sformat( _("Changes made to your RAID setup so far will be
lost if you exit the dialog with %1.
Continue?
"),
deletechars(Label::BackButton(),"&") );
if( !Popup::ContinueCancel( txt ))
{
ret = `again;
}
}
}
while( !contains( [`next, `back ], ret ));
if( what == `settings)
{
UI::CloseDialog();
}
if( ret == `back && what==`wizard )
{
y2milestone( "ChooseRaidType raidp:%1", raidp );
if( raidp["create"]:false )
{
string md = sformat( "md%1", raidp["nr"]:0 );
list<map> parts = filter( map p, all_raid_partitions(tg),
``(p["used_by"]:""==md));
foreach( map p, parts,
``{
Storage::UnchangePartitionId( p["device"]:"" );
});
y2milestone( "ChooseRaidType parts:%1", parts );
Storage::DeleteDevice( "/dev/md", raidp["device"]:"" );
}
}
y2milestone( "ChooseRaidType ret %1", ret );
return ret;
}
/**
* Help for RaidDevices Dialog
* @return string
*/
define string RaidDevicesHelp()
``{
// help text, richtext format
string helptext = _("<p><b>Add partitions to your RAID.</b> According to
the RAID type, the usable disk size is the sum of these partitions (RAID0), the size
of the smallest partition (RAID 1), or (N-1)*smallest partition (RAID 5).</p>
");
// help text, richtext format
helptext = helptext + _("<p>Generally, the partitions should be on different drives,
to get the redundancy and performance you want.</p>
");
// help text, richtext format
helptext = helptext + _("<p><b>Expert options:</b><br>Here, set
things like chunk size to get the best performance
out of your system. These settings are used for all partitions of this RAID.</p>
");
return helptext;
}
/**
* Popup to display an error when changing an existing raid.
*
* in dev: device name of the raid device
*/
define void CannotEditExistingRaid( string dev )
``{
// Error popup text
Popup::Error(sformat( _("The RAID to change (%1) is already created on disk.
It can no longer be changed. To change %1,
remove it and create it again.
"),dev));
};
/**
* partition add partition widget table.
* @return term
*/
define term get_raid_devices_content( symbol what, string current_raid_text,
list all_raids, string size_md )
``{
term top = `HBox(
`Left (`Label (current_raid_text)),
// Label in raid -wf
`Label (_("Size:")),
`Label (`id(`raid_size), `opt( `outputField), "---------")
);
if( what == `settings )
{
top = `HBox(
`Left(`VBox(
`ReplacePoint(`id(`raids_rp),
`ComboBox(`id(`raids),
`opt(`notify),
// label text
_("RA&ID:"), all_raids)),
`PushButton( `id(`md_raid_edit),
// label text
`opt(`hstretch), _("O&ptions"))
)),
`HSpacing(0.5),
// label text
`Left(`Label(_("Size:"))),
`Left(`Label( `id(`raid_size),
`opt( `hstretch, `outputField), "-------" )),
`HWeight(1,`HStretch()),
`Right(`VBox(
`PushButton( `id(`md_raid_remove),
`opt(`hstretch),
// button text
_("Remo&ve RAID")),
`PushButton( `id(`md_raid_add),
`opt(`hstretch),
// button text
_("Add RAI&D"))))
);
}
return( `HBox(
`HSpacing(1),
`VBox(
`VSpacing (0.5),
top,
`VSpacing (0.2),
`Table(`id(`raid_table), `opt(`notify),
// table header
`header(_(" Device "),
// table header
`Right(_(" Size ")),
// table header
`Center(_(" Type ")),
// table header
`Center(_(" RAID "))),
[]
),
`HBox (
// Button in RAID-WF
`PushButton (`id (`raid_add), _("A&dd")),
// Button in RAID-WF
`PushButton (`id (`raid_remove), _("&Remove"))
),
`VSpacing (0.5)
),
`HSpacing(1)
)
);
};
/**
* RaidExpertDlgHelp
* @return string
*/
define string RaidExpertDlgHelp()
``{
// help text
string helptext_edit_raid = _("<p><b>chunk size:</b><br>It is the smallest \"atomic\" mass
of data that can be written to the devices. A reasonable chunk size for RAID 5 is 128KB. For RAID 0,
32 KB is a good starting point. For RAID 1, the chunk size does not affect the array very much.</p>
");
// help text
helptext_edit_raid = helptext_edit_raid + _("<p><b>parity algorithm:</b><br>The parity algorithm to use with RAID5.
Left-symmetric is the one that offers maximum performance on typical disks with rotating platters.</p>
");
return helptext_edit_raid;
};
/**
* raidExpertDlg dialog
* edit expert options
*/
define map<string,any>
RaidExpertDlg( symbol what, string device, map<string,any> cur_raid,
map<symbol,map> file_systems, boolean edit_raid_type,
map<string,map> targetMap )
``{
string raid_type = cur_raid["raid_type"]:"raid1";
// heading text
string caption = sformat(_("Raid settings %1"), device );
boolean created = cur_raid["create"]:false;
term contents = `HBox(
FormatDlg( cur_raid, file_systems ),
`HSpacing(2),
`VBox(
`Top( RaidOptionsDlg( cur_raid, true )),
`Bottom(
`ReplacePoint( `id(`mount_dlg_rp),
MountDlg( cur_raid, [] )))
)
);
if( what == `settings )
{
contents = `VBox(
`Heading(caption),
`VSpacing(1),
`VStretch(),
contents,
`VSpacing(1),
`VStretch(),
`HBox(
// popup create partition:
`PushButton(`id(`ok), `opt(`default),
Label::OKButton() ),
// popup create partition:
`PushButton(`id(`cancel), Label::CancelButton() )
));
/////////////////////////////////////////////////////////////
// Open main dialog for Raid
/////////////////////////////////////////////////////////////
if( ! UI::OpenDialog( `opt(`decorated ),
`HBox(
`HWeight(30,`RichText(RaidExpertDlgHelp())),
`HStretch(),
`HSpacing(1),
`HWeight(70, contents ),
`HSpacing(1),
`HStretch()
)))
return cur_raid;
}
else
{
// heading text
Wizard::SetContentsButtons(_("RAID Wizard Step 3:"),
`HBox(
`HSpacing(),
`VBox(
`VSpacing(),
`HVCenter(`HVSquash(contents)),
`VSpacing(),
`VSpacing(1)
),
`HSpacing()
),
RaidExpertDlgHelp(),
Label::BackButton(), Label::FinishButton());
}
////////////////////////////////////////////////////////////////
// configure main dialog for the first call
ChangeExistingSymbolsState( [`raid_combo], false);
UI::ChangeWidget( `id(`raid_combo), `Value, raid_type );
UI::ChangeWidget( `id(`chunk_size), `Value, cur_raid["chunk_size"]:4 );
UI::ChangeWidget( `id(`parity), `Enabled, created && raid_type=="raid5" );
UI::ChangeWidget( `id(`chunk_size), `Enabled,
created && raid_type!="multipath" );
map<string,any> retval = eval(cur_raid);
symbol ret = `ok;
retval = HandlePartWidgetChanges( true, ret, file_systems, cur_raid, retval );
repeat
{
ret = (symbol)UI::UserInput();
y2debug( "DlgRaid %1", ret);
////////////////////////////////////////////////////////////
if( ret != `cancel )
{
retval = HandlePartWidgetChanges( false, ret, file_systems,
cur_raid, retval );
if( edit_raid_type )
retval["raid_type"] =
UI::QueryWidget(`id(`raid_combo), `Value);
retval["chunk_size"] = UI::QueryWidget(`id(`chunk_size), `Value);
retval["parity_algorithm"] = UI::QueryWidget(`id(`parity), `Value);
y2milestone( "RaidExpertDlg retval:%1", retval );
}
if( ret == `raid_combo )
{
UI::ChangeWidget( `id(`parity), `Enabled,
created && raid_type=="raid5" );
UI::ChangeWidget( `id(`chunk_size), `Enabled,
created && raid_type!="multipath" );
}
if( ret == `ok || ret == `next )
{
map ret_mp = CheckOkMount( retval["device"]:"", cur_raid, retval );
retval = ret_mp["map"]:$[];
if( !ret_mp["ok"]:false )
{
if( ret_mp["field"]:`none != `none )
UI::SetFocus(`id( ret_mp["field"]:`none ));
ret = `again;
continue;
}
ret_mp = CheckDeviceFinalOk( retval );
if( !ret_mp["ok"]:false )
{
ret = `again;
}
else
{
retval = ret_mp["map"]:$[];
y2milestone( "RaidExpertDlg retval:%1", retval );
}
}
} until( ret == `ok || ret == `cancel || ret == `next ||
ret == `back || ret == `abort );
y2milestone( "ret:%1 retval=%2", ret, retval );
if( ret == `back || ret == `next )
{
retval["symbol"] = ret;
}
else
{
UI::CloseDialog();
}
if( ret == `ok || ret == `next || ret == `back )
{
y2milestone( "RaidExpertDlg retval:%1", retval );
Storage::ChangeVolumeProperties( retval );
if( edit_raid_type && haskey( retval, "raid_type" ))
Storage::ChangeMdType( retval["nr"]:0, retval["raid_type"]:"raid1" );
if( haskey( retval, "chunk_size" ))
Storage::ChangeMdChunk( retval["nr"]:0, retval["chunk_size"]:4 );
if( retval["raid_type"]:"raid1"=="raid5" &&
haskey( retval, "parity_algorithm" ))
Storage::ChangeMdParity( retval["nr"]:0,
retval["parity_algorithm"]:"" );
return retval;
}
return cur_raid;
}
/**
* AddRaidDevices dialog
*
* Choose free partitions and add them to the raid.
* additionally you can edit the raid options like chunk size
* in -
* out:
*/
define symbol RaidDevices( symbol what )
``{
y2milestone( "RaidDevices what %1", what );
Storage::CreateTargetBackup("raid");
string raiddev = Storage::GetWizardKey();
y2milestone( "RaidDevices Current raid; raiddev=%1", raiddev );
map<string,map> tg = Storage::GetTargetMap();
map<string,any> raidp = Storage::GetPartition( tg, raiddev );
y2milestone( "RaidDevices raidp=%1", raidp );
/* e.g.: subdevraidindex = 1; */
integer raidnr = raidp["nr"]:0;
// heading text
string caption = _("RAID Wizard Step 2:");
/* key for subdev that can assigned to a raid */
string pdevice = "";
if( what == `settings )
{
// heading text
caption = _("RAID settings");
}
list<map> parts = [];
list table = [];
Wizard::SetContentsButtons( caption,
get_raid_devices_content(what,
// label text
sformat(_("Current RAID: /dev/md%1"), raidnr),
get_raid_devices(tg,raidp["nr"]:0),
""
),
RaidDevicesHelp(),
Label::BackButton(), Label::NextButton() );
UI::SetFocus( `id(`raid_table));
//////////////////////////////////////////////////////////////////////
// mainloop
//////////////////////////////////////////////////////////////////////
symbol ret = `start;
tg = Storage::GetTargetMap();
repeat
{
//////////////////////////////////////////////////////////
// Raid ComboBox
if( what == `settings )
{
raiddev = (string)UI::QueryWidget(`id(`raids), `Value );
y2milestone( "RaidDevices Selected Raid in ComboBox; raiddev=%1",
raiddev );
raidp = Storage::GetPartition( tg, raiddev );
raidnr = raidp["nr"]:255;
}
y2milestone( "RaidDevices Current raid; raiddev=%1", raiddev );
y2milestone( "RaidDevices ret %1", ret );
///////////////////////////////////////////////////////////
// Update raid widget table
if( ret != `raids || ret == `start )
{
parts = get_possible_rds( tg );
if( what == `wizard )
{
parts = filter( map part, parts,
``( part["used_by"]:"" == sformat("md%1",raidnr) ||
size(part["used_by"]:"")==0 ));
}
y2milestone( "RaidDevices parts %1", parts );
/////////////////////////////////////////////////////////////////
// Show the current state:
table = get_raid_widget_table( parts );
UI::ChangeWidget( `id(`raid_table), `Items, table);
}
UI::ChangeWidget( `id(`raid_size), `Value, raid_size_str( raidp ));
if( pdevice != "" && (ret == `raid_add || ret == `raid_remove) )
{
UI::ChangeWidget( `id(`raid_table), `CurrentItem, pdevice);
}
/////////////////////////////////////////////////////////////////
// Wait for User input
ret = (symbol)UI::UserInput();
y2milestone( "RaidDevices ret %1", ret );
/////////////////////////////////////////////////////////////////
// Edit raid settings - not in wizard
if( ret == `md_raid_edit )
{
RaidExpertDlg( `settings, raiddev, raidp,
FileSystems::GetAllFileSystems(true,true),
false, tg );
tg = Storage::GetTargetMap();
raidp = Storage::GetPartition( tg, raiddev );
}
/////////////////////////////////////////////////////////////////
// Add a new raid
if( ret == `md_raid_add )
{
if( !check_raid_possible( tg ))
{
ret = `again;
continue;
}
ChooseRaidType( `settings );
tg = Storage::GetTargetMap();
y2milestone( "RaidDevices new raid:%1", Storage::GetWizardKey() );
if( Storage::GetWizardKey()!=raiddev )
{
raiddev = Storage::GetWizardKey();
y2milestone( "RaidDevices new raid:%1", raiddev );
UI::ChangeWidget( `id(`raids), `Value, raiddev );
raidp = Storage::GetPartition( tg, raiddev );
}
}
/////////////////////////////////////////////////////////////////
// Remove a new raid (2//dev/md ) - not in wizard
if( ret == `md_raid_remove )
{
// popup text
if ( Popup::YesNo ( sformat(_("Do you really want to delete partition %1?"), "/dev/md"+raidnr )))
{
Storage::DeleteDevice( "/dev/md", raiddev );
tg = Storage::GetTargetMap();
}
}
/////////////////////////////////////////////////////////////////
// Update Raid ComboBox - not in wizard
if( ret == `md_raid_add || ret == `md_raid_remove )
{
new_raid_list( get_raid_devices( tg, raidp["nr"]:0 ));
raiddev = (string)UI::QueryWidget(`id(`raids), `Value );
y2milestone( "RaidDevices raiddev %1", raiddev );
raidp = Storage::GetPartition( tg, raiddev );
raidnr = raidp["nr"]:0;
}
if( ret == `raid_table )
{
pdevice = (string)UI::QueryWidget( `id(`raid_table), `CurrentItem );
ret = isItemRd(tg,pdevice) ? `raid_remove : `raid_add;
}
/////////////////////////////////////////////////////////////
// Add a new physical volume to a raid e.g. assign 1//dev/hda
// to 1//dev/md
if( ret == `raid_add )
{
pdevice = (string)UI::QueryWidget( `id(`raid_table), `CurrentItem );
if( CheckItemIsNotRaid( tg, pdevice ) &&
CheckRaidNumbers( raidnr ) )
{
if( raidp["create"]:false )
{
Storage::SetPartitionId( pdevice, Partitions::fsid_raid );
Storage::ExtendMd( raidnr, pdevice );
tg = Storage::GetTargetMap();
raidp = Storage::GetPartition( tg, raiddev );
}
else
{
CannotEditExistingRaid( raiddev );
ret = `again;
}
}
}
/////////////////////////////////////////////////////////////
// Delete a new physical volume e.g. remove 1//dev/hda from 1//dev/md
if( ret == `raid_remove )
{
pdevice = (string)UI::QueryWidget(`id(`raid_table), `CurrentItem);
if( CheckItemIsRaid( tg, pdevice) )
{
if( raidp["create"]:false )
{
Storage::UnchangePartitionId( pdevice );
Storage::ShrinkMd( raidnr, pdevice );
tg = Storage::GetTargetMap();
raidp = Storage::GetPartition( tg, raiddev );
}
else
{
CannotEditExistingRaid( raiddev );
ret = `again;
}
}
}
if (ret == `next)
{
///////////////////////////////////////////////////////
// check if enough disks are attached to the raid
list<map> parts = (list<map>)Storage::GetDisk( tg, "/dev/md" )["partitions"]:[];
foreach( map part, parts,
``{
if( part["create"]:false )
{
string raid_type = part["raid_type"]:"raid1";
integer nr_of_parts =
getNrOfParts( tg, sformat("%1", part["nr"]:0) );
string raid = part["device"]:"";
boolean ok = Storage::CheckMd(part["nr"]:0)==0;
if( !ok )
{
string txt = "";
if( raid_type=="raid0" )
{
// Error popup text
txt = sformat(_("For RAID 0, add at least two partitions to %1."), raid );
}
else if( raid_type=="raid1" )
{
// Error popup text
txt = sformat(_("For RAID 1, add at least two partitions to %1."), raid );
}
else if( raid_type == "raid5" )
{
// Error popup text
txt = sformat(_("For RAID 5, add at least three partitions to %1."), raid);
}
else if( raid_type == "raid6" )
{
// Error popup text
txt = sformat(_("For RAID 6, add at least four partitions to %1."), raid);
}
else if( raid_type == "raid10" )
{
// Error popup text
txt = sformat(_("For RAID 10, add at least two partitions to %1."), raid);
}
else if( raid_type == "multipath" )
{
// Error popup text
txt = sformat(_("For Multipath raid, add at least two partitions to %1."), raid);
}
Popup::Error(txt);
ret = `again;
}
}
});
}
}
until( ret == `next || ret == `back || ret == `cancel || ret == `abort );
return ret;
}
/**
* RaidExpertWizard
*
*/
define symbol RaidExpertWizard()
``{
string raiddev = Storage::GetWizardKey();
map<string,map> tg = Storage::GetTargetMap();
map<string,any> raidp = Storage::GetPartition( tg, raiddev );
raidp = RaidExpertDlg( `wizard, raidp["used_by"]:"", raidp,
FileSystems::GetAllFileSystems(true, true),
false, tg );
symbol ret = raidp["symbol"]:`next;
y2milestone( "RaidExpertWizard ret:%1", ret );
return ret;
}
}