예제 #1
0
    def run(self):
        if not self.driver.enabled:
            return

        while True:
            logger.debug('Waiting for event')
            self.wait_for_event(timeout=5)
            logger.debug('Observer woke up')

            self.run_once()
예제 #2
0
    def run_once(self):
        try:
            model_accessor.check_db_connection_okay()

            loop_start = time.time()
            error_map_file = Config.get('error_map_path')
            self.error_mapper = ErrorMapper(error_map_file)

            # Two passes. One for sync, the other for deletion.
            for deletion in [False, True]:
                # Set of individual objects within steps that failed
                self.failed_step_objects = set()

                # Set up conditions and step status
                # This is needed for steps to run in parallel
                # while obeying dependencies.

                providers = set()
                dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph

                for v in dependency_graph.values():
                    if (v):
                        providers.update(v)

                self.step_conditions = {}
                self.step_status = {}

                for p in list(providers):
                    self.step_conditions[p] = threading.Condition()

                    self.step_status[p] = STEP_STATUS_WORKING

                self.failed_steps = []

                threads = []
                logger.debug('Deletion=%r...' % deletion)
                schedule = self.ordered_steps if not deletion else reversed(
                    self.ordered_steps)

                for S in schedule:
                    thread = threading.Thread(target=self.sync,
                                              name='synchronizer',
                                              args=(S, deletion))

                    logger.debug('Deletion=%r...' % deletion)
                    threads.append(thread)

                # Start threads
                for t in threads:
                    t.start()

                # another spot to clean up debug state
                try:
                    model_accessor.reset_queries()
                except:
                    # this shouldn't happen, but in case it does, catch it...
                    logger.log_exc("exception in reset_queries")

                # Wait for all threads to finish before continuing with the run
                # loop
                for t in threads:
                    t.join()

            self.save_run_times()

            loop_end = time.time()

            model_accessor.update_diag(loop_end=loop_end,
                                       loop_start=loop_start,
                                       backend_status="1 - Bottom Of Loop")

        except Exception as e:
            logger.error(
                'Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!'
                % e)
            logger.log_exc("Exception in observer run loop")
            traceback.print_exc()
            model_accessor.update_diag(
                backend_status="2 - Exception in Event Loop")
예제 #3
0
    def load_sync_steps(self):
        dep_path = Config.get("dependency_graph")
        logger.info('Loading model dependency graph from %s' % dep_path)
        try:
            # This contains dependencies between records, not sync steps
            self.model_dependency_graph = json.loads(open(dep_path).read())
            for left, lst in self.model_dependency_graph.items():
                new_lst = []
                for k in lst:
                    try:
                        tup = (k, k.lower())
                        new_lst.append(tup)
                        deps = self.model_dependency_graph[k]
                    except:
                        self.model_dependency_graph[k] = []

                self.model_dependency_graph[left] = new_lst
        except Exception as e:
            raise e

        try:
            # FIXME `pl_dependency_graph` is never defined, this will always fail
            # NOTE can we remove it?
            backend_path = Config.get("pl_dependency_graph")
            logger.info('Loading backend dependency graph from %s' %
                        backend_path)
            # This contains dependencies between backend records
            self.backend_dependency_graph = json.loads(
                open(backend_path).read())
            for k, v in self.backend_dependency_graph.items():
                try:
                    self.model_dependency_graph[k].extend(v)
                except KeyError:
                    self.model_dependency_graphp[k] = v

        except Exception as e:
            logger.info('Backend dependency graph not loaded')
            # We can work without a backend graph
            self.backend_dependency_graph = {}

        provides_dict = {}
        for s in self.sync_steps:
            self.step_lookup[s.__name__] = s
            for m in s.provides:
                try:
                    provides_dict[m.__name__].append(s.__name__)
                except KeyError:
                    provides_dict[m.__name__] = [s.__name__]

        step_graph = {}
        phantom_steps = []
        for k, v in self.model_dependency_graph.items():
            try:
                for source in provides_dict[k]:
                    if (not v):
                        step_graph[source] = []

                    for m, _ in v:
                        try:
                            for dest in provides_dict[m]:
                                # no deps, pass
                                try:
                                    if (dest not in step_graph[source]):
                                        step_graph[source].append(dest)
                                except:
                                    step_graph[source] = [dest]
                        except KeyError:
                            if (m not in provides_dict):
                                try:
                                    step_graph[source] += ['#%s' % m]
                                except:
                                    step_graph[source] = ['#%s' % m]

                                phantom_steps += ['#%s' % m]
                            pass

            except KeyError:
                pass
                # no dependencies, pass

        self.dependency_graph = step_graph
        self.deletion_dependency_graph = invert_graph(step_graph)

        pp = pprint.PrettyPrinter(indent=4)
        logger.debug(pp.pformat(step_graph))
        self.ordered_steps = toposort(
            self.dependency_graph,
            phantom_steps + map(lambda s: s.__name__, self.sync_steps))
        self.ordered_steps = [
            i for i in self.ordered_steps if i != 'SyncObject'
        ]

        logger.info("Order of steps=%s" % self.ordered_steps)

        self.load_run_times()
