zscams 2.0.1__py2.py3-none-any.whl → 2.0.2__py2.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.
zscams/__main__.py CHANGED
@@ -2,84 +2,26 @@
2
2
  Main entry point for ZSCAMs Agent
3
3
  """
4
4
 
5
- import os
6
5
  import asyncio
7
6
  import sys
8
- import argparse
9
- from zscams.agent.src.core.api.backend.bootstrap import bootstrap
10
- from zscams.agent.src.core.api.backend.update_machine_info import update_machine_info
11
- from zscams.agent.src.support.configuration import get_config, CONFIG_PATH
7
+ import os
8
+ from zscams.agent.src.core.backend.bootstrap import bootstrap
9
+ from zscams.agent.src.core.backend.update_machine_info import update_machine_info
12
10
  from zscams.agent.src.support.logger import get_logger
13
- from zscams.agent.src.core.tunnel.tls import create_ssl_context
14
- from zscams.agent.src.core.tunnels import start_all_tunnels
15
- from zscams.agent.src.core.services import start_all_services
16
- from zscams.agent.src.core.service_health_check import monitor_services
17
- from zscams.agent.src.core.api.backend.client import backend_client
18
-
19
- logger = get_logger("tls_tunnel_main")
20
-
21
-
22
- def ensure_bootstrapped():
23
- """Ensure the agent is bootstrapped with the backend."""
24
-
25
- bootstrapped = backend_client.is_bootstrapped()
26
- logger.debug("Agent bootstrapped: %s", bootstrapped)
27
- if not bootstrapped:
28
- logger.error(
29
- "Agent is not bootstrapped. Please run `zscams --bootstrap` to start the bootstrap process.",
30
- )
31
- sys.exit(1)
32
-
33
-
34
- async def async_main():
35
- """Asynchronous main function to start tunnels and services."""
36
-
37
- config = get_config()
38
- config_dir = os.path.dirname(CONFIG_PATH)
39
- ssl_context = create_ssl_context(config["remote"], config_dir=config_dir)
40
- remote_host = config["remote"]["host"]
41
- remote_port = config["remote"]["port"]
42
-
43
- # Start tunnels and wait for readiness
44
- tunnel_tasks = await start_all_tunnels(
45
- config.get("forwards", []), remote_host, remote_port, ssl_context
46
- )
47
-
48
- # Start services that depend on tunnels
49
- service_tasks = asyncio.create_task(
50
- start_all_services(config.get("services", []), config_dir=config_dir)
51
- )
52
-
53
- # Start health checks
54
- monitor_task = asyncio.create_task(
55
- monitor_services(
56
- config.get("services", []),
57
- config_dir=config_dir,
58
- interval=config.get("general", {}).get("health_check_interval", 300),
59
- )
60
- )
11
+ from zscams.agent import init_parser, ensure_bootstrapped, run
61
12
 
62
- logger.info("[*] All tunnels and services started. Press Ctrl+C to stop.")
63
- await asyncio.gather(*tunnel_tasks, service_tasks, monitor_task)
13
+ logger = get_logger("ZSCAMs")
64
14
 
65
15
 
66
16
  def main():
67
17
  """Main function to run the asynchronous main."""
68
- parser = argparse.ArgumentParser(description="ZSCAMs Agent")
69
- parser.add_argument(
70
- "--bootstrap",
71
- action="store_true",
72
- help="Run bootstrap process and exit",
73
- )
74
- parser.add_argument(
75
- "--update-machine-info",
76
- action="store_true",
77
- help="Run bootstrap process and exit",
78
- )
79
- args = parser.parse_args()
18
+ args = init_parser().parse_args()
80
19
 
81
20
  if args.bootstrap:
82
21
  try:
22
+ if os.geteuid() != 0:
23
+ logger.error("You are NOT running as root.")
24
+ sys.exit(1)
83
25
  bootstrap()
84
26
  sys.exit(0)
85
27
  except Exception as exception:
@@ -92,7 +34,7 @@ def main():
92
34
 
93
35
  try:
94
36
  ensure_bootstrapped()
95
- asyncio.run(async_main())
37
+ asyncio.run(run())
96
38
  except KeyboardInterrupt:
97
39
  logger.info("Exiting TLS Tunnel Client")
98
40
 
zscams/agent/__init__.py CHANGED
@@ -0,0 +1,93 @@
1
+ import os
2
+ import asyncio
3
+ import sys
4
+ import argparse
5
+ from zscams.agent.src.support.configuration import get_config, CONFIG_PATH
6
+ from zscams.agent.src.support.filesystem import is_file_exists, resolve_path
7
+ from zscams.agent.src.core.tunnel.tls import create_ssl_context
8
+ from zscams.agent.src.core.tunnels import start_all_tunnels
9
+ from zscams.agent.src.core.services import start_all_services
10
+ from zscams.agent.src.core.service_health_check import monitor_services
11
+ from zscams.agent.src.core.backend.client import backend_client
12
+ from zscams.agent.src.support.logger import get_logger
13
+
14
+
15
+ logger = get_logger("tls_tunnel_main")
16
+
17
+
18
+ def init_parser():
19
+ parser = argparse.ArgumentParser(description="ZSCAMs Agent")
20
+ parser.add_argument(
21
+ "--bootstrap",
22
+ action="store_true",
23
+ help="Run bootstrap process and exit",
24
+ )
25
+ parser.add_argument(
26
+ "--update-machine-info",
27
+ action="store_true",
28
+ help="Run bootstrap process and exit",
29
+ )
30
+ return parser
31
+
32
+
33
+ def ensure_bootstrapped():
34
+ """Ensure the agent is bootstrapped with the backend."""
35
+
36
+ config = get_config()
37
+ remote_cfg = config["remote"]
38
+ config_dir = os.path.dirname(CONFIG_PATH)
39
+
40
+ files_to_ensure = [
41
+ resolve_path(remote_cfg.get("ca_cert"), config_dir),
42
+ resolve_path(remote_cfg.get("client_cert"), config_dir),
43
+ resolve_path(remote_cfg.get("client_key"), config_dir),
44
+ ]
45
+
46
+ has_missing_file = False
47
+
48
+ for file in files_to_ensure:
49
+ if not is_file_exists(file, logger):
50
+ has_missing_file = True
51
+ break
52
+
53
+ bootstrapped = backend_client.is_bootstrapped()
54
+
55
+ logger.debug("Agent has entry on server: %s", bootstrapped)
56
+
57
+ if not bootstrapped or has_missing_file:
58
+ logger.error(
59
+ "Agent is not bootstrapped. Please run `zscams --bootstrap` to start the bootstrap process.",
60
+ )
61
+ sys.exit(1)
62
+
63
+
64
+ async def run():
65
+ """Asynchronous main function to start tunnels and services."""
66
+
67
+ config = get_config()
68
+ config_dir = os.path.dirname(CONFIG_PATH)
69
+ ssl_context = create_ssl_context(config["remote"], config_dir=config_dir)
70
+ remote_host = config["remote"]["host"]
71
+ remote_port = config["remote"]["port"]
72
+
73
+ # Start tunnels and wait for readiness
74
+ tunnel_tasks = await start_all_tunnels(
75
+ config.get("forwards", []), remote_host, remote_port, ssl_context
76
+ )
77
+
78
+ # Start services that depend on tunnels
79
+ service_tasks = asyncio.create_task(
80
+ start_all_services(config.get("services", []), config_dir=config_dir)
81
+ )
82
+
83
+ # Start health checks
84
+ monitor_task = asyncio.create_task(
85
+ monitor_services(
86
+ config.get("services", []),
87
+ config_dir=config_dir,
88
+ interval=config.get("general", {}).get("health_check_interval", 300),
89
+ )
90
+ )
91
+
92
+ logger.info("[*] All tunnels and services started. Press Ctrl+C to stop.")
93
+ await asyncio.gather(*tunnel_tasks, service_tasks, monitor_task)
zscams/agent/config.yaml CHANGED
@@ -1,121 +1,103 @@
1
1
  ---
2
+ backend:
3
+ base_url: http://22.0.122.40:5000/api
4
+ cache_dir: .cache
5
+ bootstrap_info:
6
+ blacklist_ports: []
7
+ cert_issuer: ZSCAMs
8
+ csr:
9
+ country: FR
10
+ default_common_name: zscams-agent.orangecyberdefense.com
11
+ locality: Paris
12
+ organization: zscams-agent.orangecyberdefense.com
13
+ state: Ile-de-France
14
+ forwards:
15
+ - description: Forward to SSH backend
16
+ local_port: 4422
17
+ sni_hostname: ssh-tunnel
18
+ - description: Forward to Seculogs
19
+ local_port: 4423
20
+ sni_hostname: monitor-tunnel
21
+ general:
22
+ health_check_interval: 30
2
23
  logging:
3
24
  level: 10
4
-
5
- general:
6
- health_check_interval: 30 # seconds between health checks for services
7
-
8
25
  remote:
9
- host: 81.255.240.214 # stunnel server IP or hostname
10
- port: 443 # Single TLS port on stunnel server
11
- verify_cert: false # set false for self-signed certs
12
26
  ca_cert: certificates/ca_chain.pem
27
+ ca_chain: certificates/ca_chain.pem
13
28
  client_cert: certificates/client.crt
14
29
  client_key: certificates/client.key
15
- ca_chain: certificates/ca_chain.pem
16
-
17
- forwards:
18
- - local_port: 4422
19
- sni_hostname: ssh-tunnel
20
- description: "Forward to SSH backend"
21
- - local_port: 4423
22
- sni_hostname: monitor-tunnel
23
- description: "Forward to Seculogs"
24
-
25
- backend:
26
- base_url: "http://22.0.122.40:5000/api"
27
- cache_dir: ".cache"
28
-
29
- bootstrap_info:
30
- csr:
31
- country: "FR"
32
- state: "Ile-de-France"
33
- locality: "Paris"
34
- common_name: "zscams-agent.example.com"
35
- organization: "zscams-agent.orangecyberdefense.com"
36
- cert_issuer: "ZSCAMs"
37
- blacklist_ports: []
38
-
30
+ host: 81.255.240.214
31
+ port: 443
32
+ verify_cert: false
39
33
  services:
40
- - name: "Reverse SSH"
41
- script: "src/services/reverse_ssh.py"
42
- # Its just for reference in logs but not used within the service as the
43
- # actual port is passed via params (Remote Port). Im setting it to 22 as
44
- # its the eventual port that will be connected to
45
- port: 22
46
- args: []
34
+ - args: []
35
+ custom_port_name: reverse_port
47
36
  health:
48
37
  host: localhost
49
- # port that should be open if service is healthy
50
38
  port: 22
51
-
52
- # -R [remote_listen_address:]remote_listen_port:local_host:local_port
39
+ name: Reverse SSH
53
40
  params:
54
- remote_host: "localhost"
55
- # The forwarding port on ZSCAMs server to connect to in order to create
56
- # the reverse tunnel, this should match the local_port of one of the
57
- # forwards above
58
41
  local_port: 4422
59
- server_ssh_user: "ssh_user"
60
- # Port on ZSCAMS server to forward to this agent, this port should be
61
- # dynamically assigned by the server and passed to the agent via some
62
- # secure means
63
- reverse_port: 53612
64
- # Path to private key for authentication
65
- private_key: 'zscams/agent/keys/autoport.key'
42
+ private_key: zscams/agent/keys/autoport.key
43
+ remote_host: localhost
44
+ reverse_port: 10000
45
+ server_ssh_user: ssh_user
66
46
  ssh_options:
67
- - "-o LogLevel=error"
68
- - "-o UserKnownHostsFile=/dev/null"
69
- - "-o StrictHostKeyChecking=no"
70
- - "-o ServerAliveInterval=30"
71
- - "-o ServerAliveCountMax=2"
47
+ - -o LogLevel=error
48
+ - -o UserKnownHostsFile=/dev/null
49
+ - -o StrictHostKeyChecking=no
50
+ - -o ServerAliveInterval=30
51
+ - -o ServerAliveCountMax=2
52
+ port: 22
72
53
  prerequisites:
73
54
  files:
74
- - 'zscams/agent/keys/autoport.key'
75
- services: []
55
+ - zscams/agent/keys/autoport.key
76
56
  ports:
77
57
  - 22
78
- - name: "Monitor Forwarder"
79
- script: "src/services/ssh_forwarder.py"
80
- port: 530
81
- args: []
58
+ services: []
59
+ script: src/services/reverse_ssh.py
60
+ - args: []
61
+ custom_port_name: forwarder_port
82
62
  health:
83
63
  host: localhost
84
- # port that should be open if service is healthy
85
- port: 44514
64
+ port: 10001
65
+ name: Monitor Forwarder
86
66
  params:
87
- remote_host: "194.51.14.159"
67
+ forwarder_port: 10001
68
+ local_port: 4423
69
+ private_key: zscams/agent/keys/autoport.key
70
+ remote_host: 194.51.14.159
88
71
  remote_port: 530
89
- local_port: 4423 #Stunnel port
90
- forwarder_port: 44514 #Port the forwarder will listen on and forward to remote host and port
91
- server_ssh_user: "ssh_user"
92
- private_key: 'zscams/agent/keys/autoport.key'
72
+ server_ssh_user: ssh_user
93
73
  ssh_options:
94
- - "-o LogLevel=error"
95
- - "-o UserKnownHostsFile=/dev/null"
96
- - "-o StrictHostKeyChecking=no"
97
- - "-o ServerAliveInterval=30"
98
- - "-o ServerAliveCountMax=2"
74
+ - -o LogLevel=error
75
+ - -o UserKnownHostsFile=/dev/null
76
+ - -o StrictHostKeyChecking=no
77
+ - -o ServerAliveInterval=30
78
+ - -o ServerAliveCountMax=2
79
+ port: 530
99
80
  prerequisites:
100
81
  files:
101
- - 'zscams/agent/keys/autoport.key'
102
- services: []
82
+ - zscams/agent/keys/autoport.key
103
83
  ports: []
104
- - name: "Monitor Service"
105
- script: "src/services/system_monitor.py"
106
- port: 44514
107
- args: []
84
+ services: []
85
+ script: src/services/ssh_forwarder.py
86
+ - args: []
108
87
  health:
109
88
  host: localhost
110
- port: 44514
89
+ port: 10001
90
+ name: Monitor Service
111
91
  params:
112
- remote_host: "localhost"
113
- remote_port: 44514
114
- equipment_name: "zpa-connector"
115
- equipment_type: "zpa"
116
- service_name: "Zscaler-AppConnector"
92
+ equipment_name: zpa-orange-swec-dev-01
93
+ equipment_type: zpa
94
+ remote_host: localhost
95
+ remote_port: 10001
96
+ service_name: Zscaler-AppConnector
97
+ port: 10001
117
98
  prerequisites:
118
99
  files: []
119
- services: []
120
100
  ports:
121
- - 44514
101
+ - 10001
102
+ services: []
103
+ script: src/services/system_monitor.py
@@ -0,0 +1,103 @@
1
+ ---
2
+ backend:
3
+ base_url: http://22.0.122.40:5000/api
4
+ cache_dir: .cache
5
+ bootstrap_info:
6
+ blacklist_ports: []
7
+ cert_issuer: ZSCAMs
8
+ csr:
9
+ country: FR
10
+ default_common_name: zscams-agent.orangecyberdefense.com
11
+ locality: Paris
12
+ organization: zscams-agent.orangecyberdefense.com
13
+ state: Ile-de-France
14
+ forwards:
15
+ - description: Forward to SSH backend
16
+ local_port: 4422
17
+ sni_hostname: ssh-tunnel
18
+ - description: Forward to Seculogs
19
+ local_port: 4423
20
+ sni_hostname: monitor-tunnel
21
+ general:
22
+ health_check_interval: 30
23
+ logging:
24
+ level: 10
25
+ remote:
26
+ ca_cert: certificates/ca_chain.pem
27
+ ca_chain: certificates/ca_chain.pem
28
+ client_cert: certificates/client.crt
29
+ client_key: certificates/client.key
30
+ host: 81.255.240.214
31
+ port: 443
32
+ verify_cert: false
33
+ services:
34
+ - args: []
35
+ health:
36
+ host: localhost
37
+ port: 22
38
+ name: Reverse SSH
39
+ custom_port_name: "reverse_port"
40
+ params:
41
+ local_port: 4422
42
+ private_key: zscams/agent/keys/autoport.key
43
+ remote_host: localhost
44
+ reverse_port: "{reverse_port}"
45
+ server_ssh_user: ssh_user
46
+ ssh_options:
47
+ - -o LogLevel=error
48
+ - -o UserKnownHostsFile=/dev/null
49
+ - -o StrictHostKeyChecking=no
50
+ - -o ServerAliveInterval=30
51
+ - -o ServerAliveCountMax=2
52
+ port: 22
53
+ prerequisites:
54
+ files:
55
+ - zscams/agent/keys/autoport.key
56
+ ports:
57
+ - 22
58
+ services: []
59
+ script: src/services/reverse_ssh.py
60
+ - args: []
61
+ health:
62
+ host: localhost
63
+ port: "{forwarder_port}"
64
+ name: Monitor Forwarder
65
+ custom_port_name: "forwarder_port"
66
+ params:
67
+ forwarder_port: "{forwarder_port}"
68
+ local_port: 4423
69
+ private_key: zscams/agent/keys/autoport.key
70
+ remote_host: 194.51.14.159
71
+ remote_port: 530
72
+ server_ssh_user: ssh_user
73
+ ssh_options:
74
+ - -o LogLevel=error
75
+ - -o UserKnownHostsFile=/dev/null
76
+ - -o StrictHostKeyChecking=no
77
+ - -o ServerAliveInterval=30
78
+ - -o ServerAliveCountMax=2
79
+ port: 530
80
+ prerequisites:
81
+ files:
82
+ - zscams/agent/keys/autoport.key
83
+ ports: []
84
+ services: []
85
+ script: src/services/ssh_forwarder.py
86
+ - args: []
87
+ health:
88
+ host: localhost
89
+ port: "{forwarder_port}"
90
+ name: Monitor Service
91
+ params:
92
+ equipment_name: "{equipment_name}"
93
+ equipment_type: "{equipment_type}"
94
+ remote_host: localhost
95
+ remote_port: "{forwarder_port}"
96
+ service_name: Zscaler-AppConnector
97
+ port: "{forwarder_port}"
98
+ prerequisites:
99
+ files: []
100
+ ports:
101
+ - "{forwarder_port}"
102
+ services: []
103
+ script: src/services/system_monitor.py
@@ -0,0 +1,12 @@
1
+ [Unit]
2
+ Description=ZSCAMs Service
3
+ After=network.target
4
+
5
+ [Service]
6
+ ExecStart={python_exec} -m zscams
7
+ Restart=always
8
+ User={user_to_run_as}
9
+ Environment="PYTHONPATH={pythonpath}"
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
@@ -0,0 +1,73 @@
1
+ import os
2
+ from pathlib import Path
3
+ import sysconfig
4
+ import sys
5
+ from typing import cast
6
+ from zscams.agent.src.core.backend.client import backend_client
7
+ from zscams.agent.src.support.configuration import reinitialize
8
+ from zscams.agent.src.support.logger import get_logger
9
+ from zscams.agent.src.support.os import create_system_user, install_systemd_service
10
+ from zscams.agent.src.support.ssh import add_to_authorized_keys
11
+ from zscams.agent.src.support.cli import prompt
12
+
13
+ logger = get_logger("bootstrap")
14
+
15
+
16
+ def bootstrap():
17
+ """Ensure the agent is bootstrapped with the backend."""
18
+
19
+ if backend_client.is_bootstrapped():
20
+ logger.info("Agent ID %s is already bootstrapped.", backend_client.agent_id)
21
+ return
22
+
23
+ username = input("Username: ")
24
+ totp = input("One Time Password (OTP): ")
25
+
26
+ backend_client.login(username, totp)
27
+
28
+ customer_name = prompt(
29
+ "Customer Name",
30
+ "Customer Name",
31
+ required=True,
32
+ startswith="",
33
+ )
34
+ connector_name = prompt(
35
+ "Connector Name",
36
+ "Connector Name [Unique name for this connector]",
37
+ required=True,
38
+ startswith="",
39
+ )
40
+ equipment_type = prompt(
41
+ "Equipment Type",
42
+ "Equipment Type [Can be ZPA|VZEN|PSE]",
43
+ required=True,
44
+ startswith="",
45
+ )
46
+ equipment_name = f"{equipment_type.lower()}-{customer_name.lower()}-{connector_name.lower()}"
47
+ enforced_id = prompt("Enforced ID", "Enforced Agent ID")
48
+ reinitialize(equipment_name=equipment_name,equipment_type=equipment_type)
49
+ cm_info = backend_client.bootstrap(equipment_name, enforced_id or None)
50
+
51
+ sys_user = cast(str, cm_info.get("ssh_user"))
52
+
53
+ create_system_user(sys_user)
54
+ add_to_authorized_keys(sys_user, cm_info.get("server_ssh_pub_key"))
55
+ install_zscams_systemd_service(sys_user)
56
+
57
+
58
+ def install_zscams_systemd_service(user_to_run_as: str):
59
+
60
+ data = {
61
+ "pythonpath": sysconfig.get_paths()["purelib"],
62
+ "python_exec": sys.executable,
63
+ "user_to_run_as": user_to_run_as,
64
+ }
65
+ import zscams
66
+ BASE_DIR = Path(zscams.__file__).resolve().parent
67
+ template_path = f"{BASE_DIR}/agent/configuration/service.j2"
68
+ with open(template_path) as f:
69
+ template = f.read()
70
+
71
+ rendered_config = template.format(**data)
72
+
73
+ install_systemd_service("zscams.service", rendered_config)
@@ -7,7 +7,13 @@ from typing import Optional, cast
7
7
 
8
8
  from .exceptions import AgentBootstrapError
9
9
 
10
- from zscams.agent.src.support.configuration import CONFIG_PATH, ROOT_PATH, get_config
10
+ from zscams.agent.src.support.configuration import (
11
+ CONFIG_PATH,
12
+ ROOT_PATH,
13
+ get_config,
14
+ override_config,
15
+ )
16
+ from zscams.agent.src.support.yaml import resolve_placeholders, assert_no_placeholders_left
11
17
  from zscams.agent.src.support.mac import get_mac_address
12
18
  from zscams.agent.src.support.filesystem import resolve_path, ensure_dir, is_file_exists
13
19
  from zscams.agent.src.support.network import get_local_hostname, get_local_ip_address
@@ -68,6 +74,12 @@ class BackendClient:
68
74
 
69
75
  self.logger.info("Generated the private key at %s", private_key_path)
70
76
 
77
+ common_name = (
78
+ f"{equipment_name}.orangecyberdefense.com"
79
+ if equipment_name
80
+ else csr_info.get("default_common_name")
81
+ )
82
+
71
83
  ip = get_local_ip_address()
72
84
  csr = generate_csr_from_private_key(
73
85
  private_key_content,
@@ -75,7 +87,7 @@ class BackendClient:
75
87
  csr_info.get("state"),
76
88
  csr_info.get("locality"),
77
89
  csr_info.get("organization"),
78
- csr_info.get("common_name"),
90
+ common_name,
79
91
  )
80
92
 
81
93
  payload = {
@@ -85,7 +97,7 @@ class BackendClient:
85
97
  "equipment_name": equipment_name,
86
98
  "csr": csr,
87
99
  "enforced_id": enforced_id,
88
- "services": [service.get("name") for service in self.services_config],
100
+ "services": [service.get("name") for service in self.services_config if service.get("custom_port_name", None)],
89
101
  "blacklist_ports": self.bootstrap_info.get("blacklist_ports", []),
90
102
  "cert_issuer": self.bootstrap_info.get("cert_issuer", None),
91
103
  }
@@ -111,14 +123,17 @@ class BackendClient:
111
123
  self.logger.info("Signed the cert")
112
124
  self.logger.debug("Signed cert response: %s", json.dumps(res_json, indent=2))
113
125
 
114
- ca_chain: list[str] = res_json.get("response", {}).get("ca_chain", [])
115
- signed_cert: str = res_json.get("response", {}).get("signed_certificate", [])
126
+ customer_machine = res_json.get("response", {})
127
+ ca_chain: list[str] = customer_machine.get("ca_chain", [])
128
+ signed_cert: str = customer_machine.get("signed_certificate", [])
116
129
  self._write_certificates(ca_chain, signed_cert)
117
130
 
118
131
  # To cache the machine info
119
132
  self.get_machine_info(ignore_cache=True)
120
133
 
121
- return res_json
134
+ self.__override_config_services_ports(customer_machine.get("services", []))
135
+
136
+ return customer_machine
122
137
 
123
138
  def get_machine_info(self, ignore_cache: bool = False):
124
139
  """Get machine information from the backend."""
@@ -237,6 +252,30 @@ class BackendClient:
237
252
 
238
253
  def __prepare_path(self, path):
239
254
  return f"{self.url}/{path.lstrip('/')}"
255
+
256
+ def __override_config_services_ports(self, cm_services: list[dict]):
257
+ self.logger.debug("Overriding configuration services ports...")
258
+
259
+ config = get_config()
260
+ custom_ports = {}
261
+ for cm_service in cm_services:
262
+ for cfg_service_idx, cfg_service in enumerate(config.get("services", [])):
263
+ if cm_service.get("name") == cfg_service.get("name"):
264
+
265
+ if not config["services"][cfg_service_idx]["params"]:
266
+ config["services"][cfg_service_idx]["params"] = {}
267
+
268
+ port_field_name = cfg_service.get("custom_port_name", None)
269
+ if port_field_name:
270
+ custom_ports[port_field_name] = cm_service.get("port")
271
+ config["services"][cfg_service_idx]["params"][port_field_name] = (
272
+ cm_service.get("port")
273
+ )
274
+ resolve_placeholders(config, custom_ports)
275
+ assert_no_placeholders_left(config)
276
+ self.logger.debug("Done overriding the configurations")
277
+
278
+ return override_config(config)
240
279
 
241
280
 
242
281
  backend_client = BackendClient()
@@ -1,4 +1,4 @@
1
- from zscams.agent.src.core.api.backend.client import backend_client
1
+ from zscams.agent.src.core.backend.client import backend_client
2
2
  from zscams.agent.src.support.logger import get_logger
3
3
 
4
4
  logger = get_logger("agent_machine_info")