truefoundry 0.3.0rc7__tar.gz → 0.3.0rc9__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.

Potentially problematic release.


This version of truefoundry might be problematic. Click here for more details.

Files changed (137) hide show
  1. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/PKG-INFO +2 -1
  2. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/pyproject.toml +2 -1
  3. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/__init__.py +1 -9
  4. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/auto_gen/models.py +51 -191
  5. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/__init__.py +2 -4
  6. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py +7 -5
  7. truefoundry-0.3.0rc9/truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +66 -0
  8. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/deploy_command.py +6 -3
  9. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/patch_application_command.py +2 -0
  10. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/deploy.py +52 -1
  11. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/deploy_workflow.py +130 -10
  12. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/deployable_patched_models.py +3 -1
  13. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/patched_models.py +0 -36
  14. truefoundry-0.3.0rc9/truefoundry/version.py +6 -0
  15. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/__init__.py +1 -1
  16. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/example/hello_world_package/workflow.py +3 -2
  17. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/example/package/test_workflow.py +29 -8
  18. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/example/truefoundry.yaml +1 -1
  19. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/workflow.py +62 -2
  20. truefoundry-0.3.0rc7/truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +0 -51
  21. truefoundry-0.3.0rc7/truefoundry/version.py +0 -4
  22. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/README.md +0 -0
  23. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/__init__.py +0 -0
  24. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/__init__.py +0 -0
  25. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/agents/__init__.py +0 -0
  26. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/agents/base.py +0 -0
  27. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/agents/developer.py +0 -0
  28. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/agents/project_identifier.py +0 -0
  29. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/agents/tester.py +0 -0
  30. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/cli.py +0 -0
  31. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/constants.py +0 -0
  32. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/exception.py +0 -0
  33. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/logger.py +0 -0
  34. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/__init__.py +0 -0
  35. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/ask.py +0 -0
  36. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/base.py +0 -0
  37. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/commit.py +0 -0
  38. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/docker_build.py +0 -0
  39. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/docker_run.py +0 -0
  40. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/file_type_counts.py +0 -0
  41. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/list_files.py +0 -0
  42. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/read_file.py +0 -0
  43. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/send_request.py +0 -0
  44. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/tools/write_file.py +0 -0
  45. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/utils/client.py +0 -0
  46. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/utils/diff.py +0 -0
  47. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/autodeploy/utils/pydantic_compat.py +0 -0
  48. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/cli/__init__.py +0 -0
  49. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/cli/__main__.py +0 -0
  50. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/builders/__init__.py +0 -0
  51. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/builders/dockerfile.py +0 -0
  52. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py +0 -0
  53. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +0 -0
  54. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/builder/docker_service.py +0 -0
  55. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/__init__.py +0 -0
  56. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/cli.py +0 -0
  57. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/__init__.py +0 -0
  58. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/apply_command.py +0 -0
  59. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/build_command.py +0 -0
  60. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/build_logs_command.py +0 -0
  61. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/create_command.py +0 -0
  62. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/delete_command.py +0 -0
  63. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/get_command.py +0 -0
  64. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/list_command.py +0 -0
  65. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/login_command.py +0 -0
  66. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/logout_command.py +0 -0
  67. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/logs_command.py +0 -0
  68. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/patch_command.py +0 -0
  69. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/redeploy_command.py +0 -0
  70. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/terminate_comand.py +0 -0
  71. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/commands/trigger_command.py +0 -0
  72. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/config.py +0 -0
  73. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/console.py +0 -0
  74. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/const.py +0 -0
  75. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/display_util.py +0 -0
  76. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/cli/util.py +0 -0
  77. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/core/__init__.py +0 -0
  78. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/core/login.py +0 -0
  79. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/core/logout.py +0 -0
  80. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/__init__.py +0 -0
  81. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/__main__.py +0 -0
  82. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/app.py +0 -0
  83. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/build.py +0 -0
  84. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/remote/__init__.py +0 -0
  85. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/remote/context.py +0 -0
  86. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/remote/method.py +0 -0
  87. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/remote/remote.py +0 -0
  88. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/route.py +0 -0
  89. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/service.py +0 -0
  90. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/function_service/utils.py +0 -0
  91. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/io/__init__.py +0 -0
  92. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/io/output_callback.py +0 -0
  93. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/io/rich_output_callback.py +0 -0
  94. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/json_util.py +0 -0
  95. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/__init__.py +0 -0
  96. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/auth/auth_service_client.py +0 -0
  97. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/auth/credential_file_manager.py +0 -0
  98. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/auth/credential_provider.py +0 -0
  99. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/auth/servicefoundry_session.py +0 -0
  100. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/clients/__init__.py +0 -0
  101. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/clients/servicefoundry_client.py +0 -0
  102. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/clients/shell_client.py +0 -0
  103. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/clients/utils.py +0 -0
  104. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/const.py +0 -0
  105. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/dao/__init__.py +0 -0
  106. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/dao/application.py +0 -0
  107. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/dao/apply.py +0 -0
  108. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/dao/version.py +0 -0
  109. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/dao/workspace.py +0 -0
  110. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/exceptions.py +0 -0
  111. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/logs_utils.py +0 -0
  112. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/messages.py +0 -0
  113. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/model/__init__.py +0 -0
  114. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/model/entity.py +0 -0
  115. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/session.py +0 -0
  116. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/util.py +0 -0
  117. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/lib/win32.py +0 -0
  118. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/__init__.py +0 -0
  119. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/__init__.py +0 -0
  120. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/models.py +0 -0
  121. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/deploy/v2/lib/source.py +0 -0
  122. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/langchain/__init__.py +0 -0
  123. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/langchain/deprecated.py +0 -0
  124. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/langchain/truefoundry_chat.py +0 -0
  125. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/langchain/truefoundry_embeddings.py +0 -0
  126. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/langchain/truefoundry_llm.py +0 -0
  127. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/langchain/utils.py +0 -0
  128. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/logger.py +0 -0
  129. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/ml/__init__.py +0 -0
  130. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/pydantic_v1.py +0 -0
  131. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/python_deploy_codegen.py +0 -0
  132. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/container_task.py +0 -0
  133. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/example/deploy.sh +0 -0
  134. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/example/workflow.yaml +0 -0
  135. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/map_task.py +0 -0
  136. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/python_task.py +0 -0
  137. {truefoundry-0.3.0rc7 → truefoundry-0.3.0rc9}/truefoundry/workflow/task.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: truefoundry
