Skip to content

Commit f6c06b8

Browse files
author
smothiki
committed
feat(mesos): add marathon framework support for deis
1 parent ba24426 commit f6c06b8

10 files changed

Lines changed: 410 additions & 0 deletions

File tree

controller/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ setproctitle==1.1.8
1818
static==1.1.1
1919
South==1.0.2
2020
python-ldap==2.4.19
21+
marathon
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import re
2+
import time
3+
from django.conf import settings
4+
from marathon import MarathonClient
5+
from marathon.models import MarathonApp
6+
from .states import JobState
7+
from docker import Client
8+
from .fleet import FleetHTTPClient
9+
10+
# turn down standard marathon logging
11+
12+
MATCH = re.compile(
13+
'(?P<app>[a-z0-9-]+)_?(?P<version>v[0-9]+)?\.?(?P<c_type>[a-z-_]+)?.(?P<c_num>[0-9]+)')
14+
RETRIES = 3
15+
16+
17+
class MarathonHTTPClient(object):
18+
19+
def __init__(self, target, auth, options, pkey):
20+
self.target = settings.MARATHON_HOST
21+
self.auth = auth
22+
self.options = options
23+
self.pkey = pkey
24+
self.registry = settings.REGISTRY_HOST + ':' + settings.REGISTRY_PORT
25+
self.client = MarathonClient('http://'+self.target+':8180')
26+
self.fleet = FleetHTTPClient('/var/run/fleet.sock', auth, options, pkey)
27+
28+
# helpers
29+
def _app_id(self, name):
30+
return name.replace('_', '.')
31+
32+
# container api
33+
def create(self, name, image, command='', **kwargs):
34+
"""Create a container"""
35+
app_id = self._app_id(name)
36+
l = locals().copy()
37+
l.update(re.match(MATCH, name).groupdict())
38+
image = self.registry + '/' + image
39+
mems = kwargs.get('memory', {}).get(l['c_type'])
40+
m = 0
41+
if mems:
42+
mems = mems.lower()
43+
if mems[-2:-1].isalpha() and mems[-1].isalpha():
44+
mems = mems[:-1]
45+
m = int(mems[:-1])
46+
c = 0.5
47+
cpu = kwargs.get('cpu', {}).get(l['c_type'])
48+
if cpu:
49+
c = cpu
50+
cpu = kwargs.get('cpu', {}).get(l['c_type'])
51+
self.client.create_app(app_id,
52+
MarathonApp(cmd="docker run --name "+name+" -P "+image+" "+command,
53+
mem=m, cpus=c))
54+
self.client.scale_app(app_id, 0, force=True)
55+
for _ in xrange(30):
56+
if self.client.get_app(self._app_id(name)).tasks_running == 0:
57+
return
58+
time.sleep(1)
59+
60+
def start(self, name):
61+
"""Start a container"""
62+
self.client.scale_app(self._app_id(name), 1, force=True)
63+
for _ in xrange(30):
64+
if self.client.get_app(self._app_id(name)).tasks_running == 1:
65+
return
66+
time.sleep(1)
67+
raise RuntimeError("App Not Started")
68+
69+
def stop(self, name):
70+
"""Stop a container"""
71+
raise NotImplementedError
72+
73+
def destroy(self, name):
74+
"""Destroy a container"""
75+
try:
76+
host = self.client.get_app(self._app_id(name)).tasks[0].host
77+
self.client.delete_app(self._app_id(name), force=True)
78+
self._delete_container(host, name)
79+
except:
80+
self.client.delete_app(self._app_id(name), force=True)
81+
82+
def _delete_container(self, host, name):
83+
docker_cli = Client("tcp://{}:2375".format(host), timeout=1200, version='1.17')
84+
try:
85+
if docker_cli.inspect_container(name)['State']:
86+
docker_cli.remove_container(name, force=True)
87+
except:
88+
pass
89+
90+
def run(self, name, image, entrypoint, command): # noqa
91+
"""Run a one-off command"""
92+
return self.fleet.run(name, image, entrypoint, command)
93+
94+
def state(self, name):
95+
try:
96+
for _ in xrange(30):
97+
if self.client.get_app(self._app_id(name)).tasks_running == 1:
98+
return JobState.up
99+
elif self.client.get_app(self._app_id(name)).tasks_running == 0:
100+
return JobState.created
101+
time.sleep(1)
102+
except:
103+
return JobState.destroyed
104+
105+
def attach(self, name):
106+
"""
107+
Attach to a job's stdin, stdout and stderr
108+
"""
109+
raise NotImplementedError
110+
111+
SchedulerClient = MarathonHTTPClient

controller/templates/confd_settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
SCHEDULER_OPTIONS = {}
1212

1313
# scheduler swarm manager host
14+
1415
SWARM_HOST = '{{ if exists "/deis/scheduler/swarm/host" }}{{ getv "/deis/scheduler/swarm/host" }}{{ else }}127.0.0.1{{ end }}'
1516

