-
Notifications
You must be signed in to change notification settings - Fork 668
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into feature/AKD-191
- Loading branch information
Showing
8 changed files
with
610 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
var async = require('async'); | ||
var helpers = require('../../../helpers/azure'); | ||
|
||
module.exports = { | ||
title: 'Web Apps Always On Enabled', | ||
category: 'App Service', | ||
description: 'Ensures that Azure Web Apps have Always On feature enabled.', | ||
more_info: 'Always On feature keeps the app loaded even when there\'s no traffic. It\'s required for continuous WebJobs or for WebJobs that are triggered using a CRON expression.', | ||
recommended_action: 'Enable Always On feature for Azure Web Apps', | ||
link: 'https://docs.microsoft.com/en-us/azure/app-service/configure-common', | ||
apis: ['webApps:list', 'webApps:listConfigurations'], | ||
|
||
run: function(cache, settings, callback) { | ||
var results = []; | ||
var source = {}; | ||
var locations = helpers.locations(settings.govcloud); | ||
|
||
async.each(locations.webApps, function(location, rcb) { | ||
const webApps = helpers.addSource(cache, source, | ||
['webApps', 'list', location]); | ||
|
||
if (!webApps) return rcb(); | ||
|
||
if (webApps.err || !webApps.data) { | ||
helpers.addResult(results, 3, 'Unable to query for Web Apps: ' + helpers.addError(webApps), location); | ||
return rcb(); | ||
} | ||
|
||
if (!webApps.data.length) { | ||
helpers.addResult(results, 0, 'No existing Web Apps found', location); | ||
return rcb(); | ||
} | ||
|
||
async.each(webApps.data, function(webApp, scb) { | ||
if (webApp && webApp.kind && webApp.kind === 'functionapp') { | ||
helpers.addResult(results, 0, 'Always On feature can not be configured for the function App', location, webApp.id); | ||
return scb(); | ||
} | ||
|
||
const configs = helpers.addSource(cache, source, | ||
['webApps', 'listConfigurations', location, webApp.id]); | ||
|
||
if (!configs || configs.err || !configs.data || !configs.data.length) { | ||
helpers.addResult(results, 3, 'Unable to query for Web App Configs: ' + helpers.addError(configs), location); | ||
return scb(); | ||
} | ||
|
||
const alwaysOnEnabled = configs.data.some(config => config.alwaysOn); | ||
if (alwaysOnEnabled) { | ||
helpers.addResult(results, 0, 'Always On feature is enabled for the Web App', location, webApp.id); | ||
} else { | ||
helpers.addResult(results, 2, 'Always On feature is disabled for the Web App', location, webApp.id); | ||
} | ||
|
||
scb(); | ||
}, function() { | ||
rcb(); | ||
}); | ||
}, function() { | ||
// Global checking goes here | ||
callback(null, results, source); | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
var expect = require('chai').expect; | ||
var alwaysOnEnabled = require('./alwaysOnEnabled'); | ||
|
||
const webApps = [ | ||
{ | ||
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app', | ||
'name': 'test-app', | ||
'type': 'Microsoft.Web/sites', | ||
'kind': 'app,linux', | ||
'location': 'East US' | ||
}, | ||
{ | ||
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app', | ||
'name': 'test-app', | ||
'type': 'Microsoft.Web/sites', | ||
'kind': 'functionapp', | ||
'location': 'East US' | ||
} | ||
]; | ||
|
||
const configs = [ | ||
{ | ||
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app', | ||
'name': 'test-app', | ||
'type': 'Microsoft.Web/sites', | ||
'location': 'East US', | ||
'alwaysOn': true | ||
}, | ||
{ | ||
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app', | ||
'name': 'test-app', | ||
'type': 'Microsoft.Web/sites', | ||
'location': 'East US', | ||
'alwaysOn': false | ||
} | ||
]; | ||
|
||
const createCache = (webApps, configs) => { | ||
let app = {}; | ||
let config = {}; | ||
|
||
if (webApps) { | ||
app['data'] = webApps; | ||
if (webApps && webApps.length) { | ||
config[webApps[0].id] = { | ||
'data': configs | ||
}; | ||
} | ||
} | ||
|
||
return { | ||
webApps: { | ||
list: { | ||
'eastus': app | ||
}, | ||
listConfigurations: { | ||
'eastus': config | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
describe('alwaysOnEnabled', function() { | ||
describe('run', function() { | ||
it('should give passing result if no web apps', function(done) { | ||
const cache = createCache([]); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(0); | ||
expect(results[0].message).to.include('No existing Web Apps found'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should give unknown result if unable to query for web apps', function(done) { | ||
const cache = createCache(); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(3); | ||
expect(results[0].message).to.include('Unable to query for Web Apps'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should give passing result if always on can not be configured', function(done) { | ||
const cache = createCache([webApps[1]], []); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(0); | ||
expect(results[0].message).to.include('Always On feature can not be configured for the function App'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
|
||
|
||
it('should give unknown result if no web app configs', function(done) { | ||
const cache = createCache([webApps[0]], []); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(3); | ||
expect(results[0].message).to.include('Unable to query for Web App Configs:'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should give unknown result if unable to query for web app configs', function(done) { | ||
const cache = createCache([webApps[0]]); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(3); | ||
expect(results[0].message).to.include('Unable to query for Web App Configs:'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should give passing result if always on is enabled', function(done) { | ||
const cache = createCache([webApps[0]], [configs[0]]); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(0); | ||
expect(results[0].message).to.include('Always On feature is enabled for the Web App'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should give failing result if always on is disabled', function(done) { | ||
const cache = createCache([webApps[0]], [configs[1]]); | ||
alwaysOnEnabled.run(cache, {}, (err, results) => { | ||
expect(results.length).to.equal(1); | ||
expect(results[0].status).to.equal(2); | ||
expect(results[0].message).to.include('Always On feature is disabled for the Web App'); | ||
expect(results[0].region).to.equal('eastus'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
var async = require('async'); | ||
const helpers = require('../../../helpers/azure'); | ||
|
||
module.exports = { | ||
title: 'Auto-Failover Groups Enabled', | ||
category: 'SQL Server', | ||
description: 'Ensures that auto-failover groups are configured for Azure SQL database servers.', | ||
more_info: 'In case of any outage that impacts one or more SQL databases, automatic failover process switches all secondary databases in the group to primary databases to ensure high availability.', | ||
recommended_action: 'Ensure that auto-failover Groups are configured for Azure SQL database servers', | ||
link: 'https://docs.microsoft.com/en-us/azure/azure-sql/database/auto-failover-group-overview', | ||
apis: ['servers:listSql', 'failoverGroups:listByServer'], | ||
|
||
run: function(cache, settings, callback) { | ||
var results = []; | ||
var source = {}; | ||
var locations = helpers.locations(settings.govcloud); | ||
|
||
async.each(locations.servers, function(location, rcb) { | ||
|
||
const servers = helpers.addSource(cache, source, | ||
['servers', 'listSql', location]); | ||
|
||
if (!servers) return rcb(); | ||
|
||
if (servers.err || !servers.data) { | ||
helpers.addResult(results, 3, | ||
'Unable to query for SQL servers: ' + helpers.addError(servers), location); | ||
return rcb(); | ||
} | ||
|
||
if (!servers.data.length) { | ||
helpers.addResult(results, 0, 'No SQL servers found', location); | ||
return rcb(); | ||
} | ||
|
||
for (const server of servers.data) { | ||
const failoverGroups = helpers.addSource(cache, source, | ||
['failoverGroups', 'listByServer', location, server.id]); | ||
|
||
if (!failoverGroups || failoverGroups.err || !failoverGroups.data) { | ||
helpers.addResult(results, 3, | ||
'Unable to query for auto-failover groups: ' + helpers.addError(failoverGroups), location, server.id); | ||
continue; | ||
} | ||
|
||
if (failoverGroups.data.length) { | ||
helpers.addResult(results, 0, 'Auto-failover groups are configured for the SQL server', location, server.id); | ||
} else { | ||
helpers.addResult(results, 2, 'Auto-failover groups are not configured for the SQL server', location, server.id); | ||
} | ||
} | ||
|
||
rcb(); | ||
}, function() { | ||
// Global checking goes here | ||
callback(null, results, source); | ||
}); | ||
} | ||
}; |
Oops, something went wrong.