Cloudlaunch: Automatically detect placement AZ of volumes from existing clusters, and launch using those placements. This prevents any "CRITICAL: This instance must be relaunched in zone..." at cloudman start. Also reworked error handling.

This commit is contained in:
Dannon Baker
2012-11-01 15:39:38 -04:00
parent 3d491f63c1
commit c41e8923b8
2 changed files with 62 additions and 33 deletions
@@ -59,14 +59,34 @@ class CloudController(BaseUIController):
if pd:
# This is a cloudman bucket.
# We need to get persistent data, and the cluster name.
# DBTODO: Add pyyaml egg, and rewrite this.
# This will also allow for much more sophisticated rendering of existing clusters
# Currently, this zone detection is a hack.
pd_contents = pd.get_contents_as_string()
zone = ''
try:
for line in pd_contents.split('\n'):
if 'vol_id' in line:
vol_id = line.split(':')[1].strip()
v = ec2_conn.get_all_volumes(volume_ids = [vol_id])
if v:
zone = v[0].zone
else:
zone = ''
except:
#If anything goes wrong with zone detection, use the default selection.
zone = ''
for key in bucket.list():
if key.name.endswith('.clusterName'):
clusters.append({'name': key.name.split('.clusterName')[0], 'persistent_data': pd.get_contents_as_string()})
clusters.append({'name': key.name.split('.clusterName')[0],
'persistent_data': pd_contents,
'zone':zone})
account_info['clusters'] = clusters
account_info['zones'] = [z.name for z in ec2_conn.get_all_zones()]
return to_json_string(account_info)
@web.expose
def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string, keypair, **kwargs):
def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string, keypair, zone=None, **kwargs):
ec2_error = None
try:
# Create security group & key pair used when starting an instance
@@ -90,7 +110,8 @@ class CloudController(BaseUIController):
rs = run_instance(ec2_conn=ec2_conn,
user_provided_data=user_provided_data,
key_name=kp_name,
security_groups=[sg_name])
security_groups=[sg_name],
placement=zone)
if rs:
instance = rs.instances[0]
ct = 0
@@ -241,7 +262,7 @@ def create_key_pair(ec2_conn, key_name=DEFAULT_KEYPAIR):
def run_instance(ec2_conn, user_provided_data, image_id=DEFAULT_AMI,
kernel_id=None, ramdisk_id=None, key_name=DEFAULT_KEYPAIR,
security_groups=['CloudMan']):
placement=None, security_groups=['CloudMan']):
""" Start an instance. If instance start was OK, return the ResultSet object
else return None.
"""
@@ -257,7 +278,8 @@ def run_instance(ec2_conn, user_provided_data, image_id=DEFAULT_AMI,
security_groups=security_groups,
user_data=ud,
kernel_id=kernel_id,
ramdisk_id=ramdisk_id)
ramdisk_id=ramdisk_id,
placement=placement)
except EC2ResponseError, e:
log.error("Problem starting an instance: %s\n%s" % (e, e.body))
if rs:
+35 -28
View File
@@ -60,6 +60,8 @@
<script type="text/javascript">
var ACCOUNT_URL = "${h.url_for( controller='/cloudlaunch', action='get_account_info')}";
var PKEY_DL_URL = "${h.url_for( controller='/cloudlaunch', action='get_pkey')}";
var cloudlaunch_clusters = [];
$(document).ready(function(){
$('#id_existing_instance').change(function(){
var ei_name = $(this).val();
@@ -82,6 +84,7 @@
$.getJSON(ACCOUNT_URL,
{key_id: key_el.val(),secret:secret_el.val()},
function(result){
cloudlaunch_clusters = result.clusters;
var kplist = $("#id_keypair");
var clusterlist = $("#id_existing_instance");
kplist.find('option').remove();
@@ -112,48 +115,52 @@
$('form').ajaxForm({
type: 'POST',
dataType: 'json',
beforeSubmit: function(data){
beforeSubmit: function(data, form){
if ($('#id_password').val() != $('#id_password_confirm').val()){
//Passwords don't match.
$('#cloudlaunch_form').prepend('<div class="errormessage">Passwords do not match</div>');
form.prepend('<div class="errormessage">Passwords do not match</div>');
return false;
}else{
//Clear errors
$('.errormessage').remove()
//Hide the form, show pending box with spinner.
$('#launchFormContainer').hide('fast');
$('#responsePanel').show('fast');
}
//Dig up zone info for selected cluster, set hidden input.
//This is not necessary to present to the user though the interface may prove useful.
var ei_val = _.find(data, function(f_obj){return f_obj.name === 'existing_instance'});
if( ei_val.value !== "New Cluster"){
var cluster = _.find(cloudlaunch_clusters, function(cluster){return cluster.name === ei_val.value});
var zdata = _.find(data, function(f_obj){return f_obj.name === 'zone'});
zdata.value = cluster.zone;
}
},
success: function(data){
//Success Message, link to key download if required, link to server itself.
$('#launchPending').hide('fast');
//Check for success/error.
if (data.error){
//Apologize profusely.
$("launchPending").hide();
$("#launchError").show();
}else{
//Set appropriate fields (dns, key, ami) and then display.
if(data.kp_material_tag){
var kp_download_link = $('<a/>').attr('href', PKEY_DL_URL + '?kp_material_tag=' + data.kp_material_tag)
.attr('target','_blank')
.text("Download your key now");
$('#keypairInfo').append(kp_download_link);
$('#keypairInfo').show();
}
$('.kp_name').text(data.kp_name);
$('#instance_id').text(data.instance_id);
$('#image_id').text(data.image_id);
$('#instance_link').html($('<a/>')
.attr('href', 'http://' + data.public_dns_name + '/cloud')
.attr('target','_blank')
.text(data.public_dns_name + '/cloud'));
$('#instance_dns').text(data.public_dns_name);
$('#launchSuccess').show('fast');
//Set appropriate fields (dns, key, ami) and then display.
if(data.kp_material_tag){
var kp_download_link = $('<a/>').attr('href', PKEY_DL_URL + '?kp_material_tag=' + data.kp_material_tag)
.attr('target','_blank')
.text("Download your key now");
$('#keypairInfo').append(kp_download_link);
$('#keypairInfo').show();
}
$('.kp_name').text(data.kp_name);
$('#instance_id').text(data.instance_id);
$('#image_id').text(data.image_id);
$('#instance_link').html($('<a/>')
.attr('href', 'http://' + data.public_dns_name + '/cloud')
.attr('target','_blank')
.text(data.public_dns_name + '/cloud'));
$('#instance_dns').text(data.public_dns_name);
$('#launchSuccess').show('fast');
},
error: function(data){
$('#cloudlaunch_form').prepend('<div class="errormessage">' + data.responseText + '</div>');
error: function(jqXHR, textStatus, errorThrown){
$('#launchFormContainer').prepend('<div class="errormessage">' + errorThrown + " : " + jqXHR.responseText + '</div>');
$('#responsePanel').hide('fast');
$('#launchFormContainer').show('fast');
}
});
});
@@ -196,6 +203,7 @@ Credentials section of the AWS Console</a>. </div>
<label for="id_existing_instance">Instances in your account</label>
<select name="existing_instance" id="id_existing_instance">
</select>
<input id='id_zone' type='hidden' name='zone' value=''/>
</div>
<div id='cluster_name_wrapper' class="form-row">
<label for="id_cluster_name">Cluster Name</label>
@@ -253,7 +261,6 @@ Credentials section of the AWS Console</a>. </div>
</div>
<div id="responsePanel" class="toolForm" style="display:none;">
<div id="launchPending">Launch Pending, please be patient.</div>
<div id="launchError" style="display:none;">ERROR</div>
<div id="launchSuccess" style="display:none;">
<div id="keypairInfo" style="display:none;margin-bottom:20px;">
<h3>Very Important Key Pair Information</h3>