py-serverless-kit 0.1.3__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/CHANGELOG.md +19 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/PKG-INFO +11 -9
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/README.md +8 -6
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/README.md +1 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/architecture.md +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/cli.md +1 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/configuration.md +4 -3
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/events.md +12 -7
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/getting-started.md +1 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/handlers.md +4 -2
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/local-development.md +4 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/providers.md +101 -2
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/troubleshooting.md +1 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/workflows.md +1 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/pskit.yml +6 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/README.md +5 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/app/worker.py +16 -10
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/pskit.yml +9 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/README.md +5 -3
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/app/handlers.py +1 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.yml +7 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/pskit.yml +7 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/pskit.yml +11 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/pskit.yml +3 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/pskit.yml +5 -0
- py_serverless_kit-0.3.0/examples/16-on-premises/README.md +63 -0
- py_serverless_kit-0.3.0/examples/16-on-premises/app/handlers.py +54 -0
- py_serverless_kit-0.3.0/examples/16-on-premises/pskit.yml +69 -0
- py_serverless_kit-0.3.0/examples/16-on-premises/requirements.txt +1 -0
- py_serverless_kit-0.3.0/examples/17-on-premises-remote/README.md +97 -0
- py_serverless_kit-0.3.0/examples/17-on-premises-remote/app/__init__.py +1 -0
- py_serverless_kit-0.3.0/examples/17-on-premises-remote/app/handlers.py +16 -0
- py_serverless_kit-0.3.0/examples/17-on-premises-remote/pskit.yml +60 -0
- py_serverless_kit-0.3.0/examples/17-on-premises-remote/requirements.txt +1 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/README.md +3 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/pyproject.toml +2 -2
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/_version.py +1 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/templates.py +11 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/loader.py +13 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/schema.py +1 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/packaging/builder.py +1 -1
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/base.py +7 -1
- py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem.py +562 -0
- py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem_remote.py +381 -0
- py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem_spec.py +404 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/registry.py +1 -0
- py_serverless_kit-0.3.0/src/py_serverless_kit/runtime/adapters/onprem.py +117 -0
- py_serverless_kit-0.3.0/src/py_serverless_kit/runtime/cron.py +143 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/dispatch.py +3 -3
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/invoke.py +13 -3
- py_serverless_kit-0.3.0/src/py_serverless_kit/runtime/onprem_host.py +1083 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/config/test_loader.py +18 -0
- py_serverless_kit-0.3.0/tests/providers/test_onprem.py +254 -0
- py_serverless_kit-0.3.0/tests/providers/test_onprem_remote.py +148 -0
- py_serverless_kit-0.3.0/tests/runtime/test_adapter_onprem.py +58 -0
- py_serverless_kit-0.3.0/tests/runtime/test_cron.py +46 -0
- py_serverless_kit-0.3.0/tests/runtime/test_onprem_host.py +239 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_examples.py +25 -2
- py_serverless_kit-0.3.0/tests/workflows/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/.gitignore +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/CONTRIBUTING.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/LICENSE +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/deploy_docs/CONTRIBUTING.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/dashboard.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/docs/migrating-from-aws.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/01-hello-http/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/store.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/02-rest-api/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/app/jobs.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/04-queue-worker/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/app/files.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/05-storage-events/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/app/subscribers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/app/orders.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/b2b.json +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/declined.json +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/happy.json +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.aws.yml +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.azure.yml +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.gcp.yml +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/app/quotes.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/09-function-invoke/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/.env.example +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/settings.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/config/limits.json +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/repository.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/scripts/smoke_test.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/tests/test_orders.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/12-async-and-context/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/app/orders.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/lambda_function.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/state_machine.asl.json +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/template.yaml +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/ci.github-workflow.yml +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/requirements.txt +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/tests/conftest.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/tests/test_handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/14-testing/tests/test_workflow.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/README.md +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/app/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/app/handlers.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/deploy.github-workflow.yml +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/requirements.txt +0 -0
- {py_serverless_kit-0.1.3/src/py_serverless_kit/cli → py_serverless_kit-0.3.0/examples/16-on-premises/app}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/__main__.py +0 -0
- {py_serverless_kit-0.1.3/src/py_serverless_kit/core → py_serverless_kit-0.3.0/src/py_serverless_kit/cli}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/main.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/__init__.py +0 -0
- {py_serverless_kit-0.1.3/tests → py_serverless_kit-0.3.0/src/py_serverless_kit/core}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/deployer.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/describe.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/project.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/generator.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/template.html +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/runner.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/server.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/packaging/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/alibaba.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/aws.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/azure.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/cloudflare.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/digitalocean.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/gcp.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/huawei.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/ibm.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/oracle.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/schedule.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/tencent.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/terraform_doc.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/_httpfn.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/alibaba.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/aws.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/azure.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/base.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/cloudflare.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/digitalocean.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/gcp.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/huawei.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/ibm.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/oracle.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/tencent.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/batch.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/context.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/errors.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/event.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/log.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/manifest.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/response.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/routing.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/workflow.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/terraform/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/terraform/runner.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/asl.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/gcp.py +0 -0
- {py_serverless_kit-0.1.3/tests/config → py_serverless_kit-0.3.0/tests}/__init__.py +0 -0
- {py_serverless_kit-0.1.3/tests/local → py_serverless_kit-0.3.0/tests/config}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/config/test_schema.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/conftest.py +0 -0
- {py_serverless_kit-0.1.3/tests/providers → py_serverless_kit-0.3.0/tests/local}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/local/test_server.py +0 -0
- {py_serverless_kit-0.1.3/tests/runtime → py_serverless_kit-0.3.0/tests/providers}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_alibaba.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_aws.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_azure.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_cloudflare.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_digitalocean.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_gcp.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_huawei.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_ibm.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_oracle.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_schedule.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/providers/test_tencent.py +0 -0
- {py_serverless_kit-0.1.3/tests/workflows → py_serverless_kit-0.3.0/tests/runtime}/__init__.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_alibaba.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_aws.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_azure.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_cloudflare.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_digitalocean.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_gcp.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_huawei.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_ibm.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_oracle.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_tencent.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_dispatch.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_models.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/runtime/test_workflow_engine.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_cli.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_dashboard.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/test_packaging.py +0 -0
- {py_serverless_kit-0.1.3 → py_serverless_kit-0.3.0}/tests/workflows/test_compilers.py +0 -0
|
@@ -6,6 +6,25 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.0] - 2026-10-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- On-premises deploy targets. `provider.options.deploy.method` is `local` (default, previous behaviour), `ssh` (copy the host over OpenSSH and start a process or systemd unit), or `docker` (build an image that already contains Python). When the server has no Python, set `python: bundle` to ship a portable CPython, or use `method: docker`. `python_home` / `python_url` cover air-gapped mirrors. Wheels are vendored for the target OS/arch (manylinux when the server is Linux).
|
|
13
|
+
- Example [17-on-premises-remote](examples/17-on-premises-remote): SSH + bundled interpreter + systemd.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- On-prem host: Windows process helpers (`ctypes.windll`, `subprocess.DETACHED_PROCESS`) are gated on `sys.platform == "win32"` so mypy on Linux/macOS CI no longer reports missing attributes.
|
|
17
|
+
|
|
18
|
+
Redeploy on-premises hosts to pick up the new `onprem_deploy.py` provisioner. Handler code is unchanged.
|
|
19
|
+
|
|
20
|
+
## [0.2.0] - 2026-10-17
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- On-premises provider (`provider.name: onprem`). `pskit deploy` starts one long-lived Python process on the machine that runs the command. HTTP is served directly. Schedules, file queues (with dead-letter and partial batch failure), directory storage and file topics are created at start when they do not already exist. Point `provider.options.services.<kind>` at `{use: directory, path: ...}` to use a directory you already have. `existing: true` waits for that directory instead of creating it. Workflows run on the embedded engine inside the host, and `invoke()` stays in-process. `pskit remove` stops the process and leaves the data directory in place.
|
|
24
|
+
- Example [16-on-premises](examples/16-on-premises). Every other example has an `providers.onprem` block (its own port, public auth where a cloud authorizer does not apply, local state where the file used a cloud backend).
|
|
25
|
+
|
|
26
|
+
No change to handlers that already run on a cloud. Redeploy to pick up the new runtime if you use `BatchResult` or `invoke()` on premises.
|
|
27
|
+
|
|
9
28
|
## [0.1.3] - 2026-10-15
|
|
10
29
|
|
|
11
30
|
### Fixed
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: py-serverless-kit
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Write a Python serverless function once and deploy it to AWS, Azure, GCP
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Write a Python serverless function once and deploy it to AWS, Azure, GCP, 7 more clouds, or an on-premises host with one YAML file, powered by Terraform.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ak9347128658/serverless_kit
|
|
6
6
|
Project-URL: Documentation, https://github.com/ak9347128658/serverless_kit/tree/main/docs
|
|
7
7
|
Project-URL: Issues, https://github.com/ak9347128658/serverless_kit/issues
|
|
@@ -10,7 +10,7 @@ Author: Asif Khan @ Kavion.ai
|
|
|
10
10
|
Maintainer: Asif Khan @ Kavion.ai
|
|
11
11
|
License: MIT
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Keywords: aws,azure,faas,gcp,lambda,multi-cloud,serverless,step-functions,terraform
|
|
13
|
+
Keywords: aws,azure,faas,gcp,lambda,multi-cloud,on-premises,serverless,step-functions,terraform
|
|
14
14
|
Classifier: Development Status :: 4 - Beta
|
|
15
15
|
Classifier: Environment :: Console
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
@@ -48,12 +48,12 @@ Description-Content-Type: text/markdown
|
|
|
48
48
|
[](https://pypi.org/project/py-serverless-kit/)
|
|
49
49
|
[](https://github.com/ak9347128658/serverless_kit/blob/main/LICENSE)
|
|
50
50
|
|
|
51
|
-
**Write your Python functions once. Deploy them to any of 10 clouds by changing one line of YAML.**
|
|
51
|
+
**Write your Python functions once. Deploy them to any of 10 clouds, or to your own machine, by changing one line of YAML.**
|
|
52
52
|
|
|
53
53
|
`py-serverless-kit` (CLI: `pskit`) is a Serverless-Framework-style toolkit built on **Terraform**. Your handlers use one small, provider-neutral API (`Event`, `Context`, `Response`). A `pskit.yml` file says which cloud they run on and what triggers them: HTTP, schedules, queues, storage, topics. The same file can also define workflows in the style of Step Functions. `pskit deploy` generates Terraform for the chosen cloud, applies it, and builds an HTML dashboard of everything you deployed.
|
|
54
54
|
|
|
55
55
|
```python
|
|
56
|
-
# app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare
|
|
56
|
+
# app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare, and on premises
|
|
57
57
|
from py_serverless_kit import Event, Context, NotFound
|
|
58
58
|
|
|
59
59
|
def get_order(event: Event, ctx: Context):
|
|
@@ -67,7 +67,7 @@ def get_order(event: Event, ctx: Context):
|
|
|
67
67
|
# pskit.yml
|
|
68
68
|
service: orders
|
|
69
69
|
provider:
|
|
70
|
-
name: aws # <- change to gcp, azure,
|
|
70
|
+
name: aws # <- change to gcp, azure, onprem, ... and redeploy. That's the migration.
|
|
71
71
|
region: us-east-1
|
|
72
72
|
functions:
|
|
73
73
|
get-order:
|
|
@@ -97,7 +97,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
|
|
|
97
97
|
|
|
98
98
|
## Features
|
|
99
99
|
|
|
100
|
-
- **10
|
|
100
|
+
- **10 clouds and an on-premises host:** AWS Lambda, Azure Functions, Google Cloud Functions (gen2), Alibaba Function Compute, Oracle Functions, IBM Code Engine, DigitalOcean Functions, Tencent SCF, Huawei FunctionGraph, Cloudflare Workers, plus a process on your own machine or a remote server (`onprem`: local, SSH, Docker, or a bundled CPython when the server has no Python).
|
|
101
101
|
- **Triggers:** HTTP (path params, CORS, auth), schedules (rate/cron, translated into each cloud's cron dialect), queues, object storage, pub/sub topics, and direct function-to-function `invoke()`.
|
|
102
102
|
- **Workflows:** task / choice / wait / pass / parallel / map / succeed / fail with retry and catch. Native on AWS and GCP; an embedded engine on the other clouds; runnable locally with `pskit workflow run`.
|
|
103
103
|
- **Terraform underneath:** real, reviewable `main.tf.json`, any backend (S3, GCS, azurerm, ...), works with OpenTofu. Escape hatches: `terraform.extra`, `${tf:...}` references, per-function `options`.
|
|
@@ -120,6 +120,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
|
|
|
120
120
|
| IBM Code Engine | beta | ✅ | – | – | – | – | embedded |
|
|
121
121
|
| Oracle Cloud Functions | experimental | ✅ | – | – | ✅ | – | embedded |
|
|
122
122
|
| Cloudflare Workers (Python) | experimental | ✅ | ✅ | – | – | – | embedded |
|
|
123
|
+
| On-premises | experimental | ✅ | ✅ | ✅ files | ✅ directory | ✅ files | embedded (local, SSH, or Docker) |
|
|
123
124
|
|
|
124
125
|
Run `pskit providers` for the live matrix. If a config uses a trigger the target cloud can't support, **`pskit validate` fails with a clear message instead of deploying something half-working.**
|
|
125
126
|
|
|
@@ -251,7 +252,7 @@ More: [docs/architecture.md](https://github.com/ak9347128658/serverless_kit/blob
|
|
|
251
252
|
|
|
252
253
|
## Examples
|
|
253
254
|
|
|
254
|
-
|
|
255
|
+
Sixteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658/serverless_kit/tree/main/examples/). They are tested in CI.
|
|
255
256
|
|
|
256
257
|
| | |
|
|
257
258
|
|---|---|
|
|
@@ -262,7 +263,8 @@ Fifteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658
|
|
|
262
263
|
| [05-storage-events](https://github.com/ak9347128658/serverless_kit/tree/main/examples/05-storage-events) | Object created/deleted with filters |
|
|
263
264
|
| [06-pubsub-topic](https://github.com/ak9347128658/serverless_kit/tree/main/examples/06-pubsub-topic) | Topic fan-out and filters |
|
|
264
265
|
| [07-workflow-orders](https://github.com/ak9347128658/serverless_kit/tree/main/examples/07-workflow-orders) | Every workflow state type, retry/catch |
|
|
265
|
-
| [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all
|
|
266
|
+
| [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all 11 providers |
|
|
267
|
+
| [16-on-premises](https://github.com/ak9347128658/serverless_kit/tree/main/examples/16-on-premises) | HTTP, schedule, queue, storage, topic and a workflow on one machine |
|
|
266
268
|
| [09-function-invoke](https://github.com/ak9347128658/serverless_kit/tree/main/examples/09-function-invoke) | Function-to-function `invoke()` |
|
|
267
269
|
| [10-stages-and-config](https://github.com/ak9347128658/serverless_kit/tree/main/examples/10-stages-and-config) | Stages, variables, secrets |
|
|
268
270
|
| [11-custom-terraform](https://github.com/ak9347128658/serverless_kit/tree/main/examples/11-custom-terraform) | `terraform.extra`, `${tf:...}`, remote state, hooks |
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
[](https://pypi.org/project/py-serverless-kit/)
|
|
5
5
|
[](https://github.com/ak9347128658/serverless_kit/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
**Write your Python functions once. Deploy them to any of 10 clouds by changing one line of YAML.**
|
|
7
|
+
**Write your Python functions once. Deploy them to any of 10 clouds, or to your own machine, by changing one line of YAML.**
|
|
8
8
|
|
|
9
9
|
`py-serverless-kit` (CLI: `pskit`) is a Serverless-Framework-style toolkit built on **Terraform**. Your handlers use one small, provider-neutral API (`Event`, `Context`, `Response`). A `pskit.yml` file says which cloud they run on and what triggers them: HTTP, schedules, queues, storage, topics. The same file can also define workflows in the style of Step Functions. `pskit deploy` generates Terraform for the chosen cloud, applies it, and builds an HTML dashboard of everything you deployed.
|
|
10
10
|
|
|
11
11
|
```python
|
|
12
|
-
# app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare
|
|
12
|
+
# app/handlers.py - identical on AWS, Azure, GCP, Alibaba, Oracle, IBM, DigitalOcean, Tencent, Huawei, Cloudflare, and on premises
|
|
13
13
|
from py_serverless_kit import Event, Context, NotFound
|
|
14
14
|
|
|
15
15
|
def get_order(event: Event, ctx: Context):
|
|
@@ -23,7 +23,7 @@ def get_order(event: Event, ctx: Context):
|
|
|
23
23
|
# pskit.yml
|
|
24
24
|
service: orders
|
|
25
25
|
provider:
|
|
26
|
-
name: aws # <- change to gcp, azure,
|
|
26
|
+
name: aws # <- change to gcp, azure, onprem, ... and redeploy. That's the migration.
|
|
27
27
|
region: us-east-1
|
|
28
28
|
functions:
|
|
29
29
|
get-order:
|
|
@@ -53,7 +53,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
|
|
|
53
53
|
|
|
54
54
|
## Features
|
|
55
55
|
|
|
56
|
-
- **10
|
|
56
|
+
- **10 clouds and an on-premises host:** AWS Lambda, Azure Functions, Google Cloud Functions (gen2), Alibaba Function Compute, Oracle Functions, IBM Code Engine, DigitalOcean Functions, Tencent SCF, Huawei FunctionGraph, Cloudflare Workers, plus a process on your own machine or a remote server (`onprem`: local, SSH, Docker, or a bundled CPython when the server has no Python).
|
|
57
57
|
- **Triggers:** HTTP (path params, CORS, auth), schedules (rate/cron, translated into each cloud's cron dialect), queues, object storage, pub/sub topics, and direct function-to-function `invoke()`.
|
|
58
58
|
- **Workflows:** task / choice / wait / pass / parallel / map / succeed / fail with retry and catch. Native on AWS and GCP; an embedded engine on the other clouds; runnable locally with `pskit workflow run`.
|
|
59
59
|
- **Terraform underneath:** real, reviewable `main.tf.json`, any backend (S3, GCS, azurerm, ...), works with OpenTofu. Escape hatches: `terraform.extra`, `${tf:...}` references, per-function `options`.
|
|
@@ -76,6 +76,7 @@ Teams that build on AWS Lambda and Step Functions end up with code full of API G
|
|
|
76
76
|
| IBM Code Engine | beta | ✅ | – | – | – | – | embedded |
|
|
77
77
|
| Oracle Cloud Functions | experimental | ✅ | – | – | ✅ | – | embedded |
|
|
78
78
|
| Cloudflare Workers (Python) | experimental | ✅ | ✅ | – | – | – | embedded |
|
|
79
|
+
| On-premises | experimental | ✅ | ✅ | ✅ files | ✅ directory | ✅ files | embedded (local, SSH, or Docker) |
|
|
79
80
|
|
|
80
81
|
Run `pskit providers` for the live matrix. If a config uses a trigger the target cloud can't support, **`pskit validate` fails with a clear message instead of deploying something half-working.**
|
|
81
82
|
|
|
@@ -207,7 +208,7 @@ More: [docs/architecture.md](https://github.com/ak9347128658/serverless_kit/blob
|
|
|
207
208
|
|
|
208
209
|
## Examples
|
|
209
210
|
|
|
210
|
-
|
|
211
|
+
Sixteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658/serverless_kit/tree/main/examples/). They are tested in CI.
|
|
211
212
|
|
|
212
213
|
| | |
|
|
213
214
|
|---|---|
|
|
@@ -218,7 +219,8 @@ Fifteen runnable scenarios live in [`examples/`](https://github.com/ak9347128658
|
|
|
218
219
|
| [05-storage-events](https://github.com/ak9347128658/serverless_kit/tree/main/examples/05-storage-events) | Object created/deleted with filters |
|
|
219
220
|
| [06-pubsub-topic](https://github.com/ak9347128658/serverless_kit/tree/main/examples/06-pubsub-topic) | Topic fan-out and filters |
|
|
220
221
|
| [07-workflow-orders](https://github.com/ak9347128658/serverless_kit/tree/main/examples/07-workflow-orders) | Every workflow state type, retry/catch |
|
|
221
|
-
| [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all
|
|
222
|
+
| [08-multi-cloud](https://github.com/ak9347128658/serverless_kit/tree/main/examples/08-multi-cloud) | Same code, all 11 providers |
|
|
223
|
+
| [16-on-premises](https://github.com/ak9347128658/serverless_kit/tree/main/examples/16-on-premises) | HTTP, schedule, queue, storage, topic and a workflow on one machine |
|
|
222
224
|
| [09-function-invoke](https://github.com/ak9347128658/serverless_kit/tree/main/examples/09-function-invoke) | Function-to-function `invoke()` |
|
|
223
225
|
| [10-stages-and-config](https://github.com/ak9347128658/serverless_kit/tree/main/examples/10-stages-and-config) | Stages, variables, secrets |
|
|
224
226
|
| [11-custom-terraform](https://github.com/ak9347128658/serverless_kit/tree/main/examples/11-custom-terraform) | `terraform.extra`, `${tf:...}`, remote state, hooks |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# py-serverless-kit documentation
|
|
2
2
|
|
|
3
|
-
Write a Python function once, describe its triggers in `pskit.yml`, and deploy it to any of 10 clouds with Terraform. Moving to another
|
|
3
|
+
Write a Python function once, describe its triggers in `pskit.yml`, and deploy it to any of 10 clouds or to an on-premises host with Terraform. Moving to another target means changing `provider.name`. The handler code stays the same.
|
|
4
4
|
|
|
5
5
|
| Page | What it covers |
|
|
6
6
|
|---|---|
|
|
@@ -45,9 +45,12 @@ artifact.zip
|
|
|
45
45
|
├── <shim> pskit_entry.py (aws) · main.py (gcp) · function_app.py + host.json (azure)
|
|
46
46
|
│ index.py (alibaba/tencent/huawei) · __main__.py (ibm/do)
|
|
47
47
|
│ func.py + func.yaml + Dockerfile (oracle) · generated worker module (cloudflare)
|
|
48
|
+
│ onprem_handler.py (onprem; the host is started beside the zip)
|
|
48
49
|
└── dependencies or requirements.txt
|
|
49
50
|
```
|
|
50
51
|
|
|
52
|
+
On-premises also writes `.pskit/onprem-<stage>/onprem_app/` (`pskit_host.json`, `onprem_ctl.py`, `onprem_deploy.py`, the staged bundle, and a Dockerfile or systemd unit when those methods are selected). Terraform `local-exec` runs `onprem_deploy.py apply`, which starts the host on this machine, copies it over SSH (detached process or systemd, optional portable CPython), or builds a Docker image.
|
|
53
|
+
|
|
51
54
|
## Runtime flow
|
|
52
55
|
|
|
53
56
|
```
|
|
@@ -13,7 +13,7 @@ Every command that loads a project accepts:
|
|
|
13
13
|
| Flag | Meaning |
|
|
14
14
|
|---|---|
|
|
15
15
|
| `-c, --config FILE` | config file (default: `pskit.yml`, `pskit.yaml`, `serverless_kit.yml`, `serverless_kit.yaml`) |
|
|
16
|
-
| `-p, --provider NAME` | override `provider.name` (`aws`, `azure`, `gcp`, `alibaba`, `oracle`, `ibm`, `digitalocean`, `tencent`, `huawei`, `cloudflare`) |
|
|
16
|
+
| `-p, --provider NAME` | override `provider.name` (`aws`, `azure`, `gcp`, `alibaba`, `oracle`, `ibm`, `digitalocean`, `tencent`, `huawei`, `cloudflare`, `onprem`) |
|
|
17
17
|
| `-s, --stage NAME` | stage, e.g. `dev`, `staging`, `prod` |
|
|
18
18
|
| `-r, --region NAME` | override `provider.region` |
|
|
19
19
|
| `-v, --verbose` | print tracebacks on errors |
|
|
@@ -33,7 +33,7 @@ extends: base.yml # inherit another file (see below)
|
|
|
33
33
|
|
|
34
34
|
| Key | Type | Default | Notes |
|
|
35
35
|
|---|---|---|---|
|
|
36
|
-
| `name` | `aws` \| `azure` \| `gcp` \| `alibaba` \| `oracle` \| `ibm` \| `digitalocean` \| `tencent` \| `huawei` \| `cloudflare` | — | required (or `--provider`) |
|
|
36
|
+
| `name` | `aws` \| `azure` \| `gcp` \| `alibaba` \| `oracle` \| `ibm` \| `digitalocean` \| `tencent` \| `huawei` \| `cloudflare` \| `onprem` | — | required (or `--provider`) |
|
|
37
37
|
| `region` | string | provider default | e.g. `us-east-1`, `europe-west1`, `eastus` |
|
|
38
38
|
| `stage` | string | `dev` | `[a-z][a-z0-9-]{0,15}`; overridden by `--stage` |
|
|
39
39
|
| `runtime` | `python3.9` … `python3.14` | see [default runtime](#default-runtime) | provider support varies |
|
|
@@ -45,7 +45,7 @@ extends: base.yml # inherit another file (see below)
|
|
|
45
45
|
| `iam.statements` | list of `{effect, actions, resources}` | `[]` | AWS-style; `effect` defaults to `Allow`, `resources` to `["*"]`. Ignored (with a warning) on clouds that don't map it |
|
|
46
46
|
| `iam.role` | string | — | use an existing role / agency instead of creating one |
|
|
47
47
|
| `log_retention_days` | int or null | `14` | AWS CloudWatch log group retention |
|
|
48
|
-
| `options` | mapping | `{}` | provider-specific settings, see [providers.md](providers.md) |
|
|
48
|
+
| `options` | mapping | `{}` | provider-specific settings, see [providers.md](providers.md). On-premises: `deploy.method` is `local`, `ssh`, or `docker`; `python: bundle` ships an interpreter when the server has none |
|
|
49
49
|
| `state` | mapping | local state | see [state](#state-remote-terraform-backend) |
|
|
50
50
|
| `terraform` | mapping | | see [terraform](#terraform) |
|
|
51
51
|
|
|
@@ -189,7 +189,8 @@ Relative paths resolve from the extending file. Circular `extends` is an error.
|
|
|
189
189
|
|
|
190
190
|
So a child file's explicit values beat its parent's per-provider overrides.
|
|
191
191
|
2. `stages.<active stage>` (merged across all files; the child wins).
|
|
192
|
-
3.
|
|
192
|
+
3. `stages.<active stage>.providers.<active provider>`, when that stage must differ for one target (for example a cloud state backend on `prod` and local state for `onprem`).
|
|
193
|
+
4. CLI flags: `--provider`, `--stage`, `--region`.
|
|
193
194
|
|
|
194
195
|
Dicts are deep-merged; lists are replaced, not appended.
|
|
195
196
|
|
|
@@ -18,13 +18,13 @@ A function with no events is *invoke-only*: it can be called by workflows, by `i
|
|
|
18
18
|
|
|
19
19
|
Support at a glance (the full detail is below and in [providers.md](providers.md)):
|
|
20
20
|
|
|
21
|
-
| Trigger | aws | gcp | azure | alibaba | oracle | ibm | digitalocean | tencent | huawei | cloudflare |
|
|
22
|
-
|
|
23
|
-
| `http` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓¹ | ✓ |
|
|
24
|
-
| `schedule` | ✓ | ✓ | ✓ | ✓ | – | – | ✓ | ✓ | ✓ | ✓ |
|
|
25
|
-
| `queue` | ✓ SQS | ✓ Pub/Sub | ✓ Storage Queue | – | – | – | – | – | – | – |
|
|
26
|
-
| `storage` | ✓ S3 | ✓ GCS | ✓ Blob (created only) | ✓ OSS | ✓ Object Storage | – | – | ✓ COS | ✓ OBS | – |
|
|
27
|
-
| `topic` | ✓ SNS | ✓ Pub/Sub | ✓ Service Bus | ✓ MNS | – | – | – | – | ✓ SMN | – |
|
|
21
|
+
| Trigger | aws | gcp | azure | alibaba | oracle | ibm | digitalocean | tencent | huawei | cloudflare | onprem |
|
|
22
|
+
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
23
|
+
| `http` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓¹ | ✓ | ✓ |
|
|
24
|
+
| `schedule` | ✓ | ✓ | ✓ | ✓ | – | – | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
25
|
+
| `queue` | ✓ SQS | ✓ Pub/Sub | ✓ Storage Queue | – | – | – | – | – | – | – | ✓ files |
|
|
26
|
+
| `storage` | ✓ S3 | ✓ GCS | ✓ Blob (created only) | ✓ OSS | ✓ Object Storage | – | – | ✓ COS | ✓ OBS | – | ✓ directory |
|
|
27
|
+
| `topic` | ✓ SNS | ✓ Pub/Sub | ✓ Service Bus | ✓ MNS | – | – | – | – | ✓ SMN | – | ✓ files |
|
|
28
28
|
|
|
29
29
|
¹ Huawei HTTP needs `provider.options.apig_instance_id`.
|
|
30
30
|
|
|
@@ -110,6 +110,7 @@ pskit converts the portable syntax to each cloud's dialect:
|
|
|
110
110
|
| huawei | timer trigger | `Rate` (`5m`) or 6-field cron with `?` |
|
|
111
111
|
| digitalocean | `project.yml` scheduler trigger | 5-field cron |
|
|
112
112
|
| cloudflare | Cron Triggers | 5-field cron |
|
|
113
|
+
| onprem | in-process scheduler | rate in seconds, or 5-field cron. A rate such as `7 minutes` is valid here |
|
|
113
114
|
|
|
114
115
|
A rate that can't be expressed as cron on cron-only clouds (e.g. `7 minutes`) fails validation; use a divisor of 60 minutes or 24 hours. `timezone` is honoured by AWS, GCP and Alibaba (cron form); Azure ignores it with a warning.
|
|
115
116
|
|
|
@@ -139,6 +140,8 @@ The handler gets `event.type == "queue"` and `event.records`, one `Record` per m
|
|
|
139
140
|
| `fifo` | ✓ (`.fifo` suffix, content-based dedup) | ignored (warning) | ignored (warning) |
|
|
140
141
|
| partial batch failure | ✓ `batchItemFailures` | whole delivery retried | whole delivery retried |
|
|
141
142
|
|
|
143
|
+
On premises the same options are implemented by a file broker (`batch_size`, `batch_window`, visibility, dead-letter, `max_receive`, `fifo`). `BatchResult` retries only the failed message ids, as on AWS. Set `provider.options.services.queue` to `builtin` (created at start) or `{use: directory, path: ...}`. `existing: true` waits for that directory. Example: [`examples/04-queue-worker`](../examples/04-queue-worker) and [`examples/16-on-premises`](../examples/16-on-premises).
|
|
144
|
+
|
|
142
145
|
On GCP a "queue" is a Pub/Sub topic with a push trigger, because GCP has no SQS-style pull trigger. Azure queue names must be 3–63 lowercase letters, digits and dashes. Example: [`examples/04-queue-worker`](../examples/04-queue-worker).
|
|
143
146
|
|
|
144
147
|
---
|
|
@@ -166,6 +169,7 @@ Each record has `bucket`, `key`, `size` and `action` (`"created"` / `"deleted"`)
|
|
|
166
169
|
| oracle | Events rule | not supported (warning) – filter in your handler | bucket must have "Emit Object Events" enabled |
|
|
167
170
|
| tencent | COS trigger | native | bucket name must be `<name>-<APPID>`, e.g. `uploads-1250000000` |
|
|
168
171
|
| huawei | OBS trigger | native | |
|
|
172
|
+
| onprem | a directory of files | prefix/suffix in the host | `created` and `deleted`. `builtin` creates the directory; `{use: directory, path}` uses one you already have. The first start records current files and does not emit them |
|
|
169
173
|
|
|
170
174
|
Example: [`examples/05-storage-events`](../examples/05-storage-events).
|
|
171
175
|
|
|
@@ -188,6 +192,7 @@ Example: [`examples/05-storage-events`](../examples/05-storage-events).
|
|
|
188
192
|
| azure | Service Bus topic + subscription | not applied (warning); `existing` needs `options.servicebus_namespace_id` and `options.servicebus_connection` |
|
|
189
193
|
| alibaba | MNS topic | `filter.tag` (string) only |
|
|
190
194
|
| huawei | SMN topic | – |
|
|
195
|
+
| onprem | file topic, fan-out | exact match on attributes, then on JSON body fields |
|
|
191
196
|
|
|
192
197
|
Example: [`examples/06-pubsub-topic`](../examples/06-pubsub-topic).
|
|
193
198
|
|
|
@@ -109,6 +109,7 @@ pskit runs Terraform, so credentials come from each Terraform provider's standar
|
|
|
109
109
|
| `tencent` | `TENCENTCLOUD_SECRET_ID` / `TENCENTCLOUD_SECRET_KEY`, or `options.profile` |
|
|
110
110
|
| `huawei` | `HW_ACCESS_KEY` / `HW_SECRET_KEY` (+ `HW_REGION_NAME`), or `options.profile` |
|
|
111
111
|
| `cloudflare` | `CLOUDFLARE_API_TOKEN`. `options.account_id` is required |
|
|
112
|
+
| `onprem` | local: nothing to configure (the Python that runs `pskit` starts the host). Remote: OpenSSH and `options.deploy.method: ssh`, or Docker and `method: docker`. Servers without Python: `python: bundle` or Docker |
|
|
112
113
|
|
|
113
114
|
Provider-specific required options are listed in [providers.md](providers.md).
|
|
114
115
|
|
|
@@ -156,6 +156,7 @@ def worker(event, ctx):
|
|
|
156
156
|
| Provider | Behaviour |
|
|
157
157
|
|---|---|
|
|
158
158
|
| aws (SQS) | becomes `batchItemFailures`, so only the failed messages are retried |
|
|
159
|
+
| onprem | the host retries only the failed message ids, and moves a message to `dead_letter` after `max_receive` |
|
|
159
160
|
| local | printed as `batchItemFailures` |
|
|
160
161
|
| everyone else | any failure raises `BatchFailure`, so the whole delivery is retried |
|
|
161
162
|
|
|
@@ -173,7 +174,7 @@ invoke("audit", {"order_id": 42}, asynchronous=True) # fire and forget
|
|
|
173
174
|
How the target is resolved:
|
|
174
175
|
|
|
175
176
|
1. If `PSKIT_ENDPOINT_<NAME>` is set (`billing` → `PSKIT_ENDPOINT_BILLING`, non-alphanumerics become `_`), pskit POSTs to that http(s) URL. This works on any provider.
|
|
176
|
-
2. `local` (CLI, tests)
|
|
177
|
+
2. `local` (CLI, tests) and `onprem`: call the handler in-process. `asynchronous=True` still finishes before `invoke()` returns.
|
|
177
178
|
3. `aws`: `lambda:InvokeFunction` via boto3 (`pip install py-serverless-kit[aws]`, and add `boto3` to requirements). Grant `lambda:InvokeFunction` in `iam.statements`.
|
|
178
179
|
4. `gcp`: authenticated HTTPS call to `https://<region>-<project>.cloudfunctions.net/<service>-<stage>-<name>` with an ID token from the metadata server.
|
|
179
180
|
5. Other providers raise `InvokeError` unless `PSKIT_ENDPOINT_<NAME>` is set. Point it at the target's HTTP URL from `pskit info`. On Azure, invoke-only functions expose `POST /_pskit/invoke/<name>` (function key required).
|
|
@@ -186,7 +187,8 @@ pskit injects:
|
|
|
186
187
|
|
|
187
188
|
| Variable | Value |
|
|
188
189
|
|---|---|
|
|
189
|
-
| `PSKIT_PROVIDER` | `aws`, `gcp`, … (`local` under the CLI) |
|
|
190
|
+
| `PSKIT_PROVIDER` | `aws`, `gcp`, `onprem`, … (`local` under the CLI) |
|
|
191
|
+
| `PSKIT_ONPREM_ROOT` | on-premises only: directory of the running host. Handlers use it to publish into the file broker |
|
|
190
192
|
| `PSKIT_SERVICE`, `PSKIT_STAGE`, `PSKIT_REGION` | deployment identity |
|
|
191
193
|
| `PSKIT_FUNCTION`, `PSKIT_HANDLER` | the logical function and its handler (not app settings on Azure, where they're passed explicitly) |
|
|
192
194
|
| `PSKIT_GCP_PROJECT` | GCP only |
|
|
@@ -92,6 +92,10 @@ def test_workflow():
|
|
|
92
92
|
| `LocalRunner(project, env_file=".env")` | in-process runner |
|
|
93
93
|
| `runner.invoke(function, event)` | run a handler; HTTP returns a `Response` |
|
|
94
94
|
| `runner.run_workflow(name, data, sleep=False)` | returns `{"output", "history"}`; raises `WorkflowFailed` |
|
|
95
|
+
|
|
96
|
+
## On-premises is a deploy, not `pskit dev`
|
|
97
|
+
|
|
98
|
+
`pskit dev` reloads HTTP handlers and drops the process when you stop it. `provider.name: onprem` is the durable run: `pskit deploy` starts a process that keeps schedules, file queues, directory storage, topics and embedded workflows after the command returns. `options.deploy.method` is `local` (this machine), `ssh`, or `docker`. See [providers.md](providers.md#onprem-on-premises), [`examples/16-on-premises`](../examples/16-on-premises) and [`examples/17-on-premises-remote`](../examples/17-on-premises-remote).
|
|
95
99
|
| `http_event(method, path, body=None, headers=None, query=None)` | dict/list bodies are JSON-encoded; `?query` in `path` is parsed |
|
|
96
100
|
| `build_event(type, data, **http)` | `queue`/`topic` (list → records), `storage` (`{"bucket", "key", "size", "action"}`), `schedule`, `invoke`, `workflow`, `http` |
|
|
97
101
|
|
|
@@ -14,12 +14,13 @@ Run `pskit providers` (or `pskit providers --json`) to print this matrix from th
|
|
|
14
14
|
| [`digitalocean`](#digitalocean-functions) | beta | ✓ | ✓ | – | – | – | embedded | 3.9, 3.11 | 900 s |
|
|
15
15
|
| [`oracle`](#oracle-oci-functions) | experimental | ✓ | – | – | ✓ | – | embedded | 3.9, 3.11 | 300 s |
|
|
16
16
|
| [`cloudflare`](#cloudflare-python-workers) | experimental | ✓ | ✓ | – | – | – | embedded | 3.11–3.13 | 900 s |
|
|
17
|
+
| [`onprem`](#onprem-on-premises) | experimental | ✓ | ✓ | ✓ | ✓ | ✓ | embedded | 3.9–3.14 | 3600 s |
|
|
17
18
|
|
|
18
19
|
**Tiers**
|
|
19
20
|
|
|
20
21
|
- **stable:** the generated Terraform is validated against the real provider plugin, and the full trigger set is supported.
|
|
21
22
|
- **beta:** validated with `terraform validate`; event payload formats follow vendor documentation.
|
|
22
|
-
- **experimental:** works with notable constraints (container images, Pyodide), so read the section below first.
|
|
23
|
+
- **experimental:** works with notable constraints (container images, Pyodide, or a process on your own machine), so read the section below first.
|
|
23
24
|
|
|
24
25
|
**Common to all providers**
|
|
25
26
|
|
|
@@ -27,7 +28,7 @@ Run `pskit providers` (or `pskit providers --json`) to print this matrix from th
|
|
|
27
28
|
- Resources are tagged or labelled with `pskit-service`, `pskit-stage` and `managed-by: py-serverless-kit` where the cloud supports tags.
|
|
28
29
|
- With no pinned `runtime`, pskit picks python3.12 or the newest version below it that the cloud supports (see [configuration.md](configuration.md#default-runtime)).
|
|
29
30
|
|
|
30
|
-
Every generated configuration (all
|
|
31
|
+
Every generated configuration (all 11 providers) passes `terraform validate`. The repository's `scripts/validate_all_providers.py` re-checks this in CI. On-premises uses Terraform's built-in provider, so that check does not download a plugin for it.
|
|
31
32
|
|
|
32
33
|
---
|
|
33
34
|
|
|
@@ -353,6 +354,104 @@ One Worker script per function. pskit generates a single Python module per Worke
|
|
|
353
354
|
|
|
354
355
|
---
|
|
355
356
|
|
|
357
|
+
## onprem (On-premises)
|
|
358
|
+
|
|
359
|
+
- **Terraform:** built-in `terraform_data` (no plugin download). Create/destroy run `onprem_deploy.py` via `local-exec`
|
|
360
|
+
- **Credentials:** none for `method: local`. SSH keys / an SSH agent for `method: ssh`. Docker CLI (and optional `DOCKER_HOST`) for `method: docker`
|
|
361
|
+
- **Dependencies:** native pip wheels for a local host; manylinux / Windows / macOS wheels matching `deploy.target_os` and `architecture` for a remote host. `tzdata` is vendored so cron timezones work on Windows
|
|
362
|
+
|
|
363
|
+
```yaml
|
|
364
|
+
provider:
|
|
365
|
+
name: onprem
|
|
366
|
+
region: local
|
|
367
|
+
options:
|
|
368
|
+
host: 127.0.0.1 # bind address on the *target*. 0.0.0.0 is advertised as 127.0.0.1 unless advertise is set
|
|
369
|
+
port: 8080 # 1-65535. Give each service its own port
|
|
370
|
+
advertise: https://fn.internal.example # optional URL written into outputs
|
|
371
|
+
data_dir: .pskit/onprem-data # default .pskit/onprem-data/<service>-<stage> (local); <path>/data on SSH
|
|
372
|
+
poll_seconds: 0.5
|
|
373
|
+
admin_token: "${env:PSKIT_ADMIN_TOKEN, }" # header x-pskit-token on /__pskit/* except health
|
|
374
|
+
services:
|
|
375
|
+
schedule: builtin # the only schedule implementation
|
|
376
|
+
queue: builtin # or {use: directory, path: /var/pskit/queues}
|
|
377
|
+
storage: {use: directory, path: .onprem/buckets}
|
|
378
|
+
topic: builtin
|
|
379
|
+
workflow: embedded # builtin is an alias of embedded
|
|
380
|
+
deploy:
|
|
381
|
+
method: local # local | ssh | docker (default local)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
`pskit deploy` writes the bundle under `.pskit/onprem-<stage>/onprem_app/` and runs `onprem_deploy.py apply`. `pskit remove` stops the process (or container / systemd unit) and does not delete `data_dir`.
|
|
385
|
+
|
|
386
|
+
Omitted services default to `builtin` and are created at start. `existing: true` on one queue, bucket or topic skips that create and waits until the directory appears. Names are a single path segment (`..`, slashes and NUL are rejected).
|
|
387
|
+
|
|
388
|
+
| Trigger | Implementation |
|
|
389
|
+
|---|---|
|
|
390
|
+
| http | the host process. `auth` must be `none` (check tokens in the handler) |
|
|
391
|
+
| schedule | in-process rate (any positive number of minutes, hours or days, including values that are not cron) and 5-field cron. A missing IANA timezone warns and is evaluated in UTC |
|
|
392
|
+
| queue | one JSON file per message. `batch_size`, `batch_window`, `visibility_timeout` (default `max(30, 6 x timeout)`), `dead_letter`, `max_receive` and `fifo` are honoured. `BatchResult` retries only the failed ids |
|
|
393
|
+
| storage | files under `<bucket>/<key>`. `prefix`, `suffix`, `created` and `deleted`. The first start records the current files and does not emit them |
|
|
394
|
+
| topic | fan-out. `filter` is an exact match on message attributes, then on JSON body fields |
|
|
395
|
+
| workflows | embedded engine inside the host, so a workflow is not cut off by a function timeout |
|
|
396
|
+
|
|
397
|
+
Publish from outside the process:
|
|
398
|
+
|
|
399
|
+
| Request | Effect |
|
|
400
|
+
|---|---|
|
|
401
|
+
| `GET /__pskit/health` | status, no token |
|
|
402
|
+
| `POST /__pskit/queues/<name>` | enqueue one JSON value, a list, or `{"messages": [...]}`. `202 {"queued": [ids]}` |
|
|
403
|
+
| `GET /__pskit/queues/<name>` | `{"depth": n}` |
|
|
404
|
+
| `POST /__pskit/topics/<name>` | publish, then deliver. `{"message", "attributes"}` sets attributes when those are the only keys |
|
|
405
|
+
| `PUT` / `DELETE /__pskit/storage/<bucket>/<key>` | write or remove an object, then deliver |
|
|
406
|
+
| `POST /__pskit/invoke/<function>` | in-process invoke |
|
|
407
|
+
| `POST /__pskit/workflows/<name>` | run the embedded workflow |
|
|
408
|
+
|
|
409
|
+
From a handler in that process (`PSKIT_ONPREM_ROOT` is set), call `submit_queue`, `submit_topic`, `put_object` or `delete_object` in `py_serverless_kit.runtime.onprem_host`.
|
|
410
|
+
|
|
411
|
+
**Deploy targets** (`options.deploy`)
|
|
412
|
+
|
|
413
|
+
| `method` | What runs | Target needs | Laptop needs |
|
|
414
|
+
|---|---|---|---|
|
|
415
|
+
| `local` (default) | detached process on this machine | Python (the interpreter that runs `pskit`) | — |
|
|
416
|
+
| `ssh` | process or systemd unit on a remote host | SSH. Python only if `python: system` | OpenSSH (`ssh`, `scp`) |
|
|
417
|
+
| `docker` | `docker build` + `docker run` | Docker engine, not Python | Docker CLI; set `docker_host: ssh://user@host` to use a remote daemon |
|
|
418
|
+
|
|
419
|
+
When the server has **no Python**, use `python: bundle` (a portable CPython from [python-build-standalone](https://github.com/astral-sh/python-build-standalone) is fetched at apply and copied with the app) or `method: docker` (the image is `FROM python:<minor>-slim`). Air-gapped: `python_home` (copy a tree you already have) or `python_url` + `python_sha256` (internal mirror of an `install_only` tarball).
|
|
420
|
+
|
|
421
|
+
```yaml
|
|
422
|
+
# SSH + portable CPython + systemd (server does not need Python)
|
|
423
|
+
deploy:
|
|
424
|
+
method: ssh
|
|
425
|
+
host: 10.0.1.12 # or deploy: ssh://pskit@10.0.1.12/opt/pskit/orders
|
|
426
|
+
user: pskit
|
|
427
|
+
port: 22
|
|
428
|
+
identity_file: ${env:PSKIT_SSH_KEY} # optional; otherwise the SSH agent
|
|
429
|
+
known_hosts: accept-new # accept-new | ignore | path to a known_hosts file
|
|
430
|
+
path: /opt/pskit/orders
|
|
431
|
+
python: bundle # auto | system | bundle
|
|
432
|
+
target_os: linux # auto | linux | windows | darwin
|
|
433
|
+
target_arch: x86_64 # auto | x86_64 | arm64 (drives pip wheels)
|
|
434
|
+
install: systemd # process | systemd (linux only)
|
|
435
|
+
sudo: true # needed to write /etc/systemd/system
|
|
436
|
+
|
|
437
|
+
# Docker (server needs Docker, not Python)
|
|
438
|
+
deploy:
|
|
439
|
+
method: docker
|
|
440
|
+
image: pskit/orders:dev
|
|
441
|
+
docker_host: ssh://pskit@10.0.1.12 # empty = Docker on this laptop
|
|
442
|
+
restart: unless-stopped
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
`options.host` is the bind address **on the target**. Use `0.0.0.0` so other machines can call a remote host. `advertise` is the URL stored in `pskit info`. SSH deploy defaults `advertise` to `http://<ssh host>:<port>` when it is unset.
|
|
446
|
+
|
|
447
|
+
**Resources:** `terraform_data.host` with create (`onprem_deploy.py apply`) and destroy (`onprem_deploy.py destroy`) `local-exec` provisioners.
|
|
448
|
+
|
|
449
|
+
**Limits:** no cloud authorizer and no IAM mapping. A `terraform.extra` resource from another cloud (`aws_*`, `google_*`, `azurerm_*`, and the other cloud prefixes) is omitted with a warning. A state backend of `s3`, `gcs` or `azurerm` warns; set `provider.state.backend` empty (see `providers.onprem` in examples 11 and 15) to keep state on this machine. Delivery is at-least-once. A missed schedule fires once on the next poll, not as a burst. The host does not kill a handler at `timeout`; `ctx.remaining_time_ms()` still counts down. If `method` is `local` and `provider.runtime` is not the interpreter running `pskit`, validation warns and the host still uses that interpreter. `python: bundle` needs network on first apply unless `python_home` or a cached archive under `~/.cache/pskit/python-standalone` is present. systemd units are written to `/etc/systemd/system` (set `sudo: true` unless the SSH user is root).
|
|
450
|
+
|
|
451
|
+
Examples: [`examples/16-on-premises`](../examples/16-on-premises) (local process), [`examples/17-on-premises-remote`](../examples/17-on-premises-remote) (SSH / Docker / bundled Python).
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
356
455
|
## Writing your own provider
|
|
357
456
|
|
|
358
457
|
See [architecture.md](architecture.md#third-party-providers) and [`deploy_docs/CONTRIBUTING.md`](../deploy_docs/CONTRIBUTING.md).
|
|
@@ -82,6 +82,7 @@ Add `-v` to any command to see the full traceback. Start with `pskit validate`,
|
|
|
82
82
|
| digitalocean | `doctl` must be installed and authenticated (`doctl auth init`); `options.namespace` required; set `options.api_host` to get URLs |
|
|
83
83
|
| ibm | HTTP only, python3.11 only, 120 s / 4 GB max; large bundles → `options.code_reference` |
|
|
84
84
|
| cloudflare | Pyodide: only stdlib and Pyodide packages; `options.account_id` and `CLOUDFLARE_API_TOKEN` required; non-`.py` files aren't uploaded |
|
|
85
|
+
| onprem | one process per service, so give each service its own `options.port`. `pskit remove` stops it and leaves `data_dir`. `auth` must be `none`. A cloud `terraform.extra` resource is omitted. Set `state.backend` empty when the file points at S3, GCS or Azure Storage. Remote SSH needs `ssh`/`scp` on the laptop; a server without Python needs `deploy.python: bundle` or `method: docker`. systemd writes `/etc/systemd/system` (`sudo: true`). Bind `options.host: 0.0.0.0` on a remote host so other machines can call it |
|
|
85
86
|
| alibaba / tencent / huawei | `iam.statements` aren't translated; set `iam.role` |
|
|
86
87
|
|
|
87
88
|
## FAQ
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A workflow chains functions with branching, retries, error handling, waits, parallel branches and fan-out. You define it once in `pskit.yml`, and pskit runs it:
|
|
4
4
|
|
|
5
5
|
- **natively**, as AWS Step Functions (ASL) or Google Cloud Workflows;
|
|
6
|
-
- on the **embedded engine** on every other
|
|
6
|
+
- on the **embedded engine** on every other target, inside an auto-generated orchestrator function (on premises that function runs inside the long-lived host, so the workflow is not cut off by a function timeout);
|
|
7
7
|
- **locally** with `pskit workflow run`, using the same engine.
|
|
8
8
|
|
|
9
9
|
```yaml
|
|
@@ -20,6 +20,7 @@ return result
|
|
|
20
20
|
| Cloud | What `BatchResult` does |
|
|
21
21
|
| --- | --- |
|
|
22
22
|
| AWS SQS | partial batch response: only failed messages are retried |
|
|
23
|
+
| On-premises | partial batch response: only failed messages are retried, then dead-lettered |
|
|
23
24
|
| GCP Pub/Sub, Azure Storage Queues, others | any failure fails the invocation, so the whole batch is redelivered |
|
|
24
25
|
|
|
25
26
|
Make processing **idempotent**: on most clouds a message can be delivered more than once.
|
|
@@ -34,6 +35,8 @@ Make processing **idempotent**: on most clouds a message can be delivered more t
|
|
|
34
35
|
| `fifo` | SQS FIFO | warning | not supported |
|
|
35
36
|
| `existing: true` | look up instead of create | yes | yes |
|
|
36
37
|
|
|
38
|
+
On premises every option in the YAML is implemented by a directory of message files. `builtin` (the default) creates that directory at start. `{use: directory, path: ...}` under `provider.options.services.queue` uses a directory you already have.
|
|
39
|
+
|
|
37
40
|
`pskit validate --provider <cloud>` prints the warnings for your configuration.
|
|
38
41
|
|
|
39
42
|
## The producer
|
|
@@ -53,7 +56,7 @@ def send_job(job: dict) -> None:
|
|
|
53
56
|
...
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
The example's `enqueue` handler
|
|
59
|
+
The example's `enqueue` handler logs on a cloud, so it runs anywhere without credentials. On premises (`PSKIT_ONPREM_ROOT`) it writes the job into the file queue with `submit_queue`.
|
|
57
60
|
|
|
58
61
|
## Run locally
|
|
59
62
|
|
|
@@ -77,4 +80,5 @@ pskit invoke -f enqueue -d '{"kind": "invoice", "id": 7}' # 202
|
|
|
77
80
|
pskit deploy # SQS queues + DLQ + event source mappings
|
|
78
81
|
pskit deploy --provider gcp # Pub/Sub topics + Eventarc triggers
|
|
79
82
|
pskit deploy --provider azure # Storage queues + queue triggers
|
|
83
|
+
pskit deploy --provider onprem # file queues on this machine, http://127.0.0.1:8084
|
|
80
84
|
```
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
``event.records`` holds the messages of one batch. Return a ``BatchResult``
|
|
4
4
|
naming the records that failed:
|
|
5
5
|
|
|
6
|
-
* AWS SQS:
|
|
7
|
-
(``ReportBatchItemFailures``
|
|
6
|
+
* AWS SQS and the on-premises host: only those messages become visible again
|
|
7
|
+
and are retried (``ReportBatchItemFailures`` on AWS);
|
|
8
8
|
* other clouds: any failure fails the invocation, so the whole batch is redelivered.
|
|
9
9
|
|
|
10
10
|
Either way a message that keeps failing ends up in the dead-letter queue
|
|
@@ -62,14 +62,20 @@ def _log_dead_letter(record: Record, ctx: Context) -> None:
|
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
def enqueue(event: Event, ctx: Context):
|
|
65
|
-
"""HTTP producer
|
|
65
|
+
"""HTTP producer.
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
``send_message``
|
|
70
|
-
that
|
|
71
|
-
|
|
67
|
+
On premises the host is in this process, so the message is written to the
|
|
68
|
+
file queue. On a cloud, publishing is a cloud SDK call (boto3
|
|
69
|
+
``sqs.send_message``, ``google-cloud-pubsub`` ``publish``,
|
|
70
|
+
``azure-storage-queue`` ``send_message``). Keep that call behind a small
|
|
71
|
+
function of your own (see README).
|
|
72
72
|
"""
|
|
73
73
|
job = event.http.json()
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
queue = ctx.env.get("JOBS_QUEUE") or "jobs"
|
|
75
|
+
if ctx.env.get("PSKIT_ONPREM_ROOT"):
|
|
76
|
+
from py_serverless_kit.runtime.onprem_host import submit_queue
|
|
77
|
+
|
|
78
|
+
message_id = submit_queue(queue, job)
|
|
79
|
+
return {"accepted": True, "queue": queue, "message_id": message_id}, 202
|
|
80
|
+
ctx.logger.info("would enqueue", extra={"job": job, "queue": queue})
|
|
81
|
+
return {"accepted": True, "queue": queue}, 202
|
|
@@ -52,3 +52,12 @@ providers:
|
|
|
52
52
|
audit-existing:
|
|
53
53
|
events:
|
|
54
54
|
- storage: {bucket: audit-uploads, events: [created]}
|
|
55
|
+
onprem:
|
|
56
|
+
region: local
|
|
57
|
+
options: {host: 127.0.0.1, port: 8085}
|
|
58
|
+
# The shared audit bucket is not on this machine. Create a local directory
|
|
59
|
+
# bucket with the host so the function has somewhere to listen.
|
|
60
|
+
functions:
|
|
61
|
+
audit-existing:
|
|
62
|
+
events:
|
|
63
|
+
- storage: {bucket: shared-uploads, events: [created, deleted]}
|