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

     1  package db
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	sq "github.com/Masterminds/squirrel"
     8  	"github.com/pf-qiu/concourse/v6/atc"
     9  )
    10  
    11  var ErrContainerDisappeared = errors.New("container disappeared from db")
    12  
    13  type ContainerState string
    14  
    15  //go:generate counterfeiter . Container
    16  
    17  type Container interface {
    18  	ID() int
    19  	State() string
    20  	Handle() string
    21  	WorkerName() string
    22  	Metadata() ContainerMetadata
    23  }
    24  
    25  //go:generate counterfeiter . CreatingContainer
    26  
    27  type CreatingContainer interface {
    28  	Container
    29  
    30  	Created() (CreatedContainer, error)
    31  	Failed() (FailedContainer, error)
    32  }
    33  
    34  type creatingContainer struct {
    35  	id         int
    36  	handle     string
    37  	workerName string
    38  	metadata   ContainerMetadata
    39  	conn       Conn
    40  }
    41  
    42  func newCreatingContainer(
    43  	id int,
    44  	handle string,
    45  	workerName string,
    46  	metadata ContainerMetadata,
    47  	conn Conn,
    48  ) *creatingContainer {
    49  	return &creatingContainer{
    50  		id:         id,
    51  		handle:     handle,
    52  		workerName: workerName,
    53  		metadata:   metadata,
    54  		conn:       conn,
    55  	}
    56  }
    57  
    58  func (container *creatingContainer) ID() int                     { return container.id }
    59  func (container *creatingContainer) State() string               { return atc.ContainerStateCreating }
    60  func (container *creatingContainer) Handle() string              { return container.handle }
    61  func (container *creatingContainer) WorkerName() string          { return container.workerName }
    62  func (container *creatingContainer) Metadata() ContainerMetadata { return container.metadata }
    63  
    64  func (container *creatingContainer) Created() (CreatedContainer, error) {
    65  	rows, err := psql.Update("containers").
    66  		Set("state", atc.ContainerStateCreated).
    67  		Where(sq.And{
    68  			sq.Eq{"id": container.id},
    69  			sq.Or{
    70  				sq.Eq{"state": string(atc.ContainerStateCreating)},
    71  				sq.Eq{"state": string(atc.ContainerStateCreated)},
    72  			},
    73  		}).
    74  		RunWith(container.conn).
    75  		Exec()
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	affected, err := rows.RowsAffected()
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	if affected == 0 {
    86  		return nil, ErrContainerDisappeared
    87  	}
    88  
    89  	return newCreatedContainer(
    90  		container.id,
    91  		container.handle,
    92  		container.workerName,
    93  		container.metadata,
    94  		time.Time{},
    95  		container.conn,
    96  	), nil
    97  }
    98  
    99  func (container *creatingContainer) Failed() (FailedContainer, error) {
   100  	rows, err := psql.Update("containers").
   101  		Set("state", atc.ContainerStateFailed).
   102  		Where(sq.And{
   103  			sq.Eq{"id": container.id},
   104  			sq.Or{
   105  				sq.Eq{"state": string(atc.ContainerStateCreating)},
   106  				sq.Eq{"state": string(atc.ContainerStateFailed)},
   107  			},
   108  		}).
   109  		RunWith(container.conn).
   110  		Exec()
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	affected, err := rows.RowsAffected()
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	if affected == 0 {
   121  		return nil, ErrContainerDisappeared
   122  	}
   123  
   124  	return newFailedContainer(
   125  		container.id,
   126  		container.handle,
   127  		container.workerName,
   128  		container.metadata,
   129  		container.conn,
   130  	), nil
   131  }
   132  
   133  //go:generate counterfeiter . CreatedContainer
   134  
   135  type CreatedContainer interface {
   136  	Container
   137  
   138  	Destroying() (DestroyingContainer, error)
   139  	LastHijack() time.Time
   140  	UpdateLastHijack() error
   141  }
   142  
   143  type createdContainer struct {
   144  	id         int
   145  	handle     string
   146  	workerName string
   147  	metadata   ContainerMetadata
   148  
   149  	lastHijack time.Time
   150  
   151  	conn Conn
   152  }
   153  
   154  func newCreatedContainer(
   155  	id int,
   156  	handle string,
   157  	workerName string,
   158  	metadata ContainerMetadata,
   159  	lastHijack time.Time,
   160  	conn Conn,
   161  ) *createdContainer {
   162  	return &createdContainer{
   163  		id:         id,
   164  		handle:     handle,
   165  		workerName: workerName,
   166  		metadata:   metadata,
   167  		lastHijack: lastHijack,
   168  		conn:       conn,
   169  	}
   170  }
   171  
   172  func (container *createdContainer) ID() int                     { return container.id }
   173  func (container *createdContainer) State() string               { return atc.ContainerStateCreated }
   174  func (container *createdContainer) Handle() string              { return container.handle }
   175  func (container *createdContainer) WorkerName() string          { return container.workerName }
   176  func (container *createdContainer) Metadata() ContainerMetadata { return container.metadata }
   177  
   178  func (container *createdContainer) LastHijack() time.Time { return container.lastHijack }
   179  
   180  func (container *createdContainer) Destroying() (DestroyingContainer, error) {
   181  
   182  	rows, err := psql.Update("containers").
   183  		Set("state", atc.ContainerStateDestroying).
   184  		Where(sq.And{
   185  			sq.Eq{"id": container.id},
   186  			sq.Or{
   187  				sq.Eq{"state": string(atc.ContainerStateDestroying)},
   188  				sq.Eq{"state": string(atc.ContainerStateCreated)},
   189  			},
   190  		}).
   191  		RunWith(container.conn).
   192  		Exec()
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	affected, err := rows.RowsAffected()
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	if affected == 0 {
   203  		return nil, ErrContainerDisappeared
   204  	}
   205  
   206  	return newDestroyingContainer(
   207  		container.id,
   208  		container.handle,
   209  		container.workerName,
   210  		container.metadata,
   211  		container.conn,
   212  	), nil
   213  }
   214  
   215  func (container *createdContainer) UpdateLastHijack() error {
   216  
   217  	rows, err := psql.Update("containers").
   218  		Set("last_hijack", sq.Expr("now()")).
   219  		Where(sq.Eq{
   220  			"id":    container.id,
   221  			"state": atc.ContainerStateCreated,
   222  		}).
   223  		RunWith(container.conn).
   224  		Exec()
   225  	if err != nil {
   226  		return err
   227  	}
   228  
   229  	affected, err := rows.RowsAffected()
   230  	if err != nil {
   231  		return err
   232  	}
   233  
   234  	if affected == 0 {
   235  		return ErrContainerDisappeared
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  //go:generate counterfeiter . DestroyingContainer
   242  
   243  type DestroyingContainer interface {
   244  	Container
   245  
   246  	Destroy() (bool, error)
   247  }
   248  
   249  type destroyingContainer struct {
   250  	id         int
   251  	handle     string
   252  	workerName string
   253  	metadata   ContainerMetadata
   254  
   255  	conn Conn
   256  }
   257  
   258  func newDestroyingContainer(
   259  	id int,
   260  	handle string,
   261  	workerName string,
   262  	metadata ContainerMetadata,
   263  	conn Conn,
   264  ) *destroyingContainer {
   265  	return &destroyingContainer{
   266  		id:         id,
   267  		handle:     handle,
   268  		workerName: workerName,
   269  		metadata:   metadata,
   270  		conn:       conn,
   271  	}
   272  }
   273  
   274  func (container *destroyingContainer) ID() int                     { return container.id }
   275  func (container *destroyingContainer) State() string               { return atc.ContainerStateDestroying }
   276  func (container *destroyingContainer) Handle() string              { return container.handle }
   277  func (container *destroyingContainer) WorkerName() string          { return container.workerName }
   278  func (container *destroyingContainer) Metadata() ContainerMetadata { return container.metadata }
   279  
   280  func (container *destroyingContainer) Destroy() (bool, error) {
   281  	rows, err := psql.Delete("containers").
   282  		Where(sq.Eq{
   283  			"id":    container.id,
   284  			"state": atc.ContainerStateDestroying,
   285  		}).
   286  		RunWith(container.conn).
   287  		Exec()
   288  	if err != nil {
   289  		return false, err
   290  	}
   291  
   292  	affected, err := rows.RowsAffected()
   293  	if err != nil {
   294  		return false, err
   295  	}
   296  
   297  	if affected == 0 {
   298  		return false, ErrContainerDisappeared
   299  	}
   300  
   301  	return true, nil
   302  }
   303  
   304  //go:generate counterfeiter . FailedContainer
   305  
   306  type FailedContainer interface {
   307  	Container
   308  
   309  	Destroy() (bool, error)
   310  }
   311  
   312  type failedContainer struct {
   313  	id         int
   314  	handle     string
   315  	workerName string
   316  	metadata   ContainerMetadata
   317  	conn       Conn
   318  }
   319  
   320  func newFailedContainer(
   321  	id int,
   322  	handle string,
   323  	workerName string,
   324  	metadata ContainerMetadata,
   325  	conn Conn,
   326  ) *failedContainer {
   327  	return &failedContainer{
   328  		id:         id,
   329  		handle:     handle,
   330  		workerName: workerName,
   331  		metadata:   metadata,
   332  		conn:       conn,
   333  	}
   334  }
   335  
   336  func (container *failedContainer) ID() int                     { return container.id }
   337  func (container *failedContainer) State() string               { return atc.ContainerStateFailed }
   338  func (container *failedContainer) Handle() string              { return container.handle }
   339  func (container *failedContainer) WorkerName() string          { return container.workerName }
   340  func (container *failedContainer) Metadata() ContainerMetadata { return container.metadata }
   341  
   342  func (container *failedContainer) Destroy() (bool, error) {
   343  	rows, err := psql.Delete("containers").
   344  		Where(sq.Eq{
   345  			"id":    container.id,
   346  			"state": atc.ContainerStateFailed,
   347  		}).
   348  		RunWith(container.conn).
   349  		Exec()
   350  	if err != nil {
   351  		return false, err
   352  	}
   353  
   354  	affected, err := rows.RowsAffected()
   355  	if err != nil {
   356  		return false, err
   357  	}
   358  
   359  	if affected == 0 {
   360  		return false, ErrContainerDisappeared
   361  	}
   362  
   363  	return true, nil
   364  }