import logging
import os
import sys
import time
import yaml

from patroni.api import RestApiServer
from patroni.etcd import Etcd
from patroni.ha import Ha
from patroni.postgresql import Postgresql
from patroni.utils import setup_signal_handlers, reap_children
from patroni.zookeeper import ZooKeeper
from .version import __version__

logger = logging.getLogger(__name__)


class Patroni(object):

    def __init__(self, config):
        self.nap_time = config['loop_wait']
        self.tags = config.get('tags', dict())
        self.postgresql = Postgresql(config['postgresql'])
        self.dcs = self.get_dcs(self.postgresql.name, config)
        self.version = __version__
        self.api = RestApiServer(self, config['restapi'])
        self.ha = Ha(self)
        self.next_run = time.time()

    @property
    def nofailover(self):
        return self.tags.get('nofailover', False)

    @property
    def replicatefrom(self):
        return self.tags.get('replicatefrom')

    @property
    def clonefrom(self):
        return self.tags.get('clonefrom')

    @staticmethod
    def get_dcs(name, config):
        if 'etcd' in config:
            return Etcd(name, config['etcd'])
        if 'zookeeper' in config:
            return ZooKeeper(name, config['zookeeper'])
        raise Exception('Can not find suitable configuration of distributed configuration store')

    def schedule_next_run(self):
        self.next_run += self.nap_time
        current_time = time.time()
        nap_time = self.next_run - current_time
        if nap_time <= 0:
            self.next_run = current_time
        elif self.dcs.watch(nap_time):
            self.next_run = time.time()

    def run(self):
        self.api.start()
        self.next_run = time.time()

        while True:
            logger.info(self.ha.run_cycle())
            reap_children()
            self.schedule_next_run()


def main():
    logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
    logging.getLogger('requests').setLevel(logging.WARNING)
    setup_signal_handlers()

    if len(sys.argv) < 2 or not os.path.isfile(sys.argv[1]):
        print('Usage: {0} config.yml'.format(sys.argv[0]))
        return

    with open(sys.argv[1], 'r') as f:
        config = yaml.load(f)

    patroni = Patroni(config)
    try:
        patroni.run()
    except KeyboardInterrupt:
        pass
    finally:
        patroni.api.shutdown()
        patroni.postgresql.stop(checkpoint=False)
        patroni.dcs.delete_leader()

@@ -388,16 +388,70 @@
 object):
+%0A    PATRONI_CONFIG_VARIABLE = 'PATRONI_CONFIGURATION'
 %0A%0A    de
@@ -2134,19 +2134,167 @@
 ()%0A%0A    
-if 
+# Patroni reads the configuration from the command-line argument if it exists, and from the environment otherwise.%0A    use_env = False%0A    use_file = (
 len(sys.
@@ -2303,18 +2303,16 @@
 gv) 
-%3C 2 or not
+%3E= 2 and
  os.
@@ -2339,85 +2339,424 @@
 %5B1%5D)
-:%0A        print('Usage: %7B0%7D config.yml'.format(sys.argv%5B0%5D))%0A        return%0A%0A
+)%0A    if not use_file:%0A        config_env = os.environ.get(Patroni.PATRONI_CONFIG_VARIABLE)%0A        use_env = config_env is not None%0A        if not use_env:%0A            print('Usage: %7B0%7D config.yml'.format(sys.argv%5B0%5D))%0A            print('%5CtPatroni may also read the configuration from the %7B%7D environemnt variable'.%0A                  format(Patroni.PATRONI_CONFIG_VARIABLE))%0A            return%0A%0A    if use_file:%0A    
     
@@ -2793,24 +2793,28 @@
  f:%0A        
+    
 config = yam
@@ -2822,16 +2822,73 @@
 .load(f)
+%0A    elif use_env:%0A        config = yaml.load(config_env)
 %0A%0A    pa

Read Patroni configuration from the environment.