public bool request_spot(string instance_type, string availability_zone, string spot_price, string key_tag) { write_log(region + " に対してスポットリクエストを作成しています。"); int nn = setting_.getValueInt("common", "request_spot_width_of_minutes"); try { InstanceNetworkInterfaceSpecification instanceNetworkInterfaceSpecification = new InstanceNetworkInterfaceSpecification(); instanceNetworkInterfaceSpecification.DeviceIndex = 0; instanceNetworkInterfaceSpecification.SubnetId = subnet_ids[availability_zone]; instanceNetworkInterfaceSpecification.Groups.Add(security_group_id); instanceNetworkInterfaceSpecification.AssociatePublicIpAddress = true; LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.ImageId = image_id; launchSpecification.KeyName = Helper.build_name(setting_, key_tag); launchSpecification.InstanceType = InstanceType.FindValue(instance_type); launchSpecification.Placement = new SpotPlacement(region + availability_zone); launchSpecification.NetworkInterfaces.Add(instanceNetworkInterfaceSpecification); var client = get_client(); var spot_req = new RequestSpotInstancesRequest(); spot_req.SpotPrice = spot_price; spot_req.InstanceCount = 1; spot_req.Type = SpotInstanceType.OneTime; spot_req.ValidUntil = DateTime.Now.AddMinutes(nn); spot_req.LaunchSpecification = launchSpecification; var query_res = client.RequestSpotInstances(spot_req); spot_request_id = query_res.SpotInstanceRequests[0].SpotInstanceRequestId; } catch (Exception ex) { write_log("ERROR: " + ex.ToString()); return(false); } return(true); }
private void create_instance_button_Click(object sender, EventArgs e) { menu_close(); using (AWSEC2Utils awsUtils = new AWSEC2Utils(setting_, write_log)) { bool has_err = false; using (FileStream fs = new FileStream(resouce_dir_ + "region.txt", FileMode.Open, FileAccess.Read)) { awsUtils.region = Helper.get_region(fs, region_combo_box.Text); } string availability_zone = availability_zone_combo_box.Text.ToLower(); string instance_name = instance_text_box.Text; if (instance_name == "" || instance_name.ToLower().Equals("resource")) { write_log("ERROR: インスタンス名が入力されていません。"); has_err = true; } char[] invalidChars = System.IO.Path.GetInvalidFileNameChars(); if (instance_name.IndexOfAny(invalidChars) >= 0) { write_log("ERROR: インスタンス名に使用できない文字が使用されています。(フォルダ名として不適切です)"); has_err = true; } if (instance_name.Length != Encoding.GetEncoding("shift_jis").GetByteCount(instance_name)) { write_log("ERROR: インスタンス名に使用できない文字が使用されています。(全角文字が含まれています)"); has_err = true; } string instance_type = instance_combo_box.Text; if (instance_type == "") { write_log("ERROR: インスタンスタイプが選ばれていません。"); has_err = true; } string vm_type_ = "hvm"; if (AWSEC2Utils.paravirtual_instance_types.Contains(instance_type)) { vm_type_ = "paravirtual"; } string spot_price = price_numeric_up_down.Text; if (spot_price == "") { write_log("ERROR: 値段が入力されていません。"); has_err = true; } if (Convert.ToDouble(spot_price) < 0.001) { MessageBox.Show("金額は $0.001 以上の値を入力してください。", "エラー"); return; } string engine = "", eval = ""; using (FileStream fs = new FileStream(resouce_dir_ + "install_script.txt", FileMode.Open, FileAccess.Read)) { engine = Helper.get_install_script(fs, install_script_combo_box.Text, 1); eval = Helper.get_install_script(fs, install_script_combo_box.Text, 2); } if (engine == "" || eval == "") { write_log("ERROR: エンジンが入力されていません。"); has_err = true; } string save_folder = folder_browser_dialog.SelectedPath + "\\" + instance_text_box.Text; if (Directory.Exists(save_folder) || File.Exists(save_folder)) { DialogResult rtn = MessageBox.Show( this, "既にフォルダが存在します。上書きしますか?", "上書き確認", MessageBoxButtons.OKCancel); if (rtn == DialogResult.Cancel) { return; } Directory.Delete(save_folder + "\\", true); } save_folder = save_folder + "\\"; try { Directory.CreateDirectory(save_folder); } catch { write_log("ERROR: 保存フォルダ(" + save_folder + ")の作成に失敗しました。"); has_err = true; } if (has_err) { MessageBox.Show("失敗しました。", "エラー"); return; } Helper.set_default_str(setting_, "region", awsUtils.region); Helper.set_default_str(setting_, "availability_zone", availability_zone); set_enable(false); string private_key_tmp = null; FileInfo fi_tmp = null; try { private_key_tmp = Path.GetTempFileName(); fi_tmp = new FileInfo(private_key_tmp); Mutex mutex = new Mutex(false, Application.ProductName + awsUtils.region); try { if (mutex.WaitOne(30 * 1000) == false) { MessageBox.Show("処理の開始に失敗しました", "エラー"); return; } if (!awsUtils.check_vpc_id()) { write_log("VPC が存在しないので作成します。"); create_vpc(); awsUtils.check_vpc_id(); } awsUtils.reload_key_pair(private_key_tmp, fi_tmp.Name); if (!awsUtils.check_subnet_id(availability_zone)) { return; } if (!awsUtils.check_security_group_id()) { error("セキュリティグループでエラーが発生しました。"); return; } if (!awsUtils.load_image_id(vm_type_)) { error("マシンイメージでエラーが発生しました。"); return; } if (!awsUtils.request_spot(instance_type, availability_zone, spot_price, fi_tmp.Name)) { error("スポットリクエストでエラーが発生しました。"); return; } } finally { mutex.ReleaseMutex(); } int spot_request_timeout_seconds = setting_.getValueInt("common", "spot_request_timeout_seconds"); string instance_id = ""; long timeout = DateTime.Now.Ticks / TimeSpan.TicksPerSecond + spot_request_timeout_seconds; for (int ii = 0; ii < 1024; ii++) { if (timeout < (DateTime.Now.Ticks / TimeSpan.TicksPerSecond)) { break; } Helper.sleep(100); if ((ii % 30) != 1) { continue; } string request_spot_status = awsUtils.query_request_spot(); if (request_spot_status.IndexOf(",") >= 0) { instance_id = request_spot_status.Substring(request_spot_status.IndexOf(',') + 1); break; } if (request_spot_status.IndexOf("pending-evaluation") < 0 && request_spot_status.IndexOf("pending-fulfillment") < 0) { write_log("スポットリクエストが落札できませんでした。"); instance_id = ""; awsUtils.cancel_spot(); break; } } if (instance_id == "") { awsUtils.cancel_spot(); error("スポットインスタンスが落札できませんでした。"); return; } awsUtils.set_name_tag(instance_id, instance_name); File.WriteAllText(save_folder + "instance_status-" + instance_id + ".url", String.Format("[InternetShortcut]\r\nURL=https://{0}.console.aws.amazon.com/ec2/v2/home?region={0}#Instances:search={1};sort=instanceId", awsUtils.region, instance_id)); bool rollback = true; try { string ipaddress = awsUtils.get_instance_public_ipaddress(instance_id); if (ipaddress == null || ipaddress == "") { error("インスタンスの ipaddress の取得に失敗しました。"); return; } bool flg = false; for (int ii = 0; ii < 3; ii++) { try { if (!execute_script(ipaddress, private_key_tmp, instance_type, engine, eval)) { write_log("ERROR: セットアップスクリプトの実行でエラーが発生しました。(retry)"); continue; } } catch (Exception ex) { write_log("ERROR: " + ex.ToString()); write_log("ERROR: セットアップスクリプトの実行でエラーが発生しました。(retry)"); continue; } flg = true; break; } if (flg == false) { error("セットアップスクリプトの実行に失敗しました。"); return; } File.Copy(resouce_dir_ + "USIEngineViaSSH.ex_", save_folder + "USIEngineViaSSH.exe", true); File.Copy(private_key_tmp, save_folder + "private.pem", true); File.Copy("Renci.SshNet.dll", save_folder + "Renci.SshNet.dll", true); try { File.Copy("Renci.SshNet.LICENSE", save_folder + "Renci.SshNet.LICENSE", true); } catch { // none. } File.WriteAllText(save_folder + "info.txt", ipaddress + ",private.pem\r\n" + "# " + spot_price + "," + instance_type + "," + awsUtils.region + availability_zone + "," + end_time_str_ + "\r\n" + "# ssh -o StrictHostKeyChecking=no -i private.pem ubuntu@" + ipaddress + "\r\n\r\n" + "# UsiClient.exe.config patch (https://sites.google.com/site/shogixyz/home/shogiutil)... \r\n" + "<appSettings>\r\n" + " <add key=\"HostName\" value=\"" + ipaddress + "\"/>\r\n" + " <add key=\"Port\" value=\"53556\"/>\r\n" + " <add key=\"ExePath\" value=\"" + engine + "\"/>\r\n" + "</appSettings>\r\n"); write_log(" " + save_folder + " にエンジンを作成しました"); Process.Start(save_folder); rollback = false; } finally { if (rollback) { write_log("*** 失敗を検知しました、インスタンスを削除を試行します。"); delete_instance(); } } } catch (Exception ex) { write_log("ERROR:\n" + ex.ToString()); } finally { if (private_key_tmp != null) { awsUtils.delete_key_pair(fi_tmp.Name); File.Delete(private_key_tmp); } set_enable(true); } } }