func (s *FlowGremlinTraversalStep) addTimeFilter(fsq *flow.FlowSearchQuery, timeContext *time.Time) { var timeFilter *flow.Filter if s.hasSinceParam() { tr := flow.Range{ From: timeContext.Unix() - s.context.Params[0].(traversal.Since).Seconds, To: timeContext.Unix(), } // flow need to have at least one metric included in the time range timeFilter = flow.NewFilterActiveIn(tr, "Metric.") } else { // flow having at least one metric at that time meaning being active timeFilter = flow.NewFilterActiveAt(timeContext.Unix(), "Metric.") } fsq.Filter = flow.NewAndFilter(fsq.Filter, timeFilter) }
func (f *FlowTraversalStep) Metrics() *MetricsTraversalStep { if f.error != nil { return &MetricsTraversalStep{error: f.error} } var metrics map[string][]*flow.FlowMetric context := f.GraphTraversal.Graph.GetContext() if context.Time != nil { metrics = make(map[string][]*flow.FlowMetric) // two cases, either we have a flowset and we need to use it in order to filter // flows or we don't have flowset but we have the pre-built flowSearchQuery filter // if none of these cases it's an error. if f.flowset != nil { flowFilter := flow.NewFilterForFlowSet(f.flowset) f.flowSearchQuery.Filter = flow.NewAndFilter(f.flowSearchQuery.Filter, flowFilter) } else if f.flowSearchQuery.Filter == nil { return &MetricsTraversalStep{error: errors.New("Unable to filter flows")} } // contruct metrics filter according to the time context and the since // predicate given to Flows. fr := flow.Range{To: context.Time.Unix()} if f.since.Seconds > 0 { fr.From = context.Time.Unix() - f.since.Seconds } metricFilter := flow.NewFilterIncludedIn(fr, "") var err error if metrics, err = f.Storage.SearchMetrics(f.flowSearchQuery, metricFilter); err != nil { return &MetricsTraversalStep{error: err} } } else { metrics = make(map[string][]*flow.FlowMetric, len(f.flowset.Flows)) for _, flow := range f.flowset.Flows { if flow.LastUpdateMetric.Start != 0 || flow.LastUpdateMetric.Last != 0 { metrics[flow.UUID] = append(metrics[flow.UUID], flow.LastUpdateMetric) } else { metrics[flow.UUID] = append(metrics[flow.UUID], flow.Metric) } } } return &MetricsTraversalStep{GraphTraversal: f.GraphTraversal, metrics: metrics} }
func (s *FlowGremlinTraversalStep) Exec(last traversal.GraphTraversalStep) (traversal.GraphTraversalStep, error) { var graphTraversal *traversal.GraphTraversal var err error flowSearchQuery, err := s.makeFlowSearchQuery() if err != nil { return nil, err } var flowset *flow.FlowSet switch tv := last.(type) { case *traversal.GraphTraversal: graphTraversal = tv context := graphTraversal.Graph.GetContext() // if Since predicate present in a non time context query if s.hasSinceParam() && context.Time == nil { return nil, errors.New("Since predicate has to be used with Context step") } if context.Time != nil { if s.Storage == nil { return nil, storage.NoStorageConfigured } s.addTimeFilter(&flowSearchQuery, context.Time) // We do nothing as the following step is Metrics // and we'll make a request on metrics instead of flows if s.metricsNextStep { return &FlowTraversalStep{GraphTraversal: graphTraversal, Storage: s.Storage, flowSearchQuery: flowSearchQuery, since: s.sinceParam()}, nil } if flowset, err = s.Storage.SearchFlows(flowSearchQuery); err != nil { return nil, err } } else { flowset, err = s.TableClient.LookupFlows(flowSearchQuery) } case *traversal.GraphTraversalV: graphTraversal = tv.GraphTraversal context := graphTraversal.Graph.GetContext() // if Since predicate present in a non time context query if s.hasSinceParam() && context.Time == nil { return nil, errors.New("Since predicate has to be used with Context step") } // not need to get flows from node not supporting capture nodes := captureAllowedNodes(tv.GetNodes()) if len(nodes) != 0 { if context.Time != nil { if s.Storage == nil { return nil, storage.NoStorageConfigured } s.addTimeFilter(&flowSearchQuery, context.Time) // previously selected nodes then need to filter flow belonging to them nodeFilter := flow.NewFilterForNodes(nodes) flowSearchQuery.Filter = flow.NewAndFilter(flowSearchQuery.Filter, nodeFilter) // We do nothing as the following step is Metrics // and we'll make a request on metrics instead of flows if s.metricsNextStep { return &FlowTraversalStep{GraphTraversal: graphTraversal, Storage: s.Storage, flowSearchQuery: flowSearchQuery, since: s.sinceParam()}, nil } if flowset, err = s.Storage.SearchFlows(flowSearchQuery); err != nil { return nil, err } } else { hnmap := topology.BuildHostNodeTIDMap(nodes) flowset, err = s.TableClient.LookupFlowsByNodes(hnmap, flowSearchQuery) } } default: return nil, traversal.ExecutionError } if err != nil { logging.GetLogger().Errorf("Error while looking for flows: %s", err.Error()) return nil, err } if r := s.context.StepContext.PaginationRange; r != nil { flowset.Slice(int(r[0]), int(r[1])) } return &FlowTraversalStep{GraphTraversal: graphTraversal, Storage: s.Storage, flowset: flowset, flowSearchQuery: flowSearchQuery, since: s.sinceParam()}, nil }