github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/lidar/scanner.go (about)

     1  package lidar
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"sync"
     7  
     8  	"code.cloudfoundry.org/lager/lagerctx"
     9  	"github.com/pf-qiu/concourse/v6/atc/db"
    10  	"github.com/pf-qiu/concourse/v6/atc/metric"
    11  	"github.com/pf-qiu/concourse/v6/atc/util"
    12  	"github.com/pf-qiu/concourse/v6/tracing"
    13  )
    14  
    15  func NewScanner(checkFactory db.CheckFactory) *scanner {
    16  	return &scanner{
    17  		checkFactory: checkFactory,
    18  	}
    19  }
    20  
    21  type scanner struct {
    22  	checkFactory db.CheckFactory
    23  }
    24  
    25  func (s *scanner) Run(ctx context.Context) error {
    26  	logger := lagerctx.FromContext(ctx)
    27  
    28  	spanCtx, span := tracing.StartSpan(ctx, "scanner.Run", nil)
    29  	defer span.End()
    30  
    31  	logger.Info("start")
    32  	defer logger.Info("end")
    33  
    34  	resources, err := s.checkFactory.Resources()
    35  	if err != nil {
    36  		logger.Error("failed-to-get-resources", err)
    37  		return err
    38  	}
    39  
    40  	resourceTypes, err := s.checkFactory.ResourceTypes()
    41  	if err != nil {
    42  		logger.Error("failed-to-get-resource-types", err)
    43  		return err
    44  	}
    45  
    46  	waitGroup := new(sync.WaitGroup)
    47  	resourceTypesChecked := &sync.Map{}
    48  
    49  	for _, resource := range resources {
    50  		waitGroup.Add(1)
    51  
    52  		go func(resource db.Resource, resourceTypes db.ResourceTypes) {
    53  			defer func() {
    54  				err := util.DumpPanic(recover(), "scanning resource %d", resource.ID())
    55  				if err != nil {
    56  					logger.Error("panic-in-scanner-run", err)
    57  				}
    58  			}()
    59  			defer waitGroup.Done()
    60  
    61  			s.check(spanCtx, resource, resourceTypes, resourceTypesChecked)
    62  		}(resource, resourceTypes)
    63  	}
    64  
    65  	waitGroup.Wait()
    66  
    67  	return nil
    68  }
    69  
    70  func (s *scanner) check(ctx context.Context, checkable db.Checkable, resourceTypes db.ResourceTypes, resourceTypesChecked *sync.Map) {
    71  	logger := lagerctx.FromContext(ctx)
    72  
    73  	spanCtx, span := tracing.StartSpan(ctx, "scanner.check", tracing.Attrs{
    74  		"team":                     checkable.TeamName(),
    75  		"pipeline":                 checkable.PipelineName(),
    76  		"resource":                 checkable.Name(),
    77  		"type":                     checkable.Type(),
    78  		"resource_config_scope_id": strconv.Itoa(checkable.ResourceConfigScopeID()),
    79  	})
    80  	defer span.End()
    81  
    82  	parentType, found := resourceTypes.Parent(checkable)
    83  	if found {
    84  		if _, exists := resourceTypesChecked.LoadOrStore(parentType.ID(), true); !exists {
    85  			// only create a check for resource type if it has not been checked yet
    86  			s.check(spanCtx, parentType, resourceTypes, resourceTypesChecked)
    87  		}
    88  	}
    89  
    90  	version := checkable.CurrentPinnedVersion()
    91  
    92  	_, created, err := s.checkFactory.TryCreateCheck(lagerctx.NewContext(spanCtx, logger), checkable, resourceTypes, version, false)
    93  	if err != nil {
    94  		logger.Error("failed-to-create-check", err)
    95  		return
    96  	}
    97  
    98  	if !created {
    99  		logger.Debug("check-already-exists")
   100  	} else {
   101  		metric.Metrics.ChecksEnqueued.Inc()
   102  	}
   103  }