3
- Version: 0.3.0rc7
3
+ Version: 0.3.0rc9
4
4
  Summary: Truefoundry CLI
5
5
  Author: Abhishek Choudhary
6
6
  Author-email: abhishek@truefoundry.com
@@ -34,6 +34,7 @@ Requires-Dist: python-dotenv (>=1.0.1,<1.1.0)
34
34
  Requires-Dist: python-socketio[client] (>=5.5.2,<6.0.0)
35
35
  Requires-Dist: questionary (>=1.10.0,<2.0.0)
36
36
  Requires-Dist: requests (>=2.31.0,<3.0.0)
37
+ Requires-Dist: requirements-parser (>=0.10.2,<0.11.0)
37
38
  Requires-Dist: rich (>=13.7.1,<14.0.0)
38
39
  Requires-Dist: rich-click (>=1.2.1,<2.0.0)
39
40
  Requires-Dist: tqdm (>=4.0.0,<5.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "truefoundry"
3
- version = "0.3.0rc7"
3
+ version = "0.3.0rc9"
4
4
  description = "Truefoundry CLI"
5
5
  authors = ["Abhishek Choudhary <abhishek@truefoundry.com>"]
6
6
  readme = "README.md"
@@ -29,6 +29,7 @@ python-socketio = {version = ">=5.5.2,<6.0.0", extras = ["client"]}
29
29
  PyYAML = ">=6.0.0,<7.0.0"
30
30
  questionary = ">=1.10.0,<2.0.0"
31
31
  requests = ">=2.31.0,<3.0.0"
32
+ requirements-parser = "^0.10.2"
32
33
  rich = ">=13.7.1,<14.0.0"
33
34
  rich-click = ">=1.2.1,<2.0.0"
34
35
  tqdm = ">=4.0.0,<5.0.0"
@@ -6,6 +6,7 @@ from truefoundry.deploy.auto_gen.models import (
6
6
  Kustomize,
7
7
  ParamType,
8
8
  Protocol,
9
+ WorkbenchImage,
9
10
  )
10
11
  from truefoundry.deploy.lib.dao.application import (
11
12
  delete_application,
@@ -56,14 +57,10 @@ from truefoundry.deploy.v2.lib.patched_models import (
56
57
  BlueGreen,
57
58
  Build,
58
59
  Canary,
59
- CodeserverImage,
60
60
  CoreNATSOutputConfig,
61
61
  CPUUtilizationMetric,
62
62
  CronMetric,
63
63
  CUDAVersion,
64
- CustomCodeserverImage,
65
- CustomNotebookImage,
66
- CustomSSHServerImage,
67
64
  DockerFileBuild,
68
65
  DynamicVolumeConfig,
69
66
  Endpoint,
@@ -104,15 +101,10 @@ from truefoundry.deploy.v2.lib.patched_models import (
104
101
  SQSInputConfig,
105
102
  SQSOutputConfig,
106
103
  SQSQueueMetricConfig,
107
- SSHServerImage,
108
104
  StaticVolumeConfig,
109
105
  StringDataMount,
110
106
  TPUType,
111
107
  TruefoundryArtifactSource,
112
- TruefoundryImageBase,
113
- TruefoundryImageCuda1180,
114
- TruefoundryImageCuda1211,
115
- TruefoundryImageFull,
116
108
  VolumeBrowser,
117
109
  VolumeMount,
118
110
  WorkerConfig,
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: application.json
3
- # timestamp: 2024-07-19T06:56:20+00:00
3
+ # timestamp: 2024-08-09T07:42:58+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -125,6 +125,13 @@ class AsyncProcessorSidecar(BaseModel):
125
125
  )
126
126
 
127
127
 
128
+ class Autoshutdown(BaseModel):
129
+ wait_time: conint(ge=0) = Field(
130
+ 300,
131
+ description="+label=Wait Time\n+usage=The period to wait after the last received request before scaling the replicas to 0",
132
+ )
133
+
134
+
128
135
  class BaseAutoscaling(BaseModel):
129
136
  min_replicas: conint(ge=0) = Field(
130
137
  1,
@@ -138,10 +145,6 @@ class BaseAutoscaling(BaseModel):
138
145
  30,
139
146
  description="+label=Polling Interval\n+usage=This is the interval to check each trigger on.",
140
147
  )
141
- cooldown_period: conint(ge=0) = Field(
142
- 300,
143
- description="+label=Cooldown Period\n+usage=The period to wait after the last trigger reported active before scaling the resource back to 0.",
144
- )
145
148
 
146
149
 
147
150
  class BasicAuthCreds(BaseModel):
@@ -197,26 +200,6 @@ class CanaryStep(BaseModel):
197
200
  )
198
201
 
199
202
 
200
- class CodeserverImage(BaseModel):
201
- """
202
- +usage=Codeserver with persistent environment (Python 3.11.6)
203
- """
204
-
205
- type: constr(regex=r"^codeserver$") = Field(..., description="+value=codeserver")
206
- enable_sudo: bool = Field(
207
- True,
208
- description="+label=Enable root access to the container\n+usage=Changes made to the root directory `/` will not be persisted across notebook restarts",
209
- )
210
- apt_packages: Optional[List[str]] = Field(
211
- None,
212
- description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
213
- )
214
- docker_registry: Optional[str] = Field(
215
- None,
216
- description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
217
- )
218
-
219
-
220
203
  class CronMetric(BaseModel):
221
204
  type: Literal["cron"] = Field(..., description="+value=cron")
222
205
  desired_replicas: Optional[conint(ge=1)] = Field(
@@ -237,60 +220,6 @@ class CronMetric(BaseModel):
237
220
  )
238
221
 
239
222
 
240
- class CustomCodeserverImage(BaseModel):
241
- """
242
- +usage=User supplied docker image URI for vscode server
243
- """
244
-
245
- type: constr(regex=r"^customcodeserver$") = Field(
246
- ..., description="+value=customcodeserver"
247
- )
248
- image_uri: str = Field(
249
- ...,
250
- description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
251
- )
252
- docker_registry: Optional[str] = Field(
253
- None,
254
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
255
- )
256
-
257
-
258
- class CustomNotebookImage(BaseModel):
259
- """
260
- +usage=User supplied docker image URI for jupyter notebook
261
- """
262
-
263
- type: constr(regex=r"^customnotebook$") = Field(
264
- ..., description="+value=customnotebook"
265
- )
266
- image_uri: str = Field(
267
- ...,
268
- description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
269
- )
270
- docker_registry: Optional[str] = Field(
271
- None,
272
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
273
- )
274
-
275
-
276
- class CustomSSHServerImage(BaseModel):
277
- """
278
- +usage=User supplied docker image URI for ssh server
279
- """
280
-
281
- type: constr(regex=r"^custom-ssh-server$") = Field(
282
- ..., description="+value=custom-ssh-server"
283
- )
284
- image_uri: str = Field(
285
- ...,
286
- description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
287
- )
288
- docker_registry: Optional[str] = Field(
289
- None,
290
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
291
- )
292
-
293
-
294
223
  class DockerFileBuild(BaseModel):
295
224
  """
296
225
  +docs=Describes that we are using a dockerfile to build our image
@@ -976,22 +905,6 @@ class SQSQueueMetricConfig(BaseModel):
976
905
  )
977
906
 
978
907
 
979
- class SSHServerImage(BaseModel):
980
- """
981
- +usage=Ssh Server with persistent environment (Python 3.11.6)
982
- """
983
-
984
- type: constr(regex=r"^ssh-server$") = Field(..., description="+value=ssh-server")
985
- apt_packages: Optional[List[str]] = Field(
986
- None,
987
- description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
988
- )
989
- docker_registry: Optional[str] = Field(
990
- None,
991
- description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
992
- )
993
-
994
-
995
908
  class ConcurrencyPolicy(str, Enum):
996
909
  """
997
910
  +usage=Choose whether to allow this job to run while another instance of the job is running, or to replace the currently running instance. Allow
@@ -1149,86 +1062,6 @@ class TruefoundryArtifactSource(BaseModel):
1149
1062
  )
1150
1063
 
1151
1064
 
1152
- class TruefoundryImageBase(BaseModel):
1153
- """
1154
- +usage=JupyterLab with persistent python environment (Python 3.11.6)
1155
- """
1156
-
1157
- type: constr(regex=r"^truefoundrybase$") = Field(
1158
- ..., description="+value=truefoundrybase"
1159
- )
1160
- enable_sudo: bool = Field(
1161
- True,
1162
- description="+label=Enable root access to the container\n+usage=Changes made to the root directory `/` will not be persisted across notebook restarts",
1163
- )
1164
- apt_packages: Optional[List[str]] = Field(
1165
- None,
1166
- description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
1167
- )
1168
- docker_registry: Optional[str] = Field(
1169
- None,
1170
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
1171
- )
1172
-
1173
-
1174
- class TruefoundryImageCuda1180(BaseModel):
1175
- """
1176
- +usage=JupyterLab with persistent python environment (Python 3.11.6, Cuda 11.8.0)
1177
- """
1178
-
1179
- type: constr(regex=r"^truefoundrycuda1180$") = Field(
1180
- ..., description="+value=truefoundrycuda1180"
1181
- )
1182
- apt_packages: Optional[List[str]] = Field(
1183
- None,
1184
- description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
1185
- )
1186
- docker_registry: Optional[str] = Field(
1187
- None,
1188
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
1189
- )
1190
-
1191
-
1192
- class TruefoundryImageCuda1211(BaseModel):
1193
- """
1194
- +usage=JupyterLab with persistent python environment (Python 3.11.6, Cuda 12.1.1)
1195
- """
1196
-
1197
- type: constr(regex=r"^truefoundrycuda1211$") = Field(
1198
- ..., description="+value=truefoundrycuda1211"
1199
- )
1200
- apt_packages: Optional[List[str]] = Field(
1201
- None,
1202
- description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
1203
- )
1204
- docker_registry: Optional[str] = Field(
1205
- None,
1206
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
1207
- )
1208
-
1209
-
1210
- class TruefoundryImageFull(BaseModel):
1211
- """
1212
- +usage=JupyterLab + Tensorflow 2.15.0 and Pytorch 2.1.1 with persistent environment (Python 3.11.6)
1213
- """
1214
-
1215
- type: constr(regex=r"^truefoundryfull$") = Field(
1216
- ..., description="+value=truefoundryfull"
1217
- )
1218
- enable_sudo: bool = Field(
1219
- True,
1220
- description="+label=Enable root access to the container\n+usage=Changes made to the root directory `/` will not be persisted across notebook restarts",
1221
- )
1222
- apt_packages: Optional[List[str]] = Field(
1223
- None,
1224
- description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
1225
- )
1226
- docker_registry: Optional[str] = Field(
1227
- None,
1228
- description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
1229
- )
1230
-
1231
-
1232
1065
  class VolumeBrowser(BaseModel):
1233
1066
  """
1234
1067
  +label=Volume Browser
@@ -1265,6 +1098,25 @@ class VolumeMount(BaseModel):
1265
1098
  )
1266
1099
 
1267
1100
 
1101
+ class WorkbenchImage(BaseModel):
1102
+ """
1103
+ +usage=Workbench Image with persistent environment (Python 3.11.6)
1104
+ """
1105
+
1106
+ image_uri: str = Field(
1107
+ ...,
1108
+ description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
1109
+ )
1110
+ build_script: Optional[constr(min_length=1, max_length=1024)] = Field(
1111
+ None,
1112
+ description="+label=Build Script\n+usage=The build script to run when building the image.\nThis will be executed as the last step in the docker build process as the root user (RUN DEBIAN_FRONTEND=noninteractive bash -ex build_script.sh)\n+placeholder=Enter the build script",
1113
+ )
1114
+ docker_registry: Optional[str] = Field(
1115
+ None,
1116
+ description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
1117
+ )
1118
+
1119
+
1268
1120
  class ArtifactsDownload(BaseModel):
1269
1121
  """
1270
1122
  +docs=Describes the configuration for the artifacts cache
@@ -1317,6 +1169,10 @@ class BaseWorkbenchInput(BaseModel):
1317
1169
  )
