diff --git a/server/artifacts/artifact_server.go b/server/artifacts/artifact_server.go index 6c46fbf8c280..70ab05683768 100644 --- a/server/artifacts/artifact_server.go +++ b/server/artifacts/artifact_server.go @@ -40,6 +40,13 @@ type ArtifactServer struct { artifactRepositories artifactrepositories.Interface } +type Direction string + +const ( + Outputs Direction = "outputs" + Inputs Direction = "inputs" +) + func NewArtifactServer(authN auth.Gatekeeper, hydrator hydrator.Interface, wfArchive sqldb.WorkflowArchive, instanceIDService instanceid.Service, artifactRepositories artifactrepositories.Interface) *ArtifactServer { return newArtifactServer(authN, hydrator, wfArchive, instanceIDService, artifact.NewDriver, artifactRepositories) } @@ -59,9 +66,9 @@ func (a *ArtifactServer) GetInputArtifact(w http.ResponseWriter, r *http.Request // single endpoint to be able to handle serving directories as well as files, both those that have been archived and those that haven't // Valid requests: // -// /artifact-files/{namespace}/[archived-workflows|workflows]/{id}/{nodeId}/outputs/{artifactName} -// /artifact-files/{namespace}/[archived-workflows|workflows]/{id}/{nodeId}/outputs/{artifactName}/{fileName} -// /artifact-files/{namespace}/[archived-workflows|workflows]/{id}/{nodeId}/outputs/{artifactName}/{fileDir}/.../{fileName} +// /artifact-files/{namespace}/[archived-workflows|workflows]/{id}/{nodeId}/[inputs|outputs]/{artifactName} +// /artifact-files/{namespace}/[archived-workflows|workflows]/{id}/{nodeId}/[inputs|outputs]/{artifactName}/{fileName} +// /artifact-files/{namespace}/[archived-workflows|workflows]/{id}/{nodeId}/[inputs|outputs]/{artifactName}/{fileDir}/.../{fileName} // // 'id' field represents 'uid' for archived workflows and 'name' for non-archived func (a *ArtifactServer) GetArtifactFile(w http.ResponseWriter, r *http.Request) { @@ -92,10 +99,10 @@ func (a *ArtifactServer) GetArtifactFile(w http.ResponseWriter, r *http.Request) archiveDiscriminator := requestPath[archiveDiscrimIndex] id := requestPath[idIndex] // if archiveDiscriminator == "archived-workflows", this represents workflow UID; if archiveDiscriminator == "workflows", this represents workflow name nodeId := requestPath[nodeIdIndex] - direction := requestPath[directionIndex] + direction := Direction(requestPath[directionIndex]) artifactName := requestPath[artifactNameIndex] - if direction != "outputs" { // for now we just handle output artifacts + if direction != Outputs && direction != Inputs { // for now we handle output and input artifacts a.httpBadRequestError(w) return } @@ -147,7 +154,12 @@ func (a *ArtifactServer) GetArtifactFile(w http.ResponseWriter, r *http.Request) return } - artifact, driver, err := a.getArtifactAndDriver(ctx, nodeId, artifactName, false, wf, fileName) + isInput := false + if direction == Inputs { + isInput = true + } + + artifact, driver, err := a.getArtifactAndDriver(ctx, nodeId, artifactName, isInput, wf, fileName) if err != nil { a.serverInternalError(err, w) return diff --git a/server/artifacts/artifact_server_test.go b/server/artifacts/artifact_server_test.go index 5f194ef080b0..34d698e31dc9 100644 --- a/server/artifacts/artifact_server_test.go +++ b/server/artifacts/artifact_server_test.go @@ -191,6 +191,14 @@ func newServer() *ArtifactServer { }, }, }, + { + Name: "my-s3-artifact-directory", + ArtifactLocation: wfv1.ArtifactLocation{ + S3: &wfv1.S3Artifact{ + Key: "my-wf/my-node-1/my-s3-artifact-directory", + }, + }, + }, }, }, Outputs: &wfv1.Outputs{ @@ -397,6 +405,21 @@ func TestArtifactServer_GetArtifactFile(t *testing.T) { "c.txt", }, }, + { + path: "/artifact-files/my-ns/workflows/my-wf/my-node-1/inputs/my-s3-input-artifact", + statusCode: 200, + isDirectory: false, + }, + { + path: "/artifact-files/my-ns/workflows/my-wf/my-node-1/inputs/my-s3-artifact-directory/subdirectory/", + statusCode: 200, + isDirectory: true, + directoryFiles: []string{ + "..", + "b.txt", + "c.txt", + }, + }, { path: "/artifact-files/my-ns/workflows/my-wf/my-node-1/outputs/my-s3-artifact-directory/a.txt", statusCode: 200, diff --git a/ui/src/app/shared/services/workflow-service.test.ts b/ui/src/app/shared/services/workflow-service.test.ts index f7c983698055..59730746bc93 100644 --- a/ui/src/app/shared/services/workflow-service.test.ts +++ b/ui/src/app/shared/services/workflow-service.test.ts @@ -34,10 +34,10 @@ describe('workflow service', () => { '/artifact-files/argo/archived-workflows/test-uid/test-node/outputs/test-artifact' ); expect(service.getArtifactDownloadUrl(workflow('hello-world', 'argo', 'test-uid'), 'test-node', 'test-artifact', false, true)).toBe( - '/input-artifacts/argo/hello-world/test-node/test-artifact' + '/artifact-files/argo/workflows/hello-world/test-node/inputs/test-artifact' ); expect(service.getArtifactDownloadUrl(workflow('hello-world', 'argo', 'test-uid'), 'test-node', 'test-artifact', true, true)).toBe( - '/input-artifacts-by-uid/test-uid/test-node/test-artifact' + '/artifact-files/argo/archived-workflows/test-uid/test-node/inputs/test-artifact' ); }); }); diff --git a/ui/src/app/shared/services/workflows-service.ts b/ui/src/app/shared/services/workflows-service.ts index cdd78acfd095..dad50bf729b8 100644 --- a/ui/src/app/shared/services/workflows-service.ts +++ b/ui/src/app/shared/services/workflows-service.ts @@ -280,14 +280,8 @@ export const WorkflowsService = { }, artifactPath(workflow: Workflow, nodeId: string, artifactName: string, archived: boolean, isInput: boolean) { - if (!isInput) { - return `artifact-files/${workflow.metadata.namespace}/${archived ? 'archived-workflows' : 'workflows'}/${ - archived ? workflow.metadata.uid : workflow.metadata.name - }/${nodeId}/outputs/${artifactName}`; - } else if (archived) { - return `input-artifacts-by-uid/${workflow.metadata.uid}/${nodeId}/${encodeURIComponent(artifactName)}`; - } else { - return `input-artifacts/${workflow.metadata.namespace}/${workflow.metadata.name}/${nodeId}/${encodeURIComponent(artifactName)}`; - } + return `artifact-files/${workflow.metadata.namespace}/${archived ? 'archived-workflows' : 'workflows'}/${ + archived ? workflow.metadata.uid : workflow.metadata.name + }/${nodeId}/${isInput ? 'inputs' : 'outputs'}/${artifactName}`; } };