stoobly-agent 1.7.2__py3-none-any.whl → 1.8.1__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 (32) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/intercept_cli.py +2 -0
  3. stoobly_agent/app/cli/scaffold/constants.py +0 -3
  4. stoobly_agent/app/cli/scaffold/docker/constants.py +0 -1
  5. stoobly_agent/app/cli/scaffold/docker/service/builder.py +10 -4
  6. stoobly_agent/app/cli/scaffold/docker/service/configure_gateway.py +50 -23
  7. stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py +2 -2
  8. stoobly_agent/app/cli/scaffold/service_config.py +10 -0
  9. stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +0 -29
  10. stoobly_agent/app/cli/scaffold/templates/__init__.py +2 -2
  11. stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context +1 -1
  12. stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.template.yml +5 -5
  13. stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.configure +2 -1
  14. stoobly_agent/app/cli/scaffold/templates/build/services/build/mock/.init +2 -0
  15. stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.configure +2 -1
  16. stoobly_agent/app/cli/scaffold/templates/build/services/build/record/.init +2 -0
  17. stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.configure +2 -1
  18. stoobly_agent/app/cli/scaffold/templates/build/services/build/test/.init +2 -0
  19. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/mock/.configure +0 -6
  20. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/record/.configure +0 -6
  21. stoobly_agent/app/cli/scaffold/templates/build/services/entrypoint/test/.configure +0 -6
  22. stoobly_agent/app/cli/scaffold/templates/constants.py +5 -5
  23. stoobly_agent/app/cli/scaffold/templates/factory.py +5 -7
  24. stoobly_agent/app/cli/scaffold_cli.py +11 -0
  25. stoobly_agent/app/settings/__init__.py +8 -4
  26. stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
  27. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.1.dist-info}/METADATA +1 -1
  28. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.1.dist-info}/RECORD +31 -32
  29. stoobly_agent/app/cli/scaffold/templates/run/nginx.tmpl +0 -1060
  30. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.1.dist-info}/LICENSE +0 -0
  31. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.1.dist-info}/WHEEL +0 -0
  32. {stoobly_agent-1.7.2.dist-info → stoobly_agent-1.8.1.dist-info}/entry_points.txt +0 -0
stoobly_agent/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '1.7.2'
2
+ VERSION = '1.8.1'
@@ -41,6 +41,8 @@ def intercept(ctx):
41
41
  help="Enable intercept"
42
42
  )
43
43
  def enable(**kwargs):
44
+ settings = Settings.instance()
45
+
44
46
  settings.proxy.intercept.active = True
45
47
 
46
48
  handle_intercept_active_update(settings)
@@ -40,9 +40,6 @@ STOOBLY_HOME_DIR = '/home/stoobly'
40
40
  STOOBLY_DATA_DIR = os.path.join(STOOBLY_HOME_DIR, DATA_DIR_NAME)
41
41
  STOOBLY_CERTS_DIR = os.path.join(STOOBLY_DATA_DIR, CERTS_DIR_NAME)
42
42
  USER_ID_ENV = 'USER_ID'
43
- VIRTUAL_HOST_ENV = 'VIRTUAL_HOST'
44
- VIRTUAL_PORT_ENV = 'VIRTUAL_PORT'
45
- VIRTUAL_PROTO_ENV = 'VIRTUAL_PROTO'
46
43
  WORKFLOW_CONTAINER_CONFIGURE = 'configure'
47
44
  WORKFLOW_CONTAINER_INIT = 'init'
48
45
  WORKFLOW_CONTAINER_PROXY = 'proxy'
@@ -10,7 +10,6 @@ DOCKER_COMPOSE_CUSTOM = 'docker-compose.yml'
10
10
  DOCKER_COMPOSE_NETWORKS = '.docker-compose.networks.yml'
11
11
  DOCKERFILE_CONTEXT = '.Dockerfile.context'
12
12
  DOCKERFILE_SERVICE = 'Dockerfile.source'
13
- GATEWAY_NGINX_TEMPLATE = 'nginx.tmpl'
14
13
 
15
14
  # TODO: add scaffold container name templates here
16
15
 
@@ -91,22 +91,28 @@ class ServiceBuilder(Builder):
91
91
  if not self.config.hostname:
92
92
  return
93
93
 
94
+ service_id = self.config.id
94
95
  environment = { **self.env_dict() }
