Skip to content

Commit 04832fd

Browse files
authored
Merge pull request #83 from autopilotpattern/containerpilot3-dev
upgrade to ContainerPilot 3.0.0-RC1
2 parents 3aef683 + 9202b92 commit 04832fd

File tree

6 files changed

+100
-106
lines changed

6 files changed

+100
-106
lines changed

Dockerfile

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM percona:5.6
22

3-
ENV CONTAINERPILOT_VER 2.6.0
4-
ENV CONTAINERPILOT file:///etc/containerpilot.json
3+
ENV CONTAINERPILOT_VER 3.0.0-RC1
4+
ENV CONTAINERPILOT /etc/containerpilot.json5
55

66
# By keeping a lot of discrete steps in a single RUN we can clean up after
77
# ourselves in the same layer. This is gross but it saves ~100MB in the image
@@ -23,6 +23,7 @@ RUN set -ex \
2323
python-Consul==0.4.7 \
2424
manta==2.5.0 \
2525
mock==2.0.0 \
26+
json5==0.2.4 \
2627
# \
2728
# Add Consul from https://releases.hashicorp.com/consul \
2829
# \
@@ -35,7 +36,7 @@ RUN set -ex \
3536
# \
3637
# Add ContainerPilot and set its configuration file path \
3738
# \
38-
&& export CONTAINERPILOT_CHECKSUM=c1bcd137fadd26ca2998eec192d04c08f62beb1f \
39+
&& export CONTAINERPILOT_CHECKSUM=f67929d1c8567d31772085fc252338091a5f795c \
3940
&& curl -Lvo /tmp/containerpilot.tar.gz "https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VER}/containerpilot-${CONTAINERPILOT_VER}.tar.gz" \
4041
&& echo "${CONTAINERPILOT_CHECKSUM} /tmp/containerpilot.tar.gz" | sha1sum -c \
4142
&& tar zxf /tmp/containerpilot.tar.gz -C /usr/local/bin \
@@ -59,13 +60,4 @@ COPY bin/manage.py /usr/local/bin/manage.py
5960

6061
# override the parent entrypoint
6162
ENTRYPOINT []
62-
63-
# use --console to get error logs to stderr
64-
CMD [ "containerpilot", \
65-
"mysqld", \
66-
"--console", \
67-
"--log-bin=mysql-bin", \
68-
"--log_slave_updates=ON", \
69-
"--gtid-mode=ON", \
70-
"--enforce-gtid-consistency=ON" \
71-
]
63+
CMD ["/usr/local/bin/containerpilot"]

bin/manager/containerpilot.py

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
""" autopilotpattern/mysql ContainerPilot configuraton wrapper """
2-
import json
32
import os
43
import signal
4+
import subprocess
5+
6+
import json5
7+
58
from manager.utils import debug, env, to_flag, log, UNASSIGNED
69

710
# pylint: disable=invalid-name,no-self-use,dangerous-default-value
@@ -19,38 +22,20 @@ def __init__(self):
1922

