py-serverless-kit 0.2.0__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.
Files changed (244) hide show
  1. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/CHANGELOG.md +11 -0
  2. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/PKG-INFO +3 -3
  3. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/README.md +2 -2
  4. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/architecture.md +3 -1
  5. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/configuration.md +1 -1
  6. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/getting-started.md +1 -1
  7. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/local-development.md +1 -1
  8. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/providers.md +47 -9
  9. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/troubleshooting.md +1 -1
  10. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/16-on-premises/README.md +3 -0
  11. py_serverless_kit-0.3.0/examples/17-on-premises-remote/README.md +97 -0
  12. py_serverless_kit-0.3.0/examples/17-on-premises-remote/app/__init__.py +1 -0
  13. py_serverless_kit-0.3.0/examples/17-on-premises-remote/app/handlers.py +16 -0
  14. py_serverless_kit-0.3.0/examples/17-on-premises-remote/pskit.yml +60 -0
  15. py_serverless_kit-0.3.0/examples/17-on-premises-remote/requirements.txt +1 -0
  16. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/README.md +1 -0
  17. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/_version.py +1 -1
  18. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/templates.py +3 -0
  19. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/packaging/builder.py +1 -1
  20. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/base.py +3 -0
  21. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/onprem.py +183 -57
  22. py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem_remote.py +381 -0
  23. py_serverless_kit-0.3.0/src/py_serverless_kit/providers/onprem_spec.py +404 -0
  24. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/onprem_host.py +3 -3
  25. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_onprem.py +129 -2
  26. py_serverless_kit-0.3.0/tests/providers/test_onprem_remote.py +148 -0
  27. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/test_examples.py +2 -1
  28. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/.gitignore +0 -0
  29. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/CONTRIBUTING.md +0 -0
  30. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/LICENSE +0 -0
  31. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/deploy_docs/CONTRIBUTING.md +0 -0
  32. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/README.md +0 -0
  33. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/cli.md +0 -0
  34. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/dashboard.md +0 -0
  35. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/events.md +0 -0
  36. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/handlers.md +0 -0
  37. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/migrating-from-aws.md +0 -0
  38. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/docs/workflows.md +0 -0
  39. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/01-hello-http/README.md +0 -0
  40. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/01-hello-http/app/__init__.py +0 -0
  41. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/01-hello-http/app/handlers.py +0 -0
  42. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/01-hello-http/pskit.yml +0 -0
  43. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/01-hello-http/requirements.txt +0 -0
  44. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/02-rest-api/README.md +0 -0
  45. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/__init__.py +0 -0
  46. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/handlers.py +0 -0
  47. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/02-rest-api/app/store.py +0 -0
  48. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/02-rest-api/pskit.yml +0 -0
  49. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/02-rest-api/requirements.txt +0 -0
  50. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/README.md +0 -0
  51. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/app/__init__.py +0 -0
  52. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/app/jobs.py +0 -0
  53. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/pskit.yml +0 -0
  54. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/03-scheduled-jobs/requirements.txt +0 -0
  55. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/04-queue-worker/README.md +0 -0
  56. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/04-queue-worker/app/__init__.py +0 -0
  57. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/04-queue-worker/app/worker.py +0 -0
  58. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/04-queue-worker/pskit.yml +0 -0
  59. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/04-queue-worker/requirements.txt +0 -0
  60. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/05-storage-events/README.md +0 -0
  61. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/05-storage-events/app/__init__.py +0 -0
  62. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/05-storage-events/app/files.py +0 -0
  63. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/05-storage-events/pskit.yml +0 -0
  64. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/05-storage-events/requirements.txt +0 -0
  65. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/README.md +0 -0
  66. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/app/__init__.py +0 -0
  67. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/app/subscribers.py +0 -0
  68. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/pskit.yml +0 -0
  69. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/06-pubsub-topic/requirements.txt +0 -0
  70. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/README.md +0 -0
  71. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/app/__init__.py +0 -0
  72. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/app/orders.py +0 -0
  73. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/b2b.json +0 -0
  74. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/declined.json +0 -0
  75. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/events/happy.json +0 -0
  76. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/pskit.yml +0 -0
  77. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/07-workflow-orders/requirements.txt +0 -0
  78. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/README.md +0 -0
  79. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/app/__init__.py +0 -0
  80. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/app/handlers.py +0 -0
  81. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.aws.yml +0 -0
  82. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.azure.yml +0 -0
  83. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.gcp.yml +0 -0
  84. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/pskit.yml +0 -0
  85. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/08-multi-cloud/requirements.txt +0 -0
  86. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/09-function-invoke/README.md +0 -0
  87. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/09-function-invoke/app/__init__.py +0 -0
  88. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/09-function-invoke/app/quotes.py +0 -0
  89. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/09-function-invoke/pskit.yml +0 -0
  90. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/09-function-invoke/requirements.txt +0 -0
  91. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/.env.example +0 -0
  92. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/README.md +0 -0
  93. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/__init__.py +0 -0
  94. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/handlers.py +0 -0
  95. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/app/settings.py +0 -0
  96. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/config/limits.json +0 -0
  97. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/pskit.yml +0 -0
  98. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/10-stages-and-config/requirements.txt +0 -0
  99. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/README.md +0 -0
  100. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/__init__.py +0 -0
  101. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/handlers.py +0 -0
  102. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/app/repository.py +0 -0
  103. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/pskit.yml +0 -0
  104. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/requirements.txt +0 -0
  105. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/scripts/smoke_test.py +0 -0
  106. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/11-custom-terraform/tests/test_orders.py +0 -0
  107. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/12-async-and-context/README.md +0 -0
  108. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/12-async-and-context/app/__init__.py +0 -0
  109. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/12-async-and-context/app/handlers.py +0 -0
  110. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/12-async-and-context/pskit.yml +0 -0
  111. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/12-async-and-context/requirements.txt +0 -0
  112. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/README.md +0 -0
  113. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/app/__init__.py +0 -0
  114. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/app/orders.py +0 -0
  115. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/pskit.yml +0 -0
  116. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/after/requirements.txt +0 -0
  117. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/lambda_function.py +0 -0
  118. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/state_machine.asl.json +0 -0
  119. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/13-migrate-from-aws-lambda/before/template.yaml +0 -0
  120. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/README.md +0 -0
  121. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/app/__init__.py +0 -0
  122. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/app/handlers.py +0 -0
  123. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/ci.github-workflow.yml +0 -0
  124. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/pskit.yml +0 -0
  125. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/requirements.txt +0 -0
  126. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/tests/conftest.py +0 -0
  127. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/tests/test_handlers.py +0 -0
  128. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/14-testing/tests/test_workflow.py +0 -0
  129. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/README.md +0 -0
  130. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/app/__init__.py +0 -0
  131. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/app/handlers.py +0 -0
  132. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/deploy.github-workflow.yml +0 -0
  133. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/pskit.yml +0 -0
  134. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/15-ci-cd-deploy/requirements.txt +0 -0
  135. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/16-on-premises/app/__init__.py +0 -0
  136. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/16-on-premises/app/handlers.py +0 -0
  137. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/16-on-premises/pskit.yml +0 -0
  138. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/examples/16-on-premises/requirements.txt +0 -0
  139. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/pyproject.toml +0 -0
  140. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/__init__.py +0 -0
  141. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/__main__.py +0 -0
  142. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/__init__.py +0 -0
  143. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/cli/main.py +0 -0
  144. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/__init__.py +0 -0
  145. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/loader.py +0 -0
  146. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/config/schema.py +0 -0
  147. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/__init__.py +0 -0
  148. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/deployer.py +0 -0
  149. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/describe.py +0 -0
  150. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/core/project.py +0 -0
  151. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/__init__.py +0 -0
  152. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/generator.py +0 -0
  153. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/dashboard/template.html +0 -0
  154. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/__init__.py +0 -0
  155. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/runner.py +0 -0
  156. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/local/server.py +0 -0
  157. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/packaging/__init__.py +0 -0
  158. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/__init__.py +0 -0
  159. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/alibaba.py +0 -0
  160. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/aws.py +0 -0
  161. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/azure.py +0 -0
  162. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/cloudflare.py +0 -0
  163. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/digitalocean.py +0 -0
  164. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/gcp.py +0 -0
  165. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/huawei.py +0 -0
  166. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/ibm.py +0 -0
  167. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/oracle.py +0 -0
  168. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/registry.py +0 -0
  169. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/schedule.py +0 -0
  170. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/tencent.py +0 -0
  171. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/providers/terraform_doc.py +0 -0
  172. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/__init__.py +0 -0
  173. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/__init__.py +0 -0
  174. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/_httpfn.py +0 -0
  175. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/alibaba.py +0 -0
  176. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/aws.py +0 -0
  177. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/azure.py +0 -0
  178. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/base.py +0 -0
  179. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/cloudflare.py +0 -0
  180. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/digitalocean.py +0 -0
  181. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/gcp.py +0 -0
  182. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/huawei.py +0 -0
  183. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/ibm.py +0 -0
  184. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/onprem.py +0 -0
  185. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/oracle.py +0 -0
  186. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/adapters/tencent.py +0 -0
  187. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/batch.py +0 -0
  188. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/context.py +0 -0
  189. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/cron.py +0 -0
  190. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/dispatch.py +0 -0
  191. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/errors.py +0 -0
  192. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/event.py +0 -0
  193. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/invoke.py +0 -0
  194. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/log.py +0 -0
  195. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/manifest.py +0 -0
  196. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/response.py +0 -0
  197. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/routing.py +0 -0
  198. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/runtime/workflow.py +0 -0
  199. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/terraform/__init__.py +0 -0
  200. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/terraform/runner.py +0 -0
  201. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/__init__.py +0 -0
  202. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/asl.py +0 -0
  203. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/src/py_serverless_kit/workflows/gcp.py +0 -0
  204. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/__init__.py +0 -0
  205. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/config/__init__.py +0 -0
  206. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/config/test_loader.py +0 -0
  207. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/config/test_schema.py +0 -0
  208. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/conftest.py +0 -0
  209. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/local/__init__.py +0 -0
  210. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/local/test_server.py +0 -0
  211. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/__init__.py +0 -0
  212. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_alibaba.py +0 -0
  213. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_aws.py +0 -0
  214. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_azure.py +0 -0
  215. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_cloudflare.py +0 -0
  216. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_digitalocean.py +0 -0
  217. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_gcp.py +0 -0
  218. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_huawei.py +0 -0
  219. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_ibm.py +0 -0
  220. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_oracle.py +0 -0
  221. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_schedule.py +0 -0
  222. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/providers/test_tencent.py +0 -0
  223. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/__init__.py +0 -0
  224. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_alibaba.py +0 -0
  225. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_aws.py +0 -0
  226. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_azure.py +0 -0
  227. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_cloudflare.py +0 -0
  228. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_digitalocean.py +0 -0
  229. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_gcp.py +0 -0
  230. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_huawei.py +0 -0
  231. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_ibm.py +0 -0
  232. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_onprem.py +0 -0
  233. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_oracle.py +0 -0
  234. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_adapter_tencent.py +0 -0
  235. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_cron.py +0 -0
  236. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_dispatch.py +0 -0
  237. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_models.py +0 -0
  238. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_onprem_host.py +0 -0
  239. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/runtime/test_workflow_engine.py +0 -0
  240. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/test_cli.py +0 -0
  241. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/test_dashboard.py +0 -0
  242. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/test_packaging.py +0 -0
  243. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/workflows/__init__.py +0 -0
  244. {py_serverless_kit-0.2.0 → py_serverless_kit-0.3.0}/tests/workflows/test_compilers.py +0 -0