96
+ labels = [
97
+ 'traefik.enable=true',
98
+ f"traefik.http.routers.{service_id}.rule=Host(`{SERVICE_HOSTNAME}`)",
99
+ f"traefik.http.services.{service_id}.loadbalancer.server.port={SERVICE_PORT}"
100
+ ]
95
101
  volumes = []
96
102
 
97
- environment['VIRTUAL_HOST'] = SERVICE_HOSTNAME
98
- environment['VIRTUAL_PORT'] = SERVICE_PORT
99
- environment['VIRTUAL_PROTO'] = SERVICE_SCHEME
100
-
101
103
  if self.config.detached:
102
104
  self.__with_detached_volumes(volumes)
103
105
 
106
+ if self.config.tls:
107
+ labels.append(f"traefik.http.routers.{service_id}.tls=true")
108
+
104
109
  base = {
105
110
  'environment': environment,
106
111
  'extends': {
107
112
  'file': os.path.relpath(self.app_builder.compose_file_path, self.dir_path),
108
113
  'service': self.extends_service
109
114
  },
115
+ 'labels': labels,
110
116
  'working_dir': self.__working_dir,
111
117
  }
112
118
 
@@ -1,6 +1,5 @@
1
1
  import os
2
2
  import pdb
3
- import shutil
4
3
  import yaml
5
4
 
6
5
  from typing import List
@@ -8,9 +7,8 @@ from typing import List
8
7
  from stoobly_agent.config.data_dir import DATA_DIR_NAME, TMP_DIR_NAME
9
8
  from stoobly_agent.app.cli.scaffold.constants import APP_DIR
10
9
  from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
11
- from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE, GATEWAY_NGINX_TEMPLATE
10
+ from stoobly_agent.app.cli.scaffold.docker.constants import APP_INGRESS_NETWORK_NAME, APP_EGRESS_NETWORK_NAME, DOCKER_COMPOSE_BASE, DOCKER_COMPOSE_BASE_TEMPLATE
12
11
  from stoobly_agent.app.cli.scaffold.templates.constants import CORE_GATEWAY_SERVICE_NAME
13
- from stoobly_agent.app.cli.scaffold.templates import run_template_path
14
12
 
15
13
  def configure_gateway(service_paths: List[str], no_publish = False):
16
14
  if len(service_paths) == 0:
@@ -38,7 +36,7 @@ def configure_gateway(service_paths: List[str], no_publish = False):
38
36
  gateway_base['ports'] = ports
39
37
 
40
38
  app_dir_path = os.path.dirname(os.path.dirname(service_dir_path))
41
- __with_no_publish(gateway_base, app_dir_path)
39
+ __with_traefik_config(service_paths, gateway_base, app_dir_path)
42
40
  __with_networks(gateway_base, hostnames)
43
41
 
44
42
  with open(docker_compose_dest_path, 'w') as fp:
@@ -52,31 +50,60 @@ def __with_networks(config: dict, hostnames: List[str]):
52
50
  'aliases': hostnames
53
51
  }
54
52
 
55
- def __with_no_publish(config: dict, app_dir_path: str):
56
- if not config['volumes']:
57
- config['volumes'] = []
53
+ def __with_traefik_config(service_paths: str, compose: dict, app_dir_path: str):
54
+ if not compose['volumes']:
55
+ compose['volumes'] = []
56
+
57
+ entry_points = {}
58
+ certificates = []
59
+ traefik_config = {
60
+ 'accessLog': {
61
+ 'format': 'common',
62
+ },
63
+ 'entryPoints': entry_points,
64
+ 'log': {
65
+ 'format': 'common',
66
+ 'level': 'INFO',
67
+ },
68
+ 'providers': {
69
+ 'docker': {
70
+ 'exposedByDefault': False
71
+ }
72
+ },
73
+ 'tls': {
74
+ 'certificates': certificates
75
+ }
76
+ }
58
77
 
59
- # Copy nginx.tmpl to .stoobly/tmp
60
- nginx_template_src_path = os.path.join(run_template_path(), GATEWAY_NGINX_TEMPLATE)
61
- nginx_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, GATEWAY_NGINX_TEMPLATE)
62
- nginx_template_dest_path = os.path.join(app_dir_path, nginx_template_relative_path)
78
+ for path in service_paths:
79
+ config = ServiceConfig(path)
63
80
 
64
- if not os.path.exists(os.path.dirname(nginx_template_dest_path)):
65
- os.makedirs(os.path.dirname(nginx_template_dest_path), exist_ok=True)
81
+ if not config.hostname:
82
+ continue
66
83
 
