/*
* Copyright 2008-2012 Amazon Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://aws.amazon.com/apache2.0
*
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and
* limitations under the License.
*/
package com.amazonaws.eclipse.ec2.ui.ebs;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.ui.statushandlers.StatusManager;
import com.amazonaws.eclipse.core.AWSClientFactory;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.ec2.Ec2Plugin;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.model.AvailabilityZone;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Snapshot;
/**
* A dialog that allows a user to enter information for creating a new EBS
* volume.
*/
public class CreateNewVolumeDialog extends Dialog {
/** Shared client factory */
private AWSClientFactory clientFactory = AwsToolkitCore.getClientFactory();
/** Spinner control for specifying how large of a volume to create */
private Spinner sizeSpinner;
/** Combo box to select what availability zone to create a volume in */
private Combo availabilityZoneCombo;
/** The volume size */
private int size;
/** The availability zone to create a volume in */
private String availabilityZone;
/** The radio button for creating a volume by size */
private Button emptyVolumeRadioButton;
/** The radio button for creating a volume from a snapshot */
private Button useSnapshotRadioButton;
/** The snapshot selection table */
private SnapshotSelectionTable snapshotSelectionComposite;
/** The id of the selected snapshot */
private String snapshotId;
/**
* The device the new volume should be attached to. This is only
* set if the the new volume being created is explicitly being created
* to be attached to a specific instance.
*/
private String device;
/**
* The instance to which this new volume is being attached. This is only
* present if the new volume being created is explicitly being created to be
* attached to an instance, and isn't set during the normal
* "Create New Volume" workflow.
*/
private Instance instance = null;
private Combo deviceCombo;
/**
* Creates a new dialog ready to be opened to collect information from the
* user on how to create a new EBS volume.
*
* @param parentShell
* The parent shell for this new dialog window.
*/
public CreateNewVolumeDialog(Shell parentShell) {
super(parentShell);
}
/**
* Creates a new dialog ready to be opened to collect information from the
* user on how to create a new EBS volume which will be attached to the
* specified instance. When creating a new volume explicitly for attaching
* it to a specific instance, certain parts of the dialog are different,
* such as the availability zone being locked down to the zone the specified
* instance is in, and a new Combo box is present that allows the user to
* select what device the new EBS volume should be attached as.
*
* @param parentShell
* The parent shell for this new dialog window.
* @param instance
* The instance that the new EBS volume will be attached to.
*/
public CreateNewVolumeDialog(Shell parentShell, Instance instance) {
this(parentShell);
this.instance = instance;
}
/**
* Returns the selected volume size. This method can only be called after
* the dialog's Ok button has been pressed.
*
* @return The selected volume size.
*/
public int getSize() {
return size;
}
/**
* Returns the selected availability zone. This method can only be called
* after the dialog's Ok button has been pressed.
*
* @return The selected availability zone.
*/
public String getAvailabilityZone() {
return availabilityZone;
}
/**
* Returns the selected device that this new volume should be attached to.
*
* @return The selected device that this new volume should be attached to.
*/
public String getDevice() {
return device;
}
/**
* Returns the selected snapshot id. This method can only be called after
* the dialog's Ok button has been pressed.
*
* @return The selected snapshot id.
*/
public String getSnapshotId() {
return snapshotId;
}
/*
* Dialog Interface
*/
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(2, false));
GridData gridData;
SelectionListener selectionListener = new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
public void widgetSelected(SelectionEvent e) {
updateControls();
}
};
/*
* If we aren't creating this new volume explicitly to attach it to
* a specific instance, then we can let the user select an availability
* zone, otherwise we need to lock it down to the availability zone of the
* instance that will be attaching this new volume.
*/
newLabel("Availability Zone:", composite);
if (instance == null) {
availabilityZoneCombo = new Combo(composite, SWT.READ_ONLY);
availabilityZoneCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
populateAvailabilityZoneCombo();
} else {
newLabel(instance.getPlacement().getAvailabilityZone(), composite);
}
/*
* If we are creating this new volume explicitly for attaching it to a
* specified instance, then we also need to let the user select the
* device they want the volume attached as.
*/
if (instance != null) {
newLabel("Device:", composite);
deviceCombo = new Combo(composite, SWT.READ_ONLY);
deviceCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
String devicePrefix = "/dev/sd";
for (char c = 'b'; c <= 'z'; c++) {
deviceCombo.add(devicePrefix + c);
}
deviceCombo.setText("/dev/sdh");
}
emptyVolumeRadioButton = new Button(composite, SWT.RADIO);
emptyVolumeRadioButton.setText("Create empty volume by size (GB):");
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 1;
emptyVolumeRadioButton.setLayoutData(gridData);
emptyVolumeRadioButton.addSelectionListener(selectionListener);
sizeSpinner = new Spinner(composite, SWT.NONE);
sizeSpinner.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
sizeSpinner.setMinimum(1);
sizeSpinner.setMaximum(1024);
sizeSpinner.setEnabled(false);
useSnapshotRadioButton = new Button(composite, SWT.RADIO);
useSnapshotRadioButton.setText("Or create volume from existing snapshot:");
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 2;
useSnapshotRadioButton.setLayoutData(gridData);
useSnapshotRadioButton.addSelectionListener(selectionListener);
snapshotSelectionComposite = new SnapshotSelectionTable(composite);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 2;
gridData.horizontalIndent = 15;
gridData.heightHint = 150;
snapshotSelectionComposite.setLayoutData(gridData);
snapshotSelectionComposite.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
public void widgetSelected(SelectionEvent e) {
updateControls();
}
});
return composite;
}
/**
* Populates the availability zone combo box with the available zones.
*/
private void populateAvailabilityZoneCombo() {
if (availabilityZoneCombo == null) return;
try {
AmazonEC2 ec2 = Ec2Plugin.getDefault().getDefaultEC2Client();
for (AvailabilityZone zone : ec2.describeAvailabilityZones().getAvailabilityZones()) {
availabilityZoneCombo.add(zone.getZoneName());
}
availabilityZoneCombo.select(0);
} catch (Exception e) {
Status status = new Status(Status.ERROR, Ec2Plugin.PLUGIN_ID, "Unable to list availability zones");
StatusManager.getManager().handle(status, StatusManager.LOG);
}
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#create()
*/
@Override
public void create() {
super.create();
String title = null;
if (instance == null) {
title = "Create New EBS Volume";
} else {
title = "Attach New EBS Volume";
}
getShell().setText(title);
emptyVolumeRadioButton.setSelection(true);
updateControls();
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#okPressed()
*/
@Override
protected void okPressed() {
size = sizeSpinner.getSelection();
if (availabilityZoneCombo != null) {
availabilityZone = availabilityZoneCombo.getText();
}
if (deviceCombo != null) {
device = deviceCombo.getText();
}
Snapshot selectedSnapshot = snapshotSelectionComposite.getSelectedSnapshot();
if (selectedSnapshot != null) {
snapshotId = selectedSnapshot.getSnapshotId();
}
super.okPressed();
}
/*
* Private Interface
*/
private void updateControls() {
boolean creatingFromSnapshot = useSnapshotRadioButton.getSelection();
Button okButton = getButton(IDialogConstants.OK_ID);
snapshotSelectionComposite.setEnabled(creatingFromSnapshot);
sizeSpinner.setEnabled(!creatingFromSnapshot);
if (creatingFromSnapshot) {
if (okButton != null) {
Snapshot snapshot = snapshotSelectionComposite.getSelectedSnapshot();
okButton.setEnabled(snapshot != null);
}
} else {
snapshotSelectionComposite.clearSelection();
if (okButton != null) okButton.setEnabled(true);
}
}
private Label newLabel(String text, Composite parent) {
Label l = new Label(parent, SWT.NONE);
l.setText(text);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
l.setLayoutData(gridData);
return l;
}
}