utils.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #!/usr/bin/env python
  2. '''
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. '''
  17. import os
  18. import re
  19. import signal
  20. import socket
  21. import sys
  22. import time
  23. import glob
  24. import subprocess
  25. from ambari_commons import OSConst,OSCheck
  26. # PostgreSQL settings
  27. PG_STATUS_RUNNING_DEFAULT = "running"
  28. PG_HBA_ROOT_DEFAULT = "/var/lib/pgsql/data"
  29. #Environment
  30. ENV_PATH_DEFAULT = ['/bin', '/usr/bin', '/sbin', '/usr/sbin'] # default search path
  31. ENV_PATH = os.getenv('PATH', '').split(':') + ENV_PATH_DEFAULT
  32. #Process
  33. PROC_DIR = '/proc'
  34. PROC_CMDLINE = 'cmdline'
  35. PROC_EXEC = 'exe'
  36. def get_pg_hba_init_files():
  37. if OSCheck.is_ubuntu_family():
  38. return '/etc/postgresql'
  39. elif OSCheck.is_redhat_family():
  40. return '/etc/rc.d/init.d/postgresql'
  41. elif OSCheck.is_suse_family():
  42. return '/etc/init.d/postgresql'
  43. else:
  44. raise Exception("Unsupported OS family '{0}'".format(OSCheck.get_os_family()))
  45. # ToDo: move that function to common-functions
  46. def locate_file(filename, default=''):
  47. """Locate command path according to OS environment"""
  48. for path in ENV_PATH:
  49. path = os.path.join(path, filename)
  50. if os.path.isfile(path):
  51. return path
  52. if default != '':
  53. return os.path.join(default, filename)
  54. else:
  55. return filename
  56. def check_exitcode(exitcode_file_path):
  57. """
  58. Return exitcode of application, which is stored in the exitcode_file_path
  59. """
  60. exitcode = -1
  61. if os.path.isfile(exitcode_file_path):
  62. try:
  63. f = open(exitcode_file_path, "rb")
  64. exitcode = int(f.read())
  65. f.close()
  66. os.remove(exitcode_file_path)
  67. except IOError:
  68. pass
  69. return exitcode
  70. def save_pid(pid, pidfile):
  71. """
  72. Save pid to pidfile.
  73. """
  74. try:
  75. pfile = open(pidfile, "w")
  76. pfile.write("%s\n" % pid)
  77. except IOError:
  78. pass
  79. finally:
  80. try:
  81. pfile.close()
  82. except:
  83. pass
  84. def save_main_pid_ex(pids, pidfile, exclude_list=[], kill_exclude_list=False):
  85. """
  86. Save pid which is not included to exclude_list to pidfile.
  87. If kill_exclude_list is set to true, all processes in that
  88. list would be killed. It's might be useful to daemonize child process
  89. exclude_list contains list of full executable paths which should be excluded
  90. """
  91. try:
  92. pfile = open(pidfile, "w")
  93. for item in pids:
  94. if pid_exists(item["pid"]) and (item["exe"] not in exclude_list):
  95. pfile.write("%s\n" % item["pid"])
  96. if pid_exists(item["pid"]) and (item["exe"] in exclude_list):
  97. try:
  98. os.kill(int(item["pid"]), signal.SIGKILL)
  99. except:
  100. pass
  101. except IOError:
  102. pass
  103. finally:
  104. try:
  105. pfile.close()
  106. except:
  107. pass
  108. def wait_for_pid(pids, timeout):
  109. """
  110. Check pid for existence during timeout
  111. """
  112. tstart = time.time()
  113. pid_live = 0
  114. while int(time.time()-tstart) <= timeout and len(pids) > 0:
  115. sys.stdout.write('.')
  116. sys.stdout.flush()
  117. pid_live = 0
  118. for item in pids:
  119. if pid_exists(item["pid"]):
  120. pid_live += 1
  121. time.sleep(1)
  122. return pid_live
  123. def get_symlink_path(path_to_link):
  124. """
  125. Expand symlink to real file path
  126. """
  127. return os.path.normpath(os.path.join(
  128. os.path.dirname(path_to_link),
  129. os.readlink(path_to_link)
  130. ))
  131. def looking_for_pid(pattern, wait_time=1):
  132. """
  133. Searching for pid according to given pattern of command line
  134. during wait_time.
  135. Wait time is required to give a time to process to be executed.
  136. Return list of PID Items, which match the pattern.
  137. """
  138. tstart = time.time()
  139. found_pids = []
  140. while int(time.time()-tstart) <= wait_time:
  141. sys.stdout.write('.')
  142. sys.stdout.flush()
  143. pids = [pid for pid in os.listdir(PROC_DIR) if pid.isdigit()]
  144. found_pids = [] # clear list
  145. for pid in pids:
  146. try:
  147. arg = open(os.path.join(PROC_DIR, pid, PROC_CMDLINE), 'rb').read()
  148. if pattern in arg:
  149. found_pids += [{
  150. "pid": pid,
  151. "exe": get_symlink_path(os.path.join(PROC_DIR, pid, PROC_EXEC)),
  152. "cmd": arg.replace('\x00', ' ').strip()
  153. }]
  154. except:
  155. pass
  156. if wait_time == 1: # to support unit test
  157. break
  158. time.sleep(1)
  159. return found_pids
  160. def pid_exists(pid):
  161. """
  162. Check if pid is exist
  163. """
  164. return os.path.exists(os.path.join(PROC_DIR, pid))
  165. def get_ubuntu_pg_version():
  166. """Return installed version of postgre server. In case of several
  167. installed versions will be returned a more new one.
  168. """
  169. postgre_ver = ""
  170. if os.path.isdir(get_pg_hba_init_files()): # detect actual installed versions of PG and select a more new one
  171. postgre_ver = sorted(
  172. [fld for fld in os.listdir(get_pg_hba_init_files()) if
  173. os.path.isdir(os.path.join(get_pg_hba_init_files(), fld))],
  174. reverse=True)
  175. if len(postgre_ver) > 0:
  176. return postgre_ver[0]
  177. return postgre_ver
  178. def get_postgre_hba_dir(OS_FAMILY):
  179. """Return postgre hba dir location depends on OS.
  180. Also depends on version of postgres creates symlink like postgresql-->postgresql-9.3
  181. 1) /etc/rc.d/init.d/postgresql --> /etc/rc.d/init.d/postgresql-9.3
  182. 2) /etc/init.d/postgresql --> /etc/init.d/postgresql-9.1
  183. """
  184. if OSCheck.is_ubuntu_family():
  185. # Like: /etc/postgresql/9.1/main/
  186. return os.path.join(get_pg_hba_init_files(), get_ubuntu_pg_version(),
  187. "main")
  188. elif OSCheck.is_redhat7():
  189. return PG_HBA_ROOT_DEFAULT
  190. else:
  191. if not os.path.isfile(get_pg_hba_init_files()):
  192. # Link: /etc/init.d/postgresql --> /etc/init.d/postgresql-9.1
  193. os.symlink(glob.glob(get_pg_hba_init_files() + '*')[0],
  194. get_pg_hba_init_files())
  195. # Get postgres_data location (default: /var/lib/pgsql/data)
  196. cmd = "alias exit=return; source " + get_pg_hba_init_files() + " status &>/dev/null; echo $PGDATA"
  197. p = subprocess.Popen(cmd,
  198. stdout=subprocess.PIPE,
  199. stdin=subprocess.PIPE,
  200. stderr=subprocess.PIPE,
  201. shell=True)
  202. (PG_HBA_ROOT, err) = p.communicate()
  203. if PG_HBA_ROOT and len(PG_HBA_ROOT.strip()) > 0:
  204. return PG_HBA_ROOT.strip()
  205. else:
  206. return PG_HBA_ROOT_DEFAULT
  207. def get_postgre_running_status():
  208. """Return postgre running status indicator"""
  209. if OSCheck.is_ubuntu_family():
  210. return os.path.join(get_ubuntu_pg_version(), "main")
  211. else:
  212. return PG_STATUS_RUNNING_DEFAULT
  213. def compare_versions(version1, version2):
  214. """Compare two versions by digits. Ignore any alphanumeric characters after - and _ postfix.
  215. Return 1 if version1 is newer than version2
  216. Return -1 if version1 is older than version2
  217. Return 0 if two versions are the same
  218. """
  219. def normalize(v):
  220. v = str(v)
  221. v = re.sub(r'^\D+', '', v)
  222. v = re.sub(r'\D+$', '', v)
  223. v = v.strip(".-_")
  224. pos_under = v.find("_")
  225. pos_dash = v.find("-")
  226. if pos_under > 0 and pos_dash < 0:
  227. pos = pos_under
  228. elif pos_under < 0 and pos_dash > 0:
  229. pos = pos_dash
  230. else:
  231. pos = min(pos_under, pos_dash)
  232. if pos > 0:
  233. v = v[0:pos]
  234. return [int(x) for x in re.sub(r'(\.0+)*$', '', v).split(".")]
  235. return cmp(normalize(version1), normalize(version2))
  236. pass
  237. def check_reverse_lookup():
  238. """
  239. Check if host fqdn resolves to current host ip
  240. """
  241. try:
  242. host_name = socket.gethostname().lower()
  243. host_ip = socket.gethostbyname(host_name)
  244. host_fqdn = socket.getfqdn().lower()
  245. fqdn_ip = socket.gethostbyname(host_fqdn)
  246. return host_ip == fqdn_ip
  247. except socket.error:
  248. pass
  249. return False