67
- shutil.copy(nginx_template_src_path, nginx_template_dest_path)
84
+ entry_points[config.port] = {
85
+ 'address': f":{config.port}"
86
+ }
68
87
 
69
- config['volumes'].append(
70
- f"{os.path.join(APP_DIR, nginx_template_relative_path)}:/app/nginx.tmpl:ro"
71
- )
88
+ if config.scheme == 'https':
89
+ certificates.append({
90
+ 'certFile': f"/certs/{config.hostname}.crt",
91
+ 'keyFile': f"/certs/{config.hostname}.key"
92
+ })
93
+
94
+ # Create traefik.yml in .stoobly/tmp
95
+ traefik_template_relative_path = os.path.join(DATA_DIR_NAME, TMP_DIR_NAME, 'traefik.yml')
96
+ traefik_template_dest_path = os.path.join(app_dir_path, traefik_template_relative_path)
72
97
 
73
- environment = {}
74
- if not config['environment']:
75
- config['environment'] = environment
76
- else:
77
- environment = config['environment']
98
+ if not os.path.exists(os.path.dirname(traefik_template_dest_path)):
99
+ os.makedirs(os.path.dirname(traefik_template_dest_path), exist_ok=True)
78
100
 
79
- environment['HTTPS_METHOD'] = 'noredirect'
101
+ with open(traefik_template_dest_path, 'w') as fp:
102
+ fp.write(yaml.dump(traefik_config))
103
+
104
+ compose['volumes'].append(
105
+ f"{os.path.join(APP_DIR, traefik_template_relative_path)}:/etc/traefik/traefik.yml:ro"
106
+ )
80
107
 
81
108
  def __find_hosts(service_paths):
82
109
  hostnames = []
@@ -1,6 +1,6 @@
1
1
  from stoobly_agent.app.cli.scaffold.service_config import ServiceConfig
2
2
 
3
- from ...constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE
3
+ from ...constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
4
4
  from .dns_decorator import DnsDecorator
5
5
  from .mock_decorator import MockDecorator
6
6
  from .reverse_proxy_decorator import ReverseProxyDecorator
@@ -12,7 +12,7 @@ def get_workflow_decorators(workflow: str, service_config: ServiceConfig):
12
12
  if service_config.hostname:
13
13
  workflow_decorators.append(ReverseProxyDecorator)
14
14
  workflow_decorators.append(DnsDecorator)
15
- elif workflow == WORKFLOW_MOCK_TYPE:
15
+ elif workflow == WORKFLOW_MOCK_TYPE or workflow == WORKFLOW_TEST_TYPE:
16
16
  if service_config.hostname:
17
17
  workflow_decorators.append(ReverseProxyDecorator if service_config.detached else MockDecorator)
18
18
  workflow_decorators.append(DnsDecorator)
@@ -1,4 +1,6 @@
1
1
  # Wraps the .config.yml file in the service folder
2
+ import hashlib
3
+ import os
2
4
  import pdb
3
5
 
4
6
  from .config import Config
@@ -51,6 +53,10 @@ class ServiceConfig(Config):
51
53
  def detached(self, v):
52
54
  self.__detached = v
53
55
 
56
+ @property
57
+ def id(self):
58
+ return hashlib.md5(os.path.basename(self.dir).encode()).hexdigest()
59
+
54
60
  @property
55
61
  def hostname(self):
56
62
  return (self.__hostname or '').strip()
@@ -120,6 +126,10 @@ class ServiceConfig(Config):
120
126
  def scheme(self, v):
121
127
  self.__scheme = v
122
128
 
129
+ @property
130
+ def tls(self) -> bool:
131
+ return self.__scheme == 'https'
132
+
123
133
  def load(self, config = None):
124
134
  config = config or self.read()
125
135
 
@@ -13,9 +13,6 @@ from docker.models.containers import Container
13
13
  from stoobly_agent.app.cli.scaffold.constants import (
14
14
  PUBLIC_FOLDER_NAME,
15
15
  STOOBLY_DATA_DIR,
16
- VIRTUAL_HOST_ENV,
17
- VIRTUAL_PORT_ENV,
18
- VIRTUAL_PROTO_ENV,
19
16
  WORKFLOW_RECORD_TYPE,
20
17
  WORKFLOW_TEST_TYPE,
21
18
  )
