├── grails-app
├── i18n
│ └── messages.properties
├── views
│ ├── error.gsp
│ ├── dashboard
│ │ ├── editappgroup.gsp
│ │ ├── summary.gsp
│ │ └── breakdown.gsp
│ └── layouts
│ │ └── main.gsp
└── conf
│ ├── UrlMappings.groovy
│ ├── TrackingFilters.groovy
│ ├── DataSource.groovy
│ ├── Config.groovy
│ └── BuildConfig.groovy
├── OSSMETADATA
├── screenshots
├── ss_detail.png
├── ss_summary.png
├── ss_breakdown_appgroup.png
├── ss_reservation_bytype.png
└── ss_reservation_byreservation.png
├── web-app
├── images
│ ├── spinner.gif
│ ├── downarrowdark.gif
│ ├── skin
│ │ └── information.png
│ └── tango
│ │ ├── 16
│ │ ├── places
│ │ │ └── user-trash.png
│ │ ├── tools
│ │ │ └── draw-freehand.png
│ │ ├── actions
│ │ │ └── document-save.png
│ │ └── apps
│ │ │ └── utilities-system-monitor.png
│ │ ├── 24
│ │ ├── actions
│ │ │ ├── edit-undo.png
│ │ │ └── document-save.png
│ │ └── places
│ │ │ └── user-trash.png
│ │ └── tango-icon-theme
│ │ └── 32x32
│ │ └── actions
│ │ ├── go-next.png
│ │ └── go-previous.png
├── css
│ ├── ui-lightness
│ │ └── images
│ │ │ ├── animated-overlay.gif
│ │ │ ├── ui-icons_222222_256x240.png
│ │ │ ├── ui-icons_228ef1_256x240.png
│ │ │ ├── ui-icons_ef8c08_256x240.png
│ │ │ ├── ui-icons_ffd27a_256x240.png
│ │ │ ├── ui-icons_ffffff_256x240.png
│ │ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ │ └── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ └── errors.css
└── WEB-INF
│ ├── sitemesh.xml
│ ├── grails.xml
│ └── applicationContext.xml
├── wrapper
├── grails-wrapper.properties
├── springloaded-1.2.1.RELEASE.jar
└── grails-wrapper-runtime-2.4.4.jar
├── .travis.yml
├── src
├── java
│ ├── log4j.properties
│ ├── com
│ │ └── netflix
│ │ │ └── ice
│ │ │ ├── reader
│ │ │ ├── AggregateType.java
│ │ │ ├── ThroughputMetricService.java
│ │ │ ├── DataManager.java
│ │ │ ├── ApplicationGroupService.java
│ │ │ ├── Managers.java
│ │ │ ├── ReadOnlyData.java
│ │ │ ├── ApplicationGroup.java
│ │ │ ├── TagGroupManager.java
│ │ │ └── ReaderConfig.java
│ │ │ ├── tag
│ │ │ ├── ApplicationGroup.java
│ │ │ ├── TagType.java
│ │ │ ├── Account.java
│ │ │ ├── ResourceGroup.java
│ │ │ ├── InstanceOs.java
│ │ │ ├── Tag.java
│ │ │ ├── Product.java
│ │ │ ├── UsageType.java
│ │ │ └── Region.java
│ │ │ ├── common
│ │ │ ├── ConsolidateType.java
│ │ │ ├── Randomizer.java
│ │ │ ├── ProductService.java
│ │ │ ├── AccountService.java
│ │ │ ├── Config.java
│ │ │ ├── ResourceService.java
│ │ │ ├── Poller.java
│ │ │ └── IceOptions.java
│ │ │ ├── basic
│ │ │ ├── BasicResourceService.java
│ │ │ ├── BasicAccountService.java
│ │ │ ├── SampleMapDbResourceService.java
│ │ │ ├── MapDb.java
│ │ │ ├── BasicS3ApplicationGroupService.java
│ │ │ ├── BasicProductService.java
│ │ │ ├── EddaResourceService.java
│ │ │ └── BasicManagers.java
│ │ │ └── processor
│ │ │ ├── LineItemProcessor.java
│ │ │ ├── DataWriter.java
│ │ │ ├── TagGroupWriter.java
│ │ │ ├── ReservationService.java
│ │ │ ├── ReadWriteData.java
│ │ │ └── ProcessorConfig.java
│ └── sample.properties
├── groovy
│ └── com
│ │ └── netflix
│ │ └── ice
│ │ └── JSONConverter.groovy
└── test
│ └── com
│ └── netflix
│ └── ice
│ └── basic
│ └── EddaResourceServiceTest.java
├── .gitignore
├── application.properties
├── conf
└── system
│ ├── setenv.sh
│ └── server.xml
├── install.sh
└── grailsw.bat
/grails-app/i18n/messages.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/OSSMETADATA:
--------------------------------------------------------------------------------
1 | osslifecycle=maintenance
2 |
--------------------------------------------------------------------------------
/screenshots/ss_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/screenshots/ss_detail.png
--------------------------------------------------------------------------------
/screenshots/ss_summary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/screenshots/ss_summary.png
--------------------------------------------------------------------------------
/web-app/images/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/spinner.gif
--------------------------------------------------------------------------------
/web-app/images/downarrowdark.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/downarrowdark.gif
--------------------------------------------------------------------------------
/web-app/images/skin/information.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/skin/information.png
--------------------------------------------------------------------------------
/screenshots/ss_breakdown_appgroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/screenshots/ss_breakdown_appgroup.png
--------------------------------------------------------------------------------
/screenshots/ss_reservation_bytype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/screenshots/ss_reservation_bytype.png
--------------------------------------------------------------------------------
/wrapper/grails-wrapper.properties:
--------------------------------------------------------------------------------
1 | wrapper.dist.url=http://dist.springframework.org.s3.amazonaws.com/release/GRAILS/
2 |
--------------------------------------------------------------------------------
/wrapper/springloaded-1.2.1.RELEASE.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/wrapper/springloaded-1.2.1.RELEASE.jar
--------------------------------------------------------------------------------
/wrapper/grails-wrapper-runtime-2.4.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/wrapper/grails-wrapper-runtime-2.4.4.jar
--------------------------------------------------------------------------------
/screenshots/ss_reservation_byreservation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/screenshots/ss_reservation_byreservation.png
--------------------------------------------------------------------------------
/web-app/images/tango/16/places/user-trash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/16/places/user-trash.png
--------------------------------------------------------------------------------
/web-app/images/tango/24/actions/edit-undo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/24/actions/edit-undo.png
--------------------------------------------------------------------------------
/web-app/images/tango/24/places/user-trash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/24/places/user-trash.png
--------------------------------------------------------------------------------
/web-app/images/tango/16/tools/draw-freehand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/16/tools/draw-freehand.png
--------------------------------------------------------------------------------
/web-app/images/tango/16/actions/document-save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/16/actions/document-save.png
--------------------------------------------------------------------------------
/web-app/images/tango/24/actions/document-save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/24/actions/document-save.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/animated-overlay.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/animated-overlay.gif
--------------------------------------------------------------------------------
/web-app/images/tango/16/apps/utilities-system-monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/16/apps/utilities-system-monitor.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/web-app/images/tango/tango-icon-theme/32x32/actions/go-next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/tango-icon-theme/32x32/actions/go-next.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/web-app/images/tango/tango-icon-theme/32x32/actions/go-previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/images/tango/tango-icon-theme/32x32/actions/go-previous.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/web-app/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Teevity/ice/HEAD/web-app/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language: groovy
4 |
5 | jdk:
6 | - oraclejdk7
7 |
8 | install:
9 | - export ICE_HOME=${TRAVIS_BUILD_DIR}
10 | - ./grailsw clean
11 | - yes | ./grailsw refresh-dependencies
12 |
13 | script:
14 | - bash -n install.sh
15 | - ./grailsw compile
--------------------------------------------------------------------------------
/src/java/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout
2 |
3 | # stdout
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} - %-5p %C{1} - [%F:%L] %m%n
--------------------------------------------------------------------------------
/grails-app/views/error.gsp:
--------------------------------------------------------------------------------
1 |
2 |
3 | Ice Runtime ExceptionError
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | - An error has occurred
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/grails-app/conf/UrlMappings.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Netflix, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | class UrlMappings {
18 |
19 | static mappings = {
20 | "/$controller/$action?/$id?" {}
21 | "/" { controller = "dashboard"}
22 | "500" (view: '/error')
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # .gitignore for Grails 1.2 and 1.3
2 |
3 | # web application files
4 | /web-app/WEB-INF
5 |
6 | # IDE support files
7 | /.classpath
8 | /.launch
9 | /.project
10 | /.settings
11 | /*.launch
12 | /*.tmproj
13 | /ivy*
14 | /eclipse
15 |
16 | # default HSQL database files for production mode
17 | /prodDb.*
18 |
19 | # general HSQL database files
20 | *Db.properties
21 | *Db.script
22 |
23 | # logs
24 | /stacktrace.log
25 | /test/reports
26 | /logs
27 |
28 | # project release file
29 | /*.war
30 |
31 | # plugin release file
32 | /*.zip
33 |
34 | # older plugin install locations
35 | /plugins
36 | /web-app/plugins
37 | /web-app/WEB-INF/classes
38 |
39 | # "temporary" build files
40 | /target
41 | /target-eclipse
42 | /work
43 |
44 | # other
45 | *.iws
46 |
47 | #project specific:
48 | /src/java/ice.properties
49 |
50 | # OSX
51 | .DS_Store
52 |
53 | # FUSE files
54 | .fuse_hidden*
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/AggregateType.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | public enum AggregateType {
21 | none,
22 | stats,
23 | data,
24 | both
25 | }
26 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/ApplicationGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | public class ApplicationGroup extends Tag {
21 |
22 | public ApplicationGroup(String name) {
23 | super(name);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/TagType.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | public enum TagType {
21 | Account,
22 | Region,
23 | Zone,
24 | Product,
25 | Operation,
26 | UsageType,
27 | ResourceGroup,
28 | ApplicationGroup;
29 | }
30 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/Account.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | public class Account extends Tag {
21 | public final String id;
22 |
23 | public Account(String accountId, String accountName) {
24 | super(accountName);
25 | this.id = accountId;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/common/ConsolidateType.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.common;
19 |
20 | public enum ConsolidateType {
21 | hourly(3600000L),
22 | daily(24*3600000L),
23 | weekly(24*7*3600000L),
24 | monthly(-1);
25 |
26 | public final long millis;
27 |
28 | private ConsolidateType(long millis) {
29 | this.millis = millis;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/ThroughputMetricService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | import com.netflix.ice.common.ConsolidateType;
21 | import org.joda.time.Interval;
22 |
23 | /**
24 | * Interface to provide throughput metrics.
25 | */
26 | public interface ThroughputMetricService {
27 | void init();
28 | String getMetricName();
29 | String getMetricUnitName();
30 | String getFactoredCostCurrencySign();
31 | double getFactoredCostMultiply();
32 | double[] getData(Interval interval, ConsolidateType consolidateType) throws Exception;
33 | }
34 |
--------------------------------------------------------------------------------
/application.properties:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Netflix, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | app.grails.version=2.4.4
18 | app.name=ice
19 | app.servlet.version=2.4
20 | app.version=1.1.0
21 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
22 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
23 | log4j.appender.stdout.layout.ConversionPattern=%d %5p [%c] %m%n
24 | log4j.category.com.amazonaws.request=WARN
25 | log4j.category.com.netflix.cloud=DEBUG
26 | log4j.category.com.netflix.logging=WARN
27 | log4j.category.com.netflix.monitoring=WARN
28 | log4j.category.hibernate=ERROR
29 | log4j.category.httpclient=ERROR
30 | log4j.category.org.codehaus.groovy=WARN
31 | log4j.category.sun.reflect=WARN
32 | log4j.rootLogger=INFO, stdout
33 |
--------------------------------------------------------------------------------
/grails-app/conf/TrackingFilters.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Netflix, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.util.regex.Pattern
17 | import org.joda.time.DateTime
18 |
19 | class TrackingFilters {
20 |
21 | static final Pattern nonBrowserUserAgents = Pattern.compile(
22 | '.*(libcurl|Python-urllib|Wget|HttpClient|lwp-request|Java).*')
23 |
24 | static filters = {
25 | allExceptError(controller: 'error', invert: true) {
26 | before = {
27 |
28 | String userAgent = request.getHeader('user-agent')
29 | if (userAgent?.contains('MSIE') && !userAgent.contains('chromeframe')) {
30 | request['ieWithoutChromeFrame'] = true
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/web-app/WEB-INF/sitemesh.xml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
23 |
25 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/common/Randomizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.common;
19 |
20 | import java.util.Map;
21 |
22 | /**
23 | * Used to generate random/fake data
24 | */
25 | public interface Randomizer {
26 |
27 | /**
28 | * Get random/fake usage for given tag group.
29 | * @param time
30 | * @param tagGroup
31 | * @param usage
32 | * @return random/fake usage
33 | */
34 | double randomizeUsage(long time, TagGroup tagGroup, double usage);
35 |
36 | /**
37 | * Get random/fake cost for given tag group.
38 | * @param tagGroup
39 | * @return random/fake cost
40 | */
41 | double randomizeCost(TagGroup tagGroup);
42 |
43 | /**
44 | * Get map of resource distribution.
45 | * @return map of resource distribution
46 | */
47 | Map getDistribution(TagGroup tagGroup);
48 | }
49 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/DataManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | import com.netflix.ice.tag.Tag;
21 | import com.netflix.ice.tag.TagType;
22 | import org.joda.time.DateTime;
23 | import org.joda.time.Interval;
24 |
25 | import java.util.Map;
26 |
27 | /**
28 | * Interface to feed data to UI.
29 | */
30 | public interface DataManager {
31 |
32 | /**
33 | * Get map of data.
34 | * @param interval
35 | * @param tagLists
36 | * @param groupBy
37 | * @param aggregate
38 | * @param forReservation
39 | * @return
40 | */
41 | Map getData(Interval interval, TagLists tagLists, TagType groupBy, AggregateType aggregate, boolean forReservation);
42 |
43 | /**
44 | * Get data length.
45 | * @param start
46 | * @return
47 | */
48 | int getDataLength(DateTime start);
49 | }
50 |
--------------------------------------------------------------------------------
/src/groovy/com/netflix/ice/JSONConverter.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice
19 |
20 | import grails.converters.JSON
21 | import com.netflix.ice.tag.Tag
22 | import com.netflix.ice.reader.ApplicationGroup
23 |
24 | class JSONConverter {
25 |
26 | static void register() {
27 | JSON.registerObjectMarshaller(Tag) { Tag it ->
28 | return [name: it.name]
29 | }
30 | JSON.registerObjectMarshaller(ApplicationGroup) { ApplicationGroup appgroup ->
31 | def result = [name: appgroup.name, owner: appgroup.owner, data: [:]]
32 | for (String key: appgroup.data.keySet()) {
33 | result.data[key] = []
34 | for (String v: appgroup.data.get(key)) {
35 | result.data[key].add([name: v])
36 | }
37 | }
38 | return result
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/grails-app/conf/DataSource.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Netflix, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /*dataSource {
17 | pooled = true
18 | driverClassName = "org.hsqldb.jdbcDriver"
19 | username = "sa"
20 | password = ""
21 | }*/
22 | hibernate {
23 | cache.use_second_level_cache = true
24 | cache.use_query_cache = true
25 | cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
26 | }
27 |
28 | // environment specific settings
29 | environments {
30 | development {
31 | dataSource {
32 | dbCreate = "create-drop" // one of 'create', 'create-drop','update'
33 | //url = "jdbc:hsqldb:mem:devDB"
34 | }
35 | }
36 | test {
37 | dataSource {
38 | dbCreate = "update"
39 | //url = "jdbc:hsqldb:mem:testDb"
40 | }
41 | }
42 | production {
43 | dataSource {
44 | dbCreate = "update"
45 | //url = "jdbc:hsqldb:file:prodDb;shutdown=true"
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/common/ProductService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.common;
19 |
20 | import com.netflix.ice.tag.Product;
21 |
22 | import java.util.Collection;
23 | import java.util.List;
24 |
25 | public interface ProductService {
26 |
27 | /**
28 | * Get product by aws name, e.g. "Amazon Elastic Compute Cloud", "AWS Elastic MapReduce"
29 | * @param name
30 | * @return product
31 | */
32 | Product getProductByAwsName(String name);
33 |
34 | /**
35 | * Get product by name, e.g. ec2, emr
36 | * @param name
37 | * @return
38 | */
39 | Product getProductByName(String name);
40 |
41 | /**
42 | * Get list of products from given names
43 | * @param names
44 | * @return list of products
45 | */
46 | public List getProducts(List names);
47 |
48 | /**
49 | * Get list of products
50 | * @return list of products
51 | */
52 | public Collection getProducts();
53 | }
54 |
--------------------------------------------------------------------------------
/web-app/WEB-INF/grails.xml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 | DefaultSecurityConfig
22 | grails.plugins.springsecurity.SpringSecurityService
23 | grails.plugins.springsecurity.SecurityTagLib
24 | DefaultLdapSecurityConfig
25 | BootStrap
26 | BuildConfig
27 | Config
28 | DataSource
29 | OccasionFilters
30 | RegionFilters
31 | SettingsFilters
32 | resources
33 | TrackingFilters
34 | UrlMappings
35 | com.netflix.ice.DashboardController
36 |
37 |
38 | HibernateGrailsPlugin
39 | SpringSecurityCoreGrailsPlugin
40 | SpringSecurityLdapGrailsPlugin
41 |
42 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/basic/BasicResourceService.java:
--------------------------------------------------------------------------------
1 | package com.netflix.ice.basic;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.netflix.ice.common.ResourceService;
5 | import com.netflix.ice.processor.ProcessorConfig;
6 | import com.netflix.ice.reader.ReaderConfig;
7 | import com.netflix.ice.tag.Account;
8 | import com.netflix.ice.tag.Product;
9 | import com.netflix.ice.tag.Region;
10 | import org.apache.commons.lang.StringUtils;
11 |
12 | import java.util.List;
13 |
14 | public class BasicResourceService extends ResourceService {
15 |
16 | private ProcessorConfig processorConfig;
17 |
18 | @Override
19 | public void init() {
20 | processorConfig = ProcessorConfig.getInstance();
21 | }
22 |
23 | @Override
24 | public String getResource(Account account, Region region, Product product, String resourceId, String[] lineItem, long millisStart) {
25 | List header = processorConfig.lineItemProcessor.getHeader();
26 |
27 | String result = "";
28 | for (String tag: processorConfig.customTags) {
29 | int index = header.indexOf(tag);
30 | if (index > 0 && lineItem.length > index && !StringUtils.isEmpty(lineItem[index]))
31 | result = StringUtils.isEmpty(result) ? lineItem[index] : result + "_" + lineItem[index];
32 | }
33 |
34 | return StringUtils.isEmpty(result) ? product.name : result;
35 | }
36 |
37 | @Override
38 | public List> getProductsWithResources() {
39 | List> result = Lists.newArrayList();
40 | for (Product product: ReaderConfig.getInstance().productService.getProducts()) {
41 | result.add(Lists.newArrayList(product));
42 | }
43 | return result;
44 | }
45 |
46 | @Override
47 | public void commit() {
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/ApplicationGroupService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | import java.util.Map;
21 |
22 | /**
23 | * Interface to manager user defined application groups.
24 | */
25 | public interface ApplicationGroupService {
26 |
27 | void init();
28 |
29 | /**
30 | * Get a map of application groups. Key will be the application group name.
31 | * @return map of application groups
32 | */
33 | Map getApplicationGroups();
34 |
35 | /**
36 | * Get application group by name.
37 | * @param name
38 | * @return application group or null if not exist
39 | */
40 | ApplicationGroup getApplicationGroup(String name);
41 |
42 | /**
43 | * Save application group configuration.
44 | * @param applicationGroup
45 | * @return whether or not save was successfull
46 | */
47 | boolean saveApplicationGroup(ApplicationGroup applicationGroup);
48 |
49 | /**
50 | * Delete application group.
51 | * @param name
52 | * @return whether or not delete was successfull
53 | */
54 | boolean deleteApplicationGroup(String name);
55 | }
56 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/ResourceGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | import com.google.common.collect.Lists;
21 | import com.google.common.collect.Maps;
22 |
23 | import java.util.List;
24 | import java.util.concurrent.ConcurrentMap;
25 |
26 | public class ResourceGroup extends Tag {
27 | private ResourceGroup (String name) {
28 | super(name);
29 | }
30 | private static ConcurrentMap resourceGroups = Maps.newConcurrentMap();
31 |
32 | public static ResourceGroup getResourceGroup(String name) {
33 | ResourceGroup resourceGroup = resourceGroups.get(name);
34 | if (resourceGroup == null) {
35 | resourceGroups.putIfAbsent(name, new ResourceGroup(name));
36 | resourceGroup = resourceGroups.get(name);
37 | }
38 | return resourceGroup;
39 | }
40 |
41 | public static List getResourceGroups(List names) {
42 | List result = Lists.newArrayList();
43 | if (names != null) {
44 | for (String name: names) {
45 | ResourceGroup resourceGroup = resourceGroups.get(name);
46 | if (resourceGroup != null)
47 | result.add(resourceGroup);
48 | }
49 | }
50 | return result;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/processor/LineItemProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.processor;
19 |
20 | import com.netflix.ice.tag.Product;
21 | import java.util.List;
22 | import org.joda.time.DateTimeZone;
23 | import org.joda.time.format.DateTimeFormat;
24 | import org.joda.time.format.DateTimeFormatter;
25 |
26 | import java.util.Map;
27 |
28 | /**
29 | * Interface to process each line item in billing file.
30 | */
31 | public interface LineItemProcessor {
32 | public static final DateTimeFormatter amazonBillingDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withZone(DateTimeZone.UTC);
33 | public static final DateTimeFormatter amazonBillingDateFormat2 = DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss").withZone(DateTimeZone.UTC);
34 |
35 | void initIndexes(ProcessorConfig config, boolean withTags, String[] header);
36 | List getHeader();
37 | int getUserTagStartIndex();
38 | long getEndMillis(String[] items);
39 | Result process(long startMilli, boolean processAll, ProcessorConfig config, String[] items, Map usageDataByProduct, Map costDataByProduct, Map ondemandRate);
40 |
41 | public static enum Result {
42 | delay,
43 | ignore,
44 | hourly,
45 | monthly,
46 | daily
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/Managers.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | import com.netflix.ice.common.*;
21 | import com.netflix.ice.tag.Product;
22 |
23 | import java.util.Collection;
24 |
25 | /**
26 | * Interface to manager all TagGroupManager and DataManager instances for different products
27 | */
28 | public interface Managers {
29 |
30 | void init();
31 |
32 | /**
33 | *
34 | * @return collection of products
35 | */
36 | Collection getProducts();
37 |
38 | /**
39 | *
40 | * @param product
41 | * @return TagGroupManager instance for specified product
42 | */
43 | TagGroupManager getTagGroupManager(Product product);
44 |
45 | /**
46 | *
47 | * @param product
48 | * @param consolidateType
49 | * @return cost DataManager instance for specified product and consolidateType
50 | */
51 | DataManager getCostManager(Product product, ConsolidateType consolidateType);
52 |
53 | /**
54 | *
55 | * @param product
56 | * @param consolidateType
57 | * @return usage DataManager instance for specified product and consolidateType
58 | */
59 | DataManager getUsageManager(Product product, ConsolidateType consolidateType);
60 |
61 | /**
62 | * shutdown all manager instances
63 | */
64 | void shutdown();
65 | }
66 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/InstanceOs.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | public enum InstanceOs {
21 | linux("", "", "Linux/UNIX"),
22 | sqlserverweb(".sqlserverweb", ":0202", "Windows with SQL Server Web"),
23 | sqlserverstd(".sqlserverstd", ":0006", "Windows with SQL Server Standard"),
24 | sles(".sles", ":000g", "SUSE Linux"),
25 | rhel(".rhel", ":0010", "Red Hat Enterprise Linux"),
26 | rhbl(".rhbl", ":00g0", "Red Hat BYOL Linux"),
27 | windows(".windows", ":0002", "Windows"),
28 | dw(".dw", ":0001", "redshift"),
29 | others(".others", ":others", "others");
30 |
31 | public final String usageType;
32 | public final String code;
33 | public final String description;
34 |
35 | InstanceOs(String usageType, String code, String description) {
36 | this.usageType = usageType;
37 | this.code = code.toLowerCase();
38 | this.description = description.toLowerCase();
39 | }
40 |
41 | public static InstanceOs withCode(String code) {
42 | for (InstanceOs os: InstanceOs.values()) {
43 | if (code.toLowerCase().equals(os.code))
44 | return os;
45 | }
46 | return others;
47 | }
48 |
49 | public static InstanceOs withDescription(String description) {
50 | for (InstanceOs os: InstanceOs.values()) {
51 | if (description.toLowerCase().startsWith(os.description))
52 | return os;
53 | }
54 | return others;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/web-app/WEB-INF/applicationContext.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
25 |
26 |
27 | Grails application factory bean
28 |
29 |
30 |
31 |
32 | A bean that manages Grails plugins
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
46 |
47 | utf-8
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/web-app/css/errors.css:
--------------------------------------------------------------------------------
1 | h1, h2 {
2 | margin: 10px 25px 5px;
3 | }
4 |
5 | h2 {
6 | font-size: 1.1em;
7 | }
8 |
9 | .filename {
10 | font-style: italic;
11 | }
12 |
13 | .exceptionMessage {
14 | margin: 10px;
15 | border: 1px solid #000;
16 | padding: 5px;
17 | background-color: #E9E9E9;
18 | }
19 |
20 | .stack,
21 | .snippet {
22 | margin: 0 25px 10px;
23 | }
24 |
25 | .stack,
26 | .snippet {
27 | border: 1px solid #ccc;
28 | -mox-box-shadow: 0 0 2px rgba(0,0,0,0.2);
29 | -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2);
30 | box-shadow: 0 0 2px rgba(0,0,0,0.2);
31 | }
32 |
33 | /* error details */
34 | .error-details {
35 | border-top: 1px solid #FFAAAA;
36 | -mox-box-shadow: 0 0 2px rgba(0,0,0,0.2);
37 | -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2);
38 | box-shadow: 0 0 2px rgba(0,0,0,0.2);
39 | border-bottom: 1px solid #FFAAAA;
40 | -mox-box-shadow: 0 0 2px rgba(0,0,0,0.2);
41 | -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2);
42 | box-shadow: 0 0 2px rgba(0,0,0,0.2);
43 | background-color:#FFF3F3;
44 | line-height: 1.5;
45 | overflow: hidden;
46 | padding: 5px;
47 | padding-left:25px;
48 | }
49 |
50 | .error-details dt {
51 | clear: left;
52 | float: left;
53 | font-weight: bold;
54 | margin-right: 5px;
55 | }
56 |
57 | .error-details dt:after {
58 | content: ":";
59 | }
60 |
61 | .error-details dd {
62 | display: block;
63 | }
64 |
65 | /* stack trace */
66 | .stack {
67 | padding: 5px;
68 | overflow: auto;
69 | height: 150px;
70 | }
71 |
72 | /* code snippet */
73 | .snippet {
74 | background-color: #fff;
75 | font-family: monospace;
76 | }
77 |
78 | .snippet .line {
79 | display: block;
80 | }
81 |
82 | .snippet .lineNumber {
83 | background-color: #ddd;
84 | color: #999;
85 | display: inline-block;
86 | margin-right: 5px;
87 | padding: 0 3px;
88 | text-align: right;
89 | width: 3em;
90 | }
91 |
92 | .snippet .error {
93 | background-color: #fff3f3;
94 | font-weight: bold;
95 | }
96 |
97 | .snippet .error .lineNumber {
98 | background-color: #faa;
99 | color: #333;
100 | font-weight: bold;
101 | }
102 |
103 | .snippet .line:first-child .lineNumber {
104 | padding-top: 5px;
105 | }
106 |
107 | .snippet .line:last-child .lineNumber {
108 | padding-bottom: 5px;
109 | }
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/Tag.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | import java.io.Serializable;
21 |
22 | public abstract class Tag implements Comparable, Serializable {
23 | public static final Tag aggregated = new Tag("aggregated") {
24 | @Override
25 | public int compareTo(Tag t) {
26 | return this == t ? 0 : -1;
27 | }
28 | };
29 |
30 | public final String name;
31 | public final String s3Name;
32 | Tag(String name) {
33 | this.name = name;
34 | this.s3Name = Tag.toS3(name);
35 | }
36 |
37 | @Override
38 | public boolean equals(Object o) {
39 | if (o instanceof Tag)
40 | return this.name.equals(((Tag)o).name);
41 | else
42 | return false;
43 | }
44 |
45 | /**
46 | * Normalize a tagname suitable to be an S3 Filename
47 | */
48 | public static String toS3(String name) {
49 | name = name.replaceAll("/","--");
50 | return name;
51 | }
52 |
53 | /**
54 | * Normalize a tagname from an S3 Filename
55 | */
56 | public static String fromS3(String name) {
57 | name = name.replaceAll("--","/");
58 | return name;
59 | }
60 |
61 | @Override
62 | public String toString() {
63 | return this.name;
64 | }
65 |
66 | @Override
67 | public int hashCode() {
68 | return this.name.hashCode();
69 | }
70 |
71 | public int compareTo(Tag t) {
72 | if (t == aggregated)
73 | return -t.compareTo(this);
74 | int result = ("a" + this.name).compareTo("a" + t.name);
75 | return result;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/ReadOnlyData.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | import com.google.common.collect.Lists;
21 | import com.netflix.ice.common.TagGroup;
22 |
23 | import java.io.DataInput;
24 | import java.io.IOException;
25 | import java.util.Collection;
26 | import java.util.List;
27 |
28 | public class ReadOnlyData {
29 | double[][] data;
30 | private Collection tagGroups;
31 |
32 | public ReadOnlyData(double[][] data, Collection tagGroups) {
33 | this.data = data;
34 | this.tagGroups = tagGroups;
35 | }
36 |
37 | public double[] getData(int i) {
38 | return data[i];
39 | }
40 |
41 | public int getNum() {
42 | return data.length;
43 | }
44 |
45 | public Collection getTagGroups() {
46 | return tagGroups;
47 | }
48 |
49 | public static class Serializer {
50 |
51 | public static ReadOnlyData deserialize(DataInput in) throws IOException {
52 |
53 | int numKeys = in.readInt();
54 | List keys = Lists.newArrayList();
55 | for (int j = 0; j < numKeys; j++) {
56 | keys.add(TagGroup.Serializer.deserialize(ReaderConfig.getInstance(), in));
57 | }
58 |
59 | int num = in.readInt();
60 | double[][] data = new double[num][];
61 | for (int i = 0; i < num; i++) {
62 | data[i] = new double[keys.size()];
63 | boolean hasData = in.readBoolean();
64 | if (hasData) {
65 | for (int j = 0; j < keys.size(); j++) {
66 | double v = in.readDouble();
67 | if (v != 0) {
68 | data[i][j] = v;
69 | }
70 | }
71 | }
72 | }
73 |
74 | return new ReadOnlyData(data, keys);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/Product.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | public class Product extends Tag {
21 | public static final Product cloudfront = new Product("cloudfront");
22 | public static final Product cloudhsm = new Product("cloudhsm");
23 | public static final Product cloudwatch = new Product("cloudwatch");
24 | public static final Product data_pipeline = new Product("data_pipeline");
25 | public static final Product data_transfer = new Product("data_transfer");
26 | public static final Product direct_connect = new Product("direct_connect");
27 | public static final Product dynamodb = new Product("dynamodb");
28 | public static final Product ebs = new Product("ebs");
29 | public static final Product ec2 = new Product("ec2");
30 | public static final Product ec2_instance = new Product("ec2_instance");
31 | public static final Product eip = new Product("eip");
32 | public static final Product elasticache = new Product("elasticache");
33 | public static final Product emr = new Product("emr");
34 | public static final Product glacier = new Product("glacier");
35 | public static final Product monitor = new Product("monitor");
36 | public static final Product rds = new Product("rds");
37 | public static final Product redshift = new Product("redshift");
38 | public static final Product route53 = new Product("route53");
39 | public static final Product s3 = new Product("s3");
40 | public static final Product simpledb = new Product("simpledb");
41 | public static final Product ses = new Product("ses");
42 | public static final Product sns = new Product("sns");
43 | public static final Product sqs = new Product("sqs");
44 | public static final Product storage_gateway = new Product("storage_gateway");
45 | public static final Product sws = new Product("sws");
46 | public static final Product vpc = new Product("vpc");
47 |
48 | public Product (String name) {
49 | super(name);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/conf/system/setenv.sh:
--------------------------------------------------------------------------------
1 | # Determine the max heap size based on the instance type.
2 | # See: http://aws.amazon.com/ec2/instance-types/
3 | #
4 | # For nodes in the datacenter we rely on the convention that the hostname
5 | # indicates the amount of memory.
6 | function heapSize {
7 | instanceType=$(hostname)
8 | if [ "$EC2_INSTANCE_TYPE" != "" ]; then
9 | instanceType="$EC2_INSTANCE_TYPE"
10 | fi
11 |
12 | case $instanceType in
13 | m1.small) echo "1g" ;; # 1.7GB
14 | m1.large) echo "6g" ;; # 7.5GB
15 | m1.xlarge) echo "12g" ;; # 15GB
16 | t1.micro) echo "256m" ;; # 613MB
17 | m2.xlarge) echo "14g" ;; # 17.1GB
18 | m2.2xlarge) echo "30g" ;; # 34.2GB
19 | m2.4xlarge) echo "60g" ;; # 68.4GB
20 | c1.medium) echo "1g" ;; # 1.7GB
21 | c1.xlarge) echo "4g" ;; # 7GB
22 | cc1.4xlarge) echo "20g" ;; # 23GB
23 | cg1.4xlarge) echo "20g" ;; # 22GB
24 | *-4g*) echo "3g" ;;
25 | *-8g*) echo "6g" ;;
26 | *-16g*) echo "14g" ;;
27 | *-24g*) echo "21g" ;;
28 | *-32g*) echo "28g" ;;
29 | *-64g*) echo "60g" ;;
30 | *-72g*) echo "68g" ;;
31 | *) echo "1g" ;; # who knows, try for a gig
32 | esac
33 | }
34 |
35 | # Create the java heap size options. We always set min and max heap size to
36 | # be the same, this ensures that the program will crash right away if there
37 | # is not enough memory.
38 | function javaOptsHeapSize {
39 | permPercent=$1
40 | max=$(heapSize)
41 | permSize="$(echo "$max" | awk "{print int(\$1 * $permPercent)}")g"
42 | echo "-Xms$max -Xmx$max -XX:PermSize=$permSize -XX:MaxPermSize=$permSize"
43 | }
44 |
45 | GCLOG=/apps/tomcat/logs/gc.log
46 | CATALINA_PID=/apps/tomcat/logs/catalina.pid
47 | JRE_HOME=/apps/java
48 | JAVA_HOME=$JRE_HOME
49 | if [ "$1" == "start" ]; then
50 | JAVA_OPTS=" \
51 | -javaagent:/apps/appagent/javaagent.jar \
52 | -verbosegc \
53 | -XX:+PrintGCDetails \
54 | -XX:+PrintGCTimeStamps \
55 | -Xloggc:$GCLOG \
56 | $(javaOptsHeapSize 0.1) \
57 | -Xss8192k \
58 | -Dnetflix.logging.realtimetracers=false \
59 | -Dlog4j.appender.RTA=org.apache.log4j.varia.NullAppender \
60 | -Dlog4j.appender.CHUKWA=org.apache.log4j.varia.NullAppender \
61 | -Dlog4j.appender.CHUKWA.threshold=OFF \
62 | -Dlog4j.logger.net.spy.memcached.internal.OperationFuture=FATAL \
63 | -Dnet.spy.log.LoggerImpl=net.spy.memcached.compat.log.Log4JLogger \
64 | -Dnetflix.environment=test
65 | -Dcom.sun.management.jmxremote.ssl=false \
66 | -Dcom.sun.management.jmxremote.port=7500 \
67 | -Dcom.sun.management.jmxremote.authenticate=false \
68 | -Dnetflix.appinfo.name=${NETFLIX_APP}"
69 |
70 | logrotate -f /apps/tomcat/bin/.logrotate.conf
71 | else
72 | JAVA_OPTS=""
73 | fi
74 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/processor/DataWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.processor;
19 |
20 | import com.netflix.ice.common.AwsUtils;
21 | import com.netflix.ice.common.TagGroup;
22 | import com.netflix.ice.tag.Tag;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | import java.io.*;
27 | import java.util.Collection;
28 | import java.util.TreeMap;
29 |
30 | public class DataWriter {
31 | private final static Logger logger = LoggerFactory.getLogger(DataWriter.class);
32 |
33 |
34 | private TreeMap> tagGroups;
35 | private ProcessorConfig config = ProcessorConfig.getInstance();
36 | private String dbName;
37 | private File file;
38 | private ReadWriteData data;
39 |
40 | DataWriter(String name, boolean loadData) throws Exception {
41 |
42 | name = Tag.toS3(name);
43 | dbName = name;
44 | file = new File(config.localDir, dbName);
45 | if (loadData) {
46 | AwsUtils.downloadFileIfNotExist(config.workS3BucketName, config.workS3BucketPrefix, file);
47 | }
48 |
49 | if (file.exists()) {
50 | DataInputStream in = new DataInputStream(new FileInputStream(file));
51 | try {
52 | data = ReadWriteData.Serializer.deserialize(in);
53 | }
54 | finally {
55 | in.close();
56 | }
57 | }
58 | else {
59 | data = new ReadWriteData();
60 | }
61 | }
62 |
63 | ReadWriteData getData() {
64 | return data;
65 | }
66 |
67 | void archive() throws IOException {
68 | archive(data);
69 | }
70 |
71 | void archive(ReadWriteData data) throws IOException {
72 |
73 | DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
74 | try {
75 | ReadWriteData.Serializer.serialize(out, data);
76 | }
77 | finally {
78 | out.close();
79 | }
80 |
81 | logger.info(this.dbName + " uploading to s3...");
82 | AwsUtils.upload(config.workS3BucketName, config.workS3BucketPrefix, config.localDir, dbName);
83 | logger.info(this.dbName + " uploading done.");
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/processor/TagGroupWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.processor;
19 |
20 | import com.google.common.collect.Maps;
21 | import com.netflix.ice.common.AwsUtils;
22 | import com.netflix.ice.common.TagGroup;
23 | import com.netflix.ice.tag.Tag;
24 | import org.slf4j.Logger;
25 | import org.slf4j.LoggerFactory;
26 |
27 | import java.io.*;
28 | import java.util.Collection;
29 | import java.util.TreeMap;
30 |
31 | public class TagGroupWriter {
32 | private final static Logger logger = LoggerFactory.getLogger(TagGroupWriter.class);
33 | public final static String DB_PREFIX = "tagdb_";
34 |
35 | private TreeMap> tagGroups;
36 | private ProcessorConfig config = ProcessorConfig.getInstance();
37 | private String dbName;
38 | private File file;
39 |
40 | TagGroupWriter(String name) throws Exception {
41 |
42 | name = Tag.toS3(name);
43 | dbName = DB_PREFIX + name;
44 | file = new File(config.localDir, dbName);
45 | logger.info("creating TagGroupWriter for " + file);
46 | AwsUtils.downloadFileIfNotExist(config.workS3BucketName, config.workS3BucketPrefix, file);
47 |
48 | if (file.exists()) {
49 | DataInputStream in = new DataInputStream(new FileInputStream(file));
50 | try {
51 | tagGroups = TagGroup.Serializer.deserializeTagGroups(config, in);
52 | }
53 | finally {
54 | if (in != null)
55 | in.close();
56 | }
57 | }
58 | else {
59 | tagGroups = Maps.newTreeMap();
60 | }
61 | }
62 |
63 | void archive(Long monthMilli,Collection tagGroups) throws IOException {
64 | this.tagGroups.put(monthMilli, tagGroups);
65 |
66 | DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
67 | try {
68 | TagGroup.Serializer.serializeTagGroups(out, this.tagGroups);
69 | }
70 | finally {
71 | out.close();
72 | }
73 |
74 | logger.info(dbName + " uploading to s3...");
75 | AwsUtils.upload(config.workS3BucketName, config.workS3BucketPrefix, config.localDir, dbName);
76 | logger.info(dbName + " uploading done.");
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/common/AccountService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.common;
19 |
20 | import com.netflix.ice.tag.Account;
21 | import com.netflix.ice.tag.Zone;
22 |
23 | import java.util.List;
24 | import java.util.Map;
25 |
26 | public interface AccountService {
27 | /**
28 | * Get account by AWS id. The AWS id is usually an un-readable 12 digit string.
29 | * @param accountId
30 | * @return Account object associated with the account id
31 | */
32 | Account getAccountById(String accountId);
33 |
34 | /**
35 | * Get account by account name. The account name is a user defined readable string.
36 | * @param accountName
37 | * @return Account object associated with the account name
38 | */
39 | Account getAccountByName(String accountName);
40 |
41 | /**
42 | * Get a list of accounts from given account names.
43 | * @param accountNames
44 | * @return List of accounts
45 | */
46 | List getAccounts(List accountNames);
47 |
48 | /**
49 | * If you don't have reserved instances, you can return an empty map.
50 | * @return Map of accounts. The keys are owner accounts, the values are list of borrowing accounts.
51 | */
52 | Map> getReservationAccounts();
53 |
54 | /**
55 | * If you don't need to poll reservation capacity through ec2 API for other accounts, you can return an empty map.
56 | * @return Map of account access roles. The keys are reservation owner accounts,
57 | * the values are assumed roles to call ec2 describeReservedInstances on each reservation owner account.
58 | */
59 | Map getReservationAccessRoles();
60 |
61 | /**
62 | * If you don't need to poll reservation capacity through ec2 API for other accounts, ir if you don't use external ids,
63 | * you can return an empty map.
64 | * @return Map of account access external ids. The keys are reservation owner accounts,
65 | * the values are external ids to call ec2 describeReservedInstances on each reservation owner account.
66 | */
67 | Map getReservationAccessExternalIds();
68 |
69 | /**
70 | * @param account
71 | * @param zone
72 | * @return Whether or not external mappings are not available in specified account.
73 | */
74 | boolean externalMappingExist(Account account, Zone zone);
75 | }
76 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/processor/ReservationService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.processor;
19 |
20 | import com.amazonaws.services.ec2.model.ReservedInstances;
21 | import com.netflix.ice.common.TagGroup;
22 | import com.netflix.ice.tag.Region;
23 | import com.netflix.ice.tag.UsageType;
24 |
25 | import java.util.Collection;
26 | import java.util.Map;
27 |
28 | /**
29 | * Interface for reservations.
30 | */
31 | public interface ReservationService {
32 |
33 | void init();
34 |
35 | /**
36 | * Get all tag groups with reservations
37 | * @param utilization
38 | * @return
39 | */
40 | Collection getTagGroups(Ec2InstanceReservationPrice.ReservationUtilization utilization);
41 |
42 | /**
43 | *
44 | * @return
45 | */
46 | Ec2InstanceReservationPrice.ReservationUtilization getDefaultReservationUtilization(long time);
47 |
48 | /**
49 | * Get reservation info.
50 | * @param time
51 | * @param tagGroup
52 | * @param utilization
53 | * @return
54 | */
55 | ReservationInfo getReservation(
56 | long time,
57 | TagGroup tagGroup,
58 | Ec2InstanceReservationPrice.ReservationUtilization utilization);
59 |
60 | /**
61 | * Some companies may get different price tiers at different times depending on reservation cost.
62 | * This method is to get the latest hourly price including amortized upfront for given, time, region and usage type.
63 | * @param time
64 | * @param region
65 | * @param usageType
66 | * @param utilization
67 | * @return
68 | */
69 | double getLatestHourlyTotalPrice(
70 | long time,
71 | Region region,
72 | UsageType usageType,
73 | Ec2InstanceReservationPrice.ReservationUtilization utilization);
74 |
75 | /**
76 | * Called by ReservationCapacityPoller to update reservations.
77 | * @param reservations
78 | */
79 | void updateEc2Reservations(Map reservations);
80 |
81 |
82 | public static class ReservationInfo {
83 | public final int capacity;
84 | public final double upfrontAmortized;
85 | public final double reservationHourlyCost;
86 |
87 | public ReservationInfo (int capacity, double upfrontAmortized, double reservationHourlyCost) {
88 | this.capacity = capacity;
89 | this.upfrontAmortized = upfrontAmortized;
90 | this.reservationHourlyCost = reservationHourlyCost;
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/test/com/netflix/ice/basic/EddaResourceServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.netflix.ice.basic;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import java.util.Properties;
6 |
7 | import org.junit.Test;
8 |
9 | import org.json.JSONArray;
10 | import com.netflix.ice.tag.Product;
11 |
12 |
13 | /**
14 | * Note: These tests require a running instance of Edda running at the url configured in ice.properties, so they
15 | * strictly speaking not unit tests any more...
16 | */
17 | public class EddaResourceServiceTest {
18 |
19 | @Test
20 | public void test() throws Exception {
21 | EddaResourceService service = new EddaResourceService(new Properties());
22 |
23 | service.init();
24 |
25 | // does nothing really...
26 | service.commit();
27 |
28 | assertNotNull(service.getProductsWithResources());
29 |
30 | assertEquals("Product-name for unsupported resource", "somename", service.getResource(null, null, new Product("somename"), null, null, 0));
31 | assertEquals("Error for empty resourceId", "Error", service.getResource(null, null, Product.ec2, null, null, 0));
32 | assertEquals("Error for empty resourceId", "Error", service.getResource(null, null, Product.ec2, "", null, 0));
33 |
34 | assertEquals("Unknown for resourceIds that we do not find", "Unknown", service.getResource(null, null, Product.ec2, "someunknowninstance", null, 0));
35 |
36 | JSONArray instances = service.readInstanceArray();
37 |
38 | String resource = service.getResource(null, null, Product.ec2, instances.getString(0), null, 0);
39 | assertFalse("Not Error for an actual instance", "Error".equals(resource));
40 |
41 | resource = service.getResource(null, null, Product.ec2_instance, instances.getString(0), null, 0);
42 | assertFalse("Not Error for an actual instance", "Error".equals(resource));
43 |
44 | for(int i = 0;i < instances.length();i++) {
45 | resource = service.getResource(null, null, Product.ec2_instance, instances.getString(i), null, 0);
46 | assertFalse("Not Error for an actual instance", "Error".equals(resource));
47 | }
48 | }
49 |
50 | @Test
51 | public void testWrongURL() throws Exception {
52 | // use a normal setup for retrieving the instances
53 | EddaResourceService service = new EddaResourceService(new Properties());
54 | JSONArray instances = service.readInstanceArray();
55 |
56 | // overwrite config with an invalid hostname
57 | Properties prop = new Properties();
58 | prop.setProperty("ice.eddaresourceservice.url", "http://invalidhostname:18081/edda/api/v2/");
59 | service = new EddaResourceService(prop);
60 |
61 | // now the retrieved resources should return an error even for valid instances
62 | String resource = service.getResource(null, null, Product.ec2, instances.getString(0), null, 0);
63 | assertTrue("Error even for an actual instance when using wrong URL", "Error".equals(resource));
64 |
65 | // overwrite config with an invalid URL
66 | prop.setProperty("ice.eddaresourceservice.url", "sasie://invalidhostname:18081/edda/api/v2/");
67 | service = new EddaResourceService(prop);
68 |
69 | // now the retrieved resources should return an error even for valid instances
70 | resource = service.getResource(null, null, Product.ec2, instances.getString(0), null, 0);
71 | assertTrue("Error even for an actual instance when using wrong URL", "Error".equals(resource));
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Exit the script if an error occur
4 | set -e
5 |
6 | # Get Ice in a ready-to-run state on a fresh AWI instance.
7 |
8 | GRAILS_VERSION=2.4.4
9 |
10 | # Install prerequisites
11 | if [ -f /etc/redhat-release ]; then
12 | echo "Installing redhat packages"
13 | sudo yum -y install git java-1.7.0-openjdk-devel.x86_64 wget unzip
14 |
15 | elif [[ -f /etc/debian-release || -f /etc/debian_version ]];then
16 | echo "Installing debian packages"
17 | sudo apt-get -y install git openjdk-7-jdk wget unzip
18 |
19 | elif [[ -f /etc/issue && $(grep "Amazon Linux AMI" /etc/issue) ]]; then
20 | echo "Assuming AWS AMI, installing packages"
21 | sudo yum -y install git java-1.7.0-openjdk-devel.x86_64 wget unzip
22 |
23 | else
24 | echo "Unknown operating system. You may have to install Java 7 manually."
25 | fi
26 |
27 | INSTALL_DIR=$(pwd)
28 |
29 | cd
30 |
31 | HOME_DIR=$(pwd)
32 |
33 | # Prep grails in such a way that we only download it once
34 | if [ ! -x ".grails/wrapper/${GRAILS_VERSION}/grails-${GRAILS_VERSION}" ]; then
35 | mkdir -p .grails/wrapper/
36 | cd .grails/wrapper/
37 | # (Fetch)
38 | wget http://dist.springframework.org.s3.amazonaws.com/release/GRAILS/grails-${GRAILS_VERSION}.zip -O grails-${GRAILS_VERSION}-download.zip
39 | mkdir ${GRAILS_VERSION}
40 | cd ${GRAILS_VERSION}
41 | # ("Install")
42 | unzip ../grails-${GRAILS_VERSION}-download.zip
43 | fi
44 |
45 | GRAILS_HOME=${HOME_DIR}/.grails/wrapper/${GRAILS_VERSION}/grails-${GRAILS_VERSION}/
46 | PATH=$PATH:${HOME_DIR}/.grails/wrapper/${GRAILS_VERSION}/grails-${GRAILS_VERSION}/bin/
47 |
48 | # Get ice
49 | cd ${INSTALL_DIR}
50 |
51 | if [ -x '.git' ]; then
52 | # We already have it; update to latest git
53 | git pull
54 | else
55 | # We don't have it at all yet; clone the repo
56 | git clone https://github.com/Netflix/ice.git
57 | cd ice
58 | INSTALL_DIR=$(pwd)
59 | fi
60 |
61 | # Initialize Ice with Grails
62 | grails ${JAVA_OPTS} wrapper
63 |
64 | # (Bug: Ice can't deal with this file existing and being empty.)
65 | rm -f grails-app/i18n/messages.properties
66 |
67 | # Create our local work directories (both for processing and reading)
68 | mkdir -p ${HOME_DIR}/ice_processor
69 | mkdir -p ${HOME_DIR}/ice_reader
70 |
71 | # Set up the config file
72 | cp src/java/sample.properties src/java/ice.properties
73 | echo Please enter the name of the bucket Ice will read Amazon billing information from:
74 | while [ "$BILLBUCKET" == "" ]
75 | do
76 | echo -n "-> "
77 | read -r BILLBUCKET
78 | done
79 |
80 | echo Please enter the name of the bucket Ice will write processed billing information to:
81 | while [ "$PROCBUCKET" == "" ]
82 | do
83 | echo -n "-> "
84 | read -r PROCBUCKET
85 | done
86 | sed -ri 's/=billing_s3bucketprefix\//=/; s|\/mnt\/|'"${HOME_DIR}"'\/|; s/=work_s3bucketprefix\//=/; s/^ice.account.*//; s/=billing_s3bucketname1/='${BILLBUCKET}'/; s/=work_s3bucketname/='${PROCBUCKET}'/' src/java/ice.properties
87 |
88 | echo Ice is now ready to run as a processor. If you want to run the reader, edit:
89 | echo "${INSTALL_DIR}/src/java/ice.properties"
90 | echo and alter the appropriate flags. You can now start Ice by running the following from the Ice root directory:
91 | echo ./grailsw -Djava.net.preferIPv4Stack=true -Dice.s3AccessKeyId=\ -Dice.s3SecretKey=\ run-app
92 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/reader/ApplicationGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.reader;
19 |
20 | import com.google.common.collect.Lists;
21 | import com.google.common.collect.Maps;
22 | import org.json.JSONArray;
23 | import org.json.JSONException;
24 | import org.json.JSONObject;
25 | import org.json.JSONTokener;
26 |
27 | import java.util.Iterator;
28 | import java.util.List;
29 | import java.util.Map;
30 |
31 | public class ApplicationGroup {
32 | public final Map> data;
33 | public final String name;
34 | public final String owner;
35 |
36 | // todo: remove this constructor
37 | public ApplicationGroup(String name, String owner, List ec2s, List s3s) {
38 | this.name = name;
39 | this.owner = owner;
40 | this.data = Maps.newHashMap();
41 | this.data.put("rds", Lists.newArrayList());
42 | this.data.put("ec2", ec2s);
43 | this.data.put("s3", s3s);
44 | }
45 |
46 | public ApplicationGroup(String name, String owner, Map> data) {
47 | this.name = name;
48 | this.owner = owner;
49 | this.data = data;
50 | }
51 |
52 | public ApplicationGroup(String jsonStr) throws JSONException {
53 | data = Maps.newHashMap();
54 | JSONObject json = new JSONObject(new JSONTokener(jsonStr));
55 | name = json.getString("name");
56 | owner = json.getString("owner");
57 | json = json.getJSONObject("data");
58 | Iterator keys = json.keys();
59 | while (keys.hasNext()) {
60 | String key = keys.next();
61 | JSONArray jsonArray = json.getJSONArray(key);
62 | List values = Lists.newArrayList();
63 | for (int i = 0; i < jsonArray.length(); i++)
64 | values.add(jsonArray.getString(i));
65 | data.put(key, values);
66 | }
67 | }
68 |
69 | public JSONObject getJSON() throws JSONException {
70 | JSONObject json = new JSONObject();
71 | json.put("name", name);
72 | json.put("owner", owner);
73 | json.put("data", new JSONObject(data));
74 |
75 | return json;
76 | }
77 |
78 | @Override
79 | public String toString() {
80 | try {
81 | return getJSON().toString();
82 | }
83 | catch (Exception e) {
84 | return e.getMessage();
85 | }
86 | }
87 |
88 | public String getDisplayName() {
89 | return "Application Group " + name;
90 | }
91 |
92 | public String getLink() {
93 | return "dashboard/appgroup#appgroup=" + name;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/common/Config.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.common;
19 |
20 | import com.amazonaws.auth.AWSCredentialsProvider;
21 | import org.joda.time.DateTime;
22 | import org.joda.time.DateTimeZone;
23 |
24 | import java.util.Properties;
25 |
26 | public abstract class Config {
27 |
28 | public final String workS3BucketName;
29 | public final String workS3BucketPrefix;
30 | public final String localDir;
31 | public final AccountService accountService;
32 | public final ProductService productService;
33 | public final ResourceService resourceService;
34 | public final DateTime startDate;
35 | public final AWSCredentialsProvider credentialsProvider;
36 |
37 | /**
38 | *
39 | * @param properties (required)
40 | * @param credentialsProvider (required)
41 | * @param accountService (required)
42 | * @param productService (required)
43 | * @param resourceService (optional)
44 | */
45 | public Config(
46 | Properties properties,
47 | AWSCredentialsProvider credentialsProvider,
48 | AccountService accountService,
49 | ProductService productService,
50 | ResourceService resourceService) {
51 | if (properties.getProperty(IceOptions.START_MILLIS) == null) throw new IllegalArgumentException("IceOptions.START_MILLIS must be specified");
52 | if (properties == null) throw new IllegalArgumentException("properties must be specified");
53 | if (credentialsProvider == null) throw new IllegalArgumentException("credentialsProvider must be specified");
54 | if (accountService == null) throw new IllegalArgumentException("accountService must be specified");
55 | if (productService == null) throw new IllegalArgumentException("productService must be specified");
56 |
57 | DateTime startDate = new DateTime(Long.parseLong(properties.getProperty(IceOptions.START_MILLIS)), DateTimeZone.UTC);
58 | workS3BucketName = properties.getProperty(IceOptions.WORK_S3_BUCKET_NAME);
59 | workS3BucketPrefix = properties.getProperty(IceOptions.WORK_S3_BUCKET_PREFIX, "ice/");
60 | localDir = properties.getProperty(IceOptions.LOCAL_DIR, "/mnt/ice");
61 |
62 | if (workS3BucketName == null) throw new IllegalArgumentException("IceOptions.WORK_S3_BUCKET_NAME must be specified");
63 |
64 | this.credentialsProvider = credentialsProvider;
65 | this.startDate = startDate;
66 | this.accountService = accountService;
67 | this.productService = productService;
68 | this.resourceService = resourceService;
69 |
70 | AwsUtils.init(credentialsProvider);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/common/ResourceService.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.common;
19 |
20 | import com.netflix.ice.tag.Account;
21 | import com.netflix.ice.tag.Product;
22 | import com.netflix.ice.tag.Region;
23 |
24 | import java.util.List;
25 |
26 | /**
27 | * Please see a sample of subclass in SampleMapDbResourceService class.
28 | */
29 | public abstract class ResourceService {
30 |
31 | /**
32 | * Subclass can choose different technologies to store the mapping of resource ids and resource group names.
33 | * E.g. SampleMapDbResourceService used MapDB to maintain a mapping of instance ids and application names.
34 | * You can initialize you mapping here.
35 | * You can also get the reference to ProcessorConfig instance here.
36 | */
37 | abstract public void init();
38 |
39 | /**
40 | * Get resource group name. Subclass can maintain a mapping of resource ids and resource group names.
41 | * Users can also choose to add user-defined tags in the billing file. E.g. in SampleMapDbResourceService,
42 | * the auto-scaling-group name is used to generate the resource group name.
43 | * @param account
44 | * @param region
45 | * @param product
46 | * @param resourceId: depending on product, resourceId could be:
47 | * 1) instance id, if product is ec2_instance. You can use Edda (https://github.com/Netflix/edda) to query application name from instance id.
48 | * 2) volumn id, if product is ebs. You can use Edda (https://github.com/Netflix/edda) to query instance id from volumn id, then application name from instance id.
49 | * 3) s3 bucket name if product is s3
50 | * 4) db name if product is rds
51 | * 5) etc.
52 | * @param lineItem: the line item in the billing file. You can access your user-defined tags here.
53 | * @param millisStart
54 | * @return
55 | */
56 | public String getResource(Account account, Region region, Product product, String resourceId, String[] lineItem, long millisStart){
57 | return product.name;
58 | }
59 |
60 | /**
61 | * Get products with resources. See example in SampleMapDbResourceService. This method will be used by UI to list
62 | * products with resources.
63 | * @return List of list of products. The inner list of products share the same resource groups.
64 | * E.g. in SampleMapDbResourceService, for products (ec2, ec2_instance, ebs), the resource group names are application names.
65 | */
66 | abstract public List> getProductsWithResources();
67 |
68 | /**
69 | * Commit resource mappings. This method will be called at the end of billing file processing to commit your mappings.
70 | */
71 | abstract public void commit();
72 | }
73 |
--------------------------------------------------------------------------------
/src/java/com/netflix/ice/tag/UsageType.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright 2013 Netflix, Inc.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 | package com.netflix.ice.tag;
19 |
20 | import com.google.common.collect.Lists;
21 | import com.google.common.collect.Maps;
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 |
25 | import java.io.DataInput;
26 | import java.io.DataOutput;
27 | import java.io.IOException;
28 | import java.util.List;
29 | import java.util.concurrent.ConcurrentMap;
30 |
31 | public class UsageType extends Tag {
32 | private static final Logger logger = LoggerFactory.getLogger(Operation.class);
33 | public final String unit;
34 |
35 | private UsageType (String name, String unit) {
36 | super(name);
37 | this.unit = unit;
38 | }
39 | private static ConcurrentMap usageTypes = Maps.newConcurrentMap();
40 |
41 | public static void serialize(DataOutput out, UsageType usageType) throws IOException {
42 | out.writeUTF(usageType.name);
43 | out.writeUTF(usageType.unit);
44 | }
45 |
46 | public static UsageType deserialize(DataInput in) throws IOException {
47 | String name = in.readUTF();
48 | String unit = in.readUTF();
49 |
50 | UsageType usageType = usageTypes.get(name);
51 | if (usageType == null) {
52 | usageTypes.putIfAbsent(name, new UsageType(name, unit));
53 | usageType = usageTypes.get(name);
54 | }
55 | else if (!usageType.unit.equals(unit)) {
56 | logger.error("found different units for " + usageType + usageType.unit + " " + unit);
57 | }
58 | return usageType;
59 | }
60 |
61 | public static UsageType getUsageType(String name, Operation operation, String description) {
62 | String unit = "";
63 | if (name.contains("Bytes") || name.contains("ByteHrs") || description.contains("GB"))
64 | unit = "GB";
65 | if (operation instanceof Operation.ReservationOperation)
66 | unit = "hours";
67 |
68 | return getUsageType(name, unit);
69 | }
70 |
71 | public static UsageType getUsageType(String name, String unit) {
72 |
73 | UsageType usageType = usageTypes.get(name);
74 | if (usageType == null) {
75 | usageTypes.putIfAbsent(name, new UsageType(name, unit));
76 | usageType = usageTypes.get(name);
77 | }
78 | else if (!usageType.unit.equals(unit)) {
79 | logger.error("found different units for " + usageType + usageType.unit + " " + unit);
80 | }
81 | return usageType;
82 | }
83 |
84 | public static List getUsageTypes(List names) {
85 | List result = Lists.newArrayList();
86 | for (String name: names)
87 | result.add(usageTypes.get(name));
88 | return result;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/grails-app/views/dashboard/editappgroup.gsp:
--------------------------------------------------------------------------------
1 | <%--
2 |
3 | Copyright 2013 Netflix, Inc.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
17 | --%>
18 |
19 | <%@ page contentType="text/html;charset=UTF-8" %>
20 |
21 |
22 |
23 | Edit Application Group
24 |
25 |
26 |
27 |
28 |
{{message}}
29 |
30 |
CreateEdit Application Group {{appgroup.name}}
31 |
32 |
67 |
68 |
69 |
70 |