Commit 22fdc65b authored by Enrique Alcantara's avatar Enrique Alcantara

Use AWS SDK to obtain cloud resource descriptors

Use AWS SDK for javascript to obtain descriptors of
the configuration parameters used to create an EKS cluster.
parent 79c02d52
import axios from '~/lib/utils/axios_utils'; import AWS from 'aws-sdk/global';
import EC2 from 'aws-sdk/clients/ec2';
export default apiPaths => ({ import IAM from 'aws-sdk/clients/iam';
fetchRoles() {
return axios const lookupVpcName = ({ Tags: tags, VpcId: id }) => {
.get(apiPaths.getRolesPath) const nameTag = tags.find(({ Key: key }) => key === 'Name');
.then(({ data: { roles } }) =>
roles.map(({ role_name: name, arn: value }) => ({ name, value })), return nameTag ? nameTag.Value : id;
); };
},
fetchKeyPairs({ region }) { export const DEFAULT_REGION = 'us-east-2';
return axios
.get(apiPaths.getKeyPairsPath, { params: { region } }) export const setAWSConfig = ({ awsCredentials }) => {
.then(({ data: { key_pairs: keyPairs } }) => AWS.config = {
keyPairs.map(({ key_name }) => ({ name: key_name, value: key_name })), ...awsCredentials,
); region: DEFAULT_REGION,
}, };
fetchRegions() { };
return axios.get(apiPaths.getRegionsPath).then(({ data: { regions } }) =>
regions.map(({ region_name }) => ({ export const fetchRoles = () => {
name: region_name, const iam = new IAM();
value: region_name,
return iam
.listRoles()
.promise()
.then(({ Roles: roles }) => roles.map(({ RoleName: name, Arn: value }) => ({ name, value })));
};
export const fetchRegions = () => {
const ec2 = new EC2();
return ec2
.describeRegions()
.promise()
.then(({ Regions: regions }) =>
regions.map(({ RegionName: name }) => ({
name,
value: name,
})), })),
); );
}, };
fetchVpcs({ region }) {
return axios.get(apiPaths.getVpcsPath, { params: { region } }).then(({ data: { vpcs } }) => export const fetchKeyPairs = ({ region }) => {
vpcs.map(({ vpc_id }) => ({ const ec2 = new EC2({ region });
value: vpc_id,
name: vpc_id, return ec2
.describeKeyPairs()
.promise()
.then(({ KeyPairs: keyPairs }) => keyPairs.map(({ KeyName: name }) => ({ name, value: name })));
};
export const fetchVpcs = ({ region }) => {
const ec2 = new EC2({ region });
return ec2
.describeVpcs()
.promise()
.then(({ Vpcs: vpcs }) =>
vpcs.map(vpc => ({
value: vpc.VpcId,
name: lookupVpcName(vpc),
})), })),
); );
}, };
fetchSubnets({ vpc, region }) {
return axios export const fetchSubnets = ({ vpc, region }) => {
.get(apiPaths.getSubnetsPath, { params: { vpc_id: vpc, region } }) const ec2 = new EC2({ region });
.then(({ data: { subnets } }) =>
subnets.map(({ subnet_id }) => ({ name: subnet_id, value: subnet_id })), return ec2
); .describeSubnets({
}, Filters: [
fetchSecurityGroups({ vpc, region }) { {
return axios Name: 'vpc-id',
.get(apiPaths.getSecurityGroupsPath, { params: { vpc_id: vpc, region } }) Values: [vpc],
.then(({ data: { security_groups: securityGroups } }) => },
securityGroups.map(({ group_name: name, group_id: value }) => ({ name, value })), ],
); })
}, .promise()
fetchInstanceTypes() { .then(({ Subnets: subnets }) => subnets.map(({ SubnetId: id }) => ({ value: id, name: id })));
return axios };
.get(apiPaths.getInstanceTypesPath)
.then(({ data: { instance_types: instanceTypes } }) => export const fetchSecurityGroups = ({ region, vpc }) => {
instanceTypes.map(({ instance_type_name }) => ({ const ec2 = new EC2({ region });
name: instance_type_name,
value: instance_type_name, return ec2
})), .describeSecurityGroups({
); Filters: [
}, {
}); Name: 'vpc-id',
Values: [vpc],
},
],
})
.promise()
.then(({ SecurityGroups: securityGroups }) =>
securityGroups.map(({ GroupName: name, GroupId: value }) => ({ name, value })),
);
};
...@@ -6,12 +6,17 @@ import state from './state'; ...@@ -6,12 +6,17 @@ import state from './state';
import clusterDropdownStore from './cluster_dropdown'; import clusterDropdownStore from './cluster_dropdown';
import awsServicesFactory from '../services/aws_services_facade'; import {
fetchRoles,
fetchRegions,
fetchKeyPairs,
fetchVpcs,
fetchSubnets,
fetchSecurityGroups,
} from '../services/aws_services_facade';
const createStore = ({ initialState, apiPaths }) => { const createStore = ({ initialState }) =>
const awsServices = awsServicesFactory(apiPaths); new Vuex.Store({
return new Vuex.Store({
actions, actions,
getters, getters,
mutations, mutations,
...@@ -19,34 +24,33 @@ const createStore = ({ initialState, apiPaths }) => { ...@@ -19,34 +24,33 @@ const createStore = ({ initialState, apiPaths }) => {
modules: { modules: {
roles: { roles: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchRoles), ...clusterDropdownStore({ fetchFn: fetchRoles }),
}, },
regions: { regions: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchRegions), ...clusterDropdownStore({ fetchFn: fetchRegions }),
}, },
keyPairs: { keyPairs: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchKeyPairs), ...clusterDropdownStore({ fetchFn: fetchKeyPairs }),
}, },
vpcs: { vpcs: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchVpcs), ...clusterDropdownStore({ fetchFn: fetchVpcs }),
}, },
subnets: { subnets: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchSubnets), ...clusterDropdownStore({ fetchFn: fetchSubnets }),
}, },
securityGroups: { securityGroups: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchSecurityGroups), ...clusterDropdownStore({ fetchFn: fetchSecurityGroups }),
}, },
instanceTypes: { instanceTypes: {
namespaced: true, namespaced: true,
...clusterDropdownStore(awsServices.fetchInstanceTypes), ...clusterDropdownStore({ initialState: initialState.instanceTypes }),
}, },
}, },
}); });
};
export default createStore; export default createStore;
import AxiosMockAdapter from 'axios-mock-adapter'; import AWS from 'aws-sdk/global';
import awsServicesFacadeFactory from '~/create_cluster/eks_cluster/services/aws_services_facade'; import EC2 from 'aws-sdk/clients/ec2';
import axios from '~/lib/utils/axios_utils'; import {
setAWSConfig,
fetchRoles,
fetchRegions,
fetchKeyPairs,
fetchVpcs,
fetchSubnets,
fetchSecurityGroups,
DEFAULT_REGION,
} from '~/create_cluster/eks_cluster/services/aws_services_facade';
const mockListRolesPromise = jest.fn();
const mockDescribeRegionsPromise = jest.fn();
const mockDescribeKeyPairsPromise = jest.fn();
const mockDescribeVpcsPromise = jest.fn();
const mockDescribeSubnetsPromise = jest.fn();
const mockDescribeSecurityGroupsPromise = jest.fn();
jest.mock('aws-sdk/clients/iam', () =>
jest.fn().mockImplementation(() => ({
listRoles: jest.fn().mockReturnValue({ promise: mockListRolesPromise }),
})),
);
jest.mock('aws-sdk/clients/ec2', () =>
jest.fn().mockImplementation(() => ({
describeRegions: jest.fn().mockReturnValue({ promise: mockDescribeRegionsPromise }),
describeKeyPairs: jest.fn().mockReturnValue({ promise: mockDescribeKeyPairsPromise }),
describeVpcs: jest.fn().mockReturnValue({ promise: mockDescribeVpcsPromise }),
describeSubnets: jest.fn().mockReturnValue({ promise: mockDescribeSubnetsPromise }),
describeSecurityGroups: jest
.fn()
.mockReturnValue({ promise: mockDescribeSecurityGroupsPromise }),
})),
);
describe('awsServicesFacade', () => { describe('awsServicesFacade', () => {
let apiPaths;
let axiosMock;
let awsServices;
let region; let region;
let vpc; let vpc;
beforeEach(() => { beforeEach(() => {
apiPaths = {
getKeyPairsPath: '/clusters/aws/api/key_pairs',
getRegionsPath: '/clusters/aws/api/regions',
getRolesPath: '/clusters/aws/api/roles',
getSecurityGroupsPath: '/clusters/aws/api/security_groups',
getSubnetsPath: '/clusters/aws/api/subnets',
getVpcsPath: '/clusters/aws/api/vpcs',
getInstanceTypesPath: '/clusters/aws/api/instance_types',
};
region = 'west-1'; region = 'west-1';
vpc = 'vpc-2'; vpc = 'vpc-2';
awsServices = awsServicesFacadeFactory(apiPaths);
axiosMock = new AxiosMockAdapter(axios);
}); });
describe('when fetchRegions succeeds', () => { it('setAWSConfig configures AWS SDK with provided credentials and default region', () => {
let regions; const awsCredentials = {
let regionsOutput; accessKeyId: 'access-key',
secretAccessKey: 'secret-key',
sessionToken: 'session-token',
};
beforeEach(() => { setAWSConfig({ awsCredentials });
regions = [{ region_name: 'east-1' }, { region_name: 'west-2' }];
regionsOutput = regions.map(({ region_name: name }) => ({ name, value: name }));
axiosMock.onGet(apiPaths.getRegionsPath).reply(200, { regions });
});
it('return list of roles where each item has a name and value', () => { expect(AWS.config).toEqual({
expect(awsServices.fetchRegions()).resolves.toEqual(regionsOutput); ...awsCredentials,
region: DEFAULT_REGION,
}); });
}); });
...@@ -46,15 +66,32 @@ describe('awsServicesFacade', () => { ...@@ -46,15 +66,32 @@ describe('awsServicesFacade', () => {
beforeEach(() => { beforeEach(() => {
roles = [ roles = [
{ role_name: 'admin', arn: 'aws::admin' }, { RoleName: 'admin', Arn: 'aws::admin' },
{ role_name: 'read-only', arn: 'aws::read-only' }, { RoleName: 'read-only', Arn: 'aws::read-only' },
]; ];
rolesOutput = roles.map(({ role_name: name, arn: value }) => ({ name, value })); rolesOutput = roles.map(({ RoleName: name, Arn: value }) => ({ name, value }));
axiosMock.onGet(apiPaths.getRolesPath).reply(200, { roles });
mockListRolesPromise.mockResolvedValueOnce({ Roles: roles });
}); });
it('return list of regions where each item has a name and value', () => { it('return list of regions where each item has a name and value', () => {
expect(awsServices.fetchRoles()).resolves.toEqual(rolesOutput); expect(fetchRoles()).resolves.toEqual(rolesOutput);
});
});
describe('when fetchRegions succeeds', () => {
let regions;
let regionsOutput;
beforeEach(() => {
regions = [{ RegionName: 'east-1' }, { RegionName: 'west-2' }];
regionsOutput = regions.map(({ RegionName: name }) => ({ name, value: name }));
mockDescribeRegionsPromise.mockResolvedValueOnce({ Regions: regions });
});
it('return list of roles where each item has a name and value', () => {
expect(fetchRegions()).resolves.toEqual(regionsOutput);
}); });
}); });
...@@ -63,15 +100,19 @@ describe('awsServicesFacade', () => { ...@@ -63,15 +100,19 @@ describe('awsServicesFacade', () => {
let keyPairsOutput; let keyPairsOutput;
beforeEach(() => { beforeEach(() => {
keyPairs = [{ key_pair: 'key-pair' }, { key_pair: 'key-pair-2' }]; keyPairs = [{ KeyName: 'key-pair' }, { KeyName: 'key-pair-2' }];
keyPairsOutput = keyPairs.map(({ key_name: name }) => ({ name, value: name })); keyPairsOutput = keyPairs.map(({ KeyName: name }) => ({ name, value: name }));
axiosMock
.onGet(apiPaths.getKeyPairsPath, { params: { region } }) mockDescribeKeyPairsPromise.mockResolvedValueOnce({ KeyPairs: keyPairs });
.reply(200, { key_pairs: keyPairs }); });
it('instantatiates ec2 service with provided region', () => {
fetchKeyPairs({ region });
expect(EC2).toHaveBeenCalledWith({ region });
}); });
it('return list of key pairs where each item has a name and value', () => { it('return list of key pairs where each item has a name and value', () => {
expect(awsServices.fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput); expect(fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput);
}); });
}); });
...@@ -80,13 +121,37 @@ describe('awsServicesFacade', () => { ...@@ -80,13 +121,37 @@ describe('awsServicesFacade', () => {
let vpcsOutput; let vpcsOutput;
beforeEach(() => { beforeEach(() => {
vpcs = [{ vpc_id: 'vpc-1' }, { vpc_id: 'vpc-2' }]; vpcs = [{ VpcId: 'vpc-1', Tags: [] }, { VpcId: 'vpc-2', Tags: [] }];
vpcsOutput = vpcs.map(({ vpc_id: name }) => ({ name, value: name })); vpcsOutput = vpcs.map(({ VpcId: vpcId }) => ({ name: vpcId, value: vpcId }));
axiosMock.onGet(apiPaths.getVpcsPath, { params: { region } }).reply(200, { vpcs });
mockDescribeVpcsPromise.mockResolvedValueOnce({ Vpcs: vpcs });
});
it('instantatiates ec2 service with provided region', () => {
fetchVpcs({ region });
expect(EC2).toHaveBeenCalledWith({ region });
}); });
it('return list of vpcs where each item has a name and value', () => { it('return list of vpcs where each item has a name and value', () => {
expect(awsServices.fetchVpcs({ region })).resolves.toEqual(vpcsOutput); expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput);
});
});
describe('when vpcs has a Name tag', () => {
const vpcName = 'vpc name';
const vpcId = 'vpc id';
let vpcs;
let vpcsOutput;
beforeEach(() => {
vpcs = [{ VpcId: vpcId, Tags: [{ Key: 'Name', Value: vpcName }] }];
vpcsOutput = [{ name: vpcName, value: vpcId }];
mockDescribeVpcsPromise.mockResolvedValueOnce({ Vpcs: vpcs });
});
it('uses name tag value as the vpc name', () => {
expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput);
}); });
}); });
...@@ -95,15 +160,14 @@ describe('awsServicesFacade', () => { ...@@ -95,15 +160,14 @@ describe('awsServicesFacade', () => {
let subnetsOutput; let subnetsOutput;
beforeEach(() => { beforeEach(() => {
subnets = [{ subnet_id: 'vpc-1' }, { subnet_id: 'vpc-2' }]; subnets = [{ SubnetId: 'subnet-1' }, { SubnetId: 'subnet-2' }];
subnetsOutput = subnets.map(({ subnet_id }) => ({ name: subnet_id, value: subnet_id })); subnetsOutput = subnets.map(({ SubnetId }) => ({ name: SubnetId, value: SubnetId }));
axiosMock
.onGet(apiPaths.getSubnetsPath, { params: { region, vpc_id: vpc } }) mockDescribeSubnetsPromise.mockResolvedValueOnce({ Subnets: subnets });
.reply(200, { subnets });
}); });
it('return list of subnets where each item has a name and value', () => { it('return list of subnets where each item has a name and value', () => {
expect(awsServices.fetchSubnets({ region, vpc })).resolves.toEqual(subnetsOutput); expect(fetchSubnets({ region, vpc })).resolves.toEqual(subnetsOutput);
}); });
}); });
...@@ -113,40 +177,19 @@ describe('awsServicesFacade', () => { ...@@ -113,40 +177,19 @@ describe('awsServicesFacade', () => {
beforeEach(() => { beforeEach(() => {
securityGroups = [ securityGroups = [
{ group_name: 'admin group', group_id: 'group-1' }, { GroupName: 'admin group', GroupId: 'group-1' },
{ group_name: 'basic group', group_id: 'group-2' }, { GroupName: 'basic group', GroupId: 'group-2' },
]; ];
securityGroupsOutput = securityGroups.map(({ group_id: value, group_name: name }) => ({ securityGroupsOutput = securityGroups.map(({ GroupId: value, GroupName: name }) => ({
name, name,
value, value,
})); }));
axiosMock
.onGet(apiPaths.getSecurityGroupsPath, { params: { region, vpc_id: vpc } })
.reply(200, { security_groups: securityGroups });
});
it('return list of security groups where each item has a name and value', () => { mockDescribeSecurityGroupsPromise.mockResolvedValueOnce({ SecurityGroups: securityGroups });
expect(awsServices.fetchSecurityGroups({ region, vpc })).resolves.toEqual(
securityGroupsOutput,
);
}); });
});
describe('when fetchInstanceTypes succeeds', () => {
let instanceTypes;
let instanceTypesOutput;
beforeEach(() => { it('return list of security groups where each item has a name and value', () => {
instanceTypes = [{ instance_type_name: 't2.small' }, { instance_type_name: 't2.medium' }]; expect(fetchSecurityGroups({ region, vpc })).resolves.toEqual(securityGroupsOutput);
instanceTypesOutput = instanceTypes.map(({ instance_type_name }) => ({
name: instance_type_name,
value: instance_type_name,
}));
axiosMock.onGet(apiPaths.getInstanceTypesPath).reply(200, { instance_types: instanceTypes });
});
it('return list of instance types where each item has a name and value', () => {
expect(awsServices.fetchInstanceTypes()).resolves.toEqual(instanceTypesOutput);
}); });
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment