Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/AKD-191: Added Azure 'Automated Backups Configured' Plugin and test cases #740

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions collectors/azure/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ var postcalls = {
reliesOnPath: 'webApps.list',
properties: ['id'],
url: 'https://management.azure.com/{id}/config?api-version=2019-08-01'
},
listBackupConfig: {
reliesOnPath: 'webApps.list',
properties: ['id'],
url: 'https://management.azure.com/{id}/config/backup/list?api-version=2019-08-01',
post: true
}
},
endpoints: {
Expand Down
1 change: 1 addition & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ module.exports = {
'http20Enabled' : require(__dirname + '/plugins/azure/appservice/http20Enabled.js'),
'httpsOnlyEnabled' : require(__dirname + '/plugins/azure/appservice/httpsOnlyEnabled.js'),
'tlsVersionCheck' : require(__dirname + '/plugins/azure/appservice/tlsVersionCheck.js'),
'automatedBackupsConfigured' : require(__dirname + '/plugins/azure/appservice/automatedBackupsConfigured.js'),
ali-imran7 marked this conversation as resolved.
Show resolved Hide resolved

'rbacEnabled' : require(__dirname + '/plugins/azure/kubernetesservice/rbacEnabled.js'),
'aksLatestVersion' : require(__dirname + '/plugins/azure/kubernetesservice/aksLatestVersion.js'),
Expand Down
65 changes: 65 additions & 0 deletions plugins/azure/appservice/automatedBackupsConfigured.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
var async = require('async');
var helpers = require('../../../helpers/azure');

module.exports = {
title: 'Web Apps Automated Backups Configured',
category: 'App Service',
description: 'Ensures that Azure Web Apps have automated backups configured.',
more_info: 'The Backup and Restore feature in Azure App Service lets you easily create app backups manually or on a schedule.You can restore the app to a snapshot of a previous state by overwriting the existing app or restoring to another app.',
recommended_action: 'Configure Automated Backups for Azure Web Apps',
link: 'https://docs.microsoft.com/en-us/azure/app-service/manage-backup',
apis: ['webApps:list', 'webApps:listBackupConfig'],

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 === 'functionapp') {
ali-imran7 marked this conversation as resolved.
Show resolved Hide resolved
helpers.addResult(results, 0, 'Backups can not be configured for the function App', location, webApp.id);
return scb();
ali-imran7 marked this conversation as resolved.
Show resolved Hide resolved
} else {
const backupConfig = helpers.addSource(
cache, source, ['webApps', 'listBackupConfig', location, webApp.id]
);

if (!backupConfig || backupConfig.err || !backupConfig.data) {
helpers.addResult(results, 2, 'Automated Backups are not configured for the webApp', location, webApp.id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for specific error

return scb();
}

if (backupConfig.data) {
helpers.addResult(results, 0, 'Automated Backups are configured for the webApp', location, webApp.id);
}
ali-imran7 marked this conversation as resolved.
Show resolved Hide resolved
}

scb();
}, function() {
rcb();
});
}, function() {
// Global checking goes here
callback(null, results, source);
});
}
};
130 changes: 130 additions & 0 deletions plugins/azure/appservice/automatedBackupsConfigured.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
var expect = require('chai').expect;
var automatedBackupsConfigured = require('./automatedBackupsConfigured');

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 backupConfig = {
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app',
'name': 'test-app',
'type': 'Microsoft.Web/sites',
'location': 'East US',
'backupSchedule': {
'frequencyInterval': 1,
'frequencyUnit': 'Day',
'keepAtLeastOneBackup': true,
'retentionPeriodInDays': 30,
'startTime': '2021-05-29T19:58:29.702'
}
};

const createCache = (webApps, backupConfig) => {
let app = {};
let config = {};

if (webApps) {
app['data'] = webApps;
if (webApps && webApps.length) {
config[webApps[0].id] = backupConfig;
}
}

return {
webApps: {
list: {
'eastus': app
},
listBackupConfig: {
'eastus': config
}
}
};
};

describe('automatedBackupsConfigured', function() {
describe('run', function() {
it('should give passing result if no web apps', function(done) {
const cache = createCache([]);
automatedBackupsConfigured.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();
automatedBackupsConfigured.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 app is a function app', function(done) {
const cache = createCache([webApps[1]]);
automatedBackupsConfigured.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Backups can not be configured for the function App');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give failing result if there is an error in getting backup config', function(done) {
const cache = createCache([webApps[0]], {
err: 'Unknown error occurred while calling the Azure API'
});
automatedBackupsConfigured.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Automated Backups are not configured for the webApp');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give failing result if no app config found', function(done) {
const cache = createCache([webApps[0]], {});
automatedBackupsConfigured.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Automated Backups are not configured for the webApp');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give passing result if automated backups are configured', function(done) {
const cache = createCache([webApps[0]], {
'data': backupConfig
});
automatedBackupsConfigured.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Automated Backups are configured for the webApp');
expect(results[0].region).to.equal('eastus');
done();
});
});
});
});