diff --git a/graph-proxy/src/graphql/workflows.rs b/graph-proxy/src/graphql/workflows.rs index 2be9c7372..7b6e851e6 100644 --- a/graph-proxy/src/graphql/workflows.rs +++ b/graph-proxy/src/graphql/workflows.rs @@ -465,7 +465,7 @@ mod tests { let mut server = mockito::Server::new_async().await; let mut response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - response_file_path.push("test-resources"); + response_file_path.push("test-assets"); response_file_path.push("get-workflow-wdkwj.json"); let workflow_endpoint = server .mock( @@ -515,7 +515,7 @@ mod tests { let mut server = mockito::Server::new_async().await; let mut response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - response_file_path.push("test-resources"); + response_file_path.push("test-assets"); response_file_path.push("get-workflow-wdkwj.json"); let workflow_endpoint = server .mock( @@ -568,6 +568,248 @@ mod tests { assert_eq!(resp.data.into_json().unwrap(), expected_data); } + #[tokio::test] + async fn single_failed_workflow_query() { + let workflow_name = "numpy-benchmark-qhb59"; + let visit = Visit { + proposal_code: "mg".to_string(), + proposal_number: 36964, + number: 1, + }; + + let mut server = mockito::Server::new_async().await; + let mut response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + response_file_path.push("test-assets"); + response_file_path.push("get-workflow-qhb59-failed.json"); + let workflow_endpoint = server + .mock( + "GET", + &format!("/api/v1/workflows/{}/{}", visit, workflow_name)[..], + ) + .with_status(200) + .with_header("content-type", "application/json") + .with_body_from_file(response_file_path) + .create_async() + .await; + + let argo_server_url = Url::parse(&server.url()).unwrap(); + let schema = root_schema_builder() + .data(ArgoServerUrl(argo_server_url)) + .data(None::>) + .finish(); + let query = format!( + r#" + query {{ + workflow(name: "{}", visit: {{proposalCode: "{}", proposalNumber: {}, number: {}}}) {{ + status {{ + ...on WorkflowFailedStatus {{ + startTime + endTime + message + tasks {{ + id + }} + }} + }} + }} + }} + "#, + workflow_name, visit.proposal_code, visit.proposal_number, visit.number + ); + let resp = schema.execute(query).await.into_result().unwrap(); + + workflow_endpoint.assert_async().await; + let expected_data = json!({ + "workflow": { + "status": { + "startTime": "2024-10-02T11:11:17+00:00", + "endTime": "2024-10-02T11:12:32+00:00", + "message": "OOMKilled (exit code 137)", + "tasks": [{"id": workflow_name}] + } + } + }); + assert_eq!(resp.data.into_json().unwrap(), expected_data); + } + + #[tokio::test] + async fn single_errored_workflow_query() { + let workflow_name = "numpy-benchmark-jwcfp"; + let visit = Visit { + proposal_code: "mg".to_string(), + proposal_number: 36964, + number: 1, + }; + + let mut server = mockito::Server::new_async().await; + let mut response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + response_file_path.push("test-assets"); + response_file_path.push("get-workflow-jwcfp-errored.json"); + let workflow_endpoint = server + .mock( + "GET", + &format!("/api/v1/workflows/{}/{}", visit, workflow_name)[..], + ) + .with_status(200) + .with_header("content-type", "application/json") + .with_body_from_file(response_file_path) + .create_async() + .await; + + let argo_server_url = Url::parse(&server.url()).unwrap(); + let schema = root_schema_builder() + .data(ArgoServerUrl(argo_server_url)) + .data(None::>) + .finish(); + let query = format!( + r#" + query {{ + workflow(name: "{}", visit: {{proposalCode: "{}", proposalNumber: {}, number: {}}}) {{ + status {{ + ...on WorkflowErroredStatus {{ + startTime + endTime + message + tasks {{ + id + }} + }} + }} + }} + }} + "#, + workflow_name, visit.proposal_code, visit.proposal_number, visit.number + ); + let resp = schema.execute(query).await.into_result().unwrap(); + + workflow_endpoint.assert_async().await; + let expected_data = json!({ + "workflow": { + "status": { + "startTime": "2024-10-11T14:35:37+00:00", + "endTime": "2024-10-11T14:35:37+00:00", + "message": "error in entry template execution: Error applying PodSpecPatch", + "tasks": [{"id": workflow_name}] + } + } + }); + assert_eq!(resp.data.into_json().unwrap(), expected_data); + } + + #[tokio::test] + async fn single_running_workflow_query() { + let workflow_name = "numpy-benchmark-kc7pf"; + let visit = Visit { + proposal_code: "mg".to_string(), + proposal_number: 36964, + number: 1, + }; + + let mut server = mockito::Server::new_async().await; + let mut response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + response_file_path.push("test-assets"); + response_file_path.push("get-workflow-kc7pf-running.json"); + let workflow_endpoint = server + .mock( + "GET", + &format!("/api/v1/workflows/{}/{}", visit, workflow_name)[..], + ) + .with_status(200) + .with_header("content-type", "application/json") + .with_body_from_file(response_file_path) + .create_async() + .await; + + let argo_server_url = Url::parse(&server.url()).unwrap(); + let schema = root_schema_builder() + .data(ArgoServerUrl(argo_server_url)) + .data(None::>) + .finish(); + let query = format!( + r#" + query {{ + workflow(name: "{}", visit: {{proposalCode: "{}", proposalNumber: {}, number: {}}}) {{ + status {{ + ...on WorkflowRunningStatus {{ + startTime + message + tasks {{ + id + }} + }} + }} + }} + }} + "#, + workflow_name, visit.proposal_code, visit.proposal_number, visit.number + ); + let resp = schema.execute(query).await.into_result().unwrap(); + + workflow_endpoint.assert_async().await; + let expected_data = json!({ + "workflow": { + "status": { + "startTime": "2025-01-22T12:29:45+00:00", + "message": null, + "tasks": [{"id": workflow_name}] + } + } + }); + assert_eq!(resp.data.into_json().unwrap(), expected_data); + } + + #[tokio::test] + async fn single_null_workflow_query() { + let workflow_name = "numpy-benchmark-pwtgn"; + let visit = Visit { + proposal_code: "mg".to_string(), + proposal_number: 36964, + number: 1, + }; + + let mut server = mockito::Server::new_async().await; + let mut response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + response_file_path.push("test-assets"); + response_file_path.push("get-workflow-pwtgn-null.json"); + let workflow_endpoint = server + .mock( + "GET", + &format!("/api/v1/workflows/{}/{}", visit, workflow_name)[..], + ) + .with_status(200) + .with_header("content-type", "application/json") + .with_body_from_file(response_file_path) + .create_async() + .await; + + let argo_server_url = Url::parse(&server.url()).unwrap(); + let schema = root_schema_builder() + .data(ArgoServerUrl(argo_server_url)) + .data(None::>) + .finish(); + let query = format!( + r#" + query {{ + workflow(name: "{}", visit: {{proposalCode: "{}", proposalNumber: {}, number: {}}}) {{ + status {{ + __typename + }} + }} + }} + "#, + workflow_name, visit.proposal_code, visit.proposal_number, visit.number + ); + let resp = schema.execute(query).await.into_result().unwrap(); + + workflow_endpoint.assert_async().await; + let expected_data = json!({ + "workflow": { + "status": null, + } + }); + assert_eq!(resp.data.into_json().unwrap(), expected_data); + } + #[tokio::test] async fn multiple_workflows_query() { let visit = Visit { @@ -579,7 +821,7 @@ mod tests { let mut server = mockito::Server::new_async().await; let mut multiple_workflows_response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - multiple_workflows_response_file_path.push("test-resources"); + multiple_workflows_response_file_path.push("test-assets"); multiple_workflows_response_file_path.push("get-workflows.json"); let workflows_endpoint = server @@ -645,13 +887,13 @@ mod tests { let mut server = mockito::Server::new_async().await; let mut multiple_workflows_response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - multiple_workflows_response_file_path.push("test-resources"); + multiple_workflows_response_file_path.push("test-assets"); multiple_workflows_response_file_path.push("get-workflows.json"); let mut workflow_one_response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - workflow_one_response_file_path.push("test-resources"); + workflow_one_response_file_path.push("test-assets"); workflow_one_response_file_path.push("get-workflow-wdkwj.json"); let mut workflow_two_response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - workflow_two_response_file_path.push("test-resources"); + workflow_two_response_file_path.push("test-assets"); workflow_two_response_file_path.push("get-workflow-n6jsg.json"); let workflows_endpoint = server @@ -746,7 +988,7 @@ mod tests { let mut server = mockito::Server::new_async().await; let mut multiple_workflows_response_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - multiple_workflows_response_file_path.push("test-resources"); + multiple_workflows_response_file_path.push("test-assets"); multiple_workflows_response_file_path.push("get-workflows.json"); let workflows_endpoint = server diff --git a/graph-proxy/test-assets/get-workflow-jwcfp-errored.json b/graph-proxy/test-assets/get-workflow-jwcfp-errored.json new file mode 100644 index 000000000..fdc178c1f --- /dev/null +++ b/graph-proxy/test-assets/get-workflow-jwcfp-errored.json @@ -0,0 +1,262 @@ +{ + "metadata": { + "name": "numpy-benchmark-jwcfp", + "generateName": "numpy-benchmark-", + "namespace": "mg36964-1", + "uid": "0b9e6a48-32cb-4c8f-8866-97aecb48adbe", + "resourceVersion": "72405469", + "generation": 2, + "creationTimestamp": "2024-10-11T14:35:37Z", + "labels": { + "workflows.argoproj.io/cluster-workflow-template": "numpy-benchmark", + "workflows.argoproj.io/completed": "true", + "workflows.argoproj.io/creator": "ed66f621-7b56-4157-a255-a03af5bd8f0e", + "workflows.argoproj.io/creator-email": "garry.o-donnell.at.diamond.ac.uk", + "workflows.argoproj.io/creator-preferred-username": "enu43627", + "workflows.argoproj.io/phase": "Error", + "workflows.argoproj.io/workflow-archiving-status": "Archived" + }, + "annotations": { + "workflows.argoproj.io/pod-name-format": "v2" + }, + "managedFields": [ + { + "manager": "argo", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2024-10-11T14:35:36Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:workflows.argoproj.io/cluster-workflow-template": {}, + "f:workflows.argoproj.io/creator": {}, + "f:workflows.argoproj.io/creator-email": {}, + "f:workflows.argoproj.io/creator-preferred-username": {} + } + }, + "f:spec": {} + } + }, + { + "manager": "workflow-controller", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2024-10-11T14:35:37Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:workflows.argoproj.io/pod-name-format": {} + }, + "f:labels": { + "f:workflows.argoproj.io/completed": {}, + "f:workflows.argoproj.io/phase": {}, + "f:workflows.argoproj.io/workflow-archiving-status": {} + } + }, + "f:status": {} + } + } + ] + }, + "spec": { + "arguments": { + "parameters": [ + { + "name": "size", + "value": "1000" + }, + { + "name": "memory", + "value": "\"10Gi\"" + } + ] + }, + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "status": { + "phase": "Error", + "startedAt": "2024-10-11T14:35:37Z", + "finishedAt": "2024-10-11T14:35:37Z", + "estimatedDuration": 11, + "progress": "0/1", + "message": "error in entry template execution: Error applying PodSpecPatch", + "nodes": { + "numpy-benchmark-jwcfp": { + "id": "numpy-benchmark-jwcfp", + "name": "numpy-benchmark-jwcfp", + "displayName": "numpy-benchmark-jwcfp", + "type": "Pod", + "templateName": "numpy-test", + "templateScope": "local/", + "phase": "Error", + "message": "Error applying PodSpecPatch", + "startedAt": "2024-10-11T14:35:37Z", + "finishedAt": "2024-10-11T14:35:37Z", + "estimatedDuration": 6, + "progress": "0/1", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "1000" + }, + { + "name": "memory", + "value": "\"10Gi\"" + } + ] + } + } + }, + "storedTemplates": { + "cluster/numpy-benchmark/numpy-test": { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + }, + "conditions": [ + { + "type": "Completed", + "status": "True" + } + ], + "storedWorkflowTemplateSpec": { + "templates": [ + { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + ], + "entrypoint": "numpy-test", + "arguments": { + "parameters": [ + { + "name": "size", + "value": "1000" + }, + { + "name": "memory", + "value": "\"10Gi\"" + } + ] + }, + "serviceAccountName": "argo-workflow", + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "artifactRepositoryRef": { + "default": true, + "artifactRepository": { + "archiveLogs": true, + "s3": { + "endpoint": "sci-nas-s3.diamond.ac.uk", + "bucket": "k8s-workflows-test", + "region": "unsupported", + "accessKeySecret": { + "name": "artifact-s3", + "key": "access-key" + }, + "secretKeySecret": { + "name": "artifact-s3", + "key": "secret-key" + } + } + } + }, + "artifactGCStatus": { + "notSpecified": true + } + } +} diff --git a/graph-proxy/test-assets/get-workflow-kc7pf-running.json b/graph-proxy/test-assets/get-workflow-kc7pf-running.json new file mode 100644 index 000000000..fd6c16986 --- /dev/null +++ b/graph-proxy/test-assets/get-workflow-kc7pf-running.json @@ -0,0 +1,267 @@ +{ + "metadata": { + "name": "numpy-benchmark-kc7pf", + "generateName": "numpy-benchmark-", + "namespace": "mg36964-1", + "uid": "9aa7ef6e-3e9a-4fdb-a5a2-6125f6a98fca", + "resourceVersion": "233334857", + "generation": 3, + "creationTimestamp": "2025-01-22T12:29:45Z", + "labels": { + "submit-from-ui": "true", + "workflows.argoproj.io/cluster-workflow-template": "numpy-benchmark", + "workflows.argoproj.io/completed": "false", + "workflows.argoproj.io/creator": "d2cc5e04-14e7-453b-9622-e20bea96ccf5", + "workflows.argoproj.io/creator-email": "yousef.moazzam.at.diamond.ac.uk", + "workflows.argoproj.io/creator-preferred-username": "twi18192", + "workflows.argoproj.io/phase": "Running", + "workflows.argoproj.io/resubmitted-from-workflow": "numpy-benchmark-hdkgt" + }, + "annotations": { + "workflows.argoproj.io/pod-name-format": "v2" + }, + "managedFields": [ + { + "manager": "argo", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2025-01-22T12:29:44Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:workflows.argoproj.io/pod-name-format": {} + }, + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:submit-from-ui": {}, + "f:workflows.argoproj.io/cluster-workflow-template": {}, + "f:workflows.argoproj.io/creator": {}, + "f:workflows.argoproj.io/creator-email": {}, + "f:workflows.argoproj.io/creator-preferred-username": {}, + "f:workflows.argoproj.io/resubmitted-from-workflow": {} + } + }, + "f:spec": {} + } + }, + { + "manager": "workflow-controller", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2025-01-22T12:29:55Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:labels": { + "f:workflows.argoproj.io/completed": {}, + "f:workflows.argoproj.io/phase": {} + } + }, + "f:status": {} + } + } + ] + }, + "spec": { + "entrypoint": "numpy-test", + "arguments": { + "parameters": [ + { + "name": "size", + "value": "100000" + }, + { + "name": "memory", + "value": "10Gi" + } + ] + }, + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "status": { + "phase": "Running", + "startedAt": "2025-01-22T12:29:45Z", + "finishedAt": null, + "estimatedDuration": 10, + "progress": "0/1", + "nodes": { + "numpy-benchmark-kc7pf": { + "id": "numpy-benchmark-kc7pf", + "name": "numpy-benchmark-kc7pf", + "displayName": "numpy-benchmark-kc7pf", + "type": "Pod", + "templateName": "numpy-test", + "templateScope": "local/", + "phase": "Running", + "startedAt": "2025-01-22T12:29:45Z", + "finishedAt": null, + "estimatedDuration": 6, + "progress": "0/1", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "100000" + }, + { + "name": "memory", + "value": "10Gi" + } + ] + }, + "hostNodeName": "cs05r-sc-cloud-10.diamond.ac.uk" + } + }, + "storedTemplates": { + "cluster/numpy-benchmark/numpy-test": { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + }, + "conditions": [ + { + "type": "PodRunning", + "status": "True" + } + ], + "storedWorkflowTemplateSpec": { + "templates": [ + { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + ], + "entrypoint": "numpy-test", + "arguments": { + "parameters": [ + { + "name": "size", + "value": "100000" + }, + { + "name": "memory", + "value": "10Gi" + } + ] + }, + "serviceAccountName": "argo-workflow", + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "artifactRepositoryRef": { + "default": true, + "artifactRepository": { + "archiveLogs": true, + "s3": { + "endpoint": "sci-nas-s3.diamond.ac.uk", + "bucket": "k8s-workflows-test", + "region": "unsupported", + "accessKeySecret": { + "name": "artifact-s3", + "key": "access-key" + }, + "secretKeySecret": { + "name": "artifact-s3", + "key": "secret-key" + } + } + } + }, + "artifactGCStatus": { + "notSpecified": true + }, + "taskResultsCompletionStatus": { + "numpy-benchmark-kc7pf": false + } + } +} diff --git a/graph-proxy/test-resources/get-workflow-n6jsg.json b/graph-proxy/test-assets/get-workflow-n6jsg.json similarity index 100% rename from graph-proxy/test-resources/get-workflow-n6jsg.json rename to graph-proxy/test-assets/get-workflow-n6jsg.json diff --git a/graph-proxy/test-assets/get-workflow-pwtgn-null.json b/graph-proxy/test-assets/get-workflow-pwtgn-null.json new file mode 100644 index 000000000..c07754d80 --- /dev/null +++ b/graph-proxy/test-assets/get-workflow-pwtgn-null.json @@ -0,0 +1,121 @@ +{ + "metadata": { + "name": "numpy-benchmark-pwtgn", + "generateName": "numpy-benchmark-", + "namespace": "mg36964-1", + "uid": "fcffd6b5-aeb5-4228-98a1-ececfe0563c7", + "resourceVersion": "233729873", + "generation": 1, + "creationTimestamp": "2025-01-22T16:38:08Z", + "labels": { + "submit-from-ui": "true", + "workflows.argoproj.io/cluster-workflow-template": "numpy-benchmark", + "workflows.argoproj.io/creator": "d2cc5e04-14e7-453b-9622-e20bea96ccf5", + "workflows.argoproj.io/creator-email": "yousef.moazzam.at.diamond.ac.uk", + "workflows.argoproj.io/creator-preferred-username": "twi18192", + "workflows.argoproj.io/resubmitted-from-workflow": "numpy-benchmark-k8jpn" + }, + "annotations": { + "workflows.argoproj.io/pod-name-format": "v2" + }, + "managedFields": [ + { + "manager": "argo", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2025-01-22T16:38:08Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:workflows.argoproj.io/pod-name-format": {} + }, + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:submit-from-ui": {}, + "f:workflows.argoproj.io/cluster-workflow-template": {}, + "f:workflows.argoproj.io/creator": {}, + "f:workflows.argoproj.io/creator-email": {}, + "f:workflows.argoproj.io/creator-preferred-username": {}, + "f:workflows.argoproj.io/resubmitted-from-workflow": {} + } + }, + "f:spec": {}, + "f:status": {} + } + } + ] + }, + "spec": { + "entrypoint": "numpy-test", + "arguments": { + "parameters": [ + { + "name": "size", + "value": "1000" + }, + { + "name": "memory", + "value": "10Gi" + } + ] + }, + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "status": { + "startedAt": null, + "finishedAt": null, + "storedTemplates": { + "cluster/numpy-benchmark/numpy-test": { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + } + } +} diff --git a/graph-proxy/test-assets/get-workflow-qhb59-failed.json b/graph-proxy/test-assets/get-workflow-qhb59-failed.json new file mode 100644 index 000000000..7eb178bd2 --- /dev/null +++ b/graph-proxy/test-assets/get-workflow-qhb59-failed.json @@ -0,0 +1,296 @@ +{ + "metadata": { + "name": "numpy-benchmark-qhb59", + "generateName": "numpy-benchmark-", + "namespace": "mg36964-1", + "uid": "d6f6f3f5-f8e5-4e6d-b345-777382b8e4d7", + "resourceVersion": "59642479", + "generation": 4, + "creationTimestamp": "2024-10-02T11:11:17Z", + "labels": { + "submit-from-ui": "true", + "workflows.argoproj.io/cluster-workflow-template": "numpy-benchmark", + "workflows.argoproj.io/completed": "true", + "workflows.argoproj.io/creator": "bf59ee1f-4b1b-4b1f-a597-9be5df98701f", + "workflows.argoproj.io/creator-email": "benedikt.daurer.at.diamond.ac.uk", + "workflows.argoproj.io/creator-posix-uid": "test-uid", + "workflows.argoproj.io/creator-preferred-username": "iat69393", + "workflows.argoproj.io/phase": "Failed", + "workflows.argoproj.io/resubmitted-from-workflow": "numpy-benchmark-vmh8q", + "workflows.argoproj.io/workflow-archiving-status": "Persisted" + }, + "annotations": { + "workflows.argoproj.io/pod-name-format": "v2" + }, + "managedFields": [ + { + "manager": "argo", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2024-10-02T11:11:17Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:spec": {}, + "f:metadata": { + "f:labels": { + ".": {}, + "f:submit-from-ui": {}, + "f:workflows.argoproj.io/creator": {}, + "f:workflows.argoproj.io/creator-email": {}, + "f:workflows.argoproj.io/creator-posix-uid": {}, + "f:workflows.argoproj.io/cluster-workflow-template": {}, + "f:workflows.argoproj.io/resubmitted-from-workflow": {}, + "f:workflows.argoproj.io/creator-preferred-username": {} + }, + "f:annotations": { + ".": {}, + "f:workflows.argoproj.io/pod-name-format": {} + }, + "f:generateName": {} + } + } + }, + { + "manager": "workflow-controller", + "operation": "Update", + "apiVersion": "argoproj.io/v1alpha1", + "time": "2024-10-02T11:12:32Z", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": {}, + "f:metadata": { + "f:labels": { + "f:workflows.argoproj.io/phase": {}, + "f:workflows.argoproj.io/completed": {}, + "f:workflows.argoproj.io/workflow-archiving-status": {} + } + } + } + } + ] + }, + "spec": { + "entrypoint": "numpy-test", + "arguments": { + "parameters": [ + { + "name": "size", + "value": "50000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "status": { + "phase": "Failed", + "startedAt": "2024-10-02T11:11:17Z", + "finishedAt": "2024-10-02T11:12:32Z", + "estimatedDuration": 42, + "progress": "0/1", + "message": "OOMKilled (exit code 137)", + "nodes": { + "numpy-benchmark-qhb59": { + "id": "numpy-benchmark-qhb59", + "name": "numpy-benchmark-qhb59", + "displayName": "numpy-benchmark-qhb59", + "type": "Pod", + "templateName": "numpy-test", + "templateScope": "local/", + "phase": "Failed", + "message": "OOMKilled (exit code 137)", + "startedAt": "2024-10-02T11:11:17Z", + "finishedAt": "2024-10-02T11:12:22Z", + "estimatedDuration": 33, + "progress": "0/1", + "resourcesDuration": { + "cpu": 67, + "memory": 12555 + }, + "inputs": { + "parameters": [ + { + "name": "size", + "value": "50000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": { + "artifacts": [ + { + "name": "main-logs", + "s3": { + "key": "numpy-benchmark-qhb59/numpy-benchmark-qhb59/main.log" + } + } + ], + "exitCode": "137" + }, + "hostNodeName": "cs05r-sc-cloud-19.diamond.ac.uk" + } + }, + "storedTemplates": { + "cluster/numpy-benchmark/numpy-test": { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + }, + "conditions": [ + { + "type": "PodRunning", + "status": "False" + }, + { + "type": "Completed", + "status": "True" + } + ], + "resourcesDuration": { + "cpu": 67, + "memory": 12555 + }, + "storedWorkflowTemplateSpec": { + "templates": [ + { + "name": "numpy-test", + "inputs": { + "parameters": [ + { + "name": "size", + "value": "2000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "outputs": {}, + "metadata": {}, + "script": { + "name": "", + "image": "gcr.io/diamond-privreg/ptypy/test_openmpi_full:0.1", + "command": [ + "python" + ], + "env": [ + { + "name": "MKL_NUM_THREADS", + "value": "1" + }, + { + "name": "NUMEXPR_NUM_THREADS", + "value": "1" + }, + { + "name": "OMP_NUM_THREADS", + "value": "1" + } + ], + "resources": {}, + "source": "import numpy as np\nimport time\n\nn = int(\"{{ inputs.parameters.size }}\")\nA = np.random.randn(n,n).astype('float64')\nB = np.random.randn(n,n).astype('float64')\nstart_time = time.time()\nnrm = np.linalg.norm(A@B)\nprint(\" took {} seconds \".format(time.time() - start_time))\nprint(\" norm = \",nrm)\nprint(np.__config__.show())\n" + }, + "podSpecPatch": "containers:\n- name: main\n resources:\n requests:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n limits:\n cpu: \"1\"\n memory: \"{{ inputs.parameters.memory }}\"\n" + } + ], + "entrypoint": "numpy-test", + "arguments": { + "parameters": [ + { + "name": "size", + "value": "50000" + }, + { + "name": "memory", + "value": "20Gi" + } + ] + }, + "serviceAccountName": "argo-workflow", + "podGC": { + "strategy": "OnPodCompletion", + "deleteDelayDuration": "60s" + }, + "workflowTemplateRef": { + "name": "numpy-benchmark", + "clusterScope": true + } + }, + "artifactRepositoryRef": { + "default": true, + "artifactRepository": { + "archiveLogs": true, + "s3": { + "endpoint": "sci-nas-s3.diamond.ac.uk", + "bucket": "k8s-workflows-test", + "region": "unsupported", + "accessKeySecret": { + "name": "artifact-s3", + "key": "access-key" + }, + "secretKeySecret": { + "name": "artifact-s3", + "key": "secret-key" + } + } + } + }, + "artifactGCStatus": { + "notSpecified": true + }, + "taskResultsCompletionStatus": { + "numpy-benchmark-qhb59": true + } + } +} diff --git a/graph-proxy/test-resources/get-workflow-wdkwj.json b/graph-proxy/test-assets/get-workflow-wdkwj.json similarity index 100% rename from graph-proxy/test-resources/get-workflow-wdkwj.json rename to graph-proxy/test-assets/get-workflow-wdkwj.json diff --git a/graph-proxy/test-resources/get-workflows.json b/graph-proxy/test-assets/get-workflows.json similarity index 100% rename from graph-proxy/test-resources/get-workflows.json rename to graph-proxy/test-assets/get-workflows.json