2023
def load(self, envs=os.environ):
2124
"""
22-
Parses the ContainerPilot config file and interpolates the
23-
environment into it the same way that ContainerPilot does.
24-
The `state` attribute will be populated with the state
25-
derived from the configuration file and not the state known
26-
by Consul.
25+
Fetches the ContainerPilot config file and asks ContainerPilot
26+
to render it out so that all environment variables have been
27+
interpolated.
2728
"""
28-
self.path = env('CONTAINERPILOT', None, envs,
29-
lambda x: x.replace('file://', ''))
30-
with open(self.path, 'r') as f:
31-
cfg = f.read()
32-
33-
# remove templating so that we can parse it as JSON; we'll
34-
# override the attributes directly in the resulting dict
35-
cfg = cfg.replace('[{{ if .CONSUL_AGENT }}', '[')
36-
cfg = cfg.replace('}{{ end }}', '}')
37-
38-
# remove templating for SERVICE_NAME
39-
service_name = env('SERVICE_NAME', 'mysql')
40-
cfg = cfg.replace('{{ if .SERVICE_NAME }}{{ .SERVICE_NAME }}{{ else }}mysql{{ end }}',service_name)
41-
config = json.loads(cfg)
42-
43-
if env('CONSUL_AGENT', False, envs, to_flag):
44-
config['consul'] = 'localhost:8500'
45-
cmd = config['coprocesses'][0]['command']
46-
host_cfg_idx = cmd.index('-retry-join') + 1
47-
cmd[host_cfg_idx] = env('CONSUL', 'consul', envs)
48-
config['coprocesses'][0]['command'] = cmd
49-
else:
50-
config['consul'] = env('CONSUL', 'consul', envs,
51-
fn='{}:8500'.format)
52-
config['coprocesses'] = []
29+
self.path = env('CONTAINERPILOT', None, envs)
30+
try:
31+
cfg = subprocess.check_output(['containerpilot', '-config',
32+
self.path, '-template'],
33+
env=envs.copy())
34+
except (subprocess.CalledProcessError, OSError) as ex:
35+
log.error('containerpilot -template returned error: %s', ex)
36+
raise(ex)
5337

38+
config = json5.loads(cfg)
5439
self.config = config
5540

