frosner / cluster-broccoli Goto Github PK
View Code? Open in Web Editor NEWSelf service for Nomad based on templates.
License: Apache License 2.0
Self service for Nomad based on templates.
License: Apache License 2.0
The black-box test should bring up the docker container of Cluster Broccoli, also start Nomad and/or Consul if required and then execute the integration tests.
Inside the travis build, after the unit tests succeeded, it should build the docker image, run it together with Nomad and Consul and then execute the integration tests.
When the instances are persisted in a file it needs to be locked to avoid concurrent access. However, this prevents us from starting multiple Broccoli instances for load balancing or having different configurations.
Support CouchDB as a persistent instance storage and talk to it over the HTTP API.
This requires us to rework the configuration properties:
broccoli.templates.storage.type
how to 'persist' templates (currently only file
supported, which is the directory structure)broccoli.templates.storage.url
path to look for templates (folder path if type is fs
)broccoli.instances.storage.type
how to 'persist' templates (fs
or couchdb
)broccoli.instances.storage.url
path to look for instances (directory if fs
, HTTP endpoint of CouchDB if couchdb
)broccoli.templatesDir
and broccoli.instancesFile
(search all code and documentation)FIXME
s and no TODO
s left around this topicRight now, when the InstanceService
receives a message that Consul is not reachable, it does nothing.
It should not show services but a warning instead, that Consul is not reachable.
Sometimes when we update the templates and restart Broccoli, we might want to update also the instances in order to apply the new template. The usual way would be to stop them and recreate them. However, this is tedious and requires either some manual work or at least saving the JSON representation of all the instances.
Also, sometimes you might want to use the same instance but just transfer it to a different template.
There should be a button to convert an instance to an existing current template version.
Use POST and add another field in the JSON which indicates that the instance should update it's template before changing the parameter values.
We will have Nomad jobs that don't match any template. This can happen if you change the name of a template and forget to stop old ones.
Show them in a separate category. However, it should not be allowed to start or stop them. They should also respect the prefix (if defined), i.e. you should only see unmatched instances that match the prefix but no template.
InstanceService.updateStatusesBasedOnNomad
is the place where we need to change.
Blocked loading mixed active content "http://ajax.googleapis.com/ajax/libs/angularjs/1.5.2/angular.min.js"[Learn More]
Blocked loading mixed active content "http://cdnjs.cloudflare.com/ajax/libs/restangular/1.3.1/restangular.min.js"[Learn More]
Include both of them as https.
An advanced user of Cluster Broccoli needs to know how to create new templates.
Quick how-to + reference to the example template folder, covering:
description.txt
template.json
{{}}
nomad run -output
){{id}}
as Nomad job ID, because it won't work otherwise (relates to #16)https://github.com/FRosner/cluster-broccoli/wiki/Template-Definition
Right now, the example templates depend on snapshot versions of the docker images and wrappers etc.
Tag the examples and point to the tags.
When discovering a service of an instance through Consul, we only get address and port, but not protocol.
Right now, we encode the protocol as tags (e.g. protocol:http
). We should decide whether this is the way to go (esp. because :
is not supported through the Consul DNS interface and throws warnings) and then document how to do it.
We will go for protocol-http
.
Progress on https://github.com/FRosner/cluster-broccoli/projects/2
When a nomad job is started through the UI, it would be nice to be able to get logs about this job. A Broccoli instance can create one (one-time batch or system jobs) or multiple (periodic jobs) Nomad jobs. A Nomad job has one or multiple allocations which can be pending, running, failing or finishing. The UI should reflect this in a consistent but understandable way.
The Broccoli HTTP API should have a possibility to query for out and err logs of an instance and the UI should show it somewhere.
[error] a.a.OneForOneStrategy - Unable to provision, see the following errors:
1) Error injecting constructor, java.util.NoSuchElementException: None.get
at de.frosner.broccoli.services.InstanceService.<init>(InstanceService.scala:21)
at de.frosner.broccoli.services.InstanceService.class(InstanceService.scala:21)
while locating de.frosner.broccoli.services.InstanceService
1 error
akka.actor.ActorInitializationException: exception during creation
at akka.actor.ActorInitializationException$.apply(Actor.scala:166) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.actor.ActorCell.create(ActorCell.scala:596) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:456) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.actor.ActorCell.systemInvoke(ActorCell.scala:478) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:263) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.dispatch.Mailbox.run(Mailbox.scala:219) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:397) [com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) [org.scala-lang.scala-library-2.10.6.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) [org.scala-lang.scala-library-2.10.6.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) [org.scala-lang.scala-library-2.10.6.jar:na]
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, java.util.NoSuchElementException: None.get
at de.frosner.broccoli.services.InstanceService.<init>(InstanceService.scala:21)
at de.frosner.broccoli.services.InstanceService.class(InstanceService.scala:21)
while locating de.frosner.broccoli.services.InstanceService
1 error
at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051) ~[com.google.inject.guice-4.0.jar:na]
at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:321) ~[com.typesafe.play.play_2.10-2.4.6.jar:2.4.6]
at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:316) ~[com.typesafe.play.play_2.10-2.4.6.jar:2.4.6]
at play.api.libs.concurrent.ActorRefProvider$$anonfun$1.apply(Akka.scala:209) ~[com.typesafe.play.play_2.10-2.4.6.jar:2.4.6]
at play.api.libs.concurrent.ActorRefProvider$$anonfun$1.apply(Akka.scala:209) ~[com.typesafe.play.play_2.10-2.4.6.jar:2.4.6]
at akka.actor.TypedCreatorFunctionConsumer.produce(Props.scala:346) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.actor.Props.newActor(Props.scala:255) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.actor.ActorCell.newActor(ActorCell.scala:552) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
at akka.actor.ActorCell.create(ActorCell.scala:578) ~[com.typesafe.akka.akka-actor_2.10-2.3.13.jar:na]
Caused by: java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:313) ~[org.scala-lang.scala-library-2.10.6.jar:na]
at scala.None$.get(Option.scala:311) ~[org.scala-lang.scala-library-2.10.6.jar:na]
at de.frosner.broccoli.services.InstanceService.<init>(InstanceService.scala:42) ~[cluster-broccoli.cluster-broccoli-0.1.0-SNAPSHOT-sans-externalized.jar:na]
at de.frosner.broccoli.services.InstanceService$$FastClassByGuice$$d986dc01.newInstance(<generated>) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.DefaultConstructionProxyFactory$1.newInstance(DefaultConstructionProxyFactory.java:61) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:105) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:85) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:267) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46) ~[com.google.inject.guice-4.0.jar:na]
Right now, a service is displayed as soon as it is discoverable. You will not see whether it is healthy. This yields to people clicking on Web-UI links that are not (yet) reachable.
Ask Consul whether the service is healthy and show this in the UI somehow (e.g. by not allowing to click or changing the color or something like this).
localhost:8500/v1/health/service/<service>?passing
returns an empty array if there is no service passing all health checks.
Right now, each template needs to have the job ID to be exactly {{id}}
, so that the mapping between an instance ID and a job ID works. Right now, the two are equal.
It is not clear and we should think about it, whether to set the instance ID based on the complete Nomad job ID instead of only the {{id}}
variable.
Example:
job "zeppelin-{{id}}" {
# ...
}
Here it might make sense to set the Broccoli instance ID to zeppelin-frank
instead of frank
, if ID = "frank".
Travis should push the image containing only the binaries and not activator. openjdk:8-jre should be used as a base image to be lean and small. The activator image can still remain in a different folder so people can use it for quick development.
It is quite boring and text-heavy to only have the name "zeppelin" and "jupyter".
Allow icon.svg
inside a template and add it to the front-end.
For the non-docker version,
After creating a new instance, it is immutable. This forces a user to stop his instance, recreate it and start it again. This can be really tedious if your templates contain a lot of parameters.
Allow updates on instances.
Updating instances will be done using the POST method on the instances/<id>
endpoint. I will deprecate the old POST endpoint which takes only a JSON string for updating an instance status (but keep it for compatibility reasons) and include status updates in it as well.
The POST request contains a JSON object which can be a partial instance. If you want to update the status, you'd have to post:
curl -v -H 'Content-Type: application/json' \
-X POST -d '{ "status": "running" }' \
'http://localhost:9000/api/v1/instances/my-http'
Allowed statuses are: "running"
and "stopped"
If you want to update the parameter values, you'd have to post:
curl -v -H 'Content-Type: application/json' \
-X POST -d '{ "parameterValues": { "id": "my-http", "cpu": "250" } }' \
'http://localhost:9000/api/v1/instances/my-http'
If a request is invalid (e.g. invalid key) HTTP status code 400 (invalid request) will be returned.
Right now, if you restart the web application, all instances are reset. The Nomad jobs will keep running but they are not visible in Broccoli.
Persist instances.
Sometimes we might want to allow customization but don't enforce it. There should be a way to define default values in the job templates.
{{name:cpu default:500}}
)Right now, all JS libraries are loaded from the internet. This has two problems. First, it doesn't work if there is no internet. Second, it is annoying if the internet connection is slow.
Is there any problem in just putting all JS files in assets?
Right now, services are advertised using the service address and port. This has several issues, the main one being that if nomad reschedules the job, using the IP might not allow finding it back. Also it is easier to remember.
activator dist
Currently, a line with a "running" service is looking red because the "Stop" button is red, and a line with a "stopped" service looks green because the "Start" button is green. This is misleading.
I would propose to have a green "running" and a red "stopped" status labels.
For action buttons, something like glyphicon-play and glyphicon-stop could be used.
It would be nice to see some more information about resource utilization.
Right now, GET /templates returns an array of template IDs. This is not extendable, if we wanted to add more information for each template.
Also the actual JSON template file should not get returned.
activator dist
Clicking on a service link will close the Broccoli UI.
Open link in a new tab.
var
s. Wenn members geändert werden müssen die case class kopieren Foo.copy(member = newValue)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Error</title>
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlFJREFUeNqUU8tOFEEUPVVdNV3dPe8xYRBnjGhmBgKjKzCIiQvBoIaNbly5Z+PSv3Aj7DSiP2B0rwkLGVdGgxITSCRIJGSMEQWZR3eVt5sEFBgTb/dN1yvnnHtPNTPG4PqdHgCMXnPRSZrpSuH8vUJu4DE4rYHDGAZDX62BZttHqTiIayM3gGiXQsgYLEvATaqxU+dy1U13YXapXptpNHY8iwn8KyIAzm1KBdtRZWErpI5lEWTXp5Z/vHpZ3/wyKKwYGGOdAYwR0EZwoezTYApBEIObyELl/aE1/83cp40Pt5mxqCKrE4Ck+mVWKKcI5tA8BLEhRBKJLjez6a7MLq7XZtp+yyOawwCBtkiBVZDKzRk4NN7NQBMYPHiZDFhXY+p9ff7F961vVcnl4R5I2ykJ5XFN7Ab7Gc61VoipNBKF+PDyztu5lfrSLT/wIwCxq0CAGtXHZTzqR2jtwQiXONma6hHpj9sLT7YaPxfTXuZdBGA02Wi7FS48YiTfj+i2NhqtdhP5RC8mh2/Op7y0v6eAcWVLFT8D7kWX5S9mepp+C450MV6aWL1cGnvkxbwHtLW2B9AOkLeUd9KEDuh9fl/7CEj7YH5g+3r/lWfF9In7tPz6T4IIwBJOr1SJyIGQMZQbsh5P9uBq5VJtqHh2mo49pdw5WFoEwKWqWHacaWOjQXWGcifKo6vj5RGS6zykI587XeUIQDqJSmAp+lE4qt19W5P9o8+Lma5DcjsC8JiT607lMVkdqQ0Vyh3lHhmh52tfNy78ajXv0rgYzv8nfwswANuk+7sD/Q0aAAAAAElFTkSuQmCC">
<style>
html, body, pre {
margin: 0;
padding: 0;
font-family: Monaco, 'Lucida Console', monospace;
background: #ECECEC;
}
h1 {
margin: 0;
background: #A31012;
padding: 20px 45px;
color: #fff;
text-shadow: 1px 1px 1px rgba(0,0,0,.3);
border-bottom: 1px solid #690000;
font-size: 28px;
}
p#detail {
margin: 0;
padding: 15px 45px;
background: #F5A0A0;
border-top: 4px solid #D36D6D;
color: #730000;
text-shadow: 1px 1px 1px rgba(255,255,255,.3);
font-size: 14px;
border-bottom: 1px solid #BA7A7A;
}
</style>
</head>
<body>
<h1>Oops, an error occurred</h1>
<p id="detail">
This exception has been logged with id <strong>70ljpnhk3</strong>.
</p>
</body>
</html>
activator dist
It is not possible to see if the Broccoli REST API is reachable or not from the JS front-end.
Add an indicator (like a green / red light or something).
The API should not be mixed with the front-end.
Move the rest API from the /
to /api/v1
When the template JSON is built in Instance
, people might be able to "inject" JSON. We might want to allow to configure an input sanitization (e.g. escaping quotes or other JSON characters). However as a user might want to allow JSON inside we should make it configurable whether you want to sanitize and how (e.g. escape quotes).
Make sanitization configurable. Should it be on a global level (all input), on a template-parameter level or both? => I think best is to actually treat text parameters as JSON text, which sanitizes it automatically. Thus when you can put "key" : {{value}}
instead of "key" : "{{value}}"
if {{value}}
is a text parameter.
And then we can just add another parameter type which we call "raw" in addition to "string". This relates to #71 also.
When creating a new instance, the focus is not inside the textbox.
Put the focus inside the text box.
Right now, the CSS is put in a style tag directly in the index.html
page.
Let's put it in a separate CSS file and include it.
{{spark-master}}
as a parameter will not work now because the regex is looking only for numbers and characters.
Also support -
and _
in the Template
regex.
Right now, templates are parsed off of a JSON template for the nomad job + a description text file + an image. In order to make this more structured and be prepared for also a create / update REST endpoint for templates later on, we might want to standardise it.
description.txt
, have another JSON document with meta information (like template name, description, etc.).Right now it is not possible to distinguish jobs created from Broccoli from normal Nomad jobs. Also it is not possible to use ACLs as they are based on prefixes.
Allow a configurable job prefix. It will be used to set the job ID and also for asking Nomad about the job status.
about
endpointbroccoli.instances.prefix
Relates to: #16
URI | Method | Action (Response Code) |
---|---|---|
/applications |
GET | JSON array of all available applications (200) |
/applications |
POST | operation not supported (405) |
/applications |
PUT | operation not supported (405) |
/applications |
DELETE | operation not supported (405) |
/applications/<app-id> |
GET | application properties: name, available configuration parameters (200) |
/applications/<app-id> |
POST | operation not supported (405) |
/applications/<app-id> |
PUT | operation not supported (405) |
/applications/<app-id> |
DELETE | operation not supported (405) |
URI | Method | Action (Response Code) |
---|---|---|
/applications/<app-id>/instances |
GET | JSON array of all running applications of the given type (200) |
/applications/<app-id>/instances |
POST | create new application of the given type, using the given parameters and return location header containing the endpoint /applications/<app-id>/instances/<instance-id> (201) |
/applications/<app-id>/instances |
PUT | operation not supported (405) |
/applications/<app-id>/instances |
DELETE | delete all instances of this application type and return their ids (200) |
/applications/<app-id>/instances/<instance-id> |
GET | name, status and parameters of the instance (200) |
/applications/<app-id>/instances/<instance-id> |
POST | update an existing application with the given parameters (200), no running application with this id (404), invalid parameters for this application (400) |
/applications/<app-id>/instances/<instance-id> |
PUT | create new or overwrite an existing application using the given available application id and parameters (201), invalid parameters for this application (400) |
/applications/<app-id>/instances/<instance-id> |
DELETE | shut down this application instance (200), no running application with this id (404) |
One should not only be able to add instances, but also to delete them.
Add a button to the UI and a REST endpoint accepting DELETE requests to delete an instance. Deletion should also send a DELETE request to Nomad.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.