Skip to content

Commit 2682ddf

Browse files
authored
Merge pull request #904 from coreemu/develop
CORE 9.2.0
2 parents f7d2e85 + ca1e497 commit 2682ddf

File tree

126 files changed

+1846
-1640
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+1846
-1640
lines changed

.github/workflows/daemon-checks.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ jobs:
77
runs-on: ubuntu-22.04
88
steps:
99
- uses: actions/checkout@v1
10-
- name: Set up Python 3.9
10+
- name: Set up Python
1111
uses: actions/setup-python@v1
1212
with:
13-
python-version: 3.9
13+
python-version: 3.10.16
1414
- name: install poetry
1515
run: |
1616
python -m pip install --upgrade pip
@@ -22,15 +22,15 @@ jobs:
2222
- name: isort
2323
run: |
2424
cd daemon
25-
poetry run isort -c -df
25+
poetry run isort -c --df .
2626
- name: black
2727
run: |
2828
cd daemon
2929
poetry run black --check .
3030
- name: flake8
3131
run: |
3232
cd daemon
33-
poetry run flake8
33+
poetry run flake8 .
3434
- name: grpc
3535
run: |
3636
cd daemon/proto

CHANGELOG.md

+21
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
## 2025-02-11 CORE 9.2.0
2+
3+
* Installation
4+
* python3.10+ now required
5+
* updated various dependencies to help avoid the need to build them from source
6+
* Documentation
7+
* docker run examples updated
8+
* gRPC edit link examples corrected
9+
* updated install examples
10+
* updated tutorials to use absolute paths
11+
* updated custom service example
12+
* core-daemon
13+
* removed use of killall in provided services
14+
* \#860 - fixed core-cli xml --start to run control network
15+
* \#881 - EMANE TDMA fails to start
16+
* \#888 - fixed service start validation
17+
* \#902 - link deletion removing incorrect nodes
18+
* core-gui
19+
* fixed bug when changing icons on a loaded scenario
20+
* \#897 - fixed to properly exit when closing on a running session
21+
122
## 2024-07-04 CORE 9.1.0
223

324
* Installation

Makefile.am

-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ fpm -s dir -t rpm -n core \
100100
-d "tk" \
101101
-d "procps-ng" \
102102
-d "bash >= 3.0" \
103-
-d "ebtables" \
104103
-d "iproute" \
105104
-d "libev" \
106105
-d "net-tools" \
@@ -133,7 +132,6 @@ fpm -s dir -t deb -n core \
133132
-d "procps" \
134133
-d "libc6 >= 2.14" \
135134
-d "bash >= 3.0" \
136-
-d "ebtables" \
137135
-d "iproute2" \
138136
-d "libev4" \
139137
-d "nftables" \

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
CORE: Common Open Research Emulator
44

5-
Copyright (c)2005-2023 the Boeing Company.
5+
Copyright (c)2005-2025 the Boeing Company.
66

77
See the LICENSE file included in this distribution.
88

configure.ac

+3-3
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, 9.1.0)
5+
AC_INIT(core, 9.2.0)
66

77
# autoconf and automake initialization
88
AC_CONFIG_SRCDIR([netns/version.h.in])
@@ -79,8 +79,8 @@ if test "x$enable_daemon" = "xyes"; then
7979
want_python=yes
8080
want_linux_netns=yes
8181

82-
AM_PATH_PYTHON(3.9)
83-
AS_IF([$PYTHON -m grpc_tools.protoc -h &> /dev/null], [], [AC_MSG_ERROR([please install python grpcio-tools])])
82+
AM_PATH_PYTHON(3.10)
83+
AS_IF([./venv/bin/python -m grpc_tools.protoc -h &> /dev/null], [], [AC_MSG_ERROR([grpc tools must be setup in venv, try setup.sh])])
8484

8585
AC_CHECK_PROG(sysctl_path, sysctl, $as_dir, no, $SEARCHPATH)
8686
if test "x$sysctl_path" = "xno" ; then

