Skip to content

Commit

Permalink
migrate instanceTypeService from wows to deck
Browse files Browse the repository at this point in the history
  • Loading branch information
anotherchrisberry committed Aug 25, 2014
1 parent 18acd67 commit 26d08ee
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 10 deletions.
231 changes: 231 additions & 0 deletions app/scripts/services/instanceTypeService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
'use strict';

require('../app');
var angular = require('angular');

angular.module('deckApp')
.factory('instanceTypeService', function ($http, $q, settings, _) {

var m3 = {
type: 'M3',
description: 'This family includes the M3 instance types and provides a balance of compute, memory, and network resources, and it is a good choice for many applications.',
instanceTypes: [
{
name: 'm3.medium',
label: 'Medium',
cpu: 1,
memory: 3.75,
storage: {
type: 'SSD',
size: 4,
count: 1
},
costFactor: 1
},
{
name: 'm3.large',
label: 'Large',
cpu: 2,
memory: 7.5,
storage: {
type: 'SSD',
size: 32,
count: 1
},
costFactor: 2
},
{
name: 'm3.xlarge',
label: 'XLarge',
cpu: 4,
memory: 15,
storage: {
type: 'SSD',
size: 40,
count: 2
},
costFactor: 2
},
{
name: 'm3.2xlarge',
label: '2XLarge',
cpu: 8,
memory: 30,
storage: {
type: 'SSD',
size: 80,
count: 2
},
costFactor: 3
}
]
};

var t2 = {
type: 'T2',
description: 'T2 instances are a good choice for workloads that don’t use the full CPU o!en or consistently, but occasionally need to burst (e.g. web servers, developer environments and small databases).',
instanceTypes: [
{
name: 't2.small',
label: 'Small',
cpu: 1,
memory: 2,
storage: { type: 'EBS' },
costFactor: 1
},
{
name: 't2.medium',
label: 'Medium',
cpu: 2,
memory: 4,
storage: { type: 'EBS' },
costFactor: 2
}
]
};

var m3micro = {
type: 'M3',
description: 'This family includes the M3 instance types and provides a balance of compute, memory, and network resources, and it is a good choice for many applications.',
instanceTypes: [
{
name: 'm3.medium',
label: 'Medium',
cpu: 1,
memory: 3.75,
storage: {
type: 'SSD',
size: 4,
count: 1
},
costFactor: 1
}
]
};

var r3 = {
type: 'R3',
description: 'R3 instances are optimized for memory-intensive applications and have the lowest cost per GiB of RAM among Amazon EC2 instance types.',
instanceTypes: [
{
name: 'r3.large',
label: 'Large',
cpu: 2,
memory: 15.25,
storage: {
type: 'SSD',
size: 32,
count: 1
},
costFactor: 1
},
{
name: 'r3.xlarge',
label: 'XLarge',
cpu: 4,
memory: 30.5,
storage: {
type: 'SSD',
size: 80,
count: 1
},
costFactor: 2
},
{
name: 'r3.2xlarge',
label: '2XLarge',
cpu: 8,
memory: 61,
storage: {
type: 'SSD',
size: 160,
count: 1
},
costFactor: 3
},
{
name: 'r3.4xlarge',
label: '4XLarge',
cpu: 16,
memory: 122,
storage: {
type: 'SSD',
size: 320,
count: 1
},
costFactor: 4
}
]
};

var categories = [
{
type: 'general',
label: 'General Purpose',
families: [ m3 ]
},
{
type: 'memory',
label: 'High Memory',
families: [ r3 ]
},
{
type: 'micro',
label: 'Micro Utility',
families: [t2, m3micro]
}
];

function getCategories() {
var deferred = $q.defer();
deferred.resolve(categories);
return deferred.promise;
}

var regionTypesCache = null;

function getAllTypesByRegion() {
var deferred = $q.defer();
if (regionTypesCache) {
deferred.resolve(regionTypesCache);
} else {
$http({ url: settings.awsMetadataUrl + '/instanceType'}).then(function(response) {
regionTypesCache = response.data;
deferred.resolve(response.data);
});
}
return deferred.promise;
}

function getAvailableTypesForRegions(selectedRegions) {
selectedRegions = selectedRegions || [];
return getAllTypesByRegion().then(function(instanceTypes) {
var availableTypes = [];
instanceTypes.forEach(function(instanceType) {
if (_.intersection(selectedRegions, instanceType.regions).length === selectedRegions.length) {
availableTypes.push(instanceType.name);
}
});
return availableTypes.sort();
});
}

function getAvailableRegionsForType(instanceType) {
return getAllTypesByRegion().then(function(data) {
var instance = _.find(data, { name: instanceType });
return instance ? instance.regions : [];
});
}

function clearCache() {
regionTypesCache = null;
}

return {
getCategories: getCategories,
getAvailableTypesForRegions: getAvailableTypesForRegions,
getAvailableRegionsForType: getAvailableRegionsForType,
clearCache: clearCache
};
}
);
1 change: 1 addition & 0 deletions app/scripts/services/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ angular.module('deckApp')
front50Url: 'http://front50.test.netflix.net',
oortUrl: 'http://oort.prod.netflix.net',
pondUrl: 'http://pond.test.netflix.net',
awsMetadataUrl: 'http://spinnaker.test.netflix.net/aws',
accounts: {
prod: {
challengeDestructiveActions: true
Expand Down
12 changes: 9 additions & 3 deletions app/views/application/cluster/all.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ <h3>
<span class="glyphicon glyphicon-th-large"></span> Scaling Groups
</h3>
<div class="application-actions">
<select class="form-control input-sm">
<option value="">Cluster Actions</option>
</select>
<div class="dropdown">
<button type="button" class="btn btn-sm btn-default dropdown-toggle" ng-disabled="disabled">
Cluster Actions <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li class="dropdown-header">CONFIG</li>
<li><a href="#">Create ASG</a></li>
</ul>
</div>
</div>
</div>
<div ng-include="'views/application/cluster/filters.html'"></div>
Expand Down
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = function(config) {
// - PhantomJS
// - IE (only Windows)
browsers: [
'PhantomJS'
'Chrome'
],

// Which plugins to enable
Expand Down
15 changes: 9 additions & 6 deletions test-results.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
<?xml version="1.0"?>
<testsuites>
<testsuite name="Chrome 36.0.1985 (Mac OS X 10.9.4)" package="" timestamp="2014-08-21T02:08:02" id="0" hostname="lgml-chrisb" tests="9" errors="0" failures="0" time="0.14">
<testsuite name="Chrome 36.0.1985 (Mac OS X 10.9.4)" package="" timestamp="2014-08-25T19:52:06" id="0" hostname="lgml-chrisb" tests="12" errors="0" failures="0" time="0.166">
<properties>
<property name="browser.fullName" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"/>
</properties>
<testcase name="should create a scope" time="0.064" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Controller: MainCtrl"/>
<testcase name="should create a scope" time="0.052" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Controller: MainCtrl"/>
<testcase name="should handle cardinal directions" time="0.011" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should handle intermediate directions" time="0.011" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should handle multiple regions" time="0.008" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should handle non-region characters" time="0.008" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should handle multiple regions" time="0.007" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should handle non-region characters" time="0.007" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should ignore capitalized content" time="0.015" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should ignore invalid intermediate directions" time="0.007" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should ignore invalid intermediate directions" time="0.006" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should ignore invalid values but translate valid ones" time="0.009" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should abbreviate availability zones" time="0.007" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="should abbreviate availability zones" time="0.006" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Filter: regionAbbreviator"/>
<testcase name="list caches results and reuses them" time="0.017" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Service: InstanceType"/>
<testcase name="returns an intersection of instance types, sorted by name" time="0.011" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Service: InstanceType"/>
<testcase name="returns the regions for the supplied instance type, or an empty list if non-existent" time="0.014" classname="Chrome 36.0.1985 (Mac OS X 10.9.4).Service: InstanceType"/>
<system-out><![CDATA[
]]></system-out>
<system-err/>
Expand Down
92 changes: 92 additions & 0 deletions test/spec/services/instanceTypeService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

describe('Service: InstanceType', function() {

var service, scope, $http, config, instanceTypes;

beforeEach(module('deckApp'));

beforeEach(inject(function(settings, instanceTypeService, $rootScope, $httpBackend) {
instanceTypes = [];

service = instanceTypeService;
scope = $rootScope.$new();
config = settings;
$http = $httpBackend;

$http.when('GET', config.awsMetadataUrl + '/instanceType').respond(200, instanceTypes);
}));

afterEach(function() {
service.clearCache();
});

it('list caches results and reuses them', function() {

service.getAvailableTypesForRegions();
$http.flush();
scope.$apply();
service.getAvailableTypesForRegions();

$http.verifyNoOutstandingExpectation();
$http.verifyNoOutstandingRequest();
});

it('returns an intersection of instance types, sorted by name', function() {

// setup:
instanceTypes.push({ name: 'small', regions: ['a','b']});
instanceTypes.push({ name: 'medium', regions: ['b','c']});
instanceTypes.push({ name: 'large', regions: ['c','d']});

// expect:
// regions || expectedInstanceTypes
testAvailableTypes(['a'], ['small']);
testAvailableTypes(['b'], ['medium','small']);
testAvailableTypes(['c'], ['large','medium']);
testAvailableTypes(['a','b'], ['small']);
testAvailableTypes(['b','c'], ['medium']);
testAvailableTypes(['a','c'], []);
testAvailableTypes(['a','b','c'], []);

$http.flush();

});

it('returns the regions for the supplied instance type, or an empty list if non-existent', function() {
instanceTypes.push({ name: 'small', regions: ['a','b']});
instanceTypes.push({ name: 'large', regions: ['c','d']});

service.getAvailableRegionsForType('small').then( function(result) {
expect(result).toEqual(['a','b']);
});

service.getAvailableRegionsForType('non-existent').then( function(result) {
expect(result).toEqual([]);
});

$http.flush();
});

function testAvailableTypes(regions, expected) {
service.getAvailableTypesForRegions(regions).then( function(result) {
expect(result).toEqual(expected);
});
}
});

0 comments on commit 26d08ee

Please sign in to comment.