Skip to content

Commit

Permalink
Add role field to apps and tasks
Browse files Browse the repository at this point in the history
Updated documentation for project setup

JIRA issues: MARATHON-8675
  • Loading branch information
Tim Harper committed Aug 15, 2019
2 parents a5babc7 + b9fa3a2 commit d892fcc
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 27 deletions.
26 changes: 25 additions & 1 deletion README.md
Expand Up @@ -63,6 +63,14 @@ you've installed and properly configured the following software:
* Set up a CORS proxy on your machine to proxy the UI requests to your running
Marathon instance (e.g. via Corsproxy)

##### NVM
As the required NPM version is pretty old, it's a good idea to use nvm to install
the specific version:

brew install nvm
nvm install v5.4.1
nvm use v5.4.1

##### 🤖 1. Install all dependencies

npm install
Expand All @@ -88,7 +96,23 @@ you've installed and properly configured the following software:

for a `browsersync` live-reload server.


##### 4. CORS Proxy
If you're running a local marathon, CORS will prevent the browser from accessing
it. There's a simple CORS proxy that forwards requests to the different local ports,
circumventing that issue:

```
npm install -g corsproxy
```

Adjust your dev config to use URLs like these:
```
apiURL: "http://localhost:1337/localhost:8080/"
rootUrl: "http://localhost:1337/localhost:4200/"
```

Then you can reach the local running ui under the root URL.

---

