upgrade.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # encoding: utf-8
  2. from __future__ import unicode_literals
  3. import os
  4. from .ansible import AnsibleBastionHost
  5. from .cmd import run_ansible_playbook
  6. from .utils import get_major_version
  7. from .cluster import construct_cluster
  8. from .ocboot import get_ansible_global_vars
  9. from . import consts
  10. from getpass import getuser
  11. from lib import utils
  12. from lib import color
  13. UPGRADE_MODES_UPGRADE = 'upgrade'
  14. UPGRADE_MODES_UPGRADE_CONTROLLER = 'upgrade-controller'
  15. UPGRADE_MODES_UPGRADE_HOST = 'upgrade-host'
  16. UPGRADE_MODES_UPGRADE_FINAL = 'upgrade-final'
  17. UPGRADE_MODES_HELP_MSGS = {
  18. UPGRADE_MODES_UPGRADE: 'upgrade onecloud cluster to specified version',
  19. UPGRADE_MODES_UPGRADE_CONTROLLER: 'upgrade onecloud controller to specified version',
  20. UPGRADE_MODES_UPGRADE_HOST: 'upgrade onecloud host(s) to specified version',
  21. UPGRADE_MODES_UPGRADE_FINAL: 'upgrade onecloud cluster to specified version',
  22. }
  23. UPGRADE_MODES_ROLE_FILE = {
  24. UPGRADE_MODES_UPGRADE: './onecloud/upgrade-cluster.yml',
  25. UPGRADE_MODES_UPGRADE_CONTROLLER: './onecloud/upgrade-cluster-controller.yml',
  26. UPGRADE_MODES_UPGRADE_HOST: './onecloud/upgrade-cluster-host.yml',
  27. UPGRADE_MODES_UPGRADE_FINAL: './onecloud/upgrade-cluster-final.yml',
  28. }
  29. UPGRADE_MODES_FINISH_MSG = {
  30. UPGRADE_MODES_UPGRADE: "The system has been upgraded to the latest version.",
  31. UPGRADE_MODES_UPGRADE_CONTROLLER: "The Controller has been upgraded to the latest version.",
  32. UPGRADE_MODES_UPGRADE_HOST: "Worker nodes have been upgraded to the latest version.",
  33. UPGRADE_MODES_UPGRADE_FINAL: "The final step of the upgraded is now finished.",
  34. }
  35. def add_command(subparsers, command="upgrade"):
  36. parser = subparsers.add_parser(
  37. command, help=UPGRADE_MODES_HELP_MSGS.get(command, ''))
  38. # parser.add_argument('config', help="config file")
  39. # requirement options
  40. parser.add_argument("primary_master_host",
  41. metavar="FIRST_MASTER_HOST",
  42. help="onecloud cluster primary master host, \
  43. e.g., 10.1.2.56")
  44. parser.add_argument("version",
  45. metavar="VERSION",
  46. help="onecloud version to be upgrade, \
  47. e.g., v3.6.9")
  48. # optional options
  49. def help_d(help): return help + " (default: %(default)s)"
  50. parser.add_argument("--user", "-u",
  51. dest="ssh_user",
  52. default=getuser(),
  53. help=help_d("primary master host ssh user"))
  54. parser.add_argument("--key-file", "-k",
  55. dest="ssh_private_file",
  56. default=os.path.expanduser("~/.ssh/id_rsa"),
  57. help=help_d("primary master ssh private key file"))
  58. parser.add_argument("--port", "-p",
  59. dest="ssh_port",
  60. type=int,
  61. default="22",
  62. help=help_d("primary master host ssh port"))
  63. parser.add_argument("--node-port", "-n",
  64. dest="ssh_node_port",
  65. type=int,
  66. default="22",
  67. help=help_d("worker node host ssh port"))
  68. parser.add_argument("--as-bastion", "-B",
  69. dest="primary_as_bastion",
  70. action="store_true",
  71. help="use primary master node as ssh bastion host to run ansible")
  72. parser.add_argument("--image-repository", "-i",
  73. dest="image_repository",
  74. help="specify 3rd party image and namespace")
  75. parser.add_argument("--offline-data-path",
  76. dest="offline_data_path",
  77. default="",
  78. help="offline rpm repo path for upgrade mode")
  79. parser.add_argument("--primary-node-ip",
  80. dest="primary_node_ip",
  81. default="",
  82. help="offline rpm repo path for upgrade mode")
  83. parser.add_argument("--gpu-init", "-G",
  84. dest="gpu_init",
  85. action="store_true",
  86. default=False,
  87. help="re-init gpu druing upgrading. default: false.")
  88. if command == UPGRADE_MODES_UPGRADE_HOST:
  89. parser.add_argument("--hosts", "-H",
  90. dest='target_node_hosts',
  91. nargs='+',
  92. default=[],
  93. metavar="TARGET_NODE_HOSTS",
  94. help="target nodes ip added into cluster")
  95. parser.set_defaults(func=do_upgrade)
  96. def do_upgrade(args):
  97. cluster = construct_cluster(
  98. args.primary_master_host,
  99. args.ssh_user,
  100. args.ssh_private_file,
  101. args.ssh_port)
  102. playbook_file = UPGRADE_MODES_ROLE_FILE.get(args.subcmd, '')
  103. playbook_file = os.path.normpath(os.path.join(os.getcwd(), playbook_file))
  104. if os.path.getsize(playbook_file) == 0:
  105. print(color.red(f"Yaml file {playbook_file} is empty!"))
  106. exit(1)
  107. cur_ver = cluster.get_current_version()
  108. config = UpgradeConfig(cur_ver, args.version)
  109. bastion_host = None
  110. if args.primary_as_bastion:
  111. bastion_host = AnsibleBastionHost(args.primary_master_host)
  112. if args.subcmd == UPGRADE_MODES_UPGRADE_CONTROLLER:
  113. cluster.worker_nodes = []
  114. elif args.subcmd == UPGRADE_MODES_UPGRADE_HOST:
  115. cluster.worker_nodes = [i for i in cluster.worker_nodes if i.get_ip() in args.target_node_hosts]
  116. inventory_content = cluster.generate_playbook_inventory(bastion_host, args.ssh_port, args.ssh_node_port)
  117. inventory_f = '/tmp/test-hosts.ini'
  118. with open(inventory_f, 'w') as f:
  119. f.write(inventory_content)
  120. vars = config.to_ansible_vars(cluster)
  121. if args.image_repository:
  122. if args.image_repository == consts.REGISTRY_ALI_YUNION:
  123. if utils.is_below_v3_9(args.version):
  124. args.image_repository = consts.REGISTRY_ALI_YUNIONIO
  125. vars['image_repository'] = args.image_repository.rstrip('/')
  126. else:
  127. vars['image_repository'] = cluster.get_image_repository()
  128. if args.offline_data_path:
  129. vars['offline_data_path'] = args.offline_data_path
  130. vars['primary_master_host'] = args.primary_master_host
  131. # for sync files. no ha ip.
  132. if args.primary_node_ip:
  133. vars['primary_node_ip'] = args.primary_node_ip
  134. # when using -G: include gpu_init task;
  135. # when not using -G: ignore gpu_init task;
  136. # installation with run.py: include gpu_init task. (remains the same)
  137. if not args.gpu_init:
  138. vars['upgrade_without_gpu'] = True
  139. return_code = run_ansible_playbook(
  140. inventory_f,
  141. playbook_file,
  142. vars=vars,
  143. )
  144. if return_code is not None and return_code != 0:
  145. return return_code
  146. cluster.set_current_version(args.version)
  147. utils.pr_green('\n' + UPGRADE_MODES_FINISH_MSG.get(args.subcmd) + '\n')
  148. class UpgradeConfig(object):
  149. def __init__(self, cur_ver, upgrade_ver):
  150. self.current_onecloud_version = cur_ver
  151. self.current_onecloud_major_version = get_major_version(cur_ver)
  152. self.upgrade_onecloud_version = upgrade_ver
  153. self.upgrade_onecloud_major_version = get_major_version(upgrade_ver)
  154. def is_major_upgrade(self):
  155. return self.current_onecloud_major_version != self.upgrade_onecloud_major_version
  156. def get_yunion_yum_repo(self):
  157. ver = self.upgrade_onecloud_major_version.replace('_', '.')
  158. ver = ver[1:]
  159. return "https://iso.yunion.cn/centos/7/%s/x86_64/yunion.repo" % (ver)
  160. def to_ansible_vars(self, cluster):
  161. ret = {
  162. "current_onecloud_version": self.current_onecloud_version,
  163. "current_onecloud_major_version": self.current_onecloud_major_version,
  164. "upgrade_onecloud_version": self.upgrade_onecloud_version,
  165. "upgrade_onecloud_major_version": self.upgrade_onecloud_major_version,
  166. "is_major_upgrade": self.is_major_upgrade(),
  167. "yunion_yum_repo": self.get_yunion_yum_repo(),
  168. "yunion_qemu_package": "yunion-qemu-4.2.0",
  169. }
  170. g_var = get_ansible_global_vars(self.current_onecloud_version, cluster.is_using_k3s())
  171. ret.update(g_var)
  172. return ret