def _apply_user_data(from_scalr=True): logger = logging.getLogger(__name__) logger.debug('Applying user-data to configuration') if from_scalr: queryenv = bus.queryenv_service user_data = queryenv.get_server_user_data() logger.debug('User-data (QueryEnv):\n%s', pprint.pformat(user_data)) else: user_data = metadata.user_data() logger.debug('User-data (Instance):\n%s', pprint.pformat(user_data)) def g(key): return user_data.get(key, '') updates = dict(general={ 'platform': g('platform') or 'ec2', 'server_id': g(UserDataOptions.SERVER_ID), 'server_index': g('server_index'), 'role_name': g(UserDataOptions.ROLE_NAME), 'queryenv_url': g(UserDataOptions.QUERYENV_URL), 'cloud_storage_path': g(UserDataOptions.CLOUD_STORAGE_PATH), 'farm_role_id': g(UserDataOptions.FARMROLE_ID), 'env_id': g(UserDataOptions.ENV_ID), 'farm_id': g(UserDataOptions.FARM_ID), 'role_id': g(UserDataOptions.ROLE_ID), 'region': g(UserDataOptions.REGION), 'owner_email': g(UserDataOptions.OWNER_EMAIL) }, messaging_p2p={ 'producer_url': g(UserDataOptions.MESSAGE_SERVER_URL), 'message_format': g(UserDataOptions.MESSAGE_FORMAT) or 'xml' }) behaviour = g(UserDataOptions.BEHAVIOUR) if behaviour: if behaviour == 'base': behaviour = '' updates['general']['behaviour'] = behaviour cnf = bus.cnf if not cnf.rawini.has_option('general', 'scalr_id') and \ bus.scalr_version >= (3, 5, 7): queryenv = bus.queryenv_service global_config = queryenv.get_global_config()['params'] updates['general']['scalr_id'] = global_config['scalr.id'] cnf.update_ini('config.ini', updates) cnf.write_key(cnf.DEFAULT_KEY, g(UserDataOptions.CRYPTO_KEY)) logger.debug('Reloading configuration after user-data applying') cnf.bootstrap(force_reload=True)
def start(self): self._logger.debug("Initialize scalarizr...") _init() _init_environ() # Starting scalarizr daemon initialization globals()['_pid'] = pid = os.getpid() self._logger.info('[pid: %d] Starting scalarizr %s', pid, __version__) __node__['start_time'] = time.time() if not 'Windows' == linux.os['family']: # Check for another running scalarzir if os.path.exists(PID_FILE): try: another_pid = None with open(PID_FILE, 'r') as fp: another_pid = int(fp.read().strip()) except ValueError: pass else: if pid != another_pid and os.path.exists( '/proc/%s/status' % (another_pid, )): self._logger.error( 'Cannot start scalarizr: Another process (pid: %s) already running', another_pid) sys.exit(1) # Write PID with open(PID_FILE, 'w') as fp: fp.write(str(pid)) cnf = bus.cnf optparser = bus.optparser if optparser and optparser.values.configure: do_configure() sys.exit() elif optparser: if optparser.values.import_server: print "Starting import process..." print "Don't terminate Scalarizr until Scalr will create the new role" __node__['state'] = 'importing' # Load Command-line configuration options and auto-configure Scalarizr values = CmdLineIni.to_kvals(optparser.values.cnf) if not values.get('server_id'): values['server_id'] = str(uuid.uuid4()) self._logger.info( 'Configuring Scalarizr. This can take a few minutes...') cnf.reconfigure(values=values, silent=True, yesall=True) elif __node__['state'] == 'importing': # Reset state __node__['state'] = 'unknown' if __node__['state'] != 'importing': self._talk_to_updclient() # UpdateClient should fetch meta-data for us. metadata.wait(timeout=60) if linux.os.windows: try: wintool.wait_boot() except wintool.RebootExpected: self._logger.info('Waiting for interruption...') time.sleep(600) try: server_id = __node__['server_id'] except KeyError: server_id = None if optparser and not optparser.values.import_server \ and server_id != metadata.user_data()['serverid']: # This role was bundled with Cloud API call (i.e. CreateImage) # Now we're starting with a new server and should reset it's state self._logger.info(('This image was bundled with cloud API call. ' 'Cleauping ancestor server data')) _cleanup_after_rebundle() __node__['state'] = 'bootstrapping' if __node__['state'] == 'unknown': __node__['state'] = 'bootstrapping' if __node__['state'] == 'rebundling': __node__['state'] == 'running' if __node__['state'] == 'bootstrapping': _apply_user_data(from_scalr=False) # Load INI files configuration cnf.bootstrap(force_reload=True) ini = cnf.rawini # Initialize platform module _init_platform() pl = bus.platform # Initialize local database _init_db() STATE['global.start_after_update'] = int( bool(STATE['global.version'] and STATE['global.version'] != __version__)) STATE['global.version'] = __version__ if __node__['state'] == 'importing' and not linux.os.windows: try: pkgmgr.updatedb() except: self._logger.warn( 'Failed to update package manager database: %s', sys.exc_info()[1], exc_info=sys.exc_info()) # Check Scalr version if not bus.scalr_version: version_file = cnf.private_path('.scalr-version') if os.path.exists(version_file): bus.scalr_version = None with open(version_file, 'r') as fp: bus.scalr_version = tuple(fp.read().strip().split('.')) else: bus.scalr_version = _detect_scalr_version() with open(version_file, 'w') as fp: fp.write('.'.join(map(str, bus.scalr_version))) # Apply Command-line passed configuration options if optparser: cnf.update(CmdLineIni.to_ini_sections(optparser.values.cnf)) # Validate configuration num_errors = do_validate_cnf() if num_errors or (optparser and optparser.values.validate_cnf): sys.exit(int(not num_errors or 1)) # Initialize scalarizr services self._init_services() if STATE['global.start_after_update'] and __node__[ 'state'] == 'running': self._logger.info('Scalarizr was updated to %s', __version__) __node__['messaging'].send( 'HostUpdate', body={'scalarizr': { 'version': __version__ }}) if __node__['state'] == 'running': # ReSync user-data _apply_user_data(from_scalr=True) try: bus.fire('init') except: self._logger.warn('Caught exception in "init": %s', sys.exc_info()[1], exc_info=sys.exc_info()) # Install signal handlers if not linux.os.windows: signal.signal(signal.SIGTERM, self.onSIGTERM) self._start_services() # Fire start self.running = True try: bus.fire("start") except (BaseException, Exception) as e: if isinstance(e, SystemExit): raise self._logger.warn('Caught exception in "start": %s', e, exc_info=sys.exc_info()) try: while self.running: if linux.os.windows_family: rc = win32event.WaitForSingleObject(self.hWaitStop, 30000) if rc == win32event.WAIT_OBJECT_0: # Service stopped, stop main loop break else: try: select.select([], [], [], 30) except select.error, e: if e.args[0] == 4: # Interrupted syscall continue raise except KeyboardInterrupt: self._logger.debug('Mainloop: KeyboardInterrupt') finally: self._logger.debug('Mainloop: finally') if self.running and os.getpid() == _pid: self._shutdown() self._logger.debug('Mainloop: leave')
def get_system_id(self): return metadata.user_data()['serverid']
def bootstrap(self, dry_run=False): # [SCALARIZR-1797] # Cleanup RPMDb from old entries if linux.os.redhat_family and not dry_run: out = linux.system(('rpm', '-qa', 'scalarizr*', '--queryformat', '%{NAME}|%{VERSION}\n'))[0] for line in out.strip().split('\n'): name, version = line.strip().split('|') if not version == __version__: linux.system(('rpm', '-e', '--nodeps', '--justdb', '{0}-{1}'.format(name, version))) try: LOG.info('Getting System ID') self.system_id = self.get_system_id() LOG.info('System ID: {}'.format(self.system_id)) except: # This will force updclient to perform check updates each startup, # this is the optimal behavior cause that's ensure latest available package LOG.debug('Unable to get System ID: %s', sys.exc_info()[1]) self.system_id = str(uuid.uuid4()) LOG.debug('System ID (random generated): {}'.format( self.system_id)) system_matches = False status_data = None if os.path.exists(self.status_file): LOG.debug('Checking %s', self.status_file) with open(self.status_file) as fp: status_data = json.load(fp) if 'downgrades_enabled' not in status_data: # Field introduced in 2.7.12 # Missing field here means downgrades_enabled=False, # cause it's setted by postinst migration to new update system status_data['downgrades_enabled'] = False system_matches = status_data['system_id'] == self.system_id if not system_matches: if not status_data.get('system_id_is_server_id') \ and status_data['system_id'] == self.obsolete_get_system_id(): LOG.info( 'System-ID (obsolete) in status file matches current one' ) status_data['system_id'] = self.system_id status_data['system_id_is_server_id'] = True system_matches = True else: LOG.info('System ID changed: %s => %s', status_data['system_id'], self.system_id) else: LOG.debug('System-ID in status file matches current one') else: LOG.debug('Status file %s not exists', self.status_file) if system_matches: LOG.info('Reading state from %s', self.status_file) self._update_self_dict(status_data) if not system_matches: LOG.info('Initializing UpdateClient...') user_data = copy.deepcopy(metadata.user_data()) norm_user_data(user_data) LOG.info('Applying configuration from user-data') self._update_self_dict(user_data) crypto_dir = os.path.dirname(self.crypto_file) if not os.path.exists(crypto_dir): os.makedirs(crypto_dir) if os.path.exists(self.crypto_file): LOG.info('Testing that crypto key works (file: %s)', self.crypto_file) try: self._init_db() self._init_queryenv() LOG.info('Crypto key works') except queryenv.InvalidSignatureError: LOG.info( "Crypto key doesn't work: got invalid signature error") self.queryenv = None if not self.queryenv: LOG.info("Use crypto key from user-data") if os.path.exists(self.crypto_file): os.chmod(self.crypto_file, 0600) with open(self.crypto_file, 'w+') as fp: fp.write(user_data['szr_key']) os.chmod(self.crypto_file, 0400) self.early_bootstrapped = True try: self._init_services() except sqlite.OperationalError as e: # [SCALARIZR-2168] Scalarizr as part of post rebundle cleanup removed db.sqlite LOG.debug('Database error: {}'.format(e)) wait_until(lambda: os.path.exists(self.db_file) and os.stat( self.db_file).st_size, timeout=10, sleep=0.1) self._init_db() self._init_services() # - my uptime is 644 days, 20 hours and 13 mins and i know nothing about 'platform' in user-data if not self.platform: self.platform = bus.cnf.rawini.get('general', 'platform') # - my uptime is 1086 days, 55 mins and i know nothing about 'farm_roleid' in user-data if not self.farm_role_id: self.farm_role_id = bus.cnf.rawini.get('general', 'farm_role_id') self.system_matches = system_matches if not self.system_matches: if dry_run: self._sync() else: self.update(bootstrap=True) else: # if self.state in ('completed/wait-ack', 'noop'): if self.state not in ('error', 'rollbacked'): # forcefully finish any in-progress operations self.state = 'completed' self.store() # Set correct repo value at start. Need this to recover in case they # were not set during _sync() in the previous run [SCALARIZR-1885] self._ensure_repos() if not (self.shutdown_ev.is_set() or dry_run or (self.state == 'error' and not system_matches) or self.daemon.running): # we shouldn't start Scalarizr # - when UpdateClient is terminating # - when UpdateClient is not performing any updates # - when state is 'error' and it's a first UpdateClient start on a new system # - when Scalarizr is already running self.daemon.start() if self.state == 'completed/wait-ack': obsoletes = pkg_resources.Requirement.parse('A<=2.7.5') inst = re.sub(r'^\d\:', '', self.installed) # remove debian epoch if inst in obsoletes: LOG.info('UpdateClient is going to restart itself, cause ') def restart_self(): time.sleep(5) name = 'ScalrUpdClient' if linux.os.windows else 'scalr-upd-client' service = initdv2.Daemon(name) service.restart() proc = multiprocessing.Process(target=restart_self) proc.start()
def get_user_data(self, key=None): if key: return metadata.user_data().get(key) else: return metadata.user_data()