rtems-proxy 0.6.3__tar.gz → 1.0.0__tar.gz
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.
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/PKG-INFO +1 -1
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/requirements.txt +1 -1
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/__main__.py +66 -4
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/_version.py +2 -2
- rtems_proxy-1.0.0/src/rtems_proxy/configure.py +48 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/copy.py +6 -12
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/rsync.sh.jinja +1 -1
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/telnet.py +67 -6
- rtems_proxy-1.0.0/src/rtems_proxy/trace.py +35 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy.egg-info/PKG-INFO +1 -1
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy.egg-info/SOURCES.txt +2 -1
- rtems_proxy-0.6.3/proxy-start.sh +0 -25
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.copier-answers.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.devcontainer/devcontainer.json +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/CONTRIBUTING.md +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/ISSUE_TEMPLATE/issue.md +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/actions/install_requirements/action.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/dependabot.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/pages/index.html +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/pages/make_switcher.py +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/_check.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/_dist.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/_pypi.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/_release.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/_test.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/_tox.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/workflows/ci.yml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.gitignore +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.pre-commit-config.yaml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.vscode/extensions.json +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.vscode/launch.json +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.vscode/settings.json +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.vscode/tasks.json +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/Dockerfile +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/LICENSE +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/README.md +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/pyproject.toml +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/setup.cfg +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/__init__.py +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/globals.py +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy/utils.py +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy.egg-info/dependency_links.txt +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy.egg-info/entry_points.txt +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy.egg-info/requires.txt +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/src/rtems_proxy.egg-info/top_level.txt +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/tests/conftest.py +0 -0
- {rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/tests/test_cli.py +0 -0
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
from pathlib import Path
|
|
3
|
+
from time import sleep
|
|
2
4
|
|
|
3
5
|
import typer
|
|
4
6
|
from jinja2 import Template
|
|
5
7
|
from ruamel.yaml import YAML
|
|
6
8
|
|
|
9
|
+
from rtems_proxy.trace import parse_stack_trace
|
|
10
|
+
from rtems_proxy.utils import run_command
|
|
11
|
+
|
|
7
12
|
from . import __version__
|
|
13
|
+
from .configure import Configure
|
|
8
14
|
from .copy import copy_rtems
|
|
9
15
|
from .globals import GLOBALS
|
|
10
|
-
from .telnet import ioc_connect, report
|
|
16
|
+
from .telnet import ioc_connect, motboot_connect, report
|
|
11
17
|
|
|
12
18
|
__all__ = ["main"]
|
|
13
19
|
|
|
@@ -46,6 +52,9 @@ def start(
|
|
|
46
52
|
reboot: bool = typer.Option(
|
|
47
53
|
True, "--reboot/--no-reboot", help="reboot the IOC first"
|
|
48
54
|
),
|
|
55
|
+
raise_errors: bool = typer.Option(
|
|
56
|
+
True, "--raise-errors/--no-raise-errors", help="raise errors instead of exiting"
|
|
57
|
+
),
|
|
49
58
|
):
|
|
50
59
|
"""
|
|
51
60
|
Starts an RTEMS IOC. Places the IOC binaries in the expected location,
|
|
@@ -70,7 +79,9 @@ def start(
|
|
|
70
79
|
if copy:
|
|
71
80
|
copy_rtems()
|
|
72
81
|
if connect:
|
|
73
|
-
ioc_connect(
|
|
82
|
+
ioc_connect(
|
|
83
|
+
GLOBALS.RTEMS_CONSOLE, reboot=reboot, attach=True, raise_errors=raise_errors
|
|
84
|
+
)
|
|
74
85
|
else:
|
|
75
86
|
report("IOC console connection disabled. ")
|
|
76
87
|
|
|
@@ -154,8 +165,59 @@ def dev(
|
|
|
154
165
|
typer.echo(f"\n\nPlease first source {script_file} to set up the dev environment.")
|
|
155
166
|
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
|
|
168
|
+
@cli.command()
|
|
169
|
+
def configure(
|
|
170
|
+
debug: bool = typer.Option(False, help="use debug ioc binary"),
|
|
171
|
+
attach: bool = typer.Option(
|
|
172
|
+
False, help="attach to the IOC console after configuration"
|
|
173
|
+
),
|
|
174
|
+
):
|
|
175
|
+
"""
|
|
176
|
+
Configure the RTEMS IOC boot parameters
|
|
177
|
+
"""
|
|
178
|
+
telnet = motboot_connect(GLOBALS.RTEMS_CONSOLE)
|
|
179
|
+
config = Configure(telnet, debug)
|
|
180
|
+
config.apply_settings()
|
|
181
|
+
telnet.close()
|
|
182
|
+
if attach:
|
|
183
|
+
run_command(telnet.command)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@cli.command()
|
|
187
|
+
def stress():
|
|
188
|
+
"""
|
|
189
|
+
Stress test the IOC by constantly rebooting and checking for failed boot
|
|
190
|
+
|
|
191
|
+
Aborts and prints the time when a failed boot is detected
|
|
192
|
+
"""
|
|
193
|
+
try:
|
|
194
|
+
tries = 0
|
|
195
|
+
while True:
|
|
196
|
+
tries += 1
|
|
197
|
+
print(f">>>>>> REBOOT ATTEMPT {tries} <<<<<<<")
|
|
198
|
+
ioc_connect(
|
|
199
|
+
GLOBALS.RTEMS_CONSOLE, reboot=True, attach=False, raise_errors=True
|
|
200
|
+
)
|
|
201
|
+
sleep(5)
|
|
202
|
+
except Exception as e:
|
|
203
|
+
msg = f"\n\nIOC boot number {tries} failed at {datetime.now()}.\n\n"
|
|
204
|
+
raise RuntimeError(msg) from e
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@cli.command()
|
|
208
|
+
def trace(
|
|
209
|
+
trace_file: Path = typer.Argument(
|
|
210
|
+
...,
|
|
211
|
+
help="The path to the file containing the stack trace",
|
|
212
|
+
file_okay=True,
|
|
213
|
+
exists=True,
|
|
214
|
+
),
|
|
215
|
+
):
|
|
216
|
+
"""
|
|
217
|
+
Parse a stack trace from a RTEMS failure
|
|
218
|
+
"""
|
|
219
|
+
trace = trace_file.read_text()
|
|
220
|
+
parse_stack_trace(trace)
|
|
159
221
|
|
|
160
222
|
|
|
161
223
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Class to apply MOTBoot configuration to a VME crate.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .globals import GLOBALS
|
|
6
|
+
from .telnet import TelnetRTEMS
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Configure:
|
|
10
|
+
def __init__(self, telnet: TelnetRTEMS, debug: bool = False):
|
|
11
|
+
self.telnet = telnet
|
|
12
|
+
self.debug = debug
|
|
13
|
+
|
|
14
|
+
def apply_nvm(self, variable: str, value: str):
|
|
15
|
+
self.telnet.sendline(f"gevE {variable}")
|
|
16
|
+
self.telnet.expect(r"\(Blank line terminates input.\)")
|
|
17
|
+
self.telnet.sendline(value + "\r")
|
|
18
|
+
self.telnet.sendline("\r")
|
|
19
|
+
self.telnet.expect(r"\?")
|
|
20
|
+
self.telnet.sendline("Y\r")
|
|
21
|
+
|
|
22
|
+
def apply_settings(self):
|
|
23
|
+
nfs_mount = f"{GLOBALS.RTEMS_NFS_IP}:/iocs/{GLOBALS.IOC_NAME}:/epics"
|
|
24
|
+
ioc_bin = "ioc" if self.debug else "ioc.boot"
|
|
25
|
+
mot_boot = (
|
|
26
|
+
f"dla=malloc 0x4000000\r"
|
|
27
|
+
f"tftpGet -d/dev/enet1"
|
|
28
|
+
f" -f{GLOBALS.IOC_NAME.lower()}/ioc/bin/RTEMS-beatnik/{ioc_bin}"
|
|
29
|
+
f" -m{GLOBALS.RTEMS_IOC_NETMASK}"
|
|
30
|
+
f" -g{GLOBALS.RTEMS_IOC_GATEWAY}"
|
|
31
|
+
f" -s{GLOBALS.RTEMS_TFTP_IP}"
|
|
32
|
+
f" -c{GLOBALS.RTEMS_IOC_IP}"
|
|
33
|
+
f" -adla -r4\r"
|
|
34
|
+
f"go -a04000000\r"
|
|
35
|
+
f"reset"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
self.apply_nvm("mot-/dev/enet0-snma", GLOBALS.RTEMS_IOC_NETMASK)
|
|
39
|
+
self.apply_nvm("mot-/dev/enet0-gipa", GLOBALS.RTEMS_IOC_GATEWAY)
|
|
40
|
+
self.apply_nvm("mot-/dev/enet0-sipa", GLOBALS.RTEMS_NFS_IP)
|
|
41
|
+
self.apply_nvm("mot-/dev/enet0-cipa", GLOBALS.RTEMS_IOC_IP)
|
|
42
|
+
self.apply_nvm("mot-boot-device", "/dev/em1")
|
|
43
|
+
self.apply_nvm("mot-script-boot", mot_boot)
|
|
44
|
+
self.apply_nvm("rtems-client-name", GLOBALS.IOC_NAME)
|
|
45
|
+
self.apply_nvm("epics-script", "/epics/runtime/st.cmd")
|
|
46
|
+
self.apply_nvm("epics-nfsmount", nfs_mount)
|
|
47
|
+
# self.apply_nvm_variable("epics-ntpserver", "EPICS_TS_NTP_INET")
|
|
48
|
+
self.apply_nvm("mot-/dev/enet0-snma", GLOBALS.RTEMS_IOC_NETMASK)
|
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
functions for moving IOC assets into position for a remote IOC to access
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import re
|
|
6
5
|
import shutil
|
|
7
|
-
from pathlib import Path
|
|
8
6
|
|
|
9
7
|
from .globals import GLOBALS
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
def copy_rtems():
|
|
13
11
|
"""
|
|
14
|
-
Copy RTEMS
|
|
12
|
+
Copy RTEMS IOC binary and startup assets to a location where the RTEMS IOC
|
|
13
|
+
can access them
|
|
15
14
|
|
|
16
15
|
IMPORTANT: local_root and nfs_root are different perspectives on the same
|
|
17
16
|
folder.
|
|
@@ -23,7 +22,6 @@ def copy_rtems():
|
|
|
23
22
|
will look for them using NFS.
|
|
24
23
|
"""
|
|
25
24
|
local_root = GLOBALS.RTEMS_TFTP_PATH
|
|
26
|
-
nfs_root = Path("/iocs") / GLOBALS.IOC_NAME
|
|
27
25
|
|
|
28
26
|
# where to copy the Generic IOC folder to. This will contain the IOC binary
|
|
29
27
|
# and the files
|
|
@@ -32,10 +30,12 @@ def copy_rtems():
|
|
|
32
30
|
# st.cmd and ioc.db
|
|
33
31
|
dest_runtime = local_root / "runtime"
|
|
34
32
|
|
|
35
|
-
# TODO - perhaps do protocol files in this fashion for linux IOCs too,
|
|
36
|
-
# in which case this needs to go somewhere generic
|
|
37
33
|
protocol_folder = GLOBALS.RUNTIME / "protocol"
|
|
38
34
|
protocol_folder.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
|
|
36
|
+
# TODO - perhaps do protocol files in this fashion for linux IOCs too,
|
|
37
|
+
# in which case this needs to go somewhere generic
|
|
38
|
+
dest_ioc.mkdir(parents=True, exist_ok=True)
|
|
39
39
|
protocol_files = GLOBALS.SUPPORT.glob("**/*.proto*")
|
|
40
40
|
for proto_file in protocol_files:
|
|
41
41
|
dest = protocol_folder / proto_file.name
|
|
@@ -53,9 +53,3 @@ def copy_rtems():
|
|
|
53
53
|
GLOBALS.IOC.readlink() / folder, dest_ioc / folder, dirs_exist_ok=True
|
|
54
54
|
)
|
|
55
55
|
shutil.copytree(GLOBALS.RUNTIME, dest_runtime, dirs_exist_ok=True)
|
|
56
|
-
|
|
57
|
-
# because we moved the ioc files we need to fix up startup script paths
|
|
58
|
-
startup = dest_runtime / "st.cmd"
|
|
59
|
-
cmd_txt = startup.read_text()
|
|
60
|
-
cmd_txt = re.sub("/epics/", f"{str(nfs_root)}/", cmd_txt)
|
|
61
|
-
startup.write_text(cmd_txt)
|
|
@@ -48,7 +48,7 @@ while true; do
|
|
|
48
48
|
for i in 1 2 3 ; do
|
|
49
49
|
# repeat because inotify fires on the first change of several
|
|
50
50
|
# don't copy the huge ioc binary file with symbols
|
|
51
|
-
rsync -rim --
|
|
51
|
+
rsync -rim --delete /$RTEMS_TFTP_PATH/ \
|
|
52
52
|
"rsync://$RTEMS_TFTP_IP:12002/files/$IOC_NAME/"
|
|
53
53
|
sleep 1
|
|
54
54
|
done
|
|
@@ -36,8 +36,9 @@ class TelnetRTEMS:
|
|
|
36
36
|
IOC_CHECK = "\ntaskwdShow"
|
|
37
37
|
IOC_RESPONSE = "free nodes"
|
|
38
38
|
NO_CONNECTION = "Connection closed by foreign host"
|
|
39
|
+
FAIL_STRINGS = ["Exception", "exception", "RTEMS_FATAL_SOURCE_EXCEPTION"]
|
|
39
40
|
|
|
40
|
-
def __init__(self, host_and_port: str, ioc_reboot: bool):
|
|
41
|
+
def __init__(self, host_and_port: str, ioc_reboot: bool = False):
|
|
41
42
|
self._hostname, self._port = host_and_port.split(":")
|
|
42
43
|
self._ioc_reboot = ioc_reboot
|
|
43
44
|
self._child = None
|
|
@@ -91,6 +92,7 @@ class TelnetRTEMS:
|
|
|
91
92
|
while retries > 0:
|
|
92
93
|
try:
|
|
93
94
|
# see if we are in the IOC shell
|
|
95
|
+
sleep(0.5)
|
|
94
96
|
self._child.sendline(self.IOC_CHECK)
|
|
95
97
|
self._child.expect(self.IOC_RESPONSE, timeout=1)
|
|
96
98
|
except pexpect.exceptions.TIMEOUT:
|
|
@@ -136,6 +138,12 @@ class TelnetRTEMS:
|
|
|
136
138
|
# send space to boot the IOC
|
|
137
139
|
self._child.send(" ")
|
|
138
140
|
|
|
141
|
+
def wait_epics_prompt(self, timeout=50):
|
|
142
|
+
expects = self.FAIL_STRINGS + [self.IOC_STARTED]
|
|
143
|
+
index = self._child.expect(expects, timeout=timeout)
|
|
144
|
+
if index != len(self.FAIL_STRINGS):
|
|
145
|
+
raise RuntimeError(f"IOC boot failed - output included '{expects[index]}'")
|
|
146
|
+
|
|
139
147
|
def get_epics_prompt(self):
|
|
140
148
|
"""
|
|
141
149
|
Get to the IOC shell prompt, if the IOC is not already running, reboot
|
|
@@ -149,12 +157,12 @@ class TelnetRTEMS:
|
|
|
149
157
|
sleep(0.2)
|
|
150
158
|
self.reboot(RtemsState.IOC)
|
|
151
159
|
self.ioc_rebooted = True
|
|
152
|
-
self.
|
|
160
|
+
self.wait_epics_prompt()
|
|
153
161
|
else:
|
|
154
162
|
if self._ioc_reboot and not self.ioc_rebooted:
|
|
155
163
|
self.ioc_rebooted = True
|
|
156
164
|
self.reboot(RtemsState.IOC)
|
|
157
|
-
self.
|
|
165
|
+
self.wait_epics_prompt()
|
|
158
166
|
|
|
159
167
|
def get_boot_prompt(self):
|
|
160
168
|
"""
|
|
@@ -171,6 +179,20 @@ class TelnetRTEMS:
|
|
|
171
179
|
|
|
172
180
|
report("press enter for bootloader prompt")
|
|
173
181
|
|
|
182
|
+
def sendline(self, command: str) -> None:
|
|
183
|
+
"""
|
|
184
|
+
Send a command to the telnet session
|
|
185
|
+
"""
|
|
186
|
+
assert self._child, "must call connect before send"
|
|
187
|
+
self._child.sendline(command)
|
|
188
|
+
|
|
189
|
+
def expect(self, pattern, timeout=10) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Expect a pattern in the telnet session
|
|
192
|
+
"""
|
|
193
|
+
assert self._child, "must call connect before expect"
|
|
194
|
+
self._child.expect(pattern, timeout=timeout)
|
|
195
|
+
|
|
174
196
|
def close(self):
|
|
175
197
|
if self._child:
|
|
176
198
|
self._child.close()
|
|
@@ -187,7 +209,12 @@ def report(message):
|
|
|
187
209
|
print(f"\n>>>> {message} <<<<\n")
|
|
188
210
|
|
|
189
211
|
|
|
190
|
-
def ioc_connect(
|
|
212
|
+
def ioc_connect(
|
|
213
|
+
host_and_port: str,
|
|
214
|
+
reboot: bool = False,
|
|
215
|
+
attach: bool = True,
|
|
216
|
+
raise_errors: bool = False,
|
|
217
|
+
):
|
|
191
218
|
"""
|
|
192
219
|
Entrypoint to make a connection to an RTEMS IOC over telnet.
|
|
193
220
|
Once connected, enters an interactive user session with the IOC.
|
|
@@ -200,14 +227,48 @@ def ioc_connect(host_and_port: str, reboot: bool = False):
|
|
|
200
227
|
|
|
201
228
|
try:
|
|
202
229
|
telnet.connect()
|
|
230
|
+
|
|
231
|
+
# this will untangle a partially executed gevEdit command
|
|
232
|
+
for _ in range(3):
|
|
233
|
+
telnet.sendline("\r")
|
|
234
|
+
|
|
203
235
|
if reboot:
|
|
204
236
|
telnet.get_epics_prompt()
|
|
205
237
|
else:
|
|
206
238
|
report("Auto reboot disabled. Skipping reboot")
|
|
239
|
+
|
|
207
240
|
except (CannotConnect, pexpect.exceptions.TIMEOUT):
|
|
208
|
-
report("Connection failed
|
|
241
|
+
report("Connection failed, Exiting.")
|
|
209
242
|
telnet.close()
|
|
210
|
-
|
|
243
|
+
raise
|
|
244
|
+
|
|
245
|
+
except Exception as e:
|
|
246
|
+
# still show the remaining output
|
|
247
|
+
telnet.expect("_main_")
|
|
248
|
+
report(f"An error occurred: {e}")
|
|
211
249
|
telnet.close()
|
|
250
|
+
if raise_errors:
|
|
251
|
+
raise
|
|
252
|
+
|
|
253
|
+
telnet.close()
|
|
254
|
+
if attach:
|
|
212
255
|
report("Connecting to IOC console, hit enter for a prompt")
|
|
213
256
|
run_command(telnet.command)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def motboot_connect(host_and_port: str) -> TelnetRTEMS:
|
|
260
|
+
"""
|
|
261
|
+
Connect to the MOTBoot bootloader prompt, rebooting if needed.
|
|
262
|
+
|
|
263
|
+
Returns a TelnetRTEMS object that is connected to the MOTBoot bootloader
|
|
264
|
+
"""
|
|
265
|
+
telnet = TelnetRTEMS(host_and_port)
|
|
266
|
+
telnet.connect()
|
|
267
|
+
|
|
268
|
+
# this will untangle a partially executed gevEdit command
|
|
269
|
+
for _ in range(3):
|
|
270
|
+
telnet.sendline("\r")
|
|
271
|
+
|
|
272
|
+
telnet.get_boot_prompt()
|
|
273
|
+
|
|
274
|
+
return telnet
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Some functions to interpret a stack trace from a RTEMS failure
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from .globals import GLOBALS
|
|
8
|
+
from .utils import run_command
|
|
9
|
+
|
|
10
|
+
IP = re.compile(r"Stack Trace:\n *IP: *(0x[0-9a-f]*)")
|
|
11
|
+
STACK = re.compile(r"--\^ (0x[0-9a-f]*)")
|
|
12
|
+
symbols = GLOBALS.IOC / "bin" / "RTEMS-beatnik" / "ioc"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_stack_trace(trace: str):
|
|
16
|
+
"""
|
|
17
|
+
Parse a stack trace from a RTEMS failure
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
trace (str): log containing a stack trace
|
|
21
|
+
"""
|
|
22
|
+
ip = IP.findall(trace)
|
|
23
|
+
addrs = STACK.findall(trace)
|
|
24
|
+
|
|
25
|
+
print(f"IP: {ip[0]}\nStack {addrs}")
|
|
26
|
+
|
|
27
|
+
if len(ip) == 0 or len(addrs) == 0:
|
|
28
|
+
raise ValueError("Could not find a stack trace in the log")
|
|
29
|
+
elif len(ip) > 1:
|
|
30
|
+
raise ValueError("Multiple stack traces in the log")
|
|
31
|
+
|
|
32
|
+
addrs.reverse()
|
|
33
|
+
for addr in addrs:
|
|
34
|
+
run_command(f"rtems-addr2line {addr} -e {symbols}")
|
|
35
|
+
run_command(f"rtems-addr2line {ip[0]} -e {symbols}")
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
Dockerfile
|
|
5
5
|
LICENSE
|
|
6
6
|
README.md
|
|
7
|
-
proxy-start.sh
|
|
8
7
|
pyproject.toml
|
|
9
8
|
requirements.txt
|
|
10
9
|
.devcontainer/devcontainer.json
|
|
@@ -30,10 +29,12 @@ requirements.txt
|
|
|
30
29
|
src/rtems_proxy/__init__.py
|
|
31
30
|
src/rtems_proxy/__main__.py
|
|
32
31
|
src/rtems_proxy/_version.py
|
|
32
|
+
src/rtems_proxy/configure.py
|
|
33
33
|
src/rtems_proxy/copy.py
|
|
34
34
|
src/rtems_proxy/globals.py
|
|
35
35
|
src/rtems_proxy/rsync.sh.jinja
|
|
36
36
|
src/rtems_proxy/telnet.py
|
|
37
|
+
src/rtems_proxy/trace.py
|
|
37
38
|
src/rtems_proxy/utils.py
|
|
38
39
|
src/rtems_proxy.egg-info/PKG-INFO
|
|
39
40
|
src/rtems_proxy.egg-info/SOURCES.txt
|
rtems_proxy-0.6.3/proxy-start.sh
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
set -x
|
|
4
|
-
|
|
5
|
-
# This is the folder the PVC for the nfsv2tftp shared volume is mounted into.
|
|
6
|
-
export RTEMS_TFTP_PATH=${RTEMS_TFTP_PATH:-/nfsv2-tftp}
|
|
7
|
-
|
|
8
|
-
if [ ! -d ${RTEMS_TFTP_PATH} ]; then
|
|
9
|
-
echo "ERROR: No PVC folder found."
|
|
10
|
-
# make a folder for testing outside of the cluster
|
|
11
|
-
mkdir -p ${RTEMS_TFTP_PATH}
|
|
12
|
-
fi
|
|
13
|
-
|
|
14
|
-
# copy the IOC instance's runtime assets into the shared volume
|
|
15
|
-
cp -rL /epics/ioc ${RTEMS_TFTP_PATH}
|
|
16
|
-
cp -r /epics/runtime ${RTEMS_TFTP_PATH}
|
|
17
|
-
# move binary to the root for shorter paths
|
|
18
|
-
mv ${RTEMS_TFTP_PATH}/ioc/bin/*/ioc.boot ${RTEMS_TFTP_PATH}
|
|
19
|
-
# fix up the paths in st.cmd
|
|
20
|
-
sed -i "s|/epics/|/iocs/${IOC_LOCATION}/${IOC_NAME}/|" ${RTEMS_TFTP_PATH}/runtime/st.cmd
|
|
21
|
-
|
|
22
|
-
# keep the container running ...
|
|
23
|
-
while true; do
|
|
24
|
-
sleep 2
|
|
25
|
-
done
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rtems_proxy-0.6.3 → rtems_proxy-1.0.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|