示例#1
0
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)
示例#2
0
    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')
示例#3
0
 def get_system_id(self):
     return metadata.user_data()['serverid']
示例#4
0
    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()
示例#5
0
 def get_user_data(self, key=None):
     if key:
         return metadata.user_data().get(key)
     else:
         return metadata.user_data()