예제 #4
0
    def sync(self, S, deletion):
        try:
            step = self.lookup_step_class(S)
            start_time = time.time()

            logger.debug("Starting to work on step %s, deletion=%s" %
                         (step.__name__, str(deletion)))

            dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph
            # if not deletion else self.deletion_step_conditions
            step_conditions = self.step_conditions
            step_status = self.step_status  # if not deletion else self.deletion_step_status

            # Wait for step dependencies to be met
            try:
                deps = dependency_graph[S]
                has_deps = True
            except KeyError:
                has_deps = False

            go = True

            failed_dep = None
            if (has_deps):
                for d in deps:
                    if d == step.__name__:
                        logger.debug("   step %s self-wait skipped" %
                                     step.__name__)
                        go = True
                        continue

                    cond = step_conditions[d]
                    cond.acquire()
                    if (step_status[d] is STEP_STATUS_WORKING):
                        logger.debug("  step %s wait on dep %s" %
                                     (step.__name__, d))
                        cond.wait()
                        logger.debug("  step %s wait on dep %s cond returned" %
                                     (step.__name__, d))
                    elif step_status[d] == STEP_STATUS_OK:
                        go = True
                    else:
                        logger.debug("  step %s has failed dep %s" %
                                     (step.__name__, d))
                        go = False
                        failed_dep = d
                    cond.release()
                    if (not go):
                        break
            else:
                go = True

            if (not go):
                logger.debug("Step %s skipped" % step.__name__)
                self.failed_steps.append(step)
                my_status = STEP_STATUS_KO
            else:
                sync_step = self.lookup_step(S)
                sync_step.__name__ = step.__name__
                sync_step.dependencies = []
                try:
                    mlist = sync_step.provides

                    try:
                        for m in mlist:
                            lst = self.model_dependency_graph[m.__name__]
                            nlst = map(lambda a_b: a_b[1], lst)
                            sync_step.dependencies.extend(nlst)
                    except Exception as e:
                        raise e

                except KeyError:
                    pass
                sync_step.debug_mode = debug_mode

                should_run = False
                try:
                    # Various checks that decide whether
                    # this step runs or not
                    self.check_class_dependency(
                        sync_step,
                        self.failed_steps)  # dont run Slices if Sites failed
                    # dont run sync_network_routes if time since last run < 1
                    # hour
                    self.check_schedule(sync_step, deletion)
                    should_run = True
                except StepNotReady:
                    logger.info('Step not ready: %s' % sync_step.__name__)
                    self.failed_steps.append(sync_step)
                    my_status = STEP_STATUS_KO
                except Exception as e:
                    logger.error('%r' % e)
                    logger.log_exc("sync step failed: %r. Deletion: %r" %
                                   (sync_step, deletion))
                    self.failed_steps.append(sync_step)
                    my_status = STEP_STATUS_KO

                if (should_run):
                    try:
                        duration = time.time() - start_time

                        logger.debug('Executing step %s, deletion=%s' %
                                     (sync_step.__name__, deletion))

                        failed_objects = sync_step(failed=list(
                            self.failed_step_objects),
                                                   deletion=deletion)

                        self.check_duration(sync_step, duration)

                        if failed_objects:
                            self.failed_step_objects.update(failed_objects)

                        logger.debug("Step %r succeeded, deletion=%s" %
                                     (sync_step.__name__, deletion))
                        my_status = STEP_STATUS_OK
                        self.update_run_time(sync_step, deletion)
                    except Exception as e:
                        logger.error(
                            'Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!'
                            % (sync_step.__name__, e))
                        logger.log_exc("Exception in sync step")
                        self.failed_steps.append(S)
                        my_status = STEP_STATUS_KO
                else:
                    logger.info("Step %r succeeded due to non-run" % step)
                    my_status = STEP_STATUS_OK

            try:
                my_cond = step_conditions[S]
                my_cond.acquire()
                step_status[S] = my_status
                my_cond.notify_all()
                my_cond.release()
            except KeyError as e:
                logger.debug('Step %r is a leaf' % step)
                pass
        finally:
            try:
                model_accessor.reset_queries()
            except:
                # this shouldn't happen, but in case it does, catch it...
                logger.log_exc("exception in reset_queries")

            model_accessor.connection_close()
예제 #5
0
def debug(msg):
    logger.debug(
        basename(str(inspect.stack()[1][1])) + ':' +
        str(inspect.stack()[1][2]) + ' ' + str(inspect.stack()[1][3]) +
        '()  ' + str(msg))