{"id":36485595,"url":"https://github.com/serverlessml/ingress","last_synced_at":"2026-01-14T16:25:55.521Z","repository":{"id":55391249,"uuid":"317153641","full_name":"serverlessml/ingress","owner":"serverlessml","description":"Serverless ML Framework Pipeline Ingress","archived":false,"fork":false,"pushed_at":"2021-01-03T20:14:01.000Z","size":197,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-12T03:36:09.066Z","etag":null,"topics":["devops","ingress-service","machine-learning","mlops","pipeline"],"latest_commit_sha":null,"homepage":"https://www.serverlessml.org","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/serverlessml.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-30T08:12:16.000Z","updated_at":"2021-01-03T20:14:03.000Z","dependencies_parsed_at":"2022-08-14T23:10:55.134Z","dependency_job_id":null,"html_url":"https://github.com/serverlessml/ingress","commit_stats":null,"previous_names":["serverlessml/gcp-ingress"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/serverlessml/ingress","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverlessml%2Fingress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverlessml%2Fingress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverlessml%2Fingress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverlessml%2Fingress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/serverlessml","download_url":"https://codeload.github.com/serverlessml/ingress/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverlessml%2Fingress/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28425817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T15:24:48.085Z","status":"ssl_error","status_checked_at":"2026-01-14T15:23:41.940Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["devops","ingress-service","machine-learning","mlops","pipeline"],"created_at":"2026-01-12T01:49:41.927Z","updated_at":"2026-01-14T16:25:55.515Z","avatar_url":"https://github.com/serverlessml.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pipeline Ingress\n\n||\n|-|\n|[![Go Report Card](https://goreportcard.com/badge/github.com/serverlessml/ingress)](https://goreportcard.com/report/github.com/serverlessml/ingress)|\n|[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5f25b1430ecb41298f67750e25777169)](https://app.codacy.com/gh/serverlessml/gcp-ingress?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=serverlessml/gcp-ingress\u0026utm_campaign=Badge_Grade)|\n|[![code coverage:aws](https://img.shields.io/badge/coverage%20aws-80%25-yellowgreen)](https://img.shields.io/badge/coverage%20aws-80%25-yellowgreen)|\n|[![code coverage:gcp](https://img.shields.io/badge/coverage%20gcp-100%25-brightgreen)](https://img.shields.io/badge/coverage%20gcp-100%25-brightgreen)|\n|[![CI](https://github.com/serverlessml/gcp-ingress/workflows/Deployment/badge.svg)](https://github.com/serverlessml/gcp-ingress/workflows/Deployment/badge.svg)|\n\nThe ingress service to invoke ML pipeline. A web-server with two end-points:\n\n`GET: /status`      -\u003e status check\n\n`POST: /train`      -\u003e \u003cstrong\u003e\u003cem\u003etrain\u003c/em\u003e\u003c/strong\u003e pipeline invocation trigger request with the metadata payload\n\n`POST: /predict`    -\u003e \u003cstrong\u003e\u003cem\u003epredict\u003c/em\u003e\u003c/strong\u003e pipeline invocation trigger request with the metadata payload\n\n## Modus Operandi\n\n1. Validate input payload:\n2. Push the payload to a message bus' topic\n3. Return 202 as response in case of success\n\n## How to run\n!Note! It requires an existing GCP, or AWS account with activated pubsub/SNS API, service account (SA) with PubSub/SNS Write permissions and a PubSub/SNS topic.\n\nOnce SA is created, generate and download the access key to `${PATH_TO_SERVICE_ACCOUNT_KEY}/key-pubsub.json`.\n\nExecute:\n\n```bash\nmake build PLATFORM=gcp\n```\n\nafterwards:\n\n```bash\nmake PROJECT_ID=\u003cYOUR_GCO_PROJECT_ID\u003e run\n```\n\nor alternatively, for the sake of testing, run\n\n```bash\nmake PROJECT_ID=\u003cYOUR_GCO_PROJECT_ID\u003e test-run\n```\n\n### HTTP Response Codes\n|Endpoint|Method|HTTP Status Code|Comment|\n|:-|:-:|-:|--|\n|/status|GET|200|-|\n|/status|POST,PUT,PATCH,DELETE|405|Not supported methods|\n|/train\u003cbr\u003e/predict|POST|202|Request accepted|\n|/train\u003cbr\u003e/predict|POST|400|Faulty JSON submitted with request|\n|/train\u003cbr\u003e/predict|GET,PUT,PATCH,DELETE|405|Not supported methods|\n|/train\u003cbr\u003e/predict|POST|422|Submitted JSON doesn't pass validation/comply with the input schema|\n\n#### Input Schema\n\nInput JSON schemas per endpoint can be found here:\n\n- [/train](./config/schema_train.go)\n\n- [/predict](./config/schema_predict.go)\n\n#### Response Schema\n\nPOST requests sent to `/train` and `/predict` lead to responses of the following structure:\n\n```json\n{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"definitions\": {\n        \"uuid4\": {\n            \"oneOf\": [\n                {\n                    \"type\": \"string\",\n                    \"pattern\": \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"\n                },\n                {\n                    \"type\": \"null\"\n                }\n            ]\n        }\n    },\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\n        \"errors\",\n        \"submitted_id\"\n    ],\n    \"properties\": {\n        \"errors\": {\n            \"type\": \"array\",\n            \"items\": {\n                \"oneOf\": [\n                    {\n                        \"type\": \"string\"\n                    },\n                    {\n                        \"type\": \"null\"\n                    }\n                ]\n            }\n        },\n        \"submitted_id\": {\n            \"type\": \"array\",\n            \"items\": {\n                \"$ref\": \"#/definitions/uuid4\"\n            }\n        }\n    }\n}\n```\n\n### Tests\n\n#### Health check\n\n```bash\ncurl -iX GET \"http://0.0.0.0:8080/status\"\n```\n\nExpected output:\n\n```bash\nHTTP/1.1 200 OK\nAccess-Control-Allow-Methods: GET\nDate: YOUR CURRENT DATE/TIME\nContent-Length: 0\n```\n\n#### Integration test\n\n1. Create the PubSub topic called `trigger_0cba82ff-9790-454d-b7b9-22570e7ba28c`\n2. Execute `make PROJECT_ID=\u003cYOUR_GCO_PROJECT_ID\u003e run`\n3. Run\n\n- to trigger `train` pipeline:\n\n```bash\ncurl -H \"Accept: application/json\" -H \"Content-Type: application/json\" \\\n    -iX POST \"http://0.0.0.0:8080/train\" -d '{\n  \"project_id\": \"0cba82ff-9790-454d-b7b9-22570e7ba28c\",\n  \"code_hash\": \"8c2f3d3c5dd853231c7429b099347d13c8bb2c37\",\n  \"pipeline_config\": [\n    {\n      \"data\": {\n        \"location\": {\n          \"source\": \"gcs://test/train.csv\"\n        },\n        \"prep_config\": {}\n      },\n      \"model\": {\n        \"hyperparameters\": {},\n        \"version\": \"v1\"\n      }\n    }\n  ]\n}'\n```\n\nExpected output:\n```bash\nHTTP/1.1 202 Accepted\nAccess-Control-Allow-Headers: Content-Type, Content-Length, Accept-Encoding\nAccess-Control-Allow-Methods: POST\nContent-Type: application/json\nDate: YOUR CURRENT DATE/TIME\nContent-Length: 69\n\n{\"errors\":[],\"submitted_id\":[\"b441141f-bce1-4552-9458-999d2b8f6fda\"]}\n```\n\n- to trigger `predict` pipeline:\n\n```bash\ncurl -H \"Accept: application/json\" -H \"Content-Type: application/json\" \\\n    -iX POST \"http://0.0.0.0:8080/predict\" -d '{\n  \"project_id\": \"0cba82ff-9790-454d-b7b9-22570e7ba28c\",\n  \"train_id\": \"b441141f-bce1-4552-9458-999d2b8f6fda\",\n  \"pipeline_config\": [\n    {\n      \"data\": {\n        \"location\": {\n          \"source\": \"gcs://test/train.csv\",\n          \"destination\": \"gcs://prediction/train.csv\"\n        }\n      }\n    }\n  ]\n}'\n```\n\nExpected output:\n```bash\nHTTP/1.1 202 Accepted\nAccess-Control-Allow-Headers: Content-Type, Content-Length, Accept-Encoding\nAccess-Control-Allow-Methods: POST\nContent-Type: application/json\nDate: YOUR CURRENT DATE/TIME\nContent-Length: 69\n\n{\"errors\":[],\"submitted_id\":[\"3aab10b8-a42b-4938-aea8-fd398d2c2f01\"]}\n```\n\nIn the return payload, the `submitted_id` is a list UUID4 index, it must be different from the ones above.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fserverlessml%2Fingress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fserverlessml%2Fingress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fserverlessml%2Fingress/lists"}