blob: e5c0e3e35beb80ed04062f5f4dc8bdd7349176f0 [file] [log] [blame]
Bartosz Kupiduraf82f4142017-09-05 16:18:45 +02001#!/usr/bin/env python
2
3import errno
4import hashlib
5import io
6import logging
7import os
8import pwd
Bartosz Kupidura5d394062017-09-06 12:32:53 +02009import signal
Bartosz Kupiduraf82f4142017-09-05 16:18:45 +020010import subprocess
11import sys
12import time
13
14try:
15 import dns.resolver
16 import dns.reversename
17except ImportError:
18 pass
19
20
21def get_uid_gid(username):
22 DAEMON_UID = pwd.getpwnam(username).pw_uid
23 DAEMON_GID = pwd.getpwnam(username).pw_gid
24 return DAEMON_UID, DAEMON_GID
25
26def set_logger(level=logging.DEBUG):
27 LOG_DATEFMT = "%Y-%m-%d %H:%M:%S"
28 LOG_FORMAT = "%(asctime)s.%(msecs)03d - %(levelname)s - %(message)s"
29 logging.basicConfig(format=LOG_FORMAT, datefmt=LOG_DATEFMT)
30 LOG = logging.getLogger(__name__)
31 LOG.setLevel(logging.DEBUG)
32 return LOG
33
34
35def send_signal(pid, sig):
36 LOG.debug('Sending signal %d to pid %d', sig, pid)
Bartosz Kupidura3b7b8c02017-09-06 13:23:18 +020037 os.kill(pid, sig)
Bartosz Kupiduraf82f4142017-09-05 16:18:45 +020038
39
40def demote(demote_uid, demote_gid):
41 def set_ids():
42 os.setgid(demote_gid)
43 os.setuid(demote_uid)
44
45 return set_ids
46
47
48def execute_cmd(cmd, directory, uid, gid):
49 LOG.debug("Executing cmd '%s' with uid/gid %d/%d ", cmd, uid, gid)
50 return subprocess.Popen(cmd, cwd=directory, preexec_fn=demote(uid, gid))
51
52
53def dns_query(address, record_type, retries=10, interval=5):
54 dns_response = None
55 LOG.debug("DNS query for address '%s' record type '%s'", address, record_type)
56 while(retries > 0):
57 time.sleep(interval)
58 try:
59 dns_response = dns.resolver.query(address, record_type)
60 except:
61 LOG.error('Fail to get DNS records for autodiscovery retries %d', retries)
62 retries -= 1
63 else:
64 break
65
66 if dns_response:
67 LOG.debug('Got dns response %s', dns_response.__dict__)
68 return dns_response
69 else:
70 raise Exception('Fail to get DNS response')
71
72
73def get_data_dir(node_ip, retries=10, interval=5):
74 address = dns.reversename.from_address(node_ip)
75 ptr = dns_query(address, 'PTR', retries, interval)
76
77 if ptr:
78 # monitoring_server.2.c81t242vtv4qobpv75mckqwob.monitoring_monitoring.
79 ptr_str = str(ptr[0]).split('.')
80 # ptr_str[0] = service name, monitoring_server
81 # ptr_str[1] = replica number, 2
82 # ptr_str[3] = docker id, c81t242vtv4qobpv75mckqwob
83 # ptr_str[4] = network name, monitoring_monitoring
84 if ptr_str[1]:
85 return 'data/{}/'.format(ptr_str[1])
86
87 LOG.error('Fail to discover data dir')
88 raise Exception('Fail to discover data dir')
89
90
91def create_data_dir(data_dir_prefix, data_dir, uid, gid):
92 try:
93 os.makedirs(os.path.join(data_dir_prefix, data_dir))
94 except OSError as e:
95 if e.errno != errno.EEXIST:
96 LOG.error('Fail to create data dir, exiting')
97 raise Exception('Fail to create data dir')
98
99 os.chown(os.path.join(data_dir_prefix, data_dir), uid, gid)
100 return os.path.join(data_dir_prefix, data_dir)
101
102
103def calculate_hash(directory):
104 cur_hash = hashlib.sha256()
105 try:
106 for filename in os.listdir(directory):
107 try:
108 with open(os.path.join(directory, filename), "rb") as f:
109 for chunk in iter(lambda: f.read(io.DEFAULT_BUFFER_SIZE), b""):
110 cur_hash.update(chunk)
111 except IOError as e:
112 LOG.error('Fail to read file: %s', e)
113 except OSError as e:
114 LOG.error('Fail to calculate hash: %s', e)
115
116 return cur_hash.hexdigest()
117
118
119def wait_for_process_watch_config(proc, config_dir, interval=10):
120 config_hash = calculate_hash(config_dir)
121 while proc.poll() is None:
122 new_hash = calculate_hash(config_dir)
123 if config_hash != new_hash:
124 LOG.info('Reloading service, new hash %s', new_hash)
125 config_hash = new_hash
126 send_signal(proc.pid, signal.SIGHUP)
127
128 time.sleep(interval)
129
130 code = proc.poll()
131 LOG.info("Process exited with code %d", code)
132 sys.exit(code)
133
134def wait_for_process(proc):
135 code = proc.wait()
136 LOG.info("Process exited with code %d", code)
137 sys.exit(code)
138
139
140def run_service(cmd, cwd, uid, gid):
141 proc = execute_cmd(cmd, cwd, uid, gid)
142 return proc, proc.pid
143
144LOG = set_logger()