payload: {"action":"created","comment":{"url":"https://api.github.com/repos/jonhoo/tsunami/pulls/comments/335622027","pull_request_review_id":302763189,"id":335622027,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMzNTYyMjAyNw==","diff_hunk":"@@ -0,0 +1,858 @@\n+use crate::ssh;\n+use crate::Machine;\n+use failure::{Error, ResultExt};\n+use itertools::Itertools;\n+use rusoto_core::request::HttpClient;\n+use rusoto_core::{ProvideAwsCredentials, Region};\n+use rusoto_ec2::Ec2;\n+use std::collections::HashMap;\n+use std::io::Write;\n+use std::sync::Arc;\n+use std::{thread, time};\n+\n+struct UbuntuAmi(String);\n+\n+impl From<Region> for UbuntuAmi {\n+    fn from(r: Region) -> Self {\n+        // https://cloud-images.ubuntu.com/locator/\n+        // ec2 20190814 releases\n+        UbuntuAmi(\n+            match r {\n+                Region::ApEast1 => \"ami-e0ff8491\",               // Hong Kong\n+                Region::ApNortheast1 => \"ami-0cb1c8cab7f5249b6\", // Tokyo\n+                Region::ApNortheast2 => \"ami-081626bfb3fbc9f49\", // Seoul\n+                Region::ApSouth1 => \"ami-0cf8402efdb171312\",     // Mumbai\n+                Region::ApSoutheast1 => \"ami-099d318f80eab7e94\", // Singapore\n+                Region::ApSoutheast2 => \"ami-08a648fb5cc86fb74\", // Sydney\n+                Region::CaCentral1 => \"ami-0bc1dd4eb012a451e\",   // Canada\n+                Region::EuCentral1 => \"ami-0cdab515472ca0bac\",   // Frankfurt\n+                Region::EuNorth1 => \"ami-c37bf0bd\",              // Stockholm\n+                Region::EuWest1 => \"ami-01cca82393e531118\",      // Ireland\n+                Region::EuWest2 => \"ami-0a7c91b6616d113b1\",      // London\n+                Region::EuWest3 => \"ami-033e0056c336ecff0\",      // Paris\n+                Region::SaEast1 => \"ami-094c359b4d8c6a8ca\",      // Sao Paulo\n+                Region::UsEast1 => \"ami-064a0193585662d74\",      // N Virginia\n+                Region::UsEast2 => \"ami-021b7b04f1ac696c2\",      // Ohio\n+                Region::UsWest1 => \"ami-056d04da775d124d7\",      // N California\n+                Region::UsWest2 => \"ami-09a3d8a7177216dcf\",      // Oregon\n+                x => panic!(\"Unsupported Region {:?}\", x),\n+            }\n+            .into(),\n+        )\n+    }\n+}\n+\n+impl Into<String> for UbuntuAmi {\n+    fn into(self) -> String {\n+        self.0\n+    }\n+}\n+\n+/// A descriptor for a particular machine setup in a tsunami.\n+///\n+/// The `setup` argument is called once for every spawned instances of this type with a handle\n+/// to the target machine. Use [`Machine::ssh`](struct.Machine.html#structfield.ssh) to issue\n+/// commands on the host in question.\n+#[derive(Clone)]\n+pub struct MachineSetup {\n+    region: Region,\n+    instance_type: String,\n+    ami: String,\n+    setup: Option<Arc<dyn Fn(&mut ssh::Session, &slog::Logger) -> Result<(), Error> + Send + Sync>>,\n+}\n+\n+impl super::MachineSetup for MachineSetup {\n+    type Region = String;\n+\n+    fn region(&self) -> Self::Region {\n+        self.region.name().to_string()\n+    }\n+}\n+\n+impl PartialEq for MachineSetup {\n+    fn eq(&self, other: &Self) -> bool {\n+        self.ami == other.ami && self.instance_type == other.instance_type\n+    }\n+}\n+\n+impl Eq for MachineSetup {}\n+\n+impl std::hash::Hash for MachineSetup {\n+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n+        self.instance_type.hash(state);\n+        self.ami.hash(state);\n+    }\n+}\n+\n+impl Default for MachineSetup {\n+    fn default() -> Self {\n+        MachineSetup {","path":"src/providers/aws.rs","position":89,"original_position":89,"commit_id":"735bcf030958462d79be5bf203c52295d2d0ddfb","original_commit_id":"735bcf030958462d79be5bf203c52295d2d0ddfb","user":{"login":"jonhoo","id":176295,"node_id":"MDQ6VXNlcjE3NjI5NQ==","avatar_url":"https://avatars2.githubusercontent.com/u/176295?v=4","gravatar_id":"","url":"https://api.github.com/users/jonhoo","html_url":"https://github.com/jonhoo","followers_url":"https://api.github.com/users/jonhoo/followers","following_url":"https://api.github.com/users/jonhoo/following{/other_user}","gists_url":"https://api.github.com/users/jonhoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jonhoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonhoo/subscriptions","organizations_url":"https://api.github.com/users/jonhoo/orgs","repos_url":"https://api.github.com/users/jonhoo/repos","events_url":"https://api.github.com/users/jonhoo/events{/privacy}","received_events_url":"https://api.github.com/users/jonhoo/received_events","type":"User","site_admin":false},"body":"In fact, does it even make sense to provide a `impl Default` for `MachineSetup`? It strikes me as weird. When would you ever not care?","created_at":"2019-10-16T17:50:43Z","updated_at":"2019-10-16T17:50:44Z","html_url":"https://github.com/jonhoo/tsunami/pull/22#discussion_r335622027","pull_request_url":"https://api.github.com/repos/jonhoo/tsunami/pulls/22","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/jonhoo/tsunami/pulls/comments/335622027"},"html":{"href":"https://github.com/jonhoo/tsunami/pull/22#discussion_r335622027"},"pull_request":{"href":"https://api.github.com/repos/jonhoo/tsunami/pulls/22"}},"in_reply_to_id":335621799},"pull_request":{"url":"https://api.github.com/repos/jonhoo/tsunami/pulls/22","id":321915567,"node_id":"MDExOlB1bGxSZXF1ZXN0MzIxOTE1NTY3","html_url":"https://github.com/jonhoo/tsunami/pull/22","diff_url":"https://github.com/jonhoo/tsunami/pull/22.diff","patch_url":"https://github.com/jonhoo/tsunami/pull/22.patch","issue_url":"https://api.github.com/repos/jonhoo/tsunami/issues/22","number":22,"state":"open","locked":false,"title":"Support multiple providers and regions","user":{"login":"akshayknarayan","id":3051943,"node_id":"MDQ6VXNlcjMwNTE5NDM=","avatar_url":"https://avatars2.githubusercontent.com/u/3051943?v=4","gravatar_id":"","url":"https://api.github.com/users/akshayknarayan","html_url":"https://github.com/akshayknarayan","followers_url":"https://api.github.com/users/akshayknarayan/followers","following_url":"https://api.github.com/users/akshayknarayan/following{/other_user}","gists_url":"https://api.github.com/users/akshayknarayan/gists{/gist_id}","starred_url":"https://api.github.com/users/akshayknarayan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akshayknarayan/subscriptions","organizations_url":"https://api.github.com/users/akshayknarayan/orgs","repos_url":"https://api.github.com/users/akshayknarayan/repos","events_url":"https://api.github.com/users/akshayknarayan/events{/privacy}","received_events_url":"https://api.github.com/users/akshayknarayan/received_events","type":"User","site_admin":false},"body":"Note: this PR changes the tsunami API significantly.\r\n\r\nThis PR adds support for VM deployments across cloud providers and cloud provider regions. That is, the following is now possible:\r\n\r\n```\r\n...\r\naz.add(\"azure_uswest\", ...);\r\naws.add(\"ec2_useast\", ...);\r\nlet az = az.spawn()?;\r\nlet aws = aws.spawn()?;\r\nlet vms = az.get_machines().extend(aws.get_machines());\r\n...\r\n```\r\n\r\nTo support this, the existing functionality is moved to src/providers/aws.rs, and put behind a `Launcher` trait, which is a common interface across cloud providers.\r\n\r\nAn Azure provider is implemented (src/providers/azure.rs), as is one that just wraps a connection to an existing bare-metal machine (src/providers/baremetal.rs).","created_at":"2019-09-26T21:30:00Z","updated_at":"2019-10-16T17:50:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cc54bbb25868088c642eb8db5b483a45d23750d6","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/jonhoo/tsunami/pulls/22/commits","review_comments_url":"https://api.github.com/repos/jonhoo/tsunami/pulls/22/comments","review_comment_url":"https://api.github.com/repos/jonhoo/tsunami/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jonhoo/tsunami/issues/22/comments","statuses_url":"https://api.github.com/repos/jonhoo/tsunami/statuses/735bcf030958462d79be5bf203c52295d2d0ddfb","head":{"label":"akshayknarayan:machine-lifetimes","ref":"machine-lifetimes","sha":"735bcf030958462d79be5bf203c52295d2d0ddfb","user":{"login":"akshayknarayan","id":3051943,"node_id":"MDQ6VXNlcjMwNTE5NDM=","avatar_url":"https://avatars2.githubusercontent.com/u/3051943?v=4","gravatar_id":"","url":"https://api.github.com/users/akshayknarayan","html_url":"https://github.com/akshayknarayan","followers_url":"https://api.github.com/users/akshayknarayan/followers","following_url":"https://api.github.com/users/akshayknarayan/following{/other_user}","gists_url":"https://api.github.com/users/akshayknarayan/gists{/gist_id}","starred_url":"https://api.github.com/users/akshayknarayan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akshayknarayan/subscriptions","organizations_url":"https://api.github.com/users/akshayknarayan/orgs","repos_url":"https://api.github.com/users/akshayknarayan/repos","events_url":"https://api.github.com/users/akshayknarayan/events{/privacy}","received_events_url":"https://api.github.com/users/akshayknarayan/received_events","type":"User","site_admin":false},"repo":{"id":203401670,"node_id":"MDEwOlJlcG9zaXRvcnkyMDM0MDE2NzA=","name":"tsunami","full_name":"akshayknarayan/tsunami","private":false,"owner":{"login":"akshayknarayan","id":3051943,"node_id":"MDQ6VXNlcjMwNTE5NDM=","avatar_url":"https://avatars2.githubusercontent.com/u/3051943?v=4","gravatar_id":"","url":"https://api.github.com/users/akshayknarayan","html_url":"https://github.com/akshayknarayan","followers_url":"https://api.github.com/users/akshayknarayan/followers","following_url":"https://api.github.com/users/akshayknarayan/following{/other_user}","gists_url":"https://api.github.com/users/akshayknarayan/gists{/gist_id}","starred_url":"https://api.github.com/users/akshayknarayan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akshayknarayan/subscriptions","organizations_url":"https://api.github.com/users/akshayknarayan/orgs","repos_url":"https://api.github.com/users/akshayknarayan/repos","events_url":"https://api.github.com/users/akshayknarayan/events{/privacy}","received_events_url":"https://api.github.com/users/akshayknarayan/received_events","type":"User","site_admin":false},"html_url":"https://github.com/akshayknarayan/tsunami","description":"Rust crate for spawning short-lived clusters of EC2 spot instances","fork":true,"url":"https://api.github.com/repos/akshayknarayan/tsunami","forks_url":"https://api.github.com/repos/akshayknarayan/tsunami/forks","keys_url":"https://api.github.com/repos/akshayknarayan/tsunami/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akshayknarayan/tsunami/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akshayknarayan/tsunami/teams","hooks_url":"https://api.github.com/repos/akshayknarayan/tsunami/hooks","issue_events_url":"https://api.github.com/repos/akshayknarayan/tsunami/issues/events{/number}","events_url":"https://api.github.com/repos/akshayknarayan/tsunami/events","assignees_url":"https://api.github.com/repos/akshayknarayan/tsunami/assignees{/user}","branches_url":"https://api.github.com/repos/akshayknarayan/tsunami/branches{/branch}","tags_url":"https://api.github.com/repos/akshayknarayan/tsunami/tags","blobs_url":"https://api.github.com/repos/akshayknarayan/tsunami/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akshayknarayan/tsunami/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akshayknarayan/tsunami/git/refs{/sha}","trees_url":"https://api.github.com/repos/akshayknarayan/tsunami/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akshayknarayan/tsunami/statuses/{sha}","languages_url":"https://api.github.com/repos/akshayknarayan/tsunami/languages","stargazers_url":"https://api.github.com/repos/akshayknarayan/tsunami/stargazers","contributors_url":"https://api.github.com/repos/akshayknarayan/tsunami/contributors","subscribers_url":"https://api.github.com/repos/akshayknarayan/tsunami/subscribers","subscription_url":"https://api.github.com/repos/akshayknarayan/tsunami/subscription","commits_url":"https://api.github.com/repos/akshayknarayan/tsunami/commits{/sha}","git_commits_url":"https://api.github.com/repos/akshayknarayan/tsunami/git/commits{/sha}","comments_url":"https://api.github.com/repos/akshayknarayan/tsunami/comments{/number}","issue_comment_url":"https://api.github.com/repos/akshayknarayan/tsunami/issues/comments{/number}","contents_url":"https://api.github.com/repos/akshayknarayan/tsunami/contents/{+path}","compare_url":"https://api.github.com/repos/akshayknarayan/tsunami/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akshayknarayan/tsunami/merges","archive_url":"https://api.github.com/repos/akshayknarayan/tsunami/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akshayknarayan/tsunami/downloads","issues_url":"https://api.github.com/repos/akshayknarayan/tsunami/issues{/number}","pulls_url":"https://api.github.com/repos/akshayknarayan/tsunami/pulls{/number}","milestones_url":"https://api.github.com/repos/akshayknarayan/tsunami/milestones{/number}","notifications_url":"https://api.github.com/repos/akshayknarayan/tsunami/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akshayknarayan/tsunami/labels{/name}","releases_url":"https://api.github.com/repos/akshayknarayan/tsunami/releases{/id}","deployments_url":"https://api.github.com/repos/akshayknarayan/tsunami/deployments","created_at":"2019-08-20T15:16:08Z","updated_at":"2019-09-25T17:55:44Z","pushed_at":"2019-10-15T19:35:38Z","git_url":"git://github.com/akshayknarayan/tsunami.git","ssh_url":"git@github.com:akshayknarayan/tsunami.git","clone_url":"https://github.com/akshayknarayan/tsunami.git","svn_url":"https://github.com/akshayknarayan/tsunami","homepage":null,"size":221,"stargazers_count":1,"watchers_count":1,"language":"Rust","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"jonhoo:master","ref":"master","sha":"96a2f912f445b57b02a217b4a6998837373989b6","user":{"login":"jonhoo","id":176295,"node_id":"MDQ6VXNlcjE3NjI5NQ==","avatar_url":"https://avatars2.githubusercontent.com/u/176295?v=4","gravatar_id":"","url":"https://api.github.com/users/jonhoo","html_url":"https://github.com/jonhoo","followers_url":"https://api.github.com/users/jonhoo/followers","following_url":"https://api.github.com/users/jonhoo/following{/other_user}","gists_url":"https://api.github.com/users/jonhoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jonhoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonhoo/subscriptions","organizations_url":"https://api.github.com/users/jonhoo/orgs","repos_url":"https://api.github.com/users/jonhoo/repos","events_url":"https://api.github.com/users/jonhoo/events{/privacy}","received_events_url":"https://api.github.com/users/jonhoo/received_events","type":"User","site_admin":false},"repo":{"id":121051602,"node_id":"MDEwOlJlcG9zaXRvcnkxMjEwNTE2MDI=","name":"tsunami","full_name":"jonhoo/tsunami","private":false,"owner":{"login":"jonhoo","id":176295,"node_id":"MDQ6VXNlcjE3NjI5NQ==","avatar_url":"https://avatars2.githubusercontent.com/u/176295?v=4","gravatar_id":"","url":"https://api.github.com/users/jonhoo","html_url":"https://github.com/jonhoo","followers_url":"https://api.github.com/users/jonhoo/followers","following_url":"https://api.github.com/users/jonhoo/following{/other_user}","gists_url":"https://api.github.com/users/jonhoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jonhoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonhoo/subscriptions","organizations_url":"https://api.github.com/users/jonhoo/orgs","repos_url":"https://api.github.com/users/jonhoo/repos","events_url":"https://api.github.com/users/jonhoo/events{/privacy}","received_events_url":"https://api.github.com/users/jonhoo/received_events","type":"User","site_admin":false},"html_url":"https://github.com/jonhoo/tsunami","description":"Rust crate for spawning short-lived clusters of EC2 spot instances","fork":false,"url":"https://api.github.com/repos/jonhoo/tsunami","forks_url":"https://api.github.com/repos/jonhoo/tsunami/forks","keys_url":"https://api.github.com/repos/jonhoo/tsunami/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jonhoo/tsunami/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jonhoo/tsunami/teams","hooks_url":"https://api.github.com/repos/jonhoo/tsunami/hooks","issue_events_url":"https://api.github.com/repos/jonhoo/tsunami/issues/events{/number}","events_url":"https://api.github.com/repos/jonhoo/tsunami/events","assignees_url":"https://api.github.com/repos/jonhoo/tsunami/assignees{/user}","branches_url":"https://api.github.com/repos/jonhoo/tsunami/branches{/branch}","tags_url":"https://api.github.com/repos/jonhoo/tsunami/tags","blobs_url":"https://api.github.com/repos/jonhoo/tsunami/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jonhoo/tsunami/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jonhoo/tsunami/git/refs{/sha}","trees_url":"https://api.github.com/repos/jonhoo/tsunami/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jonhoo/tsunami/statuses/{sha}","languages_url":"https://api.github.com/repos/jonhoo/tsunami/languages","stargazers_url":"https://api.github.com/repos/jonhoo/tsunami/stargazers","contributors_url":"https://api.github.com/repos/jonhoo/tsunami/contributors","subscribers_url":"https://api.github.com/repos/jonhoo/tsunami/subscribers","subscription_url":"https://api.github.com/repos/jonhoo/tsunami/subscription","commits_url":"https://api.github.com/repos/jonhoo/tsunami/commits{/sha}","git_commits_url":"https://api.github.com/repos/jonhoo/tsunami/git/commits{/sha}","comments_url":"https://api.github.com/repos/jonhoo/tsunami/comments{/number}","issue_comment_url":"https://api.github.com/repos/jonhoo/tsunami/issues/comments{/number}","contents_url":"https://api.github.com/repos/jonhoo/tsunami/contents/{+path}","compare_url":"https://api.github.com/repos/jonhoo/tsunami/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jonhoo/tsunami/merges","archive_url":"https://api.github.com/repos/jonhoo/tsunami/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jonhoo/tsunami/downloads","issues_url":"https://api.github.com/repos/jonhoo/tsunami/issues{/number}","pulls_url":"https://api.github.com/repos/jonhoo/tsunami/pulls{/number}","milestones_url":"https://api.github.com/repos/jonhoo/tsunami/milestones{/number}","notifications_url":"https://api.github.com/repos/jonhoo/tsunami/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jonhoo/tsunami/labels{/name}","releases_url":"https://api.github.com/repos/jonhoo/tsunami/releases{/id}","deployments_url":"https://api.github.com/repos/jonhoo/tsunami/deployments","created_at":"2018-02-10T20:29:51Z","updated_at":"2019-10-12T22:32:07Z","pushed_at":"2019-10-15T19:35:40Z","git_url":"git://github.com/jonhoo/tsunami.git","ssh_url":"git@github.com:jonhoo/tsunami.git","clone_url":"https://github.com/jonhoo/tsunami.git","svn_url":"https://github.com/jonhoo/tsunami","homepage":null,"size":126,"stargazers_count":54,"watchers_count":54,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":13,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":11,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":13,"open_issues":11,"watchers":54,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jonhoo/tsunami/pulls/22"},"html":{"href":"https://github.com/jonhoo/tsunami/pull/22"},"issue":{"href":"https://api.github.com/repos/jonhoo/tsunami/issues/22"},"comments":{"href":"https://api.github.com/repos/jonhoo/tsunami/issues/22/comments"},"review_comments":{"href":"https://api.github.com/repos/jonhoo/tsunami/pulls/22/comments"},"review_comment":{"href":"https://api.github.com/repos/jonhoo/tsunami/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jonhoo/tsunami/pulls/22/commits"},"statuses":{"href":"https://api.github.com/repos/jonhoo/tsunami/statuses/735bcf030958462d79be5bf203c52295d2d0ddfb"}},"author_association":"NONE"}}
other: {"actor":{"display_login":"jonhoo"}}