Skip to content

Commit 1841fb1

Browse files
authored
Merge pull request #676 from coreemu/develop
Develop merge for 8.2.0
2 parents bcf7429 + d7b2c3c commit 1841fb1

32 files changed

+611
-707
lines changed

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## 2022-03-21 CORE 8.2.0
2+
3+
* core-gui
4+
* improved failed starts to trigger runtime to allow node investigation
5+
* core-daemon
6+
* improved default service loading to use a full import path
7+
* updated session instantiation to always set to a runtime state
8+
* core-cli
9+
* \#672 - fixed xml loading
10+
* \#578 - restored json flag and added geo output to session overview
11+
* Documentation
12+
* updated emane example and documentation
13+
* improved table markdown
14+
115
## 2022-02-18 CORE 8.1.0
216

317
* Installation

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ source ~/.bashrc
3232
# Ubuntu
3333
inv install
3434
# CentOS
35-
./install.sh -p /usr
35+
inv install -p /usr
3636
```
3737

3838
## Documentation & Support

configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Process this file with autoconf to produce a configure script.
33

44
# this defines the CORE version number, must be static for AC_INIT
5-
AC_INIT(core, 8.1.0)
5+
AC_INIT(core, 8.2.0)
66

77
# autoconf and automake initialization
88
AC_CONFIG_SRCDIR([netns/version.h.in])

daemon/core/api/grpc/wrappers.py

+9
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,15 @@ def from_proto(cls, proto: core_pb2.SessionSummary) -> "SessionSummary":
637637
dir=proto.dir,
638638
)
639639

640+
def to_proto(self) -> core_pb2.SessionSummary:
641+
return core_pb2.SessionSummary(
642+
id=self.id,
643+
state=self.state.value,
644+
nodes=self.nodes,
645+
file=self.file,
646+
dir=self.dir,
647+
)
648+
640649

641650
@dataclass
642651
class Hook:

daemon/core/configservice/base.py

+22-6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class ConfigServiceBootError(Exception):
4343
pass
4444

4545

46+
class ConfigServiceTemplateError(Exception):
47+
pass
48+
49+
4650
@dataclass
4751
class ShadowDir:
4852
path: str
@@ -316,7 +320,13 @@ def get_templates(self) -> Dict[str, str]:
316320
elif self.templates.has_template(template_path):
317321
template = self.templates.get_template(template_path).source
318322
else:
319-
template = self.get_text_template(file)
323+
try:
324+
template = self.get_text_template(file)
325+
except Exception as e:
326+
raise ConfigServiceTemplateError(
327+
f"node({self.node.name}) service({self.name}) file({file}) "
328+
f"failure getting template: {e}"
329+
)
320330
template = self.clean_text(template)
321331
templates[file] = template
322332
return templates
@@ -340,7 +350,13 @@ def create_files(self) -> None:
340350
elif self.templates.has_template(template_path):
341351
rendered = self.render_template(template_path, data)
342352
else:
343-
text = self.get_text_template(file)
353+
try:
354+
text = self.get_text_template(file)
355+
except Exception as e:
356+
raise ConfigServiceTemplateError(
357+
f"node({self.node.name}) service({self.name}) file({file}) "
358+
f"failure getting template: {e}"
359+
)
344360
rendered = self.render_text(text, data)
345361
self.node.create_file(file_path, rendered)
346362

@@ -429,20 +445,20 @@ def render_text(self, text: str, data: Dict[str, Any] = None) -> str:
429445
f"{exceptions.text_error_template().render_unicode()}"
430446
)
431447

432-
def render_template(self, basename: str, data: Dict[str, Any] = None) -> str:
448+
def render_template(self, template_path: str, data: Dict[str, Any] = None) -> str:
433449
"""
434450
Renders file based template providing all associated data to template.
435451
436-
:param basename: base name for file to render
452+
:param template_path: path of file to render
437453
:param data: service specific defined data for template
438454
:return: rendered template
439455
"""
440456
try:
441-
template = self.templates.get_template(basename)
457+
template = self.templates.get_template(template_path)
442458
return self._render(template, data)
443459
except Exception:
444460
raise CoreError(
445-
f"node({self.node.name}) service({self.name}) "
461+
f"node({self.node.name}) service({self.name}) file({template_path})"
446462
f"{exceptions.text_error_template().render_template()}"
447463
)
448464

daemon/core/emulator/coreemu.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from pathlib import Path
77
from typing import Dict, List, Type
88

9-
import core.services
109
from core import utils
1110
from core.configservice.manager import ConfigServiceManager
1211
from core.emane.modelmanager import EmaneModelManager
@@ -92,7 +91,7 @@ def _load_services(self) -> None:
9291
:return: nothing
9392
"""
9493
# load default services
95-
self.service_errors = core.services.load()
94+
self.service_errors = ServiceManager.load_locals()
9695
# load custom services
9796
service_paths = self.config.get("custom_services_dir")
9897
logger.debug("custom service paths: %s", service_paths)

daemon/core/emulator/session.py

+12-34
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,11 @@ def add_hook(
694694
self.run_hook(hook)
695695

696696
def add_node_file(
697-
self, node_id: int, src_path: Path, file_path: Path, data: str
697+
self,
698+
node_id: int,
699+
src_path: Optional[Path],
700+
file_path: Path,
701+
data: Optional[str],
698702
) -> None:
699703
"""
700704
Add a file to a node.
@@ -707,7 +711,7 @@ def add_node_file(
707711
"""
708712
node = self.get_node(node_id, CoreNode)
709713
if src_path is not None:
710-
node.addfile(src_path, file_path)
714+
node.copy_file(src_path, file_path)
711715
elif data is not None:
712716
node.create_file(file_path, data)
713717

@@ -1173,34 +1177,30 @@ def instantiate(self) -> List[Exception]:
11731177
11741178
:return: list of service boot errors during startup
11751179
"""
1180+
if self.state == EventTypes.RUNTIME_STATE:
1181+
logger.warning("ignoring instantiate, already in runtime state")
1182+
return []
11761183
# write current nodes out to session directory file
11771184
self.write_nodes()
1178-
11791185
# create control net interfaces and network tunnels
11801186
# which need to exist for emane to sync on location events
11811187
# in distributed scenarios
11821188
self.add_remove_control_net(0, remove=False)
1183-
11841189
# initialize distributed tunnels
11851190
self.distributed.start()
1186-
11871191
# instantiate will be invoked again upon emane configure
11881192
if self.emane.startup() == EmaneState.NOT_READY:
11891193
return []
1190-
11911194
# boot node services and then start mobility
11921195
exceptions = self.boot_nodes()
11931196
if not exceptions:
11941197
self.mobility.startup()
1195-
11961198
# notify listeners that instantiation is complete
11971199
event = EventData(event_type=EventTypes.INSTANTIATION_COMPLETE)
11981200
self.broadcast_event(event)
1199-
1200-
# assume either all nodes have booted already, or there are some
1201-
# nodes on slave servers that will be booted and those servers will
1202-
# send a node status response message
1203-
self.check_runtime()
1201+
# startup event loop
1202+
self.event_loop.run()
1203+
self.set_state(EventTypes.RUNTIME_STATE, send_event=True)
12041204
return exceptions
12051205

12061206
def get_node_count(self) -> int:
@@ -1222,28 +1222,6 @@ def get_node_count(self) -> int:
12221222
count += 1
12231223
return count
12241224

1225-
def check_runtime(self) -> None:
1226-
"""
1227-
Check if we have entered the runtime state, that all nodes have been
1228-
started and the emulation is running. Start the event loop once we
1229-
have entered runtime (time=0).
1230-
1231-
:return: nothing
1232-
"""
1233-
# this is called from instantiate() after receiving an event message
1234-
# for the instantiation state
1235-
logger.debug(
1236-
"session(%s) checking if not in runtime state, current state: %s",
1237-
self.id,
1238-
self.state.name,
1239-
)
1240-
if self.state == EventTypes.RUNTIME_STATE:
1241-
logger.info("valid runtime state found, returning")
1242-
return
1243-
# start event loop and set to runtime
1244-
self.event_loop.run()
1245-
self.set_state(EventTypes.RUNTIME_STATE, send_event=True)
1246-
12471225
def data_collect(self) -> None:
12481226
"""
12491227
Tear down a running session. Stop the event loop and any running

daemon/core/errors.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class CoreCommandError(subprocess.CalledProcessError):
1111

1212
def __str__(self) -> str:
1313
return (
14-
f"Command({self.cmd}), Status({self.returncode}):\n"
14+
f"command({self.cmd}), status({self.returncode}):\n"
1515
f"stdout: {self.output}\nstderr: {self.stderr}"
1616
)
1717

daemon/core/gui/toolbar.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,13 @@ def click_start(self) -> None:
304304
task.start()
305305

306306
def start_callback(self, result: bool, exceptions: List[str]) -> None:
307-
if result:
308-
self.set_runtime()
309-
self.app.core.show_mobility_players()
310-
else:
311-
enable_buttons(self.design_frame, enabled=True)
312-
if exceptions:
313-
message = "\n".join(exceptions)
314-
self.app.show_exception_data(
315-
"Start Exception", "Session failed to start", message
316-
)
307+
self.set_runtime()
308+
self.app.core.show_mobility_players()
309+
if not result and exceptions:
310+
message = "\n".join(exceptions)
311+
self.app.show_exception_data(
312+
"Start Exception", "Session failed to start", message
313+
)
317314

318315
def set_runtime(self) -> None:
319316
enable_buttons(self.runtime_frame, enabled=True)

0 commit comments

Comments
 (0)