@@ -6,6 +6,17 @@ 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
+
9
20
  ## [0.2.0] - 2026-10-17
10
21
 
11
22
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: py-serverless-kit
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
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
@@ -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 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 (`onprem`).
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,7 +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 (in the host) |
123
+ | On-premises | experimental | ✅ | ✅ | ✅ files | ✅ directory | ✅ files | embedded (local, SSH, or Docker) |
124
124
 
125
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.**
126
126
 
@@ -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 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 (`onprem`).
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,7 +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 (in the host) |
79
+ | On-premises | experimental | ✅ | ✅ | ✅ files | ✅ directory | ✅ files | embedded (local, SSH, or Docker) |
80
80
 
81
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.**
82
82
 
@@ -45,10 +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 process is started beside the zip)
48
+ │ onprem_handler.py (onprem; the host is started beside the zip)
49
49
  └── dependencies or requirements.txt
50
50
  ```
51
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
+
52
54
  ## Runtime flow
53
55
 
54
56
  ```
@@ -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
 
@@ -109,7 +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` | nothing to configure. Terraform's built-in provider starts a process with the Python that runs `pskit` |
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 |
113
113
 
114
114
  Provider-specific required options are listed in [providers.md](providers.md).
115
115
 
@@ -95,7 +95,7 @@ def test_workflow():
95
95
 
96
96
  ## On-premises is a deploy, not `pskit dev`
97
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. See [providers.md](providers.md#onprem-on-premises) and [`examples/16-on-premises`](../examples/16-on-premises).
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).
99
99
  | `http_event(method, path, body=None, headers=None, query=None)` | dict/list bodies are JSON-encoded; `?query` in `path` is parsed |
100
100
  | `build_event(type, data, **http)` | `queue`/`topic` (list → records), `storage` (`{"bucket", "key", "size", "action"}`), `schedule`, `invoke`, `workflow`, `http` |
101
101
 
@@ -356,19 +356,19 @@ One Worker script per function. pskit generates a single Python module per Worke
356
356
 
357
357
  ## onprem (On-premises)
358
358
 
359
- - **Terraform:** built-in `terraform_data` (no plugin download)
360
- - **Credentials:** none. The host is the same Python that runs `pskit deploy`
361
- - **Dependencies:** pip wheels for this machine and interpreter, not a Linux cloud image. `tzdata` is vendored so cron timezones work on Windows
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
362
 
363
363
  ```yaml