17+
MARATHON_HOST = '{{ if exists "/deis/scheduler/mesos/marathon" }}{{ getv "/deis/scheduler/mesos/marathon" }}{{ else }}127.0.0.1{{ end }}'
18+
1619
# base64-encoded SSH private key to facilitate current version of "deis run"
1720
SSH_PRIVATE_KEY = """{{ if exists "/deis/platform/sshPrivateKey" }}{{ getv "/deis/platform/sshPrivateKey" }}{{ else }}""{{end}}"""
1821

deisctl/cmd/cmd.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
// StatelessPlatformCommand is shorthand for the components except store-*, database, and logger.
2626
StatelessPlatformCommand string = "stateless-platform"
2727
swarm string = "swarm"
28+
mesos string = "mesos"
2829
)
2930

3031
// ListUnits prints a list of installed units.
@@ -75,6 +76,9 @@ func Start(targets []string, b backend.Backend) error {
7576
} else if targets[0] == swarm {
7677
return StartSwarm(b)
7778
}
79+
if targets[0] == mesos {
80+
return StartMesos(b)
81+
}
7882
}
7983
outchan := make(chan string)
8084
errchan := make(chan error)
@@ -181,6 +185,9 @@ func Stop(targets []string, b backend.Backend) error {
181185
} else if targets[0] == swarm {
182186
return StopSwarm(b)
183187
}
188+
if targets[0] == mesos {
189+
return StopMesos(b)
190+
}
184191
}
185192

186193
outchan := make(chan string)
@@ -283,6 +290,9 @@ func Install(targets []string, b backend.Backend, checkKeys func() error) error
283290
} else if targets[0] == swarm {
284291
return InstallSwarm(b)
285292
}
293+
if targets[0] == mesos {
294+
return InstallMesos(b)
295+
}
286296
}
287297
outchan := make(chan string)
288298
errchan := make(chan error)
@@ -344,6 +354,9 @@ func Uninstall(targets []string, b backend.Backend) error {
344354
} else if targets[0] == swarm {
345355
return UnInstallSwarm(b)
346356
}
357+
if targets[0] == mesos {
358+
return UninstallMesos(b)
359+
}
347360
}
348361

349362
outchan := make(chan string)

