Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Commit

Permalink
fix: re-ordering locks for alb, fix count update
Browse files Browse the repository at this point in the history
  • Loading branch information
SanketD92 committed Oct 21, 2021
1 parent 9f35b6b commit 7042d83
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,28 +189,31 @@ describe('ALBService', () => {
});
});

describe('increase alb dependent workspace count function', () => {
describe('update alb dependent workspace count function', () => {
it('should fail because project id is not valid', async () => {
projectService.mustFind.mockImplementationOnce(() => {
throw service.boom.notFound(`project with id "test-id" does not exist`, true);
});
// OPERATE
try {
await service.increaseAlbDependentWorkspaceCount({}, 'test-id');
await service.updateAlbDependentWorkspaceCount({}, 'test-id', 3);
} catch (err) {
// CHECK
expect(err.message).toEqual('project with id "test-id" does not exist');
}
});

it('should pass and increment count if the input is valid', async () => {
it('should pass and update count if the input is valid', async () => {
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
const updatedAlbDetails = {
id: 'test-id',
albStackName: null,
albArn: 'arn:test-arn',
listenerArn: null,
albDnsName: null,
albDependentWorkspacesCount: 2,
albDependentWorkspacesCount: 1,
};
service.getAlbDetails = jest.fn(() => {
return albDetails;
Expand All @@ -220,51 +223,17 @@ describe('ALBService', () => {
});
service.audit = jest.fn();
// OPERATE
await service.increaseAlbDependentWorkspaceCount({}, 'test-id');
const totalRules = 2; // including one default rule
await service.updateAlbDependentWorkspaceCount({}, 'test-id', totalRules);

// CHECK
expect(service.saveAlbDetails).toHaveBeenCalledWith(albDetails.id, updatedAlbDetails);
});

it('should call audit on success', async () => {
service.getAlbDetails = jest.fn(() => {
return albDetails;
});
service.saveAlbDetails = jest.fn(() => {
return { id: 'id-alb' };
});
service.audit = jest.fn();
// OPERATE
await service.increaseAlbDependentWorkspaceCount({}, 'test-id');

// CHECK
expect(service.audit).toHaveBeenCalledWith({}, { action: 'update-deployment-store', body: { id: 'id-alb' } });
});
});

describe('decrease alb dependent workspace count function', () => {
it('should fail because project id is not valid', async () => {
projectService.mustFind.mockImplementationOnce(() => {
throw service.boom.notFound(`project with id "test-id" does not exist`, true);
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
// OPERATE
try {
await service.decreaseAlbDependentWorkspaceCount({}, 'test-id');
} catch (err) {
// CHECK
expect(err.message).toEqual('project with id "test-id" does not exist');
}
});

it('should pass and decrement count if the input is valid', async () => {
const updatedAlbDetails = {
id: 'test-id',
albStackName: null,
albArn: 'arn:test-arn',
listenerArn: null,
albDnsName: null,
albDependentWorkspacesCount: 0,
};
service.getAlbDetails = jest.fn(() => {
return albDetails;
});
Expand All @@ -273,25 +242,13 @@ describe('ALBService', () => {
});
service.audit = jest.fn();
// OPERATE
await service.decreaseAlbDependentWorkspaceCount({}, 'test-id');
await service.updateAlbDependentWorkspaceCount({}, 'test-id', 1);

// CHECK
expect(service.saveAlbDetails).toHaveBeenCalledWith(albDetails.id, updatedAlbDetails);
});

it('should call audit if the success', async () => {
service.getAlbDetails = jest.fn(() => {
return albDetails;
});
service.saveAlbDetails = jest.fn(() => {
return { id: 'id-alb' };
});
service.audit = jest.fn();
// OPERATE
await service.decreaseAlbDependentWorkspaceCount({}, 'test-id');

// CHECK
expect(service.audit).toHaveBeenCalledWith({}, { action: 'update-deployment-store', body: { id: 'id-alb' } });
expect(service.audit).toHaveBeenCalledWith(
{},
{ action: 'update-alb-count-account-sampleAwsAccountId', body: { id: 'id-alb' } },
);
});
});

Expand Down Expand Up @@ -379,10 +336,29 @@ describe('ALBService', () => {
},
],
};
const describeAPIResponse = {
Rules: [
{
RuleArn:
'arn:aws:elasticloadbalancing:us-west-2:123456789012:listener-rule/app/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2/9683b2d02a6cabee',
},
],
};
const targetGroupArn =
'rn:aws:elasticloadbalancing:us-east-2:977461429431:targetgroup/devrgsaas-sg/f4c2a2df084e5df4';

it('should pass if system is trying to create listener rule', async () => {
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
service.updateAlbDependentWorkspaceCount = jest.fn();
albClient.describeRules = jest.fn().mockImplementation(() => {
return {
promise: () => {
return describeAPIResponse;
},
};
});
albClient.createRule = jest.fn().mockImplementation(() => {
return {
promise: () => {
Expand All @@ -405,8 +381,19 @@ describe('ALBService', () => {
});

it('should pass and return the arn with success', async () => {
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
service.updateAlbDependentWorkspaceCount = jest.fn();
const validateARN =
'arn:aws:elasticloadbalancing:us-west-2:123456789012:listener-rule/app/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2/9683b2d02a6cabee';
albClient.describeRules = jest.fn().mockImplementation(() => {
return {
promise: () => {
return describeAPIResponse;
},
};
});
albClient.createRule = jest.fn().mockImplementation(() => {
return {
promise: () => {
Expand All @@ -430,6 +417,17 @@ describe('ALBService', () => {
});

it('should fail when create rule API call throws error', async () => {
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
service.updateAlbDependentWorkspaceCount = jest.fn();
albClient.describeRules = jest.fn().mockImplementation(() => {
return {
promise: () => {
return describeAPIResponse;
},
};
});
albClient.createRule = jest.fn().mockImplementation(() => {
throw new Error(`Error creating rule. Rule creation failed with message - Too many rules`);
});
Expand All @@ -452,7 +450,26 @@ describe('ALBService', () => {
});

describe('deleteListenerRule', () => {
const describeAPIResponse = {
Rules: [
{
RuleArn:
'arn:aws:elasticloadbalancing:us-west-2:123456789012:listener-rule/app/my-load-balancer/50dc6c495c0c9188/f2f7dc8efc522ab2/9683b2d02a6cabee',
},
],
};
it('should pass and return empty object with success', async () => {
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
service.updateAlbDependentWorkspaceCount = jest.fn();
albClient.describeRules = jest.fn().mockImplementation(() => {
return {
promise: () => {
return describeAPIResponse;
},
};
});
albClient.deleteRule = jest.fn().mockImplementation(() => {
return {
promise: () => {
Expand All @@ -461,16 +478,27 @@ describe('ALBService', () => {
};
});
service.getAlbSdk = jest.fn().mockResolvedValue(albClient);
const response = await service.deleteListenerRule({}, {}, '');
const response = await service.deleteListenerRule({}, {}, '', 'sampleListenerArn');
expect(response).toEqual({});
});

it('should fail when delete rule API call throws error', async () => {
service.findAwsAccountId = jest.fn(() => {
return 'sampleAwsAccountId';
});
service.updateAlbDependentWorkspaceCount = jest.fn();
albClient.describeRules = jest.fn().mockImplementation(() => {
return {
promise: () => {
return describeAPIResponse;
},
};
});
albClient.deleteRule = jest.fn().mockImplementation(() => {
throw new Error(`Error deleting rule. Rule deletion failed with message - Rule not found`);
});
try {
await service.deleteListenerRule({}, {}, '');
await service.deleteListenerRule({}, {}, '', 'sampleListenerArn');
} catch (err) {
expect(err.message).toContain('Error deleting rule. Rule deletion failed with message - Rule not found');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ALBService extends Service {
*/
async albDependentWorkspacesCount(requestContext, projectId) {
const deploymentItem = await this.getAlbDetails(requestContext, projectId);
if (deploymentItem) {
if (!_.isEmpty(deploymentItem) && !_.isEmpty(deploymentItem.value)) {
const albRecord = JSON.parse(deploymentItem.value);
return albRecord.albDependentWorkspacesCount;
}
Expand All @@ -64,9 +64,10 @@ class ALBService extends Service {
*/
async checkAlbExists(requestContext, projectId) {
const deploymentItem = await this.getAlbDetails(requestContext, projectId);
if (deploymentItem) {
if (!_.isEmpty(deploymentItem) && !_.isEmpty(deploymentItem.value)) {
const albRecord = JSON.parse(deploymentItem.value);
return !!_.get(albRecord, 'albArn', null);
const albArn = _.get(albRecord, 'albArn', null);
return !_.isEmpty(albArn);
}
return false;
}
Expand Down Expand Up @@ -227,6 +228,10 @@ class ALBService extends Service {
let response = null;
try {
response = await albClient.createRule(params).promise();

// Get current rule count on ALB and set it in DB
const albRules = await albClient.describeRules({ ListenerArn: listenerArn }).promise();
await this.updateAlbDependentWorkspaceCount(requestContext, resolvedVars.projectId, albRules.Rules.length);
} catch (err) {
throw new Error(`Error creating rule. Rule creation failed with message - ${err.message}`);
}
Expand All @@ -235,56 +240,50 @@ class ALBService extends Service {

/**
* Method to delete listener rule. The method deletes rule using the ALB SDK client.
* Since this needs to reflect the up-to-date rule count on the ALB,
* ultimate environment termination status is not relevant
*
* @param requestContext
* @param resolvedVars
* @param ruleArn
* @param listenerArn
* @returns {Promise<>}
*/
async deleteListenerRule(requestContext, resolvedVars, ruleArn) {
async deleteListenerRule(requestContext, resolvedVars, ruleArn, listenerArn) {
const params = {
RuleArn: ruleArn,
};
const albClient = await this.getAlbSdk(requestContext, resolvedVars);
let response = null;
try {
// Check if rule exists, only then perform deletion
response = await albClient.deleteRule(params).promise();

// Get current rule count on ALB and set it in DB
const albRules = await albClient.describeRules({ ListenerArn: listenerArn }).promise();
await this.updateAlbDependentWorkspaceCount(requestContext, resolvedVars.projectId, albRules.Rules.length);
} catch (err) {
throw new Error(`Error deleting rule. Rule deletion failed with message - ${err.message}`);
}
return response;
}

/**
* Method to increase the count of alb dependent workspaces in database
* Method to update the count of alb dependent workspaces in database
* Rules limit per load balancer (not counting default rules): 100
* One default rule exists for the ALB for port 443, so subtracting that to form workspace count
*
* @param requestContext
* @param projectId
* @returns {Promise<>}
*/
async increaseAlbDependentWorkspaceCount(requestContext, projectId) {
const deploymentItem = await this.getAlbDetails(requestContext, projectId);
const albRecord = JSON.parse(deploymentItem.value);
albRecord.albDependentWorkspacesCount += 1;
const result = await this.saveAlbDetails(deploymentItem.id, albRecord);
await this.audit(requestContext, { action: 'update-deployment-store', body: result });
return result;
}

/**
* Method to decrease the count of alb dependent workspaces in database
*
* @param requestContext
* @param projectId
* @returns {Promise<>}
*/
async decreaseAlbDependentWorkspaceCount(requestContext, projectId) {
async updateAlbDependentWorkspaceCount(requestContext, projectId, currRuleCount) {
const awsAccountId = await this.findAwsAccountId(requestContext, projectId);
const deploymentItem = await this.getAlbDetails(requestContext, projectId);
const albRecord = JSON.parse(deploymentItem.value);
albRecord.albDependentWorkspacesCount -= 1;
albRecord.albDependentWorkspacesCount = currRuleCount - 1;
const result = await this.saveAlbDetails(deploymentItem.id, albRecord);
await this.audit(requestContext, { action: 'update-deployment-store', body: result });
return result;
await this.audit(requestContext, { action: `update-alb-count-account-${awsAccountId}`, body: result });
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ async function updateEnvOnProvisioningSuccess({
return { requestContext, container, resolvedVars, status, outputs, provisionedProductId };
}

// This step calls "onEnvOnProvisioningFailure" in case of any errors.
// This step calls "onEnvProvisioningFailure" in case of any errors.
async function updateEnvOnProvisioningFailure({
requestContext,
container,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,19 +378,6 @@ describe('CheckLaunchDependencyStep', () => {
});

describe('onPass', () => {
it('should not increase alb dependent workspace count when needsAlb is false', async () => {
jest.spyOn(step.payloadOrConfig, 'optionalBoolean').mockImplementationOnce(() => {
return false;
});
await step.onPass();
expect(albService.increaseAlbDependentWorkspaceCount).not.toHaveBeenCalled();
});

it('should increase alb dependent workspace count when needsAlb is true', async () => {
await step.onPass();
expect(albService.increaseAlbDependentWorkspaceCount).toHaveBeenCalled();
});

it('should release lock when alb is present', async () => {
try {
await step.onPass();
Expand Down
Loading

0 comments on commit 7042d83

Please sign in to comment.