docs: adding initial documentation to help cover using config services
This commit is contained in:
parent
35a285daa2
commit
bd3e2f5d0e
3 changed files with 209 additions and 3 deletions
206
docs/configservices.md
Normal file
206
docs/configservices.md
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
# 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
|
|
@ -29,6 +29,7 @@ networking scenarios, security studies, and increasing the size of physical test
|
||||||
|[gRPC API](grpc.md)|Covers how control core using gRPC|
|
|[gRPC API](grpc.md)|Covers how control core using gRPC|
|
||||||
|[Distributed](distributed.md)|Details for running CORE across multiple servers|
|
|[Distributed](distributed.md)|Details for running CORE across multiple servers|
|
||||||
|[Control Network](ctrlnet.md)|How to use control networks to communicate with nodes from host|
|
|[Control Network](ctrlnet.md)|How to use control networks to communicate with nodes from host|
|
||||||
|
|[Config Services](configservices.md)|Overview of provided config services and creating custom ones|
|
||||||
|[Services](services.md)|Overview of provided services and creating custom ones|
|
|[Services](services.md)|Overview of provided services and creating custom ones|
|
||||||
|[EMANE](emane.md)|Overview of EMANE integration and integrating custom EMANE models|
|
|[EMANE](emane.md)|Overview of EMANE integration and integrating custom EMANE models|
|
||||||
|[Performance](performance.md)|Notes on performance when using CORE|
|
|[Performance](performance.md)|Notes on performance when using CORE|
|
||||||
|
|
|
@ -149,12 +149,11 @@ ideas for a service before adding a new service type.
|
||||||
to do what you want. It could generate config/script files, mount per-node
|
to do what you want. It could generate config/script files, mount per-node
|
||||||
directories, start processes/scripts, etc. sample.py is a Python file that
|
directories, start processes/scripts, etc. sample.py is a Python file that
|
||||||
defines one or more classes to be imported. You can create multiple Python
|
defines one or more classes to be imported. You can create multiple Python
|
||||||
files that will be imported. Add any new filenames to the __init__.py file.
|
files that will be imported.
|
||||||
|
|
||||||
2. Put these files in a directory such as /home/username/.core/myservices
|
2. Put these files in a directory such as /home/username/.core/myservices
|
||||||
Note that the last component of this directory name **myservices** should not
|
Note that the last component of this directory name **myservices** should not
|
||||||
be named something like **services** which conflicts with an existing Python
|
be named something like **services** which conflicts with an existing module.
|
||||||
name (the syntax 'from myservices import *' is used).
|
|
||||||
|
|
||||||
3. Add a **custom_services_dir = /home/username/.core/myservices** entry to the
|
3. Add a **custom_services_dir = /home/username/.core/myservices** entry to the
|
||||||
/etc/core/core.conf file.
|
/etc/core/core.conf file.
|
||||||
|
|
Loading…
Reference in a new issue