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

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/lager/lagerctx"
     9  	sq "github.com/Masterminds/squirrel"
    10  	"github.com/pf-qiu/concourse/v6/atc"
    11  	"github.com/pf-qiu/concourse/v6/atc/creds"
    12  	"github.com/pf-qiu/concourse/v6/atc/db/lock"
    13  )
    14  
    15  //go:generate counterfeiter . Checkable
    16  
    17  type Checkable interface {
    18  	PipelineRef
    19  
    20  	Name() string
    21  	TeamID() int
    22  	ResourceConfigScopeID() int
    23  	TeamName() string
    24  	Type() string
    25  	Source() atc.Source
    26  	Tags() atc.Tags
    27  	CheckEvery() string
    28  	CheckTimeout() string
    29  	LastCheckEndTime() time.Time
    30  	CurrentPinnedVersion() atc.Version
    31  
    32  	HasWebhook() bool
    33  
    34  	CheckPlan(atc.Version, time.Duration, ResourceTypes, atc.Source) atc.CheckPlan
    35  	CreateBuild(context.Context, bool, atc.Plan) (Build, bool, error)
    36  }
    37  
    38  //go:generate counterfeiter . CheckFactory
    39  
    40  type CheckFactory interface {
    41  	TryCreateCheck(context.Context, Checkable, ResourceTypes, atc.Version, bool) (Build, bool, error)
    42  	Resources() ([]Resource, error)
    43  	ResourceTypes() ([]ResourceType, error)
    44  }
    45  
    46  type checkFactory struct {
    47  	conn        Conn
    48  	lockFactory lock.LockFactory
    49  
    50  	secrets       creds.Secrets
    51  	varSourcePool creds.VarSourcePool
    52  
    53  	planFactory atc.PlanFactory
    54  
    55  	defaultCheckTimeout             time.Duration
    56  	defaultCheckInterval            time.Duration
    57  	defaultWithWebhookCheckInterval time.Duration
    58  }
    59  
    60  type CheckDurations struct {
    61  	Timeout             time.Duration
    62  	Interval            time.Duration
    63  	IntervalWithWebhook time.Duration
    64  }
    65  
    66  func NewCheckFactory(
    67  	conn Conn,
    68  	lockFactory lock.LockFactory,
    69  	secrets creds.Secrets,
    70  	varSourcePool creds.VarSourcePool,
    71  	durations CheckDurations,
    72  ) CheckFactory {
    73  	return &checkFactory{
    74  		conn:        conn,
    75  		lockFactory: lockFactory,
    76  
    77  		secrets:       secrets,
    78  		varSourcePool: varSourcePool,
    79  
    80  		planFactory: atc.NewPlanFactory(time.Now().Unix()),
    81  
    82  		defaultCheckTimeout:             durations.Timeout,
    83  		defaultCheckInterval:            durations.Interval,
    84  		defaultWithWebhookCheckInterval: durations.IntervalWithWebhook,
    85  	}
    86  }
    87  
    88  func (c *checkFactory) TryCreateCheck(ctx context.Context, checkable Checkable, resourceTypes ResourceTypes, from atc.Version, manuallyTriggered bool) (Build, bool, error) {
    89  	logger := lagerctx.FromContext(ctx)
    90  
    91  	var err error
    92  
    93  	sourceDefaults := atc.Source{}
    94  	parentType, found := resourceTypes.Parent(checkable)
    95  	if found {
    96  		if parentType.Version() == nil {
    97  			return nil, false, fmt.Errorf("resource type '%s' has no version", parentType.Name())
    98  		}
    99  		sourceDefaults = parentType.Defaults()
   100  	} else {
   101  		defaults, found := atc.FindBaseResourceTypeDefaults(checkable.Type())
   102  		if found {
   103  			sourceDefaults = defaults
   104  		}
   105  	}
   106  
   107  	interval := c.defaultCheckInterval
   108  	if checkable.HasWebhook() {
   109  		interval = c.defaultWithWebhookCheckInterval
   110  	}
   111  	if every := checkable.CheckEvery(); every != "" {
   112  		interval, err = time.ParseDuration(every)
   113  		if err != nil {
   114  			return nil, false, fmt.Errorf("check interval: %s", err)
   115  		}
   116  	}
   117  
   118  	if !manuallyTriggered && time.Now().Before(checkable.LastCheckEndTime().Add(interval)) {
   119  		// skip creating the check if its interval hasn't elapsed yet
   120  		return nil, false, nil
   121  	}
   122  
   123  	checkPlan := checkable.CheckPlan(from, interval, resourceTypes.Filter(checkable), sourceDefaults)
   124  
   125  	plan := c.planFactory.NewPlan(checkPlan)
   126  
   127  	build, created, err := checkable.CreateBuild(ctx, manuallyTriggered, plan)
   128  	if err != nil {
   129  		return nil, false, fmt.Errorf("create build: %w", err)
   130  	}
   131  
   132  	if !created {
   133  		return nil, false, nil
   134  	}
   135  
   136  	logger.Info("created-build", build.LagerData())
   137  
   138  	return build, true, nil
   139  }
   140  
   141  func (c *checkFactory) Resources() ([]Resource, error) {
   142  	var resources []Resource
   143  
   144  	rows, err := resourcesQuery.
   145  		Join("(select DISTINCT(resource_id) FROM job_inputs) ji ON ji.resource_id = r.id").
   146  		Where(sq.Eq{"p.paused": false}).
   147  		RunWith(c.conn).
   148  		Query()
   149  
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	defer Close(rows)
   155  
   156  	for rows.Next() {
   157  		r := newEmptyResource(c.conn, c.lockFactory)
   158  		err = scanResource(r, rows)
   159  		if err != nil {
   160  			return nil, err
   161  		}
   162  
   163  		resources = append(resources, r)
   164  	}
   165  
   166  	return resources, nil
   167  }
   168  
   169  func (c *checkFactory) ResourceTypes() ([]ResourceType, error) {
   170  	var resourceTypes []ResourceType
   171  
   172  	rows, err := resourceTypesQuery.
   173  		RunWith(c.conn).
   174  		Query()
   175  
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	defer Close(rows)
   181  
   182  	for rows.Next() {
   183  		r := newEmptyResourceType(c.conn, c.lockFactory)
   184  		err = scanResourceType(r, rows)
   185  		if err != nil {
   186  			return nil, err
   187  		}
   188  
   189  		resourceTypes = append(resourceTypes, r)
   190  	}
   191  
   192  	return resourceTypes, nil
   193  }