Awesome
Mantl API
An API interface to Mantl.
Currently, Mantl API allows you to install and uninstall DCOS packages on Mantl. More capabilities are planned for the future.
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->Table of Contents
- Mantl API
Mantl API on Mantl Clusters
As of the 0.5 release, Mantl API is installed by default on Mantl clusters. It is deployed via Marathon and will be running on one of the worker nodes. Mantl automatically discovers the Mantl API instance and puts it behind Nginx on all control nodes at the /api
endpoint. By default, it is secured with SSL and basic authentication. As an example, on a default Mantl install, you can retrieve the list of available packages by running a command like the following:
curl -k -u admin:mantlpw https://mantl-control-01/api/1/packages
You just need to update the command with the correct host name and credentials for your cluster. All of the examples in this document will assume you are working with Mantl API on a Mantl cluster and will use urls underneath /api
.
Building
docker build -t mantl-api .
Deploying Manually
You can run Mantl API on your cluster via Marathon. An example mantl-api.json
is included below:
{
"id": "/mantl-api",
"container": {
"type": "DOCKER",
"docker": {
"image": "ciscocloud/mantl-api:0.1.0",
"network": "BRIDGE",
"portMappings": [
{ "containerPort": 4001, "hostPort": 0 }
]
}
},
"instances": 1,
"cpus": 1.0,
"mem": 512,
"constraints": [["hostname", "UNIQUE"]],
"env": {
"CONSUL_HTTP_SSL_VERIFY": "false",
"MANTL_API_LOG_LEVEL": "debug",
"MANTL_API_CONSUL": "https://consul.service.consul:8500",
"MANTL_API_MESOS_PRINCIPAL": "mantl-api",
"MANTL_API_MESOS_SECRET": "secret"
},
"healthChecks": [
{
"protocol": "HTTP",
"path": "/health",
"gracePeriodSeconds": 3,
"intervalSeconds": 10,
"portIndex": 0,
"timeoutSeconds": 10,
"maxConsecutiveFailures": 3
}
]
}
You will need to replace the MANTL_API_MESOS_PRINCIPAL
and MANTL_API_MESOS_SECRET
variables with valid Mesos credentials. These can be found in the security.yml
file that was generated when you ran security-setup for your Mantl cluster.
All Mantl API configuration can be set with environment variables. See below for the additional configuration options that are available.
To install Mantl API, you can submit the above json to Marathon.
curl -k -u admin:mantlpw -X POST -d @mantl-api.json -H "Content-type: application/json" https://mantl-control-01/marathon/v2/apps
You will need to replace admin:mantlpw
with valid Marathon credentials (see marathon_http_credentials
in your security.yml
). You will also replace mantl-control-01
with the host of one your Mantl control nodes.
After a few moments, Mantl API should be running on your cluster.
Usage with Vault
When configured with either vault-token
or vault-cubbyhole-token
, mantl-api will contact Vault to retrieve its secrets. They should be stored at secret/mantl-api. mantl-api will look for the following keys within that secret's Data
field: mesos-principal, mesos-secret, marathon-user, and marathon-password. You don't have to store all of your secrets in Vault to take advantage of this feature, mantl-api will only use the ones that are present.
Options
Configuration options:
--config-file string The path to a (optional) configuration file
--consul string Consul API address (default "http://localhost:8500")
--consul-acl-token string Consul ACL token for accessing mantl-install/apps path
--consul-no-verify-ssl Disable Consul SSL verification
--consul-refresh-interval int The number of seconds after which to check consul for package requests (default 10)
--force-sync Force a synchronization of respository all sources at startup
--listen string listen for connections on this address (default ":4001")
--log-format string specify output (text or json) (default "text")
--log-level string one of debug, info, warn, error, or fatal (default "info")
--marathon string Marathon API address
--marathon-no-verify-ssl Disable Marathon SSL verification
--marathon-password string Marathon API password
--marathon-user string Marathon API user
--mesos string Mesos API address
--mesos-no-verify-ssl Disable Mesos SSL verification
--mesos-principal string Mesos principal for framework authentication
--mesos-secret string Deprecated. Use mesos-secret-path instead
--mesos-secret-path string Path to a file on host sytem that contains the mesos secret for framework authentication (default "/etc/sysconfig/mantl-api")
--vault-cubbyhole-token string token for retrieving token from vault
--vault-token string token for retrieving secrets from vault
--zookeeper string Comma-delimited list of zookeeper servers
Every option can be set via environment variables prefixed with MANTL_API
. For example, you can use MANTL_API_LOG_LEVEL
for log-level
, MANTL_API_CONSUL
for consul
, and so on. You can also specify all configuration from a TOML configuration file using the config-file
argument.
Package Repository
Mantl API depends on a repository of package definitions stored in the Consul KV store. mantl-universe is the authoritative repository of packages that work out-of-the-box on Mantl today. You can install any of the DCOS packages but you will likely have to customize some of the configuration to work on Mantl. Most of the Mesosphere packages assume that service discovery is provided by Mesos-DNS and need to be converted to work with the Consul DNS interface.
Tree Structure
Mantl API is compatible with the package repository structure created for Mesosphere DCOS packages. Each repository contains a directory structure that looks something like this:
repo/packages
├── C
│ ├── cassandra
│ │ ├── 0
│ │ │ ├── config.json
│ │ │ ├── marathon.json
│ │ │ └── package.json
│ │ ├── 1
│ │ │ ├── command.json
│ │ │ ├── config.json
│ │ │ ├── marathon.json
│ │ │ └── package.json
├── H
│ └── hdfs
│ ├── 0
│ │ ├── command.json
│ │ ├── config.json
│ │ ├── marathon.json
│ │ └── package.json
│ ├── 1
│ │ ├── command.json
│ │ ├── config.json
│ │ ├── marathon.json
│ │ └── package.json
|__ ...
For each named package (cassandra and hdfs in the example above), there is a directory of JSON files corresponding to each version.
Multiple Repositories
Mantl API supports the ability to layer repositories. By default, Mantl API is configured with Mantl Universe as the base repository. It is possible to layer additional repositories on top.
The order of the repositories is important. By default, Mantl Universe is configured with index 0. In the Consul KV store, the repositories are stored as follows:
Name | Consul KV Path |
---|---|
Mantl Universe | mantl-install/repository/0 |
Custom Repository | mantl-install/repository/1 |
Repositories with higher indexes are prioritized. When Mantl API receives a request to install a particular package, it will use the package definition found in the repository with the highest index. If there are any required files missing, it will look for the corresponding package version in repositories with the lower indexes until it is able to construct a valid, installable package. For example, if mantl-install/repository/1/repo/packages/H/hdfs/1
(Custom Repository) exists but does not have a config.json
file, Mantl API will merge in the config.json
file from mantl-install/repository/0/repo/packages/H/hdfs/1
(Mantl Universe). This enables the ability to make small package customizations rather than creating an entirely new version of a package.
Configuring Sources
If you want to use additional or different source repositories, you can specify a configuration file that contains your source definitions using the --config-file
argument. Here is an example configuration file that uses 2 sources — one named "mesosphere" from a git repository and the other named "mantl-universe" from the local file system:
[sources]
[sources.mesosphere]
path = "https://github.com/mesosphere/universe.git"
type = "git"
index = 0
[sources.mantl]
path = "/home/ryan/Projects/mantl-universe"
index = 1
The following attributes can be specified for each source:
- path
- type — git or filesystem (default)
- index
- branch — only applicable for the git type
Synchronizing Repository Sources
The package repositories are synchronized to the Consul K/V backend. If you want to refresh your repositories, you can run the following command:
mantl-api sync --consul http://consul.service.consul:8500
Packages
The goals of the packaging system are:
- Make it easy to contribute packages to Mantl
- Rely on the existing DCOS package structure when possible
- Immutable package versions
- Ability for users to build customized package versions
Structure
Mantl Universe packages are based on the DCOS packaging format from Mesosphere. Packages in Mantl Universe are intended to be installed with Mantl API and may depend on the corresponding package version in the Mesosphere Universe.
Each package is made up of several json files:
package.json
The package.json file is where package metadata is set. This includes things like the name, version, description, and maintainer of the package.
config.json
The config.json file contains the configuration schema and defaults for the package.
mantl.json
The mantl.json
overrides configuration defaults from the config.json
file (either directly in the package or from the config.json
for the corresponding package version in the Mesosphere universe) with values that are known to work on Mantl.
Also, the presence of the mantl.json dictates whether the package is "supported" on Mantl. It can be empty {}
if there is no specific changes required to make the package run on Mantl.
mantl.json
includes a setting that allows you to control how the application is load balanced on Mantl clusters. Currently, it is a simple toggle that allows you to control whether the application will be load balanced by Traefik in a Mantl cluster. Here is an example mantl.json
with no other settings other than the load balancing configuration:
{
"mantl": {
"load-balancer": "external|off"
}
}
If mantl.load-balancer
is set to "external", the application will be included in the Traefik load balancer. Any other value will disable load balancing.
marathon.json
The marathon.json file contains the Marathon application json for the package. It is a mustache template that is rendered using data from config.json
and mantl.json
.
uninstall.json
The uninstall.json
defines additional behavior when uninstalling a package. The uninstall support is currently limited to removing zookeeper nodes. It is also a mustache template so that variables from config.json
and mantl.json
can be used in the uninstall definition.
{
"zookeeper": {
"delete": [
{
"path": "{{kafka.storage}}",
"always": true
}
]
}
}
Example uninstall.json that deletes zookeeper nodes with a path based on the kafka.storage
variable.
Developing Packages
When developing packages, it is easiest to run Mantl API locally and point it to a Mantl cluster. Using a Vagrant Mantl cluster is the simplest and fastest as pointing Mantl API to a remote cluster can be complicated by security settings. However, here is an example configuration file (config.toml
) showing how to run Mantl API locally against a remote Mantl cluster.
consul = "https://control-node:8500"
consul-no-verify-ssl = true
marathon = "https://control-node/marathon"
marathon-user = "user"
marathon-password = "password"
marathon-no-verify-ssl = true
mesos-principal = "mesos-principal"
mesos-secret = "mesos-secret"
mesos = "http://control-node:15050"
mesos-no-verify-ssl = true
zookeeper = "control-node:2181"
# global
log-level = "debug"
[sources]
[sources.mantl]
path = "/Users/ryan/Projects/mantl-universe"
index = 0
You will need to update the URLs and credentials as appropriate for your cluster.
Finally, you will need to update firewalls and security groups so that your development machine has access to the above ports.
You can then run Mantl API with a command like the following:
./bin/mantl-api --config-file config.toml
As shown above, you should have a copy of a valid repository on your local file system. The easiest thing to do is clone or fork Mantl. Create or update your package in this local repository. When you want to test it, you first need to synchronize it to the Mantl cluster. You can run a command like the following to synchronize the repository:
./bin/mantl-api --config-file config.toml sync
Then, you should be able to install your package using normal Mantl API calls. For example:
curl -X POST -d "{\"name\": \"mycustompackage\"}" http://localhost:4001/api/1/install
Usage
The following example curl commands assume a default Mantl API installation (with a control node called mantl-control-01
) on a Mantl cluster with SSL and authentication turned off. You will need to adjust the commands to work with valid URLs and credentials for your cluster.
Installing a Package
It is a single API call to install a package. In the example below, we are going to run Cassandra on our Mantl cluster.
curl -X POST -d "{\"name\": \"cassandra\"}" http://mantl-control-01/api/1/install
You can use the Marathon API or UI to find this. You'll also need to make sure that the port is accessible to the machine where you are calling the API from. Adjust the security groups or firewall rules for your platform accordingly.
After about 5 minutes, you should have Cassandra up and running on your Mantl cluster.
Uninstalling a Package
Uninstalling is just as easy. Run the command below to uninstall Cassandra:
curl -X DELETE -d "{\"name\": \"cassandra\"}" http://mantl-control-01/api/1/install
After a moment, Cassandra will have been removed from your cluster. This will also remove the Zookeeper state for the Cassandra framework. In the future, we will add more flexibility in being able to control what is uninstalled.
API Reference
Endpoints
Endpoint | Method | Description |
---|---|---|
/health | GET | health check - returns OK with an HTTP 200 status |
/1/packages | GET | list available packages |
/1/packages/:name | GET | provides information about a specific package |
/1/install | POST | install a package |
/1/install | DELETE | uninstalls a specific package |
/1/frameworks | GET | lists mesos frameworks |
/1/frameworks/:id | DELETE | shuts down a running mesos framework |
GET /health
GET /health
: returns OK
curl http://mantl-control-01/api/health
OK
GET /1/packages
GET /1/packages
: returns a JSON representation of packages available to install.
curl http://mantl-control-01/api/1/packages | jq .
[
{
"name": "cassandra",
"description": "Apache Cassandra running on Apache Mesos",
"framework": true,
"currentVersion": "0.2.0-1",
"supported": true,
"tags": [
"mesosphere",
"framework",
"data",
"database"
],
"versions": {
"0.1.0-1": {
"version": "0.1.0-1",
"index": "0",
"supported": true
},
"0.2.0-1": {
"version": "0.2.0-1",
"index": "1",
"supported": true
}
}
},
...
{
"name": "swarm",
"description": "Swarm is a Docker-native clustering system.",
"framework": true,
"currentVersion": "0.4.0",
"supported": false,
"tags": [
"mesosphere",
"framework",
"docker"
],
"versions": {
"0.4.0": {
"version": "0.4.0",
"index": "0",
"supported": false
}
}
}
]
GET /1/packages/<package>
GET /1/packages/<package>
: returns a JSON representation of a package.
curl http://mantl-control-01/api/1/packages/cassandra | jq .
{
"name": "cassandra",
"description": "Apache Cassandra running on Apache Mesos",
"framework": true,
"currentVersion": "0.2.0-1",
"supported": true,
"tags": [
"mesosphere",
"framework",
"data",
"database"
],
"versions": {
"0.1.0-1": {
"version": "0.1.0-1",
"index": "0",
"supported": true
},
"0.2.0-1": {
"version": "0.2.0-1",
"index": "1",
"supported": true
}
}
}
POST /1/install
POST /1/install
: post a JSON representation of a package to install.
curl -X POST -d "{\"name\": \"cassandra\"}" http://mantl-control-01/api/1/install | jq .
{
"id": "/cassandra/dcos-test",
"cmd": "$(pwd)/jre*/bin/java $JAVA_OPTS -classpath cassandra-mesos-framework.jar io.mesosphere.mesos.frameworks.cassandra.framework.Main",
"args": null,
"user": null,
"env": {
"CASSANDRA_ZK_TIMEOUT_MS": "10000",
"JAVA_OPTS": "-Xms256m -Xmx256m",
"MESOS_AUTHENTICATE": "true",
"CASSANDRA_RESOURCE_CPU_CORES": "0.1",
"CASSANDRA_FAILOVER_TIMEOUT_SECONDS": "604800",
"DEFAULT_SECRET": "secret",
"CASSANDRA_BOOTSTRAP_GRACE_TIME_SECONDS": "120",
"CASSANDRA_DEFAULT_DC": "DC1",
"CASSANDRA_RESOURCE_MEM_MB": "768",
"MESOS_ZK": "zk://zookeeper.service.consul:2181/mesos",
"CASSANDRA_DATA_DIRECTORY": ".",
"DEFAULT_PRINCIPAL": "mantl-install",
"CASSANDRA_FRAMEWORK_MESOS_ROLE": "*",
"CASSANDRA_CLUSTER_NAME": "dcos-test",
"CASSANDRA_RESOURCE_DISK_MB": "16",
"CASSANDRA_SEED_COUNT": "2",
"CASSANDRA_ZK": "zk://zookeeper.service.consul:2181/cassandra-mesos/dcos-test",
"CASSANDRA_NODE_COUNT": "3",
"CASSANDRA_DEFAULT_RACK": "RAC1",
"CASSANDRA_HEALTH_CHECK_INTERVAL_SECONDS": "60"
},
"instances": 1,
"cpus": 0.5,
"mem": 512,
"disk": 0,
"executor": "",
"constraints": [],
"uris": [
"https://downloads.mesosphere.io/cassandra-mesos/artifacts/0.2.0-1/cassandra-mesos-0.2.0-1.tar.gz",
"https://downloads.mesosphere.io/java/jre-7u76-linux-x64.tar.gz"
],
"storeUrls": [],
"ports": [
0
],
"requirePorts": false,
"backoffFactor": 0,
"container": null,
"healthChecks": [
{
"path": "/health/cluster",
"protocol": "HTTP",
"portIndex": 0,
"command": null,
"gracePeriodSeconds": 120,
"intervalSeconds": 15,
"timeoutSeconds": 5,
"maxConsecutiveFailures": 0,
"ignoreHttp1xx": false
},
{
"path": "/health/process",
"protocol": "HTTP",
"portIndex": 0,
"command": null,
"gracePeriodSeconds": 120,
"intervalSeconds": 30,
"timeoutSeconds": 5,
"maxConsecutiveFailures": 3,
"ignoreHttp1xx": false
}
],
"dependencies": [],
"upgradeStrategy": {
"minimumHealthCapacity": 0,
"maximumOverCapacity": 0
},
"labels": {
"MANTL_PACKAGE_NAME": "cassandra",
"MANTL_PACKAGE_IS_FRAMEWORK": "true",
"DCOS_PACKAGE_FRAMEWORK_NAME": "cassandra.dcos-test",
"MANTL_PACKAGE_FRAMEWORK_NAME": "cassandra.dcos-test",
"MANTL_PACKAGE_INDEX": "1",
"MANTL_PACKAGE_VERSION": "0.2.0-1"
},
"acceptedResourceRoles": null,
"version": "2015-09-17T22:19:24.576Z",
"tasks": [],
"deployments": [
{
"id": "dd113528-388c-4438-a524-9eba45aa2908"
}
],
"tasksStaged": 0,
"tasksRunning": 0,
"tasksHealthy": 0,
"tasksUnhealthy": 0,
"backoffSeconds": 0,
"maxLaunchDelaySeconds": 3600
}
DELETE /1/install
DELETE /1/install
: post a JSON representation of package specific uninstall options.
curl -X DELETE -d "{\"name\": \"cassandra\"}" http://mantl-control-01/api/1/install
GET /1/frameworks
GET /1/frameworks
: returns a JSON representation of mesos frameworks.
Append a query string of ?completed
to list completed frameworks.
curl -s http://mantl-control-01/api/1/frameworks
[
{
"name": "elasticsearch",
"id": "e8569827-307e-416c-8186-47e3d08555b2-0001",
"active": true,
"hostname": "mi-worker-001.novalocal",
"user": "root",
"registeredTime": "2016-01-30T17:30:44-05:00",
"reregisteredTime": "0001-01-01T00:00:00Z",
"activeTasks": 1
},
{
"name": "chronos",
"id": "8e1863a6-3664-4f93-9f13-44a187a7fca8-0000",
"active": true,
"hostname": "mi-control-01.novalocal",
"user": "root",
"registeredTime": "2016-01-30T13:57:25-05:00",
"reregisteredTime": "0001-01-01T00:00:00Z",
"activeTasks": 0
},
{
"name": "marathon",
"id": "90e1b7ed-9369-4ec8-b50c-331a47e28468-0000",
"active": true,
"hostname": "mi-control-01.node.consul",
"user": "root",
"registeredTime": "2016-01-30T13:57:24-05:00",
"reregisteredTime": "2016-01-31T23:39:52-05:00",
"activeTasks": 7
}
]
DELETE /1/frameworks/:id
DELETE /1/frameworks/<mesos-framework-id>
: Shutdown the mesos framework with the specified ID.
curl -X DELETE http://mantl-control-01/api/1/frameworks/a1c0c9da-f554-4140-8e04-bb92ac9d2a39-0000
Comparison to Other Software
Mantl API takes advantage of the Mesosphere DCOS packaging format and provides capabilities similar to the package
command in the DCOS CLI. The goal is to provide a simple, API-driven way to install and uninstall pre-built packages on Mantl clusters. In the future, mantl-api will contain additional functionality for maintaining and operating Mantl clusters.
Future Enhancement Ideas
- Discover running packages (in progress) so that they can automatically be added to UI when applicable.
- Operational tasks. Ability to see and manage Mesos frameworks, Marathon tasks, health checks, logs, etc.
- Addons / Optional components. Turn on and off optional components.
- Cluster management. Scale cluster up and down.
- Other ideas?
License
mantl-api is released under the Apache 2.0 license (see LICENSE)