stoobly-agent 1.9.9__py3-none-any.whl → 1.9.11__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.
Files changed (29) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/helpers/shell.py +9 -1
  3. stoobly_agent/app/cli/intercept_cli.py +1 -1
  4. stoobly_agent/app/cli/scaffold/app.py +6 -0
  5. stoobly_agent/app/cli/scaffold/app_command.py +1 -1
  6. stoobly_agent/app/cli/scaffold/app_config.py +14 -14
  7. stoobly_agent/app/cli/scaffold/app_create_command.py +7 -7
  8. stoobly_agent/app/cli/scaffold/command.py +3 -3
  9. stoobly_agent/app/cli/scaffold/constants.py +6 -3
  10. stoobly_agent/app/cli/scaffold/docker/service/builder.py +7 -3
  11. stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +6 -6
  12. stoobly_agent/app/cli/scaffold/env.py +0 -2
  13. stoobly_agent/app/cli/scaffold/service_command.py +1 -1
  14. stoobly_agent/app/cli/scaffold/service_config.py +12 -7
  15. stoobly_agent/app/cli/scaffold/service_create_command.py +1 -1
  16. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +3 -2
  17. stoobly_agent/app/cli/scaffold/templates/app/.Makefile +15 -11
  18. stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml +1 -1
  19. stoobly_agent/app/cli/scaffold/workflow_command.py +3 -3
  20. stoobly_agent/app/cli/scaffold/workflow_env.py +10 -3
  21. stoobly_agent/app/cli/scaffold/workflow_namesapce.py +41 -0
  22. stoobly_agent/app/cli/scaffold/workflow_run_command.py +15 -23
  23. stoobly_agent/app/cli/scaffold_cli.py +15 -16
  24. stoobly_agent/app/cli/types/workflow_run_command.py +18 -0
  25. {stoobly_agent-1.9.9.dist-info → stoobly_agent-1.9.11.dist-info}/METADATA +1 -1
  26. {stoobly_agent-1.9.9.dist-info → stoobly_agent-1.9.11.dist-info}/RECORD +29 -27
  27. {stoobly_agent-1.9.9.dist-info → stoobly_agent-1.9.11.dist-info}/LICENSE +0 -0
  28. {stoobly_agent-1.9.9.dist-info → stoobly_agent-1.9.11.dist-info}/WHEEL +0 -0
  29. {stoobly_agent-1.9.9.dist-info → stoobly_agent-1.9.11.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.9'
2
+ VERSION = '1.9.11'
@@ -1,10 +1,18 @@
1
+ import os
1
2
  import subprocess
2
3
  import sys
3
4
 
4
5
  from dotenv import load_dotenv
5
6
 
7
+ DOTENV_PATH = 'STOOBLY_DOTENV_PATH'
8
+
6
9
  def exec_stream(command):
7
- load_dotenv()
10
+ dotenv_path = os.environ.get(DOTENV_PATH)
11
+
12
+ if dotenv_path and os.path.exists(dotenv_path):
13
+ load_dotenv(dotenv_path=dotenv_path)
14
+ else:
15
+ load_dotenv()
8
16
 
9
17
  # Start the process
10
18
  process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
@@ -8,7 +8,7 @@ from stoobly_agent.lib.api.keys.project_key import ProjectKey
8
8
 
9
9
  from .helpers.handle_config_update_service import handle_intercept_active_update, handle_order_update
10
10
 
11
- settings = Settings.instance()
11
+ settings: Settings = Settings.instance()
12
12
 
13
13
  mode_options = [mode.MOCK, mode.RECORD, mode.REPLAY]
14
14
 
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import os
2
3
  import shutil
3
4
 
@@ -73,6 +74,11 @@ class App():
73
74
  def data_dir_path(self):
74
75
  return self.__data_dir_path
75
76
 
77
+ @property
78
+ def network(self):
79
+ # An app may contain one or more context dirs from which services will derive their mocks from
80
+ return hashlib.md5(self.context_dir_path.encode()).hexdigest()
81
+
76
82
  @property
77
83
  def scaffold_namespace_path(self):
78
84
  return os.path.join(self.data_dir_path, self.scaffold_namespace)
@@ -40,7 +40,7 @@ class AppCommand(Command):
40
40
  @property
41
41
  def networks_compose_relative_path(self):
42
42
  return os.path.join(
43
- self.namespace,
43
+ self.scaffold_namespace,
44
44
  DOCKER_COMPOSE_NETWORKS
45
45
  )
46
46
 
@@ -1,16 +1,25 @@
1
1
  from .config import Config
2
- from .constants import APP_NAME_ENV, APP_NETWORK_ENV, APP_UI_PORT_ENV
2
+ from .constants import APP_DOCKER_SOCKET_PATH_ENV, APP_NAME_ENV, APP_UI_PORT_ENV
3
3
 
4
4
  class AppConfig(Config):
5
5
 
6
6
  def __init__(self, dir: str):
7
7
  super().__init__(dir)
8
8
 
9
+ self.__docker_socket_path = '/var/run/docker.sock'
9
10
  self.__name = None
10
- self.__network = None
11
+ self.__ui_port = None
11
12
 
12
13
  self.load()
13
14
 
15
+ @property
16
+ def docker_socket_path(self):
17
+ return self.__docker_socket_path
18
+
19
+ @docker_socket_path.setter
20
+ def docker_socket_path(self, v):
21
+ self.__docker_socket_path = v
22
+
14
23
  @property
15
24
  def name(self):
16
25
  return self.__name
@@ -19,14 +28,6 @@ class AppConfig(Config):
19
28
  def name(self, v):
20
29
  self.__name = v
21
30
 
22
- @property
23
- def network(self):
24
- return self.__network
25
-
26
- @network.setter
27
- def network(self, v):
28
- self.__network = v
29
-
30
31
  @property
31
32
  def ui_port(self):
32
33
  return self.__ui_port
@@ -39,18 +40,17 @@ class AppConfig(Config):
39
40
  config = config or self.read()
40
41
 
41
42
  self.name = config.get(APP_NAME_ENV)
42
- self.network = config.get(APP_NETWORK_ENV)
43
43
  self.ui_port = config.get(APP_UI_PORT_ENV)
44
44
 
45
45
  def write(self):
46
46
  config = {}
47
47
 
48
+ if self.docker_socket_path:
49
+ config[APP_DOCKER_SOCKET_PATH_ENV] = self.docker_socket_path
50
+
48
51
  if self.name:
49
52
  config[APP_NAME_ENV] = self.name
50
53
 
51
- if self.network:
52
- config[APP_NETWORK_ENV] = self.network
53
-
54
54
  if self.ui_port:
55
55
  config[APP_UI_PORT_ENV] = self.ui_port
56
56
 
@@ -7,8 +7,8 @@ from .app import App
7
7
  from .app_command import AppCommand
8
8
 
9
9
  class AppCreateOptions(TypedDict):
10
+ docker_socket_path: str
10
11
  name: str
11
- network: str
12
12
  ui_port: int
13
13
 
14
14
  class AppCreateCommand(AppCommand):
@@ -19,19 +19,19 @@ class AppCreateCommand(AppCommand):
19
19
  if kwargs.get('app_name'):
20
20
  self.app_config.name = kwargs['app_name']
21
21
 
22
- if kwargs.get('network'):
23
- self.app_config.network = kwargs['network']
22
+ if kwargs.get('docker_socket_path'):
23
+ self.app_config.docker_socket_path = kwargs['docker_socket_path']
24
24
 
25
25
  if kwargs.get('ui_port'):
26
26
  self.app_config.ui_port = kwargs['ui_port']
27
27
 
28
28
  @property
29
- def app_name(self):
30
- return self.app_config.name
29
+ def docker_socket_path(self):
30
+ return self.app_config.docker_socket_path
31
31
 
32
32
  @property
33
- def app_network(self):
34
- return self.app_config.network
33
+ def app_name(self):
34
+ return self.app_config.name
35
35
 
36
36
  @property
37
37
  def app_ui_port(self):
@@ -4,12 +4,12 @@ class Command():
4
4
 
5
5
  def __init__(self, app: App):
6
6
  self.__app = app
7
- self.__namespace = app.scaffold_namespace
7
+ self.__scaffold_namespace = app.scaffold_namespace
8
8
 
9
9
  @property
10
10
  def app(self):
11
11
  return self.__app
12
12
 
13
13
  @property
14
- def namespace(self):
15
- return self.__namespace
14
+ def scaffold_namespace(self):
15
+ return self.__scaffold_namespace
@@ -6,6 +6,7 @@ from stoobly_agent.config.data_dir import CERTS_DIR_NAME, DATA_DIR_NAME
6
6
 
7
7
  APP_DIR = '${APP_DIR}'
8
8
  APP_DIR_ENV = 'APP_DIR'
9
+ APP_DOCKER_SOCKET_PATH_ENV = 'APP_DOCKER_SOCKET_PATH'
9
10
  APP_NETWORK_ENV = 'APP_NETWORK'
10
11
  APP_NAME_ENV = 'APP_NAME'
11
12
  APP_UI_PORT_ENV = 'APP_UI_PORT'
@@ -16,15 +17,17 @@ COMPOSE_TEMPLATE = '.docker-compose.{workflow}.yml'
16
17
  CONFIG_FILE = '.config.yml'
17
18
  CONTEXT_DIR_ENV = 'CONTEXT_DIR'
18
19
  DOCKER_NAMESPACE = 'docker'
19
- ENV_FILE = '.env'
20
+ DOTENV_FILE = '.env'
20
21
  NAMESERVERS_FILE = '.nameservers'
21
22
  PUBLIC_FOLDER_NAME = 'public'
22
23
  SERVICE_DETACHED = '${SERVICE_DETACHED}'
23
24
  SERVICE_DETACHED_ENV = 'SERVICE_DETACHED'
24
- SERVICE_HOSTNAME = '${SERVICE_HOSTNAME}'
25
- SERVICE_HOSTNAME_ENV = 'SERVICE_HOSTNAME'
26
25
  SERVICE_DNS = '${SERVICE_DNS}'
27
26
  SERVICE_DNS_ENV = 'SERVICE_DNS'
27
+ SERVICE_HOSTNAME = '${SERVICE_HOSTNAME}'
28
+ SERVICE_HOSTNAME_ENV = 'SERVICE_HOSTNAME'
29
+ SERVICE_ID = '${SERVICE_ID}'
30
+ SERVICE_ID_ENV = 'SERVICE_ID'
28
31
  SERVICE_NAME = '${SERVICE_NAME}'
29
32
  SERVICE_NAME_ENV = 'SERVICE_NAME'
30
33
  SERVICE_PROXY_MODE = '${SERVICE_PROXY_MODE}'
@@ -7,8 +7,12 @@ from stoobly_agent.config.data_dir import DATA_DIR_NAME
7
7
 
8
8
  from ...app_config import AppConfig
9
9
  from ...constants import (
10
- APP_DIR, DOCKER_NAMESPACE, SERVICE_NAME, SERVICE_NAME_ENV,
11
- SERVICE_HOSTNAME, SERVICE_HOSTNAME_ENV, SERVICE_NAME_ENV, SERVICE_PORT, SERVICE_PORT_ENV, SERVICE_SCHEME, SERVICE_SCHEME_ENV,
10
+ APP_DIR, DOCKER_NAMESPACE,
11
+ SERVICE_HOSTNAME, SERVICE_HOSTNAME_ENV,
12
+ SERVICE_NAME, SERVICE_NAME_ENV,
13
+ SERVICE_ID,
14
+ SERVICE_PORT, SERVICE_PORT_ENV,
15
+ SERVICE_SCHEME, SERVICE_SCHEME_ENV,
12
16
  STOOBLY_HOME_DIR, STOOBLY_HOME_DIR,
13
17
  WORKFLOW_NAME, WORKFLOW_NAME_ENV, WORKFLOW_SCRIPTS, WORKFLOW_TEMPLATE
14
18
  )
@@ -91,7 +95,7 @@ class ServiceBuilder(Builder):
91
95
  if not self.config.hostname:
92
96
  return
93
97
 
94
- service_id = self.config.id
98
+ service_id = SERVICE_ID
95
99
  environment = { **self.env_dict() }
96
100
  labels = [
97
101
  'traefik.enable=true',
@@ -4,13 +4,13 @@ import yaml
4
4
 
5
5
  from typing import List
6
6
 
7
- from stoobly_agent.config.data_dir import DATA_DIR_NAME, TMP_DIR_NAME
8
7
  from stoobly_agent.app.cli.scaffold.constants import APP_DIR
9
8
  from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
10
9
  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
10
  from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
11
+ from stoobly_agent.app.cli.scaffold.workflow_namesapce import WorkflowNamespace
12
12
 
13
- def configure_gateway(namespace: str, service_paths: List[str], no_publish = False):
13
+ def configure_gateway(workflow_namespace: WorkflowNamespace, 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(namespace: str, service_paths: List[str], no_publish = Fal
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(namespace, service_paths, app_dir_path, gateway_base)
39
+ __with_traefik_config(workflow_namespace, 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(namespace: str, service_paths: List[str], app_dir_path: str, compose: dict):
53
+ def __with_traefik_config(workflow_namespace: WorkflowNamespace, 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,8 +98,8 @@ def __with_traefik_config(namespace: str, service_paths: List[str], app_dir_path
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, namespace, 'traefik.yml')
102
- traefik_template_dest_path = os.path.join(app_dir_path, traefik_template_relative_path)
101
+ traefik_template_relative_path = workflow_namespace.traefik_config_relative_path(app_dir_path)
102
+ traefik_template_dest_path = workflow_namespace.traefik_config_path
103
103
 
104
104
  if not os.path.exists(os.path.dirname(traefik_template_dest_path)):
105
105
  os.makedirs(os.path.dirname(traefik_template_dest_path), exist_ok=True)
@@ -1,7 +1,5 @@
1
1
  import os
2
2
 
3
- from .constants import ENV_FILE
4
-
5
3
  DELIMITTER = "\n"
6
4
 
7
5
  class Env():
@@ -48,7 +48,7 @@ class ServiceCommand(AppCommand):
48
48
  @property
49
49
  def service_relative_path(self):
50
50
  return os.path.join(
51
- self.namespace,
51
+ self.scaffold_namespace,
52
52
  self.service_name,
53
53
  )
54
54
 
@@ -7,6 +7,7 @@ from .config import Config
7
7
  from .constants import (
8
8
  SERVICE_DETACHED_ENV,
9
9
  SERVICE_HOSTNAME_ENV,
10
+ SERVICE_ID_ENV,
10
11
  SERVICE_PRIORITY_ENV,
11
12
  SERVICE_PORT_ENV,
12
13
  SERVICE_PROXY_MODE_ENV,
@@ -55,7 +56,7 @@ class ServiceConfig(Config):
55
56
 
56
57
  @property
57
58
  def id(self):
58
- return hashlib.md5(os.path.basename(self.dir).encode()).hexdigest()
59
+ return hashlib.md5(self.url.encode()).hexdigest()
59
60
 
60
61
  @property
61
62
  def hostname(self):
@@ -106,18 +107,22 @@ class ServiceConfig(Config):
106
107
  if not self.hostname:
107
108
  return ''
108
109
 
109
- _proxy_mode = f"reverse:{self.scheme}://{self.hostname}"
110
+ return f"reverse:{self.url}"
111
+
112
+ @property
113
+ def url(self):
114
+ _url = f"{self.scheme}://{self.hostname}"
110
115
 
111
116
  if not self.port:
112
- return _proxy_mode
117
+ return _url
113
118
 
114
119
  if self.scheme == 'http' and self.port == 80:
115
- return _proxy_mode
120
+ return _url
116
121
 
117
122
  if self.scheme == 'https' and self.port == 443:
118
- return _proxy_mode
123
+ return _url
119
124
 
120
- return f"{_proxy_mode}:{self.port}"
125
+ return f"{_url}:{self.port}"
121
126
 
122
127
  @proxy_mode.setter
123
128
  def proxy_mode(self, v):
@@ -171,7 +176,7 @@ class ServiceConfig(Config):
171
176
  config[SERVICE_SCHEME_ENV] = self.scheme
172
177
 
173
178
  config[SERVICE_DETACHED_ENV] = bool(self.detached)
174
-
179
+ config[SERVICE_ID_ENV] = self.id
175
180
  config[SERVICE_PROXY_MODE_ENV] = self.proxy_mode
176
181
 
177
182
  super().write(config)
@@ -37,7 +37,7 @@ class ServiceCreateCommand(ServiceCommand):
37
37
 
38
38
  workflow_kwargs = {
39
39
  'app_dir_path': self.app_dir_path,
40
- 'namespace': self.namespace,
40
+ 'namespace': self.scaffold_namespace,
41
41
  'service_name': self.service_name,
42
42
  }
43
43
 
@@ -116,8 +116,9 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
116
116
 
117
117
  def validate_internal_hostname(self, url: str) -> None:
118
118
  print(f"Validating hostname inside Docker network, url: {url}")
119
-
120
- network = f"{self.workflow_name}.{self.app_config.network}"
119
+
120
+ # See WorkflowRunCommand for how 'network' is generated
121
+ network = f"{self.workflow_name}.{self.app.network}"
121
122
  timeout_seconds = 1
122
123
  output = self.docker_client.containers.run(
123
124
  image='curlimages/curl:8.11.0',
@@ -4,7 +4,7 @@
4
4
  # STOOBLY_CA_CERTS_DIR: path to folder where ca certs are stored, defaults to $(pwd)/.stoobly/ca_certs
5
5
  # STOOBLY_CERTS_DIR: path to a folder to store certs, defaults to $(pwd)/.stoobly/certs
6
6
  # STOOBLY_CONTEXT_DIR: path to the folder containing the .stoobly folder, defaults to $(pwd)
7
- # STOOBLY_ENV_FILE: path to dotenv file, defaults to $(pwd)/.env
7
+ # STOOBLY_DOTENV_FILE: path to dotenv file, defaults to $(pwd)/.env
8
8
  # STOOBLY_WORKFLOW_SERVICE_OPTIONS: extra --service options to pass 'stoobly-agent scaffold workflow' commands
9
9
 
10
10
  # Overridable Options
@@ -28,7 +28,7 @@ app_dir=$$(realpath "$${STOOBLY_APP_DIR:-$(CONTEXT_DIR_DEFAULT)}")
28
28
  ca_certs_dir=$$(realpath "$${STOOBLY_CA_CERTS_DIR:-$(app_data_dir)/ca_certs}")
29
29
  certs_dir=$$(realpath "$${STOOBLY_CERTS_DIR:-$(app_data_dir)/certs}")
30
30
  context_dir=$$(realpath "$${STOOBLY_CONTEXT_DIR:-$(CONTEXT_DIR_DEFAULT)}")
31
- env_file=$$(realpath "$${STOOBLY_ENV_FILE:-.env}" 2> /dev/null || echo '')
31
+ dotenv_file=$$(realpath "$${STOOBLY_DOTENV_FILE:-.env}" 2> /dev/null || echo '')
32
32
  workflow=record
33
33
  workflow_service_options=$(shell echo $$STOOBLY_WORKFLOW_SERVICE_OPTIONS)
34
34
 
@@ -38,34 +38,34 @@ app_tmp_dir=$(app_data_dir)/tmp
38
38
  dockerfile_path=$(app_namespace_dir)/.Dockerfile.context
39
39
  exec_docker_compose_file_path=$(app_namespace_dir)/stoobly-ui/exec/.docker-compose.exec.yml
40
40
  workflow_namespace=$(if $(namespace),$(namespace),$(workflow))
41
+ workflow_namespace_dir=$(app_tmp_dir)/$(workflow_namespace)
41
42
  workflow_script=.stoobly/tmp/$(workflow_namespace)/run.sh
42
43
 
43
44
  # Options
44
45
  certs_dir_options=--ca-certs-dir-path $(ca_certs_dir) --certs-dir-path $(certs_dir)
45
46
  working_dir_options=--app-dir-path $(app_dir) --context-dir-path $(context_dir)
46
47
 
47
- workflow_down_options=--user-id $(USER_ID) $(workflow_down_extra_options)
48
+ workflow_down_options=$(working_dir_options) --user-id $(USER_ID) $(workflow_down_extra_options)
48
49
  workflow_log_options=$(workflow_log_extra_options)
49
50
  workflow_run_options=--namespace $(workflow_namespace) --script-path $(workflow_script) $(workflow_service_options)
50
51
  workflow_up_options=$(working_dir_options) $(certs_dir_options) --user-id $(USER_ID) $(workflow_up_extra_options)
51
-
52
+
52
53
  # Commands
53
54
  exec_env=APP_DIR="$(app_dir)" CA_CERTS_DIR="$(ca_certs_dir)" USER_ID="$(USER_ID)"
54
55
  exec_up=$(DOCKER_BIN) compose -f "$(exec_docker_compose_file_path)" run --rm stoobly_ui.command
55
- source_env=set -a; [ -f "$(env_file)" ] && . "$(env_file)"; set +a
56
56
 
57
57
  # Build base image
58
58
  stoobly_exec_build=$(DOCKER_BIN) build $(stoobly_exec_build_args) $(app_namespace_dir) > /dev/null
59
59
  stoobly_exec_build_args=-f "$(dockerfile_path)" -t stoobly.$(USER_ID) --build-arg USER_ID=$(USER_ID) $(PULL_OPTION) --quiet
60
60
 
61
61
  # Exec any
62
- stoobly_exec=$(source_env); $(stoobly_exec_build) && $(stoobly_exec_env) $(exec_up)
62
+ stoobly_exec=$(stoobly_exec_build) && $(stoobly_exec_env) $(exec_up)
63
63
  stoobly_exec_env=$(exec_env) CONTEXT_DIR="$(context_dir)"
64
64
 
65
65
  # Exec workflow run
66
66
  # Scaffold is stored in the application source code directory.
67
67
  # When running a scaffold command from within a container, it needs access to $(app_dir) rather than $(context_dir)
68
- stoobly_exec_run=$(source_env); $(stoobly_exec_build) && $(stoobly_exec_run_env) $(exec_up)
68
+ stoobly_exec_run=$(stoobly_exec_build) && $(stoobly_exec_run_env) $(exec_up)
69
69
  stoobly_exec_run_env=$(exec_env) CONTEXT_DIR="$(app_dir)"
70
70
 
71
71
  # Workflow run
@@ -88,14 +88,16 @@ ca-cert/install: stoobly/install
88
88
  certs:
89
89
  @export EXEC_COMMAND=scaffold/.mkcert EXEC_OPTIONS="" EXEC_ARGS="" && \
90
90
  $(stoobly_exec)
91
- nameservers: tmpdir
91
+ dotenv: workflow/namespace
92
+ @if [ -f "$(dotenv_file)" ]; then cp "$(dotenv_file)" $(workflow_namespace_dir)/.env; fi
93
+ nameservers: workflow/namespace
92
94
  @if [ -f /etc/resolv.conf ]; then \
93
95
  nameserver=$$(grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' /etc/resolv.conf) && \
94
96
  if [ "$$nameserver" = "127.0.0.53" ]; then \
95
97
  echo "Nameserver is 127.0.0.53. Checking resolvectl status..."; \
96
98
  nameserver=$$(resolvectl status | sed -n '/DNS Servers:/s/.*DNS Servers:\s*\([^ ]*\).*/\1/p' | head -n 1); \
97
99
  fi; \
98
- echo "$$nameserver" > $(app_tmp_dir)/.nameservers; \
100
+ echo "$$nameserver" > $(workflow_namespace_dir)/.nameservers; \
99
101
  else \
100
102
  echo "/etc/resolv.conf not found." >&2; \
101
103
  fi
@@ -158,7 +160,7 @@ test/logs: workflow/test workflow/logs
158
160
  test/down: workflow/test workflow/down
159
161
  tmpdir:
160
162
  @mkdir -p $(app_tmp_dir)
161
- workflow/down:
163
+ workflow/down: dotenv
162
164
  @export EXEC_COMMAND=scaffold/.down EXEC_OPTIONS="$(workflow_down_options) $(workflow_run_options) $(options)" EXEC_ARGS="$(workflow)" && \
163
165
  $(stoobly_exec_run) && \
164
166
  $(workflow_run)
@@ -182,6 +184,8 @@ workflow/logs:
182
184
  $(workflow_run)
183
185
  workflow/mock:
184
186
  $(eval workflow=mock)
187
+ workflow/namespace: tmpdir
188
+ @mkdir -p $(workflow_namespace_dir)
185
189
  workflow/record:
186
190
  $(eval workflow=record)
187
191
  workflow/services:
@@ -189,7 +193,7 @@ workflow/services:
189
193
  $(stoobly_exec_run)
190
194
  workflow/test:
191
195
  $(eval workflow=test) $(eval workflow_up_extra_options=$(workflow_up_extra_options) --no-publish)
192
- workflow/up:
196
+ workflow/up: dotenv
193
197
  @export EXEC_COMMAND=scaffold/.up EXEC_OPTIONS="$(workflow_up_options) $(workflow_run_options) $(options)" EXEC_ARGS="$(workflow)" && \
194
198
  $(stoobly_exec_run) && \
195
199
  $(workflow_run)
@@ -6,5 +6,5 @@ services:
6
6
  profiles:
7
7
  - gateway_base
8
8
  volumes:
9
- - /var/run/docker.sock:/var/run/docker.sock:ro
9
+ - ${APP_DOCKER_SOCKET_PATH}:/var/run/docker.sock:ro
10
10
  - ${CERTS_DIR}:/certs:ro
@@ -5,7 +5,7 @@ import yaml
5
5
  from stoobly_agent.lib.logger import Logger
6
6
 
7
7
  from .app import App
8
- from .constants import BIN_FOLDER_NAME, COMPOSE_TEMPLATE, CONFIG_FILE, ENV_FILE, PUBLIC_FOLDER_NAME
8
+ from .constants import BIN_FOLDER_NAME, COMPOSE_TEMPLATE, CONFIG_FILE, DOTENV_FILE, PUBLIC_FOLDER_NAME
9
9
  from .docker.constants import DOCKER_COMPOSE_CUSTOM
10
10
  from .service_command import ServiceCommand
11
11
  from .workflow_config import WorkflowConfig
@@ -101,8 +101,8 @@ class WorkflowCommand(ServiceCommand):
101
101
  return os.path.join(self.workflow_path, CONFIG_FILE)
102
102
 
103
103
  @property
104
- def workflow_env_path(self):
105
- return os.path.join(self.workflow_path, ENV_FILE)
104
+ def workflow_dotenv_path(self):
105
+ return os.path.join(self.workflow_path, DOTENV_FILE)
106
106
 
107
107
  @property
108
108
  def workflow_exists(self):
@@ -1,11 +1,15 @@
1
+ import os
2
+
3
+ from dotenv import dotenv_values
4
+
1
5
  from .config import Config
2
- from .constants import ENV_FILE
6
+ from .constants import DOTENV_FILE
3
7
  from .env import Env
4
8
 
5
9
  class WorkflowEnv(Config):
6
10
 
7
11
  def __init__(self, dir: str):
8
- super().__init__(dir, ENV_FILE)
12
+ super().__init__(dir, DOTENV_FILE)
9
13
 
10
14
  self.__env_vars = {}
11
15
 
@@ -15,6 +19,9 @@ class WorkflowEnv(Config):
15
19
  def load(self):
16
20
  self.__env_vars = self.read()
17
21
 
18
- def write(self, env_vars: dict):
22
+ def write(self, env_vars: dict, dotenv_path: str = None):
23
+ if dotenv_path and os.path.exists(dotenv_path):
24
+ env_vars = { **env_vars, **dotenv_values(dotenv_path) }
25
+
19
26
  Env(self.path).write(env_vars)
20
27
  self.__env_vars = env_vars
@@ -0,0 +1,41 @@
1
+ import os
2
+
3
+
4
+ from .app import App
5
+ from .constants import DOTENV_FILE, NAMESERVERS_FILE
6
+
7
+ class WorkflowNamespace():
8
+
9
+ def __init__(self, app: App, namespace: str = None):
10
+ self._app = app
11
+ self._namespace = namespace
12
+ self._path = os.path.join(app.data_dir.tmp_dir_path, namespace or '')
13
+
14
+ @property
15
+ def dotenv_path(self):
16
+ return os.path.join(self.path, DOTENV_FILE)
17
+
18
+ @property
19
+ def nameservers_path(self):
20
+ return os.path.join(self.path, NAMESERVERS_FILE)
21
+
22
+ @property
23
+ def namespace(self):
24
+ return self._namespace
25
+
26
+ @property
27
+ def path(self):
28
+ return self._path
29
+
30
+ @property
31
+ def run_script_path(self):
32
+ return os.path.join(self.path, 'run.sh')
33
+
34
+ @property
35
+ def traefik_config_path(self):
36
+ return os.path.join(self.path, 'traefik.yml')
37
+
38
+ def traefik_config_relative_path(self, path: str):
39
+ if not path:
40
+ return path
41
+ return self.traefik_config_path.replace(path if path[len(path) - 1] == '/' else path + '/', '', 1)
@@ -3,42 +3,25 @@ import os
3
3
  import pdb
4
4
  import subprocess
5
5
  import re
6
- import yaml
7
6
 
8
- from typing import TypedDict
9
7
 
10
8
  from stoobly_agent.config.data_dir import DataDir
11
9
  from stoobly_agent.lib.logger import Logger
12
10
 
13
11
  from .app import App
14
12
  from .constants import (
15
- APP_DIR_ENV, APP_NETWORK_ENV, CA_CERTS_DIR_ENV, CERTS_DIR_ENV, CONTEXT_DIR_ENV, NAMESERVERS_FILE,
13
+ APP_DIR_ENV, APP_NETWORK_ENV, CA_CERTS_DIR_ENV, CERTS_DIR_ENV, CONTEXT_DIR_ENV,
16
14
  SERVICE_DNS_ENV, SERVICE_NAME_ENV, SERVICE_SCRIPTS_DIR, SERVICE_SCRIPTS_ENV, USER_ID_ENV,
17
15
  WORKFLOW_NAME_ENV, WORKFLOW_NAMESPACE_ENV, WORKFLOW_SCRIPTS_DIR, WORKFLOW_SCRIPTS_ENV, WORKFLOW_TEMPLATE_ENV
18
16
  )
19
17
  from .docker.constants import APP_EGRESS_NETWORK_TEMPLATE, APP_INGRESS_NETWORK_TEMPLATE, DOCKERFILE_CONTEXT
20
18
  from .workflow_command import WorkflowCommand
21
19
  from .workflow_env import WorkflowEnv
20
+ from .workflow_namesapce import WorkflowNamespace
21
+ from ..types.workflow_run_command import BuildOptions, ComposeOptions, DownOptions, UpOptions
22
22
 
23
23
  LOG_ID = 'WorkflowRunCommand'
24
24
 
25
- class ComposeOptions(TypedDict):
26
- namespace: str
27
- user_id: str
28
-
29
- class BuildOptions(ComposeOptions):
30
- user_id: str
31
- verbose: bool
32
-
33
- class DownOptions(ComposeOptions):
34
- extra_compose_path: str
35
- rmi: bool
36
-
37
- class UpOptions(ComposeOptions):
38
- attached: bool
39
- extra_compose_path: str
40
- pull: bool
41
-
42
25
  class WorkflowRunCommand(WorkflowCommand):
43
26
  def __init__(self, app: App, **kwargs):
44
27
  super().__init__(app, **kwargs)
@@ -48,7 +31,8 @@ class WorkflowRunCommand(WorkflowCommand):
48
31
  self.__ca_certs_dir_path = kwargs.get('ca_certs_dir_path') or app.ca_certs_dir_path
49
32
  self.__certs_dir_path = kwargs.get('certs_dir_path') or app.certs_dir_path
50
33
  self.__context_dir_path = kwargs.get('context_dir_path') or app.context_dir_path
51
- self.__network = f"{kwargs.get('network') or {self.workflow_name}}.{self.app_config.network}"
34
+ self.__namespace = kwargs.get('namespace') or self.workflow_name
35
+ self.__network = f"{self.__namespace}.{kwargs.get('network') or app.network}"
52
36
 
53
37
  @property
54
38
  def app_dir_path(self):
@@ -78,6 +62,10 @@ class WorkflowRunCommand(WorkflowCommand):
78
62
  def current_working_dir(self, v):
79
63
  self.__current_working_dir = v
80
64
 
65
+ @property
66
+ def dotenv_path(self):
67
+ return WorkflowNamespace(self.app, self.namespace).dotenv_path
68
+
81
69
  @property
82
70
  def nameservers(self):
83
71
  path = self.nameservers_path
@@ -90,7 +78,11 @@ class WorkflowRunCommand(WorkflowCommand):
90
78
 
91
79
  @property
92
80
  def nameservers_path(self):
93
- return os.path.join(self.app.data_dir.tmp_dir_path, NAMESERVERS_FILE)
81
+ return WorkflowNamespace(self.app, self.namespace).nameservers_path
82
+
83
+ @property
84
+ def namespace(self):
85
+ return self.__namespace
94
86
 
95
87
  @property
96
88
  def network(self):
@@ -290,7 +282,7 @@ class WorkflowRunCommand(WorkflowCommand):
290
282
  _config[SERVICE_DNS_ENV] = '8.8.8.8'
291
283
 
292
284
  env_vars = self.config(_config)
293
- WorkflowEnv(self.workflow_path).write(env_vars)
285
+ WorkflowEnv(self.workflow_path).write(env_vars, self.dotenv_path)
294
286
  return env_vars
295
287
 
296
288
  def __find_nameservers(self, dns_resolver: dns.resolver.Resolver):
@@ -30,6 +30,7 @@ from stoobly_agent.app.cli.scaffold.workflow import Workflow
30
30
  from stoobly_agent.app.cli.scaffold.workflow_create_command import WorkflowCreateCommand
31
31
  from stoobly_agent.app.cli.scaffold.workflow_copy_command import WorkflowCopyCommand
32
32
  from stoobly_agent.app.cli.scaffold.workflow_log_command import WorkflowLogCommand
33
+ from stoobly_agent.app.cli.scaffold.workflow_namesapce import WorkflowNamespace
33
34
  from stoobly_agent.app.cli.scaffold.workflow_run_command import WorkflowRunCommand
34
35
  from stoobly_agent.app.cli.scaffold.workflow_validate_command import WorkflowValidateCommand
35
36
  from stoobly_agent.config.constants import env_vars
@@ -88,7 +89,7 @@ def hostname(ctx):
88
89
  help="Scaffold application"
89
90
  )
90
91
  @click.option('--app-dir-path', default=current_working_dir, help='Path to create the app scaffold.')
91
- @click.option('--network', callback=validate_network, help='App default network name. Defaults to app name.')
92
+ @click.option('--docker-socket-path', default='/var/run/docker.sock', help='Path to Docker socket.')
92
93
  @click.option('--quiet', is_flag=True, help='Disable log output.')
93
94
  @click.option('--ui-port', default=4200, type=click.IntRange(1, 65535), help='UI service port.')
94
95
  @click.argument('app_name', callback=validate_app_name)
@@ -100,9 +101,6 @@ def create(**kwargs):
100
101
  if not kwargs['quiet'] and os.path.exists(app.scaffold_namespace_path):
101
102
  print(f"{kwargs['app_dir_path']} already exists, updating scaffold maintained files...")
102
103
 
103
- if not kwargs['network']:
104
- kwargs['network'] = kwargs['app_name']
105
-
106
104
  AppCreateCommand(app, **kwargs).build()
107
105
 
108
106
  @app.command(
@@ -344,7 +342,10 @@ def copy(**kwargs):
344
342
  def down(**kwargs):
345
343
  os.environ[env_vars.LOG_LEVEL] = kwargs['log_level']
346
344
 
347
- app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE, **kwargs)
345
+ containerized = kwargs['containerized']
346
+
347
+ app_dir_path = current_working_dir if containerized else kwargs['app_dir_path']
348
+ app = App(app_dir_path, DOCKER_NAMESPACE, **kwargs)
348
349
  __validate_app(app)
349
350
 
350
351
  __with_namespace_defaults(kwargs)
@@ -361,7 +362,7 @@ def down(**kwargs):
361
362
  command.current_working_dir = current_working_dir
362
363
  commands.append(command)
363
364
 
364
- script = __build_script(**kwargs)
365
+ script = __build_script(app, **kwargs)
365
366
 
366
367
  commands = sorted(commands, key=lambda command: command.service_config.priority)
367
368
  for index, command in enumerate(commands):
@@ -450,7 +451,7 @@ def logs(**kwargs):
450
451
  command = WorkflowLogCommand(app, **config)
451
452
  commands.append(command)
452
453
 
453
- script = __build_script(**kwargs)
454
+ script = __build_script(app, **kwargs)
454
455
 
455
456
  commands = sorted(commands, key=lambda command: command.service_config.priority)
456
457
  for index, command in enumerate(commands):
@@ -514,7 +515,9 @@ def up(**kwargs):
514
515
  # Gateway ports are dynamically set depending on the workflow run
515
516
  workflow = Workflow(kwargs['workflow_name'], app)
516
517
  configure_gateway(
517
- kwargs['namespace'] or workflow.workflow_name, workflow.service_paths_from_services(services), kwargs['no_publish']
518
+ WorkflowNamespace(app, kwargs['namespace'] or workflow.workflow_name),
519
+ workflow.service_paths_from_services(services),
520
+ kwargs['no_publish']
518
521
  )
519
522
 
520
523
  commands: List[WorkflowRunCommand] = []
@@ -525,7 +528,7 @@ def up(**kwargs):
525
528
  command.current_working_dir = current_working_dir
526
529
  commands.append(command)
527
530
 
528
- script = __build_script(**kwargs)
531
+ script = __build_script(app, **kwargs)
529
532
 
530
533
  # Before services can be started, their image and network needs to be created
531
534
  if len(commands) > 0:
@@ -678,11 +681,11 @@ scaffold.add_command(service)
678
681
  scaffold.add_command(workflow)
679
682
  scaffold.add_command(hostname)
680
683
 
681
- def __build_script(**kwargs):
684
+ def __build_script(app: App, **kwargs):
682
685
  script_path = kwargs['script_path']
683
686
  if not script_path:
684
- script_file_name = 'run.sh'
685
- script_path = os.path.join(data_dir.tmp_dir_path, kwargs.get('namespace') or kwargs['workflow_name'] or '', script_file_name)
687
+ workflow_namespace = WorkflowNamespace(app, kwargs.get('namespace') or kwargs['workflow_name'])
688
+ script_path = workflow_namespace.run_script_path
686
689
 
687
690
  script_dir = os.path.dirname(script_path)
688
691
  if not os.path.exists(script_dir):
@@ -827,10 +830,6 @@ def __with_namespace_defaults(kwargs):
827
830
  if not kwargs.get('namespace'):
828
831
  kwargs['namespace'] = kwargs.get('workflow_name')
829
832
 
830
- # If network there was a network option, but it is not set, default network to namespace
831
- if 'network' in kwargs and not kwargs['network']:
832
- kwargs['network'] = kwargs['namespace']
833
-
834
833
  def __workflow_create(app, **kwargs):
835
834
  command = WorkflowCreateCommand(app, **kwargs)
836
835
 
@@ -0,0 +1,18 @@
1
+ from typing import TypedDict
2
+
3
+ class ComposeOptions(TypedDict):
4
+ namespace: str
5
+ user_id: str
6
+
7
+ class BuildOptions(ComposeOptions):
8
+ user_id: str
9
+ verbose: bool
10
+
11
+ class DownOptions(ComposeOptions):
12
+ extra_compose_path: str
13
+ rmi: bool
14
+
15
+ class UpOptions(ComposeOptions):
16
+ attached: bool
17
+ extra_compose_path: str
18
+ pull: bool
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.9.9
3
+ Version: 1.9.11
4
4
  Summary: Record, mock, and test HTTP(s) requests. CLI agent for Stoobly
5
5
  License: Apache-2.0
6
6
  Author: Matt Le
@@ -1,4 +1,4 @@
1
- stoobly_agent/__init__.py,sha256=ynj3t69d_GKqdl_NzWnMm4vXo8bYFLqoXtgFzDp3BXk,44
1
+ stoobly_agent/__init__.py,sha256=T0T5meojgC4kb3-HURdzQoFWyRESweACkhTLNw5Rsnk,45
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
@@ -52,7 +52,7 @@ stoobly_agent/app/cli/helpers/request_synchronize_handler.py,sha256=wawAL8hoZLqO
52
52
  stoobly_agent/app/cli/helpers/run_command_service.py,sha256=w9CNDZDj_gxCCXAFFOLONuOVu6_W9f8z1RX3-5RKuTM,731
53
53
  stoobly_agent/app/cli/helpers/scenario_facade.py,sha256=nWcycEZBL87OFCCQx85-5QaK0Q9XXk2-RMeC1uef2_Y,3134
54
54
  stoobly_agent/app/cli/helpers/schema_builder.py,sha256=-R_oU_d8nPNdNA31WDp8lCh7XpCeazLm_1dl_Kq8DLU,1127
55
- stoobly_agent/app/cli/helpers/shell.py,sha256=iBzZEgmB7fBsKxF1rm7i_pjCPOiE5LcMD-W1CsX4Yhg,645
55
+ stoobly_agent/app/cli/helpers/shell.py,sha256=pnztxQjm8kdeVZH40PlTSuiGB_yaSP8PXRS15MoUxtE,838
56
56
  stoobly_agent/app/cli/helpers/synchronize_request_service.py,sha256=pwsILyrR6XPBJAIVaato0tRrbCT4z5-FymJgfeWTsVw,6018
57
57
  stoobly_agent/app/cli/helpers/tabulate_print_service.py,sha256=d4xtJgn9sueL8nAwOSIyiyzuY1ptsD1wxEdLQe0X2tc,964
58
58
  stoobly_agent/app/cli/helpers/test_facade.py,sha256=gRnbjYNxnzPmtvFp2J6TZgxaMSzDjpAWdb79kaFBt_I,2227
@@ -61,19 +61,19 @@ stoobly_agent/app/cli/helpers/trace_aliases.py,sha256=8N8pnsnONwVv-fabCTvDlXec-W
61
61
  stoobly_agent/app/cli/helpers/trace_context_facade.py,sha256=3MDjY_bdhvE2dad_B_w9gemCZZoiVjotbE8o9hrmVYo,1027
62
62
  stoobly_agent/app/cli/helpers/validations.py,sha256=nvcrEHvjMOAyHlJK0bQIwyzBUciJ0qNkNESa2zZ5ZFo,6232
63
63
  stoobly_agent/app/cli/helpers/verify_raw_request_service.py,sha256=tmLeRBYhNgAQeJD-rF6Nj22F_TfVktVSb1wjRPFblBQ,658
64
- stoobly_agent/app/cli/intercept_cli.py,sha256=UswnJJiBV7FKWaxIpiOYrwPSfMTPeg8UO_h_3gUxdD4,5106
64
+ stoobly_agent/app/cli/intercept_cli.py,sha256=LNHfAec6Tf_cFNwuNvcvig-k9lKi7kVsMGIDC0fWp2o,5116
65
65
  stoobly_agent/app/cli/main_group.py,sha256=3UzBxin2f2p5KNqo6Oayo_I1VI2pHpqOoRexUnJ74a4,2187
66
66
  stoobly_agent/app/cli/project_cli.py,sha256=EXjeLjbnq9PhfCjvyfZ0UnJ2tejeCS0SIAo3Nc4fKOc,3852
67
67
  stoobly_agent/app/cli/report_cli.py,sha256=ZxJw0Xkx7KFZJn9e45BSKRKon8AD0Msrwy1fbPfbv0c,2543
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
- stoobly_agent/app/cli/scaffold/app.py,sha256=bgNc_dWZtgkuDAkS9aHSCMxCrjX907Phlfb2bOasswI,3435
71
- stoobly_agent/app/cli/scaffold/app_command.py,sha256=sliaYulMNmaxbRXpJIDtBDWEBGEv5Tht4rpErzC_xxw,2368
72
- stoobly_agent/app/cli/scaffold/app_config.py,sha256=UGVJ7DVmXh-o_gYBlAAEjngNIUZPQUiXXk2oMStcsPg,1075
73
- stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=0ogYliGbq1PYP5rFs-ML33q_Z4t_rAgPWjhk7rhnGw0,1153
74
- stoobly_agent/app/cli/scaffold/command.py,sha256=aoTsdkkBzyu7TkVSMdNQQGk0Gj874jNgFcjR14y3TuM,254
70
+ stoobly_agent/app/cli/scaffold/app.py,sha256=0HJm8cdyIBAdOBr18499MkZGhmEFu6I7GSZXR7pKxkw,3650
71
+ stoobly_agent/app/cli/scaffold/app_command.py,sha256=w15VCsyefIE9HfzpIRMrv2BEep46ZSPgvsjZmFOMPZs,2377
72
+ stoobly_agent/app/cli/scaffold/app_config.py,sha256=z4sxZcXZTEoXyUZajUuffuWQN8x8eovu-TBtgoTMXEE,1182
73
+ stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=HOlXL6Ugid2qHagqDVGl3ksjLKE4WF_3Dji8FoQlpuM,1215
74
+ stoobly_agent/app/cli/scaffold/command.py,sha256=G4Zp647cuviaEXUdcl7Rbx_qQAr0Z_DS7-Y3MWDC1Qc,281
75
75
  stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
76
- stoobly_agent/app/cli/scaffold/constants.py,sha256=e0aKyB80i1heJCubAvxt8DlzykAvYH37xeAcl9UTTgI,2496
76
+ stoobly_agent/app/cli/scaffold/constants.py,sha256=VuCpzeGxlFEQuX6WEK5D_4ih8-S-iotwOny458K85_c,2612
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
@@ -81,8 +81,8 @@ stoobly_agent/app/cli/scaffold/docker/builder.py,sha256=uiGqhxBHEasZAqLzjKUGUs-1
81
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=4cIMSYvgrkGWVuuYymiwlrR829O91qQl9ML8FhaDMj4,5857
85
- stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=8GQ2wUBwb45uSxhzkEMloezJT1hVu8v_3PudWLTU9ig,3910
84
+ stoobly_agent/app/cli/scaffold/docker/service/builder.py,sha256=u3_YNuxX8TT4TvhzTqe5b2Zvi9fF7TLWJFepkBSXwhk,5857
85
+ stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py,sha256=jbMaa08R2EoZ2esoC4uREfPoBK9b5vyPRuTNOT0QDjE,3949
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
@@ -91,21 +91,21 @@ stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py,sha256=bjQ8
91
91
  stoobly_agent/app/cli/scaffold/docker/workflow/dns_decorator.py,sha256=nlDPbyF1hkVItzFH3bk9KlqfDC8usyFZs353-ibqxvA,938
92
92
  stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=DcBnwA8YhE-VdrUiWf2xPcqirEMZEQm3AwssAg9CxLo,1226
93
93
  stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=zD4FEtBMiPEtvEb798LOfFH8sJhTWQYpA9THLq5UMbg,1227
94
- stoobly_agent/app/cli/scaffold/env.py,sha256=e-Ve4p3RUgzFx22B3SIYttvJ_yLuDtA27oDACZ8n-6E,1140
94
+ stoobly_agent/app/cli/scaffold/env.py,sha256=dT33tHoQaUxfsFCYm8kfaAv-qPVrUPmNFQmLnFQhZeQ,1107
95
95
  stoobly_agent/app/cli/scaffold/hosts_file_manager.py,sha256=zNX5wh6zXQ4J2BA0YYdD7_CPqDz02b_ghXsY3oTjjB4,4999
96
96
  stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py,sha256=-wLBXUi7DCWsfm5KzZzd_kdJKOTl1NT924XR7dyjbSY,574
97
97
  stoobly_agent/app/cli/scaffold/service.py,sha256=74JwjTRRkk6lo-k9hre1iGztbKa9zDqjPVx3Qgpze-s,699
98
- stoobly_agent/app/cli/scaffold/service_command.py,sha256=NxJakoq1Dy79LEIJ8QSsKEwsofIfN13GN0UGpp9i6qY,1230
99
- stoobly_agent/app/cli/scaffold/service_config.py,sha256=edL356wqpfJgFdeSrWof-CAUB1Tgi4nO1Jx9nkql9Qc,3903
100
- stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=1B6TK3JDAjouikCV84WDrX7b0crdPMPIo1caMwhi-L8,2815
98
+ stoobly_agent/app/cli/scaffold/service_command.py,sha256=n5tVp8jIypnNO9uxtaMt33lX5ho0xhV6A53HDN2Yet4,1239
99
+ stoobly_agent/app/cli/scaffold/service_config.py,sha256=WCHy1bZ8-nlVwCWdOWKXrdIVTtjye8XStA1bqvbRgZ0,3959
100
+ stoobly_agent/app/cli/scaffold/service_create_command.py,sha256=nCONco0ducMcX4rsdFe3A-iRiySyUnu-T6bTb312XP0,2824
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_update_command.py,sha256=oWusBKfvjt4RnK03_V3CJYWrfsCI4_LcR7W12eLXMR4,2579
104
104
  stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOWkGEKz7gSgEGNI8f7aXOdg,444
105
- stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=veigidzR4EwGi8dc0v_l4Ik7cZikDBnLcvwcHNc1Wzg,11457
105
+ stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=-hdg7RLsoEQXCI9rebIXyO3d8JbpyTxGnhpjaPQfmFk,11514
106
106
  stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=x8C_a0VoO_vUbosp4_6IC1U7Ge9NnUdVKDPpVMtMkeY,171
107
107
  stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=Okk4Q0Fj7Wi5NU58gQfpjpFwAL3RUBJyRe56kteQfcA,158
108
- stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=VGtO-dz0tXHfUN9MMkc3Lqfqg6Vhdb_aiz7cxiot3DE,8950
108
+ stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=uV-xqit3fz3tfcU6sbBOxK0Zon11v-fydfuYLSxS7jQ,9164
109
109
  stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml,sha256=6tFqXh3ine8vaD0FCL5TMoY5NjKx2wLUR8XpW3tJtew,245
110
110
  stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.networks.yml,sha256=I4PbJpQjFHb5IbAUWNvYM6okDEtmwtKFDQg-yog05WM,141
111
111
  stoobly_agent/app/cli/scaffold/templates/app/Makefile,sha256=TEmPG7Bf0KZOnmfsgdzza3UdwcVMmM5Lj1YdLc4cgjA,79
@@ -138,7 +138,7 @@ stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure,sha25
138
138
  stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/init,sha256=YxWVVQMEdGarcMtBcE1Sj2kdLgUgwY9kXp3MjPsVcmg,46
139
139
  stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/docker-compose.yml,sha256=JpWLQrW69EatLD3HPHpmi3Y6n7cjlrUgekYVbJ4ngSY,523
140
140
  stoobly_agent/app/cli/scaffold/templates/app/gateway/.config.yml,sha256=XnLQZMzzMMIwVycjyPN5QXsmRztkTFAna1kIHYuDfJQ,19
141
- stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=0A08JbYpa7LGv9SphRwCgkvy5y4_T74LoWiV-NyCmyA,241
141
+ stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml,sha256=QipWNy2mEbJuceiNfRbv6L3ARk1lMkD1gE4l_Z0PrPU,246
142
142
  stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml,sha256=CDL5x18-ues4F_ujqpNef_zJTG6PyDOkQ11cIHBOW5k,136
143
143
  stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml,sha256=eyLH2h33Peunus8M1sUKL9AALCG2ABhV_heiJKhvgwo,138
144
144
  stoobly_agent/app/cli/scaffold/templates/app/gateway/test/.docker-compose.test.yml,sha256=oJO6i0lsuQaQeIH80yoPZo3Vs0LzUAH2WRl853yLq6g,136
@@ -196,15 +196,16 @@ stoobly_agent/app/cli/scaffold/templates/workflow/test/public/.gitignore,sha256=
196
196
  stoobly_agent/app/cli/scaffold/validate_command.py,sha256=BEDcF5qPDbMjWe-SCAr5jxcrVMZlV3ciLa89TDDENmM,3787
197
197
  stoobly_agent/app/cli/scaffold/validate_exceptions.py,sha256=Jtjl4OkbbSRWm0hy7Kf_50zcFh2J324HhNcnwJKH_Oc,54
198
198
  stoobly_agent/app/cli/scaffold/workflow.py,sha256=KlbWT9CIo9EpZxKU1WVZtmodhxK7CpmLUHPNk4Mh6DA,1570
199
- stoobly_agent/app/cli/scaffold/workflow_command.py,sha256=eI9I5LLgO0U3b46QhHusy-4BV2zUDVai6jErcluYCRI,3344
199
+ stoobly_agent/app/cli/scaffold/workflow_command.py,sha256=sGe5uVr34P6IZ0qfCTgM8sQ7LkvdvymM2LmBzXpw1ZY,3353
200
200
  stoobly_agent/app/cli/scaffold/workflow_config.py,sha256=ghnbcnCyb6ECdylUJCAJ6A8ulzaFY9bu7RvRuYeiRkk,901
201
201
  stoobly_agent/app/cli/scaffold/workflow_copy_command.py,sha256=wi8qHH_M2e6jXIPuumx65Zd4Zt7hTBb6b3Z4vt4xYeQ,1320
202
202
  stoobly_agent/app/cli/scaffold/workflow_create_command.py,sha256=-fwsr6_LvGT8BbBWdGY3Qd8cSQhBOSJiMr1r8s2R86w,3390
203
- stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=x8V5pJmIiklD3f2q2-qq-CORf4YaXYq_r2JpR2MmSwk,416
203
+ stoobly_agent/app/cli/scaffold/workflow_env.py,sha256=shPjoX1SWe7K6pGpZvw2fPVHWd6j_azTe58jvOjGUns,607
204
204
  stoobly_agent/app/cli/scaffold/workflow_log_command.py,sha256=Bke4lMOMxuDUFuAx9nlXHbKgYMO4KAg9ASHvjz4aVWc,1372
205
- stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=AZhLd1N260RjXEiUSRppqfhQMwVyRnn0jpapRu4FwyM,11114
205
+ stoobly_agent/app/cli/scaffold/workflow_namesapce.py,sha256=DXPCjfY6LAJDHy1ZlKVhVgp2aX97TmQK78lmgzBRN20,968
206
+ stoobly_agent/app/cli/scaffold/workflow_run_command.py,sha256=H9s0F8LaoB7ZLUVXWP6M6yPLYk5IE4JD8qgGXntwtMc,11138
206
207
  stoobly_agent/app/cli/scaffold/workflow_validate_command.py,sha256=Uo_yo6rVR1ZR7xpvsQvlH48AyMBVLRupd4G-bRjzm_Q,5584
207
- stoobly_agent/app/cli/scaffold_cli.py,sha256=PmFDxe0pACL7hdyf7bPlol3xxGkOS4VES92HTAnga6Y,32622
208
+ stoobly_agent/app/cli/scaffold_cli.py,sha256=v4b8jCopSbCUv8rpPqqeC-NeziqD8mWbiF3nOZWQ77Y,32598
208
209
  stoobly_agent/app/cli/scenario_cli.py,sha256=3J1EiJOvunkfWrEkOsanw-XrKkOk78ij_GjBlE9p7CE,8229
209
210
  stoobly_agent/app/cli/snapshot_cli.py,sha256=1Dw5JgDlmG6vctrawIRO7CdB73vAQk_wRBnPG2lVOrQ,11929
210
211
  stoobly_agent/app/cli/trace_cli.py,sha256=K7E-vx3JUcqEDSWOdIOi_AieKNQz7dBfmRrVvKDkzFI,4605
@@ -215,6 +216,7 @@ stoobly_agent/app/cli/types/request.py,sha256=QthojE5sfx7OvKu-vVNnSUfGk8n4pLzuBQ
215
216
  stoobly_agent/app/cli/types/scenario.py,sha256=28WxmOlbm2Bsek1uu7yc4hJGz-d5oHbYAro7LlFWRoc,81
216
217
  stoobly_agent/app/cli/types/snapshot_migration.py,sha256=4_Re46FKjsflcTOO3qhNsbWWmdEU67SFsF-XE_FKG3M,1859
217
218
  stoobly_agent/app/cli/types/test.py,sha256=1c458B7DFBWsEk5Q1CrZ2CUi84YzEzcs-W4qTcudwAk,714
219
+ stoobly_agent/app/cli/types/workflow_run_command.py,sha256=SQ5PGpoqIEQ7w9xeSQE1FBqelnVfsdlRXXaODDW4yPY,326
218
220
  stoobly_agent/app/cli/validators/scaffold.py,sha256=Y2XQrN2RFMcBh228q6inTwZGoN0K5FmXO8JfrgKVwJA,1669
219
221
  stoobly_agent/app/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
222
  stoobly_agent/app/models/adapters/__init__.py,sha256=cEEE--Bvrvk6DAsHx_uPgFhLnZJETP4zSBtWjMqyIKc,233
@@ -751,8 +753,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
751
753
  stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
752
754
  stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
753
755
  stoobly_agent/test/test_helper.py,sha256=m_oAI7tmRYCNZdKfNqISWhMv3e44tjeYViQ3nTUfnos,1007
754
- stoobly_agent-1.9.9.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
755
- stoobly_agent-1.9.9.dist-info/METADATA,sha256=P2fxdK2aPocPzJHjKZKqyFF4xz9zhyeERR-EylS6FLA,3087
756
- stoobly_agent-1.9.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
757
- stoobly_agent-1.9.9.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
758
- stoobly_agent-1.9.9.dist-info/RECORD,,
756
+ stoobly_agent-1.9.11.dist-info/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
757
+ stoobly_agent-1.9.11.dist-info/METADATA,sha256=BhaA2CQUDiNOSEBokPAeKi22VSZyNFl6A8Aqx5oPGUg,3088
758
+ stoobly_agent-1.9.11.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
759
+ stoobly_agent-1.9.11.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
760
+ stoobly_agent-1.9.11.dist-info/RECORD,,