├── .gitignore ├── .jsdoc.json ├── .publishrc ├── .travis.yml ├── LICENSE ├── README.md ├── docker-compose.yml ├── docs ├── Builder.html ├── Executor.html ├── Mesos.html ├── Scheduler.html ├── TaskHealthHelper.html ├── TaskHelper.html ├── builder.js.html ├── coverage │ ├── base.css │ ├── index.html │ ├── mesos-framework │ │ ├── index.html │ │ ├── index.js.html │ │ └── lib │ │ │ ├── builder.js.html │ │ │ ├── executor.js.html │ │ │ ├── executorHandlers.js.html │ │ │ ├── helpers.js.html │ │ │ ├── index.html │ │ │ ├── mesos.js.html │ │ │ ├── scheduler.js.html │ │ │ ├── schedulerHandlers.js.html │ │ │ ├── taskHealthHelper.js.html │ │ │ └── taskHelper.js.html │ ├── prettify.css │ ├── prettify.js │ ├── sort-arrow-sprite.png │ └── sorter.js ├── executor.js.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ ├── OpenSans-Regular-webfont.woff │ ├── OpenSans-Semibold-webfont.eot │ ├── OpenSans-Semibold-webfont.svg │ ├── OpenSans-Semibold-webfont.ttf │ ├── OpenSans-Semibold-webfont.woff │ ├── OpenSans-SemiboldItalic-webfont.eot │ ├── OpenSans-SemiboldItalic-webfont.svg │ ├── OpenSans-SemiboldItalic-webfont.ttf │ └── OpenSans-SemiboldItalic-webfont.woff ├── index.html ├── mesos.js.html ├── scheduler.js.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js ├── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css ├── taskHealthHelper.js.html └── taskHelper.js.html ├── examples ├── README.md ├── commandScheduler.js ├── commandSchedulerZk.js ├── dockerSchedulerApacheFlink.js ├── dockerSchedulerBridgeNetworking.js ├── dockerSchedulerHostNetworking.js └── dockerSchedulerHostNetworkingZk.js ├── index.js ├── lib ├── builder.js ├── executor.js ├── executorHandlers.js ├── helpers.js ├── mesos.js ├── scheduler.js ├── schedulerHandlers.js ├── taskHealthHelper.js └── taskHelper.js ├── logs └── .gitkeep ├── package-lock.json ├── package.json ├── proto ├── 1.5.0 │ ├── executor.proto │ ├── mesos.proto │ └── scheduler.proto └── all.proto └── test ├── helpers.test.js ├── scheduler.test.js ├── schedulerHandlers.test.js ├── taskHealthHelper.test.js └── taskHelper.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.log 3 | 4 | node_modules 5 | 6 | npm-debug.log* 7 | .npm 8 | .node_repl_history 9 | 10 | .DS_Store 11 | 12 | .idea/ 13 | 14 | .nyc_output 15 | -------------------------------------------------------------------------------- /.jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true, 4 | "dictionaries": ["jsdoc"] 5 | }, 6 | "source": { 7 | "include": ["lib", "README.md"], 8 | "includePattern": ".js$", 9 | "excludePattern": "(node_modules/|docs)" 10 | }, 11 | "plugins": [ 12 | "plugins/markdown" 13 | ], 14 | "templates": { 15 | "cleverLinks": false, 16 | "monospaceLinks": true 17 | }, 18 | "opts": { 19 | "destination": "./docs/", 20 | "encoding": "utf8", 21 | "private": true, 22 | "recurse": true, 23 | "template": "./node_modules/minami" 24 | } 25 | } -------------------------------------------------------------------------------- /.publishrc: -------------------------------------------------------------------------------- 1 | { 2 | "validations": { 3 | "vulnerableDependencies": true, 4 | "uncommittedChanges": true, 5 | "untrackedFiles": true, 6 | "sensitiveData": true, 7 | "branch": "master", 8 | "gitTag": true 9 | }, 10 | "confirm": true, 11 | "publishTag": "latest", 12 | "prePublishScript": "npm run test" 13 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | script: 2 | - "npm run test" 3 | 4 | language: node_js 5 | 6 | node_js: 7 | - "6" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 TobiLG 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | zk: 5 | image: bobrik/zookeeper 6 | network_mode: host 7 | environment: 8 | ZK_CONFIG: tickTime=2000,initLimit=10,syncLimit=5,maxClientCnxns=128,forceSync=no,clientPort=2181 9 | ZK_ID: 1 10 | 11 | master: 12 | image: mesosphere/mesos-master:1.5.0 13 | network_mode: host 14 | environment: 15 | MESOS_ZK: zk://127.0.0.1:2181/mesos 16 | MESOS_QUORUM: 1 17 | MESOS_CLUSTER: docker-compose 18 | MESOS_REGISTRY: replicated_log 19 | MESOS_HOSTNAME: ${DOCKER_IP} 20 | LIBPROCESS_IP: ${DOCKER_IP} 21 | depends_on: 22 | - zk 23 | 24 | agent: 25 | image: mesosphere/mesos-slave:1.5.0 26 | network_mode: host 27 | pid: host 28 | environment: 29 | MESOS_SYSTEMD_ENABLE_SUPPORT: "false" 30 | MESOS_MASTER: zk://127.0.0.1:2181/mesos 31 | MESOS_CONTAINERIZERS: docker,mesos 32 | MESOS_PORT: 5051 33 | MESOS_RESOURCES: ports(*):[11000-11999] 34 | MESOS_HOSTNAME: ${DOCKER_IP} 35 | LIBPROCESS_IP: ${DOCKER_IP} 36 | MESOS_WORK_DIR: /tmp/mesos 37 | volumes: 38 | - /sys/fs/cgroup:/sys/fs/cgroup 39 | - /usr/local/bin/docker:/usr/bin/docker 40 | - /var/run/docker.sock:/var/run/docker.sock 41 | depends_on: 42 | - zk 43 | - master -------------------------------------------------------------------------------- /docs/Builder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Builder - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Builder

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | Builder 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 |
56 | 57 | 58 | 59 |

new Builder(messageType)

60 | 61 | 62 | 63 | 64 | 65 |
66 |

Represents a variable builder for protobuf to JavaScript instantiations.

67 |
68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Parameters:
122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 157 | 158 | 159 | 160 | 161 | 162 | 166 | 167 | 168 | 169 | 170 |
NameTypeDescription
messageType 150 | 151 | 152 | string 153 | 154 | 155 | 156 | 163 |

The message type as string, e.g. mesos.HealthCheck.

164 | 165 |
171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 |
188 | 189 |
190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 |
209 | 210 |
211 | 212 | 213 | 214 | 215 |
216 | 217 |
218 | 219 | 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /docs/TaskHealthHelper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | TaskHealthHelper - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

TaskHealthHelper

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | TaskHealthHelper 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 |
56 | 57 | 58 | 59 |

new TaskHealthHelper(scheduler, options)

60 | 61 | 62 | 63 | 64 | 65 |
66 |

Represents a TaskHealthHelper object

67 |
68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Parameters:
122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 157 | 158 | 159 | 160 | 161 | 162 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 183 | 184 | 185 | 186 | 187 | 188 | 192 | 193 | 194 | 195 | 196 |
NameTypeDescription
scheduler 150 | 151 | 152 | object 153 | 154 | 155 | 156 | 163 |

The scheduler object.

164 | 165 |
options 176 | 177 | 178 | object 179 | 180 | 181 | 182 | 189 |

The option map object.

190 | 191 |
197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 |
214 | 215 |
216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 |
235 | 236 |
237 | 238 | 239 | 240 | 241 |
242 | 243 |
244 | 245 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /docs/builder.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | builder.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

builder.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
"use strict";
43 | 
44 | var path = require("path");
45 | var protoBuf = require("protobufjs");
46 | 
47 | // Load Mesos protobuf definitions
48 | var builder = protoBuf.loadProtoFile(path.join(__dirname, "../", "proto/all.proto"));
49 | 
50 | /**
51 |  * Represents a variable builder for protobuf to JavaScript instantiations.
52 |  * @constructor
53 |  * @param {string} messageType - The message type as string, e.g. `mesos.HealthCheck`.
54 |  */
55 | function Builder (messageType) {
56 | 
57 |     if (!(this instanceof Builder)) {
58 |         return new Builder(messageType);
59 |     } else {
60 |         return new (builder.build(messageType))();
61 |     }
62 | 
63 | }
64 | 
65 | module.exports = Builder;
66 | 
67 |
68 |
69 | 70 | 71 | 72 | 73 |
74 | 75 |
76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/coverage/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | 170 | 171 | .medium .chart { border:1px solid #666; } 172 | .medium .cover-fill { background: #666; } 173 | 174 | .cbranch-no { background: yellow !important; color: #111; } 175 | 176 | .cstat-skip { background: #ddd; color: #111; } 177 | .fstat-skip { background: #ddd; color: #111 !important; } 178 | .cbranch-skip { background: #ddd !important; color: #111; } 179 | 180 | span.cline-neutral { background: #eaeaea; } 181 | .medium { background: #eaeaea; } 182 | 183 | .cover-fill, .cover-empty { 184 | display:inline-block; 185 | height: 12px; 186 | } 187 | .chart { 188 | line-height: 0; 189 | } 190 | .cover-empty { 191 | background: white; 192 | } 193 | .cover-full { 194 | border-right: none !important; 195 | } 196 | pre.prettyprint { 197 | border: none !important; 198 | padding: 0 !important; 199 | margin: 0 !important; 200 | } 201 | .com { color: #999 !important; } 202 | .ignore-none { color: #999; font-weight: normal; } 203 | 204 | .wrapper { 205 | min-height: 100%; 206 | height: auto !important; 207 | height: 100%; 208 | margin: 0 auto -48px; 209 | } 210 | .footer, .push { 211 | height: 48px; 212 | } 213 | -------------------------------------------------------------------------------- /docs/coverage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files 20 |

21 |
22 |
23 | 87.67% 24 | Statements 25 | 903/1030 26 |
27 |
28 | 85.26% 29 | Branches 30 | 538/631 31 |
32 |
33 | 78.06% 34 | Functions 35 | 121/155 36 |
37 |
38 | 87.67% 39 | Lines 40 | 903/1030 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
FileStatementsBranchesFunctionsLines
mesos-framework
100%6/6100%0/0100%0/0100%6/6
mesos-framework/lib
87.6%897/102485.26%538/63178.06%121/15587.6%897/1024
89 |
90 |
91 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/coverage/mesos-framework/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for mesos-framework 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files mesos-framework 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 6/6 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 6/6 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
index.js
100%6/6100%0/0100%0/0100%6/6
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /docs/coverage/mesos-framework/index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for mesos-framework/index.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files / mesos-framework index.js 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 6/6 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 6/6 41 |
42 |
43 |
44 |
45 |

46 | 
71 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9  55 |   56 | 1x 57 | 1x 58 | 1x 59 | 1x 60 | 1x 61 | 1x 62 |  
"use strict";
63 |  
64 | module.exports.Scheduler = require("./lib/scheduler");
65 | module.exports.Executor = require("./lib/executor");
66 | module.exports.Mesos = require("./lib/mesos")();
67 | module.exports.TaskHealthHelper = require("./lib/taskHealthHelper");
68 | module.exports.helpers = require("./lib/helpers");
69 | module.exports.Builder = require("./lib/builder");
70 |  
72 |
73 |
74 | 78 | 79 | 80 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/coverage/mesos-framework/lib/builder.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for mesos-framework/lib/builder.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files / mesos-framework/lib builder.js 20 |

21 |
22 |
23 | 85.71% 24 | Statements 25 | 6/7 26 |
27 |
28 | 50% 29 | Branches 30 | 1/2 31 |
32 |
33 | 100% 34 | Functions 35 | 1/1 36 |
37 |
38 | 85.71% 39 | Lines 40 | 6/7 41 |
42 |
43 |
44 |
45 |

 46 | 
119 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25  71 |   72 | 1x 73 | 1x 74 |   75 |   76 | 1x 77 |   78 |   79 |   80 |   81 |   82 |   83 |   84 |   85 | 880x 86 |   87 |   88 | 880x 89 |   90 |   91 |   92 |   93 | 1x 94 |  
"use strict";
 95 |  
 96 | var path = require("path");
 97 | var protoBuf = require("protobufjs");
 98 |  
 99 | // Load Mesos protobuf definitions
100 | var builder = protoBuf.loadProtoFile(path.join(__dirname, "../", "proto/all.proto"));
101 |  
102 | /**
103 |  * Represents a variable builder for protobuf to JavaScript instantiations.
104 |  * @constructor
105 |  * @param {string} messageType - The message type as string, e.g. `mesos.HealthCheck`.
106 |  */
107 | function Builder (messageType) {
108 |  
109 |     Iif (!(this instanceof Builder)) {
110 |         return new Builder(messageType);
111 |     } else {
112 |         return new (builder.build(messageType))();
113 |     }
114 |  
115 | }
116 |  
117 | module.exports = Builder;
118 |  
120 |
121 |
122 | 126 | 127 | 128 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/coverage/mesos-framework/lib/executorHandlers.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for mesos-framework/lib/executorHandlers.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files / mesos-framework/lib executorHandlers.js 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 6/6 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 0% 34 | Functions 35 | 0/7 36 |
37 |
38 | 100% 39 | Lines 40 | 6/6 41 |
42 |
43 |
44 |
45 |

 46 | 
122 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26  72 | 1x 73 |   74 | 1x 75 | 1x 76 |   77 | 1x 78 | 1x 79 |   80 | 1x 81 |   82 |   83 |   84 |   85 |   86 |   87 |   88 |   89 |   90 |   91 |   92 |   93 |   94 |   95 |   96 |  
"use strict";
 97 | var uuid = require('uuid');
 98 |  
 99 | var helpers = require("./helpers");
100 | var Mesos = new (require("./mesos"))();
101 |  
102 | var mesos = Mesos.getMesos();
103 | var builder = Mesos.getBuilder();
104 |  
105 | module.exports = {
106 |     "SUBSCRIBED": function (subscribed) {
107 |     },
108 |     "LAUNCH": function (launched) {
109 |     },
110 |     "KILL": function (killed) {
111 |     },
112 |     "ACKNOWLEDGED": function (acknowledged) {
113 |     },
114 |     "MESSAGE": function (message) {
115 |     },
116 |     "ERROR": function (error) {
117 |     },
118 |     "SHUTDOWN": function (shutdown) {
119 |     }
120 | };
121 |  
123 |
124 |
125 | 129 | 130 | 131 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/coverage/mesos-framework/lib/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for mesos-framework/lib 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files mesos-framework/lib 20 |

21 |
22 |
23 | 87.6% 24 | Statements 25 | 897/1024 26 |
27 |
28 | 85.26% 29 | Branches 30 | 538/631 31 |
32 |
33 | 78.06% 34 | Functions 35 | 121/155 36 |
37 |
38 | 87.6% 39 | Lines 40 | 897/1024 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 |
FileStatementsBranchesFunctionsLines
builder.js
85.71%6/750%1/2100%1/185.71%6/7
executor.js
12.37%12/970%0/450%0/1312.37%12/97
executorHandlers.js
100%6/6100%0/00%0/7100%6/6
helpers.js
100%69/69100%55/55100%16/16100%69/69
mesos.js
93.33%14/15100%2/280%4/593.33%14/15
scheduler.js
90.77%364/40185.28%197/23184.62%55/6590.77%364/401
schedulerHandlers.js
98.83%254/25793.05%174/18786.36%19/2298.83%254/257
taskHealthHelper.js
100%88/88100%61/61100%15/15100%88/88
taskHelper.js
100%84/84100%48/48100%11/11100%84/84
180 |
181 |
182 | 186 | 187 | 188 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /docs/coverage/mesos-framework/lib/mesos.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for mesos-framework/lib/mesos.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files / mesos-framework/lib mesos.js 20 |

21 |
22 |
23 | 93.33% 24 | Statements 25 | 14/15 26 |
27 |
28 | 100% 29 | Branches 30 | 2/2 31 |
32 |
33 | 80% 34 | Functions 35 | 4/5 36 |
37 |
38 | 93.33% 39 | Lines 40 | 14/15 41 |
42 |
43 |
44 |
45 |

 46 | 
221 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59  105 |   106 | 1x 107 | 1x 108 |   109 |   110 | 1x 111 |   112 |   113 | 1x 114 |   115 |   116 |   117 |   118 |   119 |   120 |   121 |   122 | 20x 123 | 9x 124 |   125 |   126 |   127 |   128 |   129 |   130 |   131 |   132 | 1x 133 | 9x 134 |   135 |   136 |   137 |   138 |   139 |   140 | 1x 141 | 1x 142 |   143 |   144 |   145 |   146 |   147 |   148 |   149 | 1x 150 |   151 |   152 |   153 |   154 |   155 |   156 |   157 | 1x 158 | 1x 159 |   160 |   161 | 1x 162 |  
"use strict";
163 |  
164 | var protoBuf = require("protobufjs");
165 | var path = require("path");
166 |  
167 | // Load Mesos protobuf definitions
168 | var builder = protoBuf.loadProtoFile(path.join(__dirname, "../", "proto/all.proto"));
169 |  
170 | // Instantiate protobuf definitions
171 | var mesos = builder.build("mesos");
172 |  
173 | /**
174 |  * The Mesos protocol buffers helper
175 |  * @returns {object} An object with the Mesos protocol buffer definitions
176 |  * @constructor
177 |  */
178 | function Mesos () {
179 |  
180 |     if (!(this instanceof Mesos)) {
181 |         return new Mesos();
182 |     }
183 |  
184 | }
185 |  
186 | /**
187 |  *
188 |  * @returns {Mesos}
189 |  */
190 | Mesos.prototype.getMesos = function () {
191 |     return mesos;
192 | };
193 |  
194 | /**
195 |  * Get a ProtoBuf.Builder instance
196 |  * @returns {?ProtoBuf.Builder|undefined|ProtoBuf.Builder} A ProtoBuf.Builder instance
197 |  */
198 | Mesos.prototype.getBuilder = function () {
199 |     return builder;
200 | };
201 |  
202 | /**
203 |  * Convenience method to get a ProtoBuf.Message instance of the specified `messageType`
204 |  * @param {string} messageType The
205 |  * @returns {?ProtoBuf.Message|undefined|ProtoBuf.Message} A ProtoBuf.Message instance
206 |  */
207 | Mesos.prototype.build = function (messageType) {
208 |     return new (builder.build(messageType))()
209 | };
210 |  
211 | /**
212 |  * Get a reference to the protobuf.js module
213 |  * @returns {function} A reference to the protobuf.js module
214 |  */
215 | Mesos.prototype.getProtoBuf = function () {
216 |     return protoBuf;
217 | };
218 |  
219 | module.exports = Mesos;
220 |  
222 |
223 |
224 | 228 | 229 | 230 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /docs/coverage/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /docs/coverage/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/coverage/sort-arrow-sprite.png -------------------------------------------------------------------------------- /docs/coverage/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, 4 | currentSort = { 5 | index: 0, 6 | desc: false 7 | }; 8 | 9 | // returns the summary table element 10 | function getTable() { return document.querySelector('.coverage-summary'); } 11 | // returns the thead element of the summary table 12 | function getTableHeader() { return getTable().querySelector('thead tr'); } 13 | // returns the tbody element of the summary table 14 | function getTableBody() { return getTable().querySelector('tbody'); } 15 | // returns the th element for nth column 16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 17 | 18 | // loads all columns 19 | function loadColumns() { 20 | var colNodes = getTableHeader().querySelectorAll('th'), 21 | colNode, 22 | cols = [], 23 | col, 24 | i; 25 | 26 | for (i = 0; i < colNodes.length; i += 1) { 27 | colNode = colNodes[i]; 28 | col = { 29 | key: colNode.getAttribute('data-col'), 30 | sortable: !colNode.getAttribute('data-nosort'), 31 | type: colNode.getAttribute('data-type') || 'string' 32 | }; 33 | cols.push(col); 34 | if (col.sortable) { 35 | col.defaultDescSort = col.type === 'number'; 36 | colNode.innerHTML = colNode.innerHTML + ''; 37 | } 38 | } 39 | return cols; 40 | } 41 | // attaches a data attribute to every tr element with an object 42 | // of data values keyed by column name 43 | function loadRowData(tableRow) { 44 | var tableCols = tableRow.querySelectorAll('td'), 45 | colNode, 46 | col, 47 | data = {}, 48 | i, 49 | val; 50 | for (i = 0; i < tableCols.length; i += 1) { 51 | colNode = tableCols[i]; 52 | col = cols[i]; 53 | val = colNode.getAttribute('data-value'); 54 | if (col.type === 'number') { 55 | val = Number(val); 56 | } 57 | data[col.key] = val; 58 | } 59 | return data; 60 | } 61 | // loads all row data 62 | function loadData() { 63 | var rows = getTableBody().querySelectorAll('tr'), 64 | i; 65 | 66 | for (i = 0; i < rows.length; i += 1) { 67 | rows[i].data = loadRowData(rows[i]); 68 | } 69 | } 70 | // sorts the table using the data for the ith column 71 | function sortByIndex(index, desc) { 72 | var key = cols[index].key, 73 | sorter = function (a, b) { 74 | a = a.data[key]; 75 | b = b.data[key]; 76 | return a < b ? -1 : a > b ? 1 : 0; 77 | }, 78 | finalSorter = sorter, 79 | tableBody = document.querySelector('.coverage-summary tbody'), 80 | rowNodes = tableBody.querySelectorAll('tr'), 81 | rows = [], 82 | i; 83 | 84 | if (desc) { 85 | finalSorter = function (a, b) { 86 | return -1 * sorter(a, b); 87 | }; 88 | } 89 | 90 | for (i = 0; i < rowNodes.length; i += 1) { 91 | rows.push(rowNodes[i]); 92 | tableBody.removeChild(rowNodes[i]); 93 | } 94 | 95 | rows.sort(finalSorter); 96 | 97 | for (i = 0; i < rows.length; i += 1) { 98 | tableBody.appendChild(rows[i]); 99 | } 100 | } 101 | // removes sort indicators for current column being sorted 102 | function removeSortIndicators() { 103 | var col = getNthColumn(currentSort.index), 104 | cls = col.className; 105 | 106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 107 | col.className = cls; 108 | } 109 | // adds sort indicators for current column being sorted 110 | function addSortIndicators() { 111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 112 | } 113 | // adds event listeners for all sorter widgets 114 | function enableUI() { 115 | var i, 116 | el, 117 | ithSorter = function ithSorter(i) { 118 | var col = cols[i]; 119 | 120 | return function () { 121 | var desc = col.defaultDescSort; 122 | 123 | if (currentSort.index === i) { 124 | desc = !currentSort.desc; 125 | } 126 | sortByIndex(i, desc); 127 | removeSortIndicators(); 128 | currentSort.index = i; 129 | currentSort.desc = desc; 130 | addSortIndicators(); 131 | }; 132 | }; 133 | for (i =0 ; i < cols.length; i += 1) { 134 | if (cols[i].sortable) { 135 | // add the click event handler on the th so users 136 | // dont have to click on those tiny arrows 137 | el = getNthColumn(i).querySelector('.sorter').parentElement; 138 | if (el.addEventListener) { 139 | el.addEventListener('click', ithSorter(i)); 140 | } else { 141 | el.attachEvent('onclick', ithSorter(i)); 142 | } 143 | } 144 | } 145 | } 146 | // adds sorting functionality to the UI 147 | return function () { 148 | if (!getTable()) { 149 | return; 150 | } 151 | cols = loadColumns(); 152 | loadData(cols); 153 | addSortIndicators(); 154 | enableUI(); 155 | }; 156 | })(); 157 | 158 | window.addEventListener('load', addSorting); 159 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Semibold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Semibold-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-Semibold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-SemiboldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-SemiboldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-SemiboldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/OpenSans-SemiboldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/docs/fonts/OpenSans-SemiboldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/mesos.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | mesos.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

mesos.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
"use strict";
 43 | 
 44 | var protoBuf = require("protobufjs");
 45 | var path = require("path");
 46 | 
 47 | // Load Mesos protobuf definitions
 48 | var builder = protoBuf.loadProtoFile(path.join(__dirname, "../", "proto/all.proto"));
 49 | 
 50 | // Instantiate protobuf definitions
 51 | var mesos = builder.build("mesos");
 52 | 
 53 | /**
 54 |  * The Mesos protocol buffers helper
 55 |  * @returns {object} An object with the Mesos protocol buffer definitions
 56 |  * @constructor
 57 |  */
 58 | function Mesos () {
 59 | 
 60 |     if (!(this instanceof Mesos)) {
 61 |         return new Mesos();
 62 |     }
 63 | 
 64 | }
 65 | 
 66 | /**
 67 |  *
 68 |  * @returns {Mesos}
 69 |  */
 70 | Mesos.prototype.getMesos = function () {
 71 |     return mesos;
 72 | };
 73 | 
 74 | /**
 75 |  * Get a ProtoBuf.Builder instance
 76 |  * @returns {?ProtoBuf.Builder|undefined|ProtoBuf.Builder} A ProtoBuf.Builder instance
 77 |  */
 78 | Mesos.prototype.getBuilder = function () {
 79 |     return builder;
 80 | };
 81 | 
 82 | /**
 83 |  * Convenience method to get a ProtoBuf.Message instance of the specified `messageType`
 84 |  * @param {string} messageType The
 85 |  * @returns {?ProtoBuf.Message|undefined|ProtoBuf.Message} A ProtoBuf.Message instance
 86 |  */
 87 | Mesos.prototype.build = function (messageType) {
 88 |     return new (builder.build(messageType))()
 89 | };
 90 | 
 91 | /**
 92 |  * Get a reference to the protobuf.js module
 93 |  * @returns {function} A reference to the protobuf.js module
 94 |  */
 95 | Mesos.prototype.getProtoBuf = function () {
 96 |     return protoBuf;
 97 | };
 98 | 
 99 | module.exports = Mesos;
100 | 
101 |
102 |
103 | 104 | 105 | 106 | 107 |
108 | 109 |
110 | 111 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 2 | 3 | 4 | 5 | 6 | taskHealthHelper.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

taskHealthHelper.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
"use strict";
 43 | 
 44 | var http = require("http");
 45 | 
 46 | /**
 47 |  * Represents a TaskHealthHelper object
 48 |  * @constructor
 49 |  * @param {object} scheduler - The scheduler object.
 50 |  * @param {object} options - The option map object.
 51 |  */
 52 | function TaskHealthHelper(scheduler, options) {
 53 |     if (!(this instanceof TaskHealthHelper)) {
 54 |         return new TaskHealthHelper(scheduler, options);
 55 |     }
 56 | 
 57 |     var self = this;
 58 | 
 59 |     self.scheduler = scheduler;
 60 |     self.logger = scheduler.logger;
 61 |     self.options = {};
 62 |     self.options.interval = options.interval || 30;
 63 |     self.options.graceCount = options.graceCount || 4;
 64 |     self.options.portIndex = options.portIndex || 0;
 65 |     self.options.propertyPrefix = options.propertyPrefix || "";
 66 |     self.options.errorEvent = options.errorEvent || self.options.propertyPrefix + "task_unhealthy";
 67 |     self.options.additionalProperties = options.additionalProperties || [];
 68 |     self.options.taskNameFilter = options.taskNameFilter || null;
 69 |     self.options.statusCodes = options.statusCodes || [200];
 70 |     self.options.checkBodyFunction = options.checkBodyFunction || null;
 71 | 
 72 |     if (options.url) {
 73 |         self.options.url = options.url;
 74 |     } else {
 75 |         throw new Error("Must set URL");
 76 |     }
 77 | 
 78 |     self.healthRequestCreate = function (host, port) {
 79 |         return {
 80 |             "host": host,
 81 |             "port": port,
 82 |             "path": options.url,
 83 |             "method": "GET",
 84 |             headers: {}
 85 |         };
 86 |     };
 87 | 
 88 |     self.checkRunningInstances = function () {
 89 | 
 90 |         self.logger.debug("Running periodic healthcheck" + (self.options.propertyPrefix.length ? ", prefix: " + self.options.propertyPrefix : ""));
 91 | 
 92 |         self.scheduler.launchedTasks.forEach(function (task) {
 93 |             self.checkInstance.call(self, task);
 94 |         });
 95 |     };
 96 | }
 97 | 
 98 | TaskHealthHelper.prototype.taskFilter = function (name) {
 99 |     var self = this;
100 |     if (self.options.taskNameFilter) {
101 |         return name.match(self.options.taskNameFilter) !== null;
102 |     }
103 |     return true;
104 | };
105 | 
106 | TaskHealthHelper.prototype.setCheckFailed = function (task) {
107 | 
108 |     var self = this;
109 | 
110 |     if (task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] === undefined) {
111 |         task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] = 0;
112 |     }
113 |     task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] += 1;
114 |     if (task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] === self.options.graceCount) {
115 |         self.logger.debug("Task marked unhealthy" + (self.options.propertyPrefix.length ? ", prefix: " + self.options.propertyPrefix : ""));
116 |         task.runtimeInfo[self.options.propertyPrefix + "healthy"] = false;
117 |         self.setProperties(task, false);
118 |         self.scheduler.emit(self.options.errorEvent, task);
119 |     } else if (task.runtimeInfo[self.options.propertyPrefix + "healthy"] === false) {
120 |         self.scheduler.emit(self.options.errorEvent, task);
121 |     }
122 | };
123 | 
124 | 
125 | TaskHealthHelper.prototype.checkInstance = function (task) {
126 | 
127 |     var self = this;
128 | 
129 |     if (task.runtimeInfo && task.runtimeInfo.state === "TASK_RUNNING" && self.taskFilter(task.name)) {
130 |         if (task.runtimeInfo.network && task.runtimeInfo.network.hostname && task.runtimeInfo.network.ports && task.runtimeInfo.network.ports[self.options.portIndex]) {
131 |             var req = http.request(self.healthRequestCreate(task.runtimeInfo.network.hostname, task.runtimeInfo.network.ports[self.options.portIndex]), function (res) {
132 |                 if (self.options.statusCodes.indexOf(res.statusCode) > -1) {
133 | 
134 |                     var value = false;
135 | 
136 |                     if (self.options.checkBodyFunction) {
137 |                         var responseBodyBuilder = '';
138 | 
139 |                         res.on("data", function (chunk) {
140 |                             responseBodyBuilder += chunk;
141 |                         });
142 | 
143 |                         res.on("end", function () {
144 |                             value = self.options.checkBodyFunction.call(self, task, responseBodyBuilder);
145 |                             self.logger.debug("Checking the response body: " + value);
146 | 
147 |                             if (value) {
148 |                                 task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] = 0;
149 |                                 task.runtimeInfo[self.options.propertyPrefix + "healthy"] = value;
150 |                                 self.setProperties(task, value);
151 |                             } else {
152 |                                 self.setCheckFailed.call(self, task);
153 |                             }
154 | 
155 |                         });
156 |                     } else {
157 |                         task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] = 0;
158 |                         task.runtimeInfo[self.options.propertyPrefix + "healthy"] = true;
159 |                         self.setProperties(task, true);
160 |                     }
161 | 
162 |                 } else {
163 |                     self.setCheckFailed.call(self, task);
164 |                 }
165 |                 res.resume();
166 |             });
167 |             req.on("error", function (error) {
168 |                 self.logger.error("Error checking task health:" + JSON.stringify(error) + (self.options.propertyPrefix.length ? ", prefix: " + self.options.propertyPrefix : ""));
169 |                 self.setCheckFailed.call(self, task);
170 |             });
171 |             req.end();
172 |         }
173 |     }
174 | };
175 | 
176 | TaskHealthHelper.prototype.setProperties = function (task, value) {
177 |     var self = this;
178 |     self.options.additionalProperties.forEach(function (property) {
179 |         // If healthy or setting unhealthy
180 |         if (value || property.setUnhealthy) {
181 |             var propertyValue = value;
182 |             if (property.inverse) {
183 |                 propertyValue = !value;
184 |             }
185 |             task.runtimeInfo[property.name] = propertyValue;
186 |         }
187 |     });
188 | };
189 | 
190 | TaskHealthHelper.prototype.stopHealthCheck = function () {
191 |     var self = this;
192 | 
193 |     if (self.interval) {
194 |         clearInterval(self.interval);
195 |         self.interval = null;
196 |     }
197 | };
198 | 
199 | TaskHealthHelper.prototype.setupHealthCheck = function () {
200 |     var self = this;
201 | 
202 |     self.stopHealthCheck();
203 |     self.interval = setInterval(self.checkRunningInstances, self.options.interval * 1000);
204 | };
205 | 
206 | module.exports = TaskHealthHelper;
207 | 
208 |
209 |
210 | 211 | 212 | 213 | 214 |
215 | 216 |
217 | 218 |
219 | Generated by JSDoc 3.5.5 on Sun Mar 04 2018 17:37:29 GMT+0100 (CET) using the Minami theme. 220 |
221 | 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # mesos-framework examples 2 | 3 | There are four examples in this folder. 4 | 5 | ## commandScheduler.js 6 | 7 | This example will just start a command-based scheduler, which simply calls `sleep 10`. After execution of this command, the task will switch to `TASK_FINISHED` state. 8 | 9 | To make the finished tasks restart again, we used the `restartStates` array definition within the task object. You can specify the list of task states which should trigger a restart of a task (by default, `TASK_FINISHED` doesn't trigger a restart of the task). 10 | 11 | # dockerSchedulerBridgeNetworking.js 12 | 13 | A simple Docker-based scheduler, which starts a simple Node.js webserver. It uses `BRIDGE` networking to allocate and map container to host ports. 14 | 15 | # dockerSchedulerHostNetworking.js 16 | 17 | A simple Docker-based scheduler, which starts a simple Node.js webserver. It uses `HOST` networking to allocate and use host ports. 18 | 19 | # dockerSchedulerApacheFlink.js 20 | 21 | A more advanced setup, which uses different task type with priorities. This scheduler start a Apache Flink cluster in HA mode (3 jobmanagers and 2 taskmanagers). 22 | 23 | The only two things you should need to change to run this on your cluster are the following: 24 | 25 | * `masterUrl`: Change this either to your leading master's ip address, or use `leader.mesos` in case you're using Mesos DNS. 26 | * `flink_recovery_zookeeper_quorum`: This is the environment variable passed to the Docker containers to enable them to use HA via your existing ZooKeeper cluster (format is `hostIp1:2181,hostIp2:2181,hostIpn:2181`). 27 | -------------------------------------------------------------------------------- /examples/commandScheduler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var lib = require("requirefrom")("lib"); 4 | 5 | var Scheduler = lib("scheduler"); 6 | var Builder = lib("builder"); 7 | 8 | var scheduler = new Scheduler({ 9 | "masterUrl": "172.17.11.102", // If Mesos DNS is used this would be "leader.mesos", otherwise use the actual IP address of the leading master 10 | "port": 5050, 11 | "frameworkName": "My first Command framework", 12 | "logging": { 13 | "level": "debug" // Set log Level to debug (default is info) 14 | }, 15 | "restartStates": ["TASK_FAILED", "TASK_KILLED", "TASK_LOST", "TASK_ERROR", "TASK_FINISHED"], // Overwrite the restartStates (by default, TASK_FINISHED tasks are NOT restarted!) 16 | "tasks": { 17 | "sleepProcesses": { 18 | "priority": 1, 19 | "instances": 3, 20 | "commandInfo": new Builder("mesos.CommandInfo").setValue("env && sleep 100").setShell(true), 21 | "resources": { 22 | "cpus": 0.2, 23 | "mem": 128, 24 | "ports": 1, 25 | "disk": 0 26 | } 27 | } 28 | }, 29 | "handlers": { 30 | "HEARTBEAT": function (timestamp) { 31 | this.logger.info("CUSTOM HEARTBEAT!"); 32 | this.lastHeartbeat = timestamp; 33 | } 34 | } 35 | }); 36 | 37 | // Start the main logic once the framework scheduler has received the "SUBSCRIBED" event from the leading Mesos master 38 | scheduler.on("subscribed", function (obj) { 39 | 40 | // Display the Mesos-Stream-Id 41 | scheduler.logger.info("Mesos Stream Id is " + obj.mesosStreamId); 42 | 43 | // Display the framework id 44 | scheduler.logger.info("Framework Id is " + obj.frameworkId); 45 | 46 | // Trigger shutdown after one minute 47 | setTimeout(function() { 48 | // Send "TEARDOWN" request 49 | scheduler.teardown(); 50 | // Shutdown process 51 | process.exit(0); 52 | }, 60000); 53 | 54 | }); 55 | 56 | // Capture "offers" events 57 | scheduler.on("offers", function (offers) { 58 | scheduler.logger.info("Got offers: " + JSON.stringify(offers)); 59 | }); 60 | 61 | // Capture "heartbeat" events 62 | scheduler.on("heartbeat", function (heartbeatTimestamp) { 63 | scheduler.logger.info("Heartbeat on " + heartbeatTimestamp); 64 | }); 65 | 66 | // Capture "error" events 67 | scheduler.on("error", function (error) { 68 | scheduler.logger.error("ERROR: " + (error.message ? error.message : JSON.stringify(error))); 69 | if (error.stack) { 70 | scheduler.logger.error(error.stack); 71 | } 72 | }); 73 | 74 | scheduler.on("ready", function () { 75 | // Start framework scheduler 76 | scheduler.subscribe(); 77 | }); 78 | -------------------------------------------------------------------------------- /examples/commandSchedulerZk.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var lib = require("requirefrom")("lib"); 4 | 5 | var Scheduler = lib("scheduler"); 6 | var Builder = lib("builder"); 7 | 8 | var scheduler = new Scheduler({ 9 | "masterUrl": "172.17.11.101", // If Mesos DNS is used this would be "leader.mesos", otherwise use the actual IP address of the leading master 10 | "port": 5050, 11 | "frameworkName": "My first Command framework", 12 | "logging": { 13 | "level": "debug" // Set log Level to debug (default is info) 14 | }, 15 | "useZk": true, 16 | "zkUrl": "172.17.11.101:2181", 17 | "restartStates": ["TASK_FAILED", "TASK_KILLED", "TASK_LOST", "TASK_ERROR", "TASK_FINISHED"], // Overwrite the restartStates (by default, TASK_FINISHED tasks are NOT restarted!) 18 | "tasks": { 19 | "sleepProcesses": { 20 | "priority": 1, 21 | "instances": 1, 22 | "commandInfo": new Builder("mesos.CommandInfo").setValue("env && sleep 100").setShell(true), 23 | "resources": { 24 | "cpus": 0.2, 25 | "mem": 128, 26 | "ports": 1, 27 | "disk": 0 28 | } 29 | } 30 | }, 31 | "handlers": { 32 | "HEARTBEAT": function (timestamp) { 33 | this.logger.info("CUSTOM HEARTBEAT!"); 34 | this.lastHeartbeat = timestamp; 35 | } 36 | } 37 | }); 38 | 39 | // Start the main logic once the framework scheduler has received the "SUBSCRIBED" event from the leading Mesos master 40 | scheduler.on("subscribed", function (obj) { 41 | 42 | // Display the Mesos-Stream-Id 43 | scheduler.logger.info("Mesos Stream Id is " + obj.mesosStreamId); 44 | 45 | // Display the framework id 46 | scheduler.logger.info("Framework Id is " + obj.frameworkId); 47 | 48 | // Trigger shutdown after one minute 49 | setTimeout(function() { 50 | // Send "TEARDOWN" request 51 | scheduler.teardown(); 52 | // Shutdown process 53 | process.exit(0); 54 | }, 600000); 55 | 56 | }); 57 | 58 | // Capture "offers" events 59 | scheduler.on("offers", function (offers) { 60 | scheduler.logger.info("Got offers: " + JSON.stringify(offers)); 61 | }); 62 | 63 | // Capture "heartbeat" events 64 | scheduler.on("heartbeat", function (heartbeatTimestamp) { 65 | scheduler.logger.info("Heartbeat on " + heartbeatTimestamp); 66 | }); 67 | 68 | // Capture "error" events 69 | scheduler.on("error", function (error) { 70 | scheduler.logger.error("ERROR: " + (error.message ? error.message : JSON.stringify(error))); 71 | if (error.stack) { 72 | scheduler.logger.error(error.stack); 73 | } 74 | }); 75 | 76 | scheduler.on("ready", function () { 77 | // Start framework scheduler 78 | scheduler.subscribe(); 79 | }); 80 | -------------------------------------------------------------------------------- /examples/dockerSchedulerApacheFlink.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Scheduler = require("../index").Scheduler; 4 | var Mesos = require("../index").Mesos.getMesos(); 5 | var Builder = require("../index").Builder; 6 | 7 | var ContainerInfo = new Mesos.ContainerInfo( 8 | Mesos.ContainerInfo.Type.DOCKER, // Type 9 | null, // Volumes 10 | null, // Hostname 11 | new Mesos.ContainerInfo.DockerInfo( 12 | "mesoshq/flink:0.1.1", // Image 13 | Mesos.ContainerInfo.DockerInfo.Network.HOST, // Network 14 | null, // PortMappings 15 | false, // Privileged 16 | null, // Parameters 17 | true, // forcePullImage 18 | null // Volume Driver 19 | ) 20 | ); 21 | 22 | var scheduler = new Scheduler({ 23 | "masterUrl": "172.17.10.101", // If Mesos DNS is used this would be "leader.mesos", otherwise use the actual IP address of the leading master 24 | "port": 5050, 25 | "frameworkName": "Simple Apache Flink HA framework", 26 | "logging": { 27 | "path": "logs", 28 | "fileName": "mesos-framework-flink.log", 29 | "level": "debug" 30 | }, 31 | "tasks": { 32 | "jobmanagers": { 33 | "priority": 1, 34 | "instances": 3, 35 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 36 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 37 | "commandInfo": new Mesos.CommandInfo( 38 | null, // URI 39 | new Mesos.Environment([ 40 | new Builder("mesos.Environment.Variable").setName("flink_recovery_mode").setValue("zookeeper"), 41 | new Builder("mesos.Environment.Variable").setName("flink_recovery_zookeeper_quorum").setValue("172.17.10.101:2181"), 42 | new Builder("mesos.Environment.Variable").setName("flink_recovery_zookeeper_storageDir").setValue("/data/zk") 43 | ]), // Environment 44 | false, // Is shell? 45 | null, // Command 46 | ["jobmanager"], // Arguments 47 | null // User 48 | ), 49 | "resources": { 50 | "cpus": 0.5, 51 | "mem": 256, 52 | "ports": 2, 53 | "disk": 0 54 | }, 55 | "healthChecks": null, // Add your health checks here 56 | "labels": null // Add your labels (an array of { "key": "value" } objects) 57 | }, 58 | "taskmanagers": { 59 | "priority": 2, 60 | "instances": 2, 61 | "allowScaling": true, // Only allow scaling of the TaskManagers 62 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 63 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 64 | "commandInfo": new Mesos.CommandInfo( // Strangely, this is needed, even when specifying ContainerInfo... 65 | null, // URI 66 | new Mesos.Environment([ 67 | new Builder("mesos.Environment.Variable").setName("flink_recovery_mode").setValue("zookeeper"), 68 | new Builder("mesos.Environment.Variable").setName("flink_recovery_zookeeper_quorum").setValue("172.17.10.101:2181"), 69 | new Builder("mesos.Environment.Variable").setName("flink_recovery_zookeeper_storageDir").setValue("/data/zk"), 70 | new Builder("mesos.Environment.Variable").setName("flink_taskmanager_tmp_dirs").setValue("/data/tasks"), 71 | new Builder("mesos.Environment.Variable").setName("flink_blob_storage_directory").setValue("/data/blobs"), 72 | new Builder("mesos.Environment.Variable").setName("flink_state_backend").setValue("filesystem"), 73 | new Builder("mesos.Environment.Variable").setName("flink_taskmanager_numberOfTaskSlots").setValue("1"), 74 | new Builder("mesos.Environment.Variable").setName("flink_taskmanager_heap_mb").setValue("1536") 75 | ]), // Environment 76 | false, // Is shell? 77 | null, // Command 78 | ["taskmanager"], // Arguments 79 | null // User 80 | ), 81 | "resources": { 82 | "cpus": 0.5, 83 | "mem": 1536, 84 | "ports": 3, 85 | "disk": 0 86 | }, 87 | "healthChecks": null, // Add your health checks here 88 | "labels": null // Add your labels (an array of { "key": "value" } objects) 89 | } 90 | }, 91 | "handlers": { 92 | "HEARTBEAT": function (timestamp) { 93 | this.logger.info("CUSTOM HEARTBEAT!"); 94 | this.lastHeartbeat = timestamp; 95 | } 96 | } 97 | }); 98 | 99 | // Start the main logic once the framework scheduler has received the "SUBSCRIBED" event from the leading Mesos master 100 | scheduler.on("subscribed", function (obj) { 101 | 102 | // Display the Mesos-Stream-Id 103 | scheduler.logger.info("Mesos Stream Id is " + obj.mesosStreamId); 104 | 105 | // Display the framework id 106 | scheduler.logger.info("Framework Id is " + obj.frameworkId); 107 | 108 | // Trigger shutdown after one minute 109 | setTimeout(function() { 110 | // Send "TEARDOWN" request 111 | scheduler.teardown(); 112 | // Shutdown process 113 | process.exit(0); 114 | }, 600000); 115 | 116 | }); 117 | 118 | // Capture "offers" events 119 | scheduler.on("offers", function (offers) { 120 | scheduler.logger.info("Got offers: " + JSON.stringify(offers)); 121 | }); 122 | 123 | // Capture "heartbeat" events 124 | scheduler.on("heartbeat", function (heartbeatTimestamp) { 125 | scheduler.logger.info("Heartbeat on " + heartbeatTimestamp); 126 | }); 127 | 128 | // Capture "error" events 129 | scheduler.on("error", function (error) { 130 | scheduler.logger.info("ERROR: " + JSON.stringify(error)); 131 | scheduler.logger.info(error.stack); 132 | }); 133 | 134 | scheduler.on("ready", function () { 135 | // Start framework scheduler 136 | scheduler.subscribe(); 137 | }); 138 | -------------------------------------------------------------------------------- /examples/dockerSchedulerBridgeNetworking.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Scheduler = require("../index").Scheduler; 4 | var Mesos = require("../index").Mesos.getMesos(); 5 | 6 | var ContainerInfo = new Mesos.ContainerInfo( 7 | Mesos.ContainerInfo.Type.DOCKER, // Type 8 | null, // Volumes 9 | null, // Hostname 10 | new Mesos.ContainerInfo.DockerInfo( 11 | "tobilg/mini-webserver", // Image 12 | Mesos.ContainerInfo.DockerInfo.Network.BRIDGE, // Network 13 | null, // PortMappings 14 | false, // Privileged 15 | null, // Parameters 16 | false, // forcePullImage 17 | null // Volume Driver 18 | ) 19 | ); 20 | 21 | var scheduler = new Scheduler({ 22 | "masterUrl": "172.17.10.101", // If Mesos DNS is used this would be "leader.mesos", otherwise use the actual IP address of the leading master 23 | "port": 5050, 24 | "frameworkName": "My first Docker framework (bridge networking)", 25 | "logging": { 26 | "path": "logs", 27 | "fileName": "mesos-framework-docker-bridge.log", 28 | "level": "debug" 29 | }, 30 | "tasks": { 31 | "webservers": { 32 | "priority": 1, 33 | "instances": 3, 34 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 35 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 36 | "commandInfo": new Mesos.CommandInfo( // Strangely, this is needed, even when specifying ContainerInfo... 37 | null, // URI 38 | null, // Environment 39 | false, // Is shell? 40 | null, // Command 41 | null, // Arguments 42 | null // User 43 | ), 44 | "resources": { 45 | "cpus": 0.2, 46 | "mem": 128, 47 | "ports": 1, 48 | "disk": 0 49 | }, 50 | "portMappings": [ 51 | { "port": 80, "protocol": "tcp" } 52 | ], 53 | "healthChecks": null, // Add your health checks here 54 | "labels": null // Add your labels (an array of { "key": "value" } objects) 55 | }, 56 | "webservers1": { 57 | "priority": 2, 58 | "instances": 1, 59 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 60 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 61 | "commandInfo": new Mesos.CommandInfo( // Strangely, this is needed, even when specifying ContainerInfo... 62 | null, // URI 63 | null, // Environment 64 | false, // Is shell? 65 | null, // Command 66 | null, // Arguments 67 | null // User 68 | ), 69 | "resources": { 70 | "cpus": 0.2, 71 | "mem": 256, 72 | "ports": 1, 73 | "disk": 0 74 | }, 75 | "portMappings": [ 76 | { "port": 80, "protocol": "tcp" } 77 | ], 78 | "healthChecks": null, // Add your health checks here 79 | "labels": null // Add your labels (an array of { "key": "value" } objects) 80 | } 81 | }, 82 | "handlers": { 83 | "HEARTBEAT": function (timestamp) { 84 | this.logger.info("CUSTOM HEARTBEAT!"); 85 | this.lastHeartbeat = timestamp; 86 | } 87 | } 88 | }); 89 | 90 | // Start the main logic once the framework scheduler has received the "SUBSCRIBED" event from the leading Mesos master 91 | scheduler.on("subscribed", function (obj) { 92 | 93 | // Display the Mesos-Stream-Id 94 | scheduler.logger.info("Mesos Stream Id is " + obj.mesosStreamId); 95 | 96 | // Display the framework id 97 | scheduler.logger.info("Framework Id is " + obj.frameworkId); 98 | 99 | // Trigger shutdown after one minute 100 | setTimeout(function() { 101 | // Send "TEARDOWN" request 102 | scheduler.teardown(); 103 | // Shutdown process 104 | process.exit(0); 105 | }, 600000); 106 | 107 | }); 108 | 109 | // Capture "offers" events 110 | scheduler.on("offers", function (offers) { 111 | scheduler.logger.info("Got offers: " + JSON.stringify(offers)); 112 | }); 113 | 114 | // Capture "heartbeat" events 115 | scheduler.on("heartbeat", function (heartbeatTimestamp) { 116 | scheduler.logger.info("Heartbeat on " + heartbeatTimestamp); 117 | }); 118 | 119 | // Capture "error" events 120 | scheduler.on("error", function (error) { 121 | scheduler.logger.info("ERROR: " + JSON.stringify(error)); 122 | scheduler.logger.info(error.stack); 123 | }); 124 | 125 | scheduler.on("ready", function () { 126 | // Start framework scheduler 127 | scheduler.subscribe(); 128 | }); 129 | -------------------------------------------------------------------------------- /examples/dockerSchedulerHostNetworking.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Scheduler = require("../index").Scheduler; 4 | var Mesos = require("../index").Mesos.getMesos(); 5 | var Builder = require("../index").Builder; 6 | 7 | var ContainerInfo = new Mesos.ContainerInfo( 8 | Mesos.ContainerInfo.Type.DOCKER, // Type 9 | null, // Volumes 10 | null, // Hostname 11 | new Mesos.ContainerInfo.DockerInfo( 12 | "tobilg/mini-webserver", // Image 13 | Mesos.ContainerInfo.DockerInfo.Network.HOST, // Network 14 | null, // PortMappings 15 | false, // Privileged 16 | null, // Parameters 17 | false, // forcePullImage 18 | null // Volume Driver 19 | ) 20 | ); 21 | 22 | var scheduler = new Scheduler({ 23 | "masterUrl": "172.17.10.101", // If Mesos DNS is used this would be "leader.mesos", otherwise use the actual IP address of the leading master 24 | "port": 5050, 25 | "frameworkName": "My first Docker framework (host networking)", 26 | "logging": { 27 | "path": "logs", 28 | "fileName": "mesos-framework-docker-host.log", 29 | "level": "debug" 30 | }, 31 | "tasks": { 32 | "webservers": { 33 | "priority": 1, 34 | "instances": 3, 35 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 36 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 37 | "commandInfo": new Mesos.CommandInfo( // Strangely, this is needed, even when specifying ContainerInfo... 38 | null, // URI 39 | new Mesos.Environment([ 40 | new Builder("mesos.Environment.Variable").setName("FOO").setValue("BAR") 41 | ]), // Environment 42 | false, // Is shell? 43 | null, // Command 44 | null, // Arguments 45 | null // User 46 | ), 47 | "resources": { 48 | "cpus": 0.2, 49 | "mem": 128, 50 | "ports": 1, 51 | "disk": 0 52 | }, 53 | "healthChecks": null, // Add your health checks here 54 | "labels": null // Add your labels (an array of { "key": "value" } objects) 55 | }, 56 | "webservers1": { 57 | "priority": 2, 58 | "instances": 1, 59 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 60 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 61 | "commandInfo": new Mesos.CommandInfo( // Strangely, this is needed, even when specifying ContainerInfo... 62 | null, // URI 63 | null, // Environment 64 | false, // Is shell? 65 | null, // Command 66 | null, // Arguments 67 | null // User 68 | ), 69 | "resources": { 70 | "cpus": 0.2, 71 | "mem": 256, 72 | "ports": 1, 73 | "disk": 0 74 | }, 75 | "portMappings": [ 76 | { "port": 80, "protocol": "tcp" } 77 | ], 78 | "healthChecks": null, // Add your health checks here 79 | "labels": null // Add your labels (an array of { "key": "value" } objects) 80 | } 81 | }, 82 | "handlers": { 83 | "HEARTBEAT": function (timestamp) { 84 | this.logger.info("CUSTOM HEARTBEAT!"); 85 | this.lastHeartbeat = timestamp; 86 | } 87 | } 88 | }); 89 | 90 | // Start the main logic once the framework scheduler has received the "SUBSCRIBED" event from the leading Mesos master 91 | scheduler.on("subscribed", function (obj) { 92 | 93 | // Display the Mesos-Stream-Id 94 | scheduler.logger.info("Mesos Stream Id is " + obj.mesosStreamId); 95 | 96 | // Display the framework id 97 | scheduler.logger.info("Framework Id is " + obj.frameworkId); 98 | 99 | // Trigger shutdown after one minute 100 | setTimeout(function() { 101 | // Send "TEARDOWN" request 102 | scheduler.teardown(); 103 | // Shutdown process 104 | process.exit(0); 105 | }, 600000); 106 | 107 | }); 108 | 109 | // Capture "offers" events 110 | scheduler.on("offers", function (offers) { 111 | scheduler.logger.info("Got offers: " + JSON.stringify(offers)); 112 | }); 113 | 114 | // Capture "heartbeat" events 115 | scheduler.on("heartbeat", function (heartbeatTimestamp) { 116 | scheduler.logger.info("Heartbeat on " + heartbeatTimestamp); 117 | }); 118 | 119 | // Capture "error" events 120 | scheduler.on("error", function (error) { 121 | scheduler.logger.info("ERROR: " + JSON.stringify(error)); 122 | scheduler.logger.info(error.stack); 123 | }); 124 | 125 | scheduler.on("ready", function () { 126 | // Start framework scheduler 127 | scheduler.subscribe(); 128 | }); 129 | -------------------------------------------------------------------------------- /examples/dockerSchedulerHostNetworkingZk.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Scheduler = require("../index").Scheduler; 4 | var Mesos = require("../index").Mesos.getMesos(); 5 | var Builder = require("../index").Builder; 6 | 7 | var ContainerInfo = new Mesos.ContainerInfo( 8 | Mesos.ContainerInfo.Type.DOCKER, // Type 9 | null, // Volumes 10 | null, // Hostname 11 | new Mesos.ContainerInfo.DockerInfo( 12 | "tobilg/mini-webserver", // Image 13 | Mesos.ContainerInfo.DockerInfo.Network.HOST, // Network 14 | null, // PortMappings 15 | false, // Privileged 16 | null, // Parameters 17 | false, // forcePullImage 18 | null // Volume Driver 19 | ) 20 | ); 21 | 22 | var scheduler = new Scheduler({ 23 | "masterUrl": "172.17.11.101", // If Mesos DNS is used this would be "leader.mesos", otherwise use the actual IP address of the leading master 24 | "port": 5050, 25 | "frameworkName": "My first Docker framework (host networking)1", 26 | "logging": { 27 | "path": "logs", 28 | "fileName": "mesos-framework-docker-host.log", 29 | "level": "debug" 30 | }, 31 | "useZk": true, 32 | "zkUrl": "172.17.11.101:2181", 33 | "tasks": { 34 | "webservers": { 35 | "priority": 1, 36 | "instances": 1, 37 | "executorInfo": null, // Can take a Mesos.ExecutorInfo object 38 | "containerInfo": ContainerInfo, // Mesos.ContainerInfo object 39 | "commandInfo": new Mesos.CommandInfo( // Strangely, this is needed, even when specifying ContainerInfo... 40 | null, // URI 41 | new Mesos.Environment([ 42 | new Builder("mesos.Environment.Variable").setName("FOO").setValue("BAR") 43 | ]), // Environment 44 | false, // Is shell? 45 | null, // Command 46 | null, // Arguments 47 | null // User 48 | ), 49 | "resources": { 50 | "cpus": 0.2, 51 | "mem": 128, 52 | "ports": 1, 53 | "disk": 0 54 | }, 55 | "healthChecks": [ 56 | //new Mesos.HealthCheck(new Mesos.HealthCheck.HTTP(8080, "/health", [200]), 10.0, 20.0, 3) 57 | ], // Add your health checks here 58 | "labels": null // Add your labels (an array of { "key": "value" } objects) 59 | } 60 | }, 61 | "handlers": { 62 | "HEARTBEAT": function (timestamp) { 63 | this.logger.info("CUSTOM HEARTBEAT!"); 64 | this.lastHeartbeat = timestamp; 65 | } 66 | } 67 | }); 68 | 69 | // Start the main logic once the framework scheduler has received the "SUBSCRIBED" event from the leading Mesos master 70 | scheduler.on("subscribed", function (obj) { 71 | 72 | // Display the Mesos-Stream-Id 73 | scheduler.logger.info("Mesos Stream Id is " + obj.mesosStreamId); 74 | 75 | // Display the framework id 76 | scheduler.logger.info("Framework Id is " + obj.frameworkId); 77 | 78 | // Trigger shutdown after one minute 79 | setTimeout(function() { 80 | // Send "TEARDOWN" request 81 | scheduler.teardown(); 82 | // Shutdown process 83 | process.exit(0); 84 | }, 600000); 85 | 86 | }); 87 | 88 | // Capture "offers" events 89 | scheduler.on("offers", function (offers) { 90 | scheduler.logger.info("Got offers: " + JSON.stringify(offers)); 91 | }); 92 | 93 | // Capture "heartbeat" events 94 | scheduler.on("heartbeat", function (heartbeatTimestamp) { 95 | scheduler.logger.info("Heartbeat on " + heartbeatTimestamp); 96 | }); 97 | 98 | // Capture "error" events 99 | scheduler.on("error", function (error) { 100 | scheduler.logger.info("ERROR: " + JSON.stringify(error)); 101 | scheduler.logger.info(error.stack); 102 | }); 103 | 104 | scheduler.on("ready", function () { 105 | // Start framework scheduler 106 | scheduler.subscribe(); 107 | }); 108 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports.Scheduler = require("./lib/scheduler"); 4 | module.exports.Executor = require("./lib/executor"); 5 | module.exports.Mesos = require("./lib/mesos")(); 6 | module.exports.TaskHealthHelper = require("./lib/taskHealthHelper"); 7 | module.exports.helpers = require("./lib/helpers"); 8 | module.exports.Builder = require("./lib/builder"); 9 | -------------------------------------------------------------------------------- /lib/builder.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var path = require("path"); 4 | var protoBuf = require("protobufjs"); 5 | 6 | // Load Mesos protobuf definitions 7 | var builder = protoBuf.loadProtoFile(path.join(__dirname, "../", "proto/all.proto")); 8 | 9 | /** 10 | * Represents a variable builder for protobuf to JavaScript instantiations. 11 | * @constructor 12 | * @param {string} messageType - The message type as string, e.g. `mesos.HealthCheck`. 13 | */ 14 | function Builder (messageType) { 15 | 16 | if (!(this instanceof Builder)) { 17 | return new Builder(messageType); 18 | } else { 19 | return new (builder.build(messageType))(); 20 | } 21 | 22 | } 23 | 24 | module.exports = Builder; 25 | -------------------------------------------------------------------------------- /lib/executor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var http = require("http"); 4 | var EventEmitter = require('events').EventEmitter; 5 | var util = require('util'); 6 | var uuid = require('uuid'); 7 | 8 | var helpers = require("./helpers"); 9 | var executorHandlers = require("./executorHandlers"); 10 | var mesos = require("./mesos")().getMesos(); 11 | 12 | /** 13 | * Represents a Mesos framework executor. 14 | * @constructor 15 | * @param {object} options - The option map object. 16 | */ 17 | function Executor (options) { 18 | 19 | if (!(this instanceof Executor)) { 20 | return new Executor(options); 21 | } 22 | 23 | // Inherit from EventEmitter 24 | EventEmitter.call(this); 25 | 26 | var self = this; 27 | self.options = {}; 28 | 29 | // Optional env variables 30 | var envMap = { 31 | "MESOS_CHECKPOINT": "checkpointEnabled", 32 | "MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD": "shutdownGracePeriod", 33 | "MESOS_RECOVERY_TIMEOUT": "recoveryTimeout", 34 | "MESOS_SUBSCRIPTION_BACKOFF_MAX": "subscriptionBackoffMax" 35 | }; 36 | 37 | // Check for frameworkId 38 | if (process.env.MESOS_FRAMEWORK_ID) { 39 | self.frameworkId = new mesos.FrameworkID(process.env.MESOS_FRAMEWORK_ID); 40 | } else { 41 | console.error("No MESOS_FRAMEWORK_ID environment parameter found! Exiting..."); 42 | process.exit(1); 43 | } 44 | 45 | // Check fo rexecutorId 46 | if (process.env.MESOS_EXECUTOR_ID) { 47 | self.executorId = new mesos.ExecutorID(process.env.MESOS_EXECUTOR_ID); 48 | } else { 49 | console.error("No MESOS_EXECUTOR_ID environment parameter found! Exiting..."); 50 | process.exit(2); 51 | } 52 | 53 | // Check for working directory 54 | if (process.env.MESOS_DIRECTORY) { 55 | self.workingDirectory = process.env.MESOS_DIRECTORY; 56 | } else { 57 | console.error("No MESOS_DIRECTORY environment parameter found! Exiting..."); 58 | process.exit(3); 59 | } 60 | 61 | // Check for agent endpoint 62 | if (process.env.MESOS_AGENT_ENDPOINT) { 63 | var endpointArray = process.env.MESOS_AGENT_ENDPOINT.split(":"); 64 | if (endpointArray.length === 2) { 65 | self.options.agentUrl = endpointArray[0]; 66 | self.options.port = parseInt(endpointArray[1]); 67 | } else { 68 | console.error("MESOS_AGENT_ENDPOINT didn't contain a ip:port combination! Exiting..."); 69 | process.exit(4); 70 | } 71 | } else { 72 | console.log("No MESOS_AGENT_ENDPOINT environment parameter found! Using default values..."); 73 | self.options.agentUrl = options.agentUrl || "127.0.0.1"; 74 | self.options.port = parseInt(options.port) || 5051; 75 | } 76 | 77 | // Check for other env variables and inline them 78 | Object.getOwnPropertyNames(envMap).forEach(function (envVariable) { 79 | if (process.env[envVariable]) { 80 | self[envMap[envVariable]] = process.env[envVariable]; 81 | } 82 | }); 83 | 84 | // Template for issuing Mesos Scheduler HTTP API requests 85 | self.requestTemplate = { 86 | host: self.options.agentUrl, 87 | port: self.options.port, 88 | path: "/api/v1/executor", 89 | method: "POST", 90 | headers: { 91 | 'Content-Type': 'application/json' 92 | } 93 | }; 94 | 95 | // Customer event handlers will be registered here 96 | self.customEventHandlers = {}; 97 | 98 | // List of allowed event handler function names and their argument length 99 | var allowedEventHandlers = { 100 | "SUBSCRIBED": 1, 101 | "LAUNCH": 1, 102 | "KILL": 1, 103 | "ACKNOWLEDGED": 1, 104 | "MESSAGE": 1, 105 | "ERROR": 1, 106 | "SHUTDOWN": 1 107 | }; 108 | 109 | // Add custom event handlers if present 110 | if (options.handlers && Object.getOwnPropertyNames(options.handlers).length > 0) { 111 | Object.getOwnPropertyNames(options.handlers).forEach(function (handlerName) { 112 | // Check if name is allowed, is a function and the length of the function arguments fit to the ones defined in allowedEventHandlers 113 | if (Object.getOwnPropertyNames(allowedEventHandlers).indexOf(handlerName.toUpperCase()) > -1 && helpers.isFunction(options.handlers[handlerName]) && options.handlers[handlerName].length === allowedEventHandlers[handlerName]) { 114 | self.customEventHandlers[handlerName.toUpperCase()] = options.handlers[handlerName]; 115 | } 116 | }); 117 | } 118 | 119 | } 120 | 121 | // Inhertit from EventEmitter 122 | util.inherits(Executor, EventEmitter); 123 | 124 | /** 125 | * Subscribes the framework executor to the according Mesos agent. 126 | */ 127 | Executor.prototype.subscribe = function () { 128 | 129 | var self = this; 130 | 131 | /** 132 | * The handler funciton for the incoming Mesos agent events for this executor. 133 | * @param {object} eventData - The data object for an incoming event. Contains the event details (type etc.). 134 | */ 135 | function handleEvent (eventData) { 136 | 137 | try { 138 | 139 | var event = JSON.parse(eventData); 140 | 141 | // Determine event handler, use custom one if it exists 142 | if (self.customEventHandlers[event.type]) { 143 | // Call custom handler 144 | self.customEventHandlers[event.type].call(self, event[event.type.toLocaleLowerCase()]); 145 | } else { 146 | // Call default handler 147 | schedulerHandlers[event.type].call(self, event[event.type.toLocaleLowerCase()]); 148 | } 149 | 150 | // Emit original objects 151 | self.emit(event.type.toLocaleLowerCase(), event[event.type.toLocaleLowerCase()]); 152 | 153 | } catch (error) { 154 | self.emit("error", { message: "Couldn't parse as JSON: " + eventData, stack: (error.stack || "") }); 155 | } 156 | 157 | } 158 | 159 | var req = http.request(self.requestTemplate, function (res) { 160 | 161 | // Set encoding to UTF8 162 | res.setEncoding('utf8'); 163 | 164 | if (res.statusCode === 200) { 165 | self.emit("sent_subscribe", { mesosStreamId: self.mesosStreamId }); 166 | 167 | } 168 | 169 | // Local cache for chunked JSON messages 170 | var cache = ""; 171 | 172 | // Watch for data/chunks 173 | res.on('data', function (chunk) { 174 | 175 | console.log("BODY: " + chunk); 176 | 177 | var expectedLength = 0; 178 | 179 | if (chunk.indexOf("\n") > -1) { 180 | var temp = chunk.split("\n"); 181 | if (temp.length === 2) { 182 | expectedLength = parseInt(temp[0]); 183 | if (temp[1].length < expectedLength) { 184 | // Add to cache 185 | cache += temp[1]; 186 | } else { 187 | // Empty cache 188 | cache = ""; 189 | // Handle event 190 | handleEvent(temp[1]); 191 | } 192 | } else { 193 | self.emit("error", { message: "Other linebreak count found than expected! Actual count: " + temp.length }); 194 | } 195 | } else { 196 | if (cache.length > 0) { 197 | // Concatenate cached partial data with this chunk, replace the erroneous parts 198 | var eventData = cache + chunk; 199 | // Handle event 200 | handleEvent(eventData); 201 | // Empty cache 202 | cache = ""; 203 | } 204 | } 205 | }); 206 | 207 | res.on('end', function () { 208 | self.emit("error", { message: "Long-running connection was closed!" }); 209 | }); 210 | 211 | }); 212 | 213 | req.on('error', function (e) { 214 | self.emit("error", { message: "There was a problem with the request: " + e.message}); 215 | }); 216 | 217 | // write data to request body 218 | req.write(JSON.stringify({ 219 | "type": "SUBSCRIBE", 220 | "framework_id": self.frameworkId, 221 | "executor_id": self.executorId 222 | })); 223 | 224 | req.end(); 225 | 226 | }; 227 | 228 | /** 229 | * Communicate the state of managed tasks. It is crucial that a terminal update (e.g., TASK_FINISHED, TASK_KILLED or TASK_FAILED) is sent to the agent as soon as the task terminates, in order to allow Mesos to release the resources allocated to the task. 230 | * The scheduler must explicitly respond to this call through an ACKNOWLEDGE message (see ACKNOWLEDGED in the Events section below for the semantics). The executor must maintain a list of unacknowledged updates. If for some reason, the executor is disconnected from the agent, these updates must be sent as part of SUBSCRIBE request in the unacknowledged_updates field. 231 | * @param {Object} taskStatus The {@link https://github.com/apache/mesos/blob/c6e9ce16850f69fda719d4e32be3f2a2e1d80387/include/mesos/v1/mesos.proto#L1330|TaskStatus} object containing the update details. 232 | */ 233 | Executor.prototype.update = function (taskStatus) { 234 | 235 | var self = this; 236 | 237 | var payload = { 238 | "type": "UPDATE", 239 | "framework_id": self.frameworkId, 240 | "executor_id": self.executorId, 241 | "update": { 242 | "status": taskStatus 243 | } 244 | }; 245 | 246 | helpers.doRequest.call(self, payload, function (error, response) { 247 | if (error) { 248 | self.emit("error", error.message); 249 | } else { 250 | self.emit("sent_update"); 251 | } 252 | }); 253 | 254 | }; 255 | 256 | /** 257 | * Send arbitrary data to the scheduler. Note that Mesos neither interprets this data nor makes any guarantees about the delivery of this message to the executor. 258 | * @param {string} data The string which's raw bytes will be encoded in Base64. 259 | */ 260 | Executor.prototype.message = function (data) { 261 | 262 | var self = this; 263 | 264 | var payload = { 265 | "type": "MESSAGE", 266 | "framework_id": self.frameworkId, 267 | "executor_id": self.executorId, 268 | "message": { 269 | "data": new Buffer(data).toString('base64') 270 | } 271 | }; 272 | 273 | helpers.doRequest.call(self, payload, function (error, response) { 274 | if (error) { 275 | self.emit("error", error.message); 276 | } else { 277 | self.emit("sent_message"); 278 | } 279 | }); 280 | 281 | }; 282 | 283 | module.exports = Executor; 284 | -------------------------------------------------------------------------------- /lib/executorHandlers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var uuid = require('uuid'); 3 | 4 | var helpers = require("./helpers"); 5 | var Mesos = new (require("./mesos"))(); 6 | 7 | var mesos = Mesos.getMesos(); 8 | var builder = Mesos.getBuilder(); 9 | 10 | module.exports = { 11 | "SUBSCRIBED": function (subscribed) { 12 | }, 13 | "LAUNCH": function (launched) { 14 | }, 15 | "KILL": function (killed) { 16 | }, 17 | "ACKNOWLEDGED": function (acknowledged) { 18 | }, 19 | "MESSAGE": function (message) { 20 | }, 21 | "ERROR": function (error) { 22 | }, 23 | "SHUTDOWN": function (shutdown) { 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /lib/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var http = require("http"); 4 | var pathReq = require("path"); 5 | var _ = require('lodash'); 6 | var winston = require('winston'); 7 | 8 | module.exports = { 9 | 10 | getLogger: function(path, fileName, logLevel) { 11 | 12 | var logger = new (winston.Logger)({ 13 | transports: [ 14 | new (winston.transports.Console)({ level: logLevel || "info" }), 15 | new (require("winston-daily-rotate-file"))({ 16 | filename: pathReq.join(__dirname, "../", (path && fileName ? path + "/" + fileName : "logs/mesos-framework.log")), 17 | level: logLevel || "info", 18 | prepend: true, 19 | json: false 20 | }) 21 | ] 22 | }); 23 | 24 | return logger; 25 | 26 | }, 27 | 28 | cloneDeep: function(obj) { 29 | return _.cloneDeep(obj); 30 | }, 31 | 32 | sortTasksByPriority: function (tasks) { 33 | 34 | function prioSort(a,b) { 35 | if (a.priority < b.priority) { 36 | return -1; 37 | } 38 | if (a.priority > b.priority) { 39 | return 1; 40 | } 41 | if (a.name < b.name) { 42 | return -1; 43 | } 44 | return 1; 45 | } 46 | 47 | var tasksArray = []; 48 | 49 | Object.getOwnPropertyNames(tasks).forEach(function (task) { 50 | 51 | var instances = tasks[task].instances || 1; 52 | 53 | if (tasks[task].resources && tasks[task].resources.staticPorts) { 54 | tasks[task].resources.staticPorts.sort(); 55 | if (!tasks[task].resources.ports || tasks[task].resources.staticPorts.length > tasks[task].resources.ports) { 56 | throw new Error("Static ports must be included in the general port count for the task."); 57 | } 58 | } 59 | 60 | // Add to tasks array 61 | for (var i = 1; i <= instances; i++) { 62 | // Set defaults 63 | tasks[task].isSubmitted = false; 64 | tasks[task].name = task + "-" + i.toString(); 65 | if (!tasks[task].hasOwnProperty("allowScaling")) { 66 | tasks[task].allowScaling = false; 67 | } 68 | tasksArray.push(_.cloneDeep(tasks[task])); // Important! 69 | } 70 | 71 | }); 72 | 73 | return tasksArray.sort(prioSort); 74 | 75 | }, 76 | 77 | doRequest: function (payload, callback) { 78 | 79 | var self = this; 80 | 81 | // Add mesos-stream-id to header 82 | if (self.mesosStreamId) { 83 | self.requestTemplate.headers["mesos-stream-id"] = self.mesosStreamId; 84 | } 85 | 86 | var req = http.request(self.requestTemplate, function (res) { 87 | 88 | // Set encoding 89 | res.setEncoding('utf8'); 90 | 91 | // Buffer for the response body 92 | var body = ""; 93 | 94 | res.on('data', function (chunk) { 95 | body += chunk; 96 | }); 97 | 98 | // Watch for errors of the response 99 | res.on('error', function (e) { 100 | callback({ message: "There was a problem with the response: " + e.message }, null); 101 | }); 102 | 103 | res.on('end', function () { 104 | if (res.statusCode !== 202) { 105 | callback({ message: "Request was not accepted properly. Reponse status code was '" + res.statusCode + "'. Body was '" + body + "'." }, null); 106 | } else { 107 | callback(null, { statusCode: res.statusCode, body: body }); 108 | } 109 | }); 110 | 111 | }); 112 | 113 | // Watch for errors of the request 114 | req.on('error', function (e) { 115 | callback({ message: "There was a problem with the request: " + e.message }, null); 116 | }); 117 | 118 | // Write data to request body 119 | req.write(JSON.stringify(payload)); 120 | 121 | // End request 122 | req.end(); 123 | 124 | }, 125 | 126 | stringifyEnums: function (message) { 127 | message = _.clone(message); // We should not modify the source message in place, it causes issues with repeating calls 128 | _.forEach(message.$type.children, function(child) { 129 | var type = _.get(child, 'element.resolvedType', null); 130 | if (type && type.className === 'Enum' && type.children) { 131 | var metaValue = _.find(type.children, { 132 | id: message[child.name] 133 | }); 134 | if (metaValue && metaValue.name) 135 | // Alternatively you can do something like: 136 | // message[child.name + '_string'] = metaValue.name; 137 | // To get access to both the raw value and the string. 138 | message[child.name] = metaValue.name; 139 | } 140 | }); 141 | return message; 142 | }, 143 | 144 | fixEnums: function (message) { 145 | var self = this; 146 | var newMessage = self.stringifyEnums(message); 147 | _.forEach(message, function(subMessage, key) { 148 | if (_.isObject(subMessage) && subMessage.$type) { 149 | newMessage[key] = self.fixEnums(message[key]); 150 | } else if (_.isArray(subMessage) && subMessage.length > 0) { 151 | var arrayItems = []; 152 | var index; 153 | for (index = 0; index < subMessage.length; index += 1) { 154 | if (_.isObject(subMessage[index]) && subMessage[index].$type) { 155 | arrayItems.push(self.fixEnums(subMessage[index])); 156 | } else { 157 | arrayItems.push(subMessage[index]); 158 | } 159 | } 160 | newMessage[key] = arrayItems; 161 | } 162 | }); 163 | return newMessage; 164 | }, 165 | 166 | isFunction: function(obj) { 167 | return !!(obj && obj.constructor && obj.call && obj.apply); 168 | } 169 | 170 | }; -------------------------------------------------------------------------------- /lib/mesos.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var protoBuf = require("protobufjs"); 4 | var path = require("path"); 5 | 6 | // Load Mesos protobuf definitions 7 | var builder = protoBuf.loadProtoFile(path.join(__dirname, "../", "proto/all.proto")); 8 | 9 | // Instantiate protobuf definitions 10 | var mesos = builder.build("mesos"); 11 | 12 | /** 13 | * The Mesos protocol buffers helper 14 | * @returns {object} An object with the Mesos protocol buffer definitions 15 | * @constructor 16 | */ 17 | function Mesos () { 18 | 19 | if (!(this instanceof Mesos)) { 20 | return new Mesos(); 21 | } 22 | 23 | } 24 | 25 | /** 26 | * 27 | * @returns {Mesos} 28 | */ 29 | Mesos.prototype.getMesos = function () { 30 | return mesos; 31 | }; 32 | 33 | /** 34 | * Get a ProtoBuf.Builder instance 35 | * @returns {?ProtoBuf.Builder|undefined|ProtoBuf.Builder} A ProtoBuf.Builder instance 36 | */ 37 | Mesos.prototype.getBuilder = function () { 38 | return builder; 39 | }; 40 | 41 | /** 42 | * Convenience method to get a ProtoBuf.Message instance of the specified `messageType` 43 | * @param {string} messageType The 44 | * @returns {?ProtoBuf.Message|undefined|ProtoBuf.Message} A ProtoBuf.Message instance 45 | */ 46 | Mesos.prototype.build = function (messageType) { 47 | return new (builder.build(messageType))() 48 | }; 49 | 50 | /** 51 | * Get a reference to the protobuf.js module 52 | * @returns {function} A reference to the protobuf.js module 53 | */ 54 | Mesos.prototype.getProtoBuf = function () { 55 | return protoBuf; 56 | }; 57 | 58 | module.exports = Mesos; 59 | -------------------------------------------------------------------------------- /lib/taskHealthHelper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var http = require("http"); 4 | 5 | /** 6 | * Represents a TaskHealthHelper object 7 | * @constructor 8 | * @param {object} scheduler - The scheduler object. 9 | * @param {object} options - The option map object. 10 | */ 11 | function TaskHealthHelper(scheduler, options) { 12 | if (!(this instanceof TaskHealthHelper)) { 13 | return new TaskHealthHelper(scheduler, options); 14 | } 15 | 16 | var self = this; 17 | 18 | self.scheduler = scheduler; 19 | self.logger = scheduler.logger; 20 | self.options = {}; 21 | self.options.interval = options.interval || 30; 22 | self.options.graceCount = options.graceCount || 4; 23 | self.options.portIndex = options.portIndex || 0; 24 | self.options.propertyPrefix = options.propertyPrefix || ""; 25 | self.options.errorEvent = options.errorEvent || self.options.propertyPrefix + "task_unhealthy"; 26 | self.options.additionalProperties = options.additionalProperties || []; 27 | self.options.taskNameFilter = options.taskNameFilter || null; 28 | self.options.statusCodes = options.statusCodes || [200]; 29 | self.options.checkBodyFunction = options.checkBodyFunction || null; 30 | 31 | if (options.url) { 32 | self.options.url = options.url; 33 | } else { 34 | throw new Error("Must set URL"); 35 | } 36 | 37 | self.healthRequestCreate = function (host, port) { 38 | return { 39 | "host": host, 40 | "port": port, 41 | "path": options.url, 42 | "method": "GET", 43 | headers: {} 44 | }; 45 | }; 46 | 47 | self.checkRunningInstances = function () { 48 | 49 | self.logger.debug("Running periodic healthcheck" + (self.options.propertyPrefix.length ? ", prefix: " + self.options.propertyPrefix : "")); 50 | 51 | self.scheduler.launchedTasks.forEach(function (task) { 52 | self.checkInstance.call(self, task); 53 | }); 54 | }; 55 | } 56 | 57 | TaskHealthHelper.prototype.taskFilter = function (name) { 58 | var self = this; 59 | if (self.options.taskNameFilter) { 60 | return name.match(self.options.taskNameFilter) !== null; 61 | } 62 | return true; 63 | }; 64 | 65 | TaskHealthHelper.prototype.setCheckFailed = function (task) { 66 | 67 | var self = this; 68 | 69 | if (task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] === undefined) { 70 | task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] = 0; 71 | } 72 | task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] += 1; 73 | if (task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] === self.options.graceCount) { 74 | self.logger.debug("Task marked unhealthy" + (self.options.propertyPrefix.length ? ", prefix: " + self.options.propertyPrefix : "")); 75 | task.runtimeInfo[self.options.propertyPrefix + "healthy"] = false; 76 | self.setProperties(task, false); 77 | self.scheduler.emit(self.options.errorEvent, task); 78 | } else if (task.runtimeInfo[self.options.propertyPrefix + "healthy"] === false) { 79 | self.scheduler.emit(self.options.errorEvent, task); 80 | } 81 | }; 82 | 83 | 84 | TaskHealthHelper.prototype.checkInstance = function (task) { 85 | 86 | var self = this; 87 | 88 | if (task.runtimeInfo && task.runtimeInfo.state === "TASK_RUNNING" && self.taskFilter(task.name)) { 89 | if (task.runtimeInfo.network && task.runtimeInfo.network.hostname && task.runtimeInfo.network.ports && task.runtimeInfo.network.ports[self.options.portIndex]) { 90 | var req = http.request(self.healthRequestCreate(task.runtimeInfo.network.hostname, task.runtimeInfo.network.ports[self.options.portIndex]), function (res) { 91 | if (self.options.statusCodes.indexOf(res.statusCode) > -1) { 92 | 93 | var value = false; 94 | 95 | if (self.options.checkBodyFunction) { 96 | var responseBodyBuilder = ''; 97 | 98 | res.on("data", function (chunk) { 99 | responseBodyBuilder += chunk; 100 | }); 101 | 102 | res.on("end", function () { 103 | value = self.options.checkBodyFunction.call(self, task, responseBodyBuilder); 104 | self.logger.debug("Checking the response body: " + value); 105 | 106 | if (value) { 107 | task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] = 0; 108 | task.runtimeInfo[self.options.propertyPrefix + "healthy"] = value; 109 | self.setProperties(task, value); 110 | } else { 111 | self.setCheckFailed.call(self, task); 112 | } 113 | 114 | }); 115 | } else { 116 | task.runtimeInfo[self.options.propertyPrefix + "checkFailCount"] = 0; 117 | task.runtimeInfo[self.options.propertyPrefix + "healthy"] = true; 118 | self.setProperties(task, true); 119 | } 120 | 121 | } else { 122 | self.setCheckFailed.call(self, task); 123 | } 124 | res.resume(); 125 | }); 126 | req.on("error", function (error) { 127 | self.logger.error("Error checking task health:" + JSON.stringify(error) + (self.options.propertyPrefix.length ? ", prefix: " + self.options.propertyPrefix : "")); 128 | self.setCheckFailed.call(self, task); 129 | }); 130 | req.end(); 131 | } 132 | } 133 | }; 134 | 135 | TaskHealthHelper.prototype.setProperties = function (task, value) { 136 | var self = this; 137 | self.options.additionalProperties.forEach(function (property) { 138 | // If healthy or setting unhealthy 139 | if (value || property.setUnhealthy) { 140 | var propertyValue = value; 141 | if (property.inverse) { 142 | propertyValue = !value; 143 | } 144 | task.runtimeInfo[property.name] = propertyValue; 145 | } 146 | }); 147 | }; 148 | 149 | TaskHealthHelper.prototype.stopHealthCheck = function () { 150 | var self = this; 151 | 152 | if (self.interval) { 153 | clearInterval(self.interval); 154 | self.interval = null; 155 | } 156 | }; 157 | 158 | TaskHealthHelper.prototype.setupHealthCheck = function () { 159 | var self = this; 160 | 161 | self.stopHealthCheck(); 162 | self.interval = setInterval(self.checkRunningInstances, self.options.interval * 1000); 163 | }; 164 | 165 | module.exports = TaskHealthHelper; 166 | -------------------------------------------------------------------------------- /lib/taskHelper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var lib = require("requirefrom")("lib"); 4 | var Mesos = require("./mesos")().getMesos(); 5 | var Builder = lib("builder"); 6 | 7 | /** 8 | * Represents a TaskHelper object 9 | * @constructor 10 | * @param {object} scheduler - The scheduler object. 11 | */ 12 | function TaskHelper(scheduler) { 13 | if (!(this instanceof TaskHelper)) { 14 | return new TaskHelper(scheduler); 15 | } 16 | var self = this; 17 | self.zkClient = scheduler.zkClient; 18 | self.scheduler = scheduler; 19 | self.logger = scheduler.logger; 20 | self.zkServicePath = self.scheduler.zkServicePath; 21 | } 22 | 23 | /** 24 | * Load the task nodes belonging to the framework from ZooKeeper. 25 | */ 26 | TaskHelper.prototype.loadTasks = function() { 27 | var self = this; 28 | self.zkClient.getChildren(self.zkServicePath + "/tasks", function (error, children, stat) { 29 | if (error) { 30 | self.logger.error("Could not load task information."); 31 | // We're ready to subscribe 32 | self.scheduler.emit("ready"); 33 | } else if (children && children.length) { 34 | var childStates = {}; 35 | children.forEach(function (child) { 36 | self.zkClient.getData(self.zkServicePath + "/tasks/" + child, function (error, data, stat) { 37 | if (error || !data) { 38 | self.logger.error("Could not load task information for " + child); 39 | if (!error) { 40 | self.deleteTask(child); 41 | } 42 | childStates[child] = {'loaded': false}; 43 | self.logger.debug("childStates length " + Object.keys(childStates).length.toString() + " children.length " + children.length.toString()); 44 | if (Object.keys(childStates).length === children.length) { 45 | // We're ready to subscribe 46 | self.scheduler.emit("ready"); 47 | } 48 | return; 49 | } 50 | var pending = self.scheduler.pendingTasks; 51 | self.scheduler.pendingTasks = []; 52 | var task = JSON.parse(data.toString()); 53 | self.logger.debug("Loading task: " + JSON.stringify(task)); 54 | var found = false; 55 | var i = 0; 56 | var pendingTask; 57 | function addVars(variable) { 58 | // Check if variable name is either HOST or PORT# -> Set by this framework when starting a task - copy it to the loaded task 59 | if (variable.name.match(/^HOST$/) !== null || variable.name.match(/^PORT[0-9]+/) !== null) { 60 | // Add all matching (non-user-defined) environment variables 61 | pendingTask.commandInfo.environment.variables.push(variable); 62 | } 63 | } 64 | for (i = 0; i < pending.length; i += 1) { 65 | pendingTask = pending[i]; 66 | self.logger.debug("Pending task: \"" + JSON.stringify(pendingTask) + "\""); 67 | if (pendingTask.name === task.name) { 68 | if (task.runtimeInfo && task.runtimeInfo.agentId && (task.runtimeInfo.state === "TASK_RUNNING" || task.runtimeInfo.state === "TASK_STAGING")) { 69 | pendingTask.runtimeInfo = task.runtimeInfo; 70 | pendingTask.taskId = task.taskId; 71 | if (task.commandInfo && task.commandInfo.environment && task.commandInfo.environment.variables && task.commandInfo.environment.variables.length > 0) { 72 | if (!pendingTask.commandInfo) { 73 | pendingTask.commandInfo = new Builder("mesos.CommandInfo") 74 | .setEnvironment(new Mesos.Environment([])) 75 | .setShell(false); 76 | } 77 | if (!pendingTask.commandInfo.environment) { 78 | pendingTask.commandInfo.environment = new Mesos.Environment([]); 79 | } 80 | // Iterate over all environment variables 81 | task.commandInfo.environment.variables.forEach(addVars); 82 | } 83 | self.scheduler.launchedTasks.push(pendingTask); 84 | pending.splice(i, 1); 85 | self.scheduler.reconcileTasks.push(pendingTask); 86 | } else { 87 | self.deleteTask(task.taskId); 88 | } 89 | found = true; 90 | break; 91 | } 92 | } 93 | if (!found) { 94 | self.logger.info("Setting task ID " + task.taskId + " to be killed"); 95 | self.scheduler.killTasks.push(task); 96 | } 97 | self.scheduler.pendingTasks = pending; 98 | childStates[child] = {'loaded': true}; 99 | self.logger.debug("childStates length " + Object.keys(childStates).length.toString() + " children.length " + children.length.toString()); 100 | if (Object.keys(childStates).length === children.length) { 101 | // We're ready to subscribe 102 | self.scheduler.emit("ready"); 103 | } 104 | }); 105 | }); 106 | } else { 107 | // We're ready to subscribe - no tasks 108 | self.scheduler.emit("ready"); 109 | } 110 | }); 111 | }; 112 | 113 | /** 114 | * Save task nodes from ZooKeeper. 115 | * @param {object} task - The task object which should be persisted to ZooKeeper. 116 | */ 117 | TaskHelper.prototype.saveTask = function (task) { 118 | var self = this; 119 | var data = new Buffer(JSON.stringify(task)); 120 | // Seperating path creation from data save due to various client bugs. 121 | self.zkClient.mkdirp(self.zkServicePath+"/tasks/" + task.taskId, function (error, stat){ 122 | if (error) { 123 | self.logger.error("Got error when creating task node in ZK " + task.name + " ID " + task.taskId + " data: " + error); 124 | return; 125 | } 126 | self.zkClient.setData(self.zkServicePath+"/tasks/" + task.taskId, data, function (error, stat) { 127 | if (error) { 128 | self.logger.error("Got error when saving task " + task.name + " ID " + task.taskId + " data: " + error); 129 | return; 130 | } 131 | self.logger.debug("Saved task " + task.name + " ID " + task.taskId); 132 | }); 133 | }); 134 | }; 135 | 136 | /** 137 | * Delete task nodes from ZooKeeper. 138 | * @param {string} taskId - The id of the task which should be deleted from ZooKeeper. 139 | */ 140 | TaskHelper.prototype.deleteTask = function (taskId) { 141 | var self = this; 142 | self.zkClient.remove(self.zkServicePath + "/tasks/" + taskId, function (error) { 143 | if (error) { 144 | self.logger.error("Error deleting task ID " + taskId + " from zookeeper"); 145 | } else { 146 | self.logger.debug("Deleted task " + taskId + " from zookeeper"); 147 | } 148 | }); 149 | }; 150 | 151 | module.exports = TaskHelper; 152 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobilg/mesos-framework/6d5287f5ef7cc1844833c3bbc97fae40fe0d3ce5/logs/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mesos-framework", 3 | "version": "0.7.0", 4 | "description": "A wrapper around the Mesos HTTP APIs for Schedulers and Executors. Write your Mesos framework in pure JavaScript!", 5 | "keywords": [ 6 | "mesos", 7 | "framework", 8 | "http", 9 | "api", 10 | "wrapper", 11 | "base", 12 | "scheduler", 13 | "executor" 14 | ], 15 | "main": "index.js", 16 | "scripts": { 17 | "docs": "jsdoc --configure .jsdoc.json --verbose", 18 | "publish-please": "publish-please", 19 | "prepublishOnly": "publish-please guard", 20 | "test": "nyc mocha" 21 | }, 22 | "author": "TobiLG", 23 | "license": "Apache-2.0", 24 | "nyc": { 25 | "reporter": [ 26 | "html" 27 | ], 28 | "report-dir": "./docs/coverage" 29 | }, 30 | "dependencies": { 31 | "lodash": "^4.17.5", 32 | "node-zookeeper-client": "^0.2.2", 33 | "protobufjs": "^5.0.2", 34 | "requirefrom": "^0.2.1", 35 | "uuid": "^3.2.1", 36 | "winston": "^2.4.0", 37 | "winston-daily-rotate-file": "^1.7.2" 38 | }, 39 | "devDependencies": { 40 | "chai": "^3.5.0", 41 | "chai-as-promised": "^6.0.0", 42 | "chalk": "~1.1.3", 43 | "jsdoc": "^3.5.5", 44 | "minami": "^1.2.3", 45 | "mocha": "^3.4.2", 46 | "mock-req": "^0.2.0", 47 | "mock-res": "^0.3.3", 48 | "nyc": "^11.4.1", 49 | "publish-please": "~2.3.1", 50 | "run-sequence": "~1.2.2", 51 | "sinon": "^1.17.7" 52 | }, 53 | "repository": { 54 | "type": "git", 55 | "url": "https://github.com/tobilg/mesos-framework.git" 56 | }, 57 | "bugs": { 58 | "url": "https://github.com/tobilg/mesos-framework/issues" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /proto/1.5.0/executor.proto: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. 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 | syntax = "proto2"; 18 | 19 | //import "mesos/v1/mesos.proto"; 20 | 21 | package mesos.executor; 22 | 23 | option java_package = "org.apache.mesos.executor"; 24 | option java_outer_classname = "Protos"; 25 | 26 | 27 | /** 28 | * Executor event API. 29 | * 30 | * An event is described using the standard protocol buffer "union" 31 | * trick, see https://developers.google.com/protocol-buffers/docs/techniques#union. 32 | */ 33 | message Event { 34 | // Possible event types, followed by message definitions if 35 | // applicable. 36 | enum Type { 37 | // This must be the first enum value in this list, to 38 | // ensure that if 'type' is not set, the default value 39 | // is UNKNOWN. This enables enum values to be added 40 | // in a backwards-compatible way. See: MESOS-4997. 41 | UNKNOWN = 0; 42 | 43 | SUBSCRIBED = 1; // See 'Subscribed' below. 44 | LAUNCH = 2; // See 'Launch' below. 45 | LAUNCH_GROUP = 8; // See 'LaunchGroup' below. 46 | KILL = 3; // See 'Kill' below. 47 | ACKNOWLEDGED = 4; // See 'Acknowledged' below. 48 | MESSAGE = 5; // See 'Message' below. 49 | ERROR = 6; // See 'Error' below. 50 | 51 | // Received when the agent asks the executor to shutdown/kill itself. 52 | // The executor is then required to kill all its active tasks, send 53 | // `TASK_KILLED` status updates and gracefully exit. The executor 54 | // should terminate within a `MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD` 55 | // (an environment variable set by the agent upon executor startup); 56 | // it can be configured via `ExecutorInfo.shutdown_grace_period`. If 57 | // the executor fails to do so, the agent will forcefully destroy the 58 | // container where the executor is running. The agent would then send 59 | // `TASK_LOST` updates for any remaining active tasks of this executor. 60 | // 61 | // NOTE: The executor must not assume that it will always be allotted 62 | // the full grace period, as the agent may decide to allot a shorter 63 | // period and failures / forcible terminations may occur. 64 | // 65 | // TODO(alexr): Consider adding a duration field into the `Shutdown` 66 | // message so that the agent can communicate when a shorter period 67 | // has been allotted. 68 | SHUTDOWN = 7; 69 | } 70 | 71 | // First event received when the executor subscribes. 72 | // The 'id' field in the 'framework_info' will be set. 73 | message Subscribed { 74 | required ExecutorInfo executor_info = 1; 75 | required FrameworkInfo framework_info = 2; 76 | required AgentInfo agent_info = 3; 77 | 78 | // Uniquely identifies the container of an executor run. 79 | optional ContainerID container_id = 4; 80 | } 81 | 82 | // Received when the framework attempts to launch a task. Once 83 | // the task is successfully launched, the executor must respond with 84 | // a TASK_RUNNING update (See TaskState in v1/mesos.proto). 85 | message Launch { 86 | required TaskInfo task = 1; 87 | } 88 | 89 | // Received when the framework attempts to launch a group of tasks atomically. 90 | // Similar to `Launch` above the executor must send TASK_RUNNING updates for 91 | // tasks that are successfully launched. 92 | message LaunchGroup { 93 | required TaskGroupInfo task_group = 1; 94 | } 95 | 96 | // Received when the scheduler wants to kill a specific task. Once 97 | // the task is terminated, the executor should send a TASK_KILLED 98 | // (or TASK_FAILED) update. The terminal update is necessary so 99 | // Mesos can release the resources associated with the task. 100 | message Kill { 101 | required TaskID task_id = 1; 102 | 103 | // If set, overrides any previously specified kill policy for this task. 104 | // This includes 'TaskInfo.kill_policy' and 'Executor.kill.kill_policy'. 105 | // Can be used to forcefully kill a task which is already being killed. 106 | optional KillPolicy kill_policy = 2; 107 | } 108 | 109 | // Received when the agent acknowledges the receipt of status 110 | // update. Schedulers are responsible for explicitly acknowledging 111 | // the receipt of status updates that have 'update.status().uuid()' 112 | // field set. Unacknowledged updates can be retried by the executor. 113 | // They should also be sent by the executor whenever it 114 | // re-subscribes. 115 | message Acknowledged { 116 | required TaskID task_id = 1; 117 | required bytes uuid = 2; 118 | } 119 | 120 | // Received when a custom message generated by the scheduler is 121 | // forwarded by the agent. Note that this message is not 122 | // interpreted by Mesos and is only forwarded (without reliability 123 | // guarantees) to the executor. It is up to the scheduler to retry 124 | // if the message is dropped for any reason. 125 | message Message { 126 | required bytes data = 1; 127 | } 128 | 129 | // Received in case the executor sends invalid calls (e.g., 130 | // required values not set). 131 | // TODO(arojas): Remove this once the old executor driver is no 132 | // longer supported. With HTTP API all errors will be signaled via 133 | // HTTP response codes. 134 | message Error { 135 | required string message = 1; 136 | } 137 | 138 | // Type of the event, indicates which optional field below should be 139 | // present if that type has a nested message definition. 140 | // Enum fields should be optional, see: MESOS-4997. 141 | optional Type type = 1; 142 | 143 | optional Subscribed subscribed = 2; 144 | optional Acknowledged acknowledged = 3; 145 | optional Launch launch = 4; 146 | optional LaunchGroup launch_group = 8; 147 | optional Kill kill = 5; 148 | optional Message message = 6; 149 | optional Error error = 7; 150 | } 151 | 152 | 153 | /** 154 | * Executor call API. 155 | * 156 | * Like Event, a Call is described using the standard protocol buffer 157 | * "union" trick (see above). 158 | */ 159 | message Call { 160 | // Possible call types, followed by message definitions if 161 | // applicable. 162 | enum Type { 163 | // See comments above on `Event::Type` for more details on this enum value. 164 | UNKNOWN = 0; 165 | 166 | SUBSCRIBE = 1; // See 'Subscribe' below. 167 | UPDATE = 2; // See 'Update' below. 168 | MESSAGE = 3; // See 'Message' below. 169 | } 170 | 171 | // Request to subscribe with the agent. If subscribing after a disconnection, 172 | // it must include a list of all the tasks and updates which haven't been 173 | // acknowledged by the scheduler. 174 | message Subscribe { 175 | repeated TaskInfo unacknowledged_tasks = 1; 176 | repeated Update unacknowledged_updates = 2; 177 | } 178 | 179 | // Notifies the scheduler that a task has transitioned from one 180 | // state to another. Status updates should be used by executors 181 | // to reliably communicate the status of the tasks that they 182 | // manage. It is crucial that a terminal update (see TaskState 183 | // in v1/mesos.proto) is sent to the scheduler as soon as the task 184 | // terminates, in order for Mesos to release the resources allocated 185 | // to the task. It is the responsibility of the scheduler to 186 | // explicitly acknowledge the receipt of a status update. See 187 | // 'Acknowledged' in the 'Events' section above for the semantics. 188 | message Update { 189 | required TaskStatus status = 1; 190 | } 191 | 192 | // Sends arbitrary binary data to the scheduler. Note that Mesos 193 | // neither interprets this data nor makes any guarantees about the 194 | // delivery of this message to the scheduler. 195 | // See 'Message' in the 'Events' section. 196 | message Message { 197 | required bytes data = 2; 198 | } 199 | 200 | // Identifies the executor which generated this call. 201 | required ExecutorID executor_id = 1; 202 | required FrameworkID framework_id = 2; 203 | 204 | // Type of the call, indicates which optional field below should be 205 | // present if that type has a nested message definition. 206 | // In case type is SUBSCRIBED, no message needs to be set. 207 | // See comments on `Event::Type` above on the reasoning behind this 208 | // field being optional. 209 | optional Type type = 3; 210 | 211 | optional Subscribe subscribe = 4; 212 | optional Update update = 5; 213 | optional Message message = 6; 214 | } -------------------------------------------------------------------------------- /proto/all.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * This is used to import/concatenate all required protobufs 3 | */ 4 | import "1.5.0/mesos.proto"; 5 | import "1.5.0/scheduler.proto"; 6 | import "1.5.0/executor.proto"; --------------------------------------------------------------------------------