예제 #1
0
    def __init__(self, hosts, package_handler=None, infraclient=None, dbusemitter=None):
        GObject.GObject.__init__(self)

        self._netstate = NetworkStatusWatcher()
        self._sso_login = LoginBackendDbusSSO()
        self._can_sync = False
        self.credential = None
        self.hosts = hosts
        self.infraclient = infraclient
        self.package_handler = package_handler
        
        if dbusemitter:
            self.emit_new_hostlist = dbusemitter.hostlist_changed
            self.emit_new_packagelist = dbusemitter.packagelist_changed
            self.emit_new_logo = dbusemitter.logo_changed
            self.emit_new_latestsync = dbusemitter.latestsync_changed

        self._netstate.connect("changed", self._network_state_changed)
        self._sso_login.connect("login-result", self._sso_login_result)
예제 #2
0
class SyncHandler(GObject.GObject):
    '''Handle sync request with the server from the dbus service'''

    def __init__(self, hosts, package_handler=None, infraclient=None, dbusemitter=None):
        GObject.GObject.__init__(self)

        self._netstate = NetworkStatusWatcher()
        self._sso_login = LoginBackendDbusSSO()
        self._can_sync = False
        self.credential = None
        self.hosts = hosts
        self.infraclient = infraclient
        self.package_handler = package_handler
        
        if dbusemitter:
            self.emit_new_hostlist = dbusemitter.hostlist_changed
            self.emit_new_packagelist = dbusemitter.packagelist_changed
            self.emit_new_logo = dbusemitter.logo_changed
            self.emit_new_latestsync = dbusemitter.latestsync_changed

        self._netstate.connect("changed", self._network_state_changed)
        self._sso_login.connect("login-result", self._sso_login_result)
        

    def _refresh_can_sync(self):
        '''compute current syncable state before asking for refresh the value'''
        new_can_sync = (self.credential is not None) and self._netstate.connected
        if self._can_sync == new_can_sync:
            return
        self._can_sync = new_can_sync

        # we can now start syncing (as it's a new status), adding the timeout
        if self._can_sync:
            self.process_sync()
            # adding the timeout only if we are not on a single sync
            if not "ONECONF_SINGLE_SYNC" in os.environ or not os.environ["ONECONF_SINGLE_SYNC"]:
                GObject.timeout_add_seconds(MIN_TIME_WITHOUT_ACTIVITY, self.process_sync)

    def _sso_login_result(self, sso_login, credential):
        if credential == self.credential:
            return

        self.credential = credential
        # Prepare the authenticated infraclient
        if self.credential and not self.infraclient:
            from piston_mini_client.auth import OAuthAuthorizer
            from infraclient_pristine import WebCatalogAPI
            from oneconf.distributor import get_distro
            service_root = get_distro().ONECONF_SERVER
            authorizer = OAuthAuthorizer(token_key=credential['token'],
                token_secret=credential['token_secret'],
                consumer_key=credential['consumer_key'],
                consumer_secret=credential['consumer_secret'],
                oauth_realm='Ubuntu Software Center')
            self.infraclient = WebCatalogAPI(service_root=service_root,
                                             auth=authorizer)
        self._refresh_can_sync()

    def _network_state_changed(self, netstate, connected):
        self._refresh_can_sync()

    def check_if_refresh_needed(self, old_data, new_data, hostid, key):
        '''Return if data dictionnary needs to be refreshed'''
        need_refresh = False
        LOG.debug("Check if %s needs to be refreshed for %s" % (key, hostid))
        try:
            if old_data[hostid]['%s_checksum' % key] != new_data[hostid]['%s_checksum' % key]:
                need_refresh = True
        except KeyError:
            # there was no old_data, if the new ones are not none, refresh
            if new_data[hostid]['%s_checksum' % key]:
                need_refresh = True
        if need_refresh:
            LOG.debug("Refresh new %s" % key)
        return need_refresh

    def check_if_push_needed(self, local_data, distant_data, key):
        '''Return if data dictionnary needs to be refreshed

            Contrary to refresh needed, we are sure that the host is registered.
            However the local checksum can be null, telling that no refresh is needed'''
        LOG.debug("Check if %s for current host need to be pushed to infra" % key)
        try:
            need_push = (local_data['%s_checksum' % key] and (local_data['%s_checksum' % key] != distant_data['%s_checksum' % key]))
        except KeyError:
            need_push = True
        if need_push:
            LOG.debug("Push new %s" % key)
        return need_push

    def emit_new_hostlist(self):
        '''this signal will be bound at init time'''
        LOG.warning("emit_new_hostlist not bound to anything")
        
    def emit_new_packagelist(self, hostid):
        '''this signal will be bound at init time'''
        LOG.warning("emit_new_packagelist(%s) not bound to anything" % hostid)

    def emit_new_logo(self, hostid):
        '''this signal will be bound at init time'''
        LOG.warning("emit_new_logo(%s) not bound to anything" % hostid)
        
    def emit_new_latestsync(self, timestamp):
        '''this signal will be bound at init time'''
        LOG.warning("emit_new_lastestsync(%s) not bound to anything" % timestamp)

    def process_sync(self):
        '''start syncing what's needed if can sync
        
        process sync can be either started directly, or when can_sync changed'''
        
        # we can't no more sync, removing the timeout
        if not self._can_sync:
            return False
        LOG.debug("Start processing sync")

        # Check server connection
        try:
            if self.infraclient.server_status() != 'ok':
                LOG.error("WebClient server answering but not available")
                return True
        except (APIError, socket.error, ValueError, ServerNotFoundError, BadStatusLine, RedirectLimit), e:
            LOG.error ("WebClient server answer error: %s", e)
            return True

        # Try to do every other hosts pending changes first (we will get fresh
        # data then)
        try:
            pending_upload_filename = os.path.join(self.hosts.get_currenthost_dir(), PENDING_UPLOAD_FILENAME)
            with open(pending_upload_filename, 'r') as f:
                pending_changes = json.load(f)
            for hostid in pending_changes.keys():
                # now do action depending on what needs to be refreshed
                try:
                    # we can only remove distant machines for now, not register new ones
                    try:
                        if not pending_changes[hostid].pop('share_inventory'):
                            LOG.debug("Removing machine %s requested as a pending change" % hostid)
                            self.infraclient.delete_machine(machine_uuid=hostid)
                    except APIError, e:
                        LOG.error("WebClient server doesn't want to remove hostid (%s): %s" % (hostid, e))
                        pending_changes[hostid]['share_inventory'] = False # append it again to be done
                except KeyError:
                    pass
                # after all changes, is hostid still relevant?
                if not pending_changes[hostid]:
                    pending_changes.pop(hostid)
            # no more change, remove the file
            if not pending_changes:
                LOG.debug("No more pending changes remaining, removing the file")
                os.remove(pending_upload_filename)
            # update the remaining tasks
            else:
                utils.save_json_file_update(pending_upload_filename, pending_changes)
        except IOError:
            pass
        except ValueError:
            LOG.warning("The pending file is broken, ignoring")

        current_hostid = self.hosts.current_host['hostid']
        old_hosts = self.hosts.other_hosts
        hostlist_changed = None
        packagelist_changed = []
        logo_changed = []

        # Get all machines
        try:
            full_hosts_list = self.infraclient.list_machines()
        except APIError, e:
            LOG.error ("Invalid machine list from server, stopping sync: %s" % e)
            return True