install: updates to support building deb/rpm packages that contain python wheels and install core from a single file, updates to core to install scripts by way of python directly
This commit is contained in:
parent
cd6bb319ad
commit
fcf6f30302
54 changed files with 528 additions and 187 deletions
79
Makefile.am
79
Makefile.am
|
@ -21,6 +21,7 @@ ACLOCAL_AMFLAGS = -I config
|
|||
|
||||
# extra files to include with distribution tarball
|
||||
EXTRA_DIST = bootstrap.sh \
|
||||
package \
|
||||
LICENSE \
|
||||
README.md \
|
||||
ASSIGNMENT_OF_COPYRIGHT.pdf \
|
||||
|
@ -47,7 +48,7 @@ fpm -s dir -t deb -n core-distributed \
|
|||
--description "Common Open Research Emulator Distributed Package" \
|
||||
--url https://github.com/coreemu/core \
|
||||
--vendor "$(PACKAGE_VENDOR)" \
|
||||
-p core_distributed_VERSION_ARCH.deb \
|
||||
-p core-distributed_VERSION_ARCH.deb \
|
||||
-v $(PACKAGE_VERSION) \
|
||||
-d "ethtool" \
|
||||
-d "procps" \
|
||||
|
@ -58,7 +59,8 @@ fpm -s dir -t deb -n core-distributed \
|
|||
-d "libev4" \
|
||||
-d "openssh-server" \
|
||||
-d "xterm" \
|
||||
-C $(DESTDIR)
|
||||
netns/vnoded=/usr/bin/ \
|
||||
netns/vcmd=/usr/bin/
|
||||
endef
|
||||
|
||||
define fpm-distributed-rpm =
|
||||
|
@ -68,7 +70,7 @@ fpm -s dir -t rpm -n core-distributed \
|
|||
--description "Common Open Research Emulator Distributed Package" \
|
||||
--url https://github.com/coreemu/core \
|
||||
--vendor "$(PACKAGE_VENDOR)" \
|
||||
-p core_distributed_VERSION_ARCH.rpm \
|
||||
-p core-distributed_VERSION_ARCH.rpm \
|
||||
-v $(PACKAGE_VERSION) \
|
||||
-d "ethtool" \
|
||||
-d "procps-ng" \
|
||||
|
@ -79,12 +81,75 @@ fpm -s dir -t rpm -n core-distributed \
|
|||
-d "net-tools" \
|
||||
-d "openssh-server" \
|
||||
-d "xterm" \
|
||||
-C $(DESTDIR)
|
||||
netns/vnoded=/usr/bin/ \
|
||||
netns/vcmd=/usr/bin/
|
||||
endef
|
||||
|
||||
.PHONY: fpm-distributed
|
||||
fpm-distributed: clean-local-fpm
|
||||
$(MAKE) -C netns install DESTDIR=$(DESTDIR)
|
||||
define fpm-rpm =
|
||||
fpm -s dir -t rpm -n core \
|
||||
-m "$(PACKAGE_MAINTAINERS)" \
|
||||
--license "BSD" \
|
||||
--description "core vnoded/vcmd and system dependencies" \
|
||||
--url https://github.com/coreemu/core \
|
||||
--vendor "$(PACKAGE_VENDOR)" \
|
||||
-p core_VERSION_ARCH.rpm \
|
||||
-v $(PACKAGE_VERSION) \
|
||||
--rpm-init package/core-daemon \
|
||||
--after-install package/after-install.sh \
|
||||
--after-remove package/after-remove.sh \
|
||||
-d "ethtool" \
|
||||
-d "tk" \
|
||||
-d "procps-ng" \
|
||||
-d "bash >= 3.0" \
|
||||
-d "ebtables" \
|
||||
-d "iproute" \
|
||||
-d "libev" \
|
||||
-d "net-tools" \
|
||||
-d "nftables" \
|
||||
netns/vnoded=/usr/bin/ \
|
||||
netns/vcmd=/usr/bin/ \
|
||||
package/etc/core.conf=/etc/core/ \
|
||||
package/etc/logging.conf=/etc/core/ \
|
||||
package/examples=/opt/core/ \
|
||||
daemon/dist/core-$(PACKAGE_VERSION)-py3-none-any.whl=/opt/core/
|
||||
endef
|
||||
|
||||
define fpm-deb =
|
||||
fpm -s dir -t deb -n core \
|
||||
-m "$(PACKAGE_MAINTAINERS)" \
|
||||
--license "BSD" \
|
||||
--description "core vnoded/vcmd and system dependencies" \
|
||||
--url https://github.com/coreemu/core \
|
||||
--vendor "$(PACKAGE_VENDOR)" \
|
||||
-p core_VERSION_ARCH.deb \
|
||||
-v $(PACKAGE_VERSION) \
|
||||
--deb-systemd package/core-daemon.service \
|
||||
--deb-no-default-config-files \
|
||||
--after-install package/after-install.sh \
|
||||
--after-remove package/after-remove.sh \
|
||||
-d "ethtool" \
|
||||
-d "tk" \
|
||||
-d "libtk-img" \
|
||||
-d "procps" \
|
||||
-d "libc6 >= 2.14" \
|
||||
-d "bash >= 3.0" \
|
||||
-d "ebtables" \
|
||||
-d "iproute2" \
|
||||
-d "libev4" \
|
||||
-d "nftables" \
|
||||
netns/vnoded=/usr/bin/ \
|
||||
netns/vcmd=/usr/bin/ \
|
||||
package/etc/core.conf=/etc/core/ \
|
||||
package/etc/logging.conf=/etc/core/ \
|
||||
package/examples=/opt/core/ \
|
||||
daemon/dist/core-$(PACKAGE_VERSION)-py3-none-any.whl=/opt/core/
|
||||
endef
|
||||
|
||||
.PHONY: fpm
|
||||
fpm: clean-local-fpm
|
||||
cd daemon && poetry build -f wheel
|
||||
$(call fpm-deb)
|
||||
$(call fpm-rpm)
|
||||
$(call fpm-distributed-deb)
|
||||
$(call fpm-distributed-rpm)
|
||||
|
||||
|
|
|
@ -21,10 +21,7 @@ DISTCLEANFILES = Makefile.in
|
|||
|
||||
# files to include with distribution tarball
|
||||
EXTRA_DIST = core \
|
||||
data \
|
||||
doc/conf.py.in \
|
||||
examples \
|
||||
scripts \
|
||||
tests \
|
||||
setup.cfg \
|
||||
poetry.lock \
|
||||
|
|
103
daemon/core/scripts/cleanup.py
Executable file
103
daemon/core/scripts/cleanup.py
Executable file
|
@ -0,0 +1,103 @@
|
|||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def check_root() -> None:
|
||||
if os.geteuid() != 0:
|
||||
print("permission denied, run this script as root")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="helps cleanup lingering core processes and files",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d", "--daemon", action="store_true", help="also kill core-daemon"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def cleanup_daemon() -> None:
|
||||
print("killing core-daemon process ... ", end="")
|
||||
result = subprocess.call("pkill -9 core-daemon", shell=True)
|
||||
if result:
|
||||
print("not found")
|
||||
else:
|
||||
print("done")
|
||||
|
||||
|
||||
def cleanup_nodes() -> None:
|
||||
print("killing vnoded processes ... ", end="")
|
||||
result = subprocess.call("pkill -KILL vnoded", shell=True)
|
||||
if result:
|
||||
print("none found")
|
||||
else:
|
||||
time.sleep(1)
|
||||
print("done")
|
||||
|
||||
|
||||
def cleanup_emane() -> None:
|
||||
print("killing emane processes ... ", end="")
|
||||
result = subprocess.call("pkill emane", shell=True)
|
||||
if result:
|
||||
print("none found")
|
||||
else:
|
||||
print("done")
|
||||
|
||||
|
||||
def cleanup_sessions() -> None:
|
||||
print("removing session directories ... ", end="")
|
||||
result = subprocess.call("rm -rf /tmp/pycore*", shell=True)
|
||||
if result:
|
||||
print("none found")
|
||||
else:
|
||||
print("done")
|
||||
|
||||
|
||||
def cleanup_interfaces() -> None:
|
||||
print("cleaning up devices")
|
||||
output = subprocess.check_output("ip -o -br link show", shell=True)
|
||||
lines = output.decode().strip().split("\n")
|
||||
for line in lines:
|
||||
values = line.split()
|
||||
name = values[0]
|
||||
if (
|
||||
name.startswith("veth")
|
||||
or name.startswith("gt.")
|
||||
or name.startswith("b.")
|
||||
or name.startswith("ctrl")
|
||||
):
|
||||
result = subprocess.call(f"ip link delete {name}", shell=True)
|
||||
if result:
|
||||
print(f"failed to remove {name}")
|
||||
else:
|
||||
print(f"removed {name}")
|
||||
if name.startswith("b."):
|
||||
result = subprocess.call(
|
||||
f"nft delete table bridge {name}",
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
shell=True,
|
||||
)
|
||||
if not result:
|
||||
print(f"cleared nft rules for {name}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
check_root()
|
||||
args = parse_args()
|
||||
if args.daemon:
|
||||
cleanup_daemon()
|
||||
cleanup_nodes()
|
||||
cleanup_emane()
|
||||
cleanup_interfaces()
|
||||
cleanup_sessions()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
import json
|
||||
import sys
|
||||
from argparse import (
|
||||
|
@ -32,7 +31,9 @@ NODE_TYPES = [x.name for x in NodeType if x != NodeType.PEER_TO_PEER]
|
|||
|
||||
|
||||
def protobuf_to_json(message: Any) -> Dict[str, Any]:
|
||||
return MessageToDict(message, including_default_value_fields=True, preserving_proto_field_name=True)
|
||||
return MessageToDict(
|
||||
message, including_default_value_fields=True, preserving_proto_field_name=True
|
||||
)
|
||||
|
||||
|
||||
def print_json(data: Any) -> None:
|
||||
|
@ -122,18 +123,15 @@ def get_current_session(core: CoreGrpcClient, session_id: Optional[int]) -> int:
|
|||
return sessions[0].id
|
||||
|
||||
|
||||
def create_iface(iface_id: int, mac: str, ip4_net: IPNetwork, ip6_net: IPNetwork) -> Interface:
|
||||
def create_iface(
|
||||
iface_id: int, mac: str, ip4_net: IPNetwork, ip6_net: IPNetwork
|
||||
) -> Interface:
|
||||
ip4 = str(ip4_net.ip) if ip4_net else None
|
||||
ip4_mask = ip4_net.prefixlen if ip4_net else None
|
||||
ip6 = str(ip6_net.ip) if ip6_net else None
|
||||
ip6_mask = ip6_net.prefixlen if ip6_net else None
|
||||
return Interface(
|
||||
id=iface_id,
|
||||
mac=mac,
|
||||
ip4=ip4,
|
||||
ip4_mask=ip4_mask,
|
||||
ip6=ip6,
|
||||
ip6_mask=ip6_mask,
|
||||
id=iface_id, mac=mac, ip4=ip4, ip4_mask=ip4_mask, ip6=ip6, ip6_mask=ip6_mask
|
||||
)
|
||||
|
||||
|
||||
|
@ -216,12 +214,14 @@ def query_session(core: CoreGrpcClient, args: Namespace) -> None:
|
|||
for node in session.nodes.values():
|
||||
xy_pos = f"{int(node.position.x)},{int(node.position.y)}"
|
||||
geo_pos = f"{node.geo.lon:.7f},{node.geo.lat:.7f},{node.geo.alt:f}"
|
||||
print(f"{node.id:<7} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos:<9} | {geo_pos}")
|
||||
print(
|
||||
f"{node.id:<7} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos:<9} | {geo_pos}"
|
||||
)
|
||||
print("\nLinks")
|
||||
for link in session.links:
|
||||
n1 = session.nodes[link.node1_id].name
|
||||
n2 = session.nodes[link.node2_id].name
|
||||
print(f"Node | ", end="")
|
||||
print("Node | ", end="")
|
||||
print_iface_header()
|
||||
print(f"{n1:<6} | ", end="")
|
||||
if link.iface1:
|
||||
|
@ -248,7 +248,9 @@ def query_node(core: CoreGrpcClient, args: Namespace) -> None:
|
|||
print("ID | Name | Type | XY | Geo")
|
||||
xy_pos = f"{int(node.position.x)},{int(node.position.y)}"
|
||||
geo_pos = f"{node.geo.lon:.7f},{node.geo.lat:.7f},{node.geo.alt:f}"
|
||||
print(f"{node.id:<7} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos:<9} | {geo_pos}")
|
||||
print(
|
||||
f"{node.id:<7} | {node.name[:7]:<7} | {node.type.name[:7]:<7} | {xy_pos:<9} | {geo_pos}"
|
||||
)
|
||||
if ifaces:
|
||||
print("Interfaces")
|
||||
print("Connected To | ", end="")
|
||||
|
@ -348,10 +350,14 @@ def add_link(core: CoreGrpcClient, args: Namespace) -> None:
|
|||
session_id = get_current_session(core, args.session)
|
||||
iface1 = None
|
||||
if args.iface1_id is not None:
|
||||
iface1 = create_iface(args.iface1_id, args.iface1_mac, args.iface1_ip4, args.iface1_ip6)
|
||||
iface1 = create_iface(
|
||||
args.iface1_id, args.iface1_mac, args.iface1_ip4, args.iface1_ip6
|
||||
)
|
||||
iface2 = None
|
||||
if args.iface2_id is not None:
|
||||
iface2 = create_iface(args.iface2_id, args.iface2_mac, args.iface2_ip4, args.iface2_ip6)
|
||||
iface2 = create_iface(
|
||||
args.iface2_id, args.iface2_mac, args.iface2_ip4, args.iface2_ip6
|
||||
)
|
||||
options = LinkOptions(
|
||||
bandwidth=args.bandwidth,
|
||||
loss=args.loss,
|
||||
|
@ -432,13 +438,17 @@ def setup_node_parser(parent) -> None:
|
|||
add_parser.add_argument(
|
||||
"-t", "--type", choices=NODE_TYPES, default="DEFAULT", help="type of node"
|
||||
)
|
||||
add_parser.add_argument("-m", "--model", help="used to determine services, optional")
|
||||
add_parser.add_argument(
|
||||
"-m", "--model", help="used to determine services, optional"
|
||||
)
|
||||
group = add_parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument("-p", "--pos", type=position_type, help="x,y position")
|
||||
group.add_argument("-g", "--geo", type=geo_type, help="lon,lat,alt position")
|
||||
add_parser.add_argument("-ic", "--icon", help="icon to use, optional")
|
||||
add_parser.add_argument("-im", "--image", help="container image, optional")
|
||||
add_parser.add_argument("-e", "--emane", help="emane model, only required for emane nodes")
|
||||
add_parser.add_argument(
|
||||
"-e", "--emane", help="emane model, only required for emane nodes"
|
||||
)
|
||||
add_parser.set_defaults(func=add_node)
|
||||
|
||||
edit_parser = subparsers.add_parser("edit", help="edit a node")
|
||||
|
@ -449,7 +459,9 @@ def setup_node_parser(parent) -> None:
|
|||
|
||||
move_parser = subparsers.add_parser("move", help="move a node")
|
||||
move_parser.formatter_class = ArgumentDefaultsHelpFormatter
|
||||
move_parser.add_argument("-i", "--id", type=int, help="id to use, optional", required=True)
|
||||
move_parser.add_argument(
|
||||
"-i", "--id", type=int, help="id to use, optional", required=True
|
||||
)
|
||||
group = move_parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument("-p", "--pos", type=position_type, help="x,y position")
|
||||
group.add_argument("-g", "--geo", type=geo_type, help="lon,lat,alt position")
|
||||
|
@ -474,19 +486,33 @@ def setup_link_parser(parent) -> None:
|
|||
add_parser.add_argument("-n1", "--node1", type=int, help="node1 id", required=True)
|
||||
add_parser.add_argument("-n2", "--node2", type=int, help="node2 id", required=True)
|
||||
add_parser.add_argument("-i1-i", "--iface1-id", type=int, help="node1 interface id")
|
||||
add_parser.add_argument("-i1-m", "--iface1-mac", type=mac_type, help="node1 interface mac")
|
||||
add_parser.add_argument("-i1-4", "--iface1-ip4", type=ip4_type, help="node1 interface ip4")
|
||||
add_parser.add_argument("-i1-6", "--iface1-ip6", type=ip6_type, help="node1 interface ip6")
|
||||
add_parser.add_argument(
|
||||
"-i1-m", "--iface1-mac", type=mac_type, help="node1 interface mac"
|
||||
)
|
||||
add_parser.add_argument(
|
||||
"-i1-4", "--iface1-ip4", type=ip4_type, help="node1 interface ip4"
|
||||
)
|
||||
add_parser.add_argument(
|
||||
"-i1-6", "--iface1-ip6", type=ip6_type, help="node1 interface ip6"
|
||||
)
|
||||
add_parser.add_argument("-i2-i", "--iface2-id", type=int, help="node2 interface id")
|
||||
add_parser.add_argument("-i2-m", "--iface2-mac", type=mac_type, help="node2 interface mac")
|
||||
add_parser.add_argument("-i2-4", "--iface2-ip4", type=ip4_type, help="node2 interface ip4")
|
||||
add_parser.add_argument("-i2-6", "--iface2-ip6", type=ip6_type, help="node2 interface ip6")
|
||||
add_parser.add_argument(
|
||||
"-i2-m", "--iface2-mac", type=mac_type, help="node2 interface mac"
|
||||
)
|
||||
add_parser.add_argument(
|
||||
"-i2-4", "--iface2-ip4", type=ip4_type, help="node2 interface ip4"
|
||||
)
|
||||
add_parser.add_argument(
|
||||
"-i2-6", "--iface2-ip6", type=ip6_type, help="node2 interface ip6"
|
||||
)
|
||||
add_parser.add_argument("-b", "--bandwidth", type=int, help="bandwidth (bps)")
|
||||
add_parser.add_argument("-l", "--loss", type=float, help="loss (%%)")
|
||||
add_parser.add_argument("-j", "--jitter", type=int, help="jitter (us)")
|
||||
add_parser.add_argument("-de", "--delay", type=int, help="delay (us)")
|
||||
add_parser.add_argument("-du", "--duplicate", type=int, help="duplicate (%%)")
|
||||
add_parser.add_argument("-u", "--uni", action="store_true", help="is link unidirectional?")
|
||||
add_parser.add_argument(
|
||||
"-u", "--uni", action="store_true", help="is link unidirectional?"
|
||||
)
|
||||
add_parser.set_defaults(func=add_link)
|
||||
|
||||
edit_parser = subparsers.add_parser("edit", help="edit a link")
|
||||
|
@ -507,8 +533,12 @@ def setup_link_parser(parent) -> None:
|
|||
|
||||
delete_parser = subparsers.add_parser("delete", help="delete a link")
|
||||
delete_parser.formatter_class = ArgumentDefaultsHelpFormatter
|
||||
delete_parser.add_argument("-n1", "--node1", type=int, help="node1 id", required=True)
|
||||
delete_parser.add_argument("-n2", "--node2", type=int, help="node1 id", required=True)
|
||||
delete_parser.add_argument(
|
||||
"-n1", "--node1", type=int, help="node1 id", required=True
|
||||
)
|
||||
delete_parser.add_argument(
|
||||
"-n2", "--node2", type=int, help="node1 id", required=True
|
||||
)
|
||||
delete_parser.add_argument("-i1", "--iface1", type=int, help="node1 interface id")
|
||||
delete_parser.add_argument("-i2", "--iface2", type=int, help="node2 interface id")
|
||||
delete_parser.set_defaults(func=delete_link)
|
||||
|
@ -526,20 +556,28 @@ def setup_query_parser(parent) -> None:
|
|||
|
||||
session_parser = subparsers.add_parser("session", help="query session")
|
||||
session_parser.formatter_class = ArgumentDefaultsHelpFormatter
|
||||
session_parser.add_argument("-i", "--id", type=int, help="session to query", required=True)
|
||||
session_parser.add_argument(
|
||||
"-i", "--id", type=int, help="session to query", required=True
|
||||
)
|
||||
session_parser.set_defaults(func=query_session)
|
||||
|
||||
node_parser = subparsers.add_parser("node", help="query node")
|
||||
node_parser.formatter_class = ArgumentDefaultsHelpFormatter
|
||||
node_parser.add_argument("-i", "--id", type=int, help="session to query", required=True)
|
||||
node_parser.add_argument("-n", "--node", type=int, help="node to query", required=True)
|
||||
node_parser.add_argument(
|
||||
"-i", "--id", type=int, help="session to query", required=True
|
||||
)
|
||||
node_parser.add_argument(
|
||||
"-n", "--node", type=int, help="node to query", required=True
|
||||
)
|
||||
node_parser.set_defaults(func=query_node)
|
||||
|
||||
|
||||
def setup_xml_parser(parent) -> None:
|
||||
parser = parent.add_parser("xml", help="open session xml")
|
||||
parser.formatter_class = ArgumentDefaultsHelpFormatter
|
||||
parser.add_argument("-f", "--file", type=file_type, help="xml file to open", required=True)
|
||||
parser.add_argument(
|
||||
"-f", "--file", type=file_type, help="xml file to open", required=True
|
||||
)
|
||||
parser.add_argument("-s", "--start", action="store_true", help="start the session?")
|
||||
parser.set_defaults(func=open_xml)
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
core-daemon: the CORE daemon is a server process that receives CORE API
|
||||
messages and instantiates emulated nodes and networks within the kernel. Various
|
||||
|
@ -61,18 +60,35 @@ def get_merged_config(filename):
|
|||
defaults = {
|
||||
"grpcport": default_grpc_port,
|
||||
"grpcaddress": default_address,
|
||||
"logfile": default_log
|
||||
"logfile": default_log,
|
||||
}
|
||||
parser = argparse.ArgumentParser(
|
||||
description=f"CORE daemon v.{COREDPY_VERSION} instantiates Linux network namespace nodes.")
|
||||
parser.add_argument("-f", "--configfile", dest="configfile",
|
||||
help=f"read config from specified file; default = {filename}")
|
||||
parser.add_argument("--ovs", action="store_true", help="enable experimental ovs mode, default is false")
|
||||
parser.add_argument("--grpc-port", dest="grpcport",
|
||||
help=f"grpc port to listen on; default {default_grpc_port}")
|
||||
parser.add_argument("--grpc-address", dest="grpcaddress",
|
||||
help=f"grpc address to listen on; default {default_address}")
|
||||
parser.add_argument("-l", "--logfile", help=f"core logging configuration; default {default_log}")
|
||||
description=f"CORE daemon v.{COREDPY_VERSION} instantiates Linux network namespace nodes."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--configfile",
|
||||
dest="configfile",
|
||||
help=f"read config from specified file; default = {filename}",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ovs",
|
||||
action="store_true",
|
||||
help="enable experimental ovs mode, default is false",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--grpc-port",
|
||||
dest="grpcport",
|
||||
help=f"grpc port to listen on; default {default_grpc_port}",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--grpc-address",
|
||||
dest="grpcaddress",
|
||||
help=f"grpc address to listen on; default {default_address}",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l", "--logfile", help=f"core logging configuration; default {default_log}"
|
||||
)
|
||||
# parse command line options
|
||||
args = parser.parse_args()
|
||||
# convert ovs to internal format
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import logging
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
@ -9,12 +8,19 @@ from core.gui.app import Application
|
|||
|
||||
def main() -> None:
|
||||
# parse flags
|
||||
parser = argparse.ArgumentParser(description=f"CORE Python GUI")
|
||||
parser.add_argument("-l", "--level", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default="INFO",
|
||||
help="logging level")
|
||||
parser = argparse.ArgumentParser(description="CORE Python GUI")
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--level",
|
||||
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||
default="INFO",
|
||||
help="logging level",
|
||||
)
|
||||
parser.add_argument("-p", "--proxy", action="store_true", help="enable proxy")
|
||||
parser.add_argument("-s", "--session", type=int, help="session id to join")
|
||||
parser.add_argument("--create-dir", action="store_true", help="create gui directory and exit")
|
||||
parser.add_argument(
|
||||
"--create-dir", action="store_true", help="create gui directory and exit"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# check home directory exists and create if necessary
|
||||
|
@ -25,9 +31,13 @@ def main() -> None:
|
|||
# setup logging
|
||||
log_format = "%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s"
|
||||
stream_handler = logging.StreamHandler()
|
||||
file_handler = TimedRotatingFileHandler(filename=appconfig.LOG_PATH, when="D", backupCount=5)
|
||||
file_handler = TimedRotatingFileHandler(
|
||||
filename=appconfig.LOG_PATH, when="D", backupCount=5
|
||||
)
|
||||
log_level = logging.getLevelName(args.level)
|
||||
logging.basicConfig(level=log_level, format=log_format, handlers=[stream_handler, file_handler])
|
||||
logging.basicConfig(
|
||||
level=log_level, format=log_format, handlers=[stream_handler, file_handler]
|
||||
)
|
||||
logging.getLogger("PIL").setLevel(logging.ERROR)
|
||||
|
||||
# start app
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
@ -31,7 +29,10 @@ def parse_args() -> argparse.Namespace:
|
|||
"-f", "--file", required=True, type=path_type, help="core file to play"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s", "--session", type=int, help="session to play to, first found session otherwise"
|
||||
"-s",
|
||||
"--session",
|
||||
type=int,
|
||||
help="session to play to, first found session otherwise",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import enum
|
||||
import select
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import re
|
||||
from io import TextIOWrapper
|
||||
|
@ -6,9 +5,15 @@ from io import TextIOWrapper
|
|||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description=f"Helps transition older CORE services to work with newer versions")
|
||||
parser.add_argument("-f", "--file", dest="file", type=argparse.FileType("r"),
|
||||
help=f"service file to update")
|
||||
description="Helps transition older CORE services to work with newer versions"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--file",
|
||||
dest="file",
|
||||
type=argparse.FileType("r"),
|
||||
help="service file to update",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
|
@ -20,17 +25,32 @@ def update_service(service_file: TextIOWrapper) -> None:
|
|||
# rename dirs to directories
|
||||
line = re.sub(r"^(\s+)dirs", r"\1directories", line)
|
||||
# fix import states for service
|
||||
line = re.sub(r"^.+import.+CoreService.+$",
|
||||
r"from core.services.coreservices import CoreService", line)
|
||||
line = re.sub(
|
||||
r"^.+import.+CoreService.+$",
|
||||
r"from core.services.coreservices import CoreService",
|
||||
line,
|
||||
)
|
||||
# fix method signatures
|
||||
line = re.sub(r"def generateconfig\(cls, node, filename, services\)",
|
||||
r"def generate_config(cls, node, filename)", line)
|
||||
line = re.sub(r"def getvalidate\(cls, node, services\)",
|
||||
r"def get_validate(cls, node)", line)
|
||||
line = re.sub(r"def getstartup\(cls, node, services\)",
|
||||
r"def get_startup(cls, node)", line)
|
||||
line = re.sub(r"def getconfigfilenames\(cls, nodenum, services\)",
|
||||
r"def get_configs(cls, node)", line)
|
||||
line = re.sub(
|
||||
r"def generateconfig\(cls, node, filename, services\)",
|
||||
r"def generate_config(cls, node, filename)",
|
||||
line,
|
||||
)
|
||||
line = re.sub(
|
||||
r"def getvalidate\(cls, node, services\)",
|
||||
r"def get_validate(cls, node)",
|
||||
line,
|
||||
)
|
||||
line = re.sub(
|
||||
r"def getstartup\(cls, node, services\)",
|
||||
r"def get_startup(cls, node)",
|
||||
line,
|
||||
)
|
||||
line = re.sub(
|
||||
r"def getconfigfilenames\(cls, nodenum, services\)",
|
||||
r"def get_configs(cls, node)",
|
||||
line,
|
||||
)
|
||||
# remove unwanted lines
|
||||
if re.search(r"addservice\(", line):
|
||||
continue
|
|
@ -14,6 +14,14 @@ include = [
|
|||
]
|
||||
exclude = ["core/constants.py.in"]
|
||||
|
||||
[tool.poetry.scripts]
|
||||
core-daemon = "core.scripts.daemon:main"
|
||||
core-cli = "core.scripts.cli:main"
|
||||
core-gui = "core.scripts.gui:main"
|
||||
core-player = "core.scripts.player:main"
|
||||
core-route-monitor = "core.scripts.routemonitor:main"
|
||||
core-service-update = "core.scripts.serviceupdate:main"
|
||||
core-cleanup = "core.scripts.cleanup:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.6"
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "z$1" = "z-h" -o "z$1" = "z--help" ]; then
|
||||
echo "usage: $0 [-d [-l]]"
|
||||
echo -n " Clean up all CORE namespaces processes, bridges, interfaces, "
|
||||
echo "and session\n directories. Options:"
|
||||
echo " -h show this help message and exit"
|
||||
echo " -d also kill the Python daemon"
|
||||
echo " -l remove the core-daemon.log file"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ `id -u` != 0 ]; then
|
||||
echo "Permission denied. Re-run this script as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin"
|
||||
export PATH
|
||||
|
||||
if [ "z$1" = "z-d" ]; then
|
||||
pypids=`pidof python3 python`
|
||||
for p in $pypids; do
|
||||
grep -q core-daemon /proc/$p/cmdline
|
||||
if [ $? = 0 ]; then
|
||||
echo "cleaning up core-daemon process: $p"
|
||||
kill -9 $p
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "z$2" = "z-l" ]; then
|
||||
rm -f /var/log/core-daemon.log
|
||||
fi
|
||||
|
||||
kaopts="-v"
|
||||
killall --help 2>&1 | grep -q namespace
|
||||
if [ $? = 0 ]; then
|
||||
kaopts="$kaopts --ns 0"
|
||||
fi
|
||||
|
||||
vnodedpids=`pidof vnoded`
|
||||
if [ "z$vnodedpids" != "z" ]; then
|
||||
echo "cleaning up old vnoded processes: $vnodedpids"
|
||||
killall $kaopts -KILL vnoded
|
||||
# pause for 1 second for interfaces to disappear
|
||||
sleep 1
|
||||
fi
|
||||
killall -q emane
|
||||
killall -q emanetransportd
|
||||
killall -q emaneeventservice
|
||||
|
||||
if [ -d /sys/class/net ]; then
|
||||
ifcommand="ls -1 /sys/class/net"
|
||||
else
|
||||
ifcommand="ip -o link show | sed -r -e 's/[0-9]+: ([^[:space:]]+): .*/\1/'"
|
||||
fi
|
||||
|
||||
eval "$ifcommand" | awk '
|
||||
/^veth[0-9]+\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||
/tmp\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||
/gt\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||
/b\./ {print "removing bridge " $1; system("ip link set " $1 " down; ip link del " $1);}
|
||||
/ctrl[0-9]+\./ {print "removing bridge " $1; system("ip link set " $1 " down; ip link del " $1);}
|
||||
'
|
||||
|
||||
nft list ruleset | awk '
|
||||
$3 ~ /^b\./ {print "removing nftables " $3; system("nft delete table bridge " $3);}
|
||||
'
|
||||
|
||||
rm -rf /tmp/pycore*
|
15
package/Dockerfile.centos
Normal file
15
package/Dockerfile.centos
Normal file
|
@ -0,0 +1,15 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM centos:7
|
||||
LABEL Description="CORE CentOS Image"
|
||||
|
||||
# define environment
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# install basic dependencies
|
||||
RUN yum update -y && yum install -y python3 python3-pip python3-tkinter
|
||||
RUN python3 -m pip install --upgrade pip
|
||||
|
||||
# install core
|
||||
WORKDIR /opt/core
|
||||
COPY core_*.rpm .
|
||||
RUN NO_VENV=1 yum install -y ./core_*.rpm
|
15
package/Dockerfile.ubuntu
Normal file
15
package/Dockerfile.ubuntu
Normal file
|
@ -0,0 +1,15 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM ubuntu:20.04
|
||||
LABEL Description="CORE Docker Ubuntu Image"
|
||||
|
||||
# define environment
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# install basic dependencies
|
||||
RUN apt-get update && apt-get install -y python3 python3-tk python3-pip python3-venv
|
||||
RUN python3 -m pip install --upgrade pip
|
||||
|
||||
# install core
|
||||
WORKDIR /opt/core
|
||||
COPY core_*.deb .
|
||||
RUN apt-get install -y ./core_*.deb
|
16
package/after-install.sh
Normal file
16
package/after-install.sh
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
if [ ! -z "${NO_PYTHON}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PYTHON="${PYTHON:=python3}"
|
||||
if [ ! -z "${NO_VENV}" ]; then
|
||||
${PYTHON} -m pip install /opt/core/core-*.whl
|
||||
echo "DAEMON=/usr/local/bin/core-daemon" > /opt/core/service
|
||||
else
|
||||
${PYTHON} -m venv /opt/core/venv
|
||||
. /opt/core/venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install /opt/core/core-*.whl
|
||||
echo "DAEMON=/opt/core/venv/bin/core-daemon" > /opt/core/service
|
||||
fi
|
13
package/after-remove.sh
Normal file
13
package/after-remove.sh
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
if [ -v NO_PYTHON ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PYTHON="${PYTHON:=python3}"
|
||||
if [ -v NO_VENV ]; then
|
||||
${PYTHON} -m pip uninstall core
|
||||
else
|
||||
${PYTHON} -m venv /opt/core/venv
|
||||
. /opt/core/venv/bin/activate
|
||||
pip uninstall core
|
||||
fi
|
112
package/core-daemon
Normal file
112
package/core-daemon
Normal file
|
@ -0,0 +1,112 @@
|
|||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: core-daemon
|
||||
# Required-Start: $network $remote_fs
|
||||
# Required-Stop: $network $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start the core-daemon CORE daemon at boot time
|
||||
# Description: Starts and stops the core-daemon CORE daemon used to
|
||||
# provide network emulation services for the CORE GUI
|
||||
# or scripts.
|
||||
### END INIT INFO
|
||||
#
|
||||
# chkconfig: 35 90 03
|
||||
# description: Starts and stops the CORE daemon \
|
||||
# used to provide network emulation services.
|
||||
#
|
||||
# config: /etc/core/
|
||||
|
||||
. /opt/core/service
|
||||
NAME=`basename $0`
|
||||
PIDFILE="/var/$NAME.pid"
|
||||
LOG="/var/log/$NAME.log"
|
||||
CMD="$DAEMON"
|
||||
|
||||
get_pid() {
|
||||
cat "$PIDFILE"
|
||||
}
|
||||
|
||||
is_alive() {
|
||||
[ -f "$PIDFILE" ] && ps -p `get_pid` > /dev/null 2>&1
|
||||
}
|
||||
|
||||
corestart() {
|
||||
if is_alive; then
|
||||
echo "$NAME already started"
|
||||
else
|
||||
echo "starting $NAME"
|
||||
$CMD 2>&1 >> "$LOG" &
|
||||
fi
|
||||
|
||||
echo $! > "$PIDFILE"
|
||||
if ! is_alive; then
|
||||
echo "unable to start $NAME, see $LOG"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
corestop() {
|
||||
if is_alive; then
|
||||
echo -n "stopping $NAME.."
|
||||
kill `get_pid`
|
||||
for i in 1 2 3 4 5; do
|
||||
sleep 1
|
||||
if ! is_alive; then
|
||||
break
|
||||
fi
|
||||
echo -n "."
|
||||
done
|
||||
echo
|
||||
|
||||
if is_alive; then
|
||||
echo "not stopped; may still be shutting down"
|
||||
exit 1
|
||||
else
|
||||
echo "stopped"
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
rm -f "$PIDFILE"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "$NAME not running"
|
||||
fi
|
||||
}
|
||||
|
||||
corerestart() {
|
||||
corestop
|
||||
corestart
|
||||
}
|
||||
|
||||
corestatus() {
|
||||
if is_alive; then
|
||||
echo "$NAME is running"
|
||||
else
|
||||
echo "$NAME is stopped"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
corestart
|
||||
;;
|
||||
stop)
|
||||
corestop
|
||||
;;
|
||||
restart)
|
||||
corerestart
|
||||
;;
|
||||
force-reload)
|
||||
corerestart
|
||||
;;
|
||||
status)
|
||||
corestatus
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
12
package/core-daemon.service
Normal file
12
package/core-daemon.service
Normal file
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Common Open Research Emulator Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/opt/core/service
|
||||
ExecStart=$DAEMON
|
||||
TasksMax=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
0
package/examples/myemane/__init__.py
Normal file
0
package/examples/myemane/__init__.py
Normal file
34
tasks.py
34
tasks.py
|
@ -291,25 +291,6 @@ def install_core_files(c, local=False, verbose=False, prefix=DEFAULT_PREFIX):
|
|||
hide = not verbose
|
||||
python = get_python(c)
|
||||
bin_dir = Path(prefix).joinpath("bin")
|
||||
# install scripts
|
||||
for script in Path("daemon/scripts").iterdir():
|
||||
dest = bin_dir.joinpath(script.name)
|
||||
with open(script, "r") as f:
|
||||
lines = f.readlines()
|
||||
first = lines[0].strip()
|
||||
# modify python scripts to point to virtual environment
|
||||
if not local and first == "#!/usr/bin/env python3":
|
||||
lines[0] = f"#!{python}\n"
|
||||
temp = NamedTemporaryFile("w", delete=False)
|
||||
for line in lines:
|
||||
temp.write(line)
|
||||
temp.close()
|
||||
c.run(f"sudo cp {temp.name} {dest}", hide=hide)
|
||||
c.run(f"sudo chmod 755 {dest}", hide=hide)
|
||||
os.unlink(temp.name)
|
||||
# copy normal links
|
||||
else:
|
||||
c.run(f"sudo cp {script} {dest}", hide=hide)
|
||||
# setup core python helper
|
||||
if not local:
|
||||
core_python = bin_dir.joinpath("core-python")
|
||||
|
@ -325,12 +306,12 @@ def install_core_files(c, local=False, verbose=False, prefix=DEFAULT_PREFIX):
|
|||
# install core configuration file
|
||||
config_dir = "/etc/core"
|
||||
c.run(f"sudo mkdir -p {config_dir}", hide=hide)
|
||||
c.run(f"sudo cp -n daemon/data/core.conf {config_dir}", hide=hide)
|
||||
c.run(f"sudo cp -n daemon/data/logging.conf {config_dir}", hide=hide)
|
||||
c.run(f"sudo cp -n package/etc/core.conf {config_dir}", hide=hide)
|
||||
c.run(f"sudo cp -n package/etc/logging.conf {config_dir}", hide=hide)
|
||||
# install examples
|
||||
examples_dir = f"{prefix}/share/core"
|
||||
c.run(f"sudo mkdir -p {examples_dir}", hide=hide)
|
||||
c.run(f"sudo cp -r daemon/examples {examples_dir}", hide=hide)
|
||||
c.run(f"sudo cp -r package/examples {examples_dir}", hide=hide)
|
||||
|
||||
|
||||
@task(
|
||||
|
@ -467,11 +448,9 @@ def uninstall(
|
|||
c.run("sudo -v", hide=True)
|
||||
with p.start("uninstalling core"):
|
||||
c.run("sudo make uninstall", hide=hide)
|
||||
|
||||
with p.start("cleaning build directory"):
|
||||
c.run("make clean", hide=hide)
|
||||
c.run("./bootstrap.sh clean", hide=hide)
|
||||
|
||||
if local:
|
||||
with p.start("uninstalling core"):
|
||||
python_bin = get_env_python()
|
||||
|
@ -485,22 +464,15 @@ def uninstall(
|
|||
c.run("poetry run pre-commit uninstall", hide=hide)
|
||||
with p.start("uninstalling poetry virtual environment"):
|
||||
c.run(f"poetry env remove {python}", hide=hide)
|
||||
|
||||
# remove installed files
|
||||
bin_dir = Path(prefix).joinpath("bin")
|
||||
with p.start("uninstalling script files"):
|
||||
for script in Path("daemon/scripts").iterdir():
|
||||
dest = bin_dir.joinpath(script.name)
|
||||
c.run(f"sudo rm -f {dest}", hide=hide)
|
||||
with p.start("uninstalling examples"):
|
||||
examples_dir = Path(prefix).joinpath("share/core")
|
||||
c.run(f"sudo rm -rf {examples_dir}")
|
||||
|
||||
# remove core-python symlink
|
||||
if not local:
|
||||
core_python = bin_dir.joinpath("core-python")
|
||||
c.run(f"sudo rm -f {core_python}", hide=hide)
|
||||
|
||||
# remove service
|
||||
systemd_dir = Path("/lib/systemd/system/")
|
||||
service_name = "core-daemon.service"
|
||||
|
|
Loading…
Reference in a new issue