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

     1  package db
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"code.cloudfoundry.org/lager"
    13  	sq "github.com/Masterminds/squirrel"
    14  	"github.com/pf-qiu/concourse/v6/atc/creds"
    15  	"github.com/pf-qiu/concourse/v6/vars"
    16  	"github.com/lib/pq"
    17  	"go.opentelemetry.io/otel/api/propagation"
    18  
    19  	"github.com/pf-qiu/concourse/v6/atc"
    20  	"github.com/pf-qiu/concourse/v6/atc/db/encryption"
    21  	"github.com/pf-qiu/concourse/v6/atc/db/lock"
    22  	"github.com/pf-qiu/concourse/v6/atc/event"
    23  	"github.com/pf-qiu/concourse/v6/tracing"
    24  )
    25  
    26  const schema = "exec.v2"
    27  
    28  var ErrAdoptRerunBuildHasNoInputs = errors.New("inputs not ready for build to rerun")
    29  var ErrSetByNewerBuild = errors.New("pipeline set by a newer build")
    30  
    31  type BuildInput struct {
    32  	Name       string
    33  	Version    atc.Version
    34  	ResourceID int
    35  
    36  	FirstOccurrence bool
    37  	ResolveError    string
    38  
    39  	Context SpanContext
    40  }
    41  
    42  func (bi BuildInput) SpanContext() propagation.HTTPSupplier {
    43  	return bi.Context
    44  }
    45  
    46  type BuildOutput struct {
    47  	Name    string
    48  	Version atc.Version
    49  }
    50  
    51  type BuildStatus string
    52  
    53  const (
    54  	BuildStatusPending   BuildStatus = "pending"
    55  	BuildStatusStarted   BuildStatus = "started"
    56  	BuildStatusAborted   BuildStatus = "aborted"
    57  	BuildStatusSucceeded BuildStatus = "succeeded"
    58  	BuildStatusFailed    BuildStatus = "failed"
    59  	BuildStatusErrored   BuildStatus = "errored"
    60  )
    61  
    62  func (status BuildStatus) String() string {
    63  	return string(status)
    64  }
    65  
    66  var buildsQuery = psql.Select(`
    67  		b.id,
    68  		b.name,
    69  		b.job_id,
    70  		b.resource_id,
    71  		b.resource_type_id,
    72  		b.team_id,
    73  		b.status,
    74  		b.manually_triggered,
    75  		b.scheduled,
    76  		b.schema,
    77  		b.private_plan,
    78  		b.public_plan,
    79  		b.create_time,
    80  		b.start_time,
    81  		b.end_time,
    82  		b.reap_time,
    83  		j.name,
    84  		r.name,
    85  		rt.name,
    86  		b.pipeline_id,
    87  		p.name,
    88  		p.instance_vars,
    89  		t.name,
    90  		b.nonce,
    91  		b.drained,
    92  		b.aborted,
    93  		b.completed,
    94  		b.inputs_ready,
    95  		b.rerun_of,
    96  		rb.name,
    97  		b.rerun_number,
    98  		b.span_context
    99  	`).
   100  	From("builds b").
   101  	JoinClause("LEFT OUTER JOIN jobs j ON b.job_id = j.id").
   102  	JoinClause("LEFT OUTER JOIN resources r ON b.resource_id = r.id").
   103  	JoinClause("LEFT OUTER JOIN resource_types rt ON b.resource_type_id = rt.id").
   104  	JoinClause("LEFT OUTER JOIN pipelines p ON b.pipeline_id = p.id").
   105  	JoinClause("LEFT OUTER JOIN teams t ON b.team_id = t.id").
   106  	JoinClause("LEFT OUTER JOIN builds rb ON rb.id = b.rerun_of")
   107  
   108  var minMaxIdQuery = psql.Select("COALESCE(MAX(b.id), 0)", "COALESCE(MIN(b.id), 0)").
   109  	From("builds as b")
   110  
   111  var latestCompletedBuildQuery = psql.Select("max(id)").
   112  	From("builds").
   113  	Where(sq.Expr(`status NOT IN ('pending', 'started')`))
   114  
   115  //go:generate counterfeiter . Build
   116  
   117  type Build interface {
   118  	PipelineRef
   119  
   120  	ID() int
   121  	Name() string
   122  
   123  	TeamID() int
   124  	TeamName() string
   125  
   126  	JobID() int
   127  	JobName() string
   128  
   129  	ResourceID() int
   130  	ResourceName() string
   131  
   132  	ResourceTypeID() int
   133  	ResourceTypeName() string
   134  
   135  	Schema() string
   136  	PrivatePlan() atc.Plan
   137  	PublicPlan() *json.RawMessage
   138  	HasPlan() bool
   139  	Status() BuildStatus
   140  	StartTime() time.Time
   141  	IsNewerThanLastCheckOf(input Resource) bool
   142  	EndTime() time.Time
   143  	ReapTime() time.Time
   144  	IsManuallyTriggered() bool
   145  	IsScheduled() bool
   146  	IsRunning() bool
   147  	IsCompleted() bool
   148  	InputsReady() bool
   149  	RerunOf() int
   150  	RerunOfName() string
   151  	RerunNumber() int
   152  
   153  	LagerData() lager.Data
   154  	TracingAttrs() tracing.Attrs
   155  
   156  	SyslogTag(event.OriginID) string
   157  
   158  	Reload() (bool, error)
   159  
   160  	ResourcesChecked() (bool, error)
   161  
   162  	AcquireTrackingLock(logger lager.Logger, interval time.Duration) (lock.Lock, bool, error)
   163  
   164  	Interceptible() (bool, error)
   165  	Preparation() (BuildPreparation, bool, error)
   166  
   167  	Start(atc.Plan) (bool, error)
   168  	Finish(BuildStatus) error
   169  
   170  	Variables(lager.Logger, creds.Secrets, creds.VarSourcePool) (vars.Variables, error)
   171  
   172  	SetInterceptible(bool) error
   173  
   174  	Events(uint) (EventSource, error)
   175  	SaveEvent(event atc.Event) error
   176  
   177  	Artifacts() ([]WorkerArtifact, error)
   178  	Artifact(artifactID int) (WorkerArtifact, error)
   179  
   180  	SaveOutput(string, atc.Source, atc.VersionedResourceTypes, atc.Version, ResourceConfigMetadataFields, string, string) error
   181  	AdoptInputsAndPipes() ([]BuildInput, bool, error)
   182  	AdoptRerunInputsAndPipes() ([]BuildInput, bool, error)
   183  
   184  	Resources() ([]BuildInput, []BuildOutput, error)
   185  	SaveImageResourceVersion(UsedResourceCache) error
   186  
   187  	Delete() (bool, error)
   188  	MarkAsAborted() error
   189  	IsAborted() bool
   190  	AbortNotifier() (Notifier, error)
   191  
   192  	IsDrained() bool
   193  	SetDrained(bool) error
   194  
   195  	SpanContext() propagation.HTTPSupplier
   196  
   197  	SavePipeline(
   198  		pipelineRef atc.PipelineRef,
   199  		teamId int,
   200  		config atc.Config,
   201  		from ConfigVersion,
   202  		initiallyPaused bool,
   203  	) (Pipeline, bool, error)
   204  }
   205  
   206  type build struct {
   207  	pipelineRef
   208  
   209  	id          int
   210  	name        string
   211  	status      BuildStatus
   212  	scheduled   bool
   213  	inputsReady bool
   214  
   215  	teamID   int
   216  	teamName string
   217  
   218  	jobID   int
   219  	jobName string
   220  
   221  	resourceID   int
   222  	resourceName string
   223  
   224  	resourceTypeID   int
   225  	resourceTypeName string
   226  
   227  	isManuallyTriggered bool
   228  
   229  	rerunOf     int
   230  	rerunOfName string
   231  	rerunNumber int
   232  
   233  	schema      string
   234  	privatePlan atc.Plan
   235  	publicPlan  *json.RawMessage
   236  
   237  	createTime time.Time
   238  	startTime  time.Time
   239  	endTime    time.Time
   240  	reapTime   time.Time
   241  
   242  	drained   bool
   243  	aborted   bool
   244  	completed bool
   245  
   246  	spanContext SpanContext
   247  }
   248  
   249  func newEmptyBuild(conn Conn, lockFactory lock.LockFactory) *build {
   250  	return &build{pipelineRef: pipelineRef{conn: conn, lockFactory: lockFactory}}
   251  }
   252  
   253  var ErrBuildDisappeared = errors.New("build disappeared from db")
   254  var ErrBuildHasNoPipeline = errors.New("build has no pipeline")
   255  var ErrBuildArtifactNotFound = errors.New("build artifact not found")
   256  
   257  type ResourceNotFoundInPipeline struct {
   258  	Resource string
   259  	Pipeline string
   260  }
   261  
   262  func (r ResourceNotFoundInPipeline) Error() string {
   263  	return fmt.Sprintf("resource %s not found in pipeline %s", r.Resource, r.Pipeline)
   264  }
   265  
   266  // SyslogTag returns a string to be set as a tag on syslog events pertaining to
   267  // the build.
   268  func (b *build) SyslogTag(origin event.OriginID) string {
   269  	segments := []string{b.teamName}
   270  
   271  	if b.pipelineID != 0 {
   272  		segments = append(segments, b.pipelineName)
   273  	}
   274  
   275  	if b.jobID != 0 {
   276  		segments = append(segments, b.jobName, b.name)
   277  	} else if b.resourceID != 0 {
   278  		segments = append(segments, b.resourceName, strconv.Itoa(b.id))
   279  	} else if b.resourceTypeID != 0 {
   280  		segments = append(segments, b.resourceTypeName, strconv.Itoa(b.id))
   281  	} else {
   282  		segments = append(segments, strconv.Itoa(b.id))
   283  	}
   284  
   285  	segments = append(segments, origin.String())
   286  
   287  	return strings.Join(segments, "/")
   288  }
   289  
   290  // LagerData returns attributes which are to be emitted in logs pertaining to
   291  // the build.
   292  func (b *build) LagerData() lager.Data {
   293  	data := lager.Data{
   294  		"build_id": b.id,
   295  		"build":    b.name,
   296  		"team":     b.teamName,
   297  	}
   298  
   299  	if b.pipelineID != 0 {
   300  		data["pipeline"] = b.pipelineName
   301  	}
   302  
   303  	if b.jobID != 0 {
   304  		data["job"] = b.jobName
   305  	}
   306  
   307  	if b.resourceID != 0 {
   308  		data["resource"] = b.resourceName
   309  	}
   310  
   311  	if b.resourceTypeID != 0 {
   312  		data["resource_type"] = b.resourceTypeName
   313  	}
   314  
   315  	return data
   316  }
   317  
   318  // TracingAttrs returns attributes which are to be emitted in spans and
   319  // metrics pertaining to the build.
   320  func (b *build) TracingAttrs() tracing.Attrs {
   321  	data := tracing.Attrs{
   322  		"build_id": strconv.Itoa(b.id),
   323  		"build":    b.name,
   324  		"team":     b.teamName,
   325  	}
   326  
   327  	if b.pipelineID != 0 {
   328  		data["pipeline"] = b.pipelineName
   329  	}
   330  
   331  	if b.jobID != 0 {
   332  		data["job"] = b.jobName
   333  	}
   334  
   335  	if b.resourceID != 0 {
   336  		data["resource"] = b.resourceName
   337  	}
   338  
   339  	if b.resourceTypeID != 0 {
   340  		data["resource_type"] = b.resourceTypeName
   341  	}
   342  
   343  	return data
   344  }
   345  
   346  func (b *build) ID() int                      { return b.id }
   347  func (b *build) Name() string                 { return b.name }
   348  func (b *build) JobID() int                   { return b.jobID }
   349  func (b *build) JobName() string              { return b.jobName }
   350  func (b *build) ResourceID() int              { return b.resourceID }
   351  func (b *build) ResourceName() string         { return b.resourceName }
   352  func (b *build) ResourceTypeID() int          { return b.resourceTypeID }
   353  func (b *build) ResourceTypeName() string     { return b.resourceTypeName }
   354  func (b *build) TeamID() int                  { return b.teamID }
   355  func (b *build) TeamName() string             { return b.teamName }
   356  func (b *build) IsManuallyTriggered() bool    { return b.isManuallyTriggered }
   357  func (b *build) Schema() string               { return b.schema }
   358  func (b *build) PrivatePlan() atc.Plan        { return b.privatePlan }
   359  func (b *build) PublicPlan() *json.RawMessage { return b.publicPlan }
   360  func (b *build) HasPlan() bool                { return string(*b.publicPlan) != "{}" }
   361  func (b *build) IsNewerThanLastCheckOf(input Resource) bool {
   362  	return b.createTime.After(input.LastCheckEndTime())
   363  }
   364  func (b *build) StartTime() time.Time { return b.startTime }
   365  func (b *build) EndTime() time.Time   { return b.endTime }
   366  func (b *build) ReapTime() time.Time  { return b.reapTime }
   367  func (b *build) Status() BuildStatus  { return b.status }
   368  func (b *build) IsScheduled() bool    { return b.scheduled }
   369  func (b *build) IsDrained() bool      { return b.drained }
   370  func (b *build) IsRunning() bool      { return !b.completed }
   371  func (b *build) IsAborted() bool      { return b.aborted }
   372  func (b *build) IsCompleted() bool    { return b.completed }
   373  func (b *build) InputsReady() bool    { return b.inputsReady }
   374  func (b *build) RerunOf() int         { return b.rerunOf }
   375  func (b *build) RerunOfName() string  { return b.rerunOfName }
   376  func (b *build) RerunNumber() int     { return b.rerunNumber }
   377  
   378  func (b *build) Reload() (bool, error) {
   379  	row := buildsQuery.Where(sq.Eq{"b.id": b.id}).
   380  		RunWith(b.conn).
   381  		QueryRow()
   382  
   383  	err := scanBuild(b, row, b.conn.EncryptionStrategy())
   384  	if err != nil {
   385  		if err == sql.ErrNoRows {
   386  			return false, nil
   387  		}
   388  		return false, err
   389  	}
   390  
   391  	return true, nil
   392  }
   393  
   394  func (b *build) Interceptible() (bool, error) {
   395  	var interceptible bool
   396  
   397  	err := psql.Select("interceptible").
   398  		From("builds").
   399  		Where(sq.Eq{
   400  			"id": b.id,
   401  		}).
   402  		RunWith(b.conn).
   403  		QueryRow().Scan(&interceptible)
   404  
   405  	if err != nil {
   406  		return true, err
   407  	}
   408  
   409  	return interceptible, nil
   410  }
   411  
   412  func (b *build) SetInterceptible(i bool) error {
   413  	rows, err := psql.Update("builds").
   414  		Set("interceptible", i).
   415  		Where(sq.Eq{
   416  			"id": b.id,
   417  		}).
   418  		RunWith(b.conn).
   419  		Exec()
   420  	if err != nil {
   421  		return err
   422  	}
   423  
   424  	affected, err := rows.RowsAffected()
   425  	if err != nil {
   426  		return err
   427  	}
   428  
   429  	if affected == 0 {
   430  		return ErrBuildDisappeared
   431  	}
   432  
   433  	return nil
   434  }
   435  
   436  func (b *build) ResourcesChecked() (bool, error) {
   437  	var notChecked bool
   438  	err := b.conn.QueryRow(`
   439  		SELECT EXISTS (
   440  			SELECT 1
   441  			FROM resources r
   442  			JOIN job_inputs ji ON ji.resource_id = r.id
   443  			JOIN resource_config_scopes rs ON r.resource_config_scope_id = rs.id
   444  			WHERE ji.job_id = $1
   445  			AND rs.last_check_end_time < $2
   446  			AND NOT EXISTS (
   447  				SELECT
   448  				FROM resource_pins
   449  				WHERE resource_id = r.id
   450  			)
   451  		)`, b.jobID, b.createTime).Scan(&notChecked)
   452  	if err != nil {
   453  		return false, err
   454  	}
   455  
   456  	return !notChecked, nil
   457  }
   458  
   459  func (b *build) Start(plan atc.Plan) (bool, error) {
   460  	tx, err := b.conn.Begin()
   461  	if err != nil {
   462  		return false, err
   463  	}
   464  
   465  	defer Rollback(tx)
   466  
   467  	started, err := b.start(tx, plan)
   468  	if err != nil {
   469  		return false, err
   470  	}
   471  
   472  	err = tx.Commit()
   473  	if err != nil {
   474  		return false, err
   475  	}
   476  
   477  	if !started {
   478  		return false, nil
   479  	}
   480  
   481  	err = b.conn.Bus().Notify(buildEventsChannel(b.id))
   482  	if err != nil {
   483  		return false, err
   484  	}
   485  
   486  	err = b.conn.Bus().Notify(atc.ComponentBuildTracker)
   487  	if err != nil {
   488  		return false, err
   489  	}
   490  
   491  	return true, nil
   492  }
   493  
   494  func (b *build) start(tx Tx, plan atc.Plan) (bool, error) {
   495  	metadata, err := json.Marshal(plan)
   496  	if err != nil {
   497  		return false, err
   498  	}
   499  
   500  	encryptedPlan, nonce, err := b.conn.EncryptionStrategy().Encrypt([]byte(metadata))
   501  	if err != nil {
   502  		return false, err
   503  	}
   504  
   505  	var startTime time.Time
   506  	err = psql.Update("builds").
   507  		Set("status", BuildStatusStarted).
   508  		Set("start_time", sq.Expr("now()")).
   509  		Set("schema", schema).
   510  		Set("private_plan", encryptedPlan).
   511  		Set("public_plan", plan.Public()).
   512  		Set("nonce", nonce).
   513  		Where(sq.Eq{
   514  			"id":      b.id,
   515  			"status":  "pending",
   516  			"aborted": false,
   517  		}).
   518  		Suffix("RETURNING start_time").
   519  		RunWith(tx).
   520  		QueryRow().
   521  		Scan(&startTime)
   522  	if err != nil {
   523  		if err == sql.ErrNoRows {
   524  			return false, nil
   525  		}
   526  		return false, err
   527  	}
   528  
   529  	err = b.saveEvent(tx, event.Status{
   530  		Status: atc.StatusStarted,
   531  		Time:   startTime.Unix(),
   532  	})
   533  	if err != nil {
   534  		return false, err
   535  	}
   536  
   537  	return true, nil
   538  }
   539  
   540  func (b *build) Finish(status BuildStatus) error {
   541  	tx, err := b.conn.Begin()
   542  	if err != nil {
   543  		return err
   544  	}
   545  
   546  	defer Rollback(tx)
   547  
   548  	var endTime time.Time
   549  
   550  	err = psql.Update("builds").
   551  		Set("status", status).
   552  		Set("end_time", sq.Expr("now()")).
   553  		Set("completed", true).
   554  		Set("private_plan", nil).
   555  		Set("nonce", nil).
   556  		Where(sq.Eq{"id": b.id}).
   557  		Suffix("RETURNING end_time").
   558  		RunWith(tx).
   559  		QueryRow().
   560  		Scan(&endTime)
   561  	if err != nil {
   562  		return err
   563  	}
   564  
   565  	err = b.saveEvent(tx, event.Status{
   566  		Status: atc.BuildStatus(status),
   567  		Time:   endTime.Unix(),
   568  	})
   569  	if err != nil {
   570  		return err
   571  	}
   572  
   573  	_, err = tx.Exec(fmt.Sprintf(`
   574  		DROP SEQUENCE %s
   575  	`, buildEventSeq(b.id)))
   576  	if err != nil {
   577  		return err
   578  	}
   579  
   580  	if b.jobID != 0 && status == BuildStatusSucceeded {
   581  		_, err = tx.Exec(`WITH caches AS (
   582  			SELECT resource_cache_id, build_id
   583  			FROM build_image_resource_caches brc
   584  			JOIN builds b ON b.id = brc.build_id
   585  			WHERE b.job_id = $1
   586  		)
   587  		DELETE FROM build_image_resource_caches birc
   588  		USING caches c
   589  		WHERE c.build_id = birc.build_id AND birc.build_id < $2`,
   590  			b.jobID, b.id)
   591  		if err != nil {
   592  			return err
   593  		}
   594  
   595  		rows, err := psql.Select("o.resource_id", "o.version_md5").
   596  			From("build_resource_config_version_outputs o").
   597  			Where(sq.Eq{
   598  				"o.build_id": b.id,
   599  			}).
   600  			RunWith(tx).
   601  			Query()
   602  		if err != nil {
   603  			return err
   604  		}
   605  
   606  		defer Close(rows)
   607  
   608  		uniqueVersions := map[AlgorithmVersion]bool{}
   609  		outputVersions := map[string][]string{}
   610  		for rows.Next() {
   611  			var resourceID int
   612  			var version string
   613  
   614  			err = rows.Scan(&resourceID, &version)
   615  			if err != nil {
   616  				return err
   617  			}
   618  
   619  			resourceVersion := AlgorithmVersion{
   620  				ResourceID: resourceID,
   621  				Version:    ResourceVersion(version),
   622  			}
   623  
   624  			if !uniqueVersions[resourceVersion] {
   625  				resID := strconv.Itoa(resourceID)
   626  				outputVersions[resID] = append(outputVersions[resID], version)
   627  
   628  				uniqueVersions[resourceVersion] = true
   629  			}
   630  		}
   631  
   632  		rows, err = psql.Select("i.resource_id", "i.version_md5").
   633  			From("build_resource_config_version_inputs i").
   634  			Where(sq.Eq{
   635  				"i.build_id": b.id,
   636  			}).
   637  			RunWith(tx).
   638  			Query()
   639  		if err != nil {
   640  			return err
   641  		}
   642  
   643  		defer Close(rows)
   644  
   645  		for rows.Next() {
   646  			var resourceID int
   647  			var version string
   648  
   649  			err = rows.Scan(&resourceID, &version)
   650  			if err != nil {
   651  				return err
   652  			}
   653  
   654  			resourceVersion := AlgorithmVersion{
   655  				ResourceID: resourceID,
   656  				Version:    ResourceVersion(version),
   657  			}
   658  
   659  			if !uniqueVersions[resourceVersion] {
   660  				resID := strconv.Itoa(resourceID)
   661  				outputVersions[resID] = append(outputVersions[resID], version)
   662  
   663  				uniqueVersions[resourceVersion] = true
   664  			}
   665  		}
   666  
   667  		outputsJSON, err := json.Marshal(outputVersions)
   668  		if err != nil {
   669  			return err
   670  		}
   671  
   672  		var rerunOf sql.NullInt64
   673  		if b.rerunOf != 0 {
   674  			rerunOf = sql.NullInt64{Int64: int64(b.rerunOf), Valid: true}
   675  		}
   676  
   677  		_, err = psql.Insert("successful_build_outputs").
   678  			Columns("build_id", "job_id", "rerun_of", "outputs").
   679  			Values(b.id, b.jobID, rerunOf, outputsJSON).
   680  			RunWith(tx).
   681  			Exec()
   682  		if err != nil {
   683  			return err
   684  		}
   685  
   686  		// recursively archive any child pipelines. This is likely the most common case for
   687  		// automatic archiving so it's worth it to make the feedback more instantenous rather
   688  		// than relying on GC
   689  		pipelineRows, err := pipelinesQuery.
   690  			Prefix(`
   691  WITH RECURSIVE pipelines_to_archive AS (
   692  	SELECT id from pipelines where archived = false AND parent_job_id = $1 AND parent_build_id < $2
   693  	UNION
   694  	SELECT p.id from pipelines p join jobs j on p.parent_job_id = j.id join pipelines_to_archive on j.pipeline_id = pipelines_to_archive.id
   695  )`,
   696  				b.jobID, b.id,
   697  			).
   698  			Where("EXISTS(SELECT 1 FROM pipelines_to_archive pa WHERE pa.id = p.id)").
   699  			RunWith(tx).
   700  			Query()
   701  
   702  		if err != nil {
   703  			return err
   704  		}
   705  		defer pipelineRows.Close()
   706  
   707  		err = archivePipelines(tx, b.conn, b.lockFactory, pipelineRows)
   708  		if err != nil {
   709  			return err
   710  		}
   711  	}
   712  
   713  	if b.jobID != 0 {
   714  		err = requestScheduleOnDownstreamJobs(tx, b.jobID)
   715  		if err != nil {
   716  			return err
   717  		}
   718  
   719  		err = updateTransitionBuildForJob(tx, b.jobID, b.id, status, b.rerunOf)
   720  		if err != nil {
   721  			return err
   722  		}
   723  
   724  		latestNonRerunID, err := latestCompletedNonRerunBuild(tx, b.jobID)
   725  		if err != nil {
   726  			return err
   727  		}
   728  
   729  		err = updateLatestCompletedBuildForJob(tx, b.jobID, latestNonRerunID)
   730  		if err != nil {
   731  			return err
   732  		}
   733  
   734  		err = updateNextBuildForJob(tx, b.jobID, latestNonRerunID)
   735  		if err != nil {
   736  			return err
   737  		}
   738  	}
   739  
   740  	err = tx.Commit()
   741  	if err != nil {
   742  		return err
   743  	}
   744  
   745  	err = b.conn.Bus().Notify(buildEventsChannel(b.id))
   746  	if err != nil {
   747  		return err
   748  	}
   749  
   750  	return nil
   751  }
   752  
   753  // Variables creates variables for this build. If the build is a one-off build, it
   754  // just uses the global secrets manager. If it belongs to a pipeline, it combines
   755  // the global secrets manager with the pipeline's var_sources.
   756  func (b *build) Variables(logger lager.Logger, globalSecrets creds.Secrets, varSourcePool creds.VarSourcePool) (vars.Variables, error) {
   757  	// "fly execute" generated build will have no pipeline.
   758  	if b.pipelineID == 0 {
   759  		return creds.NewVariables(globalSecrets, b.teamName, b.pipelineName, false), nil
   760  	}
   761  	pipeline, found, err := b.Pipeline()
   762  	if err != nil {
   763  		return nil, fmt.Errorf("failed to find pipeline: %w", err)
   764  	}
   765  	if !found {
   766  		return nil, errors.New("pipeline not found")
   767  	}
   768  
   769  	return pipeline.Variables(logger, globalSecrets, varSourcePool)
   770  }
   771  
   772  func (b *build) SetDrained(drained bool) error {
   773  	_, err := psql.Update("builds").
   774  		Set("drained", drained).
   775  		Where(sq.Eq{"id": b.id}).
   776  		RunWith(b.conn).
   777  		Exec()
   778  
   779  	if err == nil {
   780  		b.drained = drained
   781  	}
   782  	return err
   783  }
   784  
   785  func (b *build) Delete() (bool, error) {
   786  	rows, err := psql.Delete("builds").
   787  		Where(sq.Eq{
   788  			"id": b.id,
   789  		}).
   790  		RunWith(b.conn).
   791  		Exec()
   792  	if err != nil {
   793  		return false, err
   794  	}
   795  
   796  	affected, err := rows.RowsAffected()
   797  	if err != nil {
   798  		return false, err
   799  	}
   800  
   801  	if affected == 0 {
   802  		return false, ErrBuildDisappeared
   803  	}
   804  
   805  	return true, nil
   806  }
   807  
   808  // MarkAsAborted will send the abort notification to all build abort
   809  // channel listeners. It will set the status to aborted that will make
   810  // AbortNotifier send notification in case if tracking ATC misses the first
   811  // notification on abort channel.
   812  // Setting status as aborted will also make Start() return false in case where
   813  // build was aborted before it was started.
   814  func (b *build) MarkAsAborted() error {
   815  	tx, err := b.conn.Begin()
   816  	if err != nil {
   817  		return err
   818  	}
   819  
   820  	defer Rollback(tx)
   821  
   822  	_, err = psql.Update("builds").
   823  		Set("aborted", true).
   824  		Where(sq.Eq{"id": b.id}).
   825  		RunWith(tx).
   826  		Exec()
   827  	if err != nil {
   828  		return err
   829  	}
   830  
   831  	if b.status == BuildStatusPending {
   832  		err = requestSchedule(tx, b.jobID)
   833  		if err != nil {
   834  			return err
   835  		}
   836  	}
   837  
   838  	err = tx.Commit()
   839  	if err != nil {
   840  		return err
   841  	}
   842  
   843  	return b.conn.Bus().Notify(buildAbortChannel(b.id))
   844  }
   845  
   846  // AbortNotifier returns a Notifier that can be watched for when the build
   847  // is marked as aborted. Once the build is marked as aborted it will send a
   848  // notification to finish the build to ATC that is tracking this build.
   849  func (b *build) AbortNotifier() (Notifier, error) {
   850  	return newConditionNotifier(b.conn.Bus(), buildAbortChannel(b.id), func() (bool, error) {
   851  		var aborted bool
   852  		err := psql.Select("aborted = true").
   853  			From("builds").
   854  			Where(sq.Eq{"id": b.id}).
   855  			RunWith(b.conn).
   856  			QueryRow().
   857  			Scan(&aborted)
   858  
   859  		return aborted, err
   860  	})
   861  }
   862  
   863  func (b *build) SaveImageResourceVersion(rc UsedResourceCache) error {
   864  	_, err := psql.Insert("build_image_resource_caches").
   865  		Columns("resource_cache_id", "build_id").
   866  		Values(rc.ID(), b.id).
   867  		RunWith(b.conn).
   868  		Exec()
   869  	if err != nil {
   870  		if pqErr, ok := err.(*pq.Error); ok && pqErr.Code.Name() == pqUniqueViolationErrCode {
   871  			return nil
   872  		}
   873  
   874  		return err
   875  	}
   876  
   877  	return nil
   878  }
   879  
   880  func (b *build) AcquireTrackingLock(logger lager.Logger, interval time.Duration) (lock.Lock, bool, error) {
   881  	lock, acquired, err := b.lockFactory.Acquire(
   882  		logger.Session("lock", lager.Data{
   883  			"build_id": b.id,
   884  		}),
   885  		lock.NewBuildTrackingLockID(b.id),
   886  	)
   887  	if err != nil {
   888  		return nil, false, err
   889  	}
   890  
   891  	if !acquired {
   892  		return nil, false, nil
   893  	}
   894  
   895  	return lock, true, nil
   896  }
   897  
   898  func (b *build) Preparation() (BuildPreparation, bool, error) {
   899  	if b.jobID == 0 || b.status != BuildStatusPending {
   900  		return BuildPreparation{
   901  			BuildID:             b.id,
   902  			PausedPipeline:      BuildPreparationStatusNotBlocking,
   903  			PausedJob:           BuildPreparationStatusNotBlocking,
   904  			MaxRunningBuilds:    BuildPreparationStatusNotBlocking,
   905  			Inputs:              map[string]BuildPreparationStatus{},
   906  			InputsSatisfied:     BuildPreparationStatusNotBlocking,
   907  			MissingInputReasons: MissingInputReasons{},
   908  		}, true, nil
   909  	}
   910  
   911  	var (
   912  		pausedPipeline     bool
   913  		pausedJob          bool
   914  		maxInFlightReached bool
   915  		pipelineID         int
   916  		jobName            string
   917  	)
   918  	err := psql.Select("p.paused, j.paused, j.max_in_flight_reached, j.pipeline_id, j.name").
   919  		From("builds b").
   920  		Join("jobs j ON b.job_id = j.id").
   921  		Join("pipelines p ON j.pipeline_id = p.id").
   922  		Where(sq.Eq{"b.id": b.id}).
   923  		RunWith(b.conn).
   924  		QueryRow().
   925  		Scan(&pausedPipeline, &pausedJob, &maxInFlightReached, &pipelineID, &jobName)
   926  	if err != nil {
   927  		if err == sql.ErrNoRows {
   928  			return BuildPreparation{}, false, nil
   929  		}
   930  		return BuildPreparation{}, false, err
   931  	}
   932  
   933  	pausedPipelineStatus := BuildPreparationStatusNotBlocking
   934  	if pausedPipeline {
   935  		pausedPipelineStatus = BuildPreparationStatusBlocking
   936  	}
   937  
   938  	pausedJobStatus := BuildPreparationStatusNotBlocking
   939  	if pausedJob {
   940  		pausedJobStatus = BuildPreparationStatusBlocking
   941  	}
   942  
   943  	maxInFlightReachedStatus := BuildPreparationStatusNotBlocking
   944  	if maxInFlightReached {
   945  		maxInFlightReachedStatus = BuildPreparationStatusBlocking
   946  	}
   947  
   948  	tf := NewTeamFactory(b.conn, b.lockFactory)
   949  	t, found, err := tf.FindTeam(b.teamName)
   950  	if err != nil {
   951  		return BuildPreparation{}, false, err
   952  	}
   953  
   954  	if !found {
   955  		return BuildPreparation{}, false, nil
   956  	}
   957  
   958  	pipeline, found, err := t.Pipeline(b.PipelineRef())
   959  	if err != nil {
   960  		return BuildPreparation{}, false, err
   961  	}
   962  
   963  	if !found {
   964  		return BuildPreparation{}, false, nil
   965  	}
   966  
   967  	job, found, err := pipeline.Job(jobName)
   968  	if err != nil {
   969  		return BuildPreparation{}, false, err
   970  	}
   971  
   972  	if !found {
   973  		return BuildPreparation{}, false, nil
   974  	}
   975  
   976  	config, err := job.Config()
   977  	if err != nil {
   978  		return BuildPreparation{}, false, err
   979  	}
   980  
   981  	configInputs := config.Inputs()
   982  
   983  	buildInputs, err := job.GetNextBuildInputs()
   984  	if err != nil {
   985  		return BuildPreparation{}, false, err
   986  	}
   987  
   988  	resolved := true
   989  	for _, input := range buildInputs {
   990  		if input.ResolveError != "" {
   991  			resolved = false
   992  			break
   993  		}
   994  	}
   995  
   996  	inputsSatisfiedStatus := BuildPreparationStatusNotBlocking
   997  	inputs := map[string]BuildPreparationStatus{}
   998  	missingInputReasons := MissingInputReasons{}
   999  
  1000  	for _, configInput := range configInputs {
  1001  		buildInput := BuildInput{}
  1002  		found := false
  1003  		for _, b := range buildInputs {
  1004  			if b.Name == configInput.Name {
  1005  				found = true
  1006  				buildInput = b
  1007  				break
  1008  			}
  1009  		}
  1010  
  1011  		if found {
  1012  			if buildInput.ResolveError == "" {
  1013  				if b.IsManuallyTriggered() {
  1014  					resource, _, err := pipeline.ResourceByID(buildInput.ResourceID)
  1015  					if err != nil {
  1016  						return BuildPreparation{}, false, err
  1017  					}
  1018  
  1019  					// input is blocking if its last check time is before build create time
  1020  					if b.IsNewerThanLastCheckOf(resource) {
  1021  						inputs[buildInput.Name] = BuildPreparationStatusBlocking
  1022  						missingInputReasons.RegisterNoResourceCheckFinished(buildInput.Name)
  1023  						inputsSatisfiedStatus = BuildPreparationStatusBlocking
  1024  					} else {
  1025  						inputs[buildInput.Name] = BuildPreparationStatusNotBlocking
  1026  					}
  1027  				} else {
  1028  					inputs[buildInput.Name] = BuildPreparationStatusNotBlocking
  1029  				}
  1030  			} else {
  1031  				inputs[configInput.Name] = BuildPreparationStatusBlocking
  1032  				missingInputReasons.RegisterResolveError(configInput.Name, buildInput.ResolveError)
  1033  				inputsSatisfiedStatus = BuildPreparationStatusBlocking
  1034  			}
  1035  		} else {
  1036  			if resolved {
  1037  				inputs[configInput.Name] = BuildPreparationStatusBlocking
  1038  				missingInputReasons.RegisterMissingInput(configInput.Name)
  1039  				inputsSatisfiedStatus = BuildPreparationStatusBlocking
  1040  			}
  1041  		}
  1042  	}
  1043  
  1044  	buildPreparation := BuildPreparation{
  1045  		BuildID:             b.id,
  1046  		PausedPipeline:      pausedPipelineStatus,
  1047  		PausedJob:           pausedJobStatus,
  1048  		MaxRunningBuilds:    maxInFlightReachedStatus,
  1049  		Inputs:              inputs,
  1050  		InputsSatisfied:     inputsSatisfiedStatus,
  1051  		MissingInputReasons: missingInputReasons,
  1052  	}
  1053  
  1054  	return buildPreparation, true, nil
  1055  }
  1056  
  1057  func (b *build) Events(from uint) (EventSource, error) {
  1058  	notifier, err := newConditionNotifier(b.conn.Bus(), buildEventsChannel(b.id), func() (bool, error) {
  1059  		return true, nil
  1060  	})
  1061  	if err != nil {
  1062  		return nil, err
  1063  	}
  1064  
  1065  	return newBuildEventSource(
  1066  		b.id,
  1067  		b.eventsTable(),
  1068  		b.conn,
  1069  		notifier,
  1070  		from,
  1071  	), nil
  1072  }
  1073  
  1074  func (b *build) SaveEvent(event atc.Event) error {
  1075  	tx, err := b.conn.Begin()
  1076  	if err != nil {
  1077  		return err
  1078  	}
  1079  
  1080  	defer Rollback(tx)
  1081  
  1082  	err = b.saveEvent(tx, event)
  1083  	if err != nil {
  1084  		return err
  1085  	}
  1086  
  1087  	err = tx.Commit()
  1088  	if err != nil {
  1089  		return err
  1090  	}
  1091  
  1092  	return b.conn.Bus().Notify(buildEventsChannel(b.id))
  1093  }
  1094  
  1095  func (b *build) Artifact(artifactID int) (WorkerArtifact, error) {
  1096  
  1097  	artifact := artifact{
  1098  		conn: b.conn,
  1099  	}
  1100  
  1101  	err := psql.Select("id", "name", "created_at").
  1102  		From("worker_artifacts").
  1103  		Where(sq.Eq{
  1104  			"id": artifactID,
  1105  		}).
  1106  		RunWith(b.conn).
  1107  		Scan(&artifact.id, &artifact.name, &artifact.createdAt)
  1108  
  1109  	return &artifact, err
  1110  }
  1111  
  1112  func (b *build) Artifacts() ([]WorkerArtifact, error) {
  1113  	artifacts := []WorkerArtifact{}
  1114  
  1115  	rows, err := psql.Select("id", "name", "created_at").
  1116  		From("worker_artifacts").
  1117  		Where(sq.Eq{
  1118  			"build_id": b.id,
  1119  		}).
  1120  		RunWith(b.conn).
  1121  		Query()
  1122  	if err != nil {
  1123  		return nil, err
  1124  	}
  1125  
  1126  	defer Close(rows)
  1127  
  1128  	for rows.Next() {
  1129  		wa := artifact{
  1130  			conn:    b.conn,
  1131  			buildID: b.id,
  1132  		}
  1133  
  1134  		err = rows.Scan(&wa.id, &wa.name, &wa.createdAt)
  1135  		if err != nil {
  1136  			return nil, err
  1137  		}
  1138  
  1139  		artifacts = append(artifacts, &wa)
  1140  	}
  1141  
  1142  	return artifacts, nil
  1143  }
  1144  
  1145  func (b *build) SaveOutput(
  1146  	resourceType string,
  1147  	source atc.Source,
  1148  	resourceTypes atc.VersionedResourceTypes,
  1149  	version atc.Version,
  1150  	metadata ResourceConfigMetadataFields,
  1151  	outputName string,
  1152  	resourceName string,
  1153  ) error {
  1154  	// We should never save outputs for builds without a Pipeline ID because
  1155  	// One-off Builds will never have Put steps. This shouldn't happen, but
  1156  	// its best to return an error just in case
  1157  	if b.pipelineID == 0 {
  1158  		return ErrBuildHasNoPipeline
  1159  	}
  1160  
  1161  	pipeline, found, err := b.Pipeline()
  1162  	if err != nil {
  1163  		return err
  1164  	}
  1165  
  1166  	if !found {
  1167  		return ErrBuildHasNoPipeline
  1168  	}
  1169  
  1170  	theResource, found, err := pipeline.Resource(resourceName)
  1171  	if err != nil {
  1172  		return err
  1173  	}
  1174  
  1175  	if !found {
  1176  		return ResourceNotFoundInPipeline{resourceName, b.pipelineName}
  1177  	}
  1178  
  1179  	tx, err := b.conn.Begin()
  1180  	if err != nil {
  1181  		return err
  1182  	}
  1183  
  1184  	defer Rollback(tx)
  1185  
  1186  	resourceConfigDescriptor, err := constructResourceConfigDescriptor(resourceType, source, resourceTypes)
  1187  	if err != nil {
  1188  		return err
  1189  	}
  1190  
  1191  	resourceConfig, err := resourceConfigDescriptor.findOrCreate(tx, b.lockFactory, b.conn)
  1192  	if err != nil {
  1193  		return err
  1194  	}
  1195  
  1196  	resourceConfigScope, err := findOrCreateResourceConfigScope(tx, b.conn, b.lockFactory, resourceConfig, theResource)
  1197  	if err != nil {
  1198  		return err
  1199  	}
  1200  
  1201  	newVersion, err := saveResourceVersion(tx, resourceConfigScope.ID(), version, metadata, nil)
  1202  	if err != nil {
  1203  		return err
  1204  	}
  1205  
  1206  	versionBytes, err := json.Marshal(version)
  1207  	if err != nil {
  1208  		return err
  1209  	}
  1210  
  1211  	versionJSON := string(versionBytes)
  1212  
  1213  	if newVersion {
  1214  		err = incrementCheckOrder(tx, resourceConfigScope.ID(), versionJSON)
  1215  		if err != nil {
  1216  			return err
  1217  		}
  1218  	}
  1219  
  1220  	err = theResource.(*resource).setResourceConfigScopeInTransaction(tx, resourceConfigScope)
  1221  	if err != nil {
  1222  		return err
  1223  	}
  1224  
  1225  	_, err = psql.Insert("build_resource_config_version_outputs").
  1226  		Columns("resource_id", "build_id", "version_md5", "name").
  1227  		Values(theResource.ID(), strconv.Itoa(b.id), sq.Expr("md5(?)", versionJSON), outputName).
  1228  		Suffix("ON CONFLICT DO NOTHING").
  1229  		RunWith(tx).
  1230  		Exec()
  1231  	if err != nil {
  1232  		return err
  1233  	}
  1234  
  1235  	if newVersion {
  1236  		err = requestScheduleForJobsUsingResourceConfigScope(tx, resourceConfigScope.ID())
  1237  		if err != nil {
  1238  			return err
  1239  		}
  1240  	}
  1241  
  1242  	err = tx.Commit()
  1243  	if err != nil {
  1244  		return err
  1245  	}
  1246  
  1247  	return nil
  1248  }
  1249  
  1250  func (b *build) AdoptInputsAndPipes() ([]BuildInput, bool, error) {
  1251  	tx, err := b.conn.Begin()
  1252  	if err != nil {
  1253  		return nil, false, err
  1254  	}
  1255  
  1256  	defer tx.Rollback()
  1257  
  1258  	var determined bool
  1259  	err = psql.Select("inputs_determined").
  1260  		From("jobs").
  1261  		Where(sq.Eq{
  1262  			"id": b.jobID,
  1263  		}).
  1264  		RunWith(tx).
  1265  		QueryRow().
  1266  		Scan(&determined)
  1267  	if err != nil {
  1268  		return nil, false, err
  1269  	}
  1270  
  1271  	if !determined {
  1272  		return nil, false, nil
  1273  	}
  1274  
  1275  	_, err = psql.Delete("build_resource_config_version_inputs").
  1276  		Where(sq.Eq{"build_id": b.id}).
  1277  		RunWith(tx).
  1278  		Exec()
  1279  	if err != nil {
  1280  		return nil, false, err
  1281  	}
  1282  
  1283  	rows, err := psql.Insert("build_resource_config_version_inputs").
  1284  		Columns("resource_id", "version_md5", "name", "first_occurrence", "build_id").
  1285  		Select(psql.Select("i.resource_id", "i.version_md5", "i.input_name", "i.first_occurrence").
  1286  			Column("?", b.id).
  1287  			From("next_build_inputs i").
  1288  			Where(sq.Eq{"i.job_id": b.jobID})).
  1289  		Suffix("ON CONFLICT (build_id, resource_id, version_md5, name) DO UPDATE SET first_occurrence = EXCLUDED.first_occurrence").
  1290  		Suffix("RETURNING name, resource_id, version_md5, first_occurrence").
  1291  		RunWith(tx).
  1292  		Query()
  1293  	if err != nil {
  1294  		return nil, false, err
  1295  	}
  1296  
  1297  	inputs := InputMapping{}
  1298  	for rows.Next() {
  1299  		var (
  1300  			inputName       string
  1301  			firstOccurrence bool
  1302  			versionMD5      string
  1303  			resourceID      int
  1304  		)
  1305  
  1306  		err := rows.Scan(&inputName, &resourceID, &versionMD5, &firstOccurrence)
  1307  		if err != nil {
  1308  			return nil, false, err
  1309  		}
  1310  
  1311  		inputs[inputName] = InputResult{
  1312  			Input: &AlgorithmInput{
  1313  				AlgorithmVersion: AlgorithmVersion{
  1314  					ResourceID: resourceID,
  1315  					Version:    ResourceVersion(versionMD5),
  1316  				},
  1317  				FirstOccurrence: firstOccurrence,
  1318  			},
  1319  		}
  1320  	}
  1321  
  1322  	buildInputs := []BuildInput{}
  1323  
  1324  	for inputName, input := range inputs {
  1325  		var versionBlob string
  1326  
  1327  		err = psql.Select("v.version").
  1328  			From("resource_config_versions v").
  1329  			Join("resources r ON r.resource_config_scope_id = v.resource_config_scope_id").
  1330  			Where(sq.Eq{
  1331  				"v.version_md5": input.Input.Version,
  1332  				"r.id":          input.Input.ResourceID,
  1333  			}).
  1334  			RunWith(tx).
  1335  			QueryRow().
  1336  			Scan(&versionBlob)
  1337  		if err != nil {
  1338  			if err == sql.ErrNoRows {
  1339  				tx.Rollback()
  1340  
  1341  				_, err = psql.Update("next_build_inputs").
  1342  					Set("resolve_error", fmt.Sprintf("chosen version of input %s not available", inputName)).
  1343  					Where(sq.Eq{
  1344  						"job_id":     b.jobID,
  1345  						"input_name": inputName,
  1346  					}).
  1347  					RunWith(b.conn).
  1348  					Exec()
  1349  			}
  1350  
  1351  			return nil, false, err
  1352  		}
  1353  
  1354  		var version atc.Version
  1355  		err = json.Unmarshal([]byte(versionBlob), &version)
  1356  		if err != nil {
  1357  			return nil, false, err
  1358  		}
  1359  
  1360  		buildInputs = append(buildInputs, BuildInput{
  1361  			Name:            inputName,
  1362  			ResourceID:      input.Input.ResourceID,
  1363  			Version:         version,
  1364  			FirstOccurrence: input.Input.FirstOccurrence,
  1365  		})
  1366  	}
  1367  
  1368  	_, err = psql.Delete("build_pipes").
  1369  		Where(sq.Eq{"to_build_id": b.id}).
  1370  		RunWith(tx).
  1371  		Exec()
  1372  	if err != nil {
  1373  		return nil, false, err
  1374  	}
  1375  
  1376  	_, err = psql.Insert("build_pipes").
  1377  		Columns("from_build_id", "to_build_id").
  1378  		Select(psql.Select("nbp.from_build_id").
  1379  			Column("?", b.id).
  1380  			From("next_build_pipes nbp").
  1381  			Where(sq.Eq{"nbp.to_job_id": b.jobID})).
  1382  		Suffix("ON CONFLICT DO NOTHING").
  1383  		RunWith(tx).
  1384  		Exec()
  1385  	if err != nil {
  1386  		return nil, false, err
  1387  	}
  1388  
  1389  	_, err = psql.Update("builds").
  1390  		Set("inputs_ready", true).
  1391  		Where(sq.Eq{
  1392  			"id": b.id,
  1393  		}).
  1394  		RunWith(tx).
  1395  		Exec()
  1396  	if err != nil {
  1397  		return nil, false, err
  1398  	}
  1399  
  1400  	err = tx.Commit()
  1401  	if err != nil {
  1402  		return nil, false, err
  1403  	}
  1404  
  1405  	return buildInputs, true, nil
  1406  }
  1407  
  1408  func (b *build) AdoptRerunInputsAndPipes() ([]BuildInput, bool, error) {
  1409  	tx, err := b.conn.Begin()
  1410  	if err != nil {
  1411  		return nil, false, err
  1412  	}
  1413  
  1414  	defer tx.Rollback()
  1415  
  1416  	var ready bool
  1417  	err = psql.Select("inputs_ready").
  1418  		From("builds").
  1419  		Where(sq.Eq{
  1420  			"id": b.rerunOf,
  1421  		}).
  1422  		RunWith(tx).
  1423  		QueryRow().
  1424  		Scan(&ready)
  1425  	if err != nil {
  1426  		return nil, false, err
  1427  	}
  1428  
  1429  	if !ready {
  1430  		return nil, false, nil
  1431  	}
  1432  
  1433  	_, err = psql.Delete("build_resource_config_version_inputs").
  1434  		Where(sq.Eq{"build_id": b.id}).
  1435  		RunWith(tx).
  1436  		Exec()
  1437  	if err != nil {
  1438  		return nil, false, err
  1439  	}
  1440  
  1441  	rows, err := psql.Insert("build_resource_config_version_inputs").
  1442  		Columns("resource_id", "version_md5", "name", "first_occurrence", "build_id").
  1443  		Select(psql.Select("i.resource_id", "i.version_md5", "i.name", "false").
  1444  			Column("?", b.id).
  1445  			From("build_resource_config_version_inputs i").
  1446  			Where(sq.Eq{"i.build_id": b.rerunOf})).
  1447  		Suffix("ON CONFLICT (build_id, resource_id, version_md5, name) DO NOTHING").
  1448  		Suffix("RETURNING name, resource_id, version_md5, first_occurrence").
  1449  		RunWith(tx).
  1450  		Query()
  1451  	if err != nil {
  1452  		return nil, false, err
  1453  	}
  1454  
  1455  	inputs := InputMapping{}
  1456  	for rows.Next() {
  1457  		var (
  1458  			inputName       string
  1459  			firstOccurrence bool
  1460  			versionMD5      string
  1461  			resourceID      int
  1462  		)
  1463  
  1464  		err := rows.Scan(&inputName, &resourceID, &versionMD5, &firstOccurrence)
  1465  		if err != nil {
  1466  			return nil, false, err
  1467  		}
  1468  
  1469  		inputs[inputName] = InputResult{
  1470  			Input: &AlgorithmInput{
  1471  				AlgorithmVersion: AlgorithmVersion{
  1472  					ResourceID: resourceID,
  1473  					Version:    ResourceVersion(versionMD5),
  1474  				},
  1475  				FirstOccurrence: firstOccurrence,
  1476  			},
  1477  		}
  1478  	}
  1479  
  1480  	buildInputs := []BuildInput{}
  1481  	for inputName, input := range inputs {
  1482  		var versionBlob string
  1483  
  1484  		err = psql.Select("v.version").
  1485  			From("resource_config_versions v").
  1486  			Join("resources r ON r.resource_config_scope_id = v.resource_config_scope_id").
  1487  			Where(sq.Eq{
  1488  				"v.version_md5": input.Input.Version,
  1489  				"r.id":          input.Input.ResourceID,
  1490  			}).
  1491  			RunWith(tx).
  1492  			QueryRow().
  1493  			Scan(&versionBlob)
  1494  		if err != nil {
  1495  			if err == sql.ErrNoRows {
  1496  				tx.Rollback()
  1497  
  1498  				_, err = psql.Update("next_build_inputs").
  1499  					Set("resolve_error", fmt.Sprintf("chosen version of input %s not available", inputName)).
  1500  					Where(sq.Eq{
  1501  						"job_id":     b.jobID,
  1502  						"input_name": inputName,
  1503  					}).
  1504  					RunWith(b.conn).
  1505  					Exec()
  1506  
  1507  				err = b.MarkAsAborted()
  1508  				if err != nil {
  1509  					return nil, false, err
  1510  				}
  1511  			}
  1512  
  1513  			return nil, false, err
  1514  		}
  1515  
  1516  		var version atc.Version
  1517  		err = json.Unmarshal([]byte(versionBlob), &version)
  1518  		if err != nil {
  1519  			return nil, false, err
  1520  		}
  1521  
  1522  		buildInputs = append(buildInputs, BuildInput{
  1523  			Name:            inputName,
  1524  			ResourceID:      input.Input.ResourceID,
  1525  			Version:         version,
  1526  			FirstOccurrence: input.Input.FirstOccurrence,
  1527  		})
  1528  	}
  1529  
  1530  	_, err = psql.Delete("build_pipes").
  1531  		Where(sq.Eq{"to_build_id": b.id}).
  1532  		RunWith(tx).
  1533  		Exec()
  1534  	if err != nil {
  1535  		return nil, false, err
  1536  	}
  1537  
  1538  	_, err = psql.Insert("build_pipes").
  1539  		Columns("from_build_id", "to_build_id").
  1540  		Select(psql.Select("bp.from_build_id").
  1541  			Column("?", b.id).
  1542  			From("build_pipes bp").
  1543  			Where(sq.Eq{"bp.to_build_id": b.rerunOf})).
  1544  		Suffix("ON CONFLICT DO NOTHING").
  1545  		RunWith(tx).
  1546  		Exec()
  1547  	if err != nil {
  1548  		return nil, false, err
  1549  	}
  1550  
  1551  	_, err = psql.Update("builds").
  1552  		Set("inputs_ready", true).
  1553  		Where(sq.Eq{
  1554  			"id": b.id,
  1555  		}).
  1556  		RunWith(tx).
  1557  		Exec()
  1558  	if err != nil {
  1559  		return nil, false, err
  1560  	}
  1561  
  1562  	err = tx.Commit()
  1563  	if err != nil {
  1564  		return nil, false, err
  1565  	}
  1566  
  1567  	return buildInputs, true, nil
  1568  }
  1569  
  1570  func (b *build) Resources() ([]BuildInput, []BuildOutput, error) {
  1571  	inputs := []BuildInput{}
  1572  	outputs := []BuildOutput{}
  1573  
  1574  	tx, err := b.conn.Begin()
  1575  	if err != nil {
  1576  		return nil, nil, err
  1577  	}
  1578  
  1579  	defer Rollback(tx)
  1580  
  1581  	rows, err := psql.Select("inputs.name", "resources.id", "versions.version", `COALESCE(inputs.first_occurrence, NOT EXISTS (
  1582  			SELECT 1
  1583  			FROM build_resource_config_version_inputs i, builds b
  1584  			WHERE versions.version_md5 = i.version_md5
  1585  			AND resources.resource_config_scope_id = versions.resource_config_scope_id
  1586  			AND resources.id = i.resource_id
  1587  			AND b.job_id = builds.job_id
  1588  			AND i.build_id = b.id
  1589  			AND i.build_id < builds.id
  1590  		))`).
  1591  		From("resource_config_versions versions, build_resource_config_version_inputs inputs, builds, resources").
  1592  		Where(sq.Eq{"builds.id": b.id}).
  1593  		Where(sq.Expr("inputs.build_id = builds.id")).
  1594  		Where(sq.Expr("inputs.version_md5 = versions.version_md5")).
  1595  		Where(sq.Expr("resources.resource_config_scope_id = versions.resource_config_scope_id")).
  1596  		Where(sq.Expr("resources.id = inputs.resource_id")).
  1597  		Where(sq.Expr(`NOT EXISTS (
  1598  			SELECT 1
  1599  			FROM build_resource_config_version_outputs outputs
  1600  			WHERE outputs.version_md5 = versions.version_md5
  1601  			AND versions.resource_config_scope_id = resources.resource_config_scope_id
  1602  			AND outputs.resource_id = resources.id
  1603  			AND outputs.build_id = inputs.build_id
  1604  		)`)).
  1605  		RunWith(tx).
  1606  		Query()
  1607  	if err != nil {
  1608  		return nil, nil, err
  1609  	}
  1610  
  1611  	defer Close(rows)
  1612  
  1613  	for rows.Next() {
  1614  		var (
  1615  			inputName   string
  1616  			firstOcc    bool
  1617  			versionBlob string
  1618  			version     atc.Version
  1619  			resourceID  int
  1620  		)
  1621  
  1622  		err = rows.Scan(&inputName, &resourceID, &versionBlob, &firstOcc)
  1623  		if err != nil {
  1624  			return nil, nil, err
  1625  		}
  1626  
  1627  		err = json.Unmarshal([]byte(versionBlob), &version)
  1628  		if err != nil {
  1629  			return nil, nil, err
  1630  		}
  1631  
  1632  		inputs = append(inputs, BuildInput{
  1633  			Name:            inputName,
  1634  			Version:         version,
  1635  			ResourceID:      resourceID,
  1636  			FirstOccurrence: firstOcc,
  1637  		})
  1638  	}
  1639  
  1640  	rows, err = psql.Select("outputs.name", "versions.version").
  1641  		From("resource_config_versions versions, build_resource_config_version_outputs outputs, builds, resources").
  1642  		Where(sq.Eq{"builds.id": b.id}).
  1643  		Where(sq.Expr("outputs.build_id = builds.id")).
  1644  		Where(sq.Expr("outputs.version_md5 = versions.version_md5")).
  1645  		Where(sq.Expr("outputs.resource_id = resources.id")).
  1646  		Where(sq.Expr("resources.resource_config_scope_id = versions.resource_config_scope_id")).
  1647  		RunWith(tx).
  1648  		Query()
  1649  
  1650  	if err != nil {
  1651  		return nil, nil, err
  1652  	}
  1653  
  1654  	defer Close(rows)
  1655  
  1656  	for rows.Next() {
  1657  		var (
  1658  			outputName  string
  1659  			versionBlob string
  1660  			version     atc.Version
  1661  		)
  1662  
  1663  		err := rows.Scan(&outputName, &versionBlob)
  1664  		if err != nil {
  1665  			return nil, nil, err
  1666  		}
  1667  
  1668  		err = json.Unmarshal([]byte(versionBlob), &version)
  1669  		if err != nil {
  1670  			return nil, nil, err
  1671  		}
  1672  
  1673  		outputs = append(outputs, BuildOutput{
  1674  			Name:    outputName,
  1675  			Version: version,
  1676  		})
  1677  	}
  1678  
  1679  	err = tx.Commit()
  1680  	if err != nil {
  1681  		return nil, nil, err
  1682  	}
  1683  
  1684  	return inputs, outputs, nil
  1685  }
  1686  
  1687  func (b *build) SpanContext() propagation.HTTPSupplier {
  1688  	return b.spanContext
  1689  }
  1690  
  1691  func (b *build) SavePipeline(
  1692  	pipelineRef atc.PipelineRef,
  1693  	teamID int,
  1694  	config atc.Config,
  1695  	from ConfigVersion,
  1696  	initiallyPaused bool,
  1697  ) (Pipeline, bool, error) {
  1698  	tx, err := b.conn.Begin()
  1699  	if err != nil {
  1700  		return nil, false, err
  1701  	}
  1702  
  1703  	defer Rollback(tx)
  1704  
  1705  	jobID := newNullInt64(b.jobID)
  1706  	buildID := newNullInt64(b.id)
  1707  	pipelineID, isNewPipeline, err := savePipeline(tx, pipelineRef, config, from, initiallyPaused, teamID, jobID, buildID)
  1708  	if err != nil {
  1709  		return nil, false, err
  1710  	}
  1711  
  1712  	pipeline := newPipeline(b.conn, b.lockFactory)
  1713  	err = scanPipeline(
  1714  		pipeline,
  1715  		pipelinesQuery.
  1716  			Where(sq.Eq{"p.id": pipelineID}).
  1717  			RunWith(tx).
  1718  			QueryRow(),
  1719  	)
  1720  	if err != nil {
  1721  		return nil, false, err
  1722  	}
  1723  
  1724  	err = tx.Commit()
  1725  	if err != nil {
  1726  		return nil, false, err
  1727  	}
  1728  
  1729  	return pipeline, isNewPipeline, nil
  1730  }
  1731  
  1732  func newNullInt64(i int) sql.NullInt64 {
  1733  	return sql.NullInt64{
  1734  		Valid: true,
  1735  		Int64: int64(i),
  1736  	}
  1737  }
  1738  
  1739  func createBuildEventSeq(tx Tx, buildid int) error {
  1740  	_, err := tx.Exec(fmt.Sprintf(`
  1741  		CREATE SEQUENCE %s MINVALUE 0
  1742  	`, buildEventSeq(buildid)))
  1743  	return err
  1744  }
  1745  
  1746  func buildEventSeq(buildid int) string {
  1747  	return fmt.Sprintf("build_event_id_seq_%d", buildid)
  1748  }
  1749  
  1750  func scanBuild(b *build, row scannable, encryptionStrategy encryption.Strategy) error {
  1751  	var (
  1752  		jobID, resourceID, resourceTypeID, pipelineID, rerunOf, rerunNumber                                 sql.NullInt64
  1753  		schema, privatePlan, jobName, resourceName, resourceTypeName, pipelineName, publicPlan, rerunOfName sql.NullString
  1754  		createTime, startTime, endTime, reapTime                                                            pq.NullTime
  1755  		nonce, spanContext                                                                                  sql.NullString
  1756  		drained, aborted, completed                                                                         bool
  1757  		status                                                                                              string
  1758  		pipelineInstanceVars                                                                                sql.NullString
  1759  	)
  1760  
  1761  	err := row.Scan(
  1762  		&b.id,
  1763  		&b.name,
  1764  		&jobID,
  1765  		&resourceID,
  1766  		&resourceTypeID,
  1767  		&b.teamID,
  1768  		&status,
  1769  		&b.isManuallyTriggered,
  1770  		&b.scheduled,
  1771  		&schema,
  1772  		&privatePlan,
  1773  		&publicPlan,
  1774  		&createTime,
  1775  		&startTime,
  1776  		&endTime,
  1777  		&reapTime,
  1778  		&jobName,
  1779  		&resourceName,
  1780  		&resourceTypeName,
  1781  		&pipelineID,
  1782  		&pipelineName,
  1783  		&pipelineInstanceVars,
  1784  		&b.teamName,
  1785  		&nonce,
  1786  		&drained,
  1787  		&aborted,
  1788  		&completed,
  1789  		&b.inputsReady,
  1790  		&rerunOf,
  1791  		&rerunOfName,
  1792  		&rerunNumber,
  1793  		&spanContext,
  1794  	)
  1795  	if err != nil {
  1796  		return err
  1797  	}
  1798  
  1799  	b.status = BuildStatus(status)
  1800  	b.jobID = int(jobID.Int64)
  1801  	b.jobName = jobName.String
  1802  	b.resourceID = int(resourceID.Int64)
  1803  	b.resourceName = resourceName.String
  1804  	b.resourceTypeID = int(resourceTypeID.Int64)
  1805  	b.resourceTypeName = resourceTypeName.String
  1806  	b.pipelineID = int(pipelineID.Int64)
  1807  	b.pipelineName = pipelineName.String
  1808  	b.schema = schema.String
  1809  	b.createTime = createTime.Time
  1810  	b.startTime = startTime.Time
  1811  	b.endTime = endTime.Time
  1812  	b.reapTime = reapTime.Time
  1813  	b.drained = drained
  1814  	b.aborted = aborted
  1815  	b.completed = completed
  1816  	b.rerunOf = int(rerunOf.Int64)
  1817  	b.rerunOfName = rerunOfName.String
  1818  	b.rerunNumber = int(rerunNumber.Int64)
  1819  
  1820  	var (
  1821  		noncense      *string
  1822  		decryptedPlan []byte
  1823  	)
  1824  
  1825  	if nonce.Valid {
  1826  		noncense = &nonce.String
  1827  		decryptedPlan, err = encryptionStrategy.Decrypt(string(privatePlan.String), noncense)
  1828  		if err != nil {
  1829  			return err
  1830  		}
  1831  	} else {
  1832  		decryptedPlan = []byte(privatePlan.String)
  1833  	}
  1834  
  1835  	if len(decryptedPlan) > 0 {
  1836  		err = json.Unmarshal(decryptedPlan, &b.privatePlan)
  1837  		if err != nil {
  1838  			return err
  1839  		}
  1840  	}
  1841  
  1842  	if publicPlan.Valid {
  1843  		err = json.Unmarshal([]byte(publicPlan.String), &b.publicPlan)
  1844  		if err != nil {
  1845  			return err
  1846  		}
  1847  	}
  1848  
  1849  	if spanContext.Valid {
  1850  		err = json.Unmarshal([]byte(spanContext.String), &b.spanContext)
  1851  		if err != nil {
  1852  			return err
  1853  		}
  1854  	}
  1855  
  1856  	if pipelineInstanceVars.Valid {
  1857  		err = json.Unmarshal([]byte(pipelineInstanceVars.String), &b.pipelineInstanceVars)
  1858  		if err != nil {
  1859  			return err
  1860  		}
  1861  	}
  1862  
  1863  	return nil
  1864  }
  1865  
  1866  func (b *build) saveEvent(tx Tx, event atc.Event) error {
  1867  	payload, err := json.Marshal(event)
  1868  	if err != nil {
  1869  		return err
  1870  	}
  1871  
  1872  	_, err = psql.Insert(b.eventsTable()).
  1873  		Columns("event_id", "build_id", "type", "version", "payload").
  1874  		Values(sq.Expr("nextval('"+buildEventSeq(b.id)+"')"), b.id, string(event.EventType()), string(event.Version()), payload).
  1875  		RunWith(tx).
  1876  		Exec()
  1877  	return err
  1878  }
  1879  
  1880  func (b *build) eventsTable() string {
  1881  	if b.pipelineID != 0 {
  1882  		return fmt.Sprintf("pipeline_build_events_%d", b.pipelineID)
  1883  	} else {
  1884  		return fmt.Sprintf("team_build_events_%d", b.teamID)
  1885  	}
  1886  }
  1887  
  1888  func createBuild(tx Tx, build *build, vals map[string]interface{}) error {
  1889  	var buildID int
  1890  
  1891  	buildVals := make(map[string]interface{})
  1892  	for name, value := range vals {
  1893  		buildVals[name] = value
  1894  	}
  1895  
  1896  	buildVals["needs_v6_migration"] = false
  1897  
  1898  	err := psql.Insert("builds").
  1899  		SetMap(buildVals).
  1900  		Suffix("RETURNING id").
  1901  		RunWith(tx).
  1902  		QueryRow().
  1903  		Scan(&buildID)
  1904  	if err != nil {
  1905  		return err
  1906  	}
  1907  
  1908  	err = scanBuild(build, buildsQuery.
  1909  		Where(sq.Eq{"b.id": buildID}).
  1910  		RunWith(tx).
  1911  		QueryRow(),
  1912  		build.conn.EncryptionStrategy(),
  1913  	)
  1914  	if err != nil {
  1915  		return err
  1916  	}
  1917  
  1918  	return createBuildEventSeq(tx, buildID)
  1919  }
  1920  
  1921  func buildStartedChannel() string {
  1922  	return atc.ComponentBuildTracker
  1923  }
  1924  
  1925  func buildEventsChannel(buildID int) string {
  1926  	return fmt.Sprintf("build_events_%d", buildID)
  1927  }
  1928  
  1929  func buildAbortChannel(buildID int) string {
  1930  	return fmt.Sprintf("build_abort_%d", buildID)
  1931  }
  1932  
  1933  func latestCompletedNonRerunBuild(tx Tx, jobID int) (int, error) {
  1934  	var latestNonRerunId int
  1935  	err := latestCompletedBuildQuery.
  1936  		Where(sq.Eq{"job_id": jobID}).
  1937  		Where(sq.Eq{"rerun_of": nil}).
  1938  		RunWith(tx).
  1939  		QueryRow().
  1940  		Scan(&latestNonRerunId)
  1941  	if err != nil && err == sql.ErrNoRows {
  1942  		return 0, nil
  1943  	}
  1944  
  1945  	return latestNonRerunId, nil
  1946  }
  1947  
  1948  func updateNextBuildForJob(tx Tx, jobID int, latestNonRerunId int) error {
  1949  	_, err := tx.Exec(`
  1950  		UPDATE jobs AS j
  1951  		SET next_build_id = (
  1952  			SELECT min(b.id)
  1953  			FROM builds b
  1954  			INNER JOIN jobs j ON j.id = b.job_id
  1955  			WHERE b.job_id = $1
  1956  			AND b.status IN ('pending', 'started')
  1957  			AND (b.rerun_of IS NULL OR b.rerun_of = $2)
  1958  		)
  1959  		WHERE j.id = $1
  1960  	`, jobID, latestNonRerunId)
  1961  	if err != nil {
  1962  		return err
  1963  	}
  1964  	return nil
  1965  }
  1966  
  1967  func updateLatestCompletedBuildForJob(tx Tx, jobID int, latestNonRerunId int) error {
  1968  	var latestRerunId sql.NullString
  1969  	err := latestCompletedBuildQuery.
  1970  		Where(sq.Eq{"job_id": jobID}).
  1971  		Where(sq.Eq{"rerun_of": latestNonRerunId}).
  1972  		RunWith(tx).
  1973  		QueryRow().
  1974  		Scan(&latestRerunId)
  1975  	if err != nil {
  1976  		return err
  1977  	}
  1978  
  1979  	var id int
  1980  	if latestRerunId.Valid {
  1981  		id, err = strconv.Atoi(latestRerunId.String)
  1982  		if err != nil {
  1983  			return err
  1984  		}
  1985  	} else {
  1986  		id = latestNonRerunId
  1987  	}
  1988  
  1989  	_, err = tx.Exec(`
  1990  		UPDATE jobs AS j
  1991  		SET latest_completed_build_id = $1
  1992  		WHERE j.id = $2
  1993  	`, id, jobID)
  1994  	if err != nil {
  1995  		return err
  1996  	}
  1997  
  1998  	return nil
  1999  }
  2000  
  2001  func updateTransitionBuildForJob(tx Tx, jobID int, buildID int, buildStatus BuildStatus, rerunID int) error {
  2002  	var shouldUpdateTransition bool
  2003  
  2004  	var latestID int
  2005  	var latestStatus BuildStatus
  2006  	err := psql.Select("b.id", "b.status").
  2007  		From("builds b").
  2008  		JoinClause("INNER JOIN jobs j ON j.latest_completed_build_id = b.id").
  2009  		Where(sq.Eq{"j.id": jobID}).
  2010  		RunWith(tx).
  2011  		QueryRow().
  2012  		Scan(&latestID, &latestStatus)
  2013  	if err != nil {
  2014  		if err == sql.ErrNoRows {
  2015  			// this is the first completed build; initiate transition
  2016  			shouldUpdateTransition = true
  2017  		} else {
  2018  			return err
  2019  		}
  2020  	}
  2021  
  2022  	if buildID < latestID {
  2023  		// latest completed build is actually after this one, so this build
  2024  		// has no influence on the job's overall state
  2025  		//
  2026  		// this can happen when multiple builds are running at a time and the
  2027  		// later-queued ones finish earlier
  2028  		return nil
  2029  	}
  2030  
  2031  	if latestStatus != buildStatus && (isNotRerunBuild(rerunID) || rerunID == latestID) {
  2032  		// status has changed; transitioned!
  2033  		shouldUpdateTransition = true
  2034  	}
  2035  
  2036  	if shouldUpdateTransition {
  2037  		_, err := psql.Update("jobs").
  2038  			Set("transition_build_id", buildID).
  2039  			Where(sq.Eq{"id": jobID}).
  2040  			RunWith(tx).
  2041  			Exec()
  2042  		if err != nil {
  2043  			return err
  2044  		}
  2045  	}
  2046  
  2047  	return nil
  2048  }
  2049  
  2050  func isNotRerunBuild(rerunID int) bool {
  2051  	return rerunID == 0
  2052  }