364
364
  provider:
365
365
  name: onprem
366
366
  region: local
367
367
  options:
368
- host: 127.0.0.1 # bind address. 0.0.0.0 is advertised as 127.0.0.1 unless advertise is set
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
369
  port: 8080 # 1-65535. Give each service its own port
370
370
  advertise: https://fn.internal.example # optional URL written into outputs
371
- data_dir: .pskit/onprem-data # default .pskit/onprem-data/<service>-<stage>
371
+ data_dir: .pskit/onprem-data # default .pskit/onprem-data/<service>-<stage> (local); <path>/data on SSH
372
372
  poll_seconds: 0.5
373
373
  admin_token: "${env:PSKIT_ADMIN_TOKEN, }" # header x-pskit-token on /__pskit/* except health
374
374
  services:
@@ -377,9 +377,11 @@ provider:
377
377
  storage: {use: directory, path: .onprem/buckets}
378
378
  topic: builtin
379
379
  workflow: embedded # builtin is an alias of embedded
380
+ deploy:
381
+ method: local # local | ssh | docker (default local)
380
382
  ```
381
383
 
382
- `pskit deploy` writes the bundle under `.pskit/onprem-<stage>/onprem_app/` and starts `onprem_ctl.py`. The process serves your HTTP routes and polls the service directories. `pskit remove` stops the process and does not delete `data_dir`.
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`.
383
385
 
