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';
export default apiPaths => ({
fetchRoles() {
return axios
.get(apiPaths.getRolesPath)
.then(({ data: { roles } }) =>
roles.map(({ role_name: name, arn: value }) => ({ name, value })),
);
},
fetchKeyPairs({ region }) {
return axios
.get(apiPaths.getKeyPairsPath, { params: { region } })
.then(({ data: { key_pairs: keyPairs } }) =>
keyPairs.map(({ key_name }) => ({ name: key_name, value: key_name })),
);
},
fetchRegions() {
return axios.get(apiPaths.getRegionsPath).then(({ data: { regions } }) =>
regions.map(({ region_name }) => ({
name: region_name,
value: region_name,
import AWS from 'aws-sdk/global';
import EC2 from 'aws-sdk/clients/ec2';
import IAM from 'aws-sdk/clients/iam';
const lookupVpcName = ({ Tags: tags, VpcId: id }) => {
const nameTag = tags.find(({ Key: key }) => key === 'Name');
return nameTag ? nameTag.Value : id;
};
export const DEFAULT_REGION = 'us-east-2';
export const setAWSConfig = ({ awsCredentials }) => {
AWS.config = {
...awsCredentials,
region: DEFAULT_REGION,
};
};
export const fetchRoles = () => {
const iam = new IAM();
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 } }) =>
vpcs.map(({ vpc_id }) => ({
value: vpc_id,
name: vpc_id,
};
export const fetchKeyPairs = ({ region }) => {
const ec2 = new EC2({ region });
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
.get(apiPaths.getSubnetsPath, { params: { vpc_id: vpc, region } })
.then(({ data: { subnets } }) =>
subnets.map(({ subnet_id }) => ({ name: subnet_id, value: subnet_id })),
);
},
fetchSecurityGroups({ vpc, region }) {
return axios
.get(apiPaths.getSecurityGroupsPath, { params: { vpc_id: vpc, region } })
.then(({ data: { security_groups: securityGroups } }) =>
securityGroups.map(({ group_name: name, group_id: value }) => ({ name, value })),
);
},
fetchInstanceTypes() {
return axios
.get(apiPaths.getInstanceTypesPath)
.then(({ data: { instance_types: instanceTypes } }) =>
instanceTypes.map(({ instance_type_name }) => ({
name: instance_type_name,
value: instance_type_name,
})),
);
},
});
};
export const fetchSubnets = ({ vpc, region }) => {
const ec2 = new EC2({ region });
return ec2
.describeSubnets({
Filters: [
{
Name: 'vpc-id',
Values: [vpc],
},
],
})
.promise()
.then(({ Subnets: subnets }) => subnets.map(({ SubnetId: id }) => ({ value: id, name: id })));
};
export const fetchSecurityGroups = ({ region, vpc }) => {
const ec2 = new EC2({ region });
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';
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 awsServices = awsServicesFactory(apiPaths);
return new Vuex.Store({
const createStore = ({ initialState }) =>
new Vuex.Store({
actions,
getters,
mutations,
......@@ -19,34 +24,33 @@ const createStore = ({ initialState, apiPaths }) => {
modules: {
roles: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchRoles),
...clusterDropdownStore({ fetchFn: fetchRoles }),
},
regions: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchRegions),
...clusterDropdownStore({ fetchFn: fetchRegions }),
},
keyPairs: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchKeyPairs),
...clusterDropdownStore({ fetchFn: fetchKeyPairs }),
},
vpcs: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchVpcs),
...clusterDropdownStore({ fetchFn: fetchVpcs }),
},
subnets: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchSubnets),
...clusterDropdownStore({ fetchFn: fetchSubnets }),
},
securityGroups: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchSecurityGroups),
...clusterDropdownStore({ fetchFn: fetchSecurityGroups }),
},
instanceTypes: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchInstanceTypes),
...clusterDropdownStore({ initialState: initialState.instanceTypes }),
},
},
});
};
export default createStore;
import AxiosMockAdapter from 'axios-mock-adapter';
import awsServicesFacadeFactory from '~/create_cluster/eks_cluster/services/aws_services_facade';
import axios from '~/lib/utils/axios_utils';
import AWS from 'aws-sdk/global';
import EC2 from 'aws-sdk/clients/ec2';
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', () => {
let apiPaths;
let axiosMock;
let awsServices;
let region;
let vpc;
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';
vpc = 'vpc-2';
awsServices = awsServicesFacadeFactory(apiPaths);
axiosMock = new AxiosMockAdapter(axios);
});
describe('when fetchRegions succeeds', () => {
let regions;
let regionsOutput;
it('setAWSConfig configures AWS SDK with provided credentials and default region', () => {
const awsCredentials = {
accessKeyId: 'access-key',
secretAccessKey: 'secret-key',
sessionToken: 'session-token',
};
beforeEach(() => {
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 });
});
setAWSConfig({ awsCredentials });
it('return list of roles where each item has a name and value', () => {
expect(awsServices.fetchRegions()).resolves.toEqual(regionsOutput);
expect(AWS.config).toEqual({
...awsCredentials,
region: DEFAULT_REGION,
});
});
......@@ -46,15 +66,32 @@ describe('awsServicesFacade', () => {
beforeEach(() => {
roles = [
{ role_name: 'admin', arn: 'aws::admin' },
{ role_name: 'read-only', arn: 'aws::read-only' },
{ RoleName: 'admin', Arn: 'aws::admin' },
{ RoleName: 'read-only', Arn: 'aws::read-only' },
];
rolesOutput = roles.map(({ role_name: name, arn: value }) => ({ name, value }));
axiosMock.onGet(apiPaths.getRolesPath).reply(200, { roles });
rolesOutput = roles.map(({ RoleName: name, Arn: value }) => ({ name, value }));
mockListRolesPromise.mockResolvedValueOnce({ Roles: roles });
});
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', () => {
let keyPairsOutput;
beforeEach(() => {
keyPairs = [{ key_pair: 'key-pair' }, { key_pair: 'key-pair-2' }];
keyPairsOutput = keyPairs.map(({ key_name: name }) => ({ name, value: name }));
axiosMock
.onGet(apiPaths.getKeyPairsPath, { params: { region } })
.reply(200, { key_pairs: keyPairs });
keyPairs = [{ KeyName: 'key-pair' }, { KeyName: 'key-pair-2' }];
keyPairsOutput = keyPairs.map(({ KeyName: name }) => ({ name, value: name }));
mockDescribeKeyPairsPromise.mockResolvedValueOnce({ KeyPairs: 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', () => {
expect(awsServices.fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput);
expect(fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput);
});
});
......@@ -80,13 +121,37 @@ describe('awsServicesFacade', () => {
let vpcsOutput;
beforeEach(() => {
vpcs = [{ vpc_id: 'vpc-1' }, { vpc_id: 'vpc-2' }];
vpcsOutput = vpcs.map(({ vpc_id: name }) => ({ name, value: name }));
axiosMock.onGet(apiPaths.getVpcsPath, { params: { region } }).reply(200, { vpcs });
vpcs = [{ VpcId: 'vpc-1', Tags: [] }, { VpcId: 'vpc-2', Tags: [] }];
vpcsOutput = vpcs.map(({ VpcId: vpcId }) => ({ name: vpcId, value: vpcId }));
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', () => {
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', () => {
let subnetsOutput;
beforeEach(() => {
subnets = [{ subnet_id: 'vpc-1' }, { subnet_id: 'vpc-2' }];
subnetsOutput = subnets.map(({ subnet_id }) => ({ name: subnet_id, value: subnet_id }));
axiosMock
.onGet(apiPaths.getSubnetsPath, { params: { region, vpc_id: vpc } })
.reply(200, { subnets });
subnets = [{ SubnetId: 'subnet-1' }, { SubnetId: 'subnet-2' }];
subnetsOutput = subnets.map(({ SubnetId }) => ({ name: SubnetId, value: SubnetId }));
mockDescribeSubnetsPromise.mockResolvedValueOnce({ Subnets: subnets });
});
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', () => {
beforeEach(() => {
securityGroups = [
{ group_name: 'admin group', group_id: 'group-1' },
{ group_name: 'basic group', group_id: 'group-2' },
{ GroupName: 'admin group', GroupId: 'group-1' },
{ GroupName: 'basic group', GroupId: 'group-2' },
];
securityGroupsOutput = securityGroups.map(({ group_id: value, group_name: name }) => ({
securityGroupsOutput = securityGroups.map(({ GroupId: value, GroupName: name }) => ({
name,
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', () => {
expect(awsServices.fetchSecurityGroups({ region, vpc })).resolves.toEqual(
securityGroupsOutput,
);
mockDescribeSecurityGroupsPromise.mockResolvedValueOnce({ SecurityGroups: securityGroups });
});
});
describe('when fetchInstanceTypes succeeds', () => {
let instanceTypes;
let instanceTypesOutput;
beforeEach(() => {
instanceTypes = [{ instance_type_name: 't2.small' }, { instance_type_name: 't2.medium' }];
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);
it('return list of security groups where each item has a name and value', () => {
expect(fetchSecurityGroups({ region, vpc })).resolves.toEqual(securityGroupsOutput);
});
});
});
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