@@ -172,30 +169,6 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
172
169
  if Counter(public_folder_contents_container) != Counter(public_folder_contents_scaffold):
173
170
  raise ScaffoldValidateException(f"public folder was not mounted properly, expected {self.public_dir_path} to exist in container path {public_folder_path}")
174
171
 
175
- # Note: might not need this if the hostname is reachable and working
176
- def proxy_environment_variables_exist(self, container: Container) -> None:
177
- environment_variables = container.attrs['Config']['Env']
178
- virtual_host_exists = False
179
- virtual_port_exists = False
180
- virtual_proto_exists = False
181
-
182
- for environment_variable in environment_variables:
183
- environment_variable_name, environment_variable_value = environment_variable.split('=')
184
- if environment_variable_name == VIRTUAL_HOST_ENV:
185
- virtual_host_exists = True
186
- elif environment_variable_name == VIRTUAL_PORT_ENV:
187
- virtual_port_exists = True
188
- elif environment_variable_name == VIRTUAL_PROTO_ENV:
189
- virtual_proto_exists = True
190
-
191
- if not virtual_host_exists:
192
- raise ScaffoldValidateException(f"VIRTUAL_HOST environment variable is missing from container: {container.name}")
193
- if not virtual_port_exists:
194
- raise ScaffoldValidateException(f"VIRTUAL_POST environment variable is missing from container: {container.name}")
195
- if not virtual_proto_exists:
196
- raise ScaffoldValidateException(f"VIRTUAL_PROTO environment variable is missing from container: {container.name}")
197
-
198
-
199
172
  def validate_proxy_container(self, service_proxy_container: Container):
200
173
  print(f"Validating proxy container: {service_proxy_container.name}")
201
174
 
@@ -209,8 +182,6 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
209
182
  if not self.service_config.detached:
210
183
  self.validate_public_folder(service_proxy_container)
211
184
 
212
- self.proxy_environment_variables_exist(service_proxy_container)
213
-
214
185
  def validate_service_container(self):
215
186
  pass
216
187
 
@@ -4,5 +4,5 @@ import pathlib
4
4
  def __path():
5
5
  return os.path.join(pathlib.Path(__file__).parent.resolve())
6
6
 
7
- def run_template_path():
8
- return os.path.join(__path(), 'run')
7
+ def build_template_path():
8
+ return os.path.join(__path(), 'build')
@@ -1,4 +1,4 @@
1
- FROM stoobly/agent:1.7
1
+ FROM stoobly/agent:1.8
2
2
 
3
3
  ARG USER_ID
4
4
 
@@ -1,10 +1,10 @@
1
1
  services:
2
2
  gateway_base:
3
- environment:
4
- TRUST_DOWNSTREAM_PROXY: true
5
- image: nginxproxy/nginx-proxy:1.7
3
+ command:
4
+ - "--configFile=/etc/traefik/traefik.yml"
5
+ image: traefik:v3
6
6
  profiles:
7
7
  - gateway_base
8
8
  volumes:
9
- - /var/run/docker.sock:/tmp/docker.sock:ro
10
- - ${CERTS_DIR}:/etc/nginx/certs
9
+ - /var/run/docker.sock:/var/run/docker.sock:ro
10
+ - ${CERTS_DIR}:/certs:ro
@@ -3,7 +3,8 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- stoobly-agent config reset
6
+ echo "Configuring intercept..."
7
+ stoobly-agent intercept configure --mode mock --policy all
7
8
 
8
9
  entrypoint=$1
9
10
 
@@ -3,6 +3,8 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
+ stoobly-agent config reset
7
+
6
8
  stoobly-agent snapshot apply
7
9
 
8
10
  entrypoint=$1
@@ -3,7 +3,8 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- stoobly-agent config reset
6
+ echo "Configuring intercept..."
7
+ stoobly-agent intercept configure --mode record --policy all
7
8
 
8
9
  entrypoint=$1
9
10
 
@@ -3,6 +3,8 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
+ stoobly-agent config reset
7
+
6
8
  stoobly-agent snapshot apply
7
9
 
8
10
  entrypoint=$1
@@ -3,7 +3,8 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- stoobly-agent config reset
6
+ echo "Configuring intercept..."
7
+ stoobly-agent intercept configure --mode mock --policy all
7
8
 
8
9
  entrypoint=$1
9
10
 
@@ -3,6 +3,8 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
+ stoobly-agent config reset
7
+
6
8
  stoobly-agent snapshot apply
7
9
 
