locust-cloud 1.16.1__py3-none-any.whl → 1.17.0.dev0__py3-none-any.whl
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.
- locust_cloud/__init__.py +18 -0
- locust_cloud/args.py +50 -73
- locust_cloud/cloud.py +16 -23
- {locust_cloud-1.16.1.dist-info → locust_cloud-1.17.0.dev0.dist-info}/METADATA +5 -2
- locust_cloud-1.17.0.dev0.dist-info/RECORD +13 -0
- locust_cloud-1.17.0.dev0.dist-info/licenses/LICENSE +21 -0
- locust_cloud-1.16.1.dist-info/RECORD +0 -11
- {locust_cloud-1.16.1.dist-info → locust_cloud-1.17.0.dev0.dist-info}/WHEEL +0 -0
- {locust_cloud-1.16.1.dist-info → locust_cloud-1.17.0.dev0.dist-info}/entry_points.txt +0 -0
locust_cloud/__init__.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
from locust import events
|
2
|
+
from locust_cloud.args import cloud_parser
|
3
|
+
from locust_cloud.cloud import main
|
4
|
+
|
5
|
+
__all__ = ["main"]
|
6
|
+
|
7
|
+
|
8
|
+
@events.init_command_line_parser.add_listener
|
9
|
+
def _(parser):
|
10
|
+
cloud_group = parser.add_argument_group(
|
11
|
+
"Locust Cloud",
|
12
|
+
"""Launches a distributed Locust run on locust.cloud infrastructure.
|
13
|
+
|
14
|
+
Example: locust --cloud -f my_locustfile.py --users 1000 ...""",
|
15
|
+
)
|
16
|
+
|
17
|
+
for action in cloud_parser._actions:
|
18
|
+
cloud_group._add_action(action)
|
locust_cloud/args.py
CHANGED
@@ -4,8 +4,14 @@ import gzip
|
|
4
4
|
import io
|
5
5
|
import os
|
6
6
|
import pathlib
|
7
|
-
import
|
8
|
-
|
7
|
+
import sys
|
8
|
+
|
9
|
+
if sys.version_info >= (3, 11):
|
10
|
+
import tomllib
|
11
|
+
else:
|
12
|
+
import tomli as tomllib
|
13
|
+
|
14
|
+
from argparse import ArgumentTypeError
|
9
15
|
from collections import OrderedDict
|
10
16
|
from collections.abc import Callable, Generator
|
11
17
|
from typing import IO, Any, cast
|
@@ -103,11 +109,8 @@ class MergeToTransferEncodedZip(argparse.Action):
|
|
103
109
|
setattr(namespace, self.dest, value)
|
104
110
|
|
105
111
|
|
106
|
-
|
112
|
+
cloud_parser = configargparse.ArgumentParser(
|
107
113
|
default_config_files=[
|
108
|
-
"~/.locust.conf",
|
109
|
-
"locust.conf",
|
110
|
-
"pyproject.toml",
|
111
114
|
"~/.cloud.conf",
|
112
115
|
"cloud.conf",
|
113
116
|
],
|
@@ -119,100 +122,55 @@ parser = configargparse.ArgumentParser(
|
|
119
122
|
configargparse.DefaultConfigFileParser,
|
120
123
|
]
|
121
124
|
),
|
122
|
-
description="""Launches a distributed Locust runs on locust.cloud infrastructure.
|
123
|
-
|
124
|
-
Example: locust-cloud -f my_locustfile.py --users 1000 ...""",
|
125
|
-
epilog="""Any parameters not listed here are forwarded to locust master unmodified, so go ahead and use things like --users, --host, --run-time, ...
|
126
|
-
Locust config can also be set using config file (~/.locust.conf, locust.conf, pyproject.toml, ~/.cloud.conf or cloud.conf).
|
127
|
-
Parameters specified on command line override env vars, which in turn override config files.""",
|
128
|
-
add_config_file_help=False,
|
129
|
-
add_env_var_help=False,
|
130
125
|
add_help=False,
|
131
126
|
)
|
132
|
-
|
133
|
-
"
|
134
|
-
"--help",
|
135
|
-
action="help",
|
136
|
-
help=configargparse.SUPPRESS,
|
137
|
-
)
|
138
|
-
parser.add_argument(
|
139
|
-
"-V",
|
140
|
-
"--version",
|
127
|
+
cloud_parser.add_argument(
|
128
|
+
"--cloud",
|
141
129
|
action="store_true",
|
142
|
-
help=
|
130
|
+
help="Run Locust in cloud mode.",
|
143
131
|
)
|
144
|
-
|
145
|
-
"
|
146
|
-
"
|
147
|
-
|
148
|
-
default="locustfile.py",
|
149
|
-
help="The Python file that contains your test. Defaults to 'locustfile.py'.",
|
150
|
-
env_var="LOCUST_LOCUSTFILE",
|
151
|
-
type=transfer_encoded_file,
|
152
|
-
)
|
153
|
-
parser.add_argument(
|
154
|
-
"-u",
|
155
|
-
"--users",
|
156
|
-
type=int,
|
157
|
-
default=1,
|
158
|
-
help="Number of users to launch. This is the same as the regular Locust argument, but also affects how many workers to launch.",
|
159
|
-
env_var="LOCUST_USERS",
|
132
|
+
cloud_parser.add_argument(
|
133
|
+
"--login",
|
134
|
+
action="store_true",
|
135
|
+
help="Launch an interactive session to authenticate your user.\nOnce completed your credentials will be stored and automatically refreshed for quite a long time.\nOnce those expires you will be prompted to perform another login.",
|
160
136
|
)
|
161
|
-
|
162
|
-
|
163
|
-
"
|
164
|
-
"-
|
165
|
-
type=str.upper,
|
166
|
-
help="Set --loglevel DEBUG for extra info.",
|
167
|
-
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
168
|
-
default="INFO",
|
137
|
+
cloud_parser.add_argument(
|
138
|
+
"--delete",
|
139
|
+
action="store_true",
|
140
|
+
help="Delete a running cluster. Useful if locust-cloud was killed/disconnected or if there was an error.",
|
169
141
|
)
|
170
|
-
|
142
|
+
cloud_parser.add_argument(
|
171
143
|
"--requirements",
|
144
|
+
metavar="<filename>",
|
172
145
|
type=transfer_encoded_file,
|
173
146
|
help="Optional requirements.txt file that contains your external libraries.",
|
174
147
|
)
|
175
|
-
|
176
|
-
"--login",
|
177
|
-
action="store_true",
|
178
|
-
default=False,
|
179
|
-
help="Launch an interactive session to authenticate your user.\nOnce completed your credentials will be stored and automatically refreshed for quite a long time.\nOnce those expires you will be prompted to perform another login.",
|
180
|
-
)
|
181
|
-
advanced.add_argument(
|
148
|
+
cloud_parser.add_argument(
|
182
149
|
"--non-interactive",
|
183
150
|
action="store_true",
|
184
151
|
default=False,
|
185
152
|
help="This can be set when, for example, running in a CI/CD environment to ensure no interactive steps while executing.\nRequires that LOCUSTCLOUD_USERNAME, LOCUSTCLOUD_PASSWORD and LOCUSTCLOUD_REGION environment variables are set.",
|
186
153
|
)
|
187
|
-
|
154
|
+
cloud_parser.add_argument(
|
188
155
|
"--workers",
|
156
|
+
metavar="<int>",
|
189
157
|
type=int,
|
190
158
|
help="Number of workers to use for the deployment. Defaults to number of users divided by 500, but the default may be customized for your account.",
|
191
159
|
default=None,
|
192
160
|
)
|
193
|
-
|
194
|
-
"--delete",
|
195
|
-
action="store_true",
|
196
|
-
help="Delete a running cluster. Useful if locust-cloud was killed/disconnected or if there was an error.",
|
197
|
-
)
|
198
|
-
parser.add_argument(
|
161
|
+
cloud_parser.add_argument(
|
199
162
|
"--image-tag",
|
200
163
|
type=str,
|
201
164
|
default=None,
|
202
165
|
help=configargparse.SUPPRESS, # overrides the locust-cloud docker image tag. for internal use
|
203
166
|
)
|
204
|
-
|
167
|
+
cloud_parser.add_argument(
|
205
168
|
"--mock-server",
|
206
169
|
action="store_true",
|
207
170
|
default=False,
|
208
171
|
help="Start a demo mock service and set --host parameter to point Locust towards it",
|
209
172
|
)
|
210
|
-
|
211
|
-
"--profile",
|
212
|
-
type=str,
|
213
|
-
help="Set a profile to group the testruns together",
|
214
|
-
)
|
215
|
-
parser.add_argument(
|
173
|
+
cloud_parser.add_argument(
|
216
174
|
"--extra-files",
|
217
175
|
action=MergeToTransferEncodedZip,
|
218
176
|
nargs="*",
|
@@ -220,6 +178,25 @@ parser.add_argument(
|
|
220
178
|
help="A list of extra files or directories to upload. Space-separated, e.g. --extra-files testdata.csv *.py my-directory/",
|
221
179
|
)
|
222
180
|
|
223
|
-
|
224
|
-
|
225
|
-
|
181
|
+
combined_cloud_parser = configargparse.ArgumentParser(parents=[cloud_parser])
|
182
|
+
combined_cloud_parser.add_argument(
|
183
|
+
"-f",
|
184
|
+
"--locustfile",
|
185
|
+
default="locustfile.py",
|
186
|
+
env_var="LOCUST_LOCUSTFILE",
|
187
|
+
type=transfer_encoded_file,
|
188
|
+
)
|
189
|
+
combined_cloud_parser.add_argument(
|
190
|
+
"-u",
|
191
|
+
"--users",
|
192
|
+
type=int,
|
193
|
+
default=1,
|
194
|
+
env_var="LOCUST_USERS",
|
195
|
+
)
|
196
|
+
combined_cloud_parser.add_argument(
|
197
|
+
"--loglevel",
|
198
|
+
"-L",
|
199
|
+
type=str.upper,
|
200
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
201
|
+
default="INFO",
|
202
|
+
)
|
locust_cloud/cloud.py
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
|
-
import sys
|
4
3
|
import time
|
5
4
|
import webbrowser
|
6
5
|
from threading import Thread
|
7
6
|
|
8
7
|
import requests
|
9
8
|
from locust_cloud.apisession import ApiSession
|
10
|
-
from locust_cloud.args import
|
9
|
+
from locust_cloud.args import combined_cloud_parser
|
11
10
|
from locust_cloud.common import __version__
|
12
11
|
from locust_cloud.input_events import input_listener
|
13
12
|
from locust_cloud.web_login import web_login
|
@@ -28,30 +27,28 @@ def configure_logging(loglevel: str) -> None:
|
|
28
27
|
logging.getLogger("urllib3").setLevel(logging.INFO)
|
29
28
|
|
30
29
|
|
31
|
-
def main()
|
32
|
-
options, locust_options = parse_known_args()
|
30
|
+
def main():
|
31
|
+
options, locust_options = combined_cloud_parser.parse_known_args()
|
32
|
+
|
33
33
|
configure_logging(options.loglevel)
|
34
34
|
|
35
|
-
if options.version:
|
36
|
-
print(f"locust-cloud version {__version__}")
|
37
|
-
sys.exit(0)
|
38
35
|
if not options.locustfile:
|
39
36
|
logger.error("A locustfile is required to run a test.")
|
40
|
-
|
37
|
+
return 1
|
41
38
|
|
42
39
|
if options.login:
|
43
40
|
try:
|
44
41
|
web_login()
|
45
42
|
except KeyboardInterrupt:
|
46
43
|
pass
|
47
|
-
|
44
|
+
return
|
48
45
|
|
49
46
|
session = ApiSession(options.non_interactive)
|
50
47
|
websocket = Websocket()
|
51
48
|
|
52
49
|
if options.delete:
|
53
50
|
delete(session)
|
54
|
-
|
51
|
+
return
|
55
52
|
|
56
53
|
try:
|
57
54
|
logger.info(f"Deploying ({session.region}, {__version__})")
|
@@ -67,12 +64,12 @@ def main() -> None:
|
|
67
64
|
"LOCUST_SKIP_MONKEY_PATCH",
|
68
65
|
]
|
69
66
|
]
|
67
|
+
|
70
68
|
payload = {
|
71
69
|
"locust_args": [
|
72
70
|
{"name": "LOCUST_USERS", "value": str(options.users)},
|
73
71
|
{"name": "LOCUST_FLAGS", "value": " ".join(locust_options)},
|
74
72
|
{"name": "LOCUSTCLOUD_DEPLOYER_URL", "value": session.api_url},
|
75
|
-
{"name": "LOCUSTCLOUD_PROFILE", "value": options.profile},
|
76
73
|
*locust_env_variables,
|
77
74
|
],
|
78
75
|
"locustfile": options.locustfile,
|
@@ -107,10 +104,10 @@ def main() -> None:
|
|
107
104
|
time.sleep(2)
|
108
105
|
except requests.exceptions.RequestException as e:
|
109
106
|
logger.error(f"Failed to deploy the load generators: {e}")
|
110
|
-
|
107
|
+
return 1
|
111
108
|
else:
|
112
|
-
logger.error("Your Locust instance is still running, run locust
|
113
|
-
|
109
|
+
logger.error("Your Locust instance is still running, run locust --cloud --delete")
|
110
|
+
return 1
|
114
111
|
|
115
112
|
if response.status_code != 200:
|
116
113
|
try:
|
@@ -119,7 +116,7 @@ def main() -> None:
|
|
119
116
|
logger.error(
|
120
117
|
f"HTTP {response.status_code}/{response.reason} - Response: {response.text} - URL: {response.request.url}"
|
121
118
|
)
|
122
|
-
|
119
|
+
return 1
|
123
120
|
|
124
121
|
log_ws_url = js["log_ws_url"]
|
125
122
|
session_id = js["session_id"]
|
@@ -146,19 +143,19 @@ def main() -> None:
|
|
146
143
|
websocket.wait(timeout=True)
|
147
144
|
except (WebsocketTimeout, SessionMismatchError) as e:
|
148
145
|
logger.error(str(e))
|
149
|
-
|
146
|
+
return 1
|
150
147
|
except WebsocketTimeout as e:
|
151
148
|
logger.error(str(e))
|
152
149
|
delete(session)
|
153
|
-
|
150
|
+
return 1
|
154
151
|
except SessionMismatchError as e:
|
155
152
|
# In this case we do not trigger the teardown since the running instance is not ours
|
156
153
|
logger.error(str(e))
|
157
|
-
|
154
|
+
return 1
|
158
155
|
except Exception as e:
|
159
156
|
logger.exception(e)
|
160
157
|
delete(session)
|
161
|
-
|
158
|
+
return 1
|
162
159
|
else:
|
163
160
|
delete(session)
|
164
161
|
finally:
|
@@ -183,7 +180,3 @@ def delete(session):
|
|
183
180
|
pass # don't show nasty callstack
|
184
181
|
except Exception as e:
|
185
182
|
logger.error(f"Could not automatically tear down Locust Cloud: {e.__class__.__name__}:{e}")
|
186
|
-
|
187
|
-
|
188
|
-
if __name__ == "__main__":
|
189
|
-
main()
|
@@ -1,15 +1,18 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: locust-cloud
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.17.0.dev0
|
4
4
|
Summary: Locust Cloud
|
5
5
|
Project-URL: Homepage, https://locust.cloud
|
6
|
-
|
6
|
+
License-File: LICENSE
|
7
|
+
Requires-Python: >=3.10
|
7
8
|
Requires-Dist: configargparse==1.7
|
8
9
|
Requires-Dist: gevent>=24.11.1
|
10
|
+
Requires-Dist: locust>=2.34.0
|
9
11
|
Requires-Dist: platformdirs>=4.3.6
|
10
12
|
Requires-Dist: pyjwt>=2.0
|
11
13
|
Requires-Dist: python-socketio[client]==5.11.4
|
12
14
|
Requires-Dist: requests==2.32.3
|
15
|
+
Requires-Dist: tomli>=1.1.0; python_version < '3.11'
|
13
16
|
Description-Content-Type: text/markdown
|
14
17
|
|
15
18
|
# Locust Cloud
|
@@ -0,0 +1,13 @@
|
|
1
|
+
locust_cloud/__init__.py,sha256=NPggKqjx13UKmmgoG6dpoXOyA1liGBAUP8pz6OSpBvI,488
|
2
|
+
locust_cloud/apisession.py,sha256=kCr271_l0IeMGw0L563mOecqPJj4OD9h2J3vxCM5zYQ,4015
|
3
|
+
locust_cloud/args.py,sha256=zf8Cowg1aMnDdPkujKDlMHYUjvadF_wPVkxOxt2fQpw,6056
|
4
|
+
locust_cloud/cloud.py,sha256=RbW7p4pQWIcvaYe_80BwNiBC8YHmrX-1tE5X8Bi0dH0,5912
|
5
|
+
locust_cloud/common.py,sha256=cFrDVKpi9OEmH6giOuj9HoIUFSBArixNtNHzZIgDvPE,992
|
6
|
+
locust_cloud/input_events.py,sha256=MyxccgboHByICuK6VpQCCJhZQqTZAacNmkSpw-gxBEw,3420
|
7
|
+
locust_cloud/web_login.py,sha256=1j2AQoEM6XVSDtE1q0Ryrs4jFEx07r9IQfZCoFAQXJg,2400
|
8
|
+
locust_cloud/websocket.py,sha256=9Q7nTFuAwVhgW74DlJNcHTZXOQ1drsXi8hX9ciZhWlQ,8998
|
9
|
+
locust_cloud-1.17.0.dev0.dist-info/METADATA,sha256=bvZTd_asbLJ9xxS7Bsx7-Xr2pKGvsJ-lsi3p3HJuUUA,638
|
10
|
+
locust_cloud-1.17.0.dev0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
11
|
+
locust_cloud-1.17.0.dev0.dist-info/entry_points.txt,sha256=PGyAb4e3aTsGS3N3VGShDl6VzJaXy7QwsEgsLOC7V00,57
|
12
|
+
locust_cloud-1.17.0.dev0.dist-info/licenses/LICENSE,sha256=Ow6fY6ta4KIjdlWalmxGvRP8yLmetvkbkl-SdHMjPIs,1093
|
13
|
+
locust_cloud-1.17.0.dev0.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024-present, Locust Technologies Inc
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
@@ -1,11 +0,0 @@
|
|
1
|
-
locust_cloud/apisession.py,sha256=kCr271_l0IeMGw0L563mOecqPJj4OD9h2J3vxCM5zYQ,4015
|
2
|
-
locust_cloud/args.py,sha256=4U_bZaEH1UJR8C7_bH_sX1DRB8m6WBcJh-ewhilFQX0,7118
|
3
|
-
locust_cloud/cloud.py,sha256=kih2Qtddry0dxmGylxXQdrw4SPTwx6k6YN0ur3u47Qc,6144
|
4
|
-
locust_cloud/common.py,sha256=cFrDVKpi9OEmH6giOuj9HoIUFSBArixNtNHzZIgDvPE,992
|
5
|
-
locust_cloud/input_events.py,sha256=MyxccgboHByICuK6VpQCCJhZQqTZAacNmkSpw-gxBEw,3420
|
6
|
-
locust_cloud/web_login.py,sha256=1j2AQoEM6XVSDtE1q0Ryrs4jFEx07r9IQfZCoFAQXJg,2400
|
7
|
-
locust_cloud/websocket.py,sha256=9Q7nTFuAwVhgW74DlJNcHTZXOQ1drsXi8hX9ciZhWlQ,8998
|
8
|
-
locust_cloud-1.16.1.dist-info/METADATA,sha256=4EHCv-Hpo9NR-IThvTMiJR9t5EWfdjARKBt2V2QApBQ,528
|
9
|
-
locust_cloud-1.16.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
-
locust_cloud-1.16.1.dist-info/entry_points.txt,sha256=PGyAb4e3aTsGS3N3VGShDl6VzJaXy7QwsEgsLOC7V00,57
|
11
|
-
locust_cloud-1.16.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|