Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions lib/compute/zone.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

'use strict';

var async = require('async');
var extend = require('extend');
var format = require('string-format-obj');
var gceImages = require('gce-images');
Expand Down Expand Up @@ -275,6 +276,11 @@ Zone.prototype.createVM = function(name, config, callback) {
}

if (body.http || body.https) {
// We will add tags to the created instance (http-server and/or
// https-server), and create the appropriate firewall rules to allow
// connections on the necessary ports to these tags.
var createFirewallMethods = [];

body.networkInterfaces[0].accessConfigs = [
{
type: 'ONE_TO_ONE_NAT'
Expand All @@ -286,17 +292,35 @@ Zone.prototype.createVM = function(name, config, callback) {

if (body.http) {
delete body.http;

createFirewallMethods.push(this.createHttpServerFirewall_.bind(this));

if (body.tags.items.indexOf('http-server') === -1) {
body.tags.items.push('http-server');
}
}

if (body.https) {
delete body.https;

createFirewallMethods.push(this.createHttpsServerFirewall_.bind(this));

if (body.tags.items.indexOf('https-server') === -1) {
body.tags.items.push('https-server');
}
}

// We have to make sure the firewall rules exist to allow HTTP/S traffic.
async.parallel(createFirewallMethods, function(err) {
if (err) {
callback(err);
return;
}

self.createVM(name, body, callback);
});

return;
}

if (body.os) {
Expand All @@ -317,6 +341,7 @@ Zone.prototype.createVM = function(name, config, callback) {

self.createVM(name, body, callback);
});

return;
}

Expand Down Expand Up @@ -714,6 +739,46 @@ Zone.prototype.vm = function(name) {
return new VM(this, name);
};

/**
* This method attempts to create a firewall rule to allow tcp:80 connections.
*
* @param {function} callback - The callback function.
* @param {?error} callback.err - If the firewall couldn't be created and it
* didn't already exist.
*/
Zone.prototype.createHttpServerFirewall_ = function(callback) {
this.compute.createFirewall('default-allow-http', {
protocols: {
tcp: [80]
},
ranges: ['0.0.0.0/0'],
tags: ['http-server']
}, function(err) {
// If it already exists, we're all good.
callback(err && err.code !== 409 ? err : null);
});
};

/**
* This method attempts to create a firewall rule to allow tcp:443 connections.
*
* @param {function} callback - The callback function.
* @param {?error} callback.err - If the firewall couldn't be created and it
* didn't already exist.
*/
Zone.prototype.createHttpsServerFirewall_ = function(callback) {
this.compute.createFirewall('default-allow-https', {
protocols: {
tcp: [443]
},
ranges: ['0.0.0.0/0'],
tags: ['https-server']
}, function(err) {
// If it already exists, we're all good.
callback(err && err.code !== 409 ? err : null);
});
};

/**
* Make a new request object from the provided arguments and wrap the callback
* to intercept non-successful responses.
Expand Down
122 changes: 122 additions & 0 deletions test/compute/zone.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,20 @@ describe('Zone', function() {
http: true
};

beforeEach(function() {
zone.createHttpServerFirewall_ = function(callback) {
callback();
};
});

it('should create a firewall rule', function(done) {
zone.createHttpServerFirewall_ = function() {
done();
};

zone.createVM(NAME, CONFIG, assert.ifError);
});

it('should add a network interface accessConfig', function(done) {
zone.makeReq_ = function(method, path, query, body) {
assert.deepEqual(body.networkInterfaces[0].accessConfigs[0], {
Expand Down Expand Up @@ -394,6 +408,20 @@ describe('Zone', function() {
https: true
};

beforeEach(function() {
zone.createHttpsServerFirewall_ = function(callback) {
callback();
};
});

it('should create a firewall rule', function(done) {
zone.createHttpsServerFirewall_ = function() {
done();
};

zone.createVM(NAME, CONFIG, assert.ifError);
});

it('should add a network interface accessConfig', function(done) {
zone.makeReq_ = function(method, path, query, body) {
assert.deepEqual(body.networkInterfaces[0].accessConfigs[0], {
Expand Down Expand Up @@ -981,6 +1009,100 @@ describe('Zone', function() {
});
});

describe('createHttpServerFirewall_', function() {
it('should create a firewall rule', function(done) {
zone.compute.createFirewall = function(name, config) {
assert.strictEqual(name, 'default-allow-http');
assert.deepEqual(config, {
protocols: {
tcp: [80]
},
ranges: ['0.0.0.0/0'],
tags: ['http-server']
});

done();
};

zone.createHttpServerFirewall_(assert.ifError);
});

it('should execute callback with error & API response', function(done) {
var error = new Error('Error.');

zone.compute.createFirewall = function(name, config, callback) {
callback(error);
};

zone.createHttpServerFirewall_(function(err) {
assert.strictEqual(err, error);
done();
});
});

it('should not execute callback with error if 409', function(done) {
var error = new Error('Error.');
error.code = 409;

var apiResponse = {};

zone.compute.createFirewall = function(name, config, callback) {
callback(error, null, apiResponse);
};

zone.createHttpServerFirewall_(function(err) {
assert.strictEqual(err, null);
done();
});
});
});

describe('createHttpsServerFirewall_', function() {
it('should create a firewall rule', function(done) {
zone.compute.createFirewall = function(name, config) {
assert.strictEqual(name, 'default-allow-https');
assert.deepEqual(config, {
protocols: {
tcp: [443]
},
ranges: ['0.0.0.0/0'],
tags: ['https-server']
});

done();
};

zone.createHttpsServerFirewall_(assert.ifError);
});

it('should execute callback with error & API response', function(done) {
var error = new Error('Error.');

zone.compute.createFirewall = function(name, config, callback) {
callback(error);
};

zone.createHttpsServerFirewall_(function(err) {
assert.strictEqual(err, error);
done();
});
});

it('should not execute callback with error if 409', function(done) {
var error = new Error('Error.');
error.code = 409;

zone.compute.createFirewall = function(name, config, callback) {
callback(error);
};

zone.createHttpsServerFirewall_(function(err) {
assert.strictEqual(err, null);
done();
});
});
});

describe('makeReq_', function() {
it('should make the correct request to Compute', function(done) {
var expectedPathPrefix = '/zones/' + zone.name;
Expand Down