8
10
  entrypoint=$1
@@ -3,12 +3,6 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- echo "Configuring intercept..."
7
- stoobly-agent intercept configure --mode mock --policy all
8
-
9
- echo "Enabling intercept..."
10
- stoobly-agent intercept enable
11
-
12
6
  entrypoint=$1
13
7
 
14
8
  if [ -e "$entrypoint" ]; then
@@ -3,12 +3,6 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- echo "Configuring intercept..."
7
- stoobly-agent intercept configure --mode record --policy all
8
-
9
- echo "Disabling intercept..."
10
- stoobly-agent intercept disable
11
-
12
6
  entrypoint=$1
13
7
 
14
8
  if [ -e "$entrypoint" ]; then
@@ -3,12 +3,6 @@
3
3
  # This file was automatically generated. DO NOT EDIT.
4
4
  # Any changes made to this file will be overwritten.
5
5
 
6
- echo "Configuring intercept..."
7
- stoobly-agent intercept configure --mode mock --policy all
8
-
9
- echo "Enabling intercept..."
10
- stoobly-agent intercept enable
11
-
12
6
  entrypoint=$1
13
7
 
14
8
  if [ -e "$entrypoint" ]; then
@@ -16,14 +16,13 @@ CUSTOM_CONFIGURE = os.path.join('bin', 'configure')
16
16
  CUSTOM_INIT = os.path.join('bin', 'init')
17
17
  CUSTOM_FIXTURES = 'fixtures.yml'
18
18
  CUSTOM_LIFECYCLE_HOOKS = os.path.join('lifecycle_hooks.py')
19
+ CUSTOM_PUBLIC_GITIGNORE = os.path.join('public', '.gitignore')
19
20
  MAINTAINED_CONFIGURE = os.path.join('bin', '.configure')
20
21
  MAINTAINED_INIT = os.path.join('bin', '.init')
21
- MAINTAINED_PUBLIC = os.path.join('public', '.gitignore')
22
22
 
23
23
  MOCK_WORKFLOW_MAINTAINED_FILES = [
24
24
  MAINTAINED_CONFIGURE,
25
25
  MAINTAINED_INIT,
26
- MAINTAINED_PUBLIC
27
26
  ]
28
27
 
