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

     1  package gc
     2  
     3  import (
     4  	"errors"
     5  
     6  	"code.cloudfoundry.org/lager"
     7  	"github.com/pf-qiu/concourse/v6/atc/db"
     8  	"github.com/pf-qiu/concourse/v6/atc/metric"
     9  )
    10  
    11  //go:generate counterfeiter . Destroyer
    12  
    13  // TODO : consider making this just a struct with methods on it,
    14  // we don't ever use the FakeDestroyer, so we don't even need the
    15  // interface boundaries for testing
    16  
    17  // Destroyer allows removal of containers and volumes from the database
    18  type Destroyer interface {
    19  	FindDestroyingVolumesForGc(workerName string) ([]string, error)
    20  	DestroyContainers(workerName string, handles []string) error
    21  	DestroyVolumes(workerName string, handles []string) error
    22  }
    23  
    24  type destroyer struct {
    25  	logger              lager.Logger
    26  	containerRepository db.ContainerRepository
    27  	volumeRepository    db.VolumeRepository
    28  }
    29  
    30  // NewDestroyer provides a constructor for a Destroyer interface implementation
    31  func NewDestroyer(
    32  	logger lager.Logger,
    33  	containerRepository db.ContainerRepository,
    34  	volumeRepository db.VolumeRepository,
    35  ) Destroyer {
    36  	return &destroyer{
    37  		logger:              logger,
    38  		containerRepository: containerRepository,
    39  		volumeRepository:    volumeRepository,
    40  	}
    41  }
    42  
    43  func (d *destroyer) DestroyContainers(workerName string, currentHandles []string) error {
    44  	if workerName == "" {
    45  		err := errors.New("worker-name-must-be-provided")
    46  		d.logger.Error("failed-to-destroy-containers", err)
    47  
    48  		return err
    49  	}
    50  
    51  	if currentHandles == nil {
    52  		return nil
    53  	}
    54  
    55  	deleted, err := d.containerRepository.RemoveDestroyingContainers(workerName, currentHandles)
    56  	if err != nil {
    57  		d.logger.Error("failed-to-destroy-containers", err)
    58  		return err
    59  	}
    60  
    61  	metric.Metrics.ContainersDeleted.IncDelta(deleted)
    62  	return nil
    63  }
    64  
    65  func (d *destroyer) DestroyVolumes(workerName string, currentHandles []string) error {
    66  	if workerName == "" {
    67  		err := errors.New("worker-name-must-be-provided")
    68  		d.logger.Error("failed-to-destroy-volumes", err)
    69  
    70  		return err
    71  	}
    72  
    73  	if currentHandles == nil {
    74  		return nil
    75  	}
    76  
    77  	deleted, err := d.volumeRepository.RemoveDestroyingVolumes(workerName, currentHandles)
    78  	if err != nil {
    79  		d.logger.Error("failed-to-destroy-volumes", err)
    80  		return err
    81  	}
    82  
    83  	metric.Metrics.VolumesDeleted.IncDelta(deleted)
    84  	return nil
    85  }
    86  
    87  // TODO : Remove this and call GetDestroyingVolumes directly on the volumeRepository
    88  // feels odd to have a "Find*" on an interface named "Destroyer"
    89  func (d *destroyer) FindDestroyingVolumesForGc(workerName string) ([]string, error) {
    90  	destroyingVolumesHandles, err := d.volumeRepository.GetDestroyingVolumes(workerName)
    91  	if err != nil {
    92  		d.logger.Error("failed-to-get-orphaned-volumes", err)
    93  		return nil, err
    94  	}
    95  
    96  	if len(destroyingVolumesHandles) > 0 {
    97  		d.logger.Debug("found-orphaned-volumes", lager.Data{
    98  			"destroying": len(destroyingVolumesHandles),
    99  		})
   100  	}
   101  
   102  	metric.DestroyingVolumesToBeGarbageCollected{
   103  		Volumes: len(destroyingVolumesHandles),
   104  	}.Emit(d.logger)
   105  
   106  	return destroyingVolumesHandles, nil
   107  }