YARN-4733. [YARN-3368] Initial commit of new YARN web UI. (wangda)
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/137c67d6 Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/137c67d6 Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/137c67d6 Branch: refs/heads/YARN-3368 Commit: 137c67d69a7619e71dd88cfc408b558ce03d6d10 Parents: 0942954 Author: Wangda Tan <wan...@apache.org> Authored: Tue Dec 8 16:37:50 2015 -0800 Committer: Wangda Tan <wan...@apache.org> Committed: Tue May 17 13:12:37 2016 -0700 ---------------------------------------------------------------------- .../hadoop-yarn/hadoop-yarn-ui/.bowerrc | 4 + .../hadoop-yarn/hadoop-yarn-ui/.editorconfig | 34 +++ .../hadoop-yarn/hadoop-yarn-ui/.ember-cli | 11 + .../hadoop-yarn/hadoop-yarn-ui/.gitignore | 17 ++ .../hadoop-yarn/hadoop-yarn-ui/.jshintrc | 32 +++ .../hadoop-yarn/hadoop-yarn-ui/.travis.yml | 23 ++ .../hadoop-yarn/hadoop-yarn-ui/.watchmanconfig | 3 + .../hadoop-yarn/hadoop-yarn-ui/README.md | 24 ++ .../hadoop-yarn-ui/app/adapters/cluster-info.js | 19 ++ .../app/adapters/cluster-metric.js | 19 ++ .../app/adapters/yarn-app-attempt.js | 31 +++ .../hadoop-yarn-ui/app/adapters/yarn-app.js | 25 ++ .../app/adapters/yarn-container.js | 42 +++ .../hadoop-yarn-ui/app/adapters/yarn-queue.js | 19 ++ .../hadoop-yarn/hadoop-yarn-ui/app/app.js | 20 ++ .../hadoop-yarn-ui/app/components/.gitkeep | 0 .../app/components/app-attempt-table.js | 4 + .../hadoop-yarn-ui/app/components/app-table.js | 4 + .../hadoop-yarn-ui/app/components/bar-chart.js | 104 +++++++ .../app/components/base-chart-component.js | 109 ++++++++ .../app/components/container-table.js | 4 + .../app/components/donut-chart.js | 148 ++++++++++ .../app/components/item-selector.js | 21 ++ .../app/components/queue-configuration-table.js | 4 + .../app/components/queue-navigator.js | 4 + .../hadoop-yarn-ui/app/components/queue-view.js | 272 +++++++++++++++++++ .../app/components/simple-table.js | 30 ++ .../app/components/timeline-view.js | 250 +++++++++++++++++ .../app/components/tree-selector.js | 257 ++++++++++++++++++ .../hadoop-yarn-ui/app/controllers/.gitkeep | 0 .../app/controllers/cluster-overview.js | 5 + .../hadoop-yarn-ui/app/controllers/yarn-apps.js | 4 + .../app/controllers/yarn-queue.js | 6 + .../hadoop-yarn-ui/app/helpers/.gitkeep | 0 .../hadoop-yarn/hadoop-yarn-ui/app/index.html | 25 ++ .../hadoop-yarn-ui/app/models/.gitkeep | 0 .../hadoop-yarn-ui/app/models/cluster-info.js | 13 + .../hadoop-yarn-ui/app/models/cluster-metric.js | 115 ++++++++ .../app/models/yarn-app-attempt.js | 44 +++ .../hadoop-yarn-ui/app/models/yarn-app.js | 65 +++++ .../hadoop-yarn-ui/app/models/yarn-container.js | 39 +++ .../hadoop-yarn-ui/app/models/yarn-queue.js | 76 ++++++ .../hadoop-yarn-ui/app/models/yarn-user.js | 8 + .../hadoop-yarn/hadoop-yarn-ui/app/router.js | 16 ++ .../hadoop-yarn-ui/app/routes/.gitkeep | 0 .../app/routes/cluster-overview.js | 11 + .../app/routes/yarn-app-attempt.js | 21 ++ .../hadoop-yarn-ui/app/routes/yarn-app.js | 10 + .../hadoop-yarn-ui/app/routes/yarn-apps.js | 8 + .../hadoop-yarn-ui/app/routes/yarn-queue.js | 20 ++ .../app/routes/yarn-queues/index.js | 5 + .../app/routes/yarn-queues/queues-selector.js | 7 + .../app/serializers/cluster-info.js | 29 ++ .../app/serializers/cluster-metric.js | 29 ++ .../app/serializers/yarn-app-attempt.js | 49 ++++ .../hadoop-yarn-ui/app/serializers/yarn-app.js | 66 +++++ .../app/serializers/yarn-container.js | 54 ++++ .../app/serializers/yarn-queue.js | 127 +++++++++ .../hadoop-yarn-ui/app/styles/app.css | 141 ++++++++++ .../app/templates/application.hbs | 25 ++ .../app/templates/cluster-overview.hbs | 56 ++++ .../app/templates/components/.gitkeep | 0 .../templates/components/app-attempt-table.hbs | 28 ++ .../app/templates/components/app-table.hbs | 62 +++++ .../templates/components/container-table.hbs | 36 +++ .../components/queue-configuration-table.hbs | 40 +++ .../templates/components/queue-navigator.hbs | 18 ++ .../app/templates/components/timeline-view.hbs | 35 +++ .../app/templates/yarn-app-attempt.hbs | 12 + .../hadoop-yarn-ui/app/templates/yarn-app.hbs | 145 ++++++++++ .../hadoop-yarn-ui/app/templates/yarn-apps.hbs | 3 + .../hadoop-yarn-ui/app/templates/yarn-queue.hbs | 48 ++++ .../hadoop-yarn-ui/app/utils/converter.js | 74 +++++ .../hadoop-yarn-ui/app/utils/sorter.js | 15 + .../hadoop-yarn/hadoop-yarn-ui/bower.json | 22 ++ .../hadoop-yarn-ui/config/environment.js | 47 ++++ .../hadoop-yarn-ui/ember-cli-build.js | 29 ++ .../hadoop-yarn/hadoop-yarn-ui/jsconfig.json | 6 + .../hadoop-yarn/hadoop-yarn-ui/package.json | 44 +++ .../assets/images/datatables/Sorting icons.psd | Bin 0 -> 27490 bytes .../public/assets/images/datatables/favicon.ico | Bin 0 -> 894 bytes .../assets/images/datatables/sort_asc.png | Bin 0 -> 160 bytes .../images/datatables/sort_asc_disabled.png | Bin 0 -> 148 bytes .../assets/images/datatables/sort_both.png | Bin 0 -> 201 bytes .../assets/images/datatables/sort_desc.png | Bin 0 -> 158 bytes .../images/datatables/sort_desc_disabled.png | Bin 0 -> 146 bytes .../hadoop-yarn-ui/public/crossdomain.xml | 15 + .../hadoop-yarn-ui/public/robots.txt | 3 + .../hadoop-yarn/hadoop-yarn-ui/testem.json | 12 + .../hadoop-yarn/hadoop-yarn-ui/tests/.jshintrc | 52 ++++ .../hadoop-yarn-ui/tests/helpers/resolver.js | 11 + .../hadoop-yarn-ui/tests/helpers/start-app.js | 18 ++ .../hadoop-yarn/hadoop-yarn-ui/tests/index.html | 33 +++ .../hadoop-yarn-ui/tests/test-helper.js | 6 + .../hadoop-yarn-ui/tests/unit/.gitkeep | 0 .../tests/unit/adapters/yarn-app-test.js | 12 + .../tests/unit/controllers/yarn-apps-test.js | 12 + .../tests/unit/controllers/yarn-queues-test.js | 12 + .../tests/unit/mixins/charts-test.js | 12 + .../tests/unit/models/yarn-app-test.js | 12 + .../tests/unit/routes/yarn-apps-test.js | 11 + .../tests/unit/serializers/yarn-app-test.js | 15 + .../tests/unit/utils/converter-test.js | 10 + .../hadoop-yarn/hadoop-yarn-ui/vendor/.gitkeep | 0 104 files changed, 3518 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.bowerrc ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.bowerrc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.bowerrc new file mode 100644 index 0000000..959e169 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.bowerrc @@ -0,0 +1,4 @@ +{ + "directory": "bower_components", + "analytics": false +} http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.editorconfig ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.editorconfig b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.editorconfig new file mode 100644 index 0000000..47c5438 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.editorconfig @@ -0,0 +1,34 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.hbs] +insert_final_newline = false +indent_style = space +indent_size = 2 + +[*.css] +indent_style = space +indent_size = 2 + +[*.html] +indent_style = space +indent_size = 2 + +[*.{diff,md}] +trim_trailing_whitespace = false http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.ember-cli ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.ember-cli b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.ember-cli new file mode 100644 index 0000000..96bd287 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.ember-cli @@ -0,0 +1,11 @@ +{ + /** + Ember CLI sends analytics information by default. The data is completely + anonymous, but there are times when you might want to disable this behavior. + + Setting `disableAnalytics` to true will prevent any data from being sent. + */ + "disableAnalytics": false, + "liveReload": true, + "watcher": "polling" +} http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.gitignore ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.gitignore b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.gitignore new file mode 100644 index 0000000..86fceae --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.gitignore @@ -0,0 +1,17 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp + +# dependencies +/node_modules +/bower_components + +# misc +/.sass-cache +/connect.lock +/coverage/* +/libpeerconnection.log +npm-debug.log +testem.log http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.jshintrc ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.jshintrc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.jshintrc new file mode 100644 index 0000000..08096ef --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.jshintrc @@ -0,0 +1,32 @@ +{ + "predef": [ + "document", + "window", + "-Promise" + ], + "browser": true, + "boss": true, + "curly": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true, + "unused": true +} http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.travis.yml ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.travis.yml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.travis.yml new file mode 100644 index 0000000..66dd107 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.travis.yml @@ -0,0 +1,23 @@ +--- +language: node_js +node_js: + - "0.12" + +sudo: false + +cache: + directories: + - node_modules + +before_install: + - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH + - "npm config set spin false" + - "npm install -g npm@^2" + +install: + - npm install -g bower + - npm install + - bower install + +script: + - npm test http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.watchmanconfig ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.watchmanconfig b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.watchmanconfig new file mode 100644 index 0000000..5e9462c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/.watchmanconfig @@ -0,0 +1,3 @@ +{ + "ignore_dirs": ["tmp"] +} http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/README.md ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/README.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/README.md new file mode 100644 index 0000000..d5cba6e --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/README.md @@ -0,0 +1,24 @@ +# Yarn-ui +*This is a WIP project, nobody should use it in production.* + +## Prerequisites + +You will need the following things properly installed on your computer. + +* Install Node.js with NPM: https://nodejs.org/download/ +* After Node.js installed, install bower: `npm install -g bower`. +* Install Ember-cli: `npm install -g ember-cli` + +## Installation + +* Goto root directory of yarn-ui project: `hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui` +* `npm install && bower install`, it will take a while to finish. + +## Try it + +* Packaging and deploying Hadoop in this branch (You can use latest trunk after YARN-4417 committed to trunk) +* Modify `app/adapters/yarn-app.js`, change `host` to your YARN RM web address +* If you running YARN RM in your localhost, you should install `npm install -g corsproxy` and run `corsproxy` to avoid CORS errors. More details: `https://www.npmjs.com/package/corsproxy`. And the `host` of `app/adapters/yarn-app.js` should start with `localhost:1337`. +* Run `ember server` +* Visit your app at [http://localhost:4200](http://localhost:4200). + http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-info.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-info.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-info.js new file mode 100644 index 0000000..ef65792 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-info.js @@ -0,0 +1,19 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + headers: { + Accept: 'application/json' + }, + host: 'http://localhost:1337/localhost:8088', // configurable + namespace: 'ws/v1/cluster', // common const + pathForType(modelName) { + return ''; // move to some common place, return path by modelname. + }, + ajax(url, method, hash) { + hash = hash || {}; + hash.crossDomain = true; + hash.xhrFields = {withCredentials: true}; + hash.targetServer = "RM"; + return this._super(url, method, hash); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-metric.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-metric.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-metric.js new file mode 100644 index 0000000..d0f084c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/cluster-metric.js @@ -0,0 +1,19 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + headers: { + Accept: 'application/json' + }, + host: 'http://localhost:1337/localhost:8088', // configurable + namespace: 'ws/v1/cluster/metrics', // common const + pathForType(modelName) { + return ''; // move to some common place, return path by modelname. + }, + ajax(url, method, hash) { + hash = hash || {}; + hash.crossDomain = true; + hash.xhrFields = {withCredentials: true}; + hash.targetServer = "RM"; + return this._super(url, method, hash); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app-attempt.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app-attempt.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app-attempt.js new file mode 100644 index 0000000..3c95d64 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app-attempt.js @@ -0,0 +1,31 @@ +import DS from 'ember-data'; +import Converter from 'yarn-ui/utils/converter'; + +export default DS.JSONAPIAdapter.extend({ + headers: { + Accept: 'application/json' + }, + host: 'http://localhost:1337/localhost:8088', // configurable + namespace: 'ws/v1/cluster', // common const + + urlForQuery(query, modelName) { + var url = this._buildURL(); + return url + '/apps/' + query.appId + "/appattempts"; + }, + + urlForFindRecord(id, modelName, snapshot) { + var url = this._buildURL(); + var url = url + '/apps/' + + Converter.attemptIdToAppId(id) + "/appattempts/" + id; + console.log(url); + return url; + }, + + ajax(url, method, hash) { + hash = {}; + hash.crossDomain = true; + hash.xhrFields = {withCredentials: true}; + hash.targetServer = "RM"; + return this._super(url, method, hash); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app.js new file mode 100644 index 0000000..e1108be --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-app.js @@ -0,0 +1,25 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + headers: { + Accept: 'application/json' + }, + host: 'http://localhost:1337/localhost:8088', // configurable + namespace: 'ws/v1/cluster', // common const + pathForType(modelName) { + return 'apps'; // move to some common place, return path by modelname. + }, + /* + urlForQuery(query, modelName) { + var url = this._buildURL(); + return url + '/apps/' + query.appId + "/appattempts"; + }, + */ + ajax(url, method, hash) { + hash = hash || {}; + hash.crossDomain = true; + hash.xhrFields = {withCredentials: true}; + hash.targetServer = "RM"; + return this._super(url, method, hash); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-container.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-container.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-container.js new file mode 100644 index 0000000..fe09f59 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-container.js @@ -0,0 +1,42 @@ +import DS from 'ember-data'; +import Converter from 'yarn-ui/utils/converter'; + +export default DS.JSONAPIAdapter.extend({ + headers: { + Accept: 'application/json' + }, + rmHost: 'http://localhost:1337/localhost:8088', + tsHost: 'http://localhost:1337/localhost:8188', + host: function() { + return undefined + }.property(), + rmNamespace: 'ws/v1/cluster', + tsNamespace: 'ws/v1/applicationhistory', + namespace: function() { + return undefined + }.property(), + + urlForQuery(query, modelName) { + if (query.is_rm) { + this.set("host", this.rmHost); + this.set("namespace", this.rmNamespace); + } else { + this.set("host", this.tsHost); + this.set("namespace", this.tsNamespace); + } + + var url = this._buildURL(); + url = url + '/apps/' + Converter.attemptIdToAppId(query.app_attempt_id) + + "/appattempts/" + query.app_attempt_id + "/containers"; + console.log(url); + return url; + }, + + ajax(url, method, hash) { + hash = {}; + hash.crossDomain = true; + hash.xhrFields = {withCredentials: true}; + hash.targetServer = "RM"; + return this._super(url, method, hash); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-queue.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-queue.js new file mode 100644 index 0000000..39cf796 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/adapters/yarn-queue.js @@ -0,0 +1,19 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + headers: { + Accept: 'application/json' + }, + host: 'http://localhost:1337/localhost:8088', // configurable + namespace: 'ws/v1/cluster', // common const + pathForType(modelName) { + return 'scheduler'; // move to some common place, return path by modelname. + }, + ajax(url, method, hash) { + hash = hash || {}; + hash.crossDomain = true; + hash.xhrFields = {withCredentials: true}; + hash.targetServer = "RM"; + return this._super(url, method, hash); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/app.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/app.js new file mode 100644 index 0000000..ff28ecf --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/app.js @@ -0,0 +1,20 @@ +import Ember from 'ember'; +import Resolver from 'ember/resolver'; +import loadInitializers from 'ember/load-initializers'; +import config from './config/environment'; +import Sorter from 'yarn-ui/utils/sorter'; + +var App; + +Ember.MODEL_FACTORY_INJECTIONS = true; + +App = Ember.Application.extend({ + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, + Resolver: Resolver +}); + +loadInitializers(App, config.modulePrefix); +Sorter.initDataTableSorter(); + +export default App; http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/.gitkeep ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/.gitkeep b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-attempt-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-attempt-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-attempt-table.js new file mode 100644 index 0000000..aff0493 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-attempt-table.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-table.js new file mode 100644 index 0000000..aff0493 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/app-table.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/bar-chart.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/bar-chart.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/bar-chart.js new file mode 100644 index 0000000..f24e947 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/bar-chart.js @@ -0,0 +1,104 @@ +import Ember from 'ember'; +import BaseChartComponent from 'yarn-ui/components/base-chart-component'; + +export default BaseChartComponent.extend({ + // data: + // [{label=label1, value=value1}, ...] + // ... + renderBarChart: function(data, title, textWidth = 50) { + var g = this.chart.g; + var layout = this.getLayout(); + this.renderTitleAndBG(g, title, layout); + + var maxValue = -1; + for (var i = 0; i < data.length; i++) { + if (data[i] instanceof Array) { + if (data[i][0].value > maxValue) { + maxValue = data[i][0].value; + } + } else { + if (data[i].value > maxValue) { + maxValue = data[i].value; + } + } + } + + var singleBarHeight = 30; + + // 50 is for text + var maxBarWidth = layout.x2 - layout.x1 - 2 * layout.margin - textWidth - 50; + + // 30 is for title + var maxBarsHeight = layout.y2 - layout.y1 - 2 * layout.margin - 30; + var gap = (maxBarsHeight - data.length * singleBarHeight) / (data.length - + 1); + + var xScaler = d3.scale.linear() + .domain([0, maxValue]) + .range([0, maxBarWidth]); + + // show bar text + for (var i = 0; i < data.length; i++) { + g.append("text") + .text( + function() { + return data[i].label; + }) + .attr("y", function() { + return layout.y1 + singleBarHeight / 2 + layout.margin + (gap + + singleBarHeight) * i + 30; + }) + .attr("x", layout.x1 + layout.margin); + } + + // show bar + var bar = g.selectAll("bars") + .data(data) + .enter() + .append("rect") + .attr("y", function(d, i) { + return layout.y1 + 30 + layout.margin + (gap + singleBarHeight) * i; + }) + .attr("x", layout.x1 + layout.margin + textWidth) + .attr("height", singleBarHeight) + .attr("fill", function(d, i) { + return this.colors[i]; + }.bind(this)) + .attr("width", 0); + + this.bindTooltip(bar); + + bar.transition() + .duration(500) + .attr("width", function(d) { + var w; + w = xScaler(d.value); + // At least each item has 3 px + w = Math.max(w, 3); + return w; + }); + + // show bar value + for (var i = 0; i < data.length; i++) { + g.append("text") + .text( + function() { + return data[i].value; + }) + .attr("y", function() { + return layout.y1 + singleBarHeight / 2 + layout.margin + (gap + + singleBarHeight) * i + 30; + }) + .attr("x", layout.x1 + layout.margin + textWidth + 15 + xScaler(data[i].value)); + } + }, + + draw: function() { + this.initChart(); + this.renderBarChart(this.get("data"), this.get("title"), this.get("textWidth")); + }, + + didInsertElement: function() { + this.draw(); + }, +}) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/base-chart-component.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/base-chart-component.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/base-chart-component.js new file mode 100644 index 0000000..acf2b5f --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/base-chart-component.js @@ -0,0 +1,109 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + chart: undefined, + tooltip : undefined, + colors: d3.scale.category10().range(), + + initChart: function() { + this.chart = { + svg: undefined, + g: undefined, + h: 0, + w: 0, + tooltip: undefined + }; + + // Init tooltip if it is not initialized + this.tooltip = d3.select("#chart-tooltip"); + if (!this.tooltip) { + this.tooltip = d3.select("body") + .append("div") + .attr("class", "tooltip") + .attr("id", "chart-tooltip") + .style("opacity", 0); + } + + // Init svg + var svg = this.chart.svg; + if (svg) { + svg.remove(); + } + + var parentId = this.get("parentId"); + var parent = d3.select("#" + parentId); + var bbox = parent.node().getBoundingClientRect(); + this.chart.w = bbox.width - 30; + + var ratio = 0.75; // 4:3 by default + if (this.get("ratio")) { + ratio = this.get("ratio"); + } + this.chart.h = bbox.width * ratio; + + if (this.get("maxHeight")) { + this.chart.h = Math.min(this.get("maxHeight"), this.chart.h); + } + + this.chart.svg = parent.append("svg") + .attr("width", this.chart.w) + .attr("height", this.chart.h); + + this.chart.g = this.chart.svg.append("g"); + }, + + renderTitleAndBG: function(g, title, layout) { + var bg = g.append("g"); + bg.append("text") + .text(title) + .attr("x", (layout.x1 + layout.x2) / 2) + .attr("y", layout.y1 + layout.margin + 20) + .attr("class", "chart-title"); + + bg.append("rect") + .attr("x", layout.x1) + .attr("y", layout.y1) + .attr("width", layout.x2 - layout.x1) + .attr("height", layout.y2 - layout.y1) + .attr("class", "chart-frame"); + }, + + bindTooltip: function(d) { + d.on("mouseover", function(d) { + this.tooltip + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 28) + "px"); + }.bind(this)) + .on("mousemove", function(d) { + // Handle pie chart case + var data = d; + if (d.data) { + data = d.data; + } + + this.tooltip.style("opacity", .9); + this.tooltip.html(data.label + " = " + data.value) + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 28) + "px"); + }.bind(this)) + .on("mouseout", function(d) { + this.tooltip.style("opacity", 0); + }.bind(this)); + }, + + getLayout: function() { + var x1 = 0; + var y1 = 0; + var x2 = this.chart.w; + var y2 = this.chart.h; + + var layout = { + x1: x1, + y1: y1, + x2: x2 - 10, + y2: y2 - 10, + margin: 10 + }; + return layout; + }, +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/container-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/container-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/container-table.js new file mode 100644 index 0000000..aff0493 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/container-table.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/donut-chart.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/donut-chart.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/donut-chart.js new file mode 100644 index 0000000..608b0c1 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/donut-chart.js @@ -0,0 +1,148 @@ +import Ember from 'ember'; +import BaseChartComponent from 'yarn-ui/components/base-chart-component'; + +export default BaseChartComponent.extend({ + /* + * data = [{label="xx", value=},{...}] + */ + renderDonutChart: function(data, title, showLabels = false, + middleLabel = "Total", middleValue = undefined) { + var g = this.chart.g; + var layout = this.getLayout(); + this.renderTitleAndBG(g, title, layout); + + var total = 0; + var allZero = true; + for (var i = 0; i < data.length; i++) { + total += data[i].value; + if (data[i].value > 1e-6) { + allZero = false; + } + } + + if (!middleValue) { + middleValue = total; + } + + //Width and height + var h = layout.y2 - layout.y1; + + // 50 is for title + var outerRadius = (h - 50 - 2 * layout.margin) / 2; + var innerRadius = outerRadius * 0.618; + var arc = d3.svg.arc() + .innerRadius(innerRadius) + .outerRadius(outerRadius); + + var cx; + var cy = layout.y1 + 50 + layout.margin + outerRadius; + if (showLabels) { + cx = layout.x1 + layout.margin + outerRadius; + } else { + cx = (layout.x1 + layout.x2) / 2; + } + + var pie = d3.layout.pie(); + pie.sort(null); + pie.value(function(d) { + var v = d.value; + // make sure it > 0 + v = Math.max(v, 1e-6); + return v; + }); + + //Set up groups + var arcs = g + .selectAll("g.arc") + .data(pie(data)) + .enter() + .append("g") + .attr("class", "arc") + .attr("transform", "translate(" + cx + "," + cy + ")"); + + function tweenPie(finish) { + var start = { + startAngle: 0, + endAngle: 0 + }; + var i = d3.interpolate(start, finish); + return function(d) { + return arc(i(d)); + }; + } + + //Draw arc paths + var path = arcs.append("path") + .attr("fill", function(d, i) { + if (d.value > 1e-6) { + return this.colors[i]; + } else { + return "white"; + } + }.bind(this)) + .attr("d", arc) + .attr("stroke", function(d, i) { + if (allZero) { + return this.colors[i]; + } + }.bind(this)) + .attr("stroke-dasharray", function(d, i) { + if (d.value <= 1e-6) { + return "10,10"; + } + }.bind(this)); + this.bindTooltip(path); + + // Show labels + if (showLabels) { + var lx = layout.x1 + layout.margin + outerRadius * 2 + 30; + var squareW = 15; + var margin = 10; + + var select = g.selectAll(".rect") + .data(data) + .enter(); + select.append("rect") + .attr("fill", function(d, i) { + return this.colors[i]; + }.bind(this)) + .attr("x", lx) + .attr("y", function(d, i) { + return layout.y1 + 50 + (squareW + margin) * i + layout.margin; + }) + .attr("width", squareW) + .attr("height", squareW); + select.append("text") + .attr("x", lx + squareW + margin) + .attr("y", function(d, i) { + return layout.y1 + 50 + (squareW + margin) * i + layout.margin + squareW / 2; + }) + .text(function(d) { + return d.label + ' = ' + d.value; + }); + } + + if (middleLabel) { + var highLightColor = this.colors[0]; + g.append("text").text(middleLabel).attr("x", cx).attr("y", cy - 10). + attr("class", "donut-highlight-text").attr("fill", highLightColor); + g.append("text").text(middleValue).attr("x", cx).attr("y", cy + 20). + attr("class", "donut-highlight-text").attr("fill", highLightColor). + style("font-size", "30px"); + } + + path.transition() + .duration(500) + .attrTween('d', tweenPie); + }, + + draw: function() { + this.initChart(); + this.renderDonutChart(this.get("data"), this.get("title"), this.get("showLabels"), + this.get("middleLabel"), this.get("middleValue")); + }, + + didInsertElement: function() { + this.draw(); + }, +}) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/item-selector.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/item-selector.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/item-selector.js new file mode 100644 index 0000000..a18ccae --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/item-selector.js @@ -0,0 +1,21 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + didInsertElement: function() { + $(".js-example-basic-single").select2( + { + width: '100%', + placeholder: "Select a queue" + }); + var elementId = this.get("element-id"); + var prefix = this.get("prefix"); + + var element = d3.select("#" + elementId); + + if (element) { + this.get("model").forEach(function(o) { + element.append("option").attr("value", o.get("name")).text(prefix + o.get("name")); + }); + } + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-configuration-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-configuration-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-configuration-table.js new file mode 100644 index 0000000..aff0493 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-configuration-table.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-navigator.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-navigator.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-navigator.js new file mode 100644 index 0000000..aff0493 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-navigator.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-view.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-view.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-view.js new file mode 100644 index 0000000..c1fd8ff --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/queue-view.js @@ -0,0 +1,272 @@ +import Ember from 'ember'; +import ChartUtilsMixin from 'yarn-ui/mixins/charts-utils'; + +export default Ember.Component.extend(ChartUtilsMixin, { + queues: { + data: undefined, + foldedQueues: {}, + selectedQueueCircle: undefined, + maxDepth: -1, + }, + + queueColors: d3.scale.category20().range(), + + renderQueue: function(now, depth, sequence) { + if (depth > this.queues.maxDepth) { + this.queues.maxDepth = depth; + } + + var cx = 20 + depth * 30; + var cy = 20 + sequence * 30; + var name = now.get("name"); + + var g = this.queues.dataGroup.append("g") + .attr("id", "queue-" + name + "-g"); + + var folded = this.queues.foldedQueues[name]; + var isParentQueue = false; + + // render its children + var children = []; + var childrenNames = now.get("children"); + if (childrenNames) { + childrenNames.forEach(function(name) { + isParentQueue = true; + var child = this.queues.data[name]; + if (child) { + children.push(child); + } + }.bind(this)); + } + if (folded) { + children = []; + } + var linefunction = d3.svg.line() + .interpolate("basis") + .x(function(d) { + return d.x; + }) + .y(function(d) { + return d.y; + }); + + for (var i = 0; i < children.length; i++) { + sequence = sequence + 1; + // Get center of children queue + var cc = this.renderQueue(children[i], + depth + 1, sequence); + g.append("path") + .attr("class", "queue") + .attr("d", linefunction([{ + x: cx, + y: cy + }, { + x: cc.x - 20, + y: cc.y + }, cc])); + } + + var circle = g.append("circle") + .attr("cx", cx) + .attr("cy", cy) + .attr("class", "queue"); + + circle.on('mouseover', function() { + circle.style("fill", this.queueColors[1]); + }.bind(this)); + circle.on('mouseout', function() { + if (circle != this.queues.selectedQueueCircle) { + circle.style("fill", this.queueColors[0]); + } + }.bind(this)); + circle.on('click', function() { + circle.style("fill", this.queueColors[2]); + var pre = this.queues.selectedQueueCircle; + this.queues.selectedQueueCircle = circle; + if (pre) { + pre.on('mouseout')(); + } + this.renderCharts(name); + }.bind(this)); + circle.on('dblclick', function() { + if (!isParentQueue) { + return; + } + + if (this.queues.foldedQueues[name]) { + delete this.queues.foldedQueues[name]; + } else { + this.queues.foldedQueues[name] = now; + } + this.renderQueues(); + }.bind(this)); + + var text = name; + if (folded) { + text = name + " (+)"; + } + + // print queue's name + g.append("text") + .attr("x", cx + 30) + .attr("y", cy + 5) + .text(text) + .attr("class", "queue"); + + return { + x: cx, + y: cy + }; + }, + + renderQueues: function() { + if (this.queues.dataGroup) { + this.queues.dataGroup.remove(); + } + // render queues + this.queues.dataGroup = this.canvas.svg.append("g") + .attr("id", "queues-g"); + var rootQueue = undefined; + + if (this.queues.data) { + this.renderQueue(this.queues.data['root'], 0, 0); + + } + }, + + draw: function() { + this.queues.data = {}; + this.get("model") + .forEach(function(o) { + this.queues.data[o.id] = o; + }.bind(this)); + + // get w/h of the svg + var bbox = d3.select("#main-container") + .node() + .getBoundingClientRect(); + this.canvas.w = bbox.width; + this.canvas.h = Math.max(Object.keys(this.queues.data) + .length * 35, 1500); + + this.canvas.svg = d3.select("#main-container") + .append("svg") + .attr("width", this.canvas.w) + .attr("height", this.canvas.h) + .attr("id", "main-svg"); + + this.renderBackground(); + + this.renderQueues(); + this.renderCharts("root"); + }, + + didInsertElement: function() { + this.draw(); + }, + + /* + * data = [{label="xx", value=},{...}] + */ + renderTable: function(data, title, layout) { + d3.select("#main-svg") + .append('table') + .selectAll('tr') + .data(data) + .enter() + .append('tr') + .selectAll('td') + .data(function(d) { + return d; + }) + .enter() + .append('td') + .text(function(d) { + return d; + }); + }, + + renderQueueCapacities: function(queue, layout) { + // Render bar chart + this.renderBarChart(this.charts.g, [{ + label: "Cap", + value: queue.get("capacity") + }, { + label: "MaxCap", + value: queue.get("maxCapacity") + }, { + label: "UsedCap", + value: queue.get("usedCapacity") + }], "Queue Capacities", layout, 60); + }, + + renderChildrenCapacities: function(queue, layout) { + var data = []; + var children = queue.get("children"); + if (children) { + for (var i = 0; i < children.length; i++) { + var child = this.queues.data[children[i]]; + data.push({ + label: child.get("name"), + value: child.get("capacity") + }); + } + } + + this.renderDonutChart(this.charts.g, data, "Children Capacities", layout, true); + }, + + renderChildrenUsedCapacities: function(queue, layout) { + var data = []; + var children = queue.get("children"); + if (children) { + for (var i = 0; i < children.length; i++) { + var child = this.queues.data[children[i]]; + data.push({ + label: child.get("name"), + value: child.get("usedCapacity") + }); + } + } + + this.renderDonutChart(this.charts.g, data, "Children Used Capacities", layout, true); + }, + + renderLeafQueueUsedCapacities: function(layout) { + var leafQueueUsedCaps = []; + for (var queueName in this.queues.data) { + var q = this.queues.data[queueName]; + if ((!q.get("children")) || q.get("children") + .length == 0) { + // it's a leafqueue + leafQueueUsedCaps.push({ + label: q.get("name"), + value: q.get("usedCapacity") + }); + } + } + + this.renderDonutChart(this.charts.g, leafQueueUsedCaps, "LeafQueues Used Capacities", + layout, true); + }, + + renderCharts: function(queueName) { + this.charts.leftBannerLen = this.queues.maxDepth * 30 + 100; + this.initCharts(); + + var queue = this.queues.data[queueName]; + var idx = 0; + + if (queue.get("name") == "root") { + this.renderLeafQueueUsedCapacities(this.getLayout(idx++)); + } + if (queue.get("name") != "root") { + this.renderQueueCapacities(queue, this.getLayout(idx++)); + } + if (queue.get("children") && queue.get("children") + .length > 0) { + this.renderChildrenCapacities(queue, this.getLayout(idx++)); + this.renderChildrenUsedCapacities(queue, this.getLayout(idx++)); + } + }, +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/simple-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/simple-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/simple-table.js new file mode 100644 index 0000000..ed8ff9b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/simple-table.js @@ -0,0 +1,30 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + didInsertElement: function() { + var paging = this.get("paging") ? true : this.get("paging"); + var ordering = this.get("ordering") ? true : this.get("ordering"); + var info = this.get("info") ? true : this.get("info"); + var bFilter = this.get("bFilter") ? true : this.get("bFilter"); + + var colDefs = []; + if (this.get("colTypes")) { + var typesArr = this.get("colTypes").split(' '); + var targetsArr = this.get("colTargets").split(' '); + for (var i = 0; i < typesArr.length; i++) { + colDefs.push({ + type: typesArr[i], + targets: parseInt(targetsArr[i]) + }); + } + } + + $('#' + this.get('table-id')).DataTable({ + "paging": paging, + "ordering": ordering, + "info": info, + "bFilter": bFilter, + columnDefs: colDefs + }); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/timeline-view.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/timeline-view.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/timeline-view.js new file mode 100644 index 0000000..fe402bb --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/timeline-view.js @@ -0,0 +1,250 @@ +import Ember from 'ember'; +import Converter from 'yarn-ui/utils/converter'; + +export default Ember.Component.extend({ + canvas: { + svg: undefined, + h: 0, + w: 0, + tooltip: undefined + }, + + clusterMetrics: undefined, + modelArr: [], + colors: d3.scale.category10().range(), + _selected: undefined, + + selected: function() { + return this._selected; + }.property(), + + tableComponentName: function() { + return "app-attempt-table"; + }.property(), + + setSelected: function(d) { + if (this._selected == d) { + return; + } + + // restore color + if (this._selected) { + var dom = d3.select("#timeline-bar-" + this._selected.get("id")); + dom.attr("fill", this.colors[0]); + } + + this._selected = d; + this.set("selected", d); + dom = d3.select("#timeline-bar-" + d.get("id")); + dom.attr("fill", this.colors[1]); + }, + + getPerItemHeight: function() { + var arrSize = this.modelArr.length; + + if (arrSize < 20) { + return 30; + } else if (arrSize < 100) { + return 10; + } else { + return 2; + } + }, + + getPerItemGap: function() { + var arrSize = this.modelArr.length; + + if (arrSize < 20) { + return 5; + } else if (arrSize < 100) { + return 1; + } else { + return 1; + } + }, + + getCanvasHeight: function() { + return (this.getPerItemHeight() + this.getPerItemGap()) * this.modelArr.length + 200; + }, + + draw: function(start, end) { + // get w/h of the svg + var bbox = d3.select("#" + this.get("parent-id")) + .node() + .getBoundingClientRect(); + this.canvas.w = bbox.width; + this.canvas.h = this.getCanvasHeight(); + + this.canvas.svg = d3.select("#" + this.get("parent-id")) + .append("svg") + .attr("width", this.canvas.w) + .attr("height", this.canvas.h) + .attr("id", this.get("my-id")); + this.renderTimeline(start, end); + }, + + renderTimeline: function(start, end) { + var border = 30; + var singleBarHeight = this.getPerItemHeight(); + var gap = this.getPerItemGap(); + var textWidth = 50; + /* + start-time end-time + |--------------------------------------| + ============== + ============== + ============== + =============== + */ + var xScaler = d3.scale.linear() + .domain([start, end]) + .range([0, this.canvas.w - 2 * border - textWidth]); + + /* + * Render frame of timeline view + */ + this.canvas.svg.append("line") + .attr("x1", border + textWidth) + .attr("y1", border - 5) + .attr("x2", this.canvas.w - border) + .attr("y2", border - 5) + .attr("class", "chart"); + + this.canvas.svg.append("line") + .attr("x1", border + textWidth) + .attr("y1", border - 10) + .attr("x2", border + textWidth) + .attr("y2", border - 5) + .attr("class", "chart"); + + this.canvas.svg.append("line") + .attr("x1", this.canvas.w - border) + .attr("y1", border - 10) + .attr("x2", this.canvas.w - border) + .attr("y2", border - 5) + .attr("class", "chart"); + + this.canvas.svg.append("text") + .text(Converter.timeStampToDate(start)) + .attr("y", border - 15) + .attr("x", border + textWidth) + .attr("class", "bar-chart-text") + .attr("text-anchor", "left"); + + this.canvas.svg.append("text") + .text(Converter.timeStampToDate(end)) + .attr("y", border - 15) + .attr("x", this.canvas.w - border) + .attr("class", "bar-chart-text") + .attr("text-anchor", "end"); + + // show bar + var bar = this.canvas.svg.selectAll("bars") + .data(this.modelArr) + .enter() + .append("rect") + .attr("y", function(d, i) { + return border + (gap + singleBarHeight) * i; + }) + .attr("x", function(d, i) { + return border + textWidth + xScaler(d.get("startTs")); + }) + .attr("height", singleBarHeight) + .attr("fill", function(d, i) { + return this.colors[0]; + }.bind(this)) + .attr("width", function(d, i) { + var finishedTs = xScaler(d.get("finishedTs")); + finishedTs = finishedTs > 0 ? finishedTs : xScaler(end); + return finishedTs - xScaler(d.get("startTs")); + }) + .attr("id", function(d, i) { + return "timeline-bar-" + d.get("id"); + }); + bar.on("click", function(d) { + this.setSelected(d); + }.bind(this)); + + this.bindTooltip(bar); + + if (this.modelArr.length <= 20) { + // show bar texts + for (var i = 0; i < this.modelArr.length; i++) { + this.canvas.svg.append("text") + .text(this.modelArr[i].get(this.get("label"))) + .attr("y", border + (gap + singleBarHeight) * i + singleBarHeight / 2) + .attr("x", border) + .attr("class", "bar-chart-text"); + } + } + }, + + bindTooltip: function(d) { + d.on("mouseover", function(d) { + this.tooltip + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 28) + "px"); + }.bind(this)) + .on("mousemove", function(d) { + this.tooltip.style("opacity", .9); + this.tooltip.html(d.get("tooltipLabel")) + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 28) + "px"); + }.bind(this)) + .on("mouseout", function(d) { + this.tooltip.style("opacity", 0); + }.bind(this)); + }, + + initTooltip: function() { + this.tooltip = d3.select("body") + .append("div") + .attr("class", "tooltip") + .attr("id", "chart-tooltip") + .style("opacity", 0); + }, + + didInsertElement: function() { + // init tooltip + this.initTooltip(); + + // init model + if (this.get("rmModel")) { + this.get("rmModel").forEach(function(o) { + this.modelArr.push(o); + }.bind(this)); + } + + if (this.get("tsModel")) { + this.get("tsModel").forEach(function(o) { + this.modelArr.push(o); + }.bind(this)); + } + + this.modelArr.sort(function(a, b) { + var tsA = a.get("startTs"); + var tsB = b.get("startTs"); + + return tsA - tsB; + }); + if (this.modelArr.length > 0) { + var begin = this.modelArr[0].get("startTs"); + } + var end = 0; + for (var i = 0; i < this.modelArr.length; i++) { + var ts = this.modelArr[i].get("finishedTs"); + if (ts > end) { + end = ts; + } + } + if (end < begin) { + end = Date.now(); + } + + this.draw(begin, end); + + if (this.modelArr.length > 0) { + this.setSelected(this.modelArr[0]); + } + }, +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/tree-selector.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/tree-selector.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/tree-selector.js new file mode 100644 index 0000000..470deaf --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/tree-selector.js @@ -0,0 +1,257 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + // Map: <queue-name, queue> + map : undefined, + + // Normalized data for d3 + treeData: undefined, + + // folded queues, folded[<queue-name>] == true means <queue-name> is folded + foldedQueues: { }, + + // maxDepth + maxDepth: 0, + + // num of leaf queue, folded queue is treated as leaf queue + numOfLeafQueue: 0, + + // mainSvg + mainSvg: undefined, + + // Init data + initData: function() { + this.map = { }; + this.treeData = { }; + this.maxDepth = 0; + this.numOfLeafQueue = 0; + + this.get("model") + .forEach(function(o) { + this.map[o.id] = o; + }.bind(this)); + + var selected = this.get("selected"); + + this.initQueue("root", 1, this.treeData); + }, + + // get Children array of given queue + getChildrenNamesArray: function(q) { + var namesArr = []; + + // Folded queue's children is empty + if (this.foldedQueues[q.get("name")]) { + return namesArr; + } + + var names = q.get("children"); + if (names) { + names.forEach(function(name) { + namesArr.push(name); + }); + } + + return namesArr; + }, + + // Init queues + initQueue: function(queueName, depth, node) { + if ((!queueName) || (!this.map[queueName])) { + // Queue is not existed + return; + } + + if (depth > this.maxDepth) { + this.maxDepth = this.maxDepth + 1; + } + + var queue = this.map[queueName]; + + var names = this.getChildrenNamesArray(queue); + + node.name = queueName; + node.parent = queue.get("parent"); + node.queueData = queue; + + if (names.length > 0) { + node.children = []; + + names.forEach(function(name) { + var childQueueData = {}; + node.children.push(childQueueData); + this.initQueue(name, depth + 1, childQueueData); + }.bind(this)); + } else { + this.numOfLeafQueue = this.numOfLeafQueue + 1; + } + }, + + update: function(source, root, tree, diagonal) { + var duration = 300; + var i = 0; + + // Compute the new tree layout. + var nodes = tree.nodes(root).reverse(); + var links = tree.links(nodes); + + // Normalize for fixed-depth. + nodes.forEach(function(d) { d.y = d.depth * 200; }); + + // Update the nodes⦠+ var node = this.mainSvg.selectAll("g.node") + .data(nodes, function(d) { return d.id || (d.id = ++i); }); + + // Enter any new nodes at the parent's previous position. + var nodeEnter = node.enter().append("g") + .attr("class", "node") + .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) + .on("click", function(d,i){ + if (d.queueData.get("name") != this.get("selected")) { + document.location.href = "yarnQueue/" + d.queueData.get("name"); + } + }.bind(this)); + // .on("click", click); + + nodeEnter.append("circle") + .attr("r", 1e-6) + .style("fill", function(d) { + var usedCap = d.queueData.get("usedCapacity"); + if (usedCap <= 60.0) { + return "LimeGreen"; + } else if (usedCap <= 100.0) { + return "DarkOrange"; + } else { + return "LightCoral"; + } + }); + + // append percentage + nodeEnter.append("text") + .attr("x", function(d) { return 0; }) + .attr("dy", ".35em") + .attr("text-anchor", function(d) { return "middle"; }) + .text(function(d) { + var usedCap = d.queueData.get("usedCapacity"); + if (usedCap >= 100.0) { + return usedCap.toFixed(0) + "%"; + } else { + return usedCap.toFixed(1) + "%"; + } + }) + .style("fill-opacity", 1e-6); + + // append queue name + nodeEnter.append("text") + .attr("x", function(d) { return 40; }) + .attr("dy", ".35em") + .attr("text-anchor", function(d) { return "start"; }) + .text(function(d) { return d.name; }) + .style("fill-opacity", 1e-6); + + // Transition nodes to their new position. + var nodeUpdate = node.transition() + .duration(duration) + .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); + + nodeUpdate.select("circle") + .attr("r", 20) + .attr("href", + function(d) { + return "yarnQueues/" + d.queueData.get("name"); + }) + .style("stroke", function(d) { + if (d.queueData.get("name") == this.get("selected")) { + return "red"; + } else { + return "gray"; + } + }.bind(this)); + + nodeUpdate.selectAll("text") + .style("fill-opacity", 1); + + // Transition exiting nodes to the parent's new position. + var nodeExit = node.exit().transition() + .duration(duration) + .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) + .remove(); + + nodeExit.select("circle") + .attr("r", 1e-6); + + nodeExit.select("text") + .style("fill-opacity", 1e-6); + + // Update the links⦠+ var link = this.mainSvg.selectAll("path.link") + .data(links, function(d) { return d.target.id; }); + + // Enter any new links at the parent's previous position. + link.enter().insert("path", "g") + .attr("class", "link") + .attr("d", function(d) { + var o = {x: source.x0, y: source.y0}; + return diagonal({source: o, target: o}); + }); + + // Transition links to their new position. + link.transition() + .duration(duration) + .attr("d", diagonal); + + // Transition exiting nodes to the parent's new position. + link.exit().transition() + .duration(duration) + .attr("d", function(d) { + var o = {x: source.x, y: source.y}; + return diagonal({source: o, target: o}); + }) + .remove(); + + // Stash the old positions for transition. + nodes.forEach(function(d) { + d.x0 = d.x; + d.y0 = d.y; + }); + }, + + reDraw: function() { + this.initData(); + + var margin = {top: 20, right: 120, bottom: 20, left: 120}; + var treeWidth = this.maxDepth * 200; + var treeHeight = this.numOfLeafQueue * 80; + var width = treeWidth + margin.left + margin.right; + var height = treeHeight + margin.top + margin.bottom; + var layout = { }; + + if (this.mainSvg) { + this.mainSvg.remove(); + } + + this.mainSvg = d3.select("#" + this.get("parentId")).append("svg") + .attr("width", width) + .attr("height", height) + .attr("class", "tree-selector") + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + var tree = d3.layout.tree().size([treeHeight, treeWidth]); + + var diagonal = d3.svg.diagonal() + .projection(function(d) { return [d.y, d.x]; }); + + var root = this.treeData; + root.x0 = height / 2; + root.y0 = 0; + + d3.select(self.frameElement).style("height", height); + + this.update(root, root, tree, diagonal); + }, + + didInsertElement: function() { + this.reDraw(); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/.gitkeep ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/.gitkeep b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/cluster-overview.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/cluster-overview.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/cluster-overview.js new file mode 100644 index 0000000..5c3c825 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/cluster-overview.js @@ -0,0 +1,5 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + loading: true, +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-apps.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-apps.js new file mode 100644 index 0000000..55ff9aa --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-apps.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-queue.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-queue.js new file mode 100644 index 0000000..b16864e --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/controllers/yarn-queue.js @@ -0,0 +1,6 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + needReload: true, + selectedQueue: undefined, +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/helpers/.gitkeep ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/helpers/.gitkeep b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/helpers/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/index.html ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/index.html b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/index.html new file mode 100644 index 0000000..edc4f2e --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/index.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>YarnUi</title> + <meta name="description" content=""> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + {{content-for 'head'}} + + <link rel="stylesheet" href="assets/vendor.css"> + <link rel="stylesheet" href="assets/yarn-ui.css"> + + {{content-for 'head-footer'}} + </head> + <body> + {{content-for 'body'}} + + <script src="assets/vendor.js"></script> + <script src="assets/yarn-ui.js"></script> + + {{content-for 'body-footer'}} + </body> +</html> http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/.gitkeep ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/.gitkeep b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-info.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-info.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-info.js new file mode 100644 index 0000000..b1f0a88 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-info.js @@ -0,0 +1,13 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + startedOn: DS.attr('string'), + state: DS.attr('string'), + haState: DS.attr('string'), + rmStateStoreName: DS.attr('string'), + resourceManagerVersion: DS.attr('string'), + resourceManagerBuildVersion: DS.attr('string'), + hadoopVersion: DS.attr('string'), + hadoopBuildVersion: DS.attr('string'), + hadoopVersionBuiltOn: DS.attr('string') +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-metric.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-metric.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-metric.js new file mode 100644 index 0000000..2dd428c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/cluster-metric.js @@ -0,0 +1,115 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + appsSubmitted: DS.attr('number'), + appsCompleted: DS.attr('number'), + appsPending: DS.attr('number'), + appsRunning: DS.attr('number'), + appsFailed: DS.attr('number'), + appsKilled: DS.attr('number'), + reservedMB: DS.attr('number'), + availableMB: DS.attr('number'), + allocatedMB: DS.attr('number'), + reservedVirtualCores: DS.attr('number'), + availableVirtualCores: DS.attr('number'), + allocatedVirtualCores: DS.attr('number'), + containersAllocated: DS.attr('number'), + containersReserved: DS.attr('number'), + containersPending: DS.attr('number'), + totalMB: DS.attr('number'), + totalVirtualCores: DS.attr('number'), + totalNodes: DS.attr('number'), + lostNodes: DS.attr('number'), + unhealthyNodes: DS.attr('number'), + decommissionedNodes: DS.attr('number'), + rebootedNodes: DS.attr('number'), + activeNodes: DS.attr('number'), + + getFinishedAppsDataForDonutChart: function() { + var arr = []; + arr.push({ + label: "Completed", + value: this.get("appsCompleted") + }); + arr.push({ + label: "Killed", + value: this.get("appsKilled") + }); + arr.push({ + label: "Failed", + value: this.get("appsFailed") + }); + + return arr; + }.property("appsCompleted", "appsKilled", "appsFailed"), + + getRunningAppsDataForDonutChart: function() { + var arr = []; + + arr.push({ + label: "Pending", + value: this.get("appsPending") + }); + arr.push({ + label: "Running", + value: this.get("appsRunning") + }); + + return arr; + }.property("appsPending", "appsRunning"), + + getNodesDataForDonutChart: function() { + var arr = []; + arr.push({ + label: "Active", + value: this.get("activeNodes") + }); + arr.push({ + label: "Unhealthy", + value: this.get("unhealthyNodes") + }); + arr.push({ + label: "Decomissioned", + value: this.get("decommissionedNodes") + }); + return arr; + }.property("activeNodes", "unhealthyNodes", "decommissionedNodes"), + + getMemoryDataForDonutChart: function() { + var type = "MB"; + var arr = []; + arr.push({ + label: "Allocated", + value: this.get("allocated" + type) + }); + arr.push({ + label: "Reserved", + value: this.get("reserved" + type) + }); + arr.push({ + label: "Available", + value: this.get("available" + type) + }); + + return arr; + }.property("allocatedMB", "reservedMB", "availableMB"), + + getVCoreDataForDonutChart: function() { + var type = "VirtualCores"; + var arr = []; + arr.push({ + label: "Allocated", + value: this.get("allocated" + type) + }); + arr.push({ + label: "Reserved", + value: this.get("reserved" + type) + }); + arr.push({ + label: "Available", + value: this.get("available" + type) + }); + + return arr; + }.property("allocatedVirtualCores", "reservedVirtualCores", "availableVirtualCores"), +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app-attempt.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app-attempt.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app-attempt.js new file mode 100644 index 0000000..fcb5134 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app-attempt.js @@ -0,0 +1,44 @@ +import DS from 'ember-data'; +import Converter from 'yarn-ui/utils/converter'; + +export default DS.Model.extend({ + startTime: DS.attr('string'), + finishedTime: DS.attr('string'), + containerId: DS.attr('string'), + nodeHttpAddress: DS.attr('string'), + nodeId: DS.attr('string'), + logsLink: DS.attr('string'), + + startTs: function() { + return Converter.dateToTimeStamp(this.get("startTime")); + }.property("startTime"), + + finishedTs: function() { + var ts = Converter.dateToTimeStamp(this.get("finishedTime")); + return ts; + }.property("finishedTime"), + + shortAppAttemptId: function() { + return "attempt_" + + parseInt(Converter.containerIdToAttemptId(this.get("containerId")).split("_")[3]); + }.property("containerId"), + + elapsedTime: function() { + var elapsedMs = this.get("finishedTs") - this.get("startTs"); + if (elapsedMs <= 0) { + elapsedMs = Date.now() - this.get("startTs"); + } + + return Converter.msToElapsedTime(elapsedMs); + }.property(), + + tooltipLabel: function() { + return "<p>Id:" + this.get("id") + + "</p><p>ElapsedTime:" + + String(this.get("elapsedTime")) + "</p>"; + }.property(), + + link: function() { + return "/yarnAppAttempt/" + this.get("id"); + }.property(), +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app.js new file mode 100644 index 0000000..cb79be1 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-app.js @@ -0,0 +1,65 @@ +import Converter from 'yarn-ui/utils/converter'; +import DS from 'ember-data'; + +export default DS.Model.extend({ + appName: DS.attr('string'), + user: DS.attr('string'), + queue: DS.attr('string'), + state: DS.attr('string'), + startTime: DS.attr('string'), + elapsedTime: DS.attr('string'), + finalStatus: DS.attr('string'), + finishedTime: DS.attr('finishedTime'), + progress: DS.attr('number'), + diagnostics: DS.attr('string'), + amContainerLogs: DS.attr('string'), + amHostHttpAddress: DS.attr('string'), + logAggregationStatus: DS.attr('string'), + unmanagedApplication: DS.attr('string'), + amNodeLabelExpression: DS.attr('string'), + applicationTags: DS.attr('string'), + priority: DS.attr('number'), + allocatedMB: DS.attr('number'), + allocatedVCores: DS.attr('number'), + runningContainers: DS.attr('number'), + memorySeconds: DS.attr('number'), + vcoreSeconds: DS.attr('number'), + preemptedResourceMB: DS.attr('number'), + preemptedResourceVCores: DS.attr('number'), + numNonAMContainerPreempted: DS.attr('number'), + numAMContainerPreempted: DS.attr('number'), + + isFailed: function() { + return this.get('finalStatus') == "FAILED" + }.property("finalStatus"), + + allocatedResource: function() { + return Converter.resourceToString(this.get("allocatedMB"), this.get("allocatedVCores")); + }.property("allocatedMB", "allocatedVCores"), + + preemptedResource: function() { + return Converter.resourceToString(this.get("preemptedResourceMB"), this.get("preemptedResourceVCores")); + }.property("preemptedResourceMB", "preemptedResourceVCores"), + + aggregatedResourceUsage: function() { + return Converter.resourceToString(this.get("memorySeconds"), this.get("vcoreSeconds")) + " (à Secs)"; + }.property("memorySeconds", "vcoreSeconds"), + + progressStyle: function() { + return "width: " + this.get("progress") + "%"; + }.property("progress"), + + finalStatusStyle: function() { + var style = "default"; + var finalStatus = this.get("finalStatus"); + if (finalStatus == "KILLED") { + style = "warning"; + } else if (finalStatus == "FAILED") { + style = "danger"; + } else { + style = "success"; + } + + return "label label-" + style; + }.property("finalStatus") +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-container.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-container.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-container.js new file mode 100644 index 0000000..f7977be --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-container.js @@ -0,0 +1,39 @@ +import DS from 'ember-data'; +import Converter from 'yarn-ui/utils/converter'; + +export default DS.Model.extend({ + allocatedMB: DS.attr('number'), + allocatedVCores: DS.attr('number'), + assignedNodeId: DS.attr('string'), + priority: DS.attr('number'), + startedTime: DS.attr('number'), + finishedTime: DS.attr('number'), + logUrl: DS.attr('string'), + containerExitStatus: DS.attr('number'), + containerState: DS.attr('string'), + nodeHttpAddress: DS.attr('string'), + + startTs: function() { + return Converter.dateToTimeStamp(this.get("startedTime")); + }.property("startedTime"), + + finishedTs: function() { + var ts = Converter.dateToTimeStamp(this.get("finishedTime")); + return ts; + }.property("finishedTime"), + + elapsedTime: function() { + var elapsedMs = this.get("finishedTs") - this.get("startTs"); + if (elapsedMs <= 0) { + elapsedMs = Date.now() - this.get("startTs"); + } + + return Converter.msToElapsedTime(elapsedMs); + }.property(), + + tooltipLabel: function() { + return "<p>Id:" + this.get("id") + + "</p><p>ElapsedTime:" + + String(this.get("elapsedTime")) + "</p>"; + }.property(), +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-queue.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-queue.js new file mode 100644 index 0000000..5b91d70 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-queue.js @@ -0,0 +1,76 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + name: DS.attr('string'), + children: DS.attr('array'), + parent: DS.attr('string'), + capacity: DS.attr('number'), + maxCapacity: DS.attr('number'), + usedCapacity: DS.attr('number'), + absCapacity: DS.attr('number'), + absMaxCapacity: DS.attr('number'), + absUsedCapacity: DS.attr('number'), + state: DS.attr('string'), + userLimit: DS.attr('number'), + userLimitFactor: DS.attr('number'), + preemptionDisabled: DS.attr('number'), + numPendingApplications: DS.attr('number'), + numActiveApplications: DS.attr('number'), + users: DS.hasMany('YarnUser'), + + isLeafQueue: function() { + var len = this.get("children.length"); + if (!len) { + return true; + } + return len <= 0; + }.property("children"), + + capacitiesBarChartData: function() { + return [ + { + label: "Absolute Capacity", + value: this.get("name") == "root" ? 100 : this.get("absCapacity") + }, + { + label: "Absolute Used", + value: this.get("name") == "root" ? this.get("usedCapacity") : this.get("absUsedCapacity") + }, + { + label: "Absolute Max Capacity", + value: this.get("name") == "root" ? 100 : this.get("absMaxCapacity") + } + ] + }.property("absCapacity", "absUsedCapacity", "absMaxCapacity"), + + userUsagesDonutChartData: function() { + var data = []; + if (this.get("users")) { + this.get("users").forEach(function(o) { + data.push({ + label: o.get("name"), + value: o.get("usedMemoryMB") + }) + }); + } + + return data; + }.property("users"), + + hasUserUsages: function() { + return this.get("userUsagesDonutChartData").length > 0; + }.property(), + + numOfApplicationsDonutChartData: function() { + return [ + { + label: "Pending Apps", + value: this.get("numPendingApplications") || 0 // TODO, fix the REST API so root will return #applications as well. + }, + { + label: "Active Apps", + value: this.get("numActiveApplications") || 0 + } + ] + }.property(), +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-user.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-user.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-user.js new file mode 100644 index 0000000..6e9c03c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/models/yarn-user.js @@ -0,0 +1,8 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + name: DS.attr('string'), + queueName: DS.attr('string'), + usedMemoryMB: DS.attr('number'), + usedVCore: DS.attr('number') +}) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/router.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/router.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/router.js new file mode 100644 index 0000000..c31190f --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/router.js @@ -0,0 +1,16 @@ +import Ember from 'ember'; +import config from './config/environment'; + +var Router = Ember.Router.extend({ + location: config.locationType +}); + +Router.map(function() { + this.route('yarnApps'); + this.route('yarnQueue', { path: '/yarnQueue/:queue_name' }); + this.route('clusterOverview'); + this.route('yarnApp', { path: '/yarnApp/:app_id' }); + this.route('yarnAppAttempt', { path: '/yarnAppAttempt/:app_attempt_id'}); +}); + +export default Router; http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/.gitkeep ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/.gitkeep b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/.gitkeep new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/cluster-overview.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/cluster-overview.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/cluster-overview.js new file mode 100644 index 0000000..4ba5dcd --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/cluster-overview.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model() { + return this.store.findAll('ClusterMetric'); + }, + + afterModel() { + this.controllerFor("ClusterOverview").set("loading", false); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app-attempt.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app-attempt.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app-attempt.js new file mode 100644 index 0000000..3b6adc7 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app-attempt.js @@ -0,0 +1,21 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model(param) { + return Ember.RSVP.hash({ + attempt: this.store.findRecord('yarnAppAttempt', param.app_attempt_id), + + rmContainers: this.store.query('yarnContainer', + { + app_attempt_id: param.app_attempt_id, + is_rm: true + }), + + tsContainers: this.store.query('yarnContainer', + { + app_attempt_id: param.app_attempt_id, + is_rm: false + }), + }); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app.js new file mode 100644 index 0000000..03092aa --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-app.js @@ -0,0 +1,10 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model(param) { + return Ember.RSVP.hash({ + app: this.store.find('yarnApp', param.app_id), + attempts: this.store.query('yarnAppAttempt', { appId: param.app_id}) + }); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-apps.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-apps.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-apps.js new file mode 100644 index 0000000..79d184f --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-apps.js @@ -0,0 +1,8 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model() { + var apps = this.store.findAll('yarnApp'); + return apps + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queue.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queue.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queue.js new file mode 100644 index 0000000..9396bac --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queue.js @@ -0,0 +1,20 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model(param) { + return Ember.RSVP.hash({ + selected : param.queue_name, + queues: this.store.findAll('yarnQueue'), + selectedQueue : undefined, + apps: undefined, // apps of selected queue + }); + }, + + afterModel(model) { + model.selectedQueue = this.store.peekRecord('yarnQueue', model.selected); + model.apps = this.store.findAll('yarnApp'); + model.apps.forEach(function(o) { + console.log(o); + }) + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/index.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/index.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/index.js new file mode 100644 index 0000000..9be90b1 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/index.js @@ -0,0 +1,5 @@ +export default Ember.Route.extend({ + beforeModel() { + this.transitionTo('yarnQueues.root'); + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/queues-selector.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/queues-selector.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/queues-selector.js new file mode 100644 index 0000000..0f6c572 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/routes/yarn-queues/queues-selector.js @@ -0,0 +1,7 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model() { + return this.store.findAll('yarnQueue'); + }, +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/hadoop/blob/137c67d6/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/serializers/cluster-info.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/serializers/cluster-info.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/serializers/cluster-info.js new file mode 100644 index 0000000..cc936cb --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/serializers/cluster-info.js @@ -0,0 +1,29 @@ +import DS from 'ember-data'; + +export default DS.JSONAPISerializer.extend({ + normalizeSingleResponse(store, primaryModelClass, payload, id, + requestType) { + var fixedPayload = { + id: id, + type: primaryModelClass.modelName, + attributes: payload + }; + + return this._super(store, primaryModelClass, fixedPayload, id, + requestType); + }, + + normalizeArrayResponse(store, primaryModelClass, payload, id, + requestType) { + // return expected is { data: [ {}, {} ] } + var normalizedArrayResponse = {}; + + // payload has apps : { app: [ {},{},{} ] } + // need some error handling for ex apps or app may not be defined. + normalizedArrayResponse.data = [ + this.normalizeSingleResponse(store, primaryModelClass, + payload.clusterInfo, payload.clusterInfo.id, requestType) + ]; + return normalizedArrayResponse; + } +}); \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org For additional commands, e-mail: common-commits-h...@hadoop.apache.org