Start slave with the correct recovery.conf on governor start

Also governor is able to pick up already running master and slave
instances without restarting them.
In case is you have a lock and postgres is not running behaviour remains
the same: it will start master in read only mode and then promote if it
still has the lock.
This commit is contained in:
Alexander Kukushkin
2015-05-11 16:50:21 +02:00
parent eb1721f65f
commit e2faf641d5
3 changed files with 51 additions and 56 deletions
+6 -16
View File
@@ -1,11 +1,10 @@
#!/usr/bin/env python
import sys
import yaml
import time
import urllib2
import atexit
import logging
import sys
import time
import yaml
from helpers.etcd import Etcd
from helpers.postgresql import Postgresql
@@ -30,14 +29,9 @@ def stop_postgresql():
atexit.register(stop_postgresql)
# wait for etcd to be available
etcd_ready = False
while not etcd_ready:
try:
etcd.touch_member(postgresql.name, postgresql.connection_string)
etcd_ready = True
except urllib2.URLError:
logging.info("waiting on etcd")
time.sleep(5)
while not etcd.touch_member(postgresql.name, postgresql.connection_string):
logging.info("waiting on etcd")
time.sleep(5)
# is data directory empty?
if postgresql.data_directory_empty():
@@ -60,11 +54,7 @@ if postgresql.data_directory_empty():
synced_from_leader = True
else:
time.sleep(5)
else:
postgresql.write_recovery_conf(None)
postgresql.start()
while True:
logging.info(ha.run_cycle())
time.sleep(config["loop_wait"])
+1 -1
View File
@@ -103,7 +103,7 @@ class Etcd:
raise CurrentLeaderError("Etcd is not responding properly")
def touch_member(self, member, connection_string):
self.put_client_path('/members/' + member, value=connection_string)
return self.put_client_path('/members/' + member, value=connection_string)
def take_leader(self, value):
return self.put_client_path('/leader', value=value, ttl=self.ttl)
+44 -39
View File
@@ -44,55 +44,60 @@ class Ha:
def run_cycle(self):
try:
if self.state_handler.is_healthy():
self.load_cluster_from_etcd()
if self.is_unlocked():
if self.state_handler.is_healthiest_node(self.cluster.members):
if self.acquire_lock():
if not self.state_handler.is_leader():
self.state_handler.promote()
return "promoted self to leader by acquiring session lock"
return "acquired session lock as a leader"
else:
self.load_cluster_from_etcd()
if self.state_handler.is_leader():
self.demote()
return "demoted self due after trying and failing to obtain lock"
else:
self.follow_the_leader()
return "following new leader after trying and failing to obtain lock"
self.load_cluster_from_etcd()
if self.is_unlocked():
if not self.state_handler.is_healthy():
return 'no action. not healthy enough to do anything.'
elif self.state_handler.is_healthiest_node(self.cluster.members):
if self.acquire_lock():
if not self.state_handler.is_leader():
self.state_handler.promote()
return "promoted self to leader by acquiring session lock"
return "acquired session lock as a leader"
else:
self.load_cluster_from_etcd()
if self.state_handler.is_leader():
self.demote()
return "demoting self because i am not the healthiest node"
return "demoted self due after trying and failing to obtain lock"
else:
self.follow_the_leader()
return "following a different leader because i am not the healthiest node"
return "following new leader after trying and failing to obtain lock"
else:
if self.has_lock() and self.update_lock():
try:
if not self.state_handler.is_leader():
self.state_handler.promote()
return "promoted self to leader because i had the session lock"
else:
return "no action. i am the leader with the lock"
finally:
# create replication slots
self.state_handler.create_replication_slots([m.hostname for m in self.cluster.members])
self.load_cluster_from_etcd()
if self.state_handler.is_leader():
self.demote()
return "demoting self because i am not the healthiest node"
else:
logger.info("does not have lock")
if self.state_handler.is_leader():
self.demote()
return "demoting self because i do not have the lock and i was a leader"
else:
self.follow_the_leader()
return "no action. i am a secondary and i am following a leader"
self.follow_the_leader()
return "following a different leader because i am not the healthiest node"
else:
if not self.state_handler.is_running(): # XXX is_running == is_healthy
if self.has_lock() and not self.state_handler.is_healthy():
self.state_handler.write_recovery_conf(None)
self.state_handler.start()
return "postgresql was stopped. starting again."
return "no action. not healthy enough to do anything."
self.load_cluster_from_etcd()
if self.has_lock() and self.update_lock():
try:
if not self.state_handler.is_leader():
self.state_handler.promote()
return "promoted self to leader because i had the session lock"
else:
return "no action. i am the leader with the lock"
finally:
# create replication slots
self.state_handler.create_replication_slots([m.hostname for m in self.cluster.members])
else:
logger.info("does not have lock")
if not self.state_handler.is_healthy():
self.state_handler.write_recovery_conf(self.cluster.leader)
self.state_handler.start()
return 'starting as a secondary'
elif self.state_handler.is_leader():
self.demote()
return "demoting self because i do not have the lock and i was a leader"
else:
self.follow_the_leader()
return "no action. i am a secondary and i am following a leader"
except EtcdError:
logger.error("Error communicating with Etcd")
except OperationalError: