openshift_ansible.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. # pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,global-statement,global-variable-not-assigned
  2. import socket
  3. import subprocess
  4. import sys
  5. import os
  6. import yaml
  7. from ooinstall.variants import find_variant
  8. CFG = None
  9. ROLES_TO_GROUPS_MAP = {
  10. 'master': 'masters',
  11. 'node': 'nodes',
  12. 'etcd': 'etcd',
  13. 'storage': 'nfs',
  14. 'master_lb': 'lb'
  15. }
  16. VARIABLES_MAP = {
  17. 'ansible_ssh_user': 'ansible_ssh_user',
  18. 'ansible_config': 'ansible_config',
  19. 'ansible_log_path': 'ansible_log_path',
  20. 'deployment_type': 'deployment_type',
  21. 'master_routingconfig_subdomain':'openshift_master_default_subdomain',
  22. 'proxy_http':'openshift_http_proxy',
  23. 'proxy_https': 'openshift_https_proxy',
  24. 'proxy_exclude_hosts': 'openshift_no_proxy',
  25. }
  26. def set_config(cfg):
  27. global CFG
  28. CFG = cfg
  29. def generate_inventory(hosts):
  30. global CFG
  31. masters = [host for host in hosts if host.is_master()]
  32. multiple_masters = len(masters) > 1
  33. new_nodes = [host for host in hosts if host.is_node() and host.new_host]
  34. scaleup = len(new_nodes) > 0
  35. lb = determine_lb_configuration(hosts)
  36. base_inventory_path = CFG.settings['ansible_inventory_path']
  37. base_inventory = open(base_inventory_path, 'w')
  38. write_inventory_children(base_inventory, scaleup)
  39. write_inventory_vars(base_inventory, multiple_masters, lb)
  40. #write_inventory_hosts
  41. for role in CFG.deployment.roles:
  42. # write group block
  43. group = ROLES_TO_GROUPS_MAP.get(role, role)
  44. base_inventory.write("\n[{}]\n".format(group))
  45. # write each host
  46. group_hosts = [host for host in hosts if role in host.roles]
  47. for host in group_hosts:
  48. schedulable = host.is_schedulable_node(hosts)
  49. write_host(host, role, base_inventory, schedulable)
  50. if scaleup:
  51. base_inventory.write('\n[new_nodes]\n')
  52. for node in new_nodes:
  53. write_host(node, 'new_nodes', base_inventory)
  54. base_inventory.close()
  55. return base_inventory_path
  56. def determine_lb_configuration(hosts):
  57. lb = next((host for host in hosts if host.is_master_lb()), None)
  58. if lb:
  59. if lb.hostname == None:
  60. lb.hostname = lb.connect_to
  61. lb.public_hostname = lb.connect_to
  62. return lb
  63. def write_inventory_children(base_inventory, scaleup):
  64. global CFG
  65. base_inventory.write('\n[OSEv3:children]\n')
  66. for role in CFG.deployment.roles:
  67. child = ROLES_TO_GROUPS_MAP.get(role, role)
  68. base_inventory.write('{}\n'.format(child))
  69. if scaleup:
  70. base_inventory.write('new_nodes\n')
  71. # pylint: disable=too-many-branches
  72. def write_inventory_vars(base_inventory, multiple_masters, lb):
  73. global CFG
  74. base_inventory.write('\n[OSEv3:vars]\n')
  75. for variable, value in CFG.settings.iteritems():
  76. inventory_var = VARIABLES_MAP.get(variable, None)
  77. if inventory_var and value:
  78. base_inventory.write('{}={}\n'.format(inventory_var, value))
  79. for variable, value in CFG.deployment.variables.iteritems():
  80. inventory_var = VARIABLES_MAP.get(variable, variable)
  81. if value:
  82. base_inventory.write('{}={}\n'.format(inventory_var, value))
  83. if CFG.settings['ansible_ssh_user'] != 'root':
  84. base_inventory.write('ansible_become=yes\n')
  85. if multiple_masters and lb is not None:
  86. base_inventory.write('openshift_master_cluster_method=native\n')
  87. base_inventory.write("openshift_master_cluster_hostname={}\n".format(lb.hostname))
  88. base_inventory.write(
  89. "openshift_master_cluster_public_hostname={}\n".format(lb.public_hostname))
  90. if CFG.settings.get('variant_version', None) == '3.1':
  91. #base_inventory.write('openshift_image_tag=v{}\n'.format(CFG.settings.get('variant_version')))
  92. base_inventory.write('openshift_image_tag=v{}\n'.format('3.1.1.6'))
  93. write_proxy_settings(base_inventory)
  94. # Find the correct deployment type for ansible:
  95. ver = find_variant(CFG.settings['variant'],
  96. version=CFG.settings.get('variant_version', None))[1]
  97. base_inventory.write('deployment_type={}\n'.format(ver.ansible_key))
  98. if 'OO_INSTALL_ADDITIONAL_REGISTRIES' in os.environ:
  99. base_inventory.write('openshift_docker_additional_registries={}\n'
  100. .format(os.environ['OO_INSTALL_ADDITIONAL_REGISTRIES']))
  101. if 'OO_INSTALL_INSECURE_REGISTRIES' in os.environ:
  102. base_inventory.write('openshift_docker_insecure_registries={}\n'
  103. .format(os.environ['OO_INSTALL_INSECURE_REGISTRIES']))
  104. if 'OO_INSTALL_PUDDLE_REPO' in os.environ:
  105. # We have to double the '{' here for literals
  106. base_inventory.write("openshift_additional_repos=[{{'id': 'ose-devel', "
  107. "'name': 'ose-devel', "
  108. "'baseurl': '{}', "
  109. "'enabled': 1, 'gpgcheck': 0}}]\n".format(os.environ['OO_INSTALL_PUDDLE_REPO']))
  110. for name, role_obj in CFG.deployment.roles.iteritems():
  111. if role_obj.variables:
  112. group_name = ROLES_TO_GROUPS_MAP.get(name, name)
  113. base_inventory.write("\n[{}:vars]\n".format(group_name))
  114. for variable, value in role_obj.variables.iteritems():
  115. inventory_var = VARIABLES_MAP.get(variable, variable)
  116. if value:
  117. base_inventory.write('{}={}\n'.format(inventory_var, value))
  118. base_inventory.write("\n")
  119. def write_proxy_settings(base_inventory):
  120. try:
  121. base_inventory.write("openshift_http_proxy={}\n".format(
  122. CFG.settings['openshift_http_proxy']))
  123. except KeyError:
  124. pass
  125. try:
  126. base_inventory.write("openshift_https_proxy={}\n".format(
  127. CFG.settings['openshift_https_proxy']))
  128. except KeyError:
  129. pass
  130. try:
  131. base_inventory.write("openshift_no_proxy={}\n".format(
  132. CFG.settings['openshift_no_proxy']))
  133. except KeyError:
  134. pass
  135. # pylint: disable=too-many-branches
  136. def write_host(host, role, inventory, schedulable=None):
  137. global CFG
  138. if host.preconfigured:
  139. return
  140. facts = ''
  141. if host.ip:
  142. facts += ' openshift_ip={}'.format(host.ip)
  143. if host.public_ip:
  144. facts += ' openshift_public_ip={}'.format(host.public_ip)
  145. if host.hostname:
  146. facts += ' openshift_hostname={}'.format(host.hostname)
  147. if host.public_hostname:
  148. facts += ' openshift_public_hostname={}'.format(host.public_hostname)
  149. if host.containerized:
  150. facts += ' containerized={}'.format(host.containerized)
  151. if host.other_variables:
  152. for variable, value in host.other_variables.iteritems():
  153. facts += " {}={}".format(variable, value)
  154. if host.node_labels:
  155. facts += ' openshift_node_labels="{}"'.format(host.node_labels)
  156. # Distinguish between three states, no schedulability specified (use default),
  157. # explicitly set to True, or explicitly set to False:
  158. if role != 'node' or schedulable is None:
  159. pass
  160. else:
  161. facts += " openshift_schedulable={}".format(schedulable)
  162. installer_host = socket.gethostname()
  163. if installer_host in [host.connect_to, host.hostname, host.public_hostname]:
  164. facts += ' ansible_connection=local'
  165. if os.geteuid() != 0:
  166. no_pwd_sudo = subprocess.call(['sudo', '-n', 'echo', 'openshift'])
  167. if no_pwd_sudo == 1:
  168. print 'The atomic-openshift-installer requires sudo access without a password.'
  169. sys.exit(1)
  170. facts += ' ansible_become=yes'
  171. inventory.write('{} {}\n'.format(host.connect_to, facts))
  172. def load_system_facts(inventory_file, os_facts_path, env_vars, verbose=False):
  173. """
  174. Retrieves system facts from the remote systems.
  175. """
  176. FNULL = open(os.devnull, 'w')
  177. args = ['ansible-playbook', '-v'] if verbose \
  178. else ['ansible-playbook']
  179. args.extend([
  180. '--inventory-file={}'.format(inventory_file),
  181. os_facts_path])
  182. status = subprocess.call(args, env=env_vars, stdout=FNULL)
  183. if not status == 0:
  184. return [], 1
  185. with open(CFG.settings['ansible_callback_facts_yaml'], 'r') as callback_facts_file:
  186. try:
  187. callback_facts = yaml.safe_load(callback_facts_file)
  188. except yaml.YAMLError, exc:
  189. print "Error in {}".format(CFG.settings['ansible_callback_facts_yaml']), exc
  190. print "Try deleting and rerunning the atomic-openshift-installer"
  191. sys.exit(1)
  192. return callback_facts, 0
  193. def default_facts(hosts, verbose=False):
  194. global CFG
  195. inventory_file = generate_inventory(hosts)
  196. os_facts_path = '{}/playbooks/byo/openshift_facts.yml'.format(CFG.ansible_playbook_directory)
  197. facts_env = os.environ.copy()
  198. facts_env["OO_INSTALL_CALLBACK_FACTS_YAML"] = CFG.settings['ansible_callback_facts_yaml']
  199. facts_env["ANSIBLE_CALLBACK_PLUGINS"] = CFG.settings['ansible_plugins_directory']
  200. facts_env["OPENSHIFT_MASTER_CLUSTER_METHOD"] = 'native'
  201. if 'ansible_log_path' in CFG.settings:
  202. facts_env["ANSIBLE_LOG_PATH"] = CFG.settings['ansible_log_path']
  203. if 'ansible_config' in CFG.settings:
  204. facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
  205. return load_system_facts(inventory_file, os_facts_path, facts_env, verbose)
  206. def run_main_playbook(inventory_file, hosts, hosts_to_run_on, verbose=False):
  207. global CFG
  208. if len(hosts_to_run_on) != len(hosts):
  209. main_playbook_path = os.path.join(CFG.ansible_playbook_directory,
  210. 'playbooks/byo/openshift-node/scaleup.yml')
  211. else:
  212. main_playbook_path = os.path.join(CFG.ansible_playbook_directory,
  213. 'playbooks/byo/openshift-cluster/config.yml')
  214. facts_env = os.environ.copy()
  215. if 'ansible_log_path' in CFG.settings:
  216. facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path']
  217. if 'ansible_config' in CFG.settings:
  218. facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
  219. return run_ansible(main_playbook_path, inventory_file, facts_env, verbose)
  220. def run_ansible(playbook, inventory, env_vars, verbose=False):
  221. args = ['ansible-playbook', '-v'] if verbose \
  222. else ['ansible-playbook']
  223. args.extend([
  224. '--inventory-file={}'.format(inventory),
  225. playbook])
  226. return subprocess.call(args, env=env_vars)
  227. def run_uninstall_playbook(hosts, verbose=False):
  228. playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
  229. 'playbooks/adhoc/uninstall.yml')
  230. inventory_file = generate_inventory(hosts)
  231. facts_env = os.environ.copy()
  232. if 'ansible_log_path' in CFG.settings:
  233. facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path']
  234. if 'ansible_config' in CFG.settings:
  235. facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
  236. return run_ansible(playbook, inventory_file, facts_env, verbose)
  237. def run_upgrade_playbook(playbook, verbose=False):
  238. playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
  239. 'playbooks/byo/openshift-cluster/upgrades/{}'.format(playbook))
  240. # TODO: Upgrade inventory for upgrade?
  241. inventory_file = generate_inventory(CFG.hosts)
  242. facts_env = os.environ.copy()
  243. if 'ansible_log_path' in CFG.settings:
  244. facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path']
  245. if 'ansible_config' in CFG.settings:
  246. facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
  247. return run_ansible(playbook, inventory_file, facts_env, verbose)