29
28
  MOCK_WORKFLOW_CUSTOM_FILES = [
@@ -32,6 +31,7 @@ MOCK_WORKFLOW_CUSTOM_FILES = [
32
31
  CUSTOM_FIXTURES,
33
32
  CUSTOM_INIT,
34
33
  CUSTOM_LIFECYCLE_HOOKS,
34
+ CUSTOM_PUBLIC_GITIGNORE
35
35
  ]
36
36
 
37
37
  RECORD_WORKFLOW_MAINTAINED_FILES = [
@@ -43,13 +43,12 @@ RECORD_WORKFLOW_CUSTOM_FILES = [
43
43
  CUSTOM_BUILD,
44
44
  CUSTOM_CONFIGURE,
45
45
  CUSTOM_INIT,
46
- CUSTOM_LIFECYCLE_HOOKS
46
+ CUSTOM_LIFECYCLE_HOOKS,
47
47
  ]
48
48
 
49
49
  TEST_WORKFLOW_MAINTAINED_FILES = [
50
50
  MAINTAINED_CONFIGURE,
51
51
  MAINTAINED_INIT,
52
- MAINTAINED_PUBLIC
53
52
  ]
54
53
 
55
54
  TEST_WORKFLOW_CUSTOM_FILES = [
@@ -57,7 +56,8 @@ TEST_WORKFLOW_CUSTOM_FILES = [
57
56
  CUSTOM_CONFIGURE,
58
57
  CUSTOM_FIXTURES,
59
58
  CUSTOM_INIT,
60
- CUSTOM_LIFECYCLE_HOOKS
59
+ CUSTOM_LIFECYCLE_HOOKS,
60
+ CUSTOM_PUBLIC_GITIGNORE
61
61
  ]
62
62
 
63
63
  SERVICE_HOSTNAME_BUILD_ARG = 'SERVICE_HOSTNAME'
@@ -1,7 +1,9 @@
1
+ import pdb
2
+
1
3
  from ..constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
2
4
  from ..docker.workflow.builder import WorkflowBuilder
3
5
  from .constants import (
4
- CUSTOM_CONFIGURE, CUSTOM_INIT, MAINTAINED_CONFIGURE, MAINTAINED_PUBLIC, MOCK_WORKFLOW_CUSTOM_FILES, MOCK_WORKFLOW_MAINTAINED_FILES, RECORD_WORKFLOW_CUSTOM_FILES, RECORD_WORKFLOW_MAINTAINED_FILES, TEST_WORKFLOW_CUSTOM_FILES, TEST_WORKFLOW_MAINTAINED_FILES
6
+ CUSTOM_CONFIGURE, CUSTOM_INIT, CUSTOM_PUBLIC_GITIGNORE, MAINTAINED_CONFIGURE, MOCK_WORKFLOW_CUSTOM_FILES, MOCK_WORKFLOW_MAINTAINED_FILES, RECORD_WORKFLOW_CUSTOM_FILES, RECORD_WORKFLOW_MAINTAINED_FILES, TEST_WORKFLOW_CUSTOM_FILES, TEST_WORKFLOW_MAINTAINED_FILES
5
7
  )
6
8
 
7
9
  def custom_files(workflow: str, workflow_builder: WorkflowBuilder):
@@ -21,8 +23,8 @@ def custom_files(workflow: str, workflow_builder: WorkflowBuilder):
21
23
 
22
24
  # Fixtures are only relevant if the workflow is mock/test and if the service has a hostname
23
25
  if not workflow_builder.config.hostname:
24
- if MAINTAINED_PUBLIC in files:
25
- files.remove(MAINTAINED_PUBLIC)
26
+ if CUSTOM_PUBLIC_GITIGNORE in files:
27
+ files.remove(CUSTOM_PUBLIC_GITIGNORE)
26
28
 
27
29
  return files
28
30
 
@@ -39,8 +41,4 @@ def maintained_files(workflow: str, workflow_builder: WorkflowBuilder):
39
41
  if workflow_builder.configure in workflow_builder.services:
40
42
  files.append(MAINTAINED_CONFIGURE)
41
43
 
42
- if not workflow_builder.config.hostname:
43
- if MAINTAINED_PUBLIC in files:
44
- files.remove(MAINTAINED_PUBLIC)
45
-
46
44
  return files
@@ -1,6 +1,7 @@
1
1
  import click
2
2
  import os
3
3
  import pdb
4
+ import re
4
5
  import sys
5
6
 
6
7
  from io import TextIOWrapper
@@ -142,6 +143,16 @@ def mkcert(**kwargs):
142
143
  def create(**kwargs):
143
144
  __validate_app_dir(kwargs['app_dir_path'])
144
145
 
146
+ if '/' in kwargs['service_name']:
147
+ print(f"Error: {kwargs['service_name']} is invalid. It cannot container '/", file=sys.stderr)
148
+ sys.exit(1)
149
+
150
+ if kwargs.get('hostname'):
151
+ hostname_regex = re.compile(r'^[a-zA-Z0-9.-]+$')
152
+ if not re.search(hostname_regex, kwargs['hostname']):
153
+ print(f"Error: {kwargs['hostname']} is invalid.", file=sys.stderr)
154
+ sys.exit(1)
155
+
145
156
  app = App(kwargs['app_dir_path'], DOCKER_NAMESPACE)
146
157
 
147
158
  service = Service(kwargs['service_name'], app)
@@ -178,14 +178,18 @@ class Settings:
178
178
 
179
179
  def write(self, contents):
180
180
  if contents:
181
- fp = open(self.__settings_file_path, 'w')
182
- yaml.dump(contents, fp, allow_unicode=True)
183
- fp.close()
181
+ with open(self.__settings_file_path, 'w') as fp:
182
+ yaml.dump(contents, fp, allow_unicode=True)
184
183
 
185
184
  ### Helpers
186
185
 
187
186
  def __create_default_file(self):
188
- copyfile(SourceDir.instance().settings_template_file_path, self.__settings_file_path)
187
+ contents = ''
188
+ with open(SourceDir.instance().settings_template_file_path, 'r') as fp:
189
+ contents = fp.read()
190
+
191
+ with open(self.__settings_file_path, 'w') as fp:
192
+ fp.write(contents)
189
193
 
190
194
  def __detect_paths(self):
191
195
  self.__settings_file_path = os.environ.get(env_vars.AGENT_CONFIG_PATH) or self.__data_dir.settings_file_path
@@ -1 +1 @@
1
- 1.7.0
1
+ 1.7.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: stoobly-agent
3
- Version: 1.7.2
3
+ Version: 1.8.1
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