/******************************************************************************* * Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> * This file is part of Gluster Management Console. * * Gluster Management Console is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Gluster Management Console is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. *******************************************************************************/ package org.gluster.storage.management.console.dialogs; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import org.gluster.storage.management.console.GlusterDataModelManager; import org.gluster.storage.management.core.model.Brick; import org.gluster.storage.management.core.model.Device; import org.gluster.storage.management.core.model.Volume; import org.gluster.storage.management.core.model.Brick.BRICK_STATUS; import org.gluster.storage.management.core.model.Volume.NAS_PROTOCOL; import org.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE; import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE; import org.gluster.storage.management.core.utils.ValidationUtil; public class CreateVolumePage1 extends WizardPage { public static final String PAGE_NAME = "create.volume.page.1"; private Text txtName; private ComboViewer typeComboViewer; private Text txtAccessControl; private Text txtCifsUsers; private Volume volume = new Volume(); private Button btnNfs; private Button btnCIFS; private Button btnStartVolume; private Link linkCustomize; private List<Device> allDevices; private List<Device> selectedDevices; /** * Create the wizard. */ public CreateVolumePage1() { super(PAGE_NAME); setTitle("Create Volume"); setDescription("Create a new Volume by choosing bricks from the cluster servers and configuring the volume properties."); // by default, we create volume with all available disks allDevices = GlusterDataModelManager.getInstance().getReadyDevicesOfAllServers(); selectedDevices = allDevices; // volume.setDisks(allDisks); } /** * Create contents of the wizard. * @param parent */ public void createControl(Composite parent) { setPageComplete(false); Composite container = createContainer(parent); createEmptyRow(container); createNameLabel(container); createNameText(container); createTypeLabel(container); createTypeCombo(container); // createTransportTypeLabel(container); // createTransportTypeValueLabel(container); createDisksLabel(container); createDisksCustomizeLink(container); createNasProtocolLabel(container); createNasProtocolCheckboxes(container); createCifsUserLabel(container); createCifsUserText(container); createEmptyLabel(container); createCifsUserInfoLabel(container); createAccessControlLabel(container); createAccessControlText(container); createEmptyLabel(container); createAccessControlInfoLabel(container); createStartVolumeLabel(container); createStartVolumeCheckbox(container); } private void createStartVolumeCheckbox(Composite container) { btnStartVolume = new Button(container, SWT.CHECK); btnStartVolume.setSelection(true); } private void createStartVolumeLabel(Composite container) { Label lblStartVolume = new Label(container, SWT.NONE); lblStartVolume.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblStartVolume.setText("Start Volume: "); } private void createCifsUserInfoLabel(Composite container) { Label lblCifsUserInfo = new Label(container, SWT.TOP); lblCifsUserInfo.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); lblCifsUserInfo.setText("(Comma separated list user names)"); } private void createAccessControlInfoLabel(Composite container) { Label lblAccessControlInfo = new Label(container, SWT.TOP); lblAccessControlInfo.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); lblAccessControlInfo.setText("(Comma separated list of IP addresses/hostnames)"); } private void createEmptyLabel(Composite container) { new Label(container, SWT.NONE); } private void createAccessControlText(Composite container) { txtAccessControl = new Text(container, SWT.BORDER); txtAccessControl.setText("*"); GridData accessControlData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); accessControlData.widthHint = 300; txtAccessControl.setLayoutData(accessControlData); txtAccessControl.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { validateForm(); } }); } private void createAccessControlLabel(Composite container) { Label lblAccessControl = new Label(container, SWT.NONE); lblAccessControl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblAccessControl.setText("Allow Access From: "); } private void createCifsUserLabel(Composite container) { Label lblAccessControl = new Label(container, SWT.NONE); lblAccessControl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblAccessControl.setText("CIFS Users: "); } private void createCifsUserText(Composite container) { txtCifsUsers = new Text(container, SWT.BORDER); // txtCifsUsers.setText("testuser1,testuser2,testuser3"); GridData cifsControlData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); cifsControlData.widthHint = 300; txtCifsUsers.setLayoutData(cifsControlData); txtCifsUsers.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { validateForm(); } }); } private void createNasProtocolCheckboxes(Composite container) { Button btnGluster = new Button(container, SWT.CHECK); btnGluster.setEnabled(false); btnGluster.setSelection(true); btnGluster.setText("Gluster"); createEmptyLabel(container); btnNfs = new Button(container, SWT.CHECK); btnNfs.setEnabled(true); btnNfs.setSelection(true); btnNfs.setText("NFS"); createEmptyLabel(container); btnCIFS = new Button(container, SWT.CHECK); btnCIFS.setEnabled(true); btnCIFS.setSelection(false); btnCIFS.setText("CIFS"); btnCIFS.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { validateForm(); } @Override public void widgetDefaultSelected(SelectionEvent e) { validateForm(); } }); } private void createNasProtocolLabel(Composite container) { Label lblNasProtocol = new Label(container, SWT.RIGHT); lblNasProtocol.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblNasProtocol.setText("Access Protocol: "); } private void createDisksCustomizeLink(Composite container) { linkCustomize = new Link(container, SWT.UNDERLINE_LINK); linkCustomize.setText("All Brick(s) (<a>customize</a>)" ); linkCustomize.setEnabled(false); linkCustomize.addListener (SWT.Selection, new Listener () { public void handleEvent(Event event) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { SelectDisksDialog dialog = new SelectDisksDialog(getShell(), allDevices, selectedDevices, txtName.getText().trim()); dialog.create(); if(dialog.open() == Window.OK) { // user has customized disks. get them from the dialog box. selectedDevices = dialog.getSelectedDevices(); linkCustomize.setText("" + selectedDevices.size() + " Brick(s) (<a>customize</a>)"); validateForm(); } } }); } }); } private void createDisksLabel(Composite container) { Label lblDisks = new Label(container, SWT.RIGHT); lblDisks.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblDisks.setText("Bricks: "); } private void createTypeCombo(Composite container) { typeComboViewer = new ComboViewer(container, SWT.READ_ONLY); Combo typeCombo = typeComboViewer.getCombo(); GridData typeComboData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); typeCombo.setLayoutData(typeComboData); typeComboViewer.setContentProvider(new ArrayContentProvider()); VOLUME_TYPE[] volumeTypes = new VOLUME_TYPE[3]; volumeTypes[0] = VOLUME_TYPE.DISTRIBUTE; volumeTypes[1] = VOLUME_TYPE.REPLICATE; volumeTypes[2] = VOLUME_TYPE.STRIPE; typeComboViewer.setInput(volumeTypes); typeCombo.select(0); // default type = Plain Distribute typeComboViewer.setLabelProvider(new LabelProvider() { @Override public String getText(Object element) { return Volume.getVolumeTypeStr((VOLUME_TYPE)element); } }); typeComboViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { validateForm(); } }); } private void createTypeLabel(Composite container) { Label lblType = new Label(container, SWT.NONE); lblType.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblType.setText("Type: "); } private void createNameText(Composite container) { txtName = new Text(container, SWT.BORDER); GridData txtNameData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); txtNameData.widthHint = 300; txtName.setTextLimit(32); txtName.setLayoutData(txtNameData); txtName.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { validateForm(); } }); } private void createNameLabel(Composite container) { Label lblName = new Label(container, SWT.NONE); lblName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); lblName.setText("Name: "); } private void createEmptyRow(Composite container) { createEmptyLabel(container); createEmptyLabel(container); } private Composite createContainer(Composite parent) { Composite container = new Composite(parent, SWT.NULL); setControl(container); GridLayout gl_container = new GridLayout(2, false); gl_container.verticalSpacing = 10; gl_container.marginHeight = 10; gl_container.marginLeft = 20; gl_container.horizontalSpacing = 10; container.setLayout(gl_container); return container; } public Volume getVolume() { volume.setName(txtName.getText()); IStructuredSelection selection = (IStructuredSelection)typeComboViewer.getSelection(); volume.setVolumeType((VOLUME_TYPE)selection.getFirstElement()); volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT); volume.setStripeCount(Volume.DEFAULT_STRIPE_COUNT); volume.setTransportType(TRANSPORT_TYPE.ETHERNET); // Support only for Ethernet Set<NAS_PROTOCOL> nasProtocols = new HashSet<Volume.NAS_PROTOCOL>(); nasProtocols.add(NAS_PROTOCOL.GLUSTERFS); nasProtocols.add(NAS_PROTOCOL.NFS); volume.setAccessControlList(txtAccessControl.getText()); if (btnNfs.getSelection()) { volume.enableNFS(); } else { volume.disableNFS(); } if (btnCIFS.getSelection()) { volume.enableCifs(); volume.setCifsUsers(Arrays.asList(txtCifsUsers.getText().split(","))); } else { volume.disableCifs(); } addVolumeBricks(); return volume; } private void addVolumeBricks() { // first clear existing bricks, if any volume.getBricks().clear(); for (Device device : selectedDevices) { Brick brick = new Brick(device.getServerName(), BRICK_STATUS.ONLINE, device.getMountPoint() + "/" + volume.getName()); volume.addBrick(brick); } } public Boolean startVolumeAfterCreation() { return btnStartVolume.getSelection(); } public Boolean volumeExists(String volumeName) { List<Volume> volumes = GlusterDataModelManager.getInstance().getModel().getCluster().getVolumes(); for (Volume volume : volumes) { if (volume.getName().equals(volumeName)) { setErrorMessage("Volume name already exists."); return false; } } return true; } private void validateForm() { clearErrors(); validateVolumeName(); validateCifsUsers(); validateAccessControl(); validateDisks(); } private void validateDisks() { int diskCount = selectedDevices.size(); if(diskCount < 1) { setError("At least one brick must be selected!"); } VOLUME_TYPE volumeType = (VOLUME_TYPE) ((IStructuredSelection) typeComboViewer .getSelection()).getFirstElement(); if ((volumeType == VOLUME_TYPE.DISTRIBUTED_REPLICATE || volumeType == VOLUME_TYPE.REPLICATE ) && diskCount % 2 != 0) { setError("Mirror type volume requires bricks in multiples of two"); } else if ((volumeType == VOLUME_TYPE.DISTRIBUTED_STRIPE || volumeType == VOLUME_TYPE.STRIPE) && diskCount % 4 != 0) { setError("Stripe type volume requires bricks in multiples of four"); } } private void validateAccessControl() { String accessControl = txtAccessControl.getText().trim(); if (accessControl.length() == 0) { setError("Please enter Access Control"); return; } if (!ValidationUtil.isValidAccessControl(accessControl)) { setError("Invalid IP address/Host name [" + ValidationUtil.getInvalidIpOrHostname(accessControl) + "]. Please enter a valid value!"); } } private void validateCifsUsers() { if (btnCIFS.getSelection()) { String cifsUserList = txtCifsUsers.getText().trim(); if (cifsUserList.length() == 0) { setError("Please enter cifs user name"); return; } } } private void validateVolumeName() { String volumeName = txtName.getText().trim(); String volumeNameToken = "^[a-zA-Z][a-zA-Z0-9\\-]*"; if (volumeName.length() > 0) { linkCustomize.setEnabled(true); } if(volumeName.length() == 0) { setError("Please enter Volume Name"); linkCustomize.setEnabled(false); } if (!volumeName.matches(volumeNameToken)) { setError("Please enter valid Volume Name"); } if(!volumeExists(volumeName)) { setError("Volume [" + volumeName + "] already exists!"); } } private void clearErrors() { setErrorMessage(null); setPageComplete(true); } private void setError(String errorMsg) { setPageComplete(false); setErrorMessage(errorMsg); } }