blob: c02a5acd1f452a6fbc24aa65cc50825d2a320307 [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)
37 if PID:
38 os.kill(pid, sig)
39
40
41def demote(demote_uid, demote_gid):
42 def set_ids():
43 os.setgid(demote_gid)
44 os.setuid(demote_uid)
45
46 return set_ids
47
48
49def execute_cmd(cmd, directory, uid, gid):
50 LOG.debug("Executing cmd '%s' with uid/gid %d/%d ", cmd, uid, gid)
51 return subprocess.Popen(cmd, cwd=directory, preexec_fn=demote(uid, gid))
52
53
54def dns_query(address, record_type, retries=10, interval=5):
55 dns_response = None
56 LOG.debug("DNS query for address '%s' record type '%s'", address, record_type)
57 while(retries > 0):
58 time.sleep(interval)
59 try:
60 dns_response = dns.resolver.query(address, record_type)
61 except:
62 LOG.error('Fail to get DNS records for autodiscovery retries %d', retries)
63 retries -= 1
64 else:
65 break
66
67 if dns_response:
68 LOG.debug('Got dns response %s', dns_response.__dict__)
69 return dns_response
70 else:
71 raise Exception('Fail to get DNS response')
72
73
74def get_data_dir(node_ip, retries=10, interval=5):
75 address = dns.reversename.from_address(node_ip)
76 ptr = dns_query(address, 'PTR', retries, interval)
77
78 if ptr:
79 # monitoring_server.2.c81t242vtv4qobpv75mckqwob.monitoring_monitoring.
80 ptr_str = str(ptr[0]).split('.')
81 # ptr_str[0] = service name, monitoring_server
82 # ptr_str[1] = replica number, 2
83 # ptr_str[3] = docker id, c81t242vtv4qobpv75mckqwob
84 # ptr_str[4] = network name, monitoring_monitoring
85 if ptr_str[1]:
86 return 'data/{}/'.format(ptr_str[1])
87
88 LOG.error('Fail to discover data dir')
89 raise Exception('Fail to discover data dir')
90
91
92def create_data_dir(data_dir_prefix, data_dir, uid, gid):
93 try:
94 os.makedirs(os.path.join(data_dir_prefix, data_dir))
95 except OSError as e:
96 if e.errno != errno.EEXIST:
97 LOG.error('Fail to create data dir, exiting')
98 raise Exception('Fail to create data dir')
99
100 os.chown(os.path.join(data_dir_prefix, data_dir), uid, gid)
101 return os.path.join(data_dir_prefix, data_dir)
102
103
104def calculate_hash(directory):
105 cur_hash = hashlib.sha256()
106 try:
107 for filename in os.listdir(directory):
108 try:
109 with open(os.path.join(directory, filename), "rb") as f:
110 for chunk in iter(lambda: f.read(io.DEFAULT_BUFFER_SIZE), b""):
111 cur_hash.update(chunk)
112 except IOError as e:
113 LOG.error('Fail to read file: %s', e)
114 except OSError as e:
115 LOG.error('Fail to calculate hash: %s', e)
116
117 return cur_hash.hexdigest()
118
119
120def wait_for_process_watch_config(proc, config_dir, interval=10):
121 config_hash = calculate_hash(config_dir)
122 while proc.poll() is None:
123 new_hash = calculate_hash(config_dir)
124 if config_hash != new_hash:
125 LOG.info('Reloading service, new hash %s', new_hash)
126 config_hash = new_hash
127 send_signal(proc.pid, signal.SIGHUP)
128
129 time.sleep(interval)
130
131 code = proc.poll()
132 LOG.info("Process exited with code %d", code)
133 sys.exit(code)
134
135def wait_for_process(proc):
136 code = proc.wait()
137 LOG.info("Process exited with code %d", code)
138 sys.exit(code)
139
140
141def run_service(cmd, cwd, uid, gid):
142 proc = execute_cmd(cmd, cwd, uid, gid)
143 return proc, proc.pid
144
145LOG = set_logger()