1318
1170
  service_account: Optional[str] = Field(None, description="+sort=10113")
1319
1171
  kustomize: Optional[Kustomize] = None
1172
+ workspace_fqn: Optional[str] = Field(
1173
+ None,
1174
+ description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
1175
+ )
1320
1176
 
1321
1177
 
1322
1178
  class Build(BaseModel):
@@ -1361,9 +1217,7 @@ class Codeserver(BaseWorkbenchInput):
1361
1217
  """
1362
1218
 
1363
1219
  type: constr(regex=r"^codeserver$") = Field(..., description="+value=Code Server")
1364
- image: Union[CodeserverImage, CustomCodeserverImage] = Field(
1365
- ..., description="+usage=Pick a codeserver image to deploy\n+sort=2"
1366
- )
1220
+ image: WorkbenchImage
1367
1221
  auth: Optional[BasicAuthCreds] = None
1368
1222
 
1369
1223
 
@@ -1458,6 +1312,10 @@ class Helm(BaseModel):
1458
1312
  )
1459
1313
  kustomize: Optional[Kustomize] = None
1460
1314
  ignoreDifferences: Optional[List[Dict[str, Any]]] = None
1315
+ workspace_fqn: Optional[str] = Field(
1316
+ None,
1317
+ description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
1318
+ )
1461
1319
 
1462
1320
 
1463
1321
  class Job(BaseModel):
@@ -1509,6 +1367,10 @@ class Job(BaseModel):
1509
1367
  )
1510
1368
  labels: Optional[Dict[str, str]] = Field(None, description="+label=Labels")
1511
1369
  kustomize: Optional[Kustomize] = None
1370
+ workspace_fqn: Optional[str] = Field(
1371
+ None,
1372
+ description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
1373
+ )
1512
1374
 
1513
1375
 
1514
1376
  class KafkaInputConfig(BaseModel):
@@ -1615,16 +1477,7 @@ class Notebook(BaseWorkbenchInput):
1615
1477
  """