daemon/.pre-commit-config.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ repos:
33
hooks:
44
- id: isort
55
name: isort
6-
stages: [commit]
6+
stages: [pre-commit]
77
language: system
8-
entry: bash -c 'cd daemon && poetry run isort --atomic -y'
8+
entry: bash -c 'cd daemon && poetry run isort --atomic .'
99
types: [python]
1010

1111
- id: black
1212
name: black
13-
stages: [commit]
13+
stages: [pre-commit]
1414
language: system
1515
entry: bash -c 'cd daemon && poetry run black .'
1616
types: [python]
1717

1818
- id: flake8
1919
name: flake8
20-
stages: [commit]
20+
stages: [pre-commit]
2121
language: system
22-
entry: bash -c 'cd daemon && poetry run flake8'
22+
entry: bash -c 'cd daemon && poetry run flake8 .'
2323
types: [python]

daemon/core/api/grpc/client.py

+19-17
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from contextlib import contextmanager
99
from pathlib import Path
1010
from queue import Queue
11-
from typing import Any, Optional
11+
from typing import Any
1212

1313
import grpc
1414

@@ -57,7 +57,7 @@
5757
class MoveNodesStreamer:
5858
def __init__(self, session_id: int, source: str = None) -> None:
5959
self.session_id: int = session_id
60-
self.source: Optional[str] = source
60+
self.source: str | None = source
6161
self.queue: SetQueue = SetQueue()
6262

6363
def send_position(self, node_id: int, x: float, y: float) -> None:
@@ -83,8 +83,8 @@ def send(self, request: wrappers.MoveNodesRequest) -> None:
8383
def stop(self) -> None:
8484
self.queue.put(None)
8585

86-
def next(self) -> Optional[core_pb2.MoveNodesRequest]:
87-
request: Optional[wrappers.MoveNodesRequest] = self.queue.get()
86+
def next(self) -> core_pb2.MoveNodesRequest | None:
87+
request: wrappers.MoveNodesRequest | None = self.queue.get()
8888
if request:
8989
return request.to_proto()
9090
else:
@@ -98,11 +98,11 @@ class EmanePathlossesStreamer:
9898
def __init__(self) -> None:
9999
self.queue: Queue = Queue()
100100

101-
def send(self, request: Optional[wrappers.EmanePathlossesRequest]) -> None:
101+
def send(self, request: wrappers.EmanePathlossesRequest | None) -> None:
102102
self.queue.put(request)
103103

104-
def next(self) -> Optional[emane_pb2.EmanePathlossesRequest]:
105-
request: Optional[wrappers.EmanePathlossesRequest] = self.queue.get()
104+
def next(self) -> emane_pb2.EmanePathlossesRequest | None:
105+
request: wrappers.EmanePathlossesRequest | None = self.queue.get()
106106
if request:
107107
return request.to_proto()
108108
else:
@@ -116,11 +116,11 @@ class EmaneEventsStreamer:
116116
def __init__(self) -> None:
117117
self.queue: Queue = Queue()
118118

119-
def send(self, request: Optional[wrappers.EmaneEventsRequest]) -> None:
119+
def send(self, request: wrappers.EmaneEventsRequest | None) -> None:
120120
self.queue.put(request)
121121

122-
def next(self) -> Optional[emane_pb2.EmaneEventsRequest]:
123-
request: Optional[wrappers.EmaneEventsRequest] = self.queue.get()
122+
def next(self) -> emane_pb2.EmaneEventsRequest | None:
123+
request: wrappers.EmaneEventsRequest | None = self.queue.get()
124124
if request:
125125
return request.to_proto()
126126
else:
@@ -133,6 +133,10 @@ def iter(self):
133133
class InterfaceHelper:
134134
"""
135135
Convenience class to help generate IP4 and IP6 addresses for gRPC clients.
136+
137+
This is not a requirement to use, as interfaces can be created manually as
138+
desired. Node IDs are used to index into a subnet, so if the subnet is tool small
139+
of a pool of addresses and the node ID is too high, there will be a failure.
136140
"""
137141

