Skip to content

Commit 9dac78f

Browse files
committed
Merge branch 'master' into trevj-remove-cloud-installer-timeout
2 parents e88568f + e8af960 commit 9dac78f

File tree

4 files changed

+42
-38
lines changed

4 files changed

+42
-38
lines changed

src/cloud/digitalocean/provisioner.ts

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ class Provisioner {
7272
}).then((keys: KeyPair) => {
7373
// Get SSH keys
7474
this.state_.ssh = keys;
75-
return this.getDroplet_(name).then((unused :any) => {
75+
76+
return this.getDropletByName_(name).then((unused :any) => {
7677
// Droplet exists so raise error
7778
return Promise.reject({
7879
'errcode': 'VM_AE',
@@ -85,23 +86,25 @@ class Provisioner {
8586
});
8687
}).then(() => {
8788
// Get the droplet's configuration
88-
return this.doRequest_('GET', 'droplets/' + this.state_.cloud.vm.id);
89-
}).then((resp: any) => {
89+
return this.getDropletByName_(name);
90+
}).then((droplet:any) => {
9091
this.sendStatus_('CLOUD_DONE_VM');
91-
this.state_.cloud.vm = resp.droplet;
92+
this.state_.cloud.vm = droplet;
9293
this.state_.network = {
9394
'ssh_port': 22
9495
};
9596
// Retrieve public IPv4 address
96-
for (var i = 0; i < resp.droplet.networks.v4.length; i++) {
97-
if (resp.droplet.networks.v4[i].type === 'public') {
98-
this.state_.network['ipv4'] = resp.droplet.networks.v4[i].ip_address;
97+
for (var i = 0; i < droplet.networks.v4.length; i++) {
98+
if (droplet.networks.v4[i].type === 'public') {
99+
this.state_.network['ipv4'] = droplet.networks.v4[i].ip_address;
100+
break;
99101
}
100102
}
101103
// Retrieve public IPv6 address
102-
for (var i = 0; i < resp.droplet.networks.v6.length; i++) {
103-
if (resp.droplet.networks.v6[i].type === 'public') {
104-
this.state_.network['ipv6'] = resp.droplet.networks.v6[i].ip_address;
104+
for (var i = 0; i < droplet.networks.v6.length; i++) {
105+
if (droplet.networks.v6[i].type === 'public') {
106+
this.state_.network['ipv6'] = droplet.networks.v6[i].ip_address;
107+
break;
105108
}
106109
}
107110
console.log(this.state_);
@@ -132,10 +135,10 @@ class Provisioner {
132135
private destroyServer_ = (name: string): Promise<void> => {
133136
return this.doRequest_('GET', 'droplets').then((resp: any) => {
134137
// Find and delete the server with the same name
135-
return this.getDroplet_(name);
136-
}).then((resp: any) => {
138+
return this.getDropletByName_(name);
139+
}).then((droplet: any) => {
137140
this.state_.cloud = this.state_.cloud || {};
138-
this.state_.cloud.vm = this.state_.cloud.vm || resp.droplet;
141+
this.state_.cloud.vm = this.state_.cloud.vm || droplet;
139142
// Make sure there are no actions in progress before deleting
140143
this.sendStatus_('CLOUD_WAITING_VM');
141144
return this.waitDigitalOceanActions_();
@@ -169,10 +172,10 @@ class Provisioner {
169172
return this.doOAuth_().then((oauthObj: any) => {
170173
this.state_.oauth = oauthObj;
171174
}).then(() => {
172-
return this.getDroplet_(name);
173-
}).then((resp: any) => {
175+
return this.getDropletByName_(name);
176+
}).then((droplet: any) => {
174177
this.state_.cloud = this.state_.cloud || {};
175-
this.state_.cloud.vm = this.state_.cloud.vm || resp.droplet;
178+
this.state_.cloud.vm = this.state_.cloud.vm || droplet;
176179
// Make sure there are no actions in progress before rebooting
177180
this.sendStatus_('CLOUD_WAITING_VM');
178181
return this.waitDigitalOceanActions_();
@@ -188,20 +191,12 @@ class Provisioner {
188191
});
189192
}
190193

191-
/**
192-
* Finds a droplet with this name
193-
* @param {String} droplet name, as a string
194-
* @return {Promise.<Object>}, resolves with {droplet: droplet_with_name}
195-
* or rejects if droplet doesn't exist
196-
*/
197-
private getDroplet_ = (name: string) : Promise<Object> => {
194+
// Resolves with the (de-serialised) droplet, rejecting if not found.
195+
private getDropletByName_ = (name: string) : Promise<Object> => {
198196
return this.doRequest_('GET', 'droplets').then((resp: any) => {
199-
// Find and delete the server with the same name
200-
for (var i = 0; i < resp.droplets.length; i++) {
197+
for (let i = 0; i < resp.droplets.length; i++) {
201198
if (resp.droplets[i].name === name) {
202-
return Promise.resolve({
203-
droplet: resp.droplets[i]
204-
});
199+
return Promise.resolve(resp.droplets[i]);
205200
}
206201
}
207202
return Promise.reject({

src/cloud/install/installer.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ const STATUS_PREFIX = 'CLOUD_INSTALL_STATUS';
2929
const INITIAL_CONNECTION_INTERVAL_MS = 500;
3030
const MAX_CONNECTION_INTERVAL_MS = 10000;
3131

32+
// Timeouts for established SSH connections.
33+
// We define these chiefly so that the installer fails quickly
34+
// in case the server is destroyed during installation, e.g.
35+
// when the user cancels install.
36+
const KEEPALIVE_INTERVAL_MS = 1000;
37+
const KEEPALIVE_MAX_FAILURES = 5;
38+
3239
// Installs uProxy on a server, via SSH.
3340
// The process is as close as possible to a manual install
3441
// so that we have fewer paths to test.
@@ -48,6 +55,8 @@ class CloudInstaller {
4855
port: port,
4956
username: username,
5057
privateKey: key,
58+
keepaliveInterval: KEEPALIVE_INTERVAL_MS,
59+
keepaliveCountMax: KEEPALIVE_MAX_FAILURES,
5160
// Remaining fields only for type-correctness.
5261
tryKeyboard: false,
5362
debug: undefined

src/promises/promises.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
/// <reference path='../../../third_party/typings/browser.d.ts' />
22

33
// Invokes f up to maxAttempts number of times, resolving with its result
4-
// on the first success and rejecting on maxAttempts-th failure.
5-
export const retry = <T>(f: () => Promise<T>, maxAttempts: number): Promise<T> => {
6-
return f().catch((e:Error) => {
7-
--maxAttempts;
8-
if (maxAttempts > 0) {
9-
return retry(f, maxAttempts);
10-
} else {
11-
return Promise.reject(e);
12-
}
4+
// on the first success and rejecting on the maxAttempts-th failure, waiting,
5+
// if specified, intervalMs ms between each attempt.
6+
export const retry = <T>(f: () => Promise<T>, maxAttempts: number, intervalMs = 0): Promise<T> => {
7+
return f().catch((e: Error) => {
8+
return maxAttempts <= 1 ? Promise.reject(e) : new Promise<T>((F, R) => {
9+
setTimeout(() => {
10+
retry(f, maxAttempts - 1, intervalMs).then(F, R);
11+
}, intervalMs);
12+
});
1313
});
1414
};
1515

src/samples/deployer-chromeapp/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@
2727
"send": "*"
2828
}
2929
},
30-
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArOOsgNK52HYy9483rhgsofyHTp/NbmXkpHNLoarN027kqKVPS3U36/L2XyPJOAtvy+DDR+kCro1JmdFWBwPAk5AqvSKvfLzuXkO+98T/3ZhqfAl4KIqc0C+PsWIYsANTAbKkXlP4bATEK6O5Mq0aItAHGLSmKoNrAAVrtxmETXaumcrq78amOpAZz7XrPdJVhrHd6uQbR90WeFEe8LBOqdnA4iKeuMI9IQdDLKGSizhYFZP78HKSk0ZY2uYeJFpya0iXAvbcuHRGY9/c7pP5UDo+FExdyrgJnIt7H1W5LWfy/mAMnR77dvCSfGX1vCD7faWntYvzZO4FlISh+h21+QIDAQAB"
30+
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk6KrQptZchMYwQN8CsbRVmhV/COoR0lxansERcz+OrkPctUBSTQVYJw3t17+6JyMPnKYR2DMKCTeYQGrmXzm2U0KpujEKN3WSTtZI4ynTzKbGhWIYo6exaHufcslJngEG91ua/q1fJz3e5Mla8+tIsT9bVdVf4NLfODNbky/Uo0M6KpOLO9r2zJoiO0yg4ThBH+TkNwH8icvHJbt2LzZVRSZtQ1Wl1uT15vnwJPOEYVQkpnEMY5yMBPxyOZ1AmUx714YAas80pSZ7+BlM9ReIirYB7lxeY6hAqs4u8iP5SDh5bg6YFXeYecwQyvnKglLdHq6djy9QyVLKUKxFzMH/wIDAQAB"
3131
}

0 commit comments

Comments
 (0)