| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- # encoding: utf-8
- import os
- import yaml
- from .color import GB
- from . import ocboot
- from .db import DB
- from .cmd import run_bash_cmd, ensure_pv
- from .utils import to_yaml
- from .utils import print_title
- ROOT_PATH = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
- PV_ARGS = 'pv --rate --timer --eta --progress'
- EXTRA_CMDS = []
- def add_command(subparsers):
- parser = subparsers.add_parser(
- "restore", help="restore onecloud cluster")
- parser.add_argument('--backup-path', dest='backup_path', help="backup path, default: /opt/backup", default="/opt/backup")
- parser.add_argument('--install-db-to-localhost', action='store_true', help="use this option when install local db")
- parser.add_argument('primary_ip', help="primary node ip")
- parser.add_argument('--master-node-ips', help="master nodes ips, seperated by comma ','")
- parser.add_argument('--master-node-as-host', action='store_true', help="use this option when use master nodes as host")
- parser.add_argument('--worker-node-ips', help="worker nodes ips, seperated by comma ','")
- parser.add_argument('--worker-node-as-host', action='store_true', help="use this option when use worker nodes as host")
- parser.add_argument('--mysql-host', help="mysql host; not needed if set --install-db-to-localhost")
- parser.add_argument('--mysql-user', default='root', help="mysql user, default: root; not needed if set --install-db-to-localhost")
- parser.add_argument('--mysql-password', help="mysql password; not needed if set --install-db-to-localhost")
- parser.add_argument('--mysql-port', default=3306, help="mysql port, default: 3306; not needed if set --install-db-to-localhost", type=int)
- parser.set_defaults(func=do_restore)
- def get_backup_db_password(args):
- config_file = os.path.join(args.backup_path, 'config.yml')
- assert os.path.exists(config_file), "the config file " + config_file + " dose not exist!"
- config = ocboot.load_config(config_file)
- primary_master_config = getattr(config, 'primary_master_config', None)
- db_password = getattr(primary_master_config, 'db_password', None)
- assert db_password, "the backup database password must not be empty!"
- return db_password
- db_config = {}
- def ensure_db_config(args):
- global db_config
- if db_config:
- return db_config
- ret = {}
- ip = args.primary_ip
- if args.install_db_to_localhost:
- ret['host'] = ip
- elif args.mysql_host:
- ret['host'] = args.mysql_host
- else:
- raise Exception("please set --install-db-to-localhost or --mysql-host option.")
- ret['port'] = args.mysql_port or '3306'
- ret['user'] = args.mysql_user or 'root'
- ret['passwd'] = args.mysql_password
- if not args.mysql_password:
- ret['passwd'] = get_backup_db_password(args)
- if args.install_db_to_localhost:
- # install
- import time
- mycnf = os.path.join(ROOT_PATH, 'onecloud/roles/mariadb/files/my.cnf')
- timestamp = str(time.time())
- bak_cnf = '/etc/my.cnf.%(timestamp)s' % locals()
- assert os.path.exists(mycnf)
- run_bash_cmd('''systemctl is-active mariadb > /dev/null || yum install -y mariadb-server && systemctl enable --now mariadb''')
- run_bash_cmd('''
- mv -fv /etc/my.cnf %(bak_cnf)s && cp -fv %(mycnf)s /etc/my.cnf && sudo systemctl restart mariadb''' % locals())
- # set password
- sqls = [
- '''grant all privileges on *.* to `%(user)s`@`localhost` identified by "%(passwd)s" with grant option''' % ret,
- '''grant all privileges on *.* to `%(user)s`@`%%` identified by "%(passwd)s" with grant option''' % ret,
- '''FLUSH PRIVILEGES''',
- '''set global net_buffer_length=999424 ''',
- '''set global max_allowed_packet=999999488 ''',
- '''set global group_concat_max_len=999999488 ''',
- ]
- db = DB()
- for sql in sqls:
- db.cursor.execute(sql)
- print("mysql init done.")
- db_config.update(ret)
- return db_config
- def source_db_files(args, tgz, db='', dry_run=False):
- db_args = '-h "%(host)s" -u "%(user)s" -p"%(passwd)s" -P "%(port)s"' % ensure_db_config(args)
- cmd = '''%(PV_ARGS)s --name " Restoring %(tgz)s " "%(tgz)s" | gunzip | mysql %(db_args)s %(db)s''' % {
- 'PV_ARGS': PV_ARGS,
- 'tgz': tgz,
- 'db_args': db_args,
- 'db': db,
- }
- if dry_run:
- return cmd
- else:
- run_bash_cmd(cmd)
- def restore_db(args):
- global EXTRA_CMDS
- from glob import glob
- os.chdir(args.backup_path)
- db_file_tar = os.path.join(args.backup_path, 'onecloud.sql.gz')
- source_db_files(args, db_file_tar)
- extra_files = glob('%s/*.sql.gz' % args.backup_path)
- extra_files = [i for i in extra_files if not i.endswith('/onecloud.sql.gz')]
- if extra_files:
- for i in extra_files:
- EXTRA_CMDS += [source_db_files(args, i, i.split('/')[-1].split('.')[0], dry_run=1)]
- print_title("Restore DB OK.")
- def generate_nodes(args, role):
- '''
- master_nodes:
- hosts:
- - hostname: $host1
- user: root
- use_local: false
- controlplane_host: $pri
- controlplane_port: "6443"
- as_controller: true
- registry_mirrors:
- - https://lje6zxpk.mirror.aliyuncs.com
- '''
- assert role in ['master', 'worker']
- ips = getattr(args, '%s_node_ips' % role)
- if not ips:
- return {}
- as_host = getattr(args, '%s_node_as_host' % role)
- vars = {
- 'controlplane_host': args.primary_ip,
- 'controlplane_port': "6443",
- 'as_controller': True,
- 'as_host': as_host,
- 'registry_mirrors': ['https://lje6zxpk.mirror.aliyuncs.com'],
- }
- nodes = []
- for i in ips.split(','):
- node = {
- 'hostname': i,
- 'user': 'root',
- }
- nodes += [node]
- vars['hosts'] = nodes
- return vars
- def restore_config(args):
- config_file = os.path.join(args.backup_path, 'config.yml')
- config_json = None
- with open(config_file, 'r') as stream:
- try:
- config_json = yaml.safe_load(stream)
- except yaml.YAMLError as exc:
- print(exc)
- # databases
- db_config = ensure_db_config(args)
- config_json['primary_master_node'].update({
- 'db_host': db_config.get('host'),
- 'db_password': db_config.get('passwd'),
- 'db_port': db_config.get('port'),
- 'db_user': db_config.get('user'),
- })
- config_json['mariadb_node'] = {
- "db_password": db_config.get('passwd'),
- "db_user": db_config.get('user'),
- "hostname": db_config.get('host'),
- "user": 'root',
- }
- # primary node ip update
- # if config_json['primary_master_node'].get('controlplane_host') != config_json['primary_master_node'].get('node_ip'):
- # raise Exception("Primary controlplane_host and node_ip are different. Not supported backup mode!")
- config_json['primary_master_node'].update({
- 'controlplane_host': args.primary_ip,
- 'node_ip': args.primary_ip,
- 'ip_autodetection_method': 'can-reach=%s' % args.primary_ip,
- 'restore_mode': True # very important for restoring.
- })
- for i in ['keepalived_version_tag', 'host_networks', 'image_repository', 'insecure_registries']:
- if i in config_json['primary_master_node']:
- del config_json['primary_master_node'][i]
- for i in ['master_node_ips', 'worker_nodes']:
- if i in config_json:
- del config_json[i]
- if args.master_node_ips:
- config_json['master_nodes'] = generate_nodes(args, 'master')
- if args.worker_node_ips:
- config_json['worker_nodes'] = generate_nodes(args, 'worker')
- yaml_content = ''
- for i in ['mariadb_node', 'primary_master_node', 'master_nodes', 'worker_nodes']:
- if i in config_json:
- yaml_content += to_yaml({i: config_json[i]})
- config_output = os.path.join(ROOT_PATH, 'config.yml')
- os.chdir(ROOT_PATH)
- with open('config.yml', 'w') as f:
- try:
- f.write(yaml_content)
- except IOError as e:
- print('write yaml config to %s error: %s!' % (config_file, e))
- run_bash_cmd(""" sed -i -e 's@^ iso_install_mode: true@# iso_install_mode: true@' '%s' """ % config_file)
- def helper():
- print('\n')
- print(GB("All done! please restore the k8s system by running:"))
- print("%s/run.py %s/config.yml" % (ROOT_PATH, ROOT_PATH))
- print
- if EXTRA_CMDS:
- print(GB('After the k8s is restored, please source the extra db tables:'))
- print('\n'.join(EXTRA_CMDS))
- def do_restore(args):
- ensure_pv()
- print_title('Restore DB')
- restore_db(args)
- print_title('Restore Config')
- restore_config(args)
- helper()
|