384
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).
385
387
 
@@ -406,11 +408,47 @@ Publish from outside the process:
406
408
 
407
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`.
408
410
 
409
- **Resources:** `terraform_data.host` with create and destroy `local-exec` provisioners.
411
+ **Deploy targets** (`options.deploy`)
410
412
 
411
- **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 `provider.runtime` is not the interpreter running `pskit`, validation warns and the host still uses that interpreter.
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 |
412
418
 
413
- Example: [`examples/16-on-premises`](../examples/16-on-premises).
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).
414
452
 
415
453
  ---
416
454
 
@@ -82,7 +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 |
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 |
86
86
  | alibaba / tencent / huawei | `iam.statements` aren't translated; set `iam.role` |
87
87
 
88
88
  ## FAQ
@@ -58,3 +58,6 @@ Set `options.admin_token` and send `x-pskit-token` on `/__pskit/*` except
58
58
 
59
59
  `pskit dev` is still the hot-reloading HTTP server. This example is the durable
60
60
  deploy: it keeps running after `pskit deploy` returns.
61
+
62
+ To copy the same host onto another machine (SSH, Docker, or a bundled CPython
63
+ when that machine has no Python), see [17-on-premises-remote](../17-on-premises-remote).
@@ -0,0 +1,97 @@
1
+ # 17 · On-premises, remote server
2
+
3
+ Example 16 runs the host on the laptop that runs `pskit deploy`. This example
4
+ copies the same kind of host onto a machine you SSH into — a factory box, a
5
+ VM, or a rack server. The handler code does not change.
6
+
7
+ Three ways to get code from this laptop onto that server:
8
+
9
+ | `options.deploy.method` | What the server needs | What the laptop needs | When to use it |
10
+ | --- | --- | --- | --- |
11
+ | `local` | this machine (example 16) | Python + pskit | laptop / the server *is* the deploy machine |
12
+ | `ssh` | SSH. Python only if `python: system` | OpenSSH (`ssh`, `scp`) | most on-prem Linux boxes |
13
+ | `docker` | Docker engine | Docker CLI (and SSH if `docker_host` is `ssh://…`) | the server has Docker and you do not want to manage Python |
14
+
15
+ When the server has **no Python**, pick one of:
16
+
17
+ - `method: ssh` and `python: bundle` — pskit downloads a portable CPython
18
+ ([python-build-standalone](https://github.com/astral-sh/python-build-standalone))
19
+ at apply time, copies it with the app, and starts systemd (this file)
20
+ - `method: docker` — the image is `FROM python:3.12-slim`; the server never
21
+ installs Python
22
+ - `python_home: /path/to/portable-python` — air-gapped: you already have a
23
+ CPython tree, pskit copies it instead of downloading
24
+
25
+ ## This file (SSH + bundled Python + systemd)
26
+
27
+ ```bash
28
+ export PSKIT_ONPREM_HOST=10.0.1.12 # SSH target
29
+ export PSKIT_ONPREM_USER=pskit
30
+ export PSKIT_SSH_KEY=$HOME/.ssh/id_ed25519 # optional
31
+ export PSKIT_ONPREM_URL=http://10.0.1.12:8090
32
+ pskit deploy
33
+ curl http://10.0.1.12:8090/hello?name=Ada
34
+ pskit remove # systemctl stop; data dir stays
35
+ ```
36
+
37
+ The SSH user needs `sudo` to write `/etc/systemd/system` (`deploy.sudo: true`).
38
+ Wheels are vendored as manylinux x86_64 because `target_os: linux`.
39
+
40
+ Shorthand for the same method:
41
+
42
+ ```yaml
43
+ deploy: ssh://pskit@10.0.1.12/opt/pskit/factory-api
44
+ ```
45
+
46
+ ## Docker instead
47
+
48
+ The server needs a Docker engine. It does not need Python.
49
+
50
+ ```yaml
51
+ provider:
52
+ options:
53
+ host: 0.0.0.0
54
+ port: 8090
55
+ deploy:
56
+ method: docker
57
+ image: pskit/factory-api:dev
58
+ docker_host: ssh://pskit@10.0.1.12 # empty = Docker on this laptop
59
+ restart: unless-stopped
60
+ ```
61
+
62
+ `pskit deploy` runs `docker build` and `docker run` (with `DOCKER_HOST` when
63
+ `docker_host` is set). Data lives in a volume named after the container.
64
+
65
+ ## Server already has Python
66
+
67
+ ```yaml
68
+ deploy:
69
+ method: ssh
70
+ host: 10.0.1.12
71
+ user: pskit
72
+ path: /opt/pskit/factory-api
73
+ python: system # uses python3.12 on the server
74
+ install: process # start a detached process instead of systemd
75
+ ```
76
+
77
+ ## Air-gapped bundle
78
+
79
+ Download the install_only archive once on a machine with network, copy it in,
80
+ and point at the unpacked tree:
81
+
82
+ ```yaml
83
+ deploy:
84
+ method: ssh
85
+ host: 10.0.1.12
86
+ python: bundle
87
+ python_home: ./vendor/python # portable CPython directory, copied as-is
88
+ ```
89
+
90
+ Or set `python_url` + `python_sha256` to an internal mirror of the
91
+ python-build-standalone `install_only` tarball.
92
+
93
+ ## Bind address
94
+
95
+ `options.host` is the address the process binds on the **target**. Use
96
+ `0.0.0.0` so other machines can call it. `advertise` is the URL written into
97
+ `pskit info` and the dashboard.
@@ -0,0 +1,16 @@
1
+ """Handlers for a remote on-premises deploy. Identical to a cloud function."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from py_serverless_kit import Context, Event
6
+
7
+
8
+ def hello(event: Event, ctx: Context):
9
+ name = event.http.query.get("name", "world")
10
+ ctx.logger.info("greeting", extra={"name": name})
11
+ return {"message": f"Hello, {name}!", "provider": event.provider, "stage": ctx.stage, "host": "remote"}
12
+
13
+
14
+ def tick(event: Event, ctx: Context):
15
+ ctx.logger.info("tick", extra={"data": event.data})
16
+ return {"ok": True, "data": event.data}
@@ -0,0 +1,60 @@
1
+ # Remote on-premises deploy.
2
+ #
3
+ # This file ships the function bundle to a Linux server that may not have Python.
4
+ # `python: bundle` downloads a portable CPython at apply time and copies it with
5
+ # the app. `install: systemd` keeps the host up across reboots.
6
+ #
7
+ # Required on the laptop: OpenSSH (`ssh`, `scp`). Required on the server: SSH
8
+ # access. Python on the server is optional.
9
+ #
10
+ # set PSKIT_ONPREM_HOST=10.0.1.12
11
+ # pskit deploy
12
+ #
13
+ # Switch to Docker (server needs Docker, not Python) with the `providers.onprem`
14
+ # block left as-is and:
15
+ # pskit deploy after changing deploy.method to docker (see README).
16
+ service: factory-api
17
+
18
+ provider:
19
+ name: onprem
20
+ region: local
21
+ runtime: python3.12
22
+ architecture: x86_64
23
+ options:
24
+ host: 0.0.0.0
25
+ port: 8090
26
+ advertise: "${env:PSKIT_ONPREM_URL, http://127.0.0.1:8090}"
27
+ data_dir: /opt/pskit/factory-api/data
28
+ deploy:
29
+ method: ssh
30
+ host: "${env:PSKIT_ONPREM_HOST, 127.0.0.1}"
31
+ user: "${env:PSKIT_ONPREM_USER, pskit}"
32
+ port: 22
33
+ identity_file: "${env:PSKIT_SSH_KEY, }"
34
+ known_hosts: accept-new
35
+ path: /opt/pskit/factory-api
36
+ python: bundle
37
+ target_os: linux
38
+ target_arch: x86_64
39
+ install: systemd
40
+ sudo: true
41
+
42
+ functions:
43
+ hello:
44
+ handler: app.handlers.hello
45
+ events:
46
+ - http: GET /hello
47
+ tick:
48
+ handler: app.handlers.tick
49
+ events:
50
+ - schedule: {rate: 1 hour, input: {source: factory}}
51
+
52
+ providers:
53
+ aws:
54
+ region: us-east-1
55
+ gcp:
56
+ region: us-central1
57
+ options: {project: "${env:GOOGLE_CLOUD_PROJECT, my-gcp-project}"}
58
+ azure:
59
+ region: eastus
60
+ options: {subscription_id: "${env:ARM_SUBSCRIPTION_ID, 00000000-0000-0000-0000-000000000000}"}
@@ -0,0 +1 @@
1
+ # No third-party dependencies. The pskit runtime is vendored into the bundle automatically.
@@ -23,6 +23,7 @@ by changing only the provider (`pskit deploy --provider gcp`).
23
23
  | 14 | [testing](14-testing) | pytest with `LocalRunner`, synthetic events, workflow tests, CI validation | AWS, GCP, Azure |
24
24
  | 15 | [ci-cd-deploy](15-ci-cd-deploy) | GitHub Actions per-stage deploys with OIDC, remote state, dashboard artifact | AWS, GCP, Azure |
25
25
  | 16 | [on-premises](16-on-premises) | one process on this machine: HTTP, schedule, queue, directory storage, topic, embedded workflow | on-premises |
26
+ | 17 | [on-premises-remote](17-on-premises-remote) | SSH / Docker / bundled CPython onto a server that may not have Python | on-premises |
26
27
 
27
28
  \* Azure blob triggers can't fire on deletions; the example's `providers.azure` block
28
29
  handles that explicitly.
@@ -1,2 +1,2 @@
1
- __version__ = "0.2.0"
1
+ __version__ = "0.3.0"
2
2
  __author__ = "Asif Khan @ Kavion.ai"
@@ -31,6 +31,9 @@ PROVIDER_OPTIONS = {
31
31
  " options:\n"
32
32
  " host: 127.0.0.1\n"
33
33
  " port: 8080\n"
34
+ " # deploy.method: local (this machine) | ssh | docker\n"
35
+ " # ssh: {host: 10.0.1.12, user: pskit, python: bundle, install: systemd}\n"
36
+ " # python: bundle ships a portable CPython when the server has none\n"
34
37
  " # builtin services are created on deploy. To use a directory you already\n"
35
38
  " # have: storage: {use: directory, path: /var/pskit/buckets}\n"
36
39
  ),
@@ -238,7 +238,7 @@ def build_artifact(project: Project, *, skip_deps: bool = False, log=print) -> A
238
238
  if final_reqs and not skip_deps:
239
239
  req_file = work / "requirements.vendor.txt"
240
240
  req_file.write_text("\n".join(final_reqs) + "\n", "utf-8")
241
- flags = provider.pip_platform(cfg.provider.runtime, cfg.provider.architecture)
241
+ flags = provider.pip_platform_for(cfg)
242
242
  log(f" vendoring {len(final_reqs)} requirement(s) for {cfg.provider.runtime}/{cfg.provider.architecture}")
243
243
  _pip_install(req_file, build_dir, flags, cfg.package.pip_args)
244
244
  else:
@@ -191,6 +191,9 @@ class Provider(ABC):
191
191
  "--only-binary=:all:",
192
192
  ]
193
193
 
194
+ def pip_platform_for(self, config: ServiceConfig) -> List[str]:
195
+ return self.pip_platform(config.provider.runtime, config.provider.architecture)
196
+
194
197
  # ------------------------------------------------------------ validation
195
198
  def workflow_engine(self, wf: WorkflowConfig) -> str:
196
199
  if wf.engine == "native":