Skip to content
This repository has been archived by the owner on Jan 19, 2018. It is now read-only.

Commit

Permalink
Merge pull request #392 from kadel/marathon-provider
Browse files Browse the repository at this point in the history
Marathon provider
  • Loading branch information
cdrage committed Dec 16, 2015
2 parents 21d71da + 22005a8 commit e55ef71
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 6 deletions.
4 changes: 2 additions & 2 deletions atomicapp/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"namespace": DEFAULT_NAMESPACE
}
}
PROVIDER_CONFIG_KEY = "providerconfig"

PROVIDERS = ['docker', 'kubernetes', 'openshift']
PROVIDERS = ["docker", "kubernetes", "openshift", "marathon"]
PROVIDER_API_KEY = "providerapi"
ACCESS_TOKEN_KEY = "accesstoken"
PROVIDER_CONFIG_KEY = "providerconfig"
122 changes: 122 additions & 0 deletions atomicapp/providers/marathon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""
Copyright 2015 Red Hat, Inc.
This file is part of Atomic App.
Atomic App is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Atomic App is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Atomic App. If not, see <http://www.gnu.org/licenses/>.
"""

import anymarkup
import urlparse
import logging
import os
from atomicapp.plugin import Provider, ProviderFailedException
from atomicapp.utils import printErrorStatus
from atomicapp.utils import Utils
from atomicapp.constants import PROVIDER_API_KEY

logger = logging.getLogger(__name__)


class Marathon(Provider):

key = "marathon"
config_file = None
marathon_api_version = "v2"
# use localhost as default, when no providerurl is specified
marathon_api = "http://localhost:8080/%s/" % marathon_api_version
marathon_artifacts = []

def init(self):
self.marathon_artifacts = []

logger.debug("Given config: %s", self.config)
if self.config.get(PROVIDER_API_KEY):
self.marathon_api = self.config.get(PROVIDER_API_KEY)
self.marathon_api = urlparse.urljoin(self.marathon_api, "v2/")

logger.debug("marathon_api = %s", self.marathon_api)
self._process_artifacts()

def deploy(self):
""" Deploys the app by given resource manifests.
"""
for artifact in self.marathon_artifacts:
url = urlparse.urljoin(self.marathon_api, "apps/")

if self.dryrun:
logger.info("DRY-RUN: %s", url)
continue

logger.debug("Deploying appid: %s", artifact["id"])
(status_code, return_data) = \
Utils.make_rest_request("post", url, data=artifact)
if status_code == 201:
logger.info(
"Marathon app %s sucessfully deployed.",
artifact["id"])
else:
msg = "Error deploying app: %s, Marathon API response %s - %s" % (
artifact["id"], status_code, return_data)
logger.error(msg)
raise ProviderFailedException(msg)

def undeploy(self):
""" Undeploys the app by given resource manifests.
Undeploy operation deletes Marathon apps from cluster.
"""
for artifact in self.marathon_artifacts:
url = urlparse.urljoin(
self.marathon_api,
"apps/%s" %
artifact["id"])

if self.dryrun:
logger.info("DRY-RUN: %s", url)
continue

logger.debug("Deleting appid: %s", artifact["id"])
(status_code, return_data) = \
Utils.make_rest_request("delete", url, data=artifact)
if status_code == 200:
logger.info(
"Marathon app %s sucessfully deleted.",
artifact["id"])
else:
msg = "Error deleting app: %s, Marathon API response %s - %s" % (
artifact["id"], status_code, return_data)
logger.error(msg)
raise ProviderFailedException(msg)

def _process_artifacts(self):
""" Parse and validate Marathon artifacts
Parsed artifacts are saved to self.marathon_artifacts
"""
for artifact in self.artifacts:
logger.debug("Procesesing artifact: %s", artifact)
data = None
with open(os.path.join(self.path, artifact), "r") as fp:
try:
data = anymarkup.parse(fp)
logger.debug("Parsed artifact %s", data)
# every marathon app has to have id. 'id' key is also used for showing messages
if "id" not in data.keys():
msg = "Error processing %s artifact. There is no id" % artifact
printErrorStatus(msg)
raise ProviderFailedException(msg)
except anymarkup.AnyMarkupError, e:
msg = "Error processing artifact - %s" % e
printErrorStatus(msg)
raise ProviderFailedException(msg)
self.marathon_artifacts.append(data)
10 changes: 6 additions & 4 deletions docs/providers.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
# Providers

This chapter includes linkes to documentation on how to use and configure the
This chapter includes linkes to documentation on how to use and configure the
providers that are supported by Atomic App. The linked documentation
will give you a short overview of all available providers and how
to use them.

**NOTE**: Not all Atomic Apps must support each provider. One Atomic App may
only include deployment information for OpenShift while another supports
**NOTE**: Not all Atomic Apps must support each provider. One Atomic App may
only include deployment information for OpenShift while another supports
OpenShift and Kubernetes.

## List of providers
Atomic App includes three providers:
Atomic App includes four providers:

* Docker
* Kubernetes
* OpenShift 3
* Marathon (Mesos)

You can run any of the providers via the Atomic App CLI.

Expand All @@ -28,3 +29,4 @@ below:
* [Docker](./providers/docker/overview.md)
* [Kubernetes](./providers/kubernetes/overview.md)
* [OpenShift](./providers/openshift/overview.md)
* [Marathon (Mesos)](./providers/marathon/overview.md)
40 changes: 40 additions & 0 deletions docs/providers/marathon/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Marathon

### Overview

The Marathon provider will deploy an application into Mesos cluster
using Marathon scheduler.

### Configuration
This provider requires configuration (`providerapi`) to be able to connect to Marathon API.
If no `providerapi` is specified it will use `http://localhost:8080` as Marathon API url.
This configuration can be provided in the `answers.conf` file.

Example:

[general]
provider=marathon
providerapi=http://10.0.2.15:8080

#### Configuration values

Table 1. Marathon default configuration values

Keyword | Required | Description | Default value
------------|----------|---------------------------------------------|--------------------------
providerapi | no | url for Marathon REST API | `http://localhost:8080`

### Operations

```
atomicapp run
```

This command creates app in Marathon.
The deploy process creates applications in order as enlisted in Nulecule Marathon artifacts.

```
atomicapp stop
```
This command deletes app from Marathon.

15 changes: 15 additions & 0 deletions tests/units/cli/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ def test_run_helloapache_app_docker(self):

assert exec_info.value.code == 0

def test_run_helloapache_app_marathon(self):
command = [
"main.py",
"--verbose",
"--dry-run",
"run",
"--provider=marathon",
self.examples_dir + 'helloapache'
]

with pytest.raises(SystemExit) as exec_info:
self.exec_cli(command)

assert exec_info.value.code == 0

def test_install_helloapache_app_docker(self):
command = [
"main.py",
Expand Down
2 changes: 2 additions & 0 deletions tests/units/cli/test_examples/helloapache/Nulecule
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ graph:
- file://artifacts/docker/hello-apache-pod_run
kubernetes:
- file://artifacts/kubernetes/hello-apache-pod.json
marathon:
- file://artifacts/marathon/helloapache.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "helloapache",
"container": {
"type": "DOCKER",
"docker": {
"network": "BRIDGE",
"image": "$image",
"portMappings": [
{
"containerPort": 80,
"servicePort": $hostport,
"hostPort": 0,
"protocol": "tcp"
}
]
}
},
"cpus": 0.5,
"mem": 128
}

0 comments on commit e55ef71

Please sign in to comment.