utils.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import functools
  2. import json
  3. import re
  4. import socket
  5. import subprocess
  6. import time
  7. import traceback
  8. from oslo_config import cfg
  9. from oslo_log import log as logging
  10. from coriolis import constants
  11. opts = [
  12. cfg.StrOpt('qemu_img_path',
  13. default='qemu-img',
  14. help='The path of the qemu-img tool.'),
  15. ]
  16. CONF = cfg.CONF
  17. CONF.register_opts(opts)
  18. LOG = logging.getLogger(__name__)
  19. def retry_on_error(max_attempts=5, sleep_seconds=1):
  20. def _retry_on_error(func):
  21. @functools.wraps(func)
  22. def _exec_retry(*args, **kwargs):
  23. i = 0
  24. while True:
  25. try:
  26. return func(*args, **kwargs)
  27. except Exception as ex:
  28. i += 1
  29. if i < max_attempts:
  30. LOG.warn("Exception occurred, retrying: %s", ex)
  31. time.sleep(sleep_seconds)
  32. else:
  33. raise
  34. return _exec_retry
  35. return _retry_on_error
  36. def get_linux_os_info(ssh):
  37. out = exec_ssh_cmd(ssh, "lsb_release -a || true").decode()
  38. dist_id = re.findall('^Distributor ID:\s(.*)$', out, re.MULTILINE)
  39. release = re.findall('^Release:\s(.*)$', out, re.MULTILINE)
  40. if dist_id and release:
  41. return (dist_id[0], release[0])
  42. @retry_on_error()
  43. def exec_ssh_cmd(ssh, cmd):
  44. stdin, stdout, stderr = ssh.exec_command(cmd)
  45. exit_code = stdout.channel.recv_exit_status()
  46. std_out = stdout.read()
  47. std_err = stderr.read()
  48. if exit_code:
  49. raise Exception("Command \"%s\" failed with exit code: %s\n"
  50. "stdout: %s\nstd_err: %s" %
  51. (cmd, exit_code, std_out, std_err))
  52. return std_out
  53. def exec_ssh_cmd_chroot(ssh, chroot_dir, cmd):
  54. return exec_ssh_cmd(ssh, "sudo chroot %s %s" % (chroot_dir, cmd))
  55. def _check_port_open(host, port):
  56. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  57. try:
  58. s.settimeout(1)
  59. s.connect((host, port))
  60. return True
  61. except ConnectionRefusedError:
  62. return False
  63. except socket.timeout:
  64. return False
  65. finally:
  66. s.close()
  67. def wait_for_port_connectivity(address, port):
  68. i = 0
  69. while not _check_port_open(address, port) and i < 120:
  70. time.sleep(1)
  71. i += 1
  72. if i == 120:
  73. raise Exception("Connection failed on port %s" % port)
  74. def exec_process(args):
  75. p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  76. std_out, std_err = p.communicate()
  77. if p.returncode:
  78. raise Exception(
  79. "Command \"%s\" failed with exit code: %s\nstdout: %s\nstd_err: %s"
  80. % (args, p.returncode, std_out, std_err))
  81. return std_out
  82. def get_disk_info(disk_path):
  83. out = exec_process([CONF.qemu_img_path, 'info', '--output=json',
  84. disk_path])
  85. disk_info = json.loads(out.decode())
  86. if disk_info["format"] == "vpc":
  87. disk_info["format"] = constants.DISK_FORMAT_VHD
  88. return disk_info
  89. def convert_disk_format(disk_path, target_disk_path, target_format):
  90. if target_format == constants.DISK_FORMAT_VHD:
  91. target_format = "vpc"
  92. exec_process([CONF.qemu_img_path, 'convert', '-O', target_format,
  93. disk_path, target_disk_path])
  94. def get_hostname():
  95. return socket.gethostname()
  96. def get_exception_details():
  97. return traceback.format_exc()