stoobly-agent 1.9.4__py3-none-any.whl → 1.9.6__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.
- stoobly_agent/__init__.py +1 -1
- stoobly_agent/app/cli/ca_cert_cli.py +18 -3
- stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +4 -4
- stoobly_agent/app/cli/scaffold/templates/app/.Makefile +15 -14
- stoobly_agent/app/cli/scaffold_cli.py +34 -44
- stoobly_agent/app/cli/snapshot_cli.py +2 -2
- stoobly_agent/app/cli/validators/scaffold.py +34 -0
- stoobly_agent/test/app/cli/scaffold/cli_invoker.py +3 -3
- stoobly_agent/test/app/cli/snapshot/snapshot_update_test.py +1 -1
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- {stoobly_agent-1.9.4.dist-info → stoobly_agent-1.9.6.dist-info}/METADATA +1 -1
- {stoobly_agent-1.9.4.dist-info → stoobly_agent-1.9.6.dist-info}/RECORD +15 -14
- {stoobly_agent-1.9.4.dist-info → stoobly_agent-1.9.6.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.9.4.dist-info → stoobly_agent-1.9.6.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.9.4.dist-info → stoobly_agent-1.9.6.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '1.9.
|
2
|
+
VERSION = '1.9.6'
|
@@ -15,8 +15,18 @@ def ca_cert(ctx):
|
|
15
15
|
pass
|
16
16
|
|
17
17
|
@ca_cert.command()
|
18
|
-
@click.option(
|
19
|
-
|
18
|
+
@click.option(
|
19
|
+
'--ca-certs-dir-path',
|
20
|
+
default=DataDir.instance().ca_certs_dir_path,
|
21
|
+
help='Path to ca certs directory used to sign SSL certs.',
|
22
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True)
|
23
|
+
)
|
24
|
+
@click.option(
|
25
|
+
'--certs-dir-path',
|
26
|
+
default=DataDir.instance().certs_dir_path,
|
27
|
+
help='Output directory.',
|
28
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True)
|
29
|
+
)
|
20
30
|
@click.argument('hostname')
|
21
31
|
def mkcert(**kwargs):
|
22
32
|
ca_certs_dir_path = kwargs['ca_certs_dir_path']
|
@@ -30,7 +40,12 @@ def mkcert(**kwargs):
|
|
30
40
|
sys.exit(1)
|
31
41
|
|
32
42
|
@ca_cert.command()
|
33
|
-
@click.option(
|
43
|
+
@click.option(
|
44
|
+
'--ca-certs-dir-path',
|
45
|
+
default=DataDir.instance().ca_certs_dir_path,
|
46
|
+
help='Path to ca certs directory.',
|
47
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True)
|
48
|
+
)
|
34
49
|
def install(**kwargs):
|
35
50
|
ca_certs_dir_path = kwargs['ca_certs_dir_path']
|
36
51
|
installer = CertificateAuthority(ca_certs_dir_path)
|
@@ -10,7 +10,7 @@ from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
|
10
10
|
from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE
|
11
11
|
from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
|
12
12
|
|
13
|
-
def configure_gateway(service_paths: List[str], no_publish = False):
|
13
|
+
def configure_gateway(workflow_name, service_paths: List[str], no_publish = False):
|
14
14
|
if len(service_paths) == 0:
|
15
15
|
return
|
16
16
|
|
@@ -36,7 +36,7 @@ def configure_gateway(service_paths: List[str], no_publish = False):
|
|
36
36
|
gateway_base['ports'] = ports
|
37
37
|
|
38
38
|
app_dir_path = os.path.dirname(os.path.dirname(service_dir_path))
|
39
|
-
__with_traefik_config(service_paths,
|
39
|
+
__with_traefik_config(workflow_name, service_paths, app_dir_path, gateway_base)
|
40
40
|
__with_networks(gateway_base, hostnames)
|
41
41
|
|
42
42
|
with open(docker_compose_dest_path, 'w') as fp:
|
@@ -50,7 +50,7 @@ def __with_networks(config: dict, hostnames: List[str]):
|
|
50
50
|
'aliases': hostnames
|
51
51
|
}
|
52
52
|
|
53
|
-
def __with_traefik_config(
|
53
|
+
def __with_traefik_config(workflow_name: str, service_paths: List[str], app_dir_path: str, compose: dict):
|
54
54
|
config_dest = '/etc/traefik/traefik.yml'
|
55
55
|
|
56
56
|
if not compose['volumes']:
|
@@ -98,7 +98,7 @@ def __with_traefik_config(service_paths: str, compose: dict, app_dir_path: str):
|
|
98
98
|
})
|
99
99
|
|
100
100
|
# Create traefik.yml in .stoobly/tmp
|
101
|
-
traefik_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, 'traefik.yml')
|
101
|
+
traefik_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, workflow_name, 'traefik.yml')
|
102
102
|
traefik_template_dest_path = os.path.join(app_dir_path, traefik_template_relative_path)
|
103
103
|
|
104
104
|
if not os.path.exists(os.path.dirname(traefik_template_dest_path)):
|
@@ -33,8 +33,9 @@ app_namespace_dir=$(app_data_dir)/docker
|
|
33
33
|
app_tmp_dir=$(app_data_dir)/tmp
|
34
34
|
dockerfile_path=$(app_namespace_dir)/.Dockerfile.context
|
35
35
|
exec_docker_compose_file_path=$(app_namespace_dir)/stoobly-ui/exec/.docker-compose.exec.yml
|
36
|
-
exec_namespace=$(shell echo $(context_dir) | (md5 2>/dev/null || md5sum 2>/dev/null || shasum 2>/dev/null) | awk '{print $$1}')
|
37
|
-
|
36
|
+
exec_namespace=$(shell echo "$(workflow_namespace).$(context_dir)" | (md5 2>/dev/null || md5sum 2>/dev/null || shasum 2>/dev/null) | awk '{print $$1}')
|
37
|
+
workflow_namespace=$(if $(namespace),$(namespace),$(workflow))
|
38
|
+
workflow_script=.stoobly/tmp/$(workflow_namespace)/run.sh
|
38
39
|
|
39
40
|
# Options
|
40
41
|
certs_dir_options=--ca-certs-dir-path $(ca_certs_dir) --certs-dir-path $(certs_dir)
|
@@ -43,7 +44,7 @@ working_dir_options=--app-dir-path $(app_dir) --context-dir-path $(context_dir)
|
|
43
44
|
|
44
45
|
workflow_down_options=--user-id $(USER_ID) $(workflow_down_extra_options)
|
45
46
|
workflow_log_options=$(workflow_log_extra_options)
|
46
|
-
workflow_run_options=--script-path $(workflow_script) $(workflow_service_options)
|
47
|
+
workflow_run_options=--namespace $(workflow_namespace) --script-path $(workflow_script) $(workflow_service_options)
|
47
48
|
workflow_up_options=$(working_dir_options) $(certs_dir_options) --user-id $(USER_ID) $(workflow_up_extra_options)
|
48
49
|
|
49
50
|
# Commands
|
@@ -51,8 +52,8 @@ docker_command=docker
|
|
51
52
|
docker_compose_command=$(docker_command) compose
|
52
53
|
exec_down=$(docker_compose_command) -f "$(exec_docker_compose_file_path)" $(stoobly_exec_options) down
|
53
54
|
exec_env=APP_DIR="$(app_dir)" CA_CERTS_DIR="$(ca_certs_dir)" USER_ID="$(USER_ID)"
|
54
|
-
exec_up=$(docker_compose_command) -f "$(exec_docker_compose_file_path)" $(stoobly_exec_options) up --remove-orphans
|
55
|
-
source_env=set -a; [ -f .env ] && source .env; set +a
|
55
|
+
exec_up=$(docker_compose_command) -f "$(exec_docker_compose_file_path)" $(stoobly_exec_options) up --abort-on-container-exit --remove-orphans
|
56
|
+
source_env=(set -a; [ -f .env ] && source .env; set +a)
|
56
57
|
|
57
58
|
# Build base image
|
58
59
|
stoobly_exec_build=$(docker_command) build $(stoobly_exec_build_args) $(app_namespace_dir)
|
@@ -71,6 +72,10 @@ stoobly_exec_run_env=$(source_env) && $(exec_env) CONTEXT_DIR="$(app_dir)"
|
|
71
72
|
# Workflow run
|
72
73
|
workflow_run=$(source_env) && bash "$(app_dir)/$(workflow_script)"
|
73
74
|
|
75
|
+
action/install:
|
76
|
+
$(eval action=install)
|
77
|
+
action/uninstall:
|
78
|
+
$(eval action=uninstall)
|
74
79
|
ca-cert/install: stoobly/install
|
75
80
|
@if [ -z "$$(ls $(ca_certs_dir) 2> /dev/null)" ]; then \
|
76
81
|
read -p "Installing CA certificate is required for $(workflow)ing requests, continue? (y/N) " confirm && \
|
@@ -84,10 +89,6 @@ ca-cert/install: stoobly/install
|
|
84
89
|
certs:
|
85
90
|
@export EXEC_COMMAND=.mkcert && \
|
86
91
|
$(stoobly_exec)
|
87
|
-
command/install:
|
88
|
-
$(eval COMMAND=install)
|
89
|
-
command/uninstall:
|
90
|
-
$(eval COMMAND=uninstall)
|
91
92
|
exec/down:
|
92
93
|
@$(stoobly_exec_env) EXEC_COMMAND=- EXEC_ARGS=- EXEC_OPTIONS=- $(exec_down)
|
93
94
|
nameservers: tmpdir
|
@@ -179,7 +180,7 @@ workflow/down:
|
|
179
180
|
$(stoobly_exec_run) && \
|
180
181
|
$(workflow_run)
|
181
182
|
workflow/hostname: stoobly/install
|
182
|
-
@read -p "Do you want to $(
|
183
|
+
@read -p "Do you want to $(action) hostname(s) in /etc/hosts? (y/N) " confirm && \
|
183
184
|
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
|
184
185
|
CURRENT_VERSION=$$(stoobly-agent --version); \
|
185
186
|
REQUIRED_VERSION="1.4.0"; \
|
@@ -187,11 +188,11 @@ workflow/hostname: stoobly/install
|
|
187
188
|
echo "stoobly-agent version $$REQUIRED_VERSION required. Please run: pipx upgrade stoobly-agent"; \
|
188
189
|
exit 1; \
|
189
190
|
fi; \
|
190
|
-
echo "Running stoobly-agent scaffold hostname $(
|
191
|
-
stoobly-agent scaffold hostname $(
|
191
|
+
echo "Running stoobly-agent scaffold hostname $(action) $(workflow_service_options)"; \
|
192
|
+
stoobly-agent scaffold hostname $(action) --app-dir-path $(app_dir) --workflow $(workflow) $(workflow_service_options); \
|
192
193
|
fi
|
193
|
-
workflow/hostname/install:
|
194
|
-
workflow/hostname/uninstall:
|
194
|
+
workflow/hostname/install: action/install workflow/hostname
|
195
|
+
workflow/hostname/uninstall: action/uninstall workflow/hostname
|
195
196
|
workflow/logs:
|
196
197
|
@export EXEC_COMMAND=.logs && \
|
197
198
|
export EXEC_OPTIONS="$(workflow_log_options) $(workflow_run_options) $(options)" && \
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import click
|
2
2
|
import os
|
3
3
|
import pdb
|
4
|
-
import re
|
5
4
|
import sys
|
6
5
|
|
7
6
|
from io import TextIOWrapper
|
@@ -37,6 +36,7 @@ from stoobly_agent.config.data_dir import DataDir
|
|
37
36
|
from stoobly_agent.lib.logger import bcolors, DEBUG, ERROR, INFO, Logger, WARNING
|
38
37
|
|
39
38
|
from .helpers.print_service import FORMATS, print_services, select_print_options
|
39
|
+
from .validators.scaffold import validate_app_name, validate_hostname, validate_namespace, validate_service_name
|
40
40
|
|
41
41
|
LOG_ID = 'Scaffold'
|
42
42
|
|
@@ -87,22 +87,22 @@ def hostname(ctx):
|
|
87
87
|
help="Scaffold application"
|
88
88
|
)
|
89
89
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to create the app scaffold.')
|
90
|
-
@click.option('--force', is_flag=True, help='Overwrite maintained scaffolded app files.')
|
91
90
|
@click.option('--network', help='App default network name. Defaults to app name.')
|
91
|
+
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
92
92
|
@click.option('--ui-port', default=4200, type=click.IntRange(1, 65535), help='UI service port.')
|
93
|
-
@click.argument('app_name')
|
93
|
+
@click.argument('app_name', callback=validate_app_name)
|
94
94
|
def create(**kwargs):
|
95
95
|
__validate_app_dir(kwargs['app_dir_path'])
|
96
96
|
|
97
97
|
app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
|
98
98
|
|
99
|
-
if kwargs['
|
100
|
-
|
101
|
-
kwargs['network'] = kwargs['app_name']
|
99
|
+
if not kwargs['quiet'] and os.path.exists(app.scaffold_namespace_path):
|
100
|
+
print(f"{kwargs['app_dir_path']} already exists, updating scaffold maintained files...")
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
if not kwargs['network']:
|
103
|
+
kwargs['network'] = kwargs['app_name']
|
104
|
+
|
105
|
+
AppCreateCommand(app, **kwargs).build()
|
106
106
|
|
107
107
|
@app.command(
|
108
108
|
help="Scaffold app service certs"
|
@@ -129,8 +129,7 @@ def mkcert(**kwargs):
|
|
129
129
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
|
130
130
|
@click.option('--detached', is_flag=True, help='Use isolated and non-persistent context directory.')
|
131
131
|
@click.option('--env', multiple=True, help='Specify an environment variable.')
|
132
|
-
@click.option('--
|
133
|
-
@click.option('--hostname', help='Service hostname.')
|
132
|
+
@click.option('--hostname', callback=validate_hostname, help='Service hostname.')
|
134
133
|
@click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
|
135
134
|
@click.option('--priority', default=5, type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
|
136
135
|
@click.option('--proxy-mode', help='''
|
@@ -139,9 +138,10 @@ def mkcert(**kwargs):
|
|
139
138
|
upstream proxy modes, SPEC is host specification in
|
140
139
|
the form of "http[s]://host[:port]".
|
141
140
|
''')
|
141
|
+
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
142
142
|
@click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
|
143
143
|
@click.option('--workflow', multiple=True, type=click.Choice([WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]), help='Include pre-defined workflows.')
|
144
|
-
@click.argument('service_name')
|
144
|
+
@click.argument('service_name', callback=validate_service_name)
|
145
145
|
def create(**kwargs):
|
146
146
|
__validate_app_dir(kwargs['app_dir_path'])
|
147
147
|
|
@@ -149,19 +149,16 @@ def create(**kwargs):
|
|
149
149
|
print(f"Error: {kwargs['service_name']} is invalid. It cannot container '/", file=sys.stderr)
|
150
150
|
sys.exit(1)
|
151
151
|
|
152
|
-
if kwargs.get('hostname'):
|
153
|
-
__validate_hostname(kwargs.get('hostname'))
|
154
|
-
|
155
152
|
if kwargs.get("proxy_mode"):
|
156
153
|
__validate_proxy_mode(kwargs.get("proxy_mode"))
|
157
154
|
|
158
155
|
app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
|
159
|
-
|
160
156
|
service = Service(kwargs['service_name'], app)
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
157
|
+
|
158
|
+
if not kwargs['quiet'] and os.path.exists(service.dir_path):
|
159
|
+
print(f"{service.dir_path} already exists, updating scaffold maintained files...")
|
160
|
+
|
161
|
+
__scaffold_build(app, **kwargs)
|
165
162
|
|
166
163
|
@service.command(
|
167
164
|
help="List services",
|
@@ -214,7 +211,7 @@ def delete(**kwargs):
|
|
214
211
|
help="Update a service config"
|
215
212
|
)
|
216
213
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
|
217
|
-
@click.option('--hostname', help='Service hostname.')
|
214
|
+
@click.option('--hostname', callback=validate_hostname, help='Service hostname.')
|
218
215
|
@click.option('--port', type=click.IntRange(1, 65535), help='Service port.')
|
219
216
|
@click.option('--priority', default=5, type=click.FloatRange(1.0, 9.0), help='Determines the service run order. Lower values run first.')
|
220
217
|
@click.option('--scheme', type=click.Choice(['http', 'https']), help='Defaults to https if hostname is set.')
|
@@ -237,8 +234,6 @@ def update(**kwargs):
|
|
237
234
|
service_config = ServiceConfig(service.dir_path)
|
238
235
|
|
239
236
|
if kwargs['hostname']:
|
240
|
-
__validate_hostname(kwargs['hostname'])
|
241
|
-
|
242
237
|
old_hostname = service_config.hostname
|
243
238
|
|
244
239
|
if old_hostname != kwargs['hostname']:
|
@@ -272,7 +267,7 @@ def update(**kwargs):
|
|
272
267
|
)
|
273
268
|
@click.option('--app-dir-path', default=current_working_dir, help='Path to application directory.')
|
274
269
|
@click.option('--context-dir-path', default=data_dir.context_dir_path, help='Path to Stoobly data directory.')
|
275
|
-
@click.option('--
|
270
|
+
@click.option('--quiet', is_flag=True, help='Disable log output.')
|
276
271
|
@click.option('--service', multiple=True, help='Specify the service(s) to create the workflow for.')
|
277
272
|
@click.option('--template', required=True, type=click.Choice([WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]), help='Select which workflow to use as a template.')
|
278
273
|
@click.argument('workflow_name')
|
@@ -290,10 +285,11 @@ def create(**kwargs):
|
|
290
285
|
__validate_service_dir(service.dir_path)
|
291
286
|
|
292
287
|
workflow_dir_path = service.workflow_dir_path(kwargs['workflow_name'])
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
288
|
+
|
289
|
+
if not kwargs['quiet'] and os.path.exists(workflow_dir_path):
|
290
|
+
print(f"{workflow_dir_path} already exists, updating scaffold maintained files...")
|
291
|
+
|
292
|
+
__workflow_create(app, **config)
|
297
293
|
|
298
294
|
@workflow.command(
|
299
295
|
help="Copy a workflow for service(s)",
|
@@ -328,7 +324,7 @@ def copy(**kwargs):
|
|
328
324
|
@click.option('--log-level', default=INFO, type=click.Choice([DEBUG, INFO, WARNING, ERROR]), help='''
|
329
325
|
Log levels can be "debug", "info", "warning", or "error"
|
330
326
|
''')
|
331
|
-
@click.option('--namespace', help='Workflow namespace.')
|
327
|
+
@click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
|
332
328
|
@click.option('--network', help='Workflow network name.')
|
333
329
|
@click.option('--rmi', is_flag=True, help='Remove images used by containers.')
|
334
330
|
@click.option('--script-path', help='Path to intermediate script path.')
|
@@ -411,7 +407,7 @@ def down(**kwargs):
|
|
411
407
|
@click.option('--log-level', default=INFO, type=click.Choice([DEBUG, INFO, WARNING, ERROR]), help='''
|
412
408
|
Log levels can be "debug", "info", "warning", or "error"
|
413
409
|
''')
|
414
|
-
@click.option('--namespace', help='Workflow namespace.')
|
410
|
+
@click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
|
415
411
|
@click.option('--script-path', help='Path to intermediate script path.')
|
416
412
|
@click.option('--service', multiple=True, help='Select which services to log. Defaults to all.')
|
417
413
|
@click.argument('workflow_name')
|
@@ -473,7 +469,7 @@ def logs(**kwargs):
|
|
473
469
|
Log levels can be "debug", "info", "warning", or "error"
|
474
470
|
''')
|
475
471
|
@click.option('--mkcert', is_flag=True, help='Set to generate SSL certs for HTTPS services.')
|
476
|
-
@click.option('--namespace', help='Workflow namespace.')
|
472
|
+
@click.option('--namespace', callback=validate_namespace, help='Workflow namespace.')
|
477
473
|
@click.option('--network', help='Workflow network name.')
|
478
474
|
@click.option('--no-build', is_flag=True, help='Do not build images before starting containers.')
|
479
475
|
@click.option('--no-publish', is_flag=True, help='Do not publish all ports.')
|
@@ -509,7 +505,7 @@ def up(**kwargs):
|
|
509
505
|
|
510
506
|
# Gateway ports are dynamically set depending on the workflow run
|
511
507
|
workflow = Workflow(kwargs['workflow_name'], app)
|
512
|
-
configure_gateway(workflow.service_paths_from_services(services), kwargs['no_publish'])
|
508
|
+
configure_gateway(workflow.workflow_name, workflow.service_paths_from_services(services), kwargs['no_publish'])
|
513
509
|
|
514
510
|
commands: List[WorkflowRunCommand] = []
|
515
511
|
for service in services:
|
@@ -675,12 +671,12 @@ scaffold.add_command(hostname)
|
|
675
671
|
def __build_script(**kwargs):
|
676
672
|
script_path = kwargs['script_path']
|
677
673
|
if not script_path:
|
678
|
-
script_file_name =
|
679
|
-
script_path = os.path.join(data_dir.tmp_dir_path, script_file_name)
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
674
|
+
script_file_name = 'run.sh'
|
675
|
+
script_path = os.path.join(data_dir.tmp_dir_path, kwargs.get('namespace') or kwargs['workflow_name'] or '', script_file_name)
|
676
|
+
|
677
|
+
script_dir = os.path.dirname(script_path)
|
678
|
+
if not os.path.exists(script_dir):
|
679
|
+
os.makedirs(script_dir, exist_ok=True)
|
684
680
|
|
685
681
|
# Truncate
|
686
682
|
with open(script_path, 'w'):
|
@@ -817,12 +813,6 @@ def __validate_proxy_mode(proxy_mode: str) -> None:
|
|
817
813
|
|
818
814
|
# TODO: validate SPEC
|
819
815
|
|
820
|
-
def __validate_hostname(hostname: str) -> None:
|
821
|
-
hostname_regex = re.compile(r'^[a-zA-Z0-9.-]+$')
|
822
|
-
if not re.search(hostname_regex, hostname):
|
823
|
-
print(f"Error: {hostname} is invalid.", file=sys.stderr)
|
824
|
-
sys.exit(1)
|
825
|
-
|
826
816
|
def __workflow_create(app, **kwargs):
|
827
817
|
command = WorkflowCreateCommand(app, **kwargs)
|
828
818
|
|
@@ -161,7 +161,7 @@ def prune(**kwargs):
|
|
161
161
|
)
|
162
162
|
@click.option('--format', type=click.Choice(FORMATS), help='Format output.')
|
163
163
|
@click.option('--select', multiple=True, help='Select column(s) to display.')
|
164
|
-
@click.option('--verify', is_flag=True, default=False)
|
164
|
+
@click.option('--no-verify', is_flag=True, default=False)
|
165
165
|
@click.option('--without-headers', is_flag=True, default=False, help='Disable printing column headers.')
|
166
166
|
@click.argument('uuid')
|
167
167
|
def update(**kwargs):
|
@@ -179,7 +179,7 @@ def update(**kwargs):
|
|
179
179
|
print(f"Error: {kwargs['uuid']} not found", file=sys.stderr)
|
180
180
|
sys.exit(1)
|
181
181
|
|
182
|
-
if kwargs['
|
182
|
+
if not kwargs['no_verify']:
|
183
183
|
if event.is_request():
|
184
184
|
snapshot: RequestSnapshot = event.snapshot()
|
185
185
|
__verify_request(snapshot)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import re
|
2
|
+
import sys
|
3
|
+
|
4
|
+
def validate_app_name(ctx, param, app_name: str) -> str:
|
5
|
+
app_name_regex = re.compile(r'^[a-zA-Z0-9._-]+$')
|
6
|
+
if not re.search(app_name_regex, app_name):
|
7
|
+
print(f"Error: app name {app_name} is invalid.", file=sys.stderr)
|
8
|
+
sys.exit(1)
|
9
|
+
return app_name
|
10
|
+
|
11
|
+
def validate_hostname(ctx, param, hostname: str) -> str:
|
12
|
+
if not hostname:
|
13
|
+
return
|
14
|
+
hostname_regex = re.compile(r'^[a-zA-Z0-9.-]+$')
|
15
|
+
if not re.search(hostname_regex, hostname):
|
16
|
+
print(f"Error: hostname {hostname} is invalid.", file=sys.stderr)
|
17
|
+
sys.exit(1)
|
18
|
+
return hostname
|
19
|
+
|
20
|
+
def validate_namespace(ctx, param, namespace: str) -> str:
|
21
|
+
if not namespace:
|
22
|
+
return
|
23
|
+
namespace_regex = re.compile(r'^[a-z0-9_-]+$')
|
24
|
+
if not re.search(namespace_regex, namespace) or namespace[0] in ['-', '_']:
|
25
|
+
print(f"Error: namespace {namespace} is invalid.", file=sys.stderr)
|
26
|
+
sys.exit(1)
|
27
|
+
return namespace
|
28
|
+
|
29
|
+
def validate_service_name(ctx, param, service_name: str) -> str:
|
30
|
+
service_name_regex = re.compile(r'^[a-zA-Z0-9._-]+$')
|
31
|
+
if not re.search(service_name_regex, service_name):
|
32
|
+
print(f"Error: service name {service_name} is invalid.", file=sys.stderr)
|
33
|
+
sys.exit(1)
|
34
|
+
return service_name
|
@@ -15,7 +15,7 @@ class ScaffoldCliInvoker():
|
|
15
15
|
|
16
16
|
result = runner.invoke(scaffold, ['app', 'create',
|
17
17
|
'--app-dir-path', app_dir_path,
|
18
|
-
'--
|
18
|
+
'--quiet',
|
19
19
|
app_name
|
20
20
|
])
|
21
21
|
|
@@ -45,10 +45,10 @@ class ScaffoldCliInvoker():
|
|
45
45
|
result = runner.invoke(scaffold, ['service', 'create',
|
46
46
|
'--app-dir-path', app_dir_path,
|
47
47
|
'--env', 'TEST',
|
48
|
-
'--force',
|
49
48
|
'--hostname', hostname,
|
50
49
|
'--scheme', scheme,
|
51
50
|
'--port', port,
|
51
|
+
'--quiet',
|
52
52
|
'--workflow', 'mock',
|
53
53
|
'--workflow', 'record',
|
54
54
|
'--workflow', 'test',
|
@@ -70,12 +70,12 @@ class ScaffoldCliInvoker():
|
|
70
70
|
|
71
71
|
result = runner.invoke(scaffold, ['service', 'create',
|
72
72
|
'--app-dir-path', app_dir_path,
|
73
|
-
'--force',
|
74
73
|
'--hostname', hostname,
|
75
74
|
'--scheme', scheme,
|
76
75
|
'--port', port,
|
77
76
|
'--proxy-mode', proxy_mode_reverse_spec,
|
78
77
|
'--detached',
|
78
|
+
'--quiet',
|
79
79
|
'--workflow', 'test',
|
80
80
|
service_name
|
81
81
|
])
|
@@ -94,7 +94,7 @@ class TestUpdate():
|
|
94
94
|
def updated_event(self, runner: CliRunner, put_event: LogEvent):
|
95
95
|
time.sleep(1) # Simulate update at different time
|
96
96
|
|
97
|
-
apply_result = runner.invoke(snapshot, ['update',
|
97
|
+
apply_result = runner.invoke(snapshot, ['update', put_event.uuid])
|
98
98
|
assert apply_result.exit_code == 0
|
99
99
|
log = Log()
|
100
100
|
events = log.events
|
@@ -1 +1 @@
|
|
1
|
-
1.9.
|
1
|
+
1.9.6
|
@@ -1,4 +1,4 @@
|
|
1
|
-
stoobly_agent/__init__.py,sha256=
|
1
|
+
stoobly_agent/__init__.py,sha256=UlQip9_Ul2fRC4UHN6HFN0lQDoz_AEInAcMSJiQnEow,44
|
2
2
|
stoobly_agent/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
stoobly_agent/app/api/__init__.py,sha256=ctkB8KR-eXO0SFhj602huHiyvQ3PslFWd8fkcufgrAI,1000
|
4
4
|
stoobly_agent/app/api/application_http_request_handler.py,sha256=Vvz53yB0bR7J-QqMAkLlhcZrA4P64ZEN7w8cMbgl6o0,5261
|
@@ -17,7 +17,7 @@ stoobly_agent/app/api/scenarios_controller.py,sha256=zJViyme9l36mlJDQONRu4N-A0kd
|
|
17
17
|
stoobly_agent/app/api/simple_http_request_handler.py,sha256=ZdJ4kKEcPDpck74dJu--M7zw76wQzpo_AQArZwN9Bes,4466
|
18
18
|
stoobly_agent/app/api/statuses_controller.py,sha256=gQsl28h-3mZ_bByEHpc4mRy3KFvUz5PeAgVB0cPx_Ao,1791
|
19
19
|
stoobly_agent/app/cli/__init__.py,sha256=uS4KJgMAhm0JVnEUC-ONW-Bq6A8I9v7Fk-_Ka7gXlrU,470
|
20
|
-
stoobly_agent/app/cli/ca_cert_cli.py,sha256=
|
20
|
+
stoobly_agent/app/cli/ca_cert_cli.py,sha256=KVIUmmZcMHW2UXZJTmXqTVk2lEbp0YbxB6C4EL5t2Q4,1629
|
21
21
|
stoobly_agent/app/cli/config_cli.py,sha256=Ljr2Ir8P0dhGXALQQcq7fwthrcipPlvxS2G_0bNE6fY,15727
|
22
22
|
stoobly_agent/app/cli/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
stoobly_agent/app/cli/decorators/config.py,sha256=AWrDGZm_gjCWFYlRwdla3iE6H7OSlM4FxkaXRNovBZA,2428
|
@@ -82,7 +82,7 @@ stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=1khQdgTaQ89ykGRNdTQh_e
|
|
82
82
|
stoobly_agent/app/cli/scaffold/docker/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
83
83
|
stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py,sha256=ZU7z4bkvdS3OK5O4fJhlA9_PNwnFtZW6t7vNF7V5obQ,1003
|
84
84
|
stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=4cIMSYvgrkGWVuuYymiwlrR829O91qQl9ML8FhaDMj4,5857
|
85
|
-
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=
|
85
|
+
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=jtx8lhvKHl0ubSHaQpE8m9lCYnOJ6Qju-SBJPBs0l7I,3921
|
86
86
|
stoobly_agent/app/cli/scaffold/docker/service/types.py,sha256=qB-yYHlu-PZDc0HYgTUvE5bWNpHxaSThC3JUG8okR1k,88
|
87
87
|
stoobly_agent/app/cli/scaffold/docker/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
88
|
stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py,sha256=VKD9hXbJGRIWHS5IeYXeX0-FQ0F43zG8VmsegL6eYwA,703
|
@@ -104,7 +104,7 @@ stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOW
|
|
104
104
|
stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=xONRUtfC3IBd-Kr4wdUKWgx9ppSsbu2H72pb2VinizQ,11412
|
105
105
|
stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=x8C_a0VoO_vUbosp4_6IC1U7Ge9NnUdVKDPpVMtMkeY,171
|
106
106
|
stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=Okk4Q0Fj7Wi5NU58gQfpjpFwAL3RUBJyRe56kteQfcA,158
|
107
|
-
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=
|
107
|
+
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=4CTrKRHho9fl7NOGrQM0lJTfn-X09ddQKBq9Zsbjbww,9278
|
108
108
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml,sha256=6tFqXh3ine8vaD0FCL5TMoY5NjKx2wLUR8XpW3tJtew,245
|
109
109
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.networks.yml,sha256=I4PbJpQjFHb5IbAUWNvYM6okDEtmwtKFDQg-yog05WM,141
|
110
110
|
stoobly_agent/app/cli/scaffold/templates/app/Makefile,sha256=TEmPG7Bf0KZOnmfsgdzza3UdwcVMmM5Lj1YdLc4cgjA,79
|
@@ -203,9 +203,9 @@ stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=x8V5pJmIiklD3f2q2-qq-CORf4
|
|
203
203
|
stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
|
204
204
|
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=eF3aaK4OIZXYuSBEAeBnhAL7EZrS1G4mSYrJbEiXt2o,11082
|
205
205
|
stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
|
206
|
-
stoobly_agent/app/cli/scaffold_cli.py,sha256=
|
206
|
+
stoobly_agent/app/cli/scaffold_cli.py,sha256=9NOSl3Qy7LN3PphuOqTFEM6t0PanVEHow8iyW-5eTW0,31958
|
207
207
|
stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
|
208
|
-
stoobly_agent/app/cli/snapshot_cli.py,sha256=
|
208
|
+
stoobly_agent/app/cli/snapshot_cli.py,sha256=1Dw5JgDlmG6vctrawIRO7CdB73vAQk_wRBnPG2lVOrQ,11929
|
209
209
|
stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
|
210
210
|
stoobly_agent/app/cli/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
211
211
|
stoobly_agent/app/cli/types/output.py,sha256=2wazv56g5IwLQeJCWfJXXAxTB9Y5WH1cKMHbpjbXNeo,439
|
@@ -214,6 +214,7 @@ stoobly_agent/app/cli/types/request.py,sha256=QthojE5sfx7OvKu-vVNnSUfGk8n4pLzuBQ
|
|
214
214
|
stoobly_agent/app/cli/types/scenario.py,sha256=28WxmOlbm2Bsek1uu7yc4hJGz-d5oHbYAro7LlFWRoc,81
|
215
215
|
stoobly_agent/app/cli/types/snapshot_migration.py,sha256=4_Re46FKjsflcTOO3qhNsbWWmdEU67SFsF-XE_FKG3M,1859
|
216
216
|
stoobly_agent/app/cli/types/test.py,sha256=1c458B7DFBWsEk5Q1CrZ2CUi84YzEzcs-W4qTcudwAk,714
|
217
|
+
stoobly_agent/app/cli/validators/scaffold.py,sha256=mjLdb1lO8_SKOspwQSONSA8upXANg6HOvtttkHEqhrk,1187
|
217
218
|
stoobly_agent/app/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
218
219
|
stoobly_agent/app/models/adapters/__init__.py,sha256=cEEE--Bvrvk6DAsHx_uPgFhLnZJETP4zSBtWjMqyIKc,233
|
219
220
|
stoobly_agent/app/models/adapters/joined_request_adapter.py,sha256=fSq16n3AAlxi8KJdBESHp3JGio_M9uzMnHbnQU8VI3w,3598
|
@@ -677,7 +678,7 @@ stoobly_agent/test/app/cli/request/request_reset_test.py,sha256=5My6Z452eideAOUu
|
|
677
678
|
stoobly_agent/test/app/cli/request/request_response_test.py,sha256=Fu-A8tIn016DKme4WIaPzo3YeFY-CPtTOpaSFigUVVM,1263
|
678
679
|
stoobly_agent/test/app/cli/request/request_snapshot_test.py,sha256=3kMmv0CuvnMXLgDQA-_u9S1DIiNOdL63L-IptVuOpf8,6308
|
679
680
|
stoobly_agent/test/app/cli/request/request_test_test.py,sha256=-cJNXKjgryVVfVt-7IN5fIhBwe3NjFoPmeavDH8lAjU,5527
|
680
|
-
stoobly_agent/test/app/cli/scaffold/cli_invoker.py,sha256=
|
681
|
+
stoobly_agent/test/app/cli/scaffold/cli_invoker.py,sha256=ZOFeLh9TejJ_k3gQ0KC6iIuqKhwrkqZV5U7CMdRDnwM,3700
|
681
682
|
stoobly_agent/test/app/cli/scaffold/cli_test.py,sha256=sMNvO845MIu5DVGa1HmwXQDmKDcwrfNTdEb3fK5886w,4557
|
682
683
|
stoobly_agent/test/app/cli/scaffold/e2e_test.py,sha256=IGWT0EXrMtB8i8kdLFbN7O8NvLrJYTi-iQ_GRiUoA94,12978
|
683
684
|
stoobly_agent/test/app/cli/scaffold/hosts_file_manager_test.py,sha256=ztcPh1x0ZCW1FWA5YL4ulEVjfbW9TOPgk1bnSDPNmCw,2287
|
@@ -692,7 +693,7 @@ stoobly_agent/test/app/cli/snapshot/snapshot_apply_test.py,sha256=mpkTZx8eaFFZU_
|
|
692
693
|
stoobly_agent/test/app/cli/snapshot/snapshot_copy_test.py,sha256=Yg78-FhSiG_r6Jpm-sN8sn0LjVXTwTOXt6hg8ni2GIY,1953
|
693
694
|
stoobly_agent/test/app/cli/snapshot/snapshot_migrate_test.py,sha256=voEvblK6CMGCrSJDTHVmkUkLXj0auNb78jxlGiiBBQQ,7370
|
694
695
|
stoobly_agent/test/app/cli/snapshot/snapshot_prune_test.py,sha256=bn4yUU7Eb4-6GnwnRaPZPi5Cn7XEaIsrJ_mB7jydgWw,6693
|
695
|
-
stoobly_agent/test/app/cli/snapshot/snapshot_update_test.py,sha256=
|
696
|
+
stoobly_agent/test/app/cli/snapshot/snapshot_update_test.py,sha256=yx_QDPYc5utiqlRhy3hTGBKLafGq9nC_lDV-0k0qWOo,4502
|
696
697
|
stoobly_agent/test/app/models/adapters/joined_rquest_adapter_test.py,sha256=bF7WMrAiASQDNzDTvIXGJhsWLNhfYOmdQpSDo0hyWYY,1098
|
697
698
|
stoobly_agent/test/app/models/adapters/orm/joined_request_string_adapter_test.py,sha256=a2IHTk3l7aiLyYF7vtqissrk0MFTF2wlUBiaKWyJKfU,2667
|
698
699
|
stoobly_agent/test/app/models/adapters/orm/request/orm_mitmproxy_request_adapter_test.py,sha256=PbJsAaxPUEbF9vM7DX4z858biWf4qlGnvE8KBuy8SgY,2763
|
@@ -708,7 +709,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
|
|
708
709
|
stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=a1SFLyEyRRLuADvAw6ckQQKORFXvyK1lyrbkaLWx8oU,3399
|
709
710
|
stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
|
710
711
|
stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
|
711
|
-
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=
|
712
|
+
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=0vY2lU8oU9tB_UhSABsgfVlYkLE7wf6JMFZoxaKHBS0,6
|
712
713
|
stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
|
713
714
|
stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
|
714
715
|
stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
|
@@ -749,8 +750,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
|
|
749
750
|
stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
|
750
751
|
stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
|
751
752
|
stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
|
752
|
-
stoobly_agent-1.9.
|
753
|
-
stoobly_agent-1.9.
|
754
|
-
stoobly_agent-1.9.
|
755
|
-
stoobly_agent-1.9.
|
756
|
-
stoobly_agent-1.9.
|
753
|
+
stoobly_agent-1.9.6.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
|
754
|
+
stoobly_agent-1.9.6.dist-info/METADATA,sha256=uLLTaIvuC4eHvFOImTS-phj_G1HeK2F0qjhOYpPiyrM,3087
|
755
|
+
stoobly_agent-1.9.6.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
756
|
+
stoobly_agent-1.9.6.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
|
757
|
+
stoobly_agent-1.9.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|