5641
@debug(log_output=True)
@@ -61,21 +46,24 @@ def update(self):
6146
"""
6247
if self.state == UNASSIGNED:
6348
return False
64-
if self.state and self.config['services'][0]['name'] != self.state:
65-
self.config['services'][0]['name'] = self.state
49+
if self.state and self.config['jobs'][1]['name'] != self.state:
50+
self.config['jobs'][1]['name'] = self.state
6651
self._render()
6752
return True
6853
return False
6954

7055
@debug
7156
def _render(self):
7257
""" Writes the current config to file. """
73-
new_config = json.dumps(self.config)
58+
new_config = json5.dumps(self.config)
7459
with open(self.path, 'w') as f:
7560
log.info('rewriting ContainerPilot config: %s', new_config)
7661
f.write(new_config)
7762

7863
def reload(self):
7964
""" Force ContainerPilot to reload its configuration """
8065
log.info('Reloading ContainerPilot configuration.')
81-
os.kill(1, signal.SIGHUP)
66+
try:
67+
subprocess.check_output(['containerpilot', '-reload'])
68+
except subprocess.CalledProcessError:
69+
log.info("call to 'containerpilot -reload' failed")

bin/test.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from datetime import datetime, timedelta
22
import fcntl
3-
import json
43
import logging
54
import os
65
import tempfile
76
import unittest
87

98
# pylint: disable=import-error
109
import consul as pyconsul
10+
import json5
1111
import mock
1212

1313
import manage
@@ -835,25 +835,20 @@ def test_parse_with_consul_agent(self):
835835
self.environ['CONSUL_AGENT'] = '1'
836836
cp = ContainerPilot()
837837
cp.load(envs=self.environ)
838+
838839
self.assertEqual(cp.config['consul'], 'localhost:8500')
839-
cmd = cp.config['coprocesses'][0]['command']
840+
cmd = cp.config['jobs'][4]['exec']
840841
host_cfg_idx = cmd.index('-retry-join') + 1
841842
self.assertEqual(cmd[host_cfg_idx], 'my.consul.example.com')
842843
self.assertEqual(cp.state, UNASSIGNED)
843844

844845
def test_parse_without_consul_agent(self):
845-
self.environ['CONSUL_AGENT'] = '0'
846-
cp = ContainerPilot()
847-
cp.load(envs=self.environ)
848-
self.assertEqual(cp.config['consul'], 'my.consul.example.com:8500')
849-
self.assertEqual(cp.config['coprocesses'], [])
850-
self.assertEqual(cp.state, UNASSIGNED)
851-
852846
self.environ['CONSUL_AGENT'] = ''
853847
cp = ContainerPilot()
854848
cp.load(envs=self.environ)
855849
self.assertEqual(cp.config['consul'], 'my.consul.example.com:8500')
856-
self.assertEqual(cp.config['coprocesses'], [])
850+
self.assertFalse('consul-agent' in
851+
[job['name'] for job in cp.config['jobs']])
857852
self.assertEqual(cp.state, UNASSIGNED)
858853

859854
def test_update(self):
@@ -873,9 +868,9 @@ def test_update(self):
873868
cp.state = PRIMARY
874869
cp.update()
875870
with open(temp_file.name, 'r') as updated:
876-
config = json.loads(updated.read())
871+
config = json5.loads(updated.read())
877872
self.assertEqual(config['consul'], 'localhost:8500')
878-
cmd = config['coprocesses'][0]['command']
873+
cmd = config['jobs'][4]['exec']
879874
host_cfg_idx = cmd.index('-retry-join') + 1
880875
self.assertEqual(cmd[host_cfg_idx], 'my.consul.example.com')
881876

@@ -936,7 +931,7 @@ def test_env_parse(self):
936931
'CONSUL': 'my.consul.example.com',
937932
'CONSUL_AGENT': '1',
938933

939-
'CONTAINERPILOT': 'file:///etc/containerpilot.json',
934+
'CONTAINERPILOT': '/etc/containerpilot.json5',
940935

941936
'MYSQL_DATABASE': 'test_mydb',
942937
'MYSQL_USER': 'test_me',

docker-compose.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ services:
1414
env_file: _env
1515
network_mode: bridge
1616
environment:
17-
- CONTAINERPILOT=file:///etc/containerpilot.json
1817
- CONSUL_AGENT=1
1918
- LOG_LEVEL=INFO
2019
- SERVICE_NAME=mysql

etc/containerpilot.json

Lines changed: 0 additions & 44 deletions
This file was deleted.

etc/containerpilot.json5

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
consul: '{{ if .CONSUL_AGENT }}localhost{{ else }}{{ .CONSUL | default "consul"}}{{ end }}:8500',
3+
logging: {
4+
level: '{{ .LOG_LEVEL | default "INFO" }}'
5+
},
6+
jobs: [
7+
{
8+
name: "preStart",
9+
exec: "python /usr/local/bin/manage.py"
10+
},
11+
{
12+
name: '{{ .SERVICE_NAME | default "mysql" }}',
13+
exec: ["mysqld",
14+
"--console",
15+
"--log-bin=mysql-bin",
16+
"--log_slave_updates=ON",
17+
"--gtid-mode=ON",
18+
"--enforce-gtid-consistency=ON"],
19+
port: 3306,
20+
when: {
21+
source: "preStart",
22+
once: "exitSuccess"
23+
},
24+
health: {
25+
exec: "python /usr/local/bin/manage.py health",
26+
interval: 5,
27+
ttl: 25
28+
}
29+
},
30+
{
31+
name: "onChange",
32+
exec: "python /usr/local/bin/manage.py on_change",
33+
when: {
34+
source:'watch.{{ .SERVICE_NAME | default "mysql" }}-primary' ,
35+
each: "changed"
36+
}
37+
},
38+
{
39+
name: "snapshot-check",
40+
exec: "python /usr/local/bin/manage.py snapshot_task",
41+
timeout: "10m",
42+
when: {
43+
interval: "5m"
44+
},
45+
},
46+
{{ if .CONSUL_AGENT }}{
47+
name: "consul-agent",
48+
restarts: "unlimited",
49+
exec: ["/usr/local/bin/consul", "agent",
50+
"-data-dir=/data",
51+
"-config-dir=/config",
52+
"-rejoin",
53+
"-retry-join", '{{ .CONSUL | default "consul"}}',
54+
"-retry-max", "10",
55+
"-retry-interval", "10s"]
56+
}{{ end }}
57+
],
58+
watches: [
59+
{
60+
name: '{{ .SERVICE_NAME | default "mysql" }}-primary',
61+
interval: 10
62+
}
63+
]
64+
}

0 commit comments

Comments
 (0)