github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/api/artifactserver/create.go (about)

     1  package artifactserver
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  
     7  	"github.com/concourse/baggageclaim"
     8  	"github.com/pf-qiu/concourse/v6/atc/api/present"
     9  	"github.com/pf-qiu/concourse/v6/atc/db"
    10  	"github.com/pf-qiu/concourse/v6/atc/worker"
    11  )
    12  
    13  func (s *Server) CreateArtifact(team db.Team) http.Handler {
    14  	hLog := s.logger.Session("create-artifact")
    15  
    16  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    17  		w.Header().Set("Content-Type", "application/json")
    18  
    19  		// TODO: can probably check if fly sent us an etag header
    20  		// which we can lookup in the checksum field
    21  		// that way we don't have to create another volume.
    22  
    23  		workerSpec := worker.WorkerSpec{
    24  			TeamID:   team.ID(),
    25  			Platform: r.FormValue("platform"),
    26  			Tags:     r.Form["tags"],
    27  		}
    28  
    29  		volumeSpec := worker.VolumeSpec{
    30  			Strategy: baggageclaim.EmptyStrategy{},
    31  		}
    32  
    33  		volume, err := s.workerClient.CreateVolume(hLog, volumeSpec, workerSpec, db.VolumeTypeArtifact)
    34  		if err != nil {
    35  			hLog.Error("failed-to-create-volume", err)
    36  			w.WriteHeader(http.StatusInternalServerError)
    37  			return
    38  		}
    39  
    40  		// NOTE: there's a race condition here between when the
    41  		// volume gets created and when the artifact gets initialized
    42  
    43  		// Within this timeframe there's a chance that the volume could
    44  		// get garbage collected out from under us.
    45  
    46  		// This happens because CreateVolume returns a 'created' instead
    47  		// of 'creating' volume.
    48  
    49  		// In the long run CreateVolume should probably return a 'creating'
    50  		// volume, but there are other changes needed in FindOrCreateContainer
    51  		// with the way we create volumes for a container
    52  
    53  		// I think leaving the race condition is fine for now. Worst case
    54  		// is a fly execute will fail and the user will need to rerun it.
    55  
    56  		artifact, err := volume.InitializeArtifact("", 0)
    57  		if err != nil {
    58  			hLog.Error("failed-to-initialize-artifact", err)
    59  			w.WriteHeader(http.StatusInternalServerError)
    60  			return
    61  		}
    62  
    63  		err = volume.StreamIn(r.Context(), "/", baggageclaim.GzipEncoding, r.Body)
    64  		if err != nil {
    65  			hLog.Error("failed-to-stream-volume-contents", err)
    66  			w.WriteHeader(http.StatusInternalServerError)
    67  			return
    68  		}
    69  
    70  		w.WriteHeader(http.StatusCreated)
    71  
    72  		json.NewEncoder(w).Encode(present.WorkerArtifact(artifact))
    73  	})
    74  }