deisctl/cmd/mesos.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
"time"
7+
8+
"github.com/deis/deis/deisctl/backend"
9+
"github.com/deis/deis/deisctl/utils"
10+
)
11+
12+
// InstallMesos loads all Mesos units for StartMesos
13+
func InstallMesos(b backend.Backend) error {
14+
15+
outchan := make(chan string)
16+
errchan := make(chan error)
17+
var wg sync.WaitGroup
18+
19+
go printState(outchan, errchan, 500*time.Millisecond)
20+
21+
outchan <- utils.DeisIfy("Installing Mesos...")
22+
23+
installMesosServices(b, &wg, outchan, errchan)
24+
25+
wg.Wait()
26+
close(outchan)
27+
28+
fmt.Println("Done.")
29+
fmt.Println()
30+
fmt.Println("Please run `deisctl start mesos` to boot up Mesos.")
31+
return nil
32+
}
33+
34+
func installMesosServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
35+
36+
outchan <- fmt.Sprintf("Zookeeper...")
37+
b.Create([]string{"mesos-zk"}, wg, outchan, errchan)
38+
wg.Wait()
39+
40+
outchan <- fmt.Sprintf("Mesos Master...")
41+
b.Create([]string{"mesos-master"}, wg, outchan, errchan)
42+
wg.Wait()
43+
44+
outchan <- fmt.Sprintf("Mesos Slave...")
45+
b.Create([]string{"mesos-slave"}, wg, outchan, errchan)
46+
wg.Wait()
47+
48+
outchan <- fmt.Sprintf("Marathon Framework...")
49+
b.Create([]string{"mesos-marathon"}, wg, outchan, errchan)
50+
wg.Wait()
51+
}
52+
53+
// UninstallMesos unloads and uninstalls all Mesos component definitions
54+
func UninstallMesos(b backend.Backend) error {
55+
56+
outchan := make(chan string)
57+
errchan := make(chan error)
58+
var wg sync.WaitGroup
59+
60+
go printState(outchan, errchan, 500*time.Millisecond)
61+
62+
outchan <- utils.DeisIfy("Uninstalling Mesos...")
63+
64+
uninstallMesosServices(b, &wg, outchan, errchan)
65+
66+
wg.Wait()
67+
close(outchan)
68+
69+
fmt.Println("Done.")
70+
return nil
71+
}
72+
73+
func uninstallMesosServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) error {
74+
75+
outchan <- fmt.Sprintf("Marathon Framework...")
76+
b.Destroy([]string{"mesos-marathon"}, wg, outchan, errchan)
77+
wg.Wait()
78+
79+
outchan <- fmt.Sprintf("Mesos Slave...")
80+
b.Destroy([]string{"mesos-slave"}, wg, outchan, errchan)
81+
wg.Wait()
82+
83+
outchan <- fmt.Sprintf("Mesos Master...")
84+
b.Destroy([]string{"mesos-master"}, wg, outchan, errchan)
85+
wg.Wait()
86+
87+
outchan <- fmt.Sprintf("Zookeeper...")
88+
b.Destroy([]string{"mesos-zk"}, wg, outchan, errchan)
89+
wg.Wait()
90+
91+
return nil
92+
}
93+
94+
// StartMesos activates all Mesos components.
95+
func StartMesos(b backend.Backend) error {
96+
97+
outchan := make(chan string)
98+
errchan := make(chan error)
99+
var wg sync.WaitGroup
100+
101+
go printState(outchan, errchan, 500*time.Millisecond)
102+
103+
outchan <- utils.DeisIfy("Starting Mesos...")
104+
105+
startMesosServices(b, &wg, outchan, errchan)
106+
107+
wg.Wait()
108+
close(outchan)
109+
110+
fmt.Println("Done.")
111+
fmt.Println()
112+
fmt.Println("Please use `deisctl config controller set schedulerModule=mesos_marathon`")
113+
return nil
114+
}
115+
116+
func startMesosServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
117+
118+
outchan <- fmt.Sprintf("Zookeeper...")
119+
b.Start([]string{"mesos-zk"}, wg, outchan, errchan)
120+
wg.Wait()
121+
122+
outchan <- fmt.Sprintf("Mesos Master...")
123+
b.Start([]string{"mesos-master"}, wg, outchan, errchan)
124+
wg.Wait()
125+
126+
outchan <- fmt.Sprintf("Mesos Slave...")
127+
b.Start([]string{"mesos-slave"}, wg, outchan, errchan)
128+
wg.Wait()
129+
130+
outchan <- fmt.Sprintf("Marathon Framework...")
131+
b.Start([]string{"mesos-marathon"}, wg, outchan, errchan)
132+
wg.Wait()
133+
}
134+
135+
// StopMesos deactivates all Mesos components.
136+
func StopMesos(b backend.Backend) error {
137+
138+
outchan := make(chan string)
139+
errchan := make(chan error)
140+
var wg sync.WaitGroup
141+
142+
go printState(outchan, errchan, 500*time.Millisecond)
143+
144+
outchan <- utils.DeisIfy("Stopping Mesos...")
145+
146+
stopMesosServices(b, &wg, outchan, errchan)
147+
148+
wg.Wait()
149+
close(outchan)
150+
151+
fmt.Println("Done.")
152+
fmt.Println()
153+
fmt.Println("Please run `deisctl start mesos` to restart Mesos.")
154+
return nil
155+
}
156+
157+
func stopMesosServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
158+
159+
outchan <- fmt.Sprintf("Marathon Framework...")
160+
b.Stop([]string{"mesos-marathon"}, wg, outchan, errchan)
161+
wg.Wait()
162+
163+
outchan <- fmt.Sprintf("Mesos Slave...")
164+
b.Stop([]string{"mesos-slave"}, wg, outchan, errchan)
165+
wg.Wait()
166+
167+
outchan <- fmt.Sprintf("Mesos Master...")
168+
b.Stop([]string{"mesos-master"}, wg, outchan, errchan)
169+
wg.Wait()
170+
171+
outchan <- fmt.Sprintf("Zookeeper...")
172+
b.Stop([]string{"mesos-zk"}, wg, outchan, errchan)
173+
wg.Wait()
174+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[Unit]
2+
Description=Mesosphere Marathon
3+
After=docker.service
4+
Requires=docker.service
5+
6+
[Service]
7+
EnvironmentFile=/etc/environment
8+
Restart=on-failure
9+
RestartSec=20
10+
TimeoutStartSec=0
11+
ExecStartPre=-/bin/sh -c "etcdctl get /deis/scheduler/mesos/marathon >/dev/null 2>&1 || etcdctl mk /deis/scheduler/mesos/marathon"
12+
ExecStartPre=/bin/sh -c "etcdctl set /deis/scheduler/mesos/marathon $COREOS_PRIVATE_IPV4"
13+
ExecStartPre=-/usr/bin/docker kill coreos-mesos-marathon
14+
ExecStartPre=-/usr/bin/docker rm coreos-mesos-marathon
15+
ExecStartPre=/usr/bin/docker pull aledbf/mesos-marathon:0.22.1
16+
ExecStart=/usr/bin/sh -c "/usr/bin/docker run \
17+
--name=coreos-mesos-marathon \
18+
--net=host \
19+
-e HOST=$COREOS_PRIVATE_IPV4 \
20+
aledbf/mesos-marathon:0.22.1"
21+
ExecStop=-/usr/bin/docker stop coreos-mesos-marathon
22+
23+
[Install]
24+
WantedBy=multi-user.target
25+
26+
[X-Fleet]
27+
MachineOf=deis-mesos-master.service

0 commit comments

Comments
 (0)