dsd-upsun 0.1.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.
Potentially problematic release.
This version of dsd-upsun might be problematic. Click here for more details.
- dsd_upsun-0.1.0/LICENSE +11 -0
- dsd_upsun-0.1.0/MANIFEST.in +2 -0
- dsd_upsun-0.1.0/PKG-INFO +43 -0
- dsd_upsun-0.1.0/README.md +5 -0
- dsd_upsun-0.1.0/dsd_upsun/__init__.py +2 -0
- dsd_upsun-0.1.0/dsd_upsun/deploy.py +20 -0
- dsd_upsun-0.1.0/dsd_upsun/deploy_messages.py +208 -0
- dsd_upsun-0.1.0/dsd_upsun/platform_deployer.py +411 -0
- dsd_upsun-0.1.0/dsd_upsun/plugin_config.py +27 -0
- dsd_upsun-0.1.0/dsd_upsun/templates/pipenv.platform.app.yaml +62 -0
- dsd_upsun-0.1.0/dsd_upsun/templates/platform.app.yaml +60 -0
- dsd_upsun-0.1.0/dsd_upsun/templates/poetry.platform.app.yaml +74 -0
- dsd_upsun-0.1.0/dsd_upsun/templates/services.yaml +11 -0
- dsd_upsun-0.1.0/dsd_upsun/templates/settings.py +41 -0
- dsd_upsun-0.1.0/dsd_upsun/utils.py +36 -0
- dsd_upsun-0.1.0/dsd_upsun.egg-info/PKG-INFO +43 -0
- dsd_upsun-0.1.0/dsd_upsun.egg-info/SOURCES.txt +20 -0
- dsd_upsun-0.1.0/dsd_upsun.egg-info/dependency_links.txt +1 -0
- dsd_upsun-0.1.0/dsd_upsun.egg-info/requires.txt +11 -0
- dsd_upsun-0.1.0/dsd_upsun.egg-info/top_level.txt +1 -0
- dsd_upsun-0.1.0/pyproject.toml +62 -0
- dsd_upsun-0.1.0/setup.cfg +4 -0
dsd_upsun-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Copyright (c) Eric Matthes and individual contributors.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
4
|
+
|
|
5
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
6
|
+
|
|
7
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
|
+
|
|
9
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
10
|
+
|
|
11
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
dsd_upsun-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dsd-upsun
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A plugin for django-simple-deploy, supporting deployments to Upsun.
|
|
5
|
+
Author-email: Eric Matthes <ehmatthes@gmail.com>
|
|
6
|
+
Project-URL: Documentation, https://github.com/django-simple-deploy/dsd-upsun
|
|
7
|
+
Project-URL: GitHub, https://github.com/django-simple-deploy/dsd-upsun
|
|
8
|
+
Project-URL: Changelog, https://github.com/django-simple-deploy/dsd-upsun/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: django,deployment
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Framework :: Django :: 4.2
|
|
12
|
+
Classifier: Framework :: Django :: 5.1
|
|
13
|
+
Classifier: Framework :: Django :: 5.2
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: django>=4.2
|
|
28
|
+
Requires-Dist: pluggy>=1.5.0
|
|
29
|
+
Requires-Dist: toml>=0.10.2
|
|
30
|
+
Requires-Dist: requests>=2.32.2
|
|
31
|
+
Requires-Dist: django-simple-deploy>=1.3.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: black>=24.1.0; extra == "dev"
|
|
34
|
+
Requires-Dist: build>=1.2.1; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
36
|
+
Requires-Dist: twine>=5.1.1; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# dsd-upsun
|
|
40
|
+
|
|
41
|
+
A plugin for deploying Django projects to Upsun, using django-simple-deploy.
|
|
42
|
+
|
|
43
|
+
For full documentation, see the documentation for [django-simple-deploy](https://django-simple-deploy.readthedocs.io/en/latest/).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Manages all Upsun-specific aspects of the deployment process."""
|
|
2
|
+
|
|
3
|
+
import django_simple_deploy
|
|
4
|
+
|
|
5
|
+
from dsd_upsun.platform_deployer import PlatformDeployer
|
|
6
|
+
from .plugin_config import PluginConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@django_simple_deploy.hookimpl
|
|
10
|
+
def dsd_get_plugin_config():
|
|
11
|
+
"""Get platform-specific attributes needed by core."""
|
|
12
|
+
plugin_config = PluginConfig()
|
|
13
|
+
return plugin_config
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@django_simple_deploy.hookimpl
|
|
17
|
+
def dsd_deploy():
|
|
18
|
+
"""Carry out platform-specific deployment steps."""
|
|
19
|
+
platform_deployer = PlatformDeployer()
|
|
20
|
+
platform_deployer.deploy()
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""A collection of messages used in platform_deployer.py."""
|
|
2
|
+
|
|
3
|
+
# For conventions, see documentation in deploy_messages.py
|
|
4
|
+
|
|
5
|
+
from textwrap import dedent
|
|
6
|
+
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
confirm_automate_all = """
|
|
11
|
+
The --automate-all flag means the deploy command will:
|
|
12
|
+
- Run `upsun create` for you, to create an empty Upsun project.
|
|
13
|
+
- This will create a project in the us-3.platform.sh region. If you wish
|
|
14
|
+
to use a different region, cancel this operation and use the --region flag.
|
|
15
|
+
- You can see a list of all regions at:
|
|
16
|
+
https://docs.upsun.com/development/regions.html#region-location
|
|
17
|
+
- Commit all changes to your project that are necessary for deployment.
|
|
18
|
+
- Push these changes to Upsun.
|
|
19
|
+
- Open your deployed project in a new browser tab.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
cancel_upsun = """
|
|
23
|
+
Okay, cancelling Upsun deployment.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
cli_not_installed = """
|
|
27
|
+
In order to deploy to Upsun, you need to install the Upsun CLI.
|
|
28
|
+
See here: https://docs.upsun.com/administration/cli.html
|
|
29
|
+
After installing the CLI, you can run the deploy command again.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
cli_logged_out = """
|
|
33
|
+
You are currently logged out of the Upsun CLI. Please log in,
|
|
34
|
+
and then run the deploy command again.
|
|
35
|
+
You can log in from the command line:
|
|
36
|
+
$ platform login
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
upsun_settings_found = """
|
|
40
|
+
There is already an Upsun-specific settings block in settings.py. Is it okay to
|
|
41
|
+
overwrite this block, and everything that follows in settings.py?
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
cant_overwrite_settings = """
|
|
45
|
+
In order to configure the project for deployment, we need to write an Upsun-specific
|
|
46
|
+
settings block. Please remove the current Upsun-specific settings, and then run
|
|
47
|
+
the deploy command again.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
no_project_name = """
|
|
51
|
+
An Upsun project name could not be found.
|
|
52
|
+
|
|
53
|
+
The deploy command expects that you've already run `platform create`, or
|
|
54
|
+
associated the local project with an existing project on Upsun.
|
|
55
|
+
|
|
56
|
+
If you haven't done so, run the `platform create` command and then run
|
|
57
|
+
the deploy command again. You can override this warning by using
|
|
58
|
+
the `--deployed-project-name` flag to specify the name you want to use for the
|
|
59
|
+
project. This must match the name of your Upsun project.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
org_not_found = """
|
|
63
|
+
An Upsun organization name could not be found.
|
|
64
|
+
|
|
65
|
+
You may have created an Upsun account, but not created an organization.
|
|
66
|
+
The Upsun CLI requires an organization name when creating a new project.
|
|
67
|
+
|
|
68
|
+
Please visit the Upsun console and make sure you have created an organization.
|
|
69
|
+
You can also do this through the CLI using the `platform organization:create` command.
|
|
70
|
+
For help, run `platform help organization:create`.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
no_org_available = """
|
|
74
|
+
An Upsun org must be used to make a deployment. Please identify or create the org
|
|
75
|
+
you'd like to use, and then try again.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
login_required = """
|
|
79
|
+
You appear to be logged out of the Upsun CLI. Please run the
|
|
80
|
+
command `platform login`, and then run the deploy command again.
|
|
81
|
+
|
|
82
|
+
You may be able to override this error by passing the `--deployed-project-name`
|
|
83
|
+
flag.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
unknown_error = """
|
|
87
|
+
An unknown error has occurred. Do you have the Upsun CLI installed?
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
may_configure = """
|
|
91
|
+
You may want to re-run the deploy command without the --automate-all flag.
|
|
92
|
+
|
|
93
|
+
You will have to create the Upsun project yourself, but django-simple-deploy
|
|
94
|
+
will do all of the necessary configuration for deployment.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# --- Dynamic strings ---
|
|
99
|
+
# These need to be generated in functions, to display information that's
|
|
100
|
+
# determined as the script runs.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def confirm_use_org(org_name):
|
|
104
|
+
"""Confirm use of this org to create a new project."""
|
|
105
|
+
|
|
106
|
+
msg = dedent(
|
|
107
|
+
f"""
|
|
108
|
+
--- The Upsun CLI requires an organization name when creating a new project. ---
|
|
109
|
+
When using --automate-all, a project will be created on your behalf. The following
|
|
110
|
+
organization was found: {org_name}
|
|
111
|
+
|
|
112
|
+
This organization will be used to create a new project. If this is not okay,
|
|
113
|
+
enter n to cancel this operation.
|
|
114
|
+
"""
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return msg
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def unknown_create_error(e):
|
|
121
|
+
"""Process a non-specific error when running `platform create`
|
|
122
|
+
while using automate_all. This is most likely an issue with the user
|
|
123
|
+
not having permission to create a new project, for example because they
|
|
124
|
+
are on a trial plan and have already created too many projects.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
msg = dedent(
|
|
128
|
+
f"""
|
|
129
|
+
--- An error has occurred when trying to create a new Upsun project. ---
|
|
130
|
+
|
|
131
|
+
While running `platform create`, an error has occurred. You should check
|
|
132
|
+
the Upsun console to see if a project was partially created.
|
|
133
|
+
|
|
134
|
+
The error messages that Upsun provides, both through the CLI and
|
|
135
|
+
the console, are not always specific enough to be helpful. For example,
|
|
136
|
+
newer users are limited to two new projects in a 24-hour period, or something
|
|
137
|
+
like that. But if you try to create an additional project, you only get
|
|
138
|
+
a message that says: "You do not have access to create a new Subscriptions resource".
|
|
139
|
+
There is no information about specific limits, and how to address them.
|
|
140
|
+
|
|
141
|
+
The following output may help diagnose the error:
|
|
142
|
+
***** output of `platform create` *****
|
|
143
|
+
|
|
144
|
+
{e.stderr.decode()}
|
|
145
|
+
|
|
146
|
+
***** end output *****
|
|
147
|
+
"""
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return msg
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def success_msg(log_output=""):
|
|
154
|
+
"""Success message, for configuration-only run."""
|
|
155
|
+
|
|
156
|
+
msg = dedent(
|
|
157
|
+
f"""
|
|
158
|
+
--- Your project is now configured for deployment on Upsun. ---
|
|
159
|
+
|
|
160
|
+
To deploy your project, you will need to:
|
|
161
|
+
- Commit the changes made in the configuration process.
|
|
162
|
+
$ git status
|
|
163
|
+
$ git add .
|
|
164
|
+
$ git commit -am "Configured project for deployment."
|
|
165
|
+
- Push your project to Upsun' servers:
|
|
166
|
+
$ platform push
|
|
167
|
+
- Open your project:
|
|
168
|
+
$ platform url
|
|
169
|
+
- As you develop your project further:
|
|
170
|
+
- Make local changes
|
|
171
|
+
- Commit your local changes
|
|
172
|
+
- Run `platform push`
|
|
173
|
+
"""
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if log_output:
|
|
177
|
+
msg += dedent(
|
|
178
|
+
f"""
|
|
179
|
+
- You can find a full record of this configuration in the dsd_logs directory.
|
|
180
|
+
"""
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return msg
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def success_msg_automate_all(deployed_url):
|
|
187
|
+
"""Success message, when using --automate-all."""
|
|
188
|
+
|
|
189
|
+
msg = dedent(
|
|
190
|
+
f"""
|
|
191
|
+
|
|
192
|
+
--- Your project should now be deployed on Upsun. ---
|
|
193
|
+
|
|
194
|
+
It should have opened up in a new browser tab.
|
|
195
|
+
- You can also visit your project at {deployed_url}
|
|
196
|
+
|
|
197
|
+
If you make further changes and want to push them to Upsun,
|
|
198
|
+
commit your changes and then run `platform push`.
|
|
199
|
+
|
|
200
|
+
Also, if you haven't already done so you should review the
|
|
201
|
+
documentation for Python deployments on Upsun at:
|
|
202
|
+
- https://fixed.docs.upsun.com/languages/python.html
|
|
203
|
+
- This documentation will help you understand how to maintain
|
|
204
|
+
your deployment.
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
)
|
|
208
|
+
return msg
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"""Manages all Upsun-specific aspects of the deployment process."""
|
|
2
|
+
|
|
3
|
+
import sys, os, subprocess, time
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.core.management.utils import get_random_secret_key
|
|
8
|
+
from django.utils.crypto import get_random_string
|
|
9
|
+
from django.utils.safestring import mark_safe
|
|
10
|
+
|
|
11
|
+
from django_simple_deploy.management.commands.utils import plugin_utils
|
|
12
|
+
from django_simple_deploy.management.commands.utils.plugin_utils import dsd_config
|
|
13
|
+
from django_simple_deploy.management.commands.utils.command_errors import (
|
|
14
|
+
DSDCommandError,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from . import deploy_messages as upsun_msgs
|
|
18
|
+
from . import utils as upsun_utils
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PlatformDeployer:
|
|
22
|
+
"""Perform the initial deployment to Upsun.
|
|
23
|
+
|
|
24
|
+
If --automate-all is used, carry out an actual deployment.
|
|
25
|
+
If not, do all configuration work so the user only has to commit changes, and call
|
|
26
|
+
`upsun push`.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.templates_path = Path(__file__).parent / "templates"
|
|
31
|
+
|
|
32
|
+
# --- Public methods ---
|
|
33
|
+
|
|
34
|
+
def deploy(self, *args, **options):
|
|
35
|
+
"""Coordinate the overall configuration and deployment."""
|
|
36
|
+
plugin_utils.write_output(
|
|
37
|
+
"\nConfiguring project for deployment to Upsun..."
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self._validate_platform()
|
|
41
|
+
|
|
42
|
+
self._prep_automate_all()
|
|
43
|
+
self._modify_settings()
|
|
44
|
+
self._add_requirements()
|
|
45
|
+
self._add_platform_app_yaml()
|
|
46
|
+
self._add_platform_dir()
|
|
47
|
+
self._add_services_yaml()
|
|
48
|
+
self._settings_env_var()
|
|
49
|
+
|
|
50
|
+
self._conclude_automate_all()
|
|
51
|
+
self._show_success_message()
|
|
52
|
+
|
|
53
|
+
# --- Helper methods for deploy() ---
|
|
54
|
+
|
|
55
|
+
def _validate_platform(self):
|
|
56
|
+
"""Make sure the local environment and project supports deployment to
|
|
57
|
+
Upsun.
|
|
58
|
+
|
|
59
|
+
Make sure CLI is installed, and user is authenticated. Make sure necessary
|
|
60
|
+
resources have been created and identified, and that we have the user's
|
|
61
|
+
permission to use those resources.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
None
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
DSDCommandError: If we find any reason deployment won't work.
|
|
68
|
+
"""
|
|
69
|
+
if dsd_config.unit_testing:
|
|
70
|
+
# Unit tests don't use the CLI. Use the deployed project name that was
|
|
71
|
+
# passed to the simple_deploy CLI.
|
|
72
|
+
self.deployed_project_name = dsd_config.deployed_project_name
|
|
73
|
+
plugin_utils.log_info(
|
|
74
|
+
f"Deployed project name: {self.deployed_project_name}"
|
|
75
|
+
)
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
self._check_upsun_settings()
|
|
79
|
+
self._validate_cli()
|
|
80
|
+
|
|
81
|
+
self.deployed_project_name = self._get_upsun_project_name()
|
|
82
|
+
plugin_utils.log_info(f"Deployed project name: {self.deployed_project_name}")
|
|
83
|
+
|
|
84
|
+
self.org_name = self._get_org_name()
|
|
85
|
+
plugin_utils.log_info(f"\nOrg name: {self.org_name}")
|
|
86
|
+
|
|
87
|
+
def _prep_automate_all(self):
|
|
88
|
+
"""Intial work for automating entire process.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
None: If creation of new project was successful.
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
DSDCommandError: If create command fails.
|
|
95
|
+
|
|
96
|
+
Note: create command outputs project id to stdout if known, all other
|
|
97
|
+
output goes to stderr.
|
|
98
|
+
"""
|
|
99
|
+
if not dsd_config.automate_all:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
plugin_utils.write_output(" Running `upsun create`...")
|
|
103
|
+
plugin_utils.write_output(
|
|
104
|
+
" (Please be patient, this can take a few minutes."
|
|
105
|
+
)
|
|
106
|
+
cmd = f"upsun create --title { self.deployed_project_name } --org {self.org_name} --region {dsd_config.region} --yes"
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
# Note: if user can't create a project the returncode will be 6, not 1.
|
|
110
|
+
# This may affect whether a CompletedProcess is returned, or an Exception
|
|
111
|
+
# is raised.
|
|
112
|
+
# Also, create command outputs project id to stdout if known, all other
|
|
113
|
+
# output goes to stderr.
|
|
114
|
+
plugin_utils.run_slow_command(cmd)
|
|
115
|
+
except subprocess.CalledProcessError as e:
|
|
116
|
+
error_msg = upsun_msgs.unknown_create_error(e)
|
|
117
|
+
raise DSDCommandError(error_msg)
|
|
118
|
+
|
|
119
|
+
def _modify_settings(self):
|
|
120
|
+
"""Add upsun-specific settings.
|
|
121
|
+
|
|
122
|
+
This settings block is currently the same for all users. The ALLOWED_HOSTS
|
|
123
|
+
setting should be customized.
|
|
124
|
+
"""
|
|
125
|
+
template_path = self.templates_path / "settings.py"
|
|
126
|
+
plugin_utils.modify_settings_file(template_path)
|
|
127
|
+
|
|
128
|
+
def _add_platform_app_yaml(self):
|
|
129
|
+
"""Add a .platform.app.yaml file."""
|
|
130
|
+
|
|
131
|
+
# Build contents from template.
|
|
132
|
+
if dsd_config.pkg_manager == "poetry":
|
|
133
|
+
template_path = "poetry.platform.app.yaml"
|
|
134
|
+
elif dsd_config.pkg_manager == "pipenv":
|
|
135
|
+
template_path = "pipenv.platform.app.yaml"
|
|
136
|
+
else:
|
|
137
|
+
template_path = "platform.app.yaml"
|
|
138
|
+
template_path = self.templates_path / template_path
|
|
139
|
+
|
|
140
|
+
context = {
|
|
141
|
+
"project_name": dsd_config.local_project_name,
|
|
142
|
+
"deployed_project_name": self.deployed_project_name,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
contents = plugin_utils.get_template_string(template_path, context)
|
|
146
|
+
|
|
147
|
+
# Write file to project.
|
|
148
|
+
path = dsd_config.project_root / ".platform.app.yaml"
|
|
149
|
+
plugin_utils.add_file(path, contents)
|
|
150
|
+
|
|
151
|
+
def _add_requirements(self):
|
|
152
|
+
"""Add requirements for Upsun."""
|
|
153
|
+
requirements = ["platformshconfig", "gunicorn", "psycopg2"]
|
|
154
|
+
plugin_utils.add_packages(requirements)
|
|
155
|
+
|
|
156
|
+
def _add_platform_dir(self):
|
|
157
|
+
"""Add a .platform directory, if it doesn't already exist."""
|
|
158
|
+
self.platform_dir_path = dsd_config.project_root / ".platform"
|
|
159
|
+
plugin_utils.add_dir(self.platform_dir_path)
|
|
160
|
+
|
|
161
|
+
def _add_services_yaml(self):
|
|
162
|
+
"""Add the .platform/services.yaml file."""
|
|
163
|
+
|
|
164
|
+
template_path = self.templates_path / "services.yaml"
|
|
165
|
+
contents = plugin_utils.get_template_string(template_path, context=None)
|
|
166
|
+
|
|
167
|
+
path = self.platform_dir_path / "services.yaml"
|
|
168
|
+
plugin_utils.add_file(path, contents)
|
|
169
|
+
|
|
170
|
+
def _settings_env_var(self):
|
|
171
|
+
"""Set the DJANGO_SETTINGS_MODULE env var, if needed."""
|
|
172
|
+
# This is primarily for Wagtail projects, as signified by a settings/production.py file.
|
|
173
|
+
if dsd_config.settings_path.parts[-2:] == ("settings", "production.py"):
|
|
174
|
+
plugin_utils.write_output(" Setting DJANGO_SETTINGS_MODULE environment variable...")
|
|
175
|
+
|
|
176
|
+
# Need form mysite.settings.production
|
|
177
|
+
dotted_settings_path = ".".join(dsd_config.settings_path.parts[-3:]).removesuffix(".py")
|
|
178
|
+
|
|
179
|
+
cmd = f"upsun variable:create --level environment --environment main --name DJANGO_SETTINGS_MODULE --value {dotted_settings_path} --no-interaction --visible-build true --prefix env"
|
|
180
|
+
output = plugin_utils.run_quick_command(cmd)
|
|
181
|
+
plugin_utils.write_output(output)
|
|
182
|
+
|
|
183
|
+
def _conclude_automate_all(self):
|
|
184
|
+
"""Finish automating the push to Upsun.
|
|
185
|
+
|
|
186
|
+
- Commit all changes.
|
|
187
|
+
- Call `upsun push`.
|
|
188
|
+
- Open project.
|
|
189
|
+
"""
|
|
190
|
+
# Making this check here lets deploy() be cleaner.
|
|
191
|
+
if not dsd_config.automate_all:
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
plugin_utils.commit_changes()
|
|
195
|
+
|
|
196
|
+
# Push project.
|
|
197
|
+
plugin_utils.write_output(" Pushing to Upsun...")
|
|
198
|
+
|
|
199
|
+
# Pause to make sure project that was just created can be used.
|
|
200
|
+
plugin_utils.write_output(
|
|
201
|
+
" Pausing 10s to make sure project is ready to use..."
|
|
202
|
+
)
|
|
203
|
+
time.sleep(10)
|
|
204
|
+
|
|
205
|
+
# Use run_slow_command(), to stream output as it runs.
|
|
206
|
+
cmd = "upsun push --yes"
|
|
207
|
+
plugin_utils.run_slow_command(cmd)
|
|
208
|
+
|
|
209
|
+
# Open project.
|
|
210
|
+
plugin_utils.write_output(" Opening deployed app in a new browser tab...")
|
|
211
|
+
cmd = "upsun url --yes"
|
|
212
|
+
output = plugin_utils.run_quick_command(cmd)
|
|
213
|
+
plugin_utils.write_output(output)
|
|
214
|
+
|
|
215
|
+
# Get url of deployed project.
|
|
216
|
+
# This can be done with an re, but there's one line of output with
|
|
217
|
+
# a url, so finding that line is simpler.
|
|
218
|
+
# DEV: Move this to a utility, and write a test against standard Upsun
|
|
219
|
+
# output.
|
|
220
|
+
self.deployed_url = ""
|
|
221
|
+
for line in output.stdout.decode().split("\n"):
|
|
222
|
+
if "https" in line:
|
|
223
|
+
self.deployed_url = line.strip()
|
|
224
|
+
|
|
225
|
+
def _show_success_message(self):
|
|
226
|
+
"""After a successful run, show a message about what to do next."""
|
|
227
|
+
|
|
228
|
+
# DEV:
|
|
229
|
+
# - Mention that this script should not need to be run again unless creating
|
|
230
|
+
# a new deployment.
|
|
231
|
+
# - Describe ongoing approach of commit, push, migrate. Lots to consider
|
|
232
|
+
# when doing this on production app with users, make sure you learn.
|
|
233
|
+
|
|
234
|
+
if dsd_config.automate_all:
|
|
235
|
+
msg = upsun_msgs.success_msg_automate_all(self.deployed_url)
|
|
236
|
+
plugin_utils.write_output(msg)
|
|
237
|
+
else:
|
|
238
|
+
msg = upsun_msgs.success_msg(dsd_config.log_output)
|
|
239
|
+
plugin_utils.write_output(msg)
|
|
240
|
+
|
|
241
|
+
# --- Helper methods for methods called from deploy.py ---
|
|
242
|
+
|
|
243
|
+
def _check_upsun_settings(self):
|
|
244
|
+
"""Check to see if an Upsun settings block already exists."""
|
|
245
|
+
start_line = "# Upsun settings."
|
|
246
|
+
plugin_utils.check_settings(
|
|
247
|
+
"Upsun",
|
|
248
|
+
start_line,
|
|
249
|
+
upsun_msgs.upsun_settings_found,
|
|
250
|
+
upsun_msgs.cant_overwrite_settings,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def _validate_cli(self):
|
|
254
|
+
"""Make sure the Upsun CLI is installed, and user is authenticated."""
|
|
255
|
+
cmd = "upsun --version"
|
|
256
|
+
|
|
257
|
+
# This generates a FileNotFoundError on Ubuntu if the CLI is not installed.
|
|
258
|
+
try:
|
|
259
|
+
output_obj = plugin_utils.run_quick_command(cmd)
|
|
260
|
+
except FileNotFoundError:
|
|
261
|
+
raise DSDCommandError(upsun_msgs.cli_not_installed)
|
|
262
|
+
|
|
263
|
+
plugin_utils.log_info(output_obj)
|
|
264
|
+
|
|
265
|
+
# Check that the user is authenticated.
|
|
266
|
+
cmd = "upsun auth:info --no-interaction"
|
|
267
|
+
output_obj = plugin_utils.run_quick_command(cmd)
|
|
268
|
+
|
|
269
|
+
if "Authentication is required." in output_obj.stderr.decode():
|
|
270
|
+
raise DSDCommandError(upsun_msgs.cli_logged_out)
|
|
271
|
+
|
|
272
|
+
def _get_upsun_project_name(self):
|
|
273
|
+
"""Get the deployed project name.
|
|
274
|
+
|
|
275
|
+
If using automate_all, we'll set this. Otherwise, we're looking for the name
|
|
276
|
+
that was given in the `upsun create` command.
|
|
277
|
+
- Try to get this from `project:info`.
|
|
278
|
+
- If can't get project name:
|
|
279
|
+
- Exit with warning, and inform user of --deployed-project-name
|
|
280
|
+
flag to override this error.
|
|
281
|
+
|
|
282
|
+
Retuns:
|
|
283
|
+
str: The deployed project name.
|
|
284
|
+
Raises:
|
|
285
|
+
DSDCommandError: If deployed project name can't be found.
|
|
286
|
+
"""
|
|
287
|
+
# If we're creating the project, we'll just use the startproject name.
|
|
288
|
+
if dsd_config.automate_all:
|
|
289
|
+
return dsd_config.local_project_name
|
|
290
|
+
|
|
291
|
+
# Use the provided name if --deployed-project-name specified.
|
|
292
|
+
if dsd_config.deployed_project_name:
|
|
293
|
+
return dsd_config.deployed_project_name
|
|
294
|
+
|
|
295
|
+
# Use --yes flag to avoid interactive prompt hanging in background
|
|
296
|
+
# if the user is not currently logged in to the CLI.
|
|
297
|
+
cmd = "upsun project:info --yes --format csv"
|
|
298
|
+
output_obj = plugin_utils.run_quick_command(cmd)
|
|
299
|
+
output_str = output_obj.stdout.decode()
|
|
300
|
+
|
|
301
|
+
# Log cmd, but don't log the output of `project:info`. It contains identifying
|
|
302
|
+
# information about the user and project, including client_ssh_key.
|
|
303
|
+
plugin_utils.log_info(cmd)
|
|
304
|
+
|
|
305
|
+
# If there's no stdout, the user is probably logged out, hasn't called
|
|
306
|
+
# create, or doesn't have the CLI installed.
|
|
307
|
+
# Also, I've seen both ProjectNotFoundException and RootNotFoundException
|
|
308
|
+
# raised when no project has been created.
|
|
309
|
+
if not output_str:
|
|
310
|
+
output_str = output_obj.stderr.decode()
|
|
311
|
+
if "LoginRequiredException" in output_str:
|
|
312
|
+
raise DSDCommandError(upsun_msgs.login_required)
|
|
313
|
+
elif "ProjectNotFoundException" in output_str:
|
|
314
|
+
raise DSDCommandError(upsun_msgs.no_project_name)
|
|
315
|
+
elif "RootNotFoundException" in output_str:
|
|
316
|
+
raise DSDCommandError(upsun_msgs.no_project_name)
|
|
317
|
+
else:
|
|
318
|
+
error_msg = upsun_msgs.unknown_error
|
|
319
|
+
error_msg += upsun_msgs.cli_not_installed
|
|
320
|
+
raise DSDCommandError(error_msg)
|
|
321
|
+
|
|
322
|
+
# Pull deployed project name from output.
|
|
323
|
+
lines = output_str.splitlines()
|
|
324
|
+
title_line = [line for line in lines if "title," in line][0]
|
|
325
|
+
# Assume first project is one to use.
|
|
326
|
+
project_name = title_line.split(",")[1].strip()
|
|
327
|
+
project_name = upsun_utils.get_project_name(output_str)
|
|
328
|
+
|
|
329
|
+
# Project names can only have lowercase alphanumeric characters.
|
|
330
|
+
# See: https://github.com/ehmatthes/django-simple-deploy/issues/323
|
|
331
|
+
if " " in project_name:
|
|
332
|
+
project_name = project_name.replace(" ", "_").lower()
|
|
333
|
+
if project_name:
|
|
334
|
+
return project_name
|
|
335
|
+
|
|
336
|
+
# Couldn't find a project name. Warn user, and tell them about override flag.
|
|
337
|
+
raise DSDCommandError(upsun_msgs.no_project_name)
|
|
338
|
+
|
|
339
|
+
def _get_org_name(self):
|
|
340
|
+
"""Get the organization name associated with the user's Upsun account.
|
|
341
|
+
|
|
342
|
+
This is needed for creating a project using automate_all.
|
|
343
|
+
Confirm that it's okay to use this org.
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
str: org name
|
|
347
|
+
None: if not using automate-all
|
|
348
|
+
Raises:
|
|
349
|
+
DSDCommandError:
|
|
350
|
+
- if org name found, but not confirmed.
|
|
351
|
+
- if org name not found
|
|
352
|
+
"""
|
|
353
|
+
if not dsd_config.automate_all:
|
|
354
|
+
return
|
|
355
|
+
|
|
356
|
+
cmd = "upsun organization:list --yes --format csv"
|
|
357
|
+
output_obj = plugin_utils.run_quick_command(cmd)
|
|
358
|
+
output_str = output_obj.stdout.decode()
|
|
359
|
+
plugin_utils.log_info(output_str)
|
|
360
|
+
|
|
361
|
+
org_names = upsun_utils.get_org_names(output_str)
|
|
362
|
+
if not org_names:
|
|
363
|
+
raise DSDCommandError(upsun_msgs.org_not_found)
|
|
364
|
+
|
|
365
|
+
if len(org_names) == 1:
|
|
366
|
+
# Get permission to use this org.
|
|
367
|
+
org_name = org_names[0]
|
|
368
|
+
if self._confirm_use_org(org_name):
|
|
369
|
+
return org_name
|
|
370
|
+
|
|
371
|
+
# Show all orgs, ask user to make selection.
|
|
372
|
+
prompt = "\n*** Found multiple orgs on Upsun. ***"
|
|
373
|
+
for index, name in enumerate(org_names):
|
|
374
|
+
prompt += f"\n {index}: {name}"
|
|
375
|
+
prompt += "\nWhich org would you like to use? "
|
|
376
|
+
|
|
377
|
+
valid_choices = [i for i in range(len(org_names))]
|
|
378
|
+
|
|
379
|
+
# Confirm selection, because we do *not* want to deploy using the wrong org.
|
|
380
|
+
confirmed = False
|
|
381
|
+
while not confirmed:
|
|
382
|
+
selection = plugin_utils.get_numbered_choice(
|
|
383
|
+
prompt, valid_choices, upsun_msgs.no_org_available
|
|
384
|
+
)
|
|
385
|
+
selected_org = org_names[selection]
|
|
386
|
+
|
|
387
|
+
confirm_prompt = f"You have selected {selected_org}."
|
|
388
|
+
confirm_prompt += " Is that correct?"
|
|
389
|
+
confirmed = plugin_utils.get_confirmation(confirm_prompt)
|
|
390
|
+
|
|
391
|
+
return selected_org
|
|
392
|
+
|
|
393
|
+
def _confirm_use_org(self, org_name):
|
|
394
|
+
"""Confirm that it's okay to use the org that was found.
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
True: if confirmed
|
|
398
|
+
DSDCommandError: if not confirmed
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
dsd_config.stdout.write(upsun_msgs.confirm_use_org(org_name))
|
|
402
|
+
confirmed = plugin_utils.get_confirmation(skip_logging=True)
|
|
403
|
+
|
|
404
|
+
if confirmed:
|
|
405
|
+
dsd_config.stdout.write(" Okay, continuing with deployment.")
|
|
406
|
+
return True
|
|
407
|
+
else:
|
|
408
|
+
# Exit, with a message that configuration is still an option.
|
|
409
|
+
msg = upsun_msgs.cancel_upsun
|
|
410
|
+
msg += upsun_msgs.may_configure
|
|
411
|
+
raise DSDCommandError(msg)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Config class for plugin information shared with core."""
|
|
2
|
+
|
|
3
|
+
from . import deploy_messages as upsun_msgs
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PluginConfig:
|
|
7
|
+
"""Class for managing attributes that need to be shared with core.
|
|
8
|
+
|
|
9
|
+
This is similar to the class DSDConfig in core's dsd_config.py.
|
|
10
|
+
|
|
11
|
+
This should future-proof plugins somewhat, in that if more information needs
|
|
12
|
+
to be shared back to core, it can be added here without breaking changes to the
|
|
13
|
+
core-plugin interface.
|
|
14
|
+
|
|
15
|
+
Get plugin-specific attributes required by core.
|
|
16
|
+
|
|
17
|
+
Required:
|
|
18
|
+
- automate_all_supported
|
|
19
|
+
- platform_name
|
|
20
|
+
Optional:
|
|
21
|
+
- confirm_automate_all_msg (required if automate_all_supported is True)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
self.automate_all_supported = True
|
|
26
|
+
self.confirm_automate_all_msg = upsun_msgs.confirm_automate_all
|
|
27
|
+
self.platform_name = "Upsun"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# This file describes an application. You can have multiple applications
|
|
2
|
+
# in the same project.
|
|
3
|
+
#
|
|
4
|
+
# See https://fixed.docs.upsun.com/create-apps.html
|
|
5
|
+
|
|
6
|
+
# The name of this app. Must be unique within a project.
|
|
7
|
+
name: '{{ deployed_project_name }}'
|
|
8
|
+
|
|
9
|
+
# The runtime the application uses.
|
|
10
|
+
type: 'python:3.10'
|
|
11
|
+
|
|
12
|
+
# The relationships of the application with services or other applications.
|
|
13
|
+
#
|
|
14
|
+
# The left-hand side is the name of the relationship as it will be exposed
|
|
15
|
+
# to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand
|
|
16
|
+
# side is in the form `<service name>:<endpoint name>`.
|
|
17
|
+
relationships:
|
|
18
|
+
database: "db:postgresql"
|
|
19
|
+
|
|
20
|
+
# The configuration of app when it is exposed to the web.
|
|
21
|
+
web:
|
|
22
|
+
# Whether your app should speak to the webserver via TCP or Unix socket
|
|
23
|
+
# https://fixed.docs.upsun.com/guides/django/deploy/configure.html#how-to-start-your-app
|
|
24
|
+
upstream:
|
|
25
|
+
socket_family: unix
|
|
26
|
+
# Commands are run once after deployment to start the application process.
|
|
27
|
+
commands:
|
|
28
|
+
start: "pipenv run gunicorn -w 4 -b unix:$SOCKET {{ project_name }}.wsgi:application"
|
|
29
|
+
locations:
|
|
30
|
+
"/":
|
|
31
|
+
passthru: true
|
|
32
|
+
"/static":
|
|
33
|
+
root: "static"
|
|
34
|
+
expires: 1h
|
|
35
|
+
allow: true
|
|
36
|
+
|
|
37
|
+
# The size of the persistent disk of the application (in MB).
|
|
38
|
+
disk: 512
|
|
39
|
+
|
|
40
|
+
# Set a local R/W mount for logs
|
|
41
|
+
mounts:
|
|
42
|
+
'logs':
|
|
43
|
+
source: local
|
|
44
|
+
source_path: logs
|
|
45
|
+
|
|
46
|
+
# The hooks executed at various points in the lifecycle of the application.
|
|
47
|
+
hooks:
|
|
48
|
+
# The build hook runs before the application is deployed, and is useful for
|
|
49
|
+
# assembling the codebase.
|
|
50
|
+
# DEV: Why remove logs right after making them?
|
|
51
|
+
# Also, may want to split requirements into requirements.txt and requirements_remote.txt.
|
|
52
|
+
build: |
|
|
53
|
+
pip install --upgrade pip
|
|
54
|
+
pip install pipenv
|
|
55
|
+
pipenv install
|
|
56
|
+
|
|
57
|
+
mkdir logs
|
|
58
|
+
pipenv run python manage.py collectstatic
|
|
59
|
+
rm -rf logs
|
|
60
|
+
deploy: |
|
|
61
|
+
pipenv run python manage.py migrate
|
|
62
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# This file describes an application. You can have multiple applications
|
|
2
|
+
# in the same project.
|
|
3
|
+
#
|
|
4
|
+
# See https://fixed.docs.upsun.com/create-apps.html
|
|
5
|
+
|
|
6
|
+
# The name of this app. Must be unique within a project.
|
|
7
|
+
name: '{{ deployed_project_name }}'
|
|
8
|
+
|
|
9
|
+
# The runtime the application uses.
|
|
10
|
+
type: 'python:3.12'
|
|
11
|
+
|
|
12
|
+
# The relationships of the application with services or other applications.
|
|
13
|
+
#
|
|
14
|
+
# The left-hand side is the name of the relationship as it will be exposed
|
|
15
|
+
# to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand
|
|
16
|
+
# side is in the form `<service name>:<endpoint name>`.
|
|
17
|
+
relationships:
|
|
18
|
+
database: "db:postgresql"
|
|
19
|
+
|
|
20
|
+
# The configuration of app when it is exposed to the web.
|
|
21
|
+
web:
|
|
22
|
+
# Whether your app should speak to the webserver via TCP or Unix socket
|
|
23
|
+
# https://fixed.docs.upsun.com/guides/django/deploy/configure.html#how-to-start-your-app
|
|
24
|
+
upstream:
|
|
25
|
+
socket_family: unix
|
|
26
|
+
# Commands are run once after deployment to start the application process.
|
|
27
|
+
commands:
|
|
28
|
+
start: "gunicorn -w 4 -b unix:$SOCKET {{ project_name }}.wsgi:application"
|
|
29
|
+
locations:
|
|
30
|
+
"/":
|
|
31
|
+
passthru: true
|
|
32
|
+
"/static":
|
|
33
|
+
root: "static"
|
|
34
|
+
expires: 1h
|
|
35
|
+
allow: true
|
|
36
|
+
|
|
37
|
+
# The size of the persistent disk of the application (in MB).
|
|
38
|
+
disk: 512
|
|
39
|
+
|
|
40
|
+
# Set a local R/W mount for logs
|
|
41
|
+
mounts:
|
|
42
|
+
'logs':
|
|
43
|
+
source: local
|
|
44
|
+
source_path: logs
|
|
45
|
+
|
|
46
|
+
# The hooks executed at various points in the lifecycle of the application.
|
|
47
|
+
hooks:
|
|
48
|
+
# The build hook runs before the application is deployed, and is useful for
|
|
49
|
+
# assembling the codebase.
|
|
50
|
+
# DEV: Why remove logs right after making them?
|
|
51
|
+
# Also, may want to split requirements into requirements.txt and requirements_remote.txt.
|
|
52
|
+
build: |
|
|
53
|
+
pip install --upgrade pip
|
|
54
|
+
pip install -r requirements.txt
|
|
55
|
+
|
|
56
|
+
mkdir logs
|
|
57
|
+
python manage.py collectstatic
|
|
58
|
+
rm -rf logs
|
|
59
|
+
deploy: |
|
|
60
|
+
python manage.py migrate
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# This file describes an application. You can have multiple applications
|
|
2
|
+
# in the same project.
|
|
3
|
+
#
|
|
4
|
+
# See https://fixed.docs.upsun.com/create-apps.html
|
|
5
|
+
|
|
6
|
+
# The name of this app. Must be unique within a project.
|
|
7
|
+
name: '{{ deployed_project_name }}'
|
|
8
|
+
|
|
9
|
+
# The runtime the application uses.
|
|
10
|
+
type: 'python:3.10'
|
|
11
|
+
|
|
12
|
+
# Set properties for poetry.
|
|
13
|
+
variables:
|
|
14
|
+
env:
|
|
15
|
+
POETRY_VERSION: '1.3.1'
|
|
16
|
+
POETRY_VIRTUALENVS_IN_PROJECT: true
|
|
17
|
+
POETRY_VIRTUALENVS_CREATE: false
|
|
18
|
+
|
|
19
|
+
# The relationships of the application with services or other applications.
|
|
20
|
+
#
|
|
21
|
+
# The left-hand side is the name of the relationship as it will be exposed
|
|
22
|
+
# to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand
|
|
23
|
+
# side is in the form `<service name>:<endpoint name>`.
|
|
24
|
+
relationships:
|
|
25
|
+
database: "db:postgresql"
|
|
26
|
+
|
|
27
|
+
# The configuration of app when it is exposed to the web.
|
|
28
|
+
web:
|
|
29
|
+
# Whether your app should speak to the webserver via TCP or Unix socket
|
|
30
|
+
# https://fixed.docs.upsun.com/guides/django/deploy/configure.html#how-to-start-your-app
|
|
31
|
+
upstream:
|
|
32
|
+
socket_family: unix
|
|
33
|
+
# Commands are run once after deployment to start the application process.
|
|
34
|
+
commands:
|
|
35
|
+
start: "/app/.local/bin/poetry run gunicorn -w 4 -b unix:$SOCKET {{ project_name }}.wsgi:application"
|
|
36
|
+
locations:
|
|
37
|
+
"/":
|
|
38
|
+
passthru: true
|
|
39
|
+
"/static":
|
|
40
|
+
root: "static"
|
|
41
|
+
expires: 1h
|
|
42
|
+
allow: true
|
|
43
|
+
|
|
44
|
+
# The size of the persistent disk of the application (in MB).
|
|
45
|
+
disk: 512
|
|
46
|
+
|
|
47
|
+
# Set a local R/W mount for logs
|
|
48
|
+
mounts:
|
|
49
|
+
'logs':
|
|
50
|
+
source: local
|
|
51
|
+
source_path: logs
|
|
52
|
+
|
|
53
|
+
# The hooks executed at various points in the lifecycle of the application.
|
|
54
|
+
hooks:
|
|
55
|
+
# The build hook runs before the application is deployed, and is useful for
|
|
56
|
+
# assembling the codebase.
|
|
57
|
+
# DEV: Why remove logs right after making them?
|
|
58
|
+
# Also, may want to split requirements into requirements.txt and requirements_remote.txt.
|
|
59
|
+
build: |
|
|
60
|
+
set -e
|
|
61
|
+
pip install --upgrade pip
|
|
62
|
+
export PIP_USER=false
|
|
63
|
+
curl -sSL https://install.python-poetry.org | python3 - --version $POETRY_VERSION
|
|
64
|
+
export PIP_USER=true
|
|
65
|
+
/app/.local/bin/poetry lock
|
|
66
|
+
/app/.local/bin/poetry export -f requirements.txt --output requirements.txt --without-hashes --with deploy
|
|
67
|
+
pip install -r requirements.txt
|
|
68
|
+
|
|
69
|
+
mkdir logs
|
|
70
|
+
python manage.py collectstatic
|
|
71
|
+
rm -rf logs
|
|
72
|
+
deploy: |
|
|
73
|
+
python manage.py migrate
|
|
74
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{{current_settings}}
|
|
2
|
+
|
|
3
|
+
# Upsun settings.
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
if os.environ.get("PLATFORM_APPLICATION_NAME"):
|
|
7
|
+
# Import some Upsun settings from the environment.
|
|
8
|
+
from platformshconfig import Config
|
|
9
|
+
|
|
10
|
+
config = Config()
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
ALLOWED_HOSTS.append("*")
|
|
14
|
+
except NameError:
|
|
15
|
+
ALLOWED_HOSTS = ["*"]
|
|
16
|
+
|
|
17
|
+
DEBUG = False
|
|
18
|
+
|
|
19
|
+
STATIC_URL = "/static/"
|
|
20
|
+
|
|
21
|
+
if config.appDir:
|
|
22
|
+
STATIC_ROOT = os.path.join(config.appDir, "static")
|
|
23
|
+
if config.projectEntropy:
|
|
24
|
+
SECRET_KEY = config.projectEntropy
|
|
25
|
+
|
|
26
|
+
if not config.in_build():
|
|
27
|
+
db_settings = config.credentials("database")
|
|
28
|
+
DATABASES = {
|
|
29
|
+
"default": {
|
|
30
|
+
"ENGINE": "django.db.backends.postgresql",
|
|
31
|
+
"NAME": db_settings["path"],
|
|
32
|
+
"USER": db_settings["username"],
|
|
33
|
+
"PASSWORD": db_settings["password"],
|
|
34
|
+
"HOST": db_settings["host"],
|
|
35
|
+
"PORT": db_settings["port"],
|
|
36
|
+
},
|
|
37
|
+
"sqlite": {
|
|
38
|
+
"ENGINE": "django.db.backends.sqlite3",
|
|
39
|
+
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
|
40
|
+
},
|
|
41
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Utilities specific to Upsun deployments."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_project_name(output_str):
|
|
5
|
+
"""Get the project name from the output of `upsun project:info`.
|
|
6
|
+
|
|
7
|
+
Command is run with `--format csv` flag.
|
|
8
|
+
|
|
9
|
+
Returns:
|
|
10
|
+
str: project name
|
|
11
|
+
"""
|
|
12
|
+
lines = output_str.splitlines()
|
|
13
|
+
title_line = [line for line in lines if "title," in line][0]
|
|
14
|
+
# Assume first project is one to use.
|
|
15
|
+
project_name = title_line.split(",")[1].strip()
|
|
16
|
+
|
|
17
|
+
return project_name
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_org_names(output_str):
|
|
21
|
+
"""Get org names from output of `upsun organization:list --yes --format csv`.
|
|
22
|
+
|
|
23
|
+
Sample input:
|
|
24
|
+
Name,Label,Owner email
|
|
25
|
+
<org-name>,<org-label>,<org-owner@example.com>
|
|
26
|
+
<org-name-2>,<org-label-2>,<org-owner-2@example.com>
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
list: [str]
|
|
30
|
+
None: If user has no organizations.
|
|
31
|
+
"""
|
|
32
|
+
if "No organizations found." in output_str:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
lines = output_str.split("\n")[1:]
|
|
36
|
+
return [line.split(",")[0] for line in lines if line]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dsd-upsun
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A plugin for django-simple-deploy, supporting deployments to Upsun.
|
|
5
|
+
Author-email: Eric Matthes <ehmatthes@gmail.com>
|
|
6
|
+
Project-URL: Documentation, https://github.com/django-simple-deploy/dsd-upsun
|
|
7
|
+
Project-URL: GitHub, https://github.com/django-simple-deploy/dsd-upsun
|
|
8
|
+
Project-URL: Changelog, https://github.com/django-simple-deploy/dsd-upsun/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: django,deployment
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Framework :: Django :: 4.2
|
|
12
|
+
Classifier: Framework :: Django :: 5.1
|
|
13
|
+
Classifier: Framework :: Django :: 5.2
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: django>=4.2
|
|
28
|
+
Requires-Dist: pluggy>=1.5.0
|
|
29
|
+
Requires-Dist: toml>=0.10.2
|
|
30
|
+
Requires-Dist: requests>=2.32.2
|
|
31
|
+
Requires-Dist: django-simple-deploy>=1.3.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: black>=24.1.0; extra == "dev"
|
|
34
|
+
Requires-Dist: build>=1.2.1; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
36
|
+
Requires-Dist: twine>=5.1.1; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# dsd-upsun
|
|
40
|
+
|
|
41
|
+
A plugin for deploying Django projects to Upsun, using django-simple-deploy.
|
|
42
|
+
|
|
43
|
+
For full documentation, see the documentation for [django-simple-deploy](https://django-simple-deploy.readthedocs.io/en/latest/).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
dsd_upsun/__init__.py
|
|
6
|
+
dsd_upsun/deploy.py
|
|
7
|
+
dsd_upsun/deploy_messages.py
|
|
8
|
+
dsd_upsun/platform_deployer.py
|
|
9
|
+
dsd_upsun/plugin_config.py
|
|
10
|
+
dsd_upsun/utils.py
|
|
11
|
+
dsd_upsun.egg-info/PKG-INFO
|
|
12
|
+
dsd_upsun.egg-info/SOURCES.txt
|
|
13
|
+
dsd_upsun.egg-info/dependency_links.txt
|
|
14
|
+
dsd_upsun.egg-info/requires.txt
|
|
15
|
+
dsd_upsun.egg-info/top_level.txt
|
|
16
|
+
dsd_upsun/templates/pipenv.platform.app.yaml
|
|
17
|
+
dsd_upsun/templates/platform.app.yaml
|
|
18
|
+
dsd_upsun/templates/poetry.platform.app.yaml
|
|
19
|
+
dsd_upsun/templates/services.yaml
|
|
20
|
+
dsd_upsun/templates/settings.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dsd_upsun
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dsd-upsun"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A plugin for django-simple-deploy, supporting deployments to Upsun."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "Eric Matthes", email = "ehmatthes@gmail.com" },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Framework :: Django :: 4.2",
|
|
18
|
+
"Framework :: Django :: 5.1",
|
|
19
|
+
"Framework :: Django :: 5.2",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: OSI Approved :: BSD License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
keywords = ["django", "deployment"]
|
|
33
|
+
|
|
34
|
+
requires-python = ">=3.9"
|
|
35
|
+
|
|
36
|
+
dependencies = [
|
|
37
|
+
"django>=4.2",
|
|
38
|
+
"pluggy>=1.5.0",
|
|
39
|
+
"toml>=0.10.2",
|
|
40
|
+
"requests>=2.32.2",
|
|
41
|
+
"django-simple-deploy>=1.3.0"
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
dev = [
|
|
46
|
+
"black>=24.1.0",
|
|
47
|
+
"build>=1.2.1",
|
|
48
|
+
"pytest>=8.3.0",
|
|
49
|
+
"twine>=5.1.1",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
"Documentation" = "https://github.com/django-simple-deploy/dsd-upsun"
|
|
54
|
+
"GitHub" = "https://github.com/django-simple-deploy/dsd-upsun"
|
|
55
|
+
"Changelog" = "https://github.com/django-simple-deploy/dsd-upsun/blob/main/CHANGELOG.md"
|
|
56
|
+
|
|
57
|
+
[tool.setuptools]
|
|
58
|
+
packages = [
|
|
59
|
+
"dsd_upsun",
|
|
60
|
+
"dsd_upsun.templates",
|
|
61
|
+
]
|
|
62
|
+
include-package-data = true
|