func bindArtifact(ctx context.Context, r render.Render, gc *gin.Context, db database.Database) *model.Artifact { bucketId := gc.Param("bucket_id") artifactName := gc.Param("artifact_name") artifact, err := db.GetArtifactByName(bucketId, artifactName) if err != nil && err.EntityNotFound() { api.LogAndRespondWithErrorf(ctx, r, http.StatusNotFound, "Artifact not found") gc.Abort() return nil } if err != nil { api.LogAndRespondWithError(ctx, r, http.StatusInternalServerError, err) gc.Abort() return nil } if artifact == nil { api.LogAndRespondWithErrorf(ctx, r, http.StatusBadRequest, "Got nil artifact without error for artifact: %s/%s", bucketId, artifactName) gc.Abort() return nil } gc.Set("artifact", artifact) return artifact }
// Returns nil on error. // // TODO return errors on error func GetArtifact(bucket *model.Bucket, artifact_name string, db database.Database) *model.Artifact { if bucket == nil { return nil } if artifact, err := db.GetArtifactByName(bucket.Id, artifact_name); err != nil { return nil } else { return artifact } }
func CreateArtifact(req CreateArtifactReq, bucket *model.Bucket, db database.Database) (*model.Artifact, error) { if len(req.Name) == 0 { return nil, fmt.Errorf("Artifact Name not provided, state = %s", bucket.State) } if bucket.State != model.OPEN { return nil, fmt.Errorf("Bucket is already closed") } artifact, err := db.GetArtifactByName(bucket.Id, req.Name) if err == nil { return nil, fmt.Errorf("Artifact already exists") } artifact = new(model.Artifact) artifact.Name = req.Name artifact.BucketId = bucket.Id artifact.DateCreated = time.Now() if req.DeadlineMins == 0 { artifact.DeadlineMins = DEFAULT_DEADLINE } else { artifact.DeadlineMins = req.DeadlineMins } if req.Chunked { artifact.State = model.APPENDING } else { if req.Size == 0 { return nil, fmt.Errorf("Cannot create a new upload artifact without size.") } artifact.Size = req.Size artifact.State = model.WAITING_FOR_UPLOAD } artifact.Name = req.Name if err := db.InsertArtifact(artifact); err != nil { return nil, fmt.Errorf("Error inserting artifact %s", err) } return artifact, nil }
// CreateArtifact creates a new artifact in a open bucket. // // If an artifact with the same name already exists in the same bucket, we attempt to rename the // artifact by adding a suffix. // If the request specifies a chunked artifact, the size field is ignored and always set to zero. // If the request is for a streamed artifact, size is mandatory. // A relative path field may be specified to preserve the original file name and path. If no path is // specified, the original artifact name is used by default. func CreateArtifact(req createArtifactReq, bucket *model.Bucket, db database.Database) (*model.Artifact, *HttpError) { if len(req.Name) == 0 { return nil, NewHttpError(http.StatusBadRequest, "Artifact name not provided") } if bucket.State != model.OPEN { return nil, NewHttpError(http.StatusBadRequest, "Bucket is already closed") } artifact := new(model.Artifact) artifact.Name = req.Name artifact.BucketId = bucket.Id artifact.DateCreated = time.Now() if req.DeadlineMins == 0 { artifact.DeadlineMins = DEFAULT_DEADLINE } else { artifact.DeadlineMins = req.DeadlineMins } if req.Chunked { artifact.State = model.APPENDING } else { if req.Size == 0 { return nil, NewHttpError(http.StatusBadRequest, "Cannot create a new upload artifact without size.") } else if req.Size > MaxArtifactSizeBytes { return nil, NewHttpError(http.StatusRequestEntityTooLarge, fmt.Sprintf("Entity '%s' (size %d) is too large (limit %d)", req.Name, req.Size, MaxArtifactSizeBytes)) } artifact.Size = req.Size artifact.State = model.WAITING_FOR_UPLOAD } if req.RelativePath == "" { // Use artifact name provided as default relativePath artifact.RelativePath = req.Name } else { artifact.RelativePath = req.RelativePath } // Attempt to insert artifact and retry with a different name if it fails. if err := db.InsertArtifact(artifact); err != nil { for attempt := 1; attempt <= MaxDuplicateFileNameResolutionAttempts; attempt++ { // Unable to create new artifact - if an artifact already exists, the above insert failed // because of a collision. if _, err := db.GetArtifactByName(bucket.Id, artifact.Name); err != nil { // This could be a transient DB error (down/unreachable), in which case we expect the client // to retry. There is no value in attempting alternate artifact names. // // We have no means of verifying there was a name collision - bail with an internal error. return nil, NewHttpError(http.StatusInternalServerError, err.Error()) } // File name collision - attempt to resolve artifact.Name = fmt.Sprintf(DuplicateArtifactNameFormat, req.Name, randString(5)) if err := db.InsertArtifact(artifact); err == nil { return artifact, nil } } return nil, NewHttpError(http.StatusInternalServerError, "Exceeded retry limit avoiding duplicates") } return artifact, nil }