207 lines
9.2 KiB
Markdown
207 lines
9.2 KiB
Markdown
|
# CORE Config Services
|
||
|
|
||
|
* Table of Contents
|
||
|
{:toc}
|
||
|
|
||
|
## Overview
|
||
|
|
||
|
Config services are a newer version of services for CORE, that leverage a
|
||
|
templating engine, for more robust service file creation. They also
|
||
|
have the power of configuration key/value pairs that values that can be
|
||
|
defined and displayed within the GUI, to help further tweak a service,
|
||
|
as needed.
|
||
|
|
||
|
CORE services are a convenience for creating reusable dynamic scripts
|
||
|
to run on nodes, for carrying out specific task(s).
|
||
|
|
||
|
This boilds down to the following functions:
|
||
|
* generating files the service will use, either directly for commands or for configuration
|
||
|
* command(s) for starting a service
|
||
|
* command(s) for validating a service
|
||
|
* command(s) for stopping a service
|
||
|
|
||
|
Most CORE nodes will have a default set of services to run, associated with
|
||
|
them. You can however customize the set of services a node will use. Or even
|
||
|
further define a new node type within the GUI, with a set of services, that
|
||
|
will allow quickly dragging and dropping that node type during creation.
|
||
|
|
||
|
## Available Services
|
||
|
|
||
|
| Service Group | Services |
|
||
|
|---|---|
|
||
|
|[BIRD](services/bird.md)|BGP, OSPF, RADV, RIP, Static|
|
||
|
|[EMANE](services/emane.md)|Transport Service|
|
||
|
|[FRR](services/frr.md)|BABEL, BGP, OSPFv2, OSPFv3, PIMD, RIP, RIPNG, Zebra|
|
||
|
|[NRL](services/nrl.md)|arouted, MGEN Sink, MGEN Actor, NHDP, OLSR, OLSRORG, OLSRv2, SMF|
|
||
|
|[Quagga](services/quagga.md)|BABEL, BGP, OSPFv2, OSPFv3, OSPFv3 MDR, RIP, RIPNG, XPIMD, Zebra|
|
||
|
|[SDN](services/sdn.md)|OVS, RYU|
|
||
|
|[Security](services/security.md)|Firewall, IPsec, NAT, VPN Client, VPN Server|
|
||
|
|[Utility](services/utility.md)|ATD, Routing Utils, DHCP, FTP, IP Forward, PCAP, RADVD, SSF, UCARP|
|
||
|
|[XORP](services/xorp.md)|BGP, OLSR, OSPFv2, OSPFv3, PIMSM4, PIMSM6, RIP, RIPNG, Router Manager|
|
||
|
|
||
|
## Node Types and Default Services
|
||
|
|
||
|
Here are the default node types and their services:
|
||
|
|
||
|
| Node Type | Services |
|
||
|
|---|---|
|
||
|
| *router* | zebra, OSFPv2, OSPFv3, and IPForward services for IGP link-state routing. |
|
||
|
| *PC* | DefaultRoute service for having a default route when connected directly to a router. |
|
||
|
| *mdr* | zebra, OSPFv3MDR, and IPForward services for wireless-optimized MANET Designated Router routing. |
|
||
|
| *prouter* | a physical router, having the same default services as the *router* node type; for incorporating Linux testbed machines into an emulation. |
|
||
|
|
||
|
Configuration files can be automatically generated by each service. For
|
||
|
example, CORE automatically generates routing protocol configuration for the
|
||
|
router nodes in order to simplify the creation of virtual networks.
|
||
|
|
||
|
To change the services associated with a node, double-click on the node to
|
||
|
invoke its configuration dialog and click on the *Services...* button,
|
||
|
or right-click a node a choose *Services...* from the menu.
|
||
|
Services are enabled or disabled by clicking on their names. The button next to
|
||
|
each service name allows you to customize all aspects of this service for this
|
||
|
node. For example, special route redistribution commands could be inserted in
|
||
|
to the Quagga routing configuration associated with the zebra service.
|
||
|
|
||
|
To change the default services associated with a node type, use the Node Types
|
||
|
dialog available from the *Edit* button at the end of the Layer-3 nodes
|
||
|
toolbar, or choose *Node types...* from the *Session* menu. Note that
|
||
|
any new services selected are not applied to existing nodes if the nodes have
|
||
|
been customized.
|
||
|
|
||
|
The node types are saved in the GUI config file **~/.coregui/config.yaml**.
|
||
|
Keep this in mind when changing the default services for
|
||
|
existing node types; it may be better to simply create a new node type. It is
|
||
|
recommended that you do not change the default built-in node types.
|
||
|
|
||
|
## New Services
|
||
|
|
||
|
Services can save time required to configure nodes, especially if a number
|
||
|
of nodes require similar configuration procedures. New services can be
|
||
|
introduced to automate tasks.
|
||
|
|
||
|
### Creating New Services
|
||
|
|
||
|
1. Modify the example service shown below
|
||
|
to do what you want. It could generate config/script files, mount per-node
|
||
|
directories, start processes/scripts, etc. Your file can define one or more
|
||
|
classes to be imported. You can create multiple Python files that will be imported.
|
||
|
|
||
|
2. Put these files in a directory such as ~/.coregui/custom_services
|
||
|
Note that the last component of this directory name **myservices** should not
|
||
|
be named something like **services** which conflicts with an existing module.
|
||
|
|
||
|
3. Add a **custom_config_services_dir = ~/.coregui/custom_services** entry to the
|
||
|
/etc/core/core.conf file.
|
||
|
|
||
|
**NOTE:**
|
||
|
The directory name used in **custom_services_dir** should be unique and
|
||
|
should not correspond to
|
||
|
any existing Python module name. For example, don't use the name **subprocess**
|
||
|
or **services**.
|
||
|
|
||
|
4. Restart the CORE daemon (core-daemon). Any import errors (Python syntax)
|
||
|
should be displayed in the terminal (or service log, like journalctl).
|
||
|
|
||
|
5. Start using your custom service on your nodes. You can create a new node
|
||
|
type that uses your service, or change the default services for an existing
|
||
|
node type, or change individual nodes. .
|
||
|
|
||
|
### Example Custom Service
|
||
|
|
||
|
Below is the skeleton for a custom service with some documentation. Most
|
||
|
people would likely only setup the required class variables **(name/group)**.
|
||
|
Then define the **files** to generate and implement the
|
||
|
**get_text_template** function to dynamically create the files wanted. Finally,
|
||
|
the **startup** commands would be supplied, which typically tend to be
|
||
|
running the shell files generated.
|
||
|
|
||
|
```python
|
||
|
from typing import Dict, List
|
||
|
|
||
|
from core.config import Configuration
|
||
|
from core.configservice.base import ConfigService, ConfigServiceMode, ShadowDir
|
||
|
from core.emulator.enumerations import ConfigDataTypes
|
||
|
|
||
|
# class that subclasses ConfigService
|
||
|
class ExampleService(ConfigService):
|
||
|
# unique name for your service within CORE
|
||
|
name: str = "Example"
|
||
|
# the group your service is associated with, used for display in GUI
|
||
|
group: str = "ExampleGroup"
|
||
|
# directories that the service should shadow mount, hiding the system directory
|
||
|
directories: List[str] = [
|
||
|
"/usr/local/core",
|
||
|
]
|
||
|
# files that this service should generate, defaults to nodes home directory
|
||
|
# or can provide an absolute path to a mounted directory
|
||
|
files: List[str] = [
|
||
|
"example-start.sh",
|
||
|
"/usr/local/core/file1",
|
||
|
]
|
||
|
# executables that should exist on path, that this service depends on
|
||
|
executables: List[str] = []
|
||
|
# other services that this service depends on, can be used to define service start order
|
||
|
dependencies: List[str] = []
|
||
|
# commands to run to start this service
|
||
|
startup: List[str] = []
|
||
|
# commands to run to validate this service
|
||
|
validate: List[str] = []
|
||
|
# commands to run to stop this service
|
||
|
shutdown: List[str] = []
|
||
|
# validation mode, blocking, non-blocking, and timer
|
||
|
validation_mode: ConfigServiceMode = ConfigServiceMode.BLOCKING
|
||
|
# configurable values that this service can use, for file generation
|
||
|
default_configs: List[Configuration] = [
|
||
|
Configuration(id="value1", type=ConfigDataTypes.STRING, label="Text"),
|
||
|
Configuration(id="value2", type=ConfigDataTypes.BOOL, label="Boolean"),
|
||
|
Configuration(
|
||
|
id="value3",
|
||
|
type=ConfigDataTypes.STRING,
|
||
|
label="Multiple Choice",
|
||
|
options=["value1", "value2", "value3"],
|
||
|
),
|
||
|
]
|
||
|
# sets of values to set for the configuration defined above, can be used to
|
||
|
# provide convenient sets of values to typically use
|
||
|
modes: Dict[str, Dict[str, str]] = {
|
||
|
"mode1": {"value1": "value1", "value2": "0", "value3": "value2"},
|
||
|
"mode2": {"value1": "value2", "value2": "1", "value3": "value3"},
|
||
|
"mode3": {"value1": "value3", "value2": "0", "value3": "value1"},
|
||
|
}
|
||
|
# defines directories that this service can help shadow within a node
|
||
|
shadow_directories: List[ShadowDir] = [
|
||
|
ShadowDir(path="/user/local/core", src="/opt/core")
|
||
|
]
|
||
|
|
||
|
def get_text_template(self, name: str) -> str:
|
||
|
if name == "example-start.sh":
|
||
|
return """
|
||
|
# sample script 1
|
||
|
# node id(${node.id}) name(${node.name})
|
||
|
# config: ${config}
|
||
|
echo hello
|
||
|
"""
|
||
|
```
|
||
|
|
||
|
#### Validation Mode
|
||
|
|
||
|
Validation modes are used to determine if a service has started up successfully.
|
||
|
|
||
|
* blocking - startup commands are expected to run til completion and return 0 exit code
|
||
|
* non-blocking - startup commands are ran, but do not wait for completion
|
||
|
* timer - startup commands are ran, and an arbitrary amount of time is waited to consider started
|
||
|
|
||
|
#### Shadow Directories
|
||
|
|
||
|
Shadow directories provide a convenience for copying a directory and the files within
|
||
|
it to a nodes home directory, to allow a unique set of per node files.
|
||
|
|
||
|
* `ShadowDir(path="/user/local/core")` - copies files at the given location into the node
|
||
|
* `ShadowDir(path="/user/local/core", src="/opt/core")` - copies files to the given location,
|
||
|
but sourced from the provided location
|
||
|
* `ShadowDir(path="/user/local/core", templates=True)` - copies files and treats them as
|
||
|
templates for generation
|
||
|
* `ShadowDir(path="/user/local/core", has_node_paths=True)` - copies files from the given
|
||
|
location, and looks for unique node names directories within it, using a directory named
|
||
|
default, when not preset
|