diff --git a/Dockerfile b/Dockerfile index 53d56965..42a90964 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,31 @@ ## This Dockerfile is meant to aid in the building and debugging governor whilst developing on your local machine ## It has all the necessary components to play/debug with a single node appliance, running etcd -FROM ubuntu:14.04 +FROM zalando/ubuntu:14.04.1-1 MAINTAINER Feike Steenbergen # Add PGDG repositories RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list -RUN apt-get install wget ca-certificates -y -RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - +RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - RUN apt-get update -y RUN apt-get upgrade -y ENV PGVERSION 9.4 -RUN apt-get install curl python python-pip python-psycopg2 python-yaml postgresql-${PGVERSION} -y +RUN apt-get install python python-psycopg2 python-yaml python-requests postgresql-${PGVERSION} -y -RUN ln -s /usr/lib/postgresql/* /usr/lib/postgresql/current -ENV PATH /usr/lib/postgresql/current/bin:$PATH +ENV PATH /usr/lib/postgresql/${PGVERSION}/bin:$PATH RUN mkdir -p /governor/helpers ADD governor.py /governor/governor.py -ADD requirements.txt /governor/requirements.txt ADD helpers /governor/helpers ADD postgres0.yml /governor/ -## As we are standalone, remove any reference to AWS -RUN sed -i '/aws_use_host_address/d' /governor/postgres0.yml -ENV ETCDVERSION 2.0.9 -RUN curl -L https://github.com/coreos/etcd/releases/download/v${ETCDVERSION}/etcd-v${ETCDVERSION}-linux-amd64.tar.gz -o etcd-v${ETCDVERSION}-linux-amd64.tar.gz && tar vzxf etcd-v${ETCDVERSION}-linux-amd64.tar.gz && cp etcd-v${ETCDVERSION}-linux-amd64/etcd* /bin/ - -## Most requirements should already have been met, only as an extra precaution -RUN pip install -r /governor/requirements.txt +ENV ETCDVERSION 2.0.10 +RUN curl -L https://github.com/coreos/etcd/releases/download/v${ETCDVERSION}/etcd-v${ETCDVERSION}-linux-amd64.tar.gz | tar xz -C /bin --strip=1 --wildcards --no-anchored etcd etcdctl ## Setting up a simple script that will serve as an entrypoint RUN mkdir /data/ && touch /var/log/etcd.log /var/log/etcd.err && chown postgres:postgres /var/log/etcd.* RUN chown postgres:postgres -R /governor/ /data/ -RUN /bin/echo -e "etcd --data-dir /tmp/etcd.data > /var/log/etcd.log 2> /var/log/etcd.err &\n/governor/governor.py /governor/postgres0.yml \"$@\"" >> /entrypoint.sh && chmod +x /entrypoint.sh +RUN /bin/echo -e "etcd --data-dir /tmp/etcd.data > /var/log/etcd.log 2> /var/log/etcd.err &\n/governor/governor.py /governor/postgres0.yml \"\$@\"" >> /entrypoint.sh && chmod +x /entrypoint.sh ENTRYPOINT /entrypoint.sh USER postgres diff --git a/governor.py b/governor.py index b0a185cb..6b2920f7 100755 --- a/governor.py +++ b/governor.py @@ -2,7 +2,6 @@ import logging import os -import requests import signal import sys import threading @@ -32,23 +31,10 @@ def sigchld_handler(signo, stack_frame): class Governor: - INSTANCE_METADATA_URL = "http://169.254.169.254/latest/meta-data/" - def __init__(self, config): self.nap_time = config['loop_wait'] self.etcd = Etcd(config['etcd']) - aws_host_address = None - if config.get('aws_use_host_address', False): - # get host address of the AWS host via a call to - # http://169.254.169.254/latest/meta-data/local-ipv4 - try: - response = requests.get(Governor.INSTANCE_METADATA_URL + '/local-ipv4') - if response.status_code == 200: - aws_host_address = response.content - except: - logging.exception('Error retrieiving IPv4 address from AWS instance') - - self.postgresql = Postgresql(config['postgresql'], aws_host_address) + self.postgresql = Postgresql(config['postgresql']) self.ha = Ha(self.postgresql, self.etcd) def touch_member(self): diff --git a/helpers/postgresql.py b/helpers/postgresql.py index e7f581e7..7eb884c7 100644 --- a/helpers/postgresql.py +++ b/helpers/postgresql.py @@ -28,15 +28,15 @@ def parseurl(url): class Postgresql: - def __init__(self, config, aws_host_address=None): + def __init__(self, config): self.name = config['name'] - self.host, self.port = config['listen'].split(':') + host, port = config['connect_address'].split(':') self.libpq_parameters = { - 'host' : aws_host_address or self.host, - 'port' : self.port, - 'fallback_application_name' : 'Governor', - 'connect_timeout' : 5, - 'options' : '-c statement_timeout=2000' + 'host': host, + 'port': port, + 'fallback_application_name': 'Governor', + 'connect_timeout': 5, + 'options': '-c statement_timeout=2000' } self.data_dir = config['data_dir'] self.replication = config['replication'] @@ -47,8 +47,8 @@ class Postgresql: self.config = config - self.connection_string = 'postgres://{username}:{password}@{host}:{port}/postgres'.format( - host=self.libpq_parameters['host'], port=self.port, **self.replication) + self.connection_string = 'postgres://{username}:{password}@{connect_address}/postgres'.format( + connect_address=self.config['connect_address'], **self.replication) self.conn = None self.cursor_holder = None @@ -56,7 +56,7 @@ class Postgresql: def cursor(self): if not self.cursor_holder: - self.conn = psycopg2.connect('postgres://{}/postgres'.format(self.config['listen'])) + self.conn = psycopg2.connect(**self.libpq_parameters) self.conn.autocommit = True self.cursor_holder = self.conn.cursor() @@ -141,7 +141,8 @@ class Postgresql: return os.system(self._pg_ctl + ' restart -m fast') == 0 def server_options(self): - options = '--listen_addresses={} --port={}'.format(self.host, self.port) + host, port = self.config['listen'].split(':') + options = '--listen_addresses={} --port={}'.format(host, port) for setting, value in self.config['parameters'].items(): options += " --{}='{}'".format(setting, value) return options @@ -240,13 +241,13 @@ primary_conninfo = '{}' def create_connection_users(self): if self.superuser: if 'username' in self.superuser: - self.query("CREATE ROLE \"{0}\" LOGIN SUPERUSER PASSWORD '{1}';".format( - self.superuser["username"], self.superuser["password"])) + self.query('CREATE ROLE "{0}" WITH LOGIN SUPERUSER PASSWORD %s'.format( + self.superuser['username']), self.superuser['password']) else: - self.query("ALTER ROLE postgres PASSWORD '{0}';".format(self.superuser['password'])) + self.query('ALTER ROLE postgres WITH PASSWORD %s', self.superuser['password']) if self.admin: - self.query("CREATE ROLE \"{0}\" LOGIN CREATEDB CREATEROLE PASSWORD '{1}';".format( - self.admin["username"], self.admin["password"])) + self.query('CREATE ROLE "{0}" WITH LOGIN CREATEDB CREATEROLE PASSWORD %s'.format( + self.admin['username']), self.admin['password']) def xlog_position(self): return self.query("SELECT pg_last_xlog_replay_location() - '0/0000000'::pg_lsn").fetchone()[0] diff --git a/postgres0.yml b/postgres0.yml index c9360d38..da630242 100644 --- a/postgres0.yml +++ b/postgres0.yml @@ -1,5 +1,4 @@ loop_wait: 10 -aws_use_host_address: "on" healthcheck_port: 8008 etcd: scope: batman @@ -8,6 +7,7 @@ etcd: postgresql: name: postgresql0 listen: 127.0.0.1:5432 + connect_address: 127.0.0.1:5432 data_dir: data/postgresql0 maximum_lag_on_failover: 1048576 # 1 megabyte in bytes replication: diff --git a/postgres1.yml b/postgres1.yml index bb01127b..e8f958b5 100644 --- a/postgres1.yml +++ b/postgres1.yml @@ -1,5 +1,4 @@ loop_wait: 10 -aws_use_host_address: "on" healthcheck_port: 8009 etcd: scope: batman @@ -8,6 +7,7 @@ etcd: postgresql: name: postgresql1 listen: 127.0.0.1:5433 + connect_address: 127.0.0.1:5433 data_dir: data/postgresql1 maximum_lag_on_failover: 1048576 # 1 megabyte in bytes replication: diff --git a/requirements.txt b/requirements.txt index 377437fe..2185e5c6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ PyYAML psycopg2 +requests