ACC SHELL

Path : /usr/share/YaST2/include/partitioning/
File Upload :
Current File : //usr/share/YaST2/include/partitioning/ep-raid-dialogs.ycp

/**
 * File:	ep-raid-dialogs.ycp
 * Package:	yast2-storage
 * Summary:	Expert Partitioner
 * Authors:	Arvin Schnell <aschnell@suse.de>
 *
 * This file must only be included in other Expert Partitioner files ("ep-*.ycp").
 */
{
    textdomain "storage";


    integer MinimalNumberOfDevicesForRaid(string raid_type)
    {
	map<string, integer> info = $[ "raid0" : 2, "raid1" : 2, "raid5" : 3, "raid6" : 4,
				       "raid10" : 2, "multipath" : 2 ];
	return info[raid_type]:0;
    }


    boolean CheckNumberOfDevicesForRaid(string raid_type, integer num)
    {
	integer min_num = MinimalNumberOfDevicesForRaid(raid_type);

	if (num < min_num)
	{
	    map<string, string> info = $[ "raid0" : "RAID0", "raid1" : "RAID1", "raid5" : "RAID5", "raid6" : "RAID6",
					  "raid10" : "RAID10", "multipath" : "Multipath RAID" ];
	    // error popup, %1 is replaced by raid type e.g. "RAID1", %2 is replaced by integer
	    Popup::Error(sformat(_("For %1, select at least %2 device.", "For %1, select at least %2 devices.", min_num),
				 info[raid_type]:"error", min_num));
	    UI::SetFocus(`id(`unselected));
	    return false;
	}
	else
	{
	    return true;
	}
    }


    integer DefaultChunkSizeK(string raid_type)
    {
	map<string, integer> info = $[ "raid0" : 32, "raid5" : 128, "raid6" : 128, "raid10" : 32 ];
	return info[raid_type]:4;
    }


    string MiniWorkflowStepRaidTypeDevicesHelptext()
    {
	// helptext
	string helptext = _("<p>Select the RAID type for the new RAID.</p>");

	// helptext
	helptext = helptext + _("<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>
");

	// helptext
	helptext = helptext + _("<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>
");

	// helptext
	helptext = helptext + _("<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>
");

	// helptext
	helptext = helptext + _("<p>Add partitions to your RAID. 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>
");

	// helptext
	helptext = helptext + _("<p>Generally, the partitions should be on different drives,
to get the redundancy and performance you want.</p>
");

	return helptext;
    }


    symbol MiniWorkflowStepRaidTypeDevices(map<string, any> &data)
    {
	y2milestone("MiniWorkflowStepRaidTypeDevices data:%1", data);

	string raid_type = data["raid_type"]:"raid0";
	string device = data["device"]:"error";
	list<string> devices = data["devices"]:[];

	integer callback(list<map> devices)
	{
	    integer sizeK = 0;
	    Storage::ComputeMdSize(tosymbol(raid_type), maplist(map device, devices, { return device["device"]:""; }), sizeK);
	    return sizeK;
	}

	list<symbol> fields = StorageSettings::FilterTable([ `device, `udev_path, `udev_id, `size, `encrypted, `type ]);

	map<string, map> target_map = Storage::GetTargetMap();
	list<map> unused_devices = filter(map dev, get_possible_rds(target_map), { return isempty(dev["used_by_device"]:"") &&
		    !contains(devices, dev["device"]:""); });
	list<map> used_devices = filter(map dev, get_possible_rds(target_map), { return isempty(dev["used_by_device"]:"") &&
		    contains(devices, dev["device"]:""); });

	term contents = `VBox(`Left(
	    // heading
	    `HVSquash(`FrameWithMarginBox(_("RAID Type"),
			     `RadioButtonGroup(`id(`raid_type),
					       `VBox(
						   // Translators, 'Striping' is a technical term here. Translate only if
						   // you are sure!! If in doubt, leave it in English.
						   `LeftRadioButton(`id(`raid0), `opt(`notify), _("RAID &0  (Striping)"),
								    raid_type == "raid0"),
						   // Translators, 'Mirroring' is a technical term here. Translate only if
						   // you are sure!! If in doubt, leave it in English.
						   `LeftRadioButton(`id(`raid1), `opt(`notify), _("RAID &1  (Mirroring)"),
								    raid_type == "raid1"),
						   // Translators, 'Redundant Striping' is a technical term here. Translate
						   // only if you are sure!! If in doubt, leave it in English.
						   `LeftRadioButton(`id(`raid5), `opt(`notify), _("RAID &5  (Redundant Striping)"),
								    raid_type == "raid5"),
						   // Translators, 'Redundant Striping' is a technical term here. Translate only if
						   // you are sure!! If in doubt, leave it in English.
						   `LeftRadioButton(`id(`raid6), `opt(`notify), _("RAID &6  (Dual Redundant Striping)"),
								    raid_type == "raid6"),
						   // Translators, 'Mirroring' and 'Striping' are technical terms here. Translate only if
						   // you are sure!! If in doubt, leave it in English.
						   `LeftRadioButton(`id(`raid10), `opt(`notify), _("RAID &10  (Mirroring and Striping)"),
								    raid_type == "raid10")
						   )
				 ))))
	    );

	contents = add(contents, `VSpacing(1));
	contents = add(contents, DevicesSelectionBox::Create(unused_devices, used_devices, fields, callback,
							     // label for selection box
							     _("Available Devices:"),
							     // label for selection box
							     _("Selected Devices:")));

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepRaidTypeDevicesHelptext());
	MiniWorkflow::SetLastStep(false);

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();
	    DevicesSelectionBox::Handle(widget);

	    switch (widget)
	    {
		case `raid0:
		case `raid1:
		case `raid5:
		case `raid6:
		case `raid10:
		{
		    raid_type = substring(tostring((symbol) UI::QueryWidget(`id(`raid_type), `Value)), 1);
		    DevicesSelectionBox::UpdateSelectedSize();
		}
		break;

		case `next:
		{
		    devices = maplist(map device, DevicesSelectionBox::GetSelectedDevices(), {
			return device["device"]:"";
		    });

		    if (!CheckNumberOfDevicesForRaid(raid_type, size(devices)))
			widget = `again;
		}
		break;
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    data["raid_type"] = raid_type;
	    data["devices"] = devices;

	    integer size_k = 0;
	    Storage::ComputeMdSize(tosymbol(raid_type), devices, size_k);
	    data["size_k"] = size_k;
	}

	y2milestone("MiniWorkflowStepRaidTypeDevices data:%1 ret:%2", data, widget);

	return widget;
    }


    string MiniWorkflowStepRaidOptionsHelptext(map<string, any> &data)
    {
	string raid_type = data["raid_type"]:"error";

	// helptext
	string helptext = _("<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 128 kB. For RAID 0,
32 kB is a good starting point. For RAID 1, the chunk size does not affect the array very much.</p>
");

	if (raid_type == "raid5")
	    // helptext
	    helptext = helptext + _("<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;
    }


    symbol MiniWorkflowStepRaidOptions(map<string, any> &data)
    {
	y2milestone("MiniWorkflowStepRaidOptions data:%1", data);

	string raid_type = data["raid_type"]:"error";
	integer chunk_size = (data["chunk_size_k"]:DefaultChunkSizeK(raid_type))*1024;
	symbol parity_algorithm = data["parity_algorithm"]:`left_asymmetric;

	list<term> chunk_sizes_list = maplist(integer i, Integer::RangeFrom(11, 22), {
	    return `item(`id(2 << i), Storage::ByteToHumanStringOmitZeroes(2 << i));
	});

	term options = `VBox(
	    `Left(`ComboBoxSelected(`id(`chunk_size), _("Chunk Size"), chunk_sizes_list,
				    `id(chunk_size)))
	    );

	if (raid_type == "raid5")
	    options = add(options,
			  `Left(`ComboBoxSelected(`id(`parity_algorithm), `opt(`hstretch),
						  // combo box label
						  _("Parity &Algorithm"),
						  [ `item(`id(`left_asymmetric), "left-asymmetric"),
						    `item(`id(`left_symmetric), "left-symmetric"),
						    `item(`id(`right_asymmetric), "right-asymmetric"),
						    `item(`id(`right_symmetric), "right-symmetric") ],
						  `id(parity_algorithm)))
		);

	// heading
	term contents = `HVSquash(`FrameWithMarginBox(_("RAID Options"), options));

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepRaidOptionsHelptext(data));
	MiniWorkflow::SetLastStep(false);

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    chunk_size = (integer) UI::QueryWidget(`id(`chunk_size), `Value);

	    if (UI::WidgetExists(`id(`parity_algorithm)))
		parity_algorithm = (symbol) UI::QueryWidget(`id(`parity_algorithm), `Value);

	    data["chunk_size_k"] = chunk_size / 1024;
	    data["parity_algorithm"] = parity_algorithm;
	}

	y2milestone("MiniWorkflowStepRaidOptions data:%1 ret:%2", data, widget);

	return widget;
    }


    string MiniWorkflowStepResizeHelptext()
    {
	// helptext
	string helptext = _("<p>Change the devices that are used for the RAID.</p>");

	return helptext;
    }


    symbol MiniWorkflowStepResizeRaid(map<string, any> &data)
    {
	y2milestone("MiniWorkflowStepResizeRaid data:%1", data);

	string device = data["device"]:"error";
	string raid_type = data["raid_type"]:"error";
	list<string> devices_new = [];

	integer callback(list<map> devices)
	{
	    integer sizeK = 0;
	    Storage::ComputeMdSize(tosymbol(raid_type), maplist(map device, devices, { return device["device"]:""; }), sizeK);
	    return sizeK;
	}

	list<symbol> fields = StorageSettings::FilterTable([ `device, `udev_path, `udev_id, `size, `encrypted, `type ]);

	map<string, map> target_map = Storage::GetTargetMap();
	list<map> unused_devices = filter(map dev, get_possible_rds(target_map), { return dev["used_by_device"]:"" == ""; });
	list<map> used_devices = filter(map dev, get_possible_rds(target_map), { return dev["used_by_device"]:"" == device; });

	term contents = `VBox();

	contents = add(contents, DevicesSelectionBox::Create(unused_devices, used_devices, fields, callback,
							     _("Available Devices:"),
							     _("Selected Devices:")));

	MiniWorkflow::SetContents(Greasemonkey::Transform(contents), MiniWorkflowStepResizeHelptext());
	MiniWorkflow::SetLastStep(true);

	symbol widget = nil;

	repeat
	{
	    widget = MiniWorkflow::UserInput();
	    DevicesSelectionBox::Handle(widget);

	    switch (widget)
	    {
		case `next:
		{
		    devices_new = maplist(map device, DevicesSelectionBox::GetSelectedDevices(), {
			return device["device"]:"";
		    });

		    if (!CheckNumberOfDevicesForRaid(raid_type, size(devices_new)))
			widget = `again;
		}
		break;
	    }
	}
	until (widget == `abort || widget == `back || widget == `next);

	if (widget == `next)
	{
	    data["devices_new"] = devices_new;

	    widget = `finish;
	}

	y2milestone("MiniWorkflowStepResizeRaid data:%1 ret:%2", data, widget);

	return widget;
    }


    boolean DlgCreateRaidNew(map<string, any> &data)
    {
	map<string, any> aliases = $[
	    "TypeDevices" : ``(MiniWorkflowStepRaidTypeDevices(data)),
	    "Options"     : ``(MiniWorkflowStepRaidOptions(data)),
	    "FormatMount" : ``(MiniWorkflowStepFormatMount(data)),
	    "Password"	  : ``(MiniWorkflowStepPassword(data))
	];

	map<string, any> sequence = $[
	    "TypeDevices" : $[ `next : "Options" ],
	    "Options"     : $[ `next : "FormatMount" ],
	    "FormatMount" : $[ `next : "Password",
			       `finish : `finish ],
	    "Password"    : $[ `finish : `finish ]
	];

	// dialog title
	string title = sformat(_("Add RAID %1"), data["device"]:"error");

	symbol widget = MiniWorkflow::Run(title, StorageIcons::raid_icon, aliases, sequence, "TypeDevices");

	return widget == `finish;
    }


    boolean DlgResizeRaid(map<string, any> &data)
    {
	map<string, any> aliases = $[
	    "TheOne" : ``(MiniWorkflowStepResizeRaid(data))
	];

	map<string, any> sequence = $[
	    "TheOne" : $[ `finish : `finish ]
	];

	// dialog title
	string title = sformat(_("Resize RAID %1"), data["device"]:"error");

	symbol widget = MiniWorkflow::Run(title, StorageIcons::raid_icon, aliases, sequence, "TheOne");

	return widget == `finish;
    }


    boolean DlgEditRaid(map<string, any> &data)
    {
	string device = data["device"]:"error";

	map<string, any> aliases = $[
	    "FormatMount" : ``(MiniWorkflowStepFormatMount(data)),
	    "Password"	  : ``(MiniWorkflowStepPassword(data))
	];

	map<string, any> sequence = $[
	    "FormatMount" : $[ `next : "Password",
			       `finish : `finish ],
	    "Password"    : $[ `finish : `finish ]
	];

	// dialog title
	string title = sformat(_("Edit RAID %1"), device);

	symbol widget = MiniWorkflow::Run(title, StorageIcons::raid_icon, aliases, sequence, "FormatMount");

	return widget == `finish;
    }
}

ACC SHELL 2018