????
Current Path : /proc/self/root/usr/lib/Acronis/PyShell/site-tools/ |
Current File : //proc/self/root/usr/lib/Acronis/PyShell/site-tools/change_machine_id.py |
# Script allows to change machine and instance identifiers, it leads to the following changes on agent: # - DML database will be cleared # - Archives database will be cleared # - Certificates for Online Backup will be removed # - All scheduled tasks will be removed # Examples: # Create and set new machine and instance IDs, in full and short forms # change_machine_id.py --machine-id new --instance-id new # change_machine_id.py -m new -i new # Set predefined machine and instance IDs # change_machine_id.py -m D2A9C54A-5D7F-4CBB-B1DB-1F2D77A012B5 -i 5449D007-3E76-47D1-9BD0-D2CBB03B775E import acrort import argparse import configparser import glob import os import platform import re import subprocess import time import uuid import yaml OS_WINDOWS = 'Windows' OS_LINUX = 'Linux' OS_MAC = 'Darwin' def get_product_data_path(): return os.path.join(acrort.fs.APPDATA_COMMON, acrort.common.BRAND_NAME) def get_product_installation_path(): system = platform.system() if system == OS_WINDOWS: key = r'SOFTWARE\{}\Installer'.format(acrort.common.BRAND_NAME) return registry_read_string(key, 'TargetDir') elif system == OS_LINUX: return '/usr/lib/' + acrort.common.BRAND_NAME elif system == OS_MAC: return '/Library/Application Support/BackupClient/' + acrort.common.BRAND_NAME acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() def get_scheduler_path(): system = platform.system() if system == OS_WINDOWS: scheduler_path = os.path.join(get_product_installation_path(), 'BackupAndRecovery', 'schedmgr') elif system == OS_LINUX: scheduler_path = '/usr/sbin/schedmgr' elif system == OS_MAC: scheduler_path = '/Library/Application Support/BackupClient/{}/sbin/schedmgr'.format(acrort.common.BRAND_NAME) else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() return scheduler_path def get_settings_key(): return r'SOFTWARE\{}\BackupAndRecovery\Settings'.format(acrort.common.BRAND_NAME) def get_machine_settings_key(): return get_settings_key() + r'\MachineManager' def is_guid(key): RE_UUID = re.compile("[0-F]{8}-[0-F]{4}-[0-F]{4}-[0-F]{4}-[0-F]{12}", re.I) return bool(RE_UUID.match(key)) def registry_read_string(key_name, value_name, open_hive=None): root_reg = acrort.registry.open_system_hive(hive=open_hive) if key_name not in root_reg.subkeys: acrort.common.make_logic_error( "Key '{}' not found. May be MMS service is not installed".format(key_name)).throw() key = root_reg.subkeys.open(key_name=key_name) if value_name not in key.values: acrort.common.make_logic_error( "Value '{}' not found. May be MMS service is not installed".format(value_name)).throw() value = key.values.open(value_name=value_name) return value.get(acrort.registry.TYPE_SZ) def registry_write_string(key_name, value_name, data, open_hive=None): root_reg = acrort.registry.open_system_hive(hive=open_hive) if key_name not in root_reg.subkeys: acrort.common.make_logic_error( "Key '{}' not found. May be MMS service is not installed".format(key_name)).throw() key = root_reg.subkeys.open(key_name=key_name) if value_name not in key.values: acrort.common.make_logic_error( "Value '{}' not found. May be MMS service is not installed".format(value_name)).throw() value = key.values.open(value_name=value_name) return value.set(data, acrort.registry.TYPE_SZ) def registry_delete_key(key_name, value_name, open_hive=None): root_reg = acrort.registry.open_system_hive(hive=open_hive) if key_name not in root_reg.subkeys: return key = root_reg.subkeys.open(key_name=key_name) if value_name not in key.values: return key.values.delete(value_name=value_name) def get_current_machine_id(): return registry_read_string(get_machine_settings_key(), 'MMSCurrentMachineID') def set_current_machine_id(machine_id): # Set machine ID in the registry registry_write_string(get_machine_settings_key(), 'MMSCurrentMachineID', machine_id) # Set machine ID in the aakore config aakore_config_path = get_aakore_config_file_path() with open(aakore_config_path, 'w') as aakore: try: config = {} config['id'] = machine_id.lower() yaml.dump(config, aakore, default_flow_style=False) except Exception as e: acrort.common.make_logic_error('Failed to modify aakore config with error: ' + str(e)).throw() def get_current_instance_id(): return registry_read_string(get_machine_settings_key(), 'InstanceID') def set_current_instance_id(instance_id): registry_write_string(get_machine_settings_key(), 'InstanceID', instance_id) def is_service_running(service_name): system = platform.system() if system == OS_WINDOWS: args = ['sc', 'query', service_name] ps = subprocess.Popen(args, stdout=subprocess.PIPE) output = ps.communicate()[0] return 'STOPPED' not in str(output) elif system in [OS_MAC, OS_LINUX]: ps = subprocess.Popen(('ps', 'aux'), stdout=subprocess.PIPE) output = ps.communicate()[0] return ('/' + service_name) in str(output) acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() def get_systemd_service_stop_timeout_sec(service_name, default_value): config = configparser.ConfigParser() config.read('/etc/systemd/system/' + service_name + '.service') value = str(config.get('Service', 'TimeoutStopSec', fallback=default_value)) if value.endswith("min"): return int(value.replace('min', '')) * 60 else: return int(value) def start_service(windows_name, unix_name, display_name): try: system = platform.system() if system == OS_WINDOWS: args = ['sc', 'start', windows_name] elif system == OS_LINUX: args = ['service', unix_name, 'start'] elif system == OS_MAC: args = ['launchctl', 'start', unix_name] else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() print('Execute command: {}'.format(' '.join(args))) subprocess.run(args, stdout=subprocess.DEVNULL, check=True) except Exception as e: print('Can\'t start {} service: {}'.format(display_name, str(e))) def stop_service(windows_name, unix_name, display_name, is_service_running): try: system = platform.system() if system == OS_WINDOWS: args = ['sc', 'stop', windows_name] timeout = 60 elif system == OS_LINUX: args = ['service', unix_name, 'stop'] timeout = get_systemd_service_stop_timeout_sec(unix_name, 60) elif system == OS_MAC: args = ['launchctl', 'stop', unix_name] timeout = 60 else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() print('Execute command: {}'.format(' '.join(args))) subprocess.run(args, stdout=subprocess.DEVNULL, check=True, timeout=timeout) except subprocess.CalledProcessError as e: acrort.common.make_logic_error( 'Can\'t stop {} service with error: {}'.format(display_name, str(e))).throw() else: # Lookup for target process, wait if it is still here wait_reattempts = 10 while wait_reattempts: time.sleep(10) if not is_service_running(): break wait_reattempts = wait_reattempts - 1 if not wait_reattempts: acrort.common.make_logic_error( 'Can\'t stop {} service, please stop it manually.'.format(display_name)).throw() def stop_service_process(): system = platform.system() if system == OS_WINDOWS: # Kill service-processes too args = ['taskkill' , '/FI', 'IMAGENAME eq service_process.exe', '/F', '/T'] subprocess.run(args, stdout=subprocess.DEVNULL, check=False) # Aakore def get_aakore_config_file_path(): system = platform.system() if system == OS_WINDOWS: aakore_path = os.path.join(get_product_data_path(), r'Agent\var\aakore\reg.yml') elif system == OS_LINUX: aakore_path = '/opt/acronis/var/aakore/reg.yml' elif system == OS_MAC: aakore_path = '/Library/Application Support/{}/Agent/var/aakore/reg.yml'.format(acrort.common.BRAND_NAME) else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() return aakore_path def is_aakore_service_running(): return is_service_running('aakore') def start_aakore_service(): start_service('aakore', 'aakore', 'Aakore') def stop_aakore_service(): stop_service('aakore', 'aakore', 'Aakore', is_aakore_service_running) # MMS def is_mms_service_running(): return is_service_running('mms') def start_mms_service(): start_service('mms', 'acronis_mms', 'MMS') def stop_mms_service(): stop_service('mms', 'acronis_mms', 'MMS', is_mms_service_running) stop_service_process() # EmergencyUpdater def is_emergency_updater_service_running(): system = platform.system() if system == OS_WINDOWS: args = ['sc', 'query', 'emergency-updater'] ps = subprocess.Popen(args, stdout=subprocess.PIPE) ps.wait() if ps.returncode != 0: # service not installed return False return is_service_running('emergency-updater') def start_emergency_updater_service(): start_service('emergency-updater', 'emergency-updater', 'EmergencyUpdater') def stop_emergency_updater_service(): stop_service('emergency-updater', 'emergency-updater', 'EmergencyUpdater', is_emergency_updater_service_running) stop_service_process() def remove_files(path): files = glob.glob(path) for f in files: reattempts = 10 while reattempts: try: os.remove(f) except FileNotFoundError: break except PermissionError as e: reattempts = reattempts - 1 if not reattempts: print(str(e)) raise time.sleep(10) else: break def drop_acp_agent_caches(): system = platform.system() if system == OS_WINDOWS: acp_agent_aakore_cache_path = os.path.join(get_product_data_path(), 'Agent', 'var', 'atp-agent', 'aakore_proxy_cache.json') elif system == OS_LINUX: acp_agent_aakore_cache_path = '/opt/acronis/var/atp-agent/aakore_proxy_cache.json' elif system == OS_MAC: acp_agent_aakore_cache_path = '/Library/Application Support/Acronis/Agent/var/atp-agent/aakore_proxy_cache.json' else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() remove_files(acp_agent_aakore_cache_path) def drop_acp_updater_caches(): system = platform.system() if system == OS_WINDOWS: acp_updater_config_cache_path = os.path.join(get_product_data_path(), 'Agent', 'var', 'atp-downloader', 'atp-downloader.json') elif system == OS_LINUX: acp_updater_config_cache_path = '/opt/acronis/var/atp-downloader/atp-downloader.json' elif system == OS_MAC: acp_updater_config_cache_path = '/Library/Application Support/Acronis/Agent/var/atp-downloader/atp-downloader.json' else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() remove_files(acp_updater_config_cache_path) def drop_acp_sh_inventory_caches(): system = platform.system() if system == OS_WINDOWS: acp_sh_inventory_instance_id_cache_path = os.path.join(get_product_data_path(), 'Agent', 'var', 'sh-inventory', '.resource') elif system == OS_LINUX: acp_sh_inventory_instance_id_cache_path = '/opt/acronis/var/sh-inventory/.resource' elif system == OS_MAC: acp_sh_inventory_instance_id_cache_path = '/Library/Application Support/Acronis/Agent/var/sh-inventory/.resource' else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() remove_files(acp_sh_inventory_instance_id_cache_path) def drop_emergency_updater_service_caches(): system = platform.system() if system == OS_WINDOWS: emergency_updater_aakore_cache_path = os.path.join(get_product_data_path(), 'Agent', 'var', 'emergency-updater', 'resources_cache.json') emergency_updater_emergency_config_cache_path = os.path.join(get_product_data_path(), 'Agent', 'var', 'emergency-updater', 'emergencyUpdaterResourcesCache.json') elif system == OS_LINUX: emergency_updater_aakore_cache_path = '/opt/acronis/var/emergency-updater/resources_cache.json' emergency_updater_emergency_config_cache_path = '/opt/acronis/var/emergency-updater/emergencyUpdaterResourcesCache.json' elif system == OS_MAC: emergency_updater_aakore_cache_path = '/Library/Application Support/Acronis/Agent/var/emergency-updater/resources_cache.json' emergency_updater_emergency_config_cache_path = '/Library/Application Support/Acronis/Agent/var/emergency-updater/emergencyUpdaterResourcesCache.json' else: acrort.common.make_logic_error('Unsupported operating system: ' + system).throw() remove_files(emergency_updater_aakore_cache_path) remove_files(emergency_updater_emergency_config_cache_path) def drop_databases(): path = get_product_data_path() archives_db_path = os.path.join(path, 'BackupAndRecovery', 'archives_cache.*') print('Deleting DB at: {} ...'.format(archives_db_path)) remove_files(archives_db_path) dml_db_path = os.path.join(path, 'BackupAndRecovery', 'MMSData', 'DML', 'F4CEEE47-042C-4828-95A0-DE44EC267A28.*') print('Deleting DB at: {} ...'.format(dml_db_path)) remove_files(dml_db_path) if platform.system() == OS_MAC: old_dml_db_path = os.path.join(get_product_installation_path(), 'var_lib', 'Acronis', 'BackupAndRecovery', 'MMSData', 'DML', 'F4CEEE47-042C-4828-95A0-DE44EC267A28.*') print('Deleting DB at: {} ...'.format(old_dml_db_path)) remove_files(old_dml_db_path) def drop_online_backup_certificates(): path = get_product_data_path() ob_cert_path = os.path.join(path, 'BackupAndRecovery', 'OnlineBackup', 'Default', '*') print('Deleting certificates at: {} ...'.format(ob_cert_path)) remove_files(ob_cert_path) def drop_cached_machine_names(): registry_delete_key(get_settings_key(), 'CachedHostName') registry_delete_key(get_settings_key(), 'CachedMachineName') def drop_scheduled_tasks(): args = [get_scheduler_path(), 'task', 'zap'] print('Execute command: {}'.format(' '.join(args))) subprocess.run(args, stdout=subprocess.DEVNULL, check=True) def main(): parser = argparse.ArgumentParser(description='Change parameters for Acronis Managed Machine Service (MMS)') parser.add_argument( '-m', '--machine-id', required=True, nargs=1, help='Machine identifier, in form <GUID> or <new> to set auto-generated new identifier') parser.add_argument( '-i', '--instance-id', required=False, nargs=1, help='Instance identifier, in form <GUID> or <new> to set auto-generated new identifier') args = parser.parse_args() machine_id = args.machine_id[0] if machine_id == 'new' or machine_id == '<new>': machine_id = str(uuid.uuid4()) if not is_guid(machine_id): print("Machine ID: invalid GUID format: {}".format(machine_id)) return machine_id = machine_id.upper() current_machine_id = get_current_machine_id() change_instance_id = args.instance_id != None if change_instance_id: instance_id = args.instance_id[0] if instance_id == 'new' or instance_id == '<new>': instance_id = str(uuid.uuid4()) if not is_guid(instance_id): print("Instance ID: invalid GUID format: {}".format(instance_id)) return instance_id = instance_id.upper() current_instance_id = get_current_instance_id() if machine_id == instance_id: print('Machine ID and Instance ID are identical. They should be different!') return emergency_updater_running = False if is_emergency_updater_service_running(): emergency_updater_running = True print("Stopping EmergencyUpdater service...") stop_emergency_updater_service() print("Done.\n") if is_mms_service_running(): print("Stopping MMS service...") stop_mms_service() print("Done.\n") if is_aakore_service_running(): print("Stopping Aakore service...") stop_aakore_service() print("Done.\n") print("Clean databases...") drop_databases() print("Done.\n") print("Removing scheduled tasks...") drop_scheduled_tasks() print("Done.\n") print("Removing certificates for online backup...") drop_online_backup_certificates() print("Done.\n") print("Removing cached machine names...") drop_cached_machine_names() print("Done.\n") print("Clean acp agent caches...") drop_acp_agent_caches() print("Done.\n") print("Clean acp updater caches...") drop_acp_updater_caches() print("Done.\n") print("Clean acp sh-inventory caches...") drop_acp_sh_inventory_caches() print("Done.\n") if emergency_updater_running: print("Clean EmergencyUpdater service caches...") drop_emergency_updater_service_caches() print("Done.\n") set_current_machine_id(machine_id) print("Machine ID has changed from '{}' to '{}'".format(current_machine_id, machine_id)) if change_instance_id: set_current_instance_id(instance_id) print("Instance ID has changed from '{}' to '{}'".format(current_instance_id, instance_id)) print("\nStarting Aakore service...") start_aakore_service() print("Done.\n") print("Starting MMS service...") start_mms_service() print("Done.\n") if emergency_updater_running: print("Starting EmergencyUpdater service...") start_emergency_updater_service() print("Done.\n") print("Successfully finished.") if __name__ == '__main__': main()