##### 🐳 Prerequisites
Expand Down
9 changes: 9 additions & 0 deletions src/js/components/AppConfigEditFormComponent.jsx
Expand Up @@ -253,6 +253,7 @@ var AppConfigEditFormComponent = React.createClass({
disk: "disk",
gpus: "gpus",
instances: "instances",
role: "role",
cmd: "cmd"
})
});
Expand Down Expand Up @@ -376,6 +377,14 @@ var AppConfigEditFormComponent = React.createClass({
<input min="0" step="1" type="number"/>
</FormGroupComponent>
</div>
<div className="col-sm-3">
<FormGroupComponent fieldId="role" label="Role"
errorMessage={this.getErrorMessage("role")}
value={state.fields.role}
onChange={this.handleFieldUpdate}>
<input ref="role"/>
</FormGroupComponent>
</div>
</div>
<FormGroupComponent errorMessage={this.getErrorMessage("cmd")}
fieldId="cmd"
Expand Down
2 changes: 2 additions & 0 deletions src/js/components/AppVersionComponent.jsx
Expand Up @@ -261,6 +261,8 @@ var AppVersionComponent = React.createClass({
{dependenciesNode}
<dt>Labels</dt>
{labelsNode}
<dt>Allocation Role</dt>
{invalidateValue(appVersion.role)}
<dt>Resource Roles</dt>
{acceptedResourceRoles}
<dt>Container</dt>
Expand Down
11 changes: 11 additions & 0 deletions src/js/components/TaskDetailComponent.jsx
Expand Up @@ -151,6 +151,15 @@ var TaskDetailComponent = React.createClass({
return <dd>{task.status}</dd>;
},

getRole: function () {
var props = this.props;
var task = props.task;
if (task == null || task.role == null) {
return <dd className="text-muted">Unknown</dd>;
}
return <dd>{task.role}</dd>;
},

getVersion: function () {
var props = this.props;
var task = props.task;
Expand Down Expand Up @@ -229,6 +238,8 @@ var TaskDetailComponent = React.createClass({
{this.getServiceDiscovery()}
<dt>Status</dt>
{this.getStatus()}
<dt>Role</dt>
{this.getRole()}
{timeFields}
<dt>Version</dt>
{this.getVersion()}
Expand Down
4 changes: 3 additions & 1 deletion src/js/config/config.template.js
@@ -1,10 +1,12 @@
import config from "./config";

var configDev = Object.assign(config, {
// Defines the Marathon API URL,
// Defines the Marathon API URL, ending in a '/', for example
// For example: http://localhost:1337/localhost:8080/
// leave empty to use the same as the UI is served.
apiURL: "",
// If the UI is served through a proxied URL, this can be set here.
// For example: http://localhost:1337/localhost:4200/
rootUrl: ""
});
export default configDev;
2 changes: 2 additions & 0 deletions src/js/constants/AppConfigDefaults.js
Expand Up @@ -3,6 +3,7 @@ import Util from "../helpers/Util";
// Default values for the config form editor
export const AppConfigFormDefaultValues = Util.deepFreeze({
id: "",
role: "",
cmd: "",
cpus: 1,
mem: 128,
Expand All @@ -14,6 +15,7 @@ export const AppConfigFormDefaultValues = Util.deepFreeze({
// Default values for an 'empty' app config, or the JSON editor
export const AppConfigDefaultValues = Util.deepFreeze({
id: null,
role: null,
cmd: null,
cpus: 1,
mem: 128,
Expand Down
5 changes: 5 additions & 0 deletions src/js/stores/AppFormStore.js
Expand Up @@ -47,6 +47,9 @@ const validationRules = {
AppFormValidators.appIdValidChars,
AppFormValidators.appIdWellFormedPath
],
"role": [
AppFormValidators.roleNotEmpty
],
"constraints": [AppFormValidators.constraints],
"containerVolumes": [
AppFormValidators.containerVolumesContainerPathIsValid,
Expand Down Expand Up @@ -97,6 +100,7 @@ const validationRules = {
*/
const resolveFieldIdToAppKeyMap = {
appId: "id",
role: "role",
acceptedResourceRoles: "acceptedResourceRoles",
cmd: "cmd",
constraints: "constraints",
Expand Down Expand Up @@ -132,6 +136,7 @@ const responseAttributePathToFieldIdMap = {
"id": "appId",
"apps": "appId",
"/id": "appId",
"/role": "role",
"/acceptedResourceRoles": "acceptedResourceRoles",
"/cmd": "cmd",
"/constraints": "constraints",
Expand Down
2 changes: 2 additions & 0 deletions src/js/stores/validators/AppFormValidators.js
Expand Up @@ -22,6 +22,8 @@ function isValidPath(value) {
}

const AppFormValidators = {
roleNotEmpty: (str) => !Util.isStringAndEmpty(str),

appIdNotEmpty: (str) => !Util.isStringAndEmpty(str),

appIdNoWhitespaces: (str) => str.match(/ /g) == null,
Expand Down
2 changes: 1 addition & 1 deletion src/test/scenarios/displayTaskDetails.test.js
Expand Up @@ -70,7 +70,7 @@ describe("TaskDetailComponent", function () {
var version = this.component
.find(".task-details")
.children()
.at(14)
.at(16)
.find("time")
.props()
.dateTime;
Expand Down
53 changes: 29 additions & 24 deletions src/test/units/AppVersionComponent.test.js
Expand Up @@ -10,6 +10,7 @@ describe("AppVersionComponent", function () {
beforeEach(function () {
this.model = {
"id": "/sleep10",
"role": "*",
"cmd": "sleep 10",
"args": ["arg1", "arg2"],
"user": "testuser",
Expand Down Expand Up @@ -89,88 +90,92 @@ describe("AppVersionComponent", function () {
expect(this.rows.at(9).text().trim()).to.equal("Unspecified");
});

it("has correct role", function () {
expect(this.rows.at(11).text().trim()).to.equal("*");
});

it("has correct accepted resource roles", function () {
expect(this.rows.at(11).text().trim()).to.equal("Unspecified");
expect(this.rows.at(13).text().trim()).to.equal("Unspecified");
});

it("has correct container", function () {
expect(this.rows.at(13).text().trim()).to.equal("Unspecified");
expect(this.rows.at(15).text().trim()).to.equal("Unspecified");
});

it("has correct cpus", function () {
expect(this.rows.at(15).text().trim()).to.equal("0.1");
expect(this.rows.at(17).text().trim()).to.equal("0.1");
});

it("has correct environment", function () {
expect(this.rows.at(17).text().trim()).to.equal("Unspecified");
expect(this.rows.at(19).text().trim()).to.equal("Unspecified");
});

it("has correct executor", function () {
expect(this.rows.at(19).text().trim()).to.equal("Unspecified");
expect(this.rows.at(21).text().trim()).to.equal("Unspecified");
});

it("has correct health checks", function () {
var healthChecks = this.rows.at(21).text().trim();
var healthChecks = this.rows.at(23).text().trim();
expect(healthChecks).to.equal(
JSON.stringify(this.model.healthChecks, null, 2)
);
});

it("has correct number of instances", function () {
expect(this.rows.at(23).text().trim()).to.equal("14");
expect(this.rows.at(25).text().trim()).to.equal("14");
});

it("has correct ip address", function () {
var ipAddress = this.rows.at(25).text().trim();
var ipAddress = this.rows.at(27).text().trim();
expect(ipAddress).to.equal(
JSON.stringify(this.model.ipAddress, null, 2)
);
});

it("has correct amount of memory", function () {
var children = this.rows.at(27).props().children;
var children = this.rows.at(29).props().children;
expect(children[0]).to.equal(16.0);
expect(children[2]).to.equal("MiB");
});

it("has correct amount of disk space", function () {
var children = this.rows.at(29).props().children;
var children = this.rows.at(31).props().children;
expect(children[0]).to.equal(0.0);
expect(children[2]).to.equal("MiB");
});

it("has correct backoff factor", function () {
var children = this.rows.at(37).props().children;
var children = this.rows.at(39).props().children;
expect(children[0]).to.equal(1.15);
});

it("has correct backoff", function () {
var children = this.rows.at(39).props().children;
var children = this.rows.at(41).props().children;
expect(children[0]).to.equal(1);
expect(children[2]).to.equal("seconds");
});

it("has correct max launch delay", function () {
var children = this.rows.at(41).props().children;
var children = this.rows.at(43).props().children;
expect(children[0]).to.equal(3600);
expect(children[2]).to.equal("seconds");
});

it("has correct URIs", function () {
expect(this.rows.at(43).text().trim()).to.equal("Unspecified");
expect(this.rows.at(45).text().trim()).to.equal("Unspecified");
});

it("has correct User", function () {
expect(this.rows.at(45).props().children[0]).to.equal("testuser");
expect(this.rows.at(47).props().children[0]).to.equal("testuser");
});

it("has correct args", function () {
expect(this.rows.at(47).text()).to.equal("arg1");
expect(this.rows.at(48).text()).to.equal("arg2");
expect(this.rows.at(49).text()).to.equal("arg1");
expect(this.rows.at(50).text()).to.equal("arg2");
});

it("has correct version", function () {
expect(this.rows.at(50).props().children[0])
expect(this.rows.at(52).props().children[0])
.to.equal("2015-06-29T12:57:02.269Z");
});

Expand All @@ -183,11 +188,11 @@ describe("AppVersionComponent", function () {
this.component = mount(<AppVersionComponent appVersion={this.model} />);
this.table = this.component.find("dl.dl-horizontal");
this.rows = this.table.children();
expect(this.rows.at(17).props().children)
expect(this.rows.at(19).props().children)
.to.equal("a=A");
expect(this.rows.at(18).props().children)
expect(this.rows.at(20).props().children)
.to.equal("b=B");
expect(this.rows.at(19).props().children)
expect(this.rows.at(21).props().children)
.to.equal("c=C");
});

Expand All @@ -201,7 +206,7 @@ describe("AppVersionComponent", function () {
this.component = mount(<AppVersionComponent appVersion={this.model} />);
this.table = this.component.find("dl.dl-horizontal");
this.rows = this.table.children();
expect(this.rows.at(43).text().trim()).to.equal("http://localhost/test");
expect(this.rows.at(45).text().trim()).to.equal("http://localhost/test");
});

it("has multiple uris", function () {
Expand All @@ -219,7 +224,7 @@ describe("AppVersionComponent", function () {
this.component = mount(<AppVersionComponent appVersion={this.model} />);
this.table = this.component.find("dl.dl-horizontal");
this.rows = this.table.children();
expect(this.rows.at(43).text().trim()).to.equal("http://localhost/test");
expect(this.rows.at(44).text().trim()).to.equal("http://localhost/test2");
expect(this.rows.at(45).text().trim()).to.equal("http://localhost/test");
expect(this.rows.at(46).text().trim()).to.equal("http://localhost/test2");
});
});

0 comments on commit d892fcc

Please sign in to comment.