1616
1478
 
1617
1479
  type: constr(regex=r"^notebook$") = Field(..., description="+value=notebook")
1618
- image: Union[
1619
- TruefoundryImageBase,
1620
- TruefoundryImageFull,
1621
- CustomNotebookImage,
1622
- TruefoundryImageCuda1180,
1623
- TruefoundryImageCuda1211,
1624
- ] = Field(
1625
- ...,
1626
- description="+usage=Changes made to the root directory `/` will not be persisted across notebook restarts\n+sort=2",
1627
- )
1480
+ image: WorkbenchImage
1628
1481
  auth: Optional[BasicAuthCreds] = None
1629
1482
  cull_timeout: conint(ge=5) = Field(
1630
1483
  30,
@@ -1660,9 +1513,7 @@ class SSHServer(BaseWorkbenchInput):
1660
1513
  """
1661
1514
 
1662
1515
  type: constr(regex=r"^ssh-server$") = Field(..., description="+value=SSH Server")
1663
- image: Union[SSHServerImage, CustomSSHServerImage] = Field(
1664
- ..., description="+usage=Pick a ssh server image to deploy\n+sort=2"
1665
- )
1516
+ image: WorkbenchImage
1666
1517
  ssh_public_key: str = Field(
1667
1518
  ...,
1668
1519
  description="+label: SSH Public Key\n+usage=Add Your SSH Public Key, this will be used to authenticate you to the SSH Server. You can find it using `cat ~/.ssh/id_rsa.pub`\n+sort=4",
@@ -1680,6 +1531,10 @@ class Volume(BaseModel):
1680
1531
  description="+sort=2\n+label=Volume Config\n+message=Volume Configuration, can be either Dynamically provisioned or statically provisioned.",
1681
1532
  )
1682
1533
  volume_browser: Optional[VolumeBrowser] = None
1534
+ workspace_fqn: Optional[str] = Field(
1535
+ None,
1536
+ description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
1537
+ )
1683
1538
 
1684
1539
 
1685
1540
  class WorkerConfig(BaseModel):
@@ -1729,6 +1584,10 @@ class BaseService(BaseModel):
1729
1584
  kustomize: Optional[Kustomize] = None
1730
1585
  liveness_probe: Optional[HealthProbe] = None
1731
1586
  readiness_probe: Optional[HealthProbe] = None
1587
+ workspace_fqn: Optional[str] = Field(
1588
+ None,
1589
+ description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
1590
+ )
1732
1591
 
1733
1592
 
1734
1593
  class FlyteLaunchPlan(BaseModel):
@@ -1756,6 +1615,7 @@ class Service(BaseService):
1756
1615
  1,
1757
1616
  description="+label=Replicas\n+usage=Deploy multiple instances of your pods to distribute incoming traffic across them, ensuring effective load balancing.\n+icon=fa-clone\n+sort=4",
1758
1617
  )
1618
+ auto_shutdown: Optional[Autoshutdown] = None
1759
1619
  allow_interception: bool = Field(
1760
1620
  False,
1761
1621
  description="+label=Allow intercepts\n+usage=Whether to allow intercepts to be applied for this service.\nThis would inject an additional sidecar in each pod of the service. Not recommended on production",
@@ -10,19 +10,17 @@ from truefoundry.deploy.builder.builders import get_builder
10
10
  from truefoundry.deploy.builder.builders.tfy_notebook_buildpack.dockerfile_template import (
11
11
  NotebookImageBuild,
12
12
  )
13
- from truefoundry.pydantic_v1 import BaseModel
13
+ from truefoundry.pydantic_v1 import BaseModel, Field
14
14
 
15
15
 
16
16
  class _BuildConfig(BaseModel):
17
- # I cannot use Field(discriminator="build_config_type") here as
18
- # build_config_type in the build configs is not a Literal.
19
17
  __root__: Union[
20
18
  DockerFileBuild,
21
19
  PythonBuild,
22
20
  NotebookImageBuild,
23
21
  TaskPythonBuild,
24
22
  TaskDockerFileBuild,
25
- ]
23
+ ] = Field(discriminator="type")
26
24
 
27
25
 
28
26
  def build(
@@ -13,18 +13,19 @@ __all__ = ["generate_dockerfile_content", "build"]
13
13
 
14
14
 
15
15
  def _convert_to_dockerfile_build_config(
16
- build_configuration: NotebookImageBuild,
17
- dockerfile_path: str,
16
+ build_configuration: NotebookImageBuild, local_dir: str
18
17
  ) -> DockerFileBuild:
19
18
  dockerfile_content = generate_dockerfile_content(
20
- build_configuration=build_configuration
19
+ build_configuration=build_configuration,
20
+ local_dir=local_dir,
21
21
  )
22
+ dockerfile_path = os.path.join(local_dir, "Dockerfile")
22
23
  with open(dockerfile_path, "w", encoding="utf8") as fp:
23
24
  fp.write(dockerfile_content)
24
-
25
25
  return DockerFileBuild(
26
26
  type="dockerfile",
27
27
  dockerfile_path=dockerfile_path,
28
+ build_context_path=local_dir,
28
29
  )
29
30
 
30
31
 
@@ -35,7 +36,8 @@ def build(
35
36
  ):
36
37
  with TemporaryDirectory() as local_dir:
37
38
  docker_build_configuration = _convert_to_dockerfile_build_config(
38
- build_configuration, dockerfile_path=os.path.join(local_dir, "Dockerfile")
39
+ build_configuration,
40
+ local_dir=local_dir,
39
41
  )
40
42
  dockerfile.build(
41
43
  tag=tag,
@@ -0,0 +1,66 @@
1
+ import hashlib
2
+ import os
3
+ from typing import Literal, Optional
4
+
5
+ from mako.template import Template
6
+
7
+ from truefoundry.pydantic_v1 import BaseModel
8
+
9
+
10
+ class NotebookImageBuild(BaseModel):
11
+ type: Literal["tfy-notebook-buildpack"] = "tfy-notebook-buildpack"
12
+ base_image_uri: str
13
+ build_script: Optional[str] = None
14
+
15
+
16
+ DOCKERFILE_TEMPLATE = Template(
17
+ """
18
+ FROM ${base_image_uri}
19
+ USER root
20
+
21
+ % if build_script_docker_commands is not None:
22
+ ${build_script_docker_commands}
23
+ % endif
24
+
25
+ USER $NB_UID
26
+ """
27
+ )
28
+
29
+
30
+ def generate_build_script_docker_commands(
31
+ build_script: Optional[str], local_dir: str
32
+ ) -> Optional[str]:
33
+ if not build_script:
34
+ return None
35
+ build_script_path = None
36
+ if build_script:
37
+ # we add build script's hash to the file name to ensure docker cache invalidation
38
+ script_hash = hashlib.sha256(build_script.encode("utf-8")).hexdigest()
39
+ build_script_path = os.path.join(local_dir, f"build-script-{script_hash}.sh")
40
+ with open(build_script_path, "w") as fp:
41
+ fp.write(build_script)
42
+ build_script_path = os.path.relpath(build_script_path, local_dir)
43
+ run_build_script_command = f"""\
44
+ COPY {build_script_path} /tmp/user-build-script.sh
45
+ RUN mkdir -p /var/log/ && DEBIAN_FRONTEND=noninteractive bash -ex /tmp/user-build-script.sh 2>&1 | tee /var/log/user-build-script-output.log
46
+ """
47
+ return run_build_script_command
48
+
49
+
50
+ def generate_dockerfile_content(
51
+ build_configuration: NotebookImageBuild, local_dir: str
52
+ ) -> str:
53
+ build_script_docker_commands = generate_build_script_docker_commands(
54
+ build_script=build_configuration.build_script,
55
+ local_dir=local_dir,
56
+ )
57
+
58
+ template_args = {
59
+ "base_image_uri": build_configuration.base_image_uri,
60
+ "build_script_docker_commands": build_script_docker_commands,
61
+ }
62
+
63
+ template = DOCKERFILE_TEMPLATE
64
+
65
+ dockerfile_content = template.render(**template_args)
66
+ return dockerfile_content
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import sys
3
+ from typing import Optional
3
4
 
4
5
  import rich_click as click
5
6
  import yaml
@@ -9,6 +10,7 @@ from click.exceptions import ClickException
9
10
  from truefoundry.autodeploy.cli import cli as autodeploy_cli
10
11
  from truefoundry.autodeploy.exception import InvalidRequirementsException
11
12
  from truefoundry.deploy.cli.const import GROUP_CLS
13
+ from truefoundry.deploy.cli.util import handle_exception_wrapper
12
14
 
13
15
 
14
16
  def _get_default_spec_file():
@@ -41,8 +43,8 @@ def _get_default_spec_file():
41
43
  "-w",
42
44
  "--workspace-fqn",
43
45
  "--workspace_fqn",
44
- required=True,
45
- help="FQN of the Workspace to deploy to",
46
+ default=None,
47
+ help="FQN of the Workspace to deploy to. If not provided, the Workspace FQN will be read from the deployment spec if available.",
46
48
  )
47
49
  @click.option(
48
50
  "--wait/--no-wait",
@@ -52,7 +54,8 @@ def _get_default_spec_file():
52
54
  default=True,
53
55
  help="Wait and tail the deployment progress",
54
56
  )
55
- def deploy_command(file: str, workspace_fqn: str, wait: bool):
57
+ @handle_exception_wrapper
58
+ def deploy_command(file: str, workspace_fqn: Optional[str], wait: bool):
56
59
  from truefoundry.deploy.lib.auth.servicefoundry_session import ServiceFoundrySession
57
60
  from truefoundry.deploy.v2.lib.deployable_patched_models import Application
58
61
 
@@ -4,6 +4,7 @@ import rich_click as click
4
4
  import yaml
5
5
 
6
6
  from truefoundry.deploy.cli.const import GROUP_CLS
7
+ from truefoundry.deploy.cli.util import handle_exception_wrapper
7
8
  from truefoundry.deploy.lib.dao import application as application_lib
8
9
 
9
10
 
@@ -44,6 +45,7 @@ from truefoundry.deploy.lib.dao import application as application_lib
44
45
  default=True,
45
46
  help="Wait and tail the deployment progress",
46
47
  )
48
+ @handle_exception_wrapper
47
49
  def patch_application_command(
48
50
  patch_file: str, application_fqn: str, patch: str, wait: bool
49
51
  ):
@@ -191,10 +191,61 @@ def _warn_when_gpu_selected_without_cuda(component: Component):
191
191
  )
192
192
 
193
193
 
194
+ def _resolve_workspace_fqn(
195
+ component: Component, workspace_fqn: Optional[str] = None
196
+ ) -> str:
197
+ if not workspace_fqn:
198
+ if hasattr(component, "workspace_fqn") and component.workspace_fqn:
199
+ resolved_workspace_fqn = component.workspace_fqn
200
+ else:
201
+ raise ValueError(
202
+ f"""\
203
+ No Workspace FQN was provided or mentioned in the spec.
204
+ Either add a `workspace_fqn` to your yaml spec as
205
+
206
+ ```
207
+ name: {getattr(component, 'name', 'my-app')}
208
+ type: {getattr(component, 'type', 'undefined')}
209
+ ...
210
+ workspace_fqn: <your workspace fqn>
211
+ ```
212
+
213
+ or Python deployment spec as
214
+
215
+ ```
216
+ app = {component.__class__.__name__}(
217
+ name='{getattr(component, 'name', 'my-app')}',
218
+ ...
219
+ workspace_fqn='<your workspace fqn>'
220
+ )
221
+ ```
222
+
223
+ or pass it explicitly using `--workspace-fqn` argument on CLI.
224
+ """
225
+ )
226
+ else:
227
+ if (
228
+ hasattr(component, "workspace_fqn")
229
+ and component.workspace_fqn
230
+ and component.workspace_fqn != workspace_fqn
231
+ ):
232
+ logger.warning(
233
+ f"`workspace_fqn` set in the deployment spec doesn't match the provided `workspace_fqn` argument {component.workspace_fqn!r} \n"
234
+ f"Using `workspace_fqn`: {workspace_fqn!r} "
235
+ )
236
+ resolved_workspace_fqn = workspace_fqn
237
+
238
+ return resolved_workspace_fqn
239
+
240
+
194
241
  def deploy_component(
195
- component: Component, workspace_fqn: str, wait: bool = True
242
+ component: Component, workspace_fqn: Optional[str] = None, wait: bool = True
196
243
  ) -> Deployment:
197
244
  _warn_when_gpu_selected_without_cuda(component=component)
245
+ workspace_fqn = _resolve_workspace_fqn(
246
+ component=component, workspace_fqn=workspace_fqn
247
+ )
248
+ component.workspace_fqn = workspace_fqn
198
249
  workspace_id = get_workspace_by_fqn(workspace_fqn).id
199
250
  updated_component = _handle_if_local_source(
200
251
  component=component, workspace_fqn=workspace_fqn