138142
def __init__(self, ip4_prefix: str = None, ip6_prefix: str = None) -> None:
@@ -242,8 +246,8 @@ def __init__(self, address: str = "localhost:50051", proxy: bool = False) -> Non
242246
:param address: grpc server address to connect to
243247
"""
244248
self.address: str = address
245-
self.stub: Optional[core_pb2_grpc.CoreApiStub] = None
246-
self.channel: Optional[grpc.Channel] = None
249+
self.stub: core_pb2_grpc.CoreApiStub | None = None
250+
self.channel: grpc.Channel | None = None
247251
self.proxy: bool = proxy
248252

249253
def start_session(
@@ -830,7 +834,7 @@ def open_xml(self, file_path: Path, start: bool = False) -> tuple[bool, int]:
830834
Load a local scenario XML file to open as a new session.
831835
832836
:param file_path: path of scenario XML file
833-
:param start: tuple of result and session id when successful
837+
:param start: instantiate session if true, false for a definition state
834838
:return: tuple of result and session id
835839
"""
836840
with file_path.open("r") as f:
@@ -934,7 +938,7 @@ def get_emane_event_channel(
934938
response = self.stub.GetEmaneEventChannel(request)
935939
return wrappers.EmaneEventChannel.from_proto(response)
936940

937-
def execute_script(self, script: str, args: str) -> Optional[int]:
941+
def execute_script(self, script: str, args: str) -> int | None:
938942
"""
939943
Executes a python script given context of the current CoreEmu object.
940944
@@ -1073,9 +1077,7 @@ def create_service(
10731077
recreate: bool = False,
10741078
) -> bool:
10751079
request = CreateServiceRequest(
1076-
service=service.to_proto(),
1077-
templates=templates,
1078-
recreate=recreate,
1080+
service=service.to_proto(), templates=templates, recreate=recreate
10791081
)
10801082
response = self.stub.CreateService(request)
10811083
return response.result

daemon/core/api/grpc/events.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import logging
22
from collections.abc import Iterable
33
from queue import Empty, Queue
4-
from typing import Optional
54

65
from core.api.grpc import core_pb2, grpcutils
76
from core.api.grpc.grpcutils import convert_link_data
@@ -113,7 +112,7 @@ def add_handlers(self) -> None:
113112
if core_pb2.EventType.SESSION in self.event_types:
114113
self.session.broadcast_manager.add_handler(EventData, self.queue.put)
115114

116-
def process(self) -> Optional[core_pb2.Event]:
115+
def process(self) -> core_pb2.Event | None:
117116
"""
118117
Process the next event in the queue.
119118

daemon/core/api/grpc/grpcutils.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
import time
33
from pathlib import Path
4-
from typing import Any, Optional, Union
4+
from typing import Any
55

66
import grpc
77
from google.protobuf.internal.containers import RepeatedCompositeFieldContainer
@@ -248,7 +248,7 @@ def convert_session_options(session: Session) -> dict[str, common_pb2.ConfigOpti
248248

249249
def get_config_options(
250250
config: dict[str, str],
251-
configurable_options: Union[ConfigurableOptions, type[ConfigurableOptions]],
251+
configurable_options: ConfigurableOptions | type[ConfigurableOptions],
252252
) -> dict[str, common_pb2.ConfigOption]:
253253
"""
254254
Retrieve configuration options in a form that is used by the grpc server.
@@ -348,8 +348,7 @@ def get_node_proto(
348348
if not service.custom_templates and not service.custom_config:
349349
continue
350350
service_configs[service.name] = services_pb2.ServiceConfig(
351-
templates=service.custom_templates,
352-
config=service.custom_config,
351+
templates=service.custom_templates, config=service.custom_config
353352
)
354353
return core_pb2.Node(
355354
id=node.id,
@@ -525,9 +524,9 @@ def convert_options_proto(options: core_pb2.LinkOptions) -> LinkOptions:
525524

526525
def convert_link(
527526
node1: NodeBase,
528-
iface1: Optional[CoreInterface],
527+
iface1: CoreInterface | None,
529528
node2: NodeBase,
530-
iface2: Optional[CoreInterface],
529+
iface2: CoreInterface | None,
531530
options: LinkOptions,
532531
unidirectional: bool,
533532
) -> core_pb2.Link:
@@ -710,7 +709,7 @@ def get_hooks(session: Session) -> list[core_pb2.Hook]:
710709

711710
def get_mobility_node(
712711
session: Session, node_id: int, context: ServicerContext
713-
) -> Union[WlanNode, EmaneNet]:
712+
) -> WlanNode | EmaneNet:
714713
"""
715714
Get mobility node.
716715
@@ -820,5 +819,5 @@ def configure_node(
820819
service.set_template(name, template)
821820

822821

823-
def get_optional(message: Message, name: str) -> Optional[Any]:
822+
def get_optional(message: Message, name: str) -> Any | None:
824823
return getattr(message, name) if message.HasField(name) else None

daemon/core/api/grpc/server.py

+5-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from concurrent import futures
1010
from pathlib import Path
1111
from re import Pattern
12-
from typing import Optional
1312

1413
import grpc
1514
from grpc import ServicerContext
@@ -107,7 +106,7 @@ def __init__(self, coreemu: CoreEmu) -> None:
107106
super().__init__()
108107
self.coreemu: CoreEmu = coreemu
109108
self.running: bool = True
110-
self.server: Optional[grpc.Server] = None
109+
self.server: grpc.Server | None = None
111110
# catch signals
112111
signal.signal(signal.SIGHUP, self._signal_handler)
113112
signal.signal(signal.SIGINT, self._signal_handler)
@@ -230,10 +229,7 @@ def GetConfig(
230229
)
231230
services.append(service_proto)
232231
emane_models = [x.name for x in EmaneModelManager.models.values()]
233-
return core_pb2.GetConfigResponse(
234-
services=services,
235-
emane_models=emane_models,
236-
)
232+
return core_pb2.GetConfigResponse(services=services, emane_models=emane_models)
237233

238234
def StartSession(
239235
self, request: core_pb2.StartSessionRequest, context: ServicerContext
@@ -1305,9 +1301,7 @@ def GetWirelessConfig(
13051301
return GetWirelessConfigResponse(config=config_options)
13061302

13071303
def EmaneEvents(
1308-
self,
1309-
request_iterator: Iterable[EmaneEventsRequest],
1310-
context: ServicerContext,
1304+
self, request_iterator: Iterable[EmaneEventsRequest], context: ServicerContext
13111305
) -> EmaneEventsResponse:
13121306
for request in request_iterator:
13131307
session = self.get_session(request.session_id, context)
@@ -1396,10 +1390,7 @@ def EmaneEvents(
13961390
session, node, antenna.iface_id, context
13971391
)
13981392
session.emane.event_manager.publish_antenna_profile(
1399-
nem_id,
1400-
antenna.profile,
1401-
antenna.azimuth,
1402-
antenna.elevation,
1393+
nem_id, antenna.profile, antenna.azimuth, antenna.elevation
14031394
)
14041395
elif request.HasField("fading"):
14051396
fading = request.fading
@@ -1416,9 +1407,7 @@ def EmaneEvents(
14161407
return EmaneEventsResponse()
14171408

14181409
def CreateService(
1419-
self,
1420-
request: CreateServiceRequest,
1421-
context: ServicerContext,
1410+
self, request: CreateServiceRequest, context: ServicerContext
14221411
) -> CreateServiceResponse:
14231412
service = request.service
14241413
class_name = f"{service.name.capitalize()}Class"

0 commit comments

Comments
 (0)