stoobly-agent 0.34.13__py3-none-any.whl → 1.0.0__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/__init__.py +1 -0
- stoobly_agent/app/cli/helpers/openapi_endpoint_adapter.py +9 -7
- stoobly_agent/app/cli/helpers/shell.py +28 -0
- stoobly_agent/app/cli/main_group.py +1 -1
- stoobly_agent/app/cli/scaffold/__init__.py +0 -0
- stoobly_agent/app/cli/scaffold/app.py +106 -0
- stoobly_agent/app/cli/scaffold/app_command.py +82 -0
- stoobly_agent/app/cli/scaffold/app_config.py +32 -0
- stoobly_agent/app/cli/scaffold/app_create_command.py +24 -0
- stoobly_agent/app/cli/scaffold/command.py +15 -0
- stoobly_agent/app/cli/scaffold/config.py +35 -0
- stoobly_agent/app/cli/scaffold/constants.py +35 -0
- stoobly_agent/app/cli/scaffold/docker/__init__.py +0 -0
- stoobly_agent/app/cli/scaffold/docker/app_builder.py +26 -0
- stoobly_agent/app/cli/scaffold/docker/builder.py +117 -0
- stoobly_agent/app/cli/scaffold/docker/constants.py +7 -0
- stoobly_agent/app/cli/scaffold/docker/service/__init__.py +0 -0
- stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py +37 -0
- stoobly_agent/app/cli/scaffold/docker/service/builder.py +117 -0
- stoobly_agent/app/cli/scaffold/docker/service/set_gateway_ports.py +47 -0
- stoobly_agent/app/cli/scaffold/docker/service/types.py +4 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/__init__.py +0 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/build_decorator.py +28 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +259 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py +17 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +40 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py +51 -0
- stoobly_agent/app/cli/scaffold/env.py +49 -0
- stoobly_agent/app/cli/scaffold/service.py +25 -0
- stoobly_agent/app/cli/scaffold/service_command.py +50 -0
- stoobly_agent/app/cli/scaffold/service_config.py +207 -0
- stoobly_agent/app/cli/scaffold/service_create_command.py +77 -0
- stoobly_agent/app/cli/scaffold/service_workflow.py +18 -0
- stoobly_agent/app/cli/scaffold/templates/__init__.py +0 -0
- stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context +8 -0
- stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.proxy +35 -0
- stoobly_agent/app/cli/scaffold/templates/app/.Makefile +118 -0
- stoobly_agent/app/cli/scaffold/templates/app/.docker-compose.base.yml +15 -0
- stoobly_agent/app/cli/scaffold/templates/app/Makefile +3 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/.config.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml +11 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/.docker-compose.mock.yml +22 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/.configure +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/.init +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/configure +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/init +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/record/.docker-compose.record.yml +22 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/.configure +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/.init +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/configure +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/init +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/test/.docker-compose.test.yml +22 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/.configure +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/.init +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/configure +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/init +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.config.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml +17 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/.docker-compose.mock.yml +31 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/.configure +10 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/.init +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/configure +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/init +4 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/docker-compose.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/.docker-compose.record.yml +31 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/.configure +10 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/.init +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/configure +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/init +4 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/docker-compose.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/.docker-compose.test.yml +31 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/.configure +10 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/.init +3 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/init +4 -0
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/docker-compose.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/gateway/.config.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/gateway/.docker-compose.base.yml +11 -0
- stoobly_agent/app/cli/scaffold/templates/app/gateway/mock/.docker-compose.mock.yml +13 -0
- stoobly_agent/app/cli/scaffold/templates/app/gateway/record/.docker-compose.record.yml +13 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.config.yml +1 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.docker-compose.base.yml +5 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/.docker-compose.exec.yml +12 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.create +11 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.delete +12 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.disable +3 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.enable +10 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.reset +12 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.run +11 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.snapshot +12 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/exec/bin/.stop +11 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/mock/.docker-compose.mock.yml +12 -0
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/record/.docker-compose.record.yml +13 -0
- stoobly_agent/app/cli/scaffold/templates/constants.py +63 -0
- stoobly_agent/app/cli/scaffold/templates/factory.py +46 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/.configure +3 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/.init +3 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/configure +18 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/init +4 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/fixtures/.keep +0 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/fixtures.yml +5 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/lifecycle_hooks.py +12 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/.configure +3 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/.init +3 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/configure +29 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/init +4 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/record/lifecycle_hooks.py +12 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/.configure +3 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/.init +3 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/configure +18 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/init +4 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/fixtures/.keep +0 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/fixtures.yml +5 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/lifecycle_hooks.py +12 -0
- stoobly_agent/app/cli/scaffold/workflow.py +49 -0
- stoobly_agent/app/cli/scaffold/workflow_command.py +137 -0
- stoobly_agent/app/cli/scaffold/workflow_copy_command.py +45 -0
- stoobly_agent/app/cli/scaffold/workflow_create_command.py +94 -0
- stoobly_agent/app/cli/scaffold/workflow_log_command.py +21 -0
- stoobly_agent/app/cli/scaffold/workflow_run_command.py +134 -0
- stoobly_agent/app/cli/scaffold_cli.py +392 -0
- stoobly_agent/cli.py +3 -2
- stoobly_agent/config/data_dir.py +40 -14
- stoobly_agent/lib/logger.py +3 -2
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- stoobly_agent/test/config/data_dir_test.py +4 -4
- {stoobly_agent-0.34.13.dist-info → stoobly_agent-1.0.0.dist-info}/METADATA +8 -7
- {stoobly_agent-0.34.13.dist-info → stoobly_agent-1.0.0.dist-info}/RECORD +132 -14
- {stoobly_agent-0.34.13.dist-info → stoobly_agent-1.0.0.dist-info}/WHEEL +1 -1
- {stoobly_agent-0.34.13.dist-info → stoobly_agent-1.0.0.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.34.13.dist-info → stoobly_agent-1.0.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
# This file defines lifecyle hooks for when Stoobly intercepts a request
|
2
|
+
from stoobly_agent.app.proxy.mock.context import MockContext
|
3
|
+
|
4
|
+
def handle_before_request(context: MockContext):
|
5
|
+
intercept_settings = context.intercept_settings
|
6
|
+
flow = context.flow
|
7
|
+
request = flow.request
|
8
|
+
|
9
|
+
# For example, uncomment the following
|
10
|
+
#print(f"Agent running in {intercept_settings.mode} mode with {intercept_settings.policy} policy")
|
11
|
+
#print(dir(request))
|
12
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from typing import List
|
4
|
+
|
5
|
+
from .app import App
|
6
|
+
|
7
|
+
class Workflow():
|
8
|
+
|
9
|
+
def __init__(self, workflow_name: str, app: App):
|
10
|
+
self.__app = app
|
11
|
+
self.__workflow_name = workflow_name
|
12
|
+
|
13
|
+
@property
|
14
|
+
def app(self):
|
15
|
+
return self.__app
|
16
|
+
|
17
|
+
@property
|
18
|
+
def workflow_name(self):
|
19
|
+
return self.__workflow_name
|
20
|
+
|
21
|
+
@property
|
22
|
+
def service(self):
|
23
|
+
return self._service
|
24
|
+
|
25
|
+
@service.setter
|
26
|
+
def service(self, v):
|
27
|
+
self._service = v
|
28
|
+
|
29
|
+
@property
|
30
|
+
def services(self):
|
31
|
+
return list(map(lambda path: os.path.basename(path), self.service_paths))
|
32
|
+
|
33
|
+
@property
|
34
|
+
def service_paths(self):
|
35
|
+
services_dir = os.path.join(self.app.scaffold_dir_path, self.app.namespace)
|
36
|
+
|
37
|
+
services = []
|
38
|
+
for filename in os.listdir(services_dir):
|
39
|
+
path = os.path.join(services_dir, filename)
|
40
|
+
if not os.path.isdir(path):
|
41
|
+
continue
|
42
|
+
|
43
|
+
services.append(path)
|
44
|
+
|
45
|
+
return services
|
46
|
+
|
47
|
+
def service_paths_from_services(self, services: List[str]):
|
48
|
+
app_namespace_path = self.app.namespace_path
|
49
|
+
return list(map(lambda service: os.path.join(app_namespace_path, service), services))
|
@@ -0,0 +1,137 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
import yaml
|
4
|
+
|
5
|
+
from stoobly_agent.lib.logger import Logger
|
6
|
+
|
7
|
+
from .app import App
|
8
|
+
from .config import Config
|
9
|
+
from .constants import COMPOSE_TEMPLATE, CONFIG_FILE, ENV_FILE, FIXTURES_FOLDER_NAME
|
10
|
+
from .docker.constants import DOCKER_COMPOSE_CUSTOM
|
11
|
+
from .service_command import ServiceCommand
|
12
|
+
|
13
|
+
LOG_ID = 'WorkflowCommand'
|
14
|
+
|
15
|
+
class WorkflowCommand(ServiceCommand):
|
16
|
+
|
17
|
+
def __init__(self, app: App, **kwargs):
|
18
|
+
super().__init__(app, **kwargs)
|
19
|
+
|
20
|
+
self.__workflow_name = kwargs['workflow_name']
|
21
|
+
|
22
|
+
@property
|
23
|
+
def compose_path(self):
|
24
|
+
return os.path.join(
|
25
|
+
self.scaffold_dir_path,
|
26
|
+
self.compose_relative_path
|
27
|
+
)
|
28
|
+
|
29
|
+
@property
|
30
|
+
def compose_relative_path(self):
|
31
|
+
return os.path.join(
|
32
|
+
self.workflow_relative_path,
|
33
|
+
COMPOSE_TEMPLATE.format(workflow=self.workflow_name)
|
34
|
+
)
|
35
|
+
|
36
|
+
@property
|
37
|
+
def containers(self):
|
38
|
+
_containers = []
|
39
|
+
if not os.path.exists(self.compose_path):
|
40
|
+
return []
|
41
|
+
|
42
|
+
with open(self.compose_path, 'r') as fp:
|
43
|
+
config = yaml.safe_load(fp)
|
44
|
+
services = config.get('services')
|
45
|
+
if not isinstance(services, dict):
|
46
|
+
return []
|
47
|
+
|
48
|
+
for service in services:
|
49
|
+
_containers.append(f"{self.workflow_name}-{service}-1")
|
50
|
+
|
51
|
+
return _containers
|
52
|
+
|
53
|
+
@property
|
54
|
+
def custom_compose(self):
|
55
|
+
if os.path.exists(self.custom_compose_path):
|
56
|
+
with open(self.custom_compose_path, 'r') as fp:
|
57
|
+
compose = yaml.safe_load(fp)
|
58
|
+
if compose and not isinstance(compose, dict):
|
59
|
+
Logger.instance(LOG_ID).warn(f"Could not parse {self.custom_compose_path} as YAML")
|
60
|
+
return {}
|
61
|
+
return compose
|
62
|
+
|
63
|
+
@property
|
64
|
+
def custom_compose_relative_path(self):
|
65
|
+
return os.path.join(
|
66
|
+
self.workflow_relative_path,
|
67
|
+
DOCKER_COMPOSE_CUSTOM
|
68
|
+
)
|
69
|
+
|
70
|
+
@property
|
71
|
+
def custom_compose_path(self):
|
72
|
+
return os.path.join(
|
73
|
+
self.scaffold_dir_path,
|
74
|
+
self.custom_compose_relative_path
|
75
|
+
)
|
76
|
+
|
77
|
+
@property
|
78
|
+
def custom_services(self):
|
79
|
+
custom_compose = self.custom_compose
|
80
|
+
|
81
|
+
if not custom_compose:
|
82
|
+
return {}
|
83
|
+
|
84
|
+
services = custom_compose.get('services')
|
85
|
+
if not isinstance(services, dict):
|
86
|
+
return {}
|
87
|
+
|
88
|
+
return services
|
89
|
+
|
90
|
+
@property
|
91
|
+
def fixtures_dir_path(self):
|
92
|
+
return os.path.join(self.workflow_path, FIXTURES_FOLDER_NAME)
|
93
|
+
|
94
|
+
@property
|
95
|
+
def workflow_config(self):
|
96
|
+
return Config(self.workflow_config_path).read()
|
97
|
+
|
98
|
+
@property
|
99
|
+
def workflow_config_path(self):
|
100
|
+
return os.path.join(self.workflow_path, CONFIG_FILE)
|
101
|
+
|
102
|
+
@property
|
103
|
+
def workflow_env_path(self):
|
104
|
+
return os.path.join(self.workflow_path, ENV_FILE)
|
105
|
+
|
106
|
+
@property
|
107
|
+
def workflow_exists(self):
|
108
|
+
return os.path.exists(self.workflow_path)
|
109
|
+
|
110
|
+
@property
|
111
|
+
def workflow_name(self):
|
112
|
+
return self.__workflow_name
|
113
|
+
|
114
|
+
@property
|
115
|
+
def workflow_path(self):
|
116
|
+
return os.path.join(
|
117
|
+
self.scaffold_dir_path,
|
118
|
+
self.workflow_relative_path
|
119
|
+
)
|
120
|
+
|
121
|
+
@property
|
122
|
+
def workflow_relative_path(self):
|
123
|
+
return os.path.join(
|
124
|
+
self.service_relative_path,
|
125
|
+
self.workflow_name
|
126
|
+
)
|
127
|
+
|
128
|
+
@property
|
129
|
+
def workflow_templates_root_dir(self):
|
130
|
+
return os.path.join(self.templates_root_dir, 'workflow')
|
131
|
+
|
132
|
+
def env(self, _c: dict):
|
133
|
+
_config = self.app_config.read()
|
134
|
+
_config.update(self.service_config)
|
135
|
+
_config.update(self.workflow_config)
|
136
|
+
_config.update(_c)
|
137
|
+
return _config
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
import shutil
|
4
|
+
|
5
|
+
from .app import App
|
6
|
+
from .constants import COMPOSE_TEMPLATE, WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE
|
7
|
+
from .service_workflow import ServiceWorkflow
|
8
|
+
from .workflow_command import WorkflowCommand
|
9
|
+
|
10
|
+
CORE_WORKFLOWS = [WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
|
11
|
+
|
12
|
+
class WorkflowCopyCommand(WorkflowCommand):
|
13
|
+
|
14
|
+
def __init__(self, app: App, **kwargs):
|
15
|
+
super().__init__(app, **kwargs)
|
16
|
+
|
17
|
+
self.__force = not not kwargs.get('force')
|
18
|
+
|
19
|
+
@property
|
20
|
+
def force(self):
|
21
|
+
return self.__force
|
22
|
+
|
23
|
+
def copy(self, destination_workflow_name: str):
|
24
|
+
destination_workflow = ServiceWorkflow(self.service_name, destination_workflow_name, self.app)
|
25
|
+
|
26
|
+
# Create workflow folder
|
27
|
+
dest = os.path.join(destination_workflow.path)
|
28
|
+
if os.path.exists(dest) and self.force:
|
29
|
+
shutil.rmtree(dest)
|
30
|
+
|
31
|
+
if not os.path.exists(dest):
|
32
|
+
os.makedirs(dest)
|
33
|
+
|
34
|
+
self.app.copy_folders_and_hidden_files(self.workflow_path, dest)
|
35
|
+
|
36
|
+
compose_file_src = os.path.join(dest, COMPOSE_TEMPLATE.format(workflow=self.workflow_name))
|
37
|
+
compose_file_dest = os.path.join(dest, COMPOSE_TEMPLATE.format(workflow=destination_workflow_name))
|
38
|
+
os.rename(compose_file_src, compose_file_dest)
|
39
|
+
|
40
|
+
# Replace workflow name
|
41
|
+
with open(compose_file_dest, 'r+') as fp:
|
42
|
+
contents = fp.read()
|
43
|
+
fp.seek(0)
|
44
|
+
fp.write(contents.replace(self.workflow_name, destination_workflow_name))
|
45
|
+
fp.truncate()
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
import shutil
|
4
|
+
|
5
|
+
from typing import List, TypedDict, Union
|
6
|
+
|
7
|
+
from .app import App
|
8
|
+
from .constants import WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE, WORKFLOW_TEMPLATE
|
9
|
+
from .docker.service.builder import ServiceBuilder
|
10
|
+
from .docker.workflow.mock_decorator import MockDecorator
|
11
|
+
from .docker.workflow.reverse_proxy_decorator import ReverseProxyDecorator
|
12
|
+
from .docker.workflow.builder import WorkflowBuilder
|
13
|
+
from .templates.factory import custom_files, maintained_files
|
14
|
+
from .workflow_command import WorkflowCommand
|
15
|
+
|
16
|
+
CORE_WORKFLOWS = [WORKFLOW_MOCK_TYPE, WORKFLOW_RECORD_TYPE, WORKFLOW_TEST_TYPE]
|
17
|
+
|
18
|
+
class BuildOptions(TypedDict):
|
19
|
+
builder_class: type
|
20
|
+
headless: bool
|
21
|
+
service_builder: ServiceBuilder
|
22
|
+
template: WORKFLOW_TEMPLATE
|
23
|
+
workflow_decorators: List[Union[MockDecorator, ReverseProxyDecorator]]
|
24
|
+
|
25
|
+
class WorkflowCreateCommand(WorkflowCommand):
|
26
|
+
|
27
|
+
def __init__(self, app: App, **kwargs):
|
28
|
+
super().__init__(app, **kwargs)
|
29
|
+
|
30
|
+
self.__env_vars: List[str] = kwargs.get('env') or []
|
31
|
+
self.__force = not not kwargs.get('force')
|
32
|
+
|
33
|
+
@property
|
34
|
+
def workflow_templates_path(self):
|
35
|
+
return self.build_workflow_templates_path(self.workflow_name)
|
36
|
+
|
37
|
+
@property
|
38
|
+
def env_vars(self):
|
39
|
+
return self.__env_vars
|
40
|
+
|
41
|
+
@property
|
42
|
+
def force(self):
|
43
|
+
return self.__force
|
44
|
+
|
45
|
+
def build(self, **kwargs: BuildOptions):
|
46
|
+
# Create workflow folder
|
47
|
+
dest = os.path.join(self.workflow_path)
|
48
|
+
if os.path.exists(dest) and self.force:
|
49
|
+
shutil.rmtree(dest)
|
50
|
+
|
51
|
+
if not os.path.exists(dest):
|
52
|
+
os.makedirs(dest)
|
53
|
+
|
54
|
+
# Create workflow maintained compose file
|
55
|
+
workflow_builder = self.__write_docker_compose_file(**kwargs)
|
56
|
+
self.__copy_templates(workflow_builder, kwargs.get('template'))
|
57
|
+
|
58
|
+
def build_workflow_templates_path(self, workflow_name: str):
|
59
|
+
return os.path.join(self.workflow_templates_root_dir, workflow_name)
|
60
|
+
|
61
|
+
def __copy_templates(self, workflow_builder: WorkflowBuilder, template: WORKFLOW_TEMPLATE = None):
|
62
|
+
if not template:
|
63
|
+
templates_path = self.workflow_templates_path
|
64
|
+
else:
|
65
|
+
templates_path = self.build_workflow_templates_path(template)
|
66
|
+
|
67
|
+
if not os.path.exists(templates_path):
|
68
|
+
return
|
69
|
+
|
70
|
+
# Maintained files are files that will always be overwritten
|
71
|
+
maintained_workflow_files = maintained_files(self.workflow_name, workflow_builder)
|
72
|
+
self.copy_files(templates_path, maintained_workflow_files, self.workflow_path)
|
73
|
+
|
74
|
+
# Custom files are files that may be modified by the user
|
75
|
+
custom_workflow_files = custom_files(self.workflow_name, workflow_builder)
|
76
|
+
self.copy_files_no_replace(templates_path, custom_workflow_files, self.workflow_path)
|
77
|
+
|
78
|
+
def __write_docker_compose_file(self, **kwargs: BuildOptions):
|
79
|
+
builder_class = kwargs.get('builder_class') or WorkflowBuilder
|
80
|
+
service_builder = kwargs.get('service_builder') or ServiceBuilder(self.service_config)
|
81
|
+
workflow_decorators: List[Union[MockDecorator, ReverseProxyDecorator]] = kwargs.get('workflow_decorators')
|
82
|
+
|
83
|
+
workflow_builder = builder_class(self.workflow_path, service_builder)
|
84
|
+
workflow_builder.with_env(list(self.env_vars))
|
85
|
+
workflow_builder.build_all()
|
86
|
+
|
87
|
+
if isinstance(workflow_decorators, list):
|
88
|
+
for workflow_decorator in workflow_decorators:
|
89
|
+
workflow_decorator(workflow_builder).decorate()
|
90
|
+
|
91
|
+
workflow_builder.write()
|
92
|
+
workflow_builder.initialize_custom_file()
|
93
|
+
|
94
|
+
return workflow_builder
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
import yaml
|
4
|
+
|
5
|
+
from .app import App
|
6
|
+
from .workflow_command import WorkflowCommand
|
7
|
+
|
8
|
+
class WorkflowLogCommand(WorkflowCommand):
|
9
|
+
def __init__(self, app: App, **kwargs):
|
10
|
+
super().__init__(app, **kwargs)
|
11
|
+
|
12
|
+
def all(self):
|
13
|
+
commands = []
|
14
|
+
containers = self.containers
|
15
|
+
|
16
|
+
for container in containers:
|
17
|
+
command = ['docker', 'logs', container]
|
18
|
+
|
19
|
+
commands.append(' '.join(command))
|
20
|
+
|
21
|
+
return commands
|
@@ -0,0 +1,134 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
|
4
|
+
from stoobly_agent.config.data_dir import DataDir
|
5
|
+
from stoobly_agent.lib.logger import Logger
|
6
|
+
|
7
|
+
from .app import App
|
8
|
+
from .constants import APP_NETWORK_ENV, CERTS_DIR_ENV, CONTEXT_DIR_ENV, SERVICE_NAME_ENV, USER_ID_ENV, WORKFLOW_NAME_ENV
|
9
|
+
from .env import Env
|
10
|
+
from .workflow_command import WorkflowCommand
|
11
|
+
|
12
|
+
LOG_ID = 'WorkflowRunCommand'
|
13
|
+
|
14
|
+
class WorkflowRunCommand(WorkflowCommand):
|
15
|
+
def __init__(self, app: App, **kwargs):
|
16
|
+
super().__init__(app, **kwargs)
|
17
|
+
|
18
|
+
self.__current_working_dir = os.getcwd()
|
19
|
+
self.__certs_dir_path = app.certs_dir_path
|
20
|
+
self.__context_dir_path = app.context_dir_path
|
21
|
+
self.__extra_compose_path = kwargs.get('extra_compose_path')
|
22
|
+
self.__network = kwargs.get('network') or app.network
|
23
|
+
|
24
|
+
@property
|
25
|
+
def certs_dir_path(self):
|
26
|
+
if not self.__certs_dir_path:
|
27
|
+
data_dir = DataDir.instance()
|
28
|
+
dir_path = os.path.join(data_dir.tmp_dir_path, 'certs')
|
29
|
+
if not os.path.exists(dir_path):
|
30
|
+
os.mkdir(dir_path)
|
31
|
+
|
32
|
+
return self.__certs_dir_path
|
33
|
+
|
34
|
+
@property
|
35
|
+
def context_dir_path(self):
|
36
|
+
if not self.__context_dir_path:
|
37
|
+
data_dir = DataDir.instance()
|
38
|
+
return os.path.dirname(data_dir.path)
|
39
|
+
|
40
|
+
return self.__context_dir_path
|
41
|
+
|
42
|
+
@property
|
43
|
+
def current_working_dir(self):
|
44
|
+
return self.__current_working_dir
|
45
|
+
|
46
|
+
@current_working_dir.setter
|
47
|
+
def current_working_dir(self, v):
|
48
|
+
self.__current_working_dir = v
|
49
|
+
|
50
|
+
@property
|
51
|
+
def extra_compose_path(self):
|
52
|
+
return self.__extra_compose_path
|
53
|
+
|
54
|
+
@property
|
55
|
+
def network(self):
|
56
|
+
return self.__network
|
57
|
+
|
58
|
+
def create_network(self):
|
59
|
+
return f"docker network create {self.network} 2> /dev/null"
|
60
|
+
|
61
|
+
def up(self):
|
62
|
+
if not os.path.exists(self.compose_path):
|
63
|
+
return ''
|
64
|
+
|
65
|
+
command = ['COMPOSE_IGNORE_ORPHANS=true', 'docker', 'compose']
|
66
|
+
|
67
|
+
# Add docker compose file
|
68
|
+
command.append(f"-f {os.path.relpath(self.compose_path, self.__current_working_dir)}")
|
69
|
+
|
70
|
+
# Add custom docker compose file
|
71
|
+
custom_services = self.custom_services
|
72
|
+
|
73
|
+
if custom_services:
|
74
|
+
uses_profile = False
|
75
|
+
for service_name in custom_services:
|
76
|
+
service = custom_services[service_name]
|
77
|
+
profiles = service.get('profiles')
|
78
|
+
if isinstance(profiles, list):
|
79
|
+
if self.workflow_name in profiles:
|
80
|
+
uses_profile = True
|
81
|
+
break
|
82
|
+
if not uses_profile:
|
83
|
+
# TODO: looking into why warning does not print in docker
|
84
|
+
Logger.instance(LOG_ID).error(f"Missing {self.workflow_name} profile in custom compose file")
|
85
|
+
|
86
|
+
command.append(f"-f {os.path.relpath(self.custom_compose_path, self.__current_working_dir)}")
|
87
|
+
|
88
|
+
if self.extra_compose_path:
|
89
|
+
command.append(f"-f {os.path.relpath(self.extra_compose_path, self.__current_working_dir)}")
|
90
|
+
|
91
|
+
command.append(f"--profile {self.workflow_name}")
|
92
|
+
command.append('up')
|
93
|
+
command.append('-d')
|
94
|
+
command.append('--build')
|
95
|
+
|
96
|
+
self.write_env()
|
97
|
+
|
98
|
+
return ' '.join(command)
|
99
|
+
|
100
|
+
def down(self):
|
101
|
+
if not os.path.exists(self.compose_path):
|
102
|
+
return ''
|
103
|
+
|
104
|
+
command = ['docker', 'compose']
|
105
|
+
|
106
|
+
# Add docker compose file
|
107
|
+
command.append(f"-f {os.path.relpath(self.compose_path, os.getcwd())}")
|
108
|
+
|
109
|
+
# Add custom docker compose file
|
110
|
+
if self.custom_services:
|
111
|
+
command.append(f"-f {os.path.relpath(self.custom_compose_path, self.__current_working_dir)}")
|
112
|
+
|
113
|
+
if self.extra_compose_path:
|
114
|
+
command.append(f"-f {os.path.relpath(self.extra_compose_path, self.__current_working_dir)}")
|
115
|
+
|
116
|
+
command.append(f"--profile {self.workflow_name}")
|
117
|
+
command.append('down')
|
118
|
+
|
119
|
+
return ' '.join(command)
|
120
|
+
|
121
|
+
def write_env(self):
|
122
|
+
_config = {}
|
123
|
+
_config[CERTS_DIR_ENV] = self.certs_dir_path
|
124
|
+
_config[CONTEXT_DIR_ENV] = self.context_dir_path
|
125
|
+
_config[SERVICE_NAME_ENV] = self.service_name
|
126
|
+
_config[USER_ID_ENV] = os.getuid()
|
127
|
+
_config[WORKFLOW_NAME_ENV] = self.workflow_name
|
128
|
+
|
129
|
+
if self.network:
|
130
|
+
_config[APP_NETWORK_ENV] = self.network
|
131
|
+
|
132
|
+
env_vars = self.config(_config)
|
133
|
+
env_path = self.workflow_env_path
|
134
|
+
Env(env_path).write(env_vars)
|