stoobly-agent 1.6.2__py3-none-any.whl → 1.6.4__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/scaffold/app_command.py +15 -0
- stoobly_agent/app/cli/scaffold/constants.py +6 -0
- stoobly_agent/app/cli/scaffold/docker/builder.py +15 -8
- stoobly_agent/app/cli/scaffold/docker/constants.py +7 -2
- stoobly_agent/app/cli/scaffold/docker/service/builder.py +10 -8
- stoobly_agent/app/cli/scaffold/docker/service/{set_gateway_ports.py → configure_gateway.py} +16 -2
- stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py +0 -1
- stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +24 -23
- stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py +3 -3
- stoobly_agent/app/cli/scaffold/docker/workflow/{development_decorator.py → dns_decorator.py} +1 -1
- stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +1 -1
- stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py +0 -13
- stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +2 -1
- stoobly_agent/app/cli/scaffold/templates/app/.Makefile +1 -2
- stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.networks.yml +7 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml +2 -2
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml +2 -2
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/docker-compose.yml +10 -6
- stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml +1 -7
- stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml +1 -7
- stoobly_agent/app/cli/scaffold/templates/app/gateway/test/.docker-compose.test.yml +7 -0
- stoobly_agent/app/cli/scaffold/workflow_run_command.py +24 -6
- stoobly_agent/app/cli/scaffold/workflow_validate_command.py +0 -7
- stoobly_agent/app/cli/scaffold_cli.py +14 -6
- stoobly_agent/app/proxy/mock/eval_request_service.py +16 -3
- stoobly_agent/lib/api/param_builder.py +0 -1
- stoobly_agent/test/app/cli/scaffold/e2e_test.py +1 -3
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- stoobly_agent/test/mock_data/scaffold/docker-compose-assets-service.yml +1 -6
- stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml +1 -7
- {stoobly_agent-1.6.2.dist-info → stoobly_agent-1.6.4.dist-info}/METADATA +1 -1
- {stoobly_agent-1.6.2.dist-info → stoobly_agent-1.6.4.dist-info}/RECORD +36 -34
- {stoobly_agent-1.6.2.dist-info → stoobly_agent-1.6.4.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.6.2.dist-info → stoobly_agent-1.6.4.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.6.2.dist-info → stoobly_agent-1.6.4.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
COMMAND = 'stoobly-agent'
|
2
|
-
VERSION = '1.6.
|
2
|
+
VERSION = '1.6.4'
|
@@ -5,6 +5,7 @@ import shutil
|
|
5
5
|
from .app import App
|
6
6
|
from .app_config import AppConfig
|
7
7
|
from .command import Command
|
8
|
+
from .docker.constants import DOCKER_COMPOSE_NETWORKS
|
8
9
|
|
9
10
|
class AppCommand(Command):
|
10
11
|
|
@@ -29,6 +30,20 @@ class AppCommand(Command):
|
|
29
30
|
def app_config_path(self):
|
30
31
|
return self.__config.path
|
31
32
|
|
33
|
+
@property
|
34
|
+
def networks_compose_path(self):
|
35
|
+
return os.path.join(
|
36
|
+
self.data_dir_path,
|
37
|
+
self.networks_compose_relative_path
|
38
|
+
)
|
39
|
+
|
40
|
+
@property
|
41
|
+
def networks_compose_relative_path(self):
|
42
|
+
return os.path.join(
|
43
|
+
self.namespace,
|
44
|
+
DOCKER_COMPOSE_NETWORKS
|
45
|
+
)
|
46
|
+
|
32
47
|
@property
|
33
48
|
def scaffold_namespace_path(self):
|
34
49
|
return self.app.scaffold_namespace_path
|
@@ -32,6 +32,9 @@ SERVICE_SCHEME_ENV = 'SERVICE_SCHEME'
|
|
32
32
|
SERVICE_PORT = '${SERVICE_PORT}'
|
33
33
|
SERVICE_PORT_ENV = 'SERVICE_PORT'
|
34
34
|
SERVICE_PRIORITY_ENV = 'SERVICE_PRIORITY'
|
35
|
+
SERVICE_SCRIPTS = '${SERVICE_SCRIPTS}'
|
36
|
+
SERVICE_SCRIPTS_DIR = '/usr/local/bin/services'
|
37
|
+
SERVICE_SCRIPTS_ENV = 'SERVICE_SCRIPTS'
|
35
38
|
STOOBLY_HOME_DIR = '/home/stoobly'
|
36
39
|
STOOBLY_DATA_DIR = os.path.join(STOOBLY_HOME_DIR, DATA_DIR_NAME)
|
37
40
|
STOOBLY_CERTS_DIR = os.path.join(STOOBLY_DATA_DIR, CERTS_DIR_NAME)
|
@@ -52,6 +55,9 @@ WORKFLOW_NAME = '${WORKFLOW_NAME}'
|
|
52
55
|
WORKFLOW_NAME_ENV = 'WORKFLOW_NAME'
|
53
56
|
WORKFLOW_NAMESPACE_ENV = 'WORKFLOW_NAMESPACE'
|
54
57
|
WORKFLOW_RECORD_TYPE = 'record'
|
58
|
+
WORKFLOW_SCRIPTS = '${WORKFLOW_SCRIPTS}'
|
59
|
+
WORKFLOW_SCRIPTS_DIR = '/usr/local/bin/workflows'
|
60
|
+
WORKFLOW_SCRIPTS_ENV = 'WORKFLOW_SCRIPTS'
|
55
61
|
WORKFLOW_TEMPLATE = '${WORKFLOW_TEMPLATE}'
|
56
62
|
WORKFLOW_TEMPLATE_ENV = 'WORKFLOW_TEMPLATE'
|
57
63
|
WORKFLOW_TEST_TYPE = 'test'
|
@@ -3,7 +3,7 @@ import pathlib
|
|
3
3
|
import pdb
|
4
4
|
import yaml
|
5
5
|
|
6
|
-
from .constants import
|
6
|
+
from .constants import APP_EGRESS_NETWORK, APP_EGRESS_NETWORK_NAME, APP_INGRESS_NETWORK, APP_INGRESS_NETWORK_NAME, DOCKER_COMPOSE_CUSTOM
|
7
7
|
|
8
8
|
class Builder():
|
9
9
|
|
@@ -35,12 +35,12 @@ class Builder():
|
|
35
35
|
return self.__dir_path
|
36
36
|
|
37
37
|
@property
|
38
|
-
def
|
39
|
-
return self.__networks.get(
|
38
|
+
def egress_network(self):
|
39
|
+
return self.__networks.get(APP_EGRESS_NETWORK_NAME)
|
40
40
|
|
41
41
|
@property
|
42
|
-
def
|
43
|
-
return
|
42
|
+
def egress_network_name(self):
|
43
|
+
return APP_EGRESS_NETWORK_NAME
|
44
44
|
|
45
45
|
@property
|
46
46
|
def networks(self):
|
@@ -86,12 +86,19 @@ class Builder():
|
|
86
86
|
|
87
87
|
def with_network(self, network):
|
88
88
|
self.__networks[network] = {
|
89
|
-
'name': f"{
|
89
|
+
'name': f"{APP_EGRESS_NETWORK}.{network}"
|
90
90
|
}
|
91
91
|
return self
|
92
92
|
|
93
|
-
def
|
94
|
-
self.__networks[
|
93
|
+
def with_egress_network(self, network = APP_EGRESS_NETWORK):
|
94
|
+
self.__networks[APP_EGRESS_NETWORK_NAME] = {
|
95
|
+
'external': True,
|
96
|
+
'name': network,
|
97
|
+
}
|
98
|
+
return self
|
99
|
+
|
100
|
+
def with_ingress_network(self, network = APP_INGRESS_NETWORK):
|
101
|
+
self.__networks[APP_INGRESS_NETWORK_NAME] = {
|
95
102
|
'external': True,
|
96
103
|
'name': network,
|
97
104
|
}
|
@@ -1,8 +1,13 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
APP_EGRESS_NETWORK = '${APP_NETWORK}.egress'
|
2
|
+
APP_EGRESS_NETWORK_NAME = 'app.egress'
|
3
|
+
APP_EGRESS_NETWORK_TEMPLATE = '{network}.egress'
|
4
|
+
APP_INGRESS_NETWORK = '${APP_NETWORK}.ingress'
|
5
|
+
APP_INGRESS_NETWORK_NAME = 'app.ingress'
|
6
|
+
APP_INGRESS_NETWORK_TEMPLATE = '{network}.ingress'
|
3
7
|
DOCKER_COMPOSE_BASE = '.docker-compose.base.yml'
|
4
8
|
DOCKER_COMPOSE_BASE_TEMPLATE = '.docker-compose.base.template.yml'
|
5
9
|
DOCKER_COMPOSE_CUSTOM = 'docker-compose.yml'
|
10
|
+
DOCKER_COMPOSE_NETWORKS = '.docker-compose.networks.yml'
|
6
11
|
DOCKERFILE_CONTEXT = '.Dockerfile.context'
|
7
12
|
DOCKERFILE_SERVICE = 'Dockerfile.source'
|
8
13
|
|
@@ -2,7 +2,7 @@ import os
|
|
2
2
|
import pdb
|
3
3
|
|
4
4
|
from ...app_config import AppConfig
|
5
|
-
from ...constants import
|
5
|
+
from ...constants import WORKFLOW_SCRIPTS, WORKFLOW_TEMPLATE
|
6
6
|
from ...service_config import ServiceConfig
|
7
7
|
from ..app_builder import AppBuilder
|
8
8
|
from ..builder import Builder
|
@@ -22,8 +22,6 @@ class ServiceBuilder(Builder):
|
|
22
22
|
self.__config = config
|
23
23
|
self.__service_name = os.path.basename(service_path)
|
24
24
|
|
25
|
-
self.load()
|
26
|
-
|
27
25
|
@property
|
28
26
|
def app_base(self):
|
29
27
|
return f"{self.service_name}.app_base"
|
@@ -86,7 +84,7 @@ class ServiceBuilder(Builder):
|
|
86
84
|
def build_init_base(self):
|
87
85
|
environment = {}
|
88
86
|
self.with_service(self.init_base, {
|
89
|
-
'command': [f"/
|
87
|
+
'command': [f"{WORKFLOW_SCRIPTS}/{WORKFLOW_TEMPLATE}/.init", 'bin/init'],
|
90
88
|
'environment': environment,
|
91
89
|
'extends': {
|
92
90
|
'file': os.path.relpath(self.app_builder.compose_file_path, self.dir_path),
|
@@ -97,7 +95,7 @@ class ServiceBuilder(Builder):
|
|
97
95
|
def build_configure_base(self):
|
98
96
|
environment = {}
|
99
97
|
self.with_service(self.configure_base, {
|
100
|
-
'command': [f"/
|
98
|
+
'command': [f"{WORKFLOW_SCRIPTS}/{WORKFLOW_TEMPLATE}/.configure", 'bin/configure'],
|
101
99
|
'environment': environment,
|
102
100
|
'extends': {
|
103
101
|
'file': os.path.relpath(self.app_builder.compose_file_path, self.dir_path),
|
@@ -112,7 +110,11 @@ class ServiceBuilder(Builder):
|
|
112
110
|
if self.config.hostname:
|
113
111
|
self.build_proxy_base()
|
114
112
|
|
115
|
-
|
116
|
-
'networks': self.networks,
|
113
|
+
compose = {
|
117
114
|
'services': self.services,
|
118
|
-
}
|
115
|
+
}
|
116
|
+
|
117
|
+
if self.networks:
|
118
|
+
compose['networks'] = self.networks
|
119
|
+
|
120
|
+
super().write(compose)
|
@@ -8,14 +8,18 @@ from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
|
8
8
|
from stoobly_agent.app.cli.scaffold.docker.constants import DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE
|
9
9
|
from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
|
10
10
|
|
11
|
-
def
|
11
|
+
def configure_gateway(service_paths: List[str], no_publish = False):
|
12
12
|
if len(service_paths) == 0:
|
13
13
|
return
|
14
14
|
|
15
15
|
ports = []
|
16
|
+
hostnames = []
|
16
17
|
for path in service_paths:
|
17
18
|
config = ServiceConfig(path)
|
18
19
|
|
20
|
+
if not config.hostname:
|
21
|
+
continue
|
22
|
+
|
19
23
|
try:
|
20
24
|
port = int(config.port)
|
21
25
|
except Exception:
|
@@ -25,6 +29,8 @@ def set_gateway_ports(service_paths: List[str]):
|
|
25
29
|
if port > 0 and port <= 65535 and port_mapping not in ports:
|
26
30
|
ports.append(port_mapping)
|
27
31
|
|
32
|
+
hostnames.append(config.hostname)
|
33
|
+
|
28
34
|
app_dir_path = os.path.dirname(service_paths[0])
|
29
35
|
gateway_service_path = os.path.join(app_dir_path, CORE_GATEWAY_SERVICE_NAME)
|
30
36
|
docker_compose_src_path = os.path.join(gateway_service_path, DOCKER_COMPOSE_BASE_TEMPLATE)
|
@@ -41,7 +47,15 @@ def set_gateway_ports(service_paths: List[str]):
|
|
41
47
|
gateway_base = services.get('gateway_base')
|
42
48
|
|
43
49
|
if gateway_base:
|
44
|
-
|
50
|
+
if not no_publish:
|
51
|
+
gateway_base['ports'] = ports
|
52
|
+
|
53
|
+
gateway_base['networks'] = {
|
54
|
+
'app.egress': {},
|
55
|
+
'app.ingress': {
|
56
|
+
'aliases': hostnames
|
57
|
+
}
|
58
|
+
}
|
45
59
|
|
46
60
|
with open(docker_compose_dest_path, 'w') as fp:
|
47
61
|
yaml.dump(compose, fp)
|
@@ -32,11 +32,6 @@ class WorkflowBuilder(Builder):
|
|
32
32
|
STOOBLY_HOME_DIR, DATA_DIR_NAME, DOCKER_NAMESPACE, self.service_builder.service_name, self.workflow_name
|
33
33
|
)
|
34
34
|
|
35
|
-
if self.config.hostname:
|
36
|
-
self.with_public_network()
|
37
|
-
|
38
|
-
self.load()
|
39
|
-
|
40
35
|
@property
|
41
36
|
def app(self):
|
42
37
|
return f"{self.namespace}.app"
|
@@ -91,8 +86,6 @@ class WorkflowBuilder(Builder):
|
|
91
86
|
|
92
87
|
def build_all(self):
|
93
88
|
# Resources
|
94
|
-
self.with_network(self.service_builder.service_name)
|
95
|
-
|
96
89
|
if self.config.detached:
|
97
90
|
self.with_volume(self.service_builder.service_name)
|
98
91
|
|
@@ -101,7 +94,6 @@ class WorkflowBuilder(Builder):
|
|
101
94
|
self.build_configure()
|
102
95
|
|
103
96
|
if self.config.hostname:
|
104
|
-
self.with_public_network()
|
105
97
|
self.build_proxy() # Depends on configure, must call build_configure first
|
106
98
|
|
107
99
|
def build_init(self):
|
@@ -166,7 +158,7 @@ class WorkflowBuilder(Builder):
|
|
166
158
|
|
167
159
|
depends_on = {}
|
168
160
|
environment = { **self.env_dict() }
|
169
|
-
networks =
|
161
|
+
networks = {}
|
170
162
|
volumes = []
|
171
163
|
|
172
164
|
service = {
|
@@ -188,14 +180,13 @@ class WorkflowBuilder(Builder):
|
|
188
180
|
'condition': 'service_completed_successfully',
|
189
181
|
}
|
190
182
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
environment['VIRTUAL_PROTO'] = SERVICE_SCHEME
|
183
|
+
environment['VIRTUAL_HOST'] = SERVICE_HOSTNAME
|
184
|
+
environment['VIRTUAL_PORT'] = SERVICE_PORT
|
185
|
+
environment['VIRTUAL_PROTO'] = SERVICE_SCHEME
|
195
186
|
|
196
|
-
|
197
|
-
|
198
|
-
|
187
|
+
# Expose this container service to the public network
|
188
|
+
# so that it is accessible to other Stoobly services
|
189
|
+
networks[self.egress_network_name] = {}
|
199
190
|
|
200
191
|
if self.config.detached:
|
201
192
|
volumes.append(f"{self.service_builder.service_name}:{STOOBLY_HOME_DIR}/.stoobly")
|
@@ -213,10 +204,14 @@ class WorkflowBuilder(Builder):
|
|
213
204
|
dest = self.custom_compose_file_path
|
214
205
|
|
215
206
|
if not os.path.exists(dest):
|
216
|
-
|
217
|
-
'networks': self.networks,
|
207
|
+
compose = {
|
218
208
|
'services': {}
|
219
|
-
}
|
209
|
+
}
|
210
|
+
|
211
|
+
if self.networks:
|
212
|
+
compose['networks'] = self.networks
|
213
|
+
|
214
|
+
super().write(compose, dest)
|
220
215
|
|
221
216
|
def with_env(self, v: List[str]):
|
222
217
|
if not isinstance(v, list):
|
@@ -225,11 +220,17 @@ class WorkflowBuilder(Builder):
|
|
225
220
|
return self
|
226
221
|
|
227
222
|
def write(self):
|
228
|
-
|
229
|
-
'networks': self.networks,
|
223
|
+
compose = {
|
230
224
|
'services': self.services,
|
231
|
-
|
232
|
-
|
225
|
+
}
|
226
|
+
|
227
|
+
if self.networks:
|
228
|
+
compose['networks'] = self.networks
|
229
|
+
|
230
|
+
if self.volumes:
|
231
|
+
compose['volumes'] = self.volumes
|
232
|
+
|
233
|
+
super().write(compose)
|
233
234
|
|
234
235
|
def __with_url_environment(self, environment):
|
235
236
|
environment[SERVICE_HOSTNAME_ENV] = SERVICE_HOSTNAME
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
|
2
2
|
|
3
3
|
from ...constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE
|
4
|
-
from .
|
4
|
+
from .dns_decorator import DnsDecorator
|
5
5
|
from .mock_decorator import MockDecorator
|
6
6
|
from .reverse_proxy_decorator import ReverseProxyDecorator
|
7
7
|
|
@@ -11,11 +11,11 @@ def get_workflow_decorators(workflow: str, service_config: ServiceConfig):
|
|
11
11
|
if workflow == WORKFLOW_RECORD_TYPE:
|
12
12
|
if service_config.hostname:
|
13
13
|
workflow_decorators.append(ReverseProxyDecorator)
|
14
|
-
workflow_decorators.append(
|
14
|
+
workflow_decorators.append(DnsDecorator)
|
15
15
|
elif workflow == WORKFLOW_MOCK_TYPE:
|
16
16
|
if service_config.hostname:
|
17
17
|
workflow_decorators.append(ReverseProxyDecorator if service_config.detached else MockDecorator)
|
18
|
-
workflow_decorators.append(
|
18
|
+
workflow_decorators.append(DnsDecorator)
|
19
19
|
else:
|
20
20
|
if service_config.hostname:
|
21
21
|
workflow_decorators.append(ReverseProxyDecorator if service_config.detached else MockDecorator)
|
@@ -40,19 +40,6 @@ class ReverseProxyDecorator():
|
|
40
40
|
|
41
41
|
additional_properties = { 'command': command }
|
42
42
|
|
43
|
-
# Proxying forwards requests to the actual service
|
44
|
-
# If the destination hostname is the same as the service's hostname, then
|
45
|
-
# If we set the 'hostname' property, this will cause an "infinite loop"
|
46
|
-
proxy_mode_toks = config.proxy_mode.split(':', 1)
|
47
|
-
|
48
|
-
if len(proxy_mode_toks) > 1:
|
49
|
-
directed = proxy_mode_toks[0] == 'reverse' or proxy_mode_toks[0] == 'upstream'
|
50
|
-
if directed:
|
51
|
-
spec = proxy_mode_toks[1]
|
52
|
-
uri = urlparse(spec)
|
53
|
-
if uri.hostname != self.service_builder.config.hostname:
|
54
|
-
additional_properties['hostname'] = f"{SERVICE_HOSTNAME}"
|
55
|
-
|
56
43
|
service = {
|
57
44
|
**proxy_service,
|
58
45
|
**additional_properties,
|
@@ -18,6 +18,7 @@ from stoobly_agent.app.cli.scaffold.constants import (
|
|
18
18
|
WORKFLOW_RECORD_TYPE,
|
19
19
|
WORKFLOW_TEST_TYPE,
|
20
20
|
)
|
21
|
+
from stoobly_agent.app.cli.scaffold.docker.constants import APP_EGRESS_NETWORK_TEMPLATE
|
21
22
|
from stoobly_agent.app.cli.scaffold.hosts_file_manager import HostsFileManager
|
22
23
|
from stoobly_agent.app.cli.scaffold.service_command import ServiceCommand
|
23
24
|
from stoobly_agent.app.cli.scaffold.service_docker_compose import ServiceDockerCompose
|
@@ -113,7 +114,7 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
|
|
113
114
|
output = self.docker_client.containers.run(
|
114
115
|
image='curlimages/curl:8.11.0',
|
115
116
|
command=f"curl --max-time {timeout_seconds} {url} --verbose",
|
116
|
-
network=self.app_config.network,
|
117
|
+
network=APP_EGRESS_NETWORK_TEMPLATE.format(network=self.app_config.network),
|
117
118
|
stderr=True,
|
118
119
|
remove=True,
|
119
120
|
)
|
@@ -88,7 +88,6 @@ nameservers: tmpdir
|
|
88
88
|
echo "$$nameserver" > $(app_tmp_dir)/.nameservers; \
|
89
89
|
else \
|
90
90
|
echo "/etc/resolv.conf not found." >&2; \
|
91
|
-
exit 1; \
|
92
91
|
fi
|
93
92
|
intercept/disable:
|
94
93
|
@export EXEC_COMMAND=.disable && \
|
@@ -191,7 +190,7 @@ workflow/services:
|
|
191
190
|
export EXEC_ARGS="$(WORKFLOW)" && \
|
192
191
|
$(stoobly_exec_run)
|
193
192
|
workflow/test:
|
194
|
-
$(eval WORKFLOW=test)
|
193
|
+
$(eval WORKFLOW=test) $(eval options=$(options) --no-publish)
|
195
194
|
workflow/up:
|
196
195
|
@export EXEC_COMMAND=.up && \
|
197
196
|
export EXEC_OPTIONS="$(user_id_option) $(workflow_up_options) $(workflow_run_options) $(options)" && \
|
@@ -1,7 +1,7 @@
|
|
1
1
|
services:
|
2
2
|
build.configure_base:
|
3
3
|
command:
|
4
|
-
-
|
4
|
+
- ${SERVICE_SCRIPTS}/${SERVICE_NAME}/${WORKFLOW_TEMPLATE}/.configure
|
5
5
|
- bin/configure
|
6
6
|
extends:
|
7
7
|
file: ../.docker-compose.base.yml
|
@@ -9,7 +9,7 @@ services:
|
|
9
9
|
working_dir: /home/stoobly/.stoobly/docker/build/${WORKFLOW_NAME}
|
10
10
|
build.init_base:
|
11
11
|
command:
|
12
|
-
-
|
12
|
+
- ${SERVICE_SCRIPTS}/${SERVICE_NAME}/${WORKFLOW_TEMPLATE}/.init
|
13
13
|
- bin/init
|
14
14
|
extends:
|
15
15
|
file: ../.docker-compose.base.yml
|
@@ -2,7 +2,7 @@ networks: {}
|
|
2
2
|
services:
|
3
3
|
entrypoint.configure_base:
|
4
4
|
command:
|
5
|
-
-
|
5
|
+
- ${SERVICE_SCRIPTS}/${SERVICE_NAME}/${WORKFLOW_TEMPLATE}/.configure
|
6
6
|
- bin/configure
|
7
7
|
environment: {}
|
8
8
|
extends:
|
@@ -11,7 +11,7 @@ services:
|
|
11
11
|
working_dir: /home/stoobly/.stoobly/docker/entrypoint/${WORKFLOW_NAME}
|
12
12
|
entrypoint.init_base:
|
13
13
|
command:
|
14
|
-
-
|
14
|
+
- ${SERVICE_SCRIPTS}/${SERVICE_NAME}/${WORKFLOW_TEMPLATE}/.init
|
15
15
|
- bin/init
|
16
16
|
environment: {}
|
17
17
|
extends:
|
@@ -1,14 +1,18 @@
|
|
1
|
-
# Define
|
1
|
+
# Define custom services here
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
3
|
+
# Container services that need to make request(s) to a Stoobly defined service
|
4
|
+
# need to have either 'app.ingress' or 'app.egress' added to the 'networks' property
|
5
|
+
#
|
6
|
+
# e.g. If we want to make a request by hostname, then the following should be added
|
7
|
+
# networks:
|
8
|
+
# - app.ingress
|
9
|
+
#
|
10
|
+
# e.g. If we want to make a request by container service name, then the following should be added
|
6
11
|
# networks:
|
7
|
-
# -
|
12
|
+
# - app.egress
|
8
13
|
#
|
9
14
|
# Container services that are intended to be run as part of a workflow need to have the workflow name added to the 'profiles' property
|
10
15
|
# e.g. If we want to run a service as part of the 'mock' workflow, then the following should be added
|
11
16
|
# profiles:
|
12
17
|
# - mock
|
13
|
-
networks: {}
|
14
18
|
services: {}
|
@@ -13,9 +13,10 @@ from stoobly_agent.lib.logger import Logger
|
|
13
13
|
from .app import App
|
14
14
|
from .constants import (
|
15
15
|
APP_DIR_ENV, APP_NETWORK_ENV, CA_CERTS_DIR_ENV, CERTS_DIR_ENV, CONTEXT_DIR_ENV, NAMESERVERS_FILE,
|
16
|
-
SERVICE_DNS_ENV, SERVICE_NAME_ENV,
|
16
|
+
SERVICE_DNS_ENV, SERVICE_NAME_ENV, SERVICE_SCRIPTS_DIR, SERVICE_SCRIPTS_ENV, USER_ID_ENV,
|
17
|
+
WORKFLOW_NAME_ENV, WORKFLOW_NAMESPACE_ENV, WORKFLOW_SCRIPTS_DIR, WORKFLOW_SCRIPTS_ENV, WORKFLOW_TEMPLATE_ENV
|
17
18
|
)
|
18
|
-
from .docker.constants import DOCKERFILE_CONTEXT
|
19
|
+
from .docker.constants import APP_EGRESS_NETWORK_TEMPLATE, APP_INGRESS_NETWORK_TEMPLATE, DOCKERFILE_CONTEXT
|
19
20
|
from .workflow_command import WorkflowCommand
|
20
21
|
from .workflow_env import WorkflowEnv
|
21
22
|
|
@@ -122,11 +123,17 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
122
123
|
command.append('|| true')
|
123
124
|
return ' '.join(command)
|
124
125
|
|
125
|
-
def
|
126
|
-
return f"docker network create {self.network} &> /dev/null"
|
126
|
+
def create_egress_network(self):
|
127
|
+
return f"docker network create {APP_EGRESS_NETWORK_TEMPLATE.format(network=self.network)} &> /dev/null"
|
127
128
|
|
128
|
-
def
|
129
|
-
return f"docker network
|
129
|
+
def create_ingress_network(self):
|
130
|
+
return f"docker network create {APP_INGRESS_NETWORK_TEMPLATE.format(network=self.network)} &> /dev/null"
|
131
|
+
|
132
|
+
def remove_egress_network(self):
|
133
|
+
return f"docker network rm {APP_EGRESS_NETWORK_TEMPLATE.format(network=self.network)} &> /dev/null || true"
|
134
|
+
|
135
|
+
def remove_ingress_network(self):
|
136
|
+
return f"docker network rm {APP_INGRESS_NETWORK_TEMPLATE.format(network=self.network)} &> /dev/null || true"
|
130
137
|
|
131
138
|
def up(self, **options: UpOptions):
|
132
139
|
if not os.path.exists(self.compose_path):
|
@@ -138,6 +145,9 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
138
145
|
# Add docker compose file
|
139
146
|
command_options.append(f"-f {os.path.relpath(self.compose_path, self.__current_working_dir)}")
|
140
147
|
|
148
|
+
# Add docker compose networks file
|
149
|
+
command_options.append(f"-f {os.path.relpath(self.networks_compose_path, os.getcwd())}")
|
150
|
+
|
141
151
|
# Add custom docker compose file
|
142
152
|
custom_services = self.custom_services
|
143
153
|
if custom_services:
|
@@ -203,6 +213,9 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
203
213
|
# Add docker compose file
|
204
214
|
command.append(f"-f {os.path.relpath(self.compose_path, os.getcwd())}")
|
205
215
|
|
216
|
+
# Add docker compose networks file
|
217
|
+
command.append(f"-f {os.path.relpath(self.networks_compose_path, os.getcwd())}")
|
218
|
+
|
206
219
|
# Add custom docker compose file
|
207
220
|
if self.custom_services:
|
208
221
|
command.append(f"-f {os.path.relpath(self.custom_compose_path, self.__current_working_dir)}")
|
@@ -257,8 +270,10 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
257
270
|
_config[CERTS_DIR_ENV] = self.certs_dir_path
|
258
271
|
_config[CONTEXT_DIR_ENV] = self.context_dir_path
|
259
272
|
_config[SERVICE_NAME_ENV] = self.service_name
|
273
|
+
_config[SERVICE_SCRIPTS_ENV] = SERVICE_SCRIPTS_DIR
|
260
274
|
_config[USER_ID_ENV] = user_id or os.getuid()
|
261
275
|
_config[WORKFLOW_NAME_ENV] = self.workflow_name
|
276
|
+
_config[WORKFLOW_SCRIPTS_ENV] = WORKFLOW_SCRIPTS_DIR
|
262
277
|
_config[WORKFLOW_TEMPLATE_ENV] = self.workflow_name
|
263
278
|
|
264
279
|
if namespace:
|
@@ -267,9 +282,12 @@ class WorkflowRunCommand(WorkflowCommand):
|
|
267
282
|
if self.network:
|
268
283
|
_config[APP_NETWORK_ENV] = self.network
|
269
284
|
|
285
|
+
# Specified DNS should prioritized, otherwise defaults to internal DNS
|
270
286
|
nameservers = self.nameservers
|
271
287
|
if nameservers:
|
272
288
|
_config[SERVICE_DNS_ENV] = nameservers[0]
|
289
|
+
else:
|
290
|
+
_config[SERVICE_DNS_ENV] = '8.8.8.8'
|
273
291
|
|
274
292
|
env_vars = self.config(_config)
|
275
293
|
WorkflowEnv(self.workflow_path).write(env_vars)
|
@@ -39,13 +39,6 @@ class WorkflowValidateCommand(WorkflowCommand, ValidateCommand):
|
|
39
39
|
raise ScaffoldValidateException(f"Container '{mock_ui_container_name}' not found for service '{CORE_MOCK_UI_SERVICE_NAME}'")
|
40
40
|
|
41
41
|
def validate_no_core_components(self):
|
42
|
-
try:
|
43
|
-
core_gateway_container = self.docker_client.containers.get(self.managed_services_docker_compose.gateway_container_name)
|
44
|
-
if core_gateway_container:
|
45
|
-
raise ScaffoldValidateException(f"Gateway container is running when it shouldn't: {core_gateway_container.name}")
|
46
|
-
except docker_errors.NotFound:
|
47
|
-
pass
|
48
|
-
|
49
42
|
try:
|
50
43
|
core_mock_ui_container_name = self.docker_client.containers.get(self.managed_services_docker_compose.mock_ui_container_name)
|
51
44
|
if core_mock_ui_container_name:
|
@@ -14,7 +14,7 @@ from stoobly_agent.app.cli.scaffold.constants import (
|
|
14
14
|
DOCKER_NAMESPACE, WORKFLOW_CONTAINER_PROXY, WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
|
15
15
|
)
|
16
16
|
from stoobly_agent.app.cli.scaffold.containerized_app import ContainerizedApp
|
17
|
-
from stoobly_agent.app.cli.scaffold.docker.service.
|
17
|
+
from stoobly_agent.app.cli.scaffold.docker.service.configure_gateway import configure_gateway
|
18
18
|
from stoobly_agent.app.cli.scaffold.docker.workflow.decorators_factory import get_workflow_decorators
|
19
19
|
from stoobly_agent.app.cli.scaffold.hosts_file_manager import HostsFileManager
|
20
20
|
from stoobly_agent.app.cli.scaffold.service import Service
|
@@ -341,8 +341,11 @@ def down(**kwargs):
|
|
341
341
|
remove_image_command = command.remove_image(kwargs['user_id'])
|
342
342
|
print(remove_image_command, file=script)
|
343
343
|
|
344
|
-
|
345
|
-
print(
|
344
|
+
remove_egress_network_command = command.remove_egress_network()
|
345
|
+
print(remove_egress_network_command, file=script)
|
346
|
+
|
347
|
+
remove_ingress_network_command = command.remove_ingress_network()
|
348
|
+
print(remove_ingress_network_command, file=script)
|
346
349
|
|
347
350
|
__run_script(script, kwargs['dry_run'])
|
348
351
|
|
@@ -425,6 +428,7 @@ def logs(**kwargs):
|
|
425
428
|
@click.option('--namespace', help='Workflow namespace.')
|
426
429
|
@click.option('--network', help='Workflow network name.')
|
427
430
|
@click.option('--no-build', is_flag=True, help='Do not build images before starting containers.')
|
431
|
+
@click.option('--no-publish', is_flag=True, help='Do not publish all ports.')
|
428
432
|
@click.option('--pull', is_flag=True, help='Pull image before running.')
|
429
433
|
@click.option('--script-path', help='Path to intermediate script path.')
|
430
434
|
@click.option('--service', multiple=True, help='Select which services to run. Defaults to all.')
|
@@ -457,7 +461,7 @@ def up(**kwargs):
|
|
457
461
|
|
458
462
|
# Gateway ports are dynamically set depending on the workflow run
|
459
463
|
workflow = Workflow(kwargs['workflow_name'], app)
|
460
|
-
|
464
|
+
configure_gateway(workflow.service_paths_from_services(services), kwargs['no_publish'])
|
461
465
|
|
462
466
|
commands: List[WorkflowRunCommand] = []
|
463
467
|
for service in services:
|
@@ -478,7 +482,8 @@ def up(**kwargs):
|
|
478
482
|
create_image_command = command.create_image(user_id=kwargs['user_id'], verbose=kwargs['verbose'])
|
479
483
|
init_commands.append(create_image_command)
|
480
484
|
|
481
|
-
init_commands.append(command.
|
485
|
+
init_commands.append(command.create_egress_network())
|
486
|
+
init_commands.append(command.create_ingress_network())
|
482
487
|
joined_command = ' && '.join(init_commands)
|
483
488
|
|
484
489
|
if not containerized:
|
@@ -666,8 +671,11 @@ def __get_services(app: App, **kwargs):
|
|
666
671
|
|
667
672
|
# Intersection
|
668
673
|
selected_services = list(filter(lambda x: x in workflow_services, selected_services))
|
674
|
+
|
675
|
+
services = list(set(selected_services))
|
676
|
+
services.sort()
|
669
677
|
|
670
|
-
return
|
678
|
+
return services
|
671
679
|
|
672
680
|
def __print_header(text: str):
|
673
681
|
Logger.instance(LOG_ID).info(f"{bcolors.OKBLUE}{text}{bcolors.ENDC}")
|
@@ -15,12 +15,16 @@ from stoobly_agent.app.settings.match_rule import MatchRule
|
|
15
15
|
from stoobly_agent.config.constants import custom_headers, query_params as request_query_params
|
16
16
|
from stoobly_agent.lib.api.param_builder import ParamBuilder
|
17
17
|
from stoobly_agent.lib.api.interfaces.requests import RequestResponseShowQueryParams
|
18
|
-
from stoobly_agent.lib.
|
18
|
+
from stoobly_agent.lib.api.keys.project_key import InvalidProjectKey
|
19
|
+
from stoobly_agent.lib.api.keys.scenario_key import InvalidScenarioKey
|
20
|
+
from stoobly_agent.lib.logger import bcolors, Logger
|
19
21
|
|
20
22
|
from .hashed_request_decorator import HashedRequestDecorator
|
21
23
|
from .search_endpoint import inject_search_endpoint
|
22
24
|
from ..mitmproxy.request_facade import MitmproxyRequestFacade
|
23
25
|
|
26
|
+
LOG_ID = 'EvalRequest'
|
27
|
+
|
24
28
|
class EvalRequestOptions(TypedDict):
|
25
29
|
infer: bool
|
26
30
|
retry: int
|
@@ -49,10 +53,19 @@ def eval_request(
|
|
49
53
|
**options: EvalRequestOptions
|
50
54
|
) -> Response:
|
51
55
|
query_params_builder = ParamBuilder({})
|
56
|
+
scenario_key = intercept_settings.scenario_key
|
57
|
+
|
58
|
+
if not scenario_key:
|
59
|
+
Logger.instance(LOG_ID).info(f"{bcolors.WARNING}Missing{bcolors.ENDC} scenario key, defaulting to all requests for mocking")
|
52
60
|
|
53
61
|
try:
|
54
|
-
query_params_builder.with_resource_scoping(intercept_settings.project_key,
|
55
|
-
except:
|
62
|
+
query_params_builder.with_resource_scoping(intercept_settings.project_key, scenario_key)
|
63
|
+
except InvalidScenarioKey:
|
64
|
+
Logger.instance(LOG_ID).warn(f"{bcolors.WARNING}Invalid{bcolors.ENDC} scenario key ${scenario_key}")
|
65
|
+
# If project_key or scenario_key are invalid, assume custom not found
|
66
|
+
return CustomNotFoundResponseBuilder().build()
|
67
|
+
except InvalidProjectKey:
|
68
|
+
Logger.instance(LOG_ID).warn(f"{bcolors.WARNING}Invalid{bcolors.ENDC} project key ${intercept_settings.project_key}")
|
56
69
|
# If project_key or scenario_key are invalid, assume custom not found
|
57
70
|
return CustomNotFoundResponseBuilder().build()
|
58
71
|
|
@@ -292,7 +292,6 @@ class TestScaffoldE2e():
|
|
292
292
|
pass
|
293
293
|
|
294
294
|
def test_assets(self, app_dir_path, target_workflow_name):
|
295
|
-
|
296
295
|
app = App(app_dir_path, DOCKER_NAMESPACE)
|
297
296
|
config = {
|
298
297
|
'workflow_name': target_workflow_name,
|
@@ -300,5 +299,4 @@ class TestScaffoldE2e():
|
|
300
299
|
}
|
301
300
|
|
302
301
|
command = ServiceWorkflowValidateCommand(app, **config)
|
303
|
-
command.validate()
|
304
|
-
|
302
|
+
command.validate()
|
@@ -1 +1 @@
|
|
1
|
-
1.6.
|
1
|
+
1.6.4
|
@@ -1,15 +1,10 @@
|
|
1
1
|
# Define services here
|
2
|
-
networks:
|
3
|
-
app:
|
4
|
-
external: true
|
5
|
-
name: ${APP_NETWORK}
|
6
|
-
|
7
2
|
services:
|
8
3
|
assets:
|
9
4
|
hostname: assets
|
10
5
|
image: nginx:1.27
|
11
6
|
networks:
|
12
|
-
- app
|
7
|
+
- app.egress
|
13
8
|
volumes:
|
14
9
|
- ./index.html:/usr/share/nginx/html/index.html
|
15
10
|
profiles: &id001
|
@@ -1,16 +1,10 @@
|
|
1
1
|
# Define services here
|
2
|
-
|
3
|
-
networks:
|
4
|
-
app:
|
5
|
-
external: true
|
6
|
-
name: ${APP_NETWORK}
|
7
|
-
|
8
2
|
services:
|
9
3
|
my-httpbin:
|
10
4
|
image: kennethreitz/httpbin:latest
|
11
5
|
hostname: my-httpbin.com
|
12
6
|
networks:
|
13
|
-
- app
|
7
|
+
- app.egress
|
14
8
|
profiles: &id001
|
15
9
|
- record
|
16
10
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
stoobly_agent/__init__.py,sha256=
|
1
|
+
stoobly_agent/__init__.py,sha256=ftbaOUQT2yhRxLPO2HWJBT3dcSrAFLEftXLYmnaHuBg,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
|
@@ -68,29 +68,29 @@ stoobly_agent/app/cli/report_cli.py,sha256=ZxJw0Xkx7KFZJn9e45BSKRKon8AD0Msrwy1fb
|
|
68
68
|
stoobly_agent/app/cli/request_cli.py,sha256=THNloW111l9MLE0oPg4y7hVXL1U7OXoz760g0A1CtJ0,7747
|
69
69
|
stoobly_agent/app/cli/scaffold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
70
70
|
stoobly_agent/app/cli/scaffold/app.py,sha256=bgNc_dWZtgkuDAkS9aHSCMxCrjX907Phlfb2bOasswI,3435
|
71
|
-
stoobly_agent/app/cli/scaffold/app_command.py,sha256=
|
71
|
+
stoobly_agent/app/cli/scaffold/app_command.py,sha256=sliaYulMNmaxbRXpJIDtBDWEBGEv5Tht4rpErzC_xxw,2368
|
72
72
|
stoobly_agent/app/cli/scaffold/app_config.py,sha256=Gs-BynV1vY7_PpTOenn2mqc7lBIu0vBx6as9vtEU1sk,818
|
73
73
|
stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=sy4017eiir9MK0TEbTi1NyG9mhOGlenGGVnq0GsGUrQ,966
|
74
74
|
stoobly_agent/app/cli/scaffold/command.py,sha256=aoTsdkkBzyu7TkVSMdNQQGk0Gj874jNgFcjR14y3TuM,254
|
75
75
|
stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
|
76
|
-
stoobly_agent/app/cli/scaffold/constants.py,sha256=
|
76
|
+
stoobly_agent/app/cli/scaffold/constants.py,sha256=s5SBy8Xs4-Lg4tYEVBTiDIzeWwerrnz8qHXbXQtXH5U,2465
|
77
77
|
stoobly_agent/app/cli/scaffold/containerized_app.py,sha256=dAjn4RwcZV3aEL0POUmrbF_DC-r9h6s1zx7gT2t45v0,175
|
78
78
|
stoobly_agent/app/cli/scaffold/docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
79
|
stoobly_agent/app/cli/scaffold/docker/app_builder.py,sha256=7z5pk5JKlRDHx2USxY-WurttLyyUkIVYfl34_u1x9dE,501
|
80
|
-
stoobly_agent/app/cli/scaffold/docker/builder.py,sha256=
|
81
|
-
stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=
|
80
|
+
stoobly_agent/app/cli/scaffold/docker/builder.py,sha256=uiGqhxBHEasZAqLzjKUGUs-1QEZiMsJQYn4mdJ2jy3A,3137
|
81
|
+
stoobly_agent/app/cli/scaffold/docker/constants.py,sha256=1khQdgTaQ89ykGRNdTQh_ejFOdjNFGaZ_3cOGda6y7Y,692
|
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
|
-
stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=
|
85
|
-
stoobly_agent/app/cli/scaffold/docker/service/
|
84
|
+
stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=AE0tEHKeDM3dDMSjaqUwJA9ZLgzeyr0ErMAhOzNuaSI,3190
|
85
|
+
stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=bdqY9jESbyGEwPW5cwb51oznYFlzK4MUP770zxxgrds,1701
|
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
|
-
stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py,sha256=
|
89
|
-
stoobly_agent/app/cli/scaffold/docker/workflow/builder.py,sha256=
|
90
|
-
stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=
|
91
|
-
stoobly_agent/app/cli/scaffold/docker/workflow/
|
92
|
-
stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=
|
93
|
-
stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=
|
88
|
+
stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py,sha256=VKD9hXbJGRIWHS5IeYXeX0-FQ0F43zG8VmsegL6eYwA,703
|
89
|
+
stoobly_agent/app/cli/scaffold/docker/workflow/builder.py,sha256=i2T3TvWlXBT2O4wqwMcwsN55-4VzAblo36dEwCPf8yU,6736
|
90
|
+
stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=gU4RfuZ13r_YoB4eLS6FuiB1A4kfuLrWLPmYjZ0EJJw,955
|
91
|
+
stoobly_agent/app/cli/scaffold/docker/workflow/dns_decorator.py,sha256=nlDPbyF1hkVItzFH3bk9KlqfDC8usyFZs353-ibqxvA,938
|
92
|
+
stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=DcBnwA8YhE-VdrUiWf2xPcqirEMZEQm3AwssAg9CxLo,1226
|
93
|
+
stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=zD4FEtBMiPEtvEb798LOfFH8sJhTWQYpA9THLq5UMbg,1227
|
94
94
|
stoobly_agent/app/cli/scaffold/env.py,sha256=e-Ve4p3RUgzFx22B3SIYttvJ_yLuDtA27oDACZ8n-6E,1140
|
95
95
|
stoobly_agent/app/cli/scaffold/hosts_file_manager.py,sha256=FiX1hYEWN4cJiCOV4h6wOOlY7t71uwIwe6t2upS65aQ,5006
|
96
96
|
stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py,sha256=-wLBXUi7DCWsfm5KzZzd_kdJKOTl1NT924XR7dyjbSY,574
|
@@ -101,14 +101,15 @@ stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=bmLGgx9qnh-X_i2_
|
|
101
101
|
stoobly_agent/app/cli/scaffold/service_delete_command.py,sha256=_nBDQjm8eL62MQpzSCxgUHlW04ZXKG8MDlN1BXxlqww,986
|
102
102
|
stoobly_agent/app/cli/scaffold/service_docker_compose.py,sha256=OMUN1-ujQYIZXxDvS4XBf5C9wGalQULkwOiBBQPZbHY,820
|
103
103
|
stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOWkGEKz7gSgEGNI8f7aXOdg,444
|
104
|
-
stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=
|
104
|
+
stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=M5fc9RiCgN9ReCXsb3KIVJIKo0aSIOv28Q3izLkEQTo,10036
|
105
105
|
stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
106
106
|
stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=xnUFSlP8YvEs04lTh1Jj_ggNcwyVjyzZjzF0Vh9pris,158
|
107
|
-
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=
|
107
|
+
stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=_krOdKu4LX9C_UvWuJeyD7VhWVs0aZtuDNxwlzvvsBY,8418
|
108
108
|
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml,sha256=6tFqXh3ine8vaD0FCL5TMoY5NjKx2wLUR8XpW3tJtew,245
|
109
|
+
stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.networks.yml,sha256=I4PbJpQjFHb5IbAUWNvYM6okDEtmwtKFDQg-yog05WM,141
|
109
110
|
stoobly_agent/app/cli/scaffold/templates/app/Makefile,sha256=TEmPG7Bf0KZOnmfsgdzza3UdwcVMmM5Lj1YdLc4cgjA,79
|
110
111
|
stoobly_agent/app/cli/scaffold/templates/app/build/.config.yml,sha256=8Wt8ZZ5irvBYYS44xGrR_EWlZDuXH9kyWmquzsh7s8g,19
|
111
|
-
stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml,sha256=
|
112
|
+
stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml,sha256=SBjI-5APmzvzQafHzRahH_xcoXEEV9M9GIeEmXSwnAU,559
|
112
113
|
stoobly_agent/app/cli/scaffold/templates/app/build/mock/.docker-compose.mock.yml,sha256=3DJ8LTq3QScaz0SA_tXQqJ0kljSCeqkPyDbhLOxBJvc,414
|
113
114
|
stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/configure,sha256=dEOGIKUKJf5kjOwJRdTgZkS0ZjmQHWVuAmKrWUjPij4,44
|
114
115
|
stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
|
@@ -119,11 +120,11 @@ stoobly_agent/app/cli/scaffold/templates/app/build/test/.docker-compose.test.yml
|
|
119
120
|
stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/configure,sha256=dEOGIKUKJf5kjOwJRdTgZkS0ZjmQHWVuAmKrWUjPij4,44
|
120
121
|
stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
|
121
122
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.config.yml,sha256=T9VQz6OwAQpKdIoFrnfKAxuX_to0c6EhuWRLKM34Sr4,22
|
122
|
-
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml,sha256=
|
123
|
+
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml,sha256=Sl_E6IUaHSR_Av_Tm3FzCJ6w5qjtR2LiJfiQJAMZUFI,630
|
123
124
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/.docker-compose.mock.yml,sha256=-YbHd6BrAlBpT8PYg8kOsq0GyDeZ3g_q8IB0B0rGluU,551
|
124
125
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/configure,sha256=dEOGIKUKJf5kjOwJRdTgZkS0ZjmQHWVuAmKrWUjPij4,44
|
125
126
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
|
126
|
-
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/docker-compose.yml,sha256=
|
127
|
+
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/docker-compose.yml,sha256=JZztRTAEd_byGjhBbI_TOrj7CML8l5lV4tYOM2syHUw,717
|
127
128
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/.docker-compose.record.yml,sha256=aIcgjelss4V86lxS3-xN8j_2eR-0YkzhtN_b-g3Y0nE,555
|
128
129
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/configure,sha256=dEOGIKUKJf5kjOwJRdTgZkS0ZjmQHWVuAmKrWUjPij4,44
|
129
130
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
|
@@ -134,8 +135,9 @@ stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/init,sha256=YxW
|
|
134
135
|
stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/docker-compose.yml,sha256=E4gGJwHfnZoFo9-0vM17-Qg5LPjx7vIPpcz2K7eiZg0,591
|
135
136
|
stoobly_agent/app/cli/scaffold/templates/app/gateway/.config.yml,sha256=XnLQZMzzMMIwVycjyPN5QXsmRztkTFAna1kIHYuDfJQ,19
|
136
137
|
stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=bgBvyDhyehS75D2ObEi7sl9DLGV6U3c9JhCAncsvjq8,251
|
137
|
-
stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml,sha256=
|
138
|
-
stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml,sha256=
|
138
|
+
stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml,sha256=CDL5x18-ues4F_ujqpNef_zJTG6PyDOkQ11cIHBOW5k,136
|
139
|
+
stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml,sha256=eyLH2h33Peunus8M1sUKL9AALCG2ABhV_heiJKhvgwo,138
|
140
|
+
stoobly_agent/app/cli/scaffold/templates/app/gateway/test/.docker-compose.test.yml,sha256=oJO6i0lsuQaQeIH80yoPZo3Vs0LzUAH2WRl853yLq6g,136
|
139
141
|
stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.config.yml,sha256=XnLQZMzzMMIwVycjyPN5QXsmRztkTFAna1kIHYuDfJQ,19
|
140
142
|
stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.docker-compose.base.yml,sha256=bxrtZqf3YtaJCukzScslh5PgWC5q8xkGIP1wKJf33LA,111
|
141
143
|
stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/.docker-compose.exec.yml,sha256=JN89sU5uRf6YqHvN_O63K8rwQIAPJHbhFDLFmuUjKNM,304
|
@@ -195,9 +197,9 @@ stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=R9hh5dWVz7vGld7pE
|
|
195
197
|
stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256=WmGKoqJqOkhL40oLCo8PnWhBKdfbY0dO2UtRn1IKynE,3504
|
196
198
|
stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=x8V5pJmIiklD3f2q2-qq-CORf4YaXYq_r2JpR2MmSwk,416
|
197
199
|
stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
|
198
|
-
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=
|
199
|
-
stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=
|
200
|
-
stoobly_agent/app/cli/scaffold_cli.py,sha256=
|
200
|
+
stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=eF3aaK4OIZXYuSBEAeBnhAL7EZrS1G4mSYrJbEiXt2o,11082
|
201
|
+
stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=wv1Zrq0GoYO8ryac3oGno0C282c6UjMtniO19mBSyrE,4036
|
202
|
+
stoobly_agent/app/cli/scaffold_cli.py,sha256=qR1AvPbUFsn9QL_QrWVFxW77n4yMVI7DVwiV2ylRcOM,28686
|
201
203
|
stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
|
202
204
|
stoobly_agent/app/cli/snapshot_cli.py,sha256=cpCjxFYBuVwLuq_b2lIUu-5zWqupRlrp4xWgDytirSM,10047
|
203
205
|
stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
|
@@ -321,7 +323,7 @@ stoobly_agent/app/proxy/mock/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
321
323
|
stoobly_agent/app/proxy/mock/context.py,sha256=vDo5_3WBL73mVFnsmQWvcxvPg5nWtRJbigSrE3zGc-o,794
|
322
324
|
stoobly_agent/app/proxy/mock/custom_not_found_response_builder.py,sha256=xHjA2CNhW5A4NyPkDzws6DY5YQeJqF6b3Y3k0iJKNss,611
|
323
325
|
stoobly_agent/app/proxy/mock/eval_fixtures_service.py,sha256=hc4VLnN50HBaWvFnrhQUJqdH-r3jBu9DHrpt8gbvkHY,3847
|
324
|
-
stoobly_agent/app/proxy/mock/eval_request_service.py,sha256=
|
326
|
+
stoobly_agent/app/proxy/mock/eval_request_service.py,sha256=A1tcE3wmrC1HwLpz0aRuRw-Nucn0dyHD_yHw5BeQEJU,8146
|
325
327
|
stoobly_agent/app/proxy/mock/hashed_request_decorator.py,sha256=h1ma90fdaYI9LBWpMWMqWBz-RjNwI628O4VuS_uUBX4,5061
|
326
328
|
stoobly_agent/app/proxy/mock/ignored_components_response_builder.py,sha256=E32_E1eSdmPn2SeM_e1jWnqu4xh5w_SnmOs32Shx99E,501
|
327
329
|
stoobly_agent/app/proxy/mock/request_hasher.py,sha256=WeOeksmW_b5Ql0Xb0fL2WMH3MVHrm-9GYWYoKYS1teg,3755
|
@@ -481,7 +483,7 @@ stoobly_agent/lib/api/keys/resource_key.py,sha256=9qrkp3t8iJsScZvKVcBDvVbcfwmP0y
|
|
481
483
|
stoobly_agent/lib/api/keys/scenario_key.py,sha256=VAc6gayvJS7shWgDL3SAqVET3fmgBefcygXTsKot07U,629
|
482
484
|
stoobly_agent/lib/api/keys/test_key.py,sha256=-MCWp1oYLkJ3S_Pqs62j8KkkssXpT9quKb4YqMSq1Ks,438
|
483
485
|
stoobly_agent/lib/api/keys/uuid_key.py,sha256=7_aL5wVTKF68bESHvqeQ2RUeC-Fw9-zpSrl8EWuFTJw,603
|
484
|
-
stoobly_agent/lib/api/param_builder.py,sha256=
|
486
|
+
stoobly_agent/lib/api/param_builder.py,sha256=50eq0zkqRz5MVezPZMIu69fYSB6z4CD5FG26_IU3eq0,996
|
485
487
|
stoobly_agent/lib/api/projects_resource.py,sha256=7leBuQnlpgUwbYUX445lUC3jy-dzLMpTumeNPrqRc5c,1166
|
486
488
|
stoobly_agent/lib/api/query_param_names_resource.py,sha256=k-3nlyfCOa_Vwj-TMI7v8_4g9qAs50baP073gkStAKE,1710
|
487
489
|
stoobly_agent/lib/api/reports_resource.py,sha256=Dtw-96J99u0AEJRYYNUA1awPAneg2Y0IOHyjvuF6juQ,601
|
@@ -671,7 +673,7 @@ stoobly_agent/test/app/cli/request/request_snapshot_test.py,sha256=0013aoiMZin-2
|
|
671
673
|
stoobly_agent/test/app/cli/request/request_test_test.py,sha256=-cJNXKjgryVVfVt-7IN5fIhBwe3NjFoPmeavDH8lAjU,5527
|
672
674
|
stoobly_agent/test/app/cli/scaffold/cli_invoker.py,sha256=_nGDLUsYxqkeqs5DdhvAeXy3IuotpgqKHXKVzu6GDF4,3700
|
673
675
|
stoobly_agent/test/app/cli/scaffold/cli_test.py,sha256=sMNvO845MIu5DVGa1HmwXQDmKDcwrfNTdEb3fK5886w,4557
|
674
|
-
stoobly_agent/test/app/cli/scaffold/e2e_test.py,sha256=
|
676
|
+
stoobly_agent/test/app/cli/scaffold/e2e_test.py,sha256=Zq0nYPObbH6tYjuGHrT2hOT71FO6kDnvRQWGDK1yK4M,12971
|
675
677
|
stoobly_agent/test/app/cli/scaffold/hosts_file_manager_test.py,sha256=sVFHHYBxzyfRbVIe3gnToQ-6JPy71BCBjdQDnboYzac,2306
|
676
678
|
stoobly_agent/test/app/cli/scenario/scenario_create_test.py,sha256=fGqcjO1_1OvdpUMQfGRVkSyFe61u8WIcp_ndLFrf33A,3962
|
677
679
|
stoobly_agent/test/app/cli/scenario/scenario_replay_integration_test.py,sha256=NbGJzmvPsNLBR0ac65yt_cOTfpnsST1IG7i3F0euwAk,7031
|
@@ -697,7 +699,7 @@ stoobly_agent/test/app/models/factories/resource/local_db/helpers/log_test.py,sh
|
|
697
699
|
stoobly_agent/test/app/models/factories/resource/local_db/helpers/tiebreak_scenario_request_test.py,sha256=a1SFLyEyRRLuADvAw6ckQQKORFXvyK1lyrbkaLWx8oU,3399
|
698
700
|
stoobly_agent/test/app/models/factories/resource/local_db/request_adapter_test.py,sha256=Pzq1cBPnP9oSWG-p0c-VoymoHxgp483QmNwmV1b78RA,8453
|
699
701
|
stoobly_agent/test/app/models/factories/resource/local_db/response_adapter_test.py,sha256=9P95EKH5rZGOrmRkRIDlQZqtiLJHk9735og18Ffwpfw,2204
|
700
|
-
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=
|
702
|
+
stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION,sha256=1-dHLCYhhLoNpJuXwyP9qKDsvu4z17NNtIQF76_WVd4,6
|
701
703
|
stoobly_agent/test/app/models/schemas/.stoobly/db/stoobly_agent.sqlite3,sha256=ch8gNx6zIelLKQx65gwFx_LRNqUD3EC5xcHZ0ukIQiU,188416
|
702
704
|
stoobly_agent/test/app/models/schemas/.stoobly/settings.yml,sha256=vLwMjweKOdod6tSLtIlyBefPQuNXq9wio4kBaODKtAU,726
|
703
705
|
stoobly_agent/test/app/models/schemas/.stoobly/tmp/options.json,sha256=OTRzarwus48CTrItedXCrgQttJHSEZonEYc7R_knvYg,2212
|
@@ -733,13 +735,13 @@ stoobly_agent/test/mock_data/petstore-references.yaml,sha256=OpNrCSb5-qKmUBIO9oG
|
|
733
735
|
stoobly_agent/test/mock_data/petstore-swagger-io.yaml,sha256=FbOEaArZKl1dV7jEf1hyJQv9jdAb5jXfsRRZB5i4-0Y,22094
|
734
736
|
stoobly_agent/test/mock_data/petstore.yaml,sha256=CCdliJky04Az4FIOkFA883uunwFDHLr2Y8ohtozFi_Q,2714
|
735
737
|
stoobly_agent/test/mock_data/request_show_response.py,sha256=K_a0fP0QT58T8sX9PaM6hqtX1A1depZsqg_GsNPf--k,707
|
736
|
-
stoobly_agent/test/mock_data/scaffold/docker-compose-assets-service.yml,sha256=
|
737
|
-
stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=
|
738
|
+
stoobly_agent/test/mock_data/scaffold/docker-compose-assets-service.yml,sha256=m2eN4XZLHnUMDq9wub34Yv9rh8GUWOUgJjY6U3wAljQ,220
|
739
|
+
stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1WGJJzb8tO13RH5toF4g8km0vItksnO2RIjE36nnp-8,185
|
738
740
|
stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
|
739
741
|
stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
|
740
742
|
stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
|
741
|
-
stoobly_agent-1.6.
|
742
|
-
stoobly_agent-1.6.
|
743
|
-
stoobly_agent-1.6.
|
744
|
-
stoobly_agent-1.6.
|
745
|
-
stoobly_agent-1.6.
|
743
|
+
stoobly_agent-1.6.4.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
|
744
|
+
stoobly_agent-1.6.4.dist-info/METADATA,sha256=Yx-Gc2cFV8iqjcfH8XeqLd3dc1IRPhKkJ5hYKbtVUCU,3087
|
745
|
+
stoobly_agent-1.6.4.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
746
|
+
stoobly_agent-1.6.4.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
|
747
|
+
stoobly_agent-1.6.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|