updates to example service and documentation supporting it

This commit is contained in:
Blake J. Harnden 2018-08-02 10:12:05 -07:00
parent 4f592d0651
commit 973a4b9d76
6 changed files with 424 additions and 56 deletions

View file

@ -2,57 +2,81 @@
Sample user-defined service. Sample user-defined service.
""" """
from core.misc.ipaddress import Ipv4Prefix
from core.service import CoreService from core.service import CoreService
from core.service import ServiceMode
## Custom CORE Service
class MyService(CoreService): class MyService(CoreService):
""" ### Service Attributes
This is a sample user-defined service.
""" # Name used as a unique ID for this service and is required, no spaces.
# a unique name is required, without spaces
name = "MyService" name = "MyService"
# you can create your own group here # Allows you to group services within the GUI under a common name.
group = "Utility" group = "Utility"
# list executables that this service requires # Executables this service depends on to function, if executable is not on the path, service will not be loaded.
executables = () executables = ()
# list of other services this service depends on # Services that this service depends on for startup, tuple of service names.
dependencies = () dependencies = ()
# per-node directories # Directories that this service will create within a node.
dirs = () dirs = ()
# generated files (without a full path this file goes in the node's dir, # Files that this service will generate, without a full path this file goes in the node's directory.
# e.g. /tmp/pycore.12345/n1.conf/) # e.g. /tmp/pycore.12345/n1.conf/myfile
configs = ("myservice.sh",) configs = ("sh myservice1.sh", "sh myservice2.sh")
# list of startup commands, also may be generated during startup # Commands used to start this service, any non-zero exit code will cause a failure.
startup = ("sh myservice.sh",) startup = ("sh %s" % configs[0], "sh %s" % configs[1])
# list of shutdown commands # Commands used to validate that a service was started, any non-zero exit code will cause a failure.
validate = ()
# Validation mode, used to determine startup success.
# * NON_BLOCKING - runs startup commands, and validates success with validation commands
# * BLOCKING - runs startup commands, and validates success with the startup commands themselves
# * TIMER - runs startup commands, and validates success by waiting for "validation_timer" alone
validation_mode = ServiceMode.NON_BLOCKING
# Time for a service to wait before running validation commands or determining success in TIMER mode.
validation_timer = 0
# Shutdown commands to stop this service.
shutdown = () shutdown = ()
### On Load
@classmethod
def on_load(cls):
# Provides a way to run some arbitrary logic when the service is loaded, possibly to help facilitate
# dynamic settings for the environment.
pass
### Get Configs
@classmethod
def get_configs(cls, node):
# Provides a way to dynamically generate the config files from the node a service will run.
# Defaults to the class definition and can be left out entirely if not needed.
return cls.configs
### Generate Config
@classmethod @classmethod
def generate_config(cls, node, filename): def generate_config(cls, node, filename):
""" # Returns a string representation for a file, given the node the service is starting on the config filename
Return a string that will be written to filename, or sent to the # that this information will be used for. This must be defined, if "configs" are defined.
GUI for user customization.
"""
cfg = "#!/bin/sh\n" cfg = "#!/bin/sh\n"
cfg += "# auto-generated by MyService (sample.py)\n"
if filename == cls.configs[0]:
cfg += "# auto-generated by MyService (sample.py)\n"
for ifc in node.netifs(): for ifc in node.netifs():
cfg += 'echo "Node %s has interface %s"\n' % (node.name, ifc.name) cfg += 'echo "Node %s has interface %s"\n' % (node.name, ifc.name)
# here we do something interesting elif filename == cls.configs[1]:
cfg += "\n".join(map(cls.subnetentry, ifc.addrlist)) cfg += "echo hello"
break
return cfg return cfg
@staticmethod ### Get Startup
def subnetentry(x): @classmethod
""" def get_startup(cls, node):
Generate a subnet declaration block given an IPv4 prefix string # Provides a way to dynamically generate the startup commands from the node a service will run.
for inclusion in the config file. # Defaults to the class definition and can be left out entirely if not needed.
""" return cls.startup
if x.find(":") >= 0:
# this is an IPv6 address ### Get Validate
return "" @classmethod
else: def get_validate(cls, node):
net = Ipv4Prefix(x) # Provides a way to dynamically generate the validate commands from the node a service will run.
return 'echo " network %s"' % net # Defaults to the class definition and can be left out entirely if not needed.
return cls.validate

View file

@ -65,7 +65,7 @@ sudo ln -s /usr/local/share/emane /usr/share/emane
## Custom EMANE Models ## Custom EMANE Models
CORE supports custom developed EMANE models by way of dynamically loading user created python files that represent the model. Custom EMANE models should be placed within the path defined by **emane_models_dir** in the CORE configuration file. This path cannot end in **emane**. CORE supports custom developed EMANE models by way of dynamically loading user created python files that represent the model. Custom EMANE models should be placed within the path defined by **emane_models_dir** in the CORE configuration file. This path cannot end in **/emane**.
Here is an example model with documentation describing functionality: Here is an example model with documentation describing functionality:
[Example Model](examplemodel.html) [Example Model](examplemodel.html)

330
docs/exampleservice.html Normal file
View file

@ -0,0 +1,330 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>sample.py</title>
<link rel="stylesheet" href="pycco.css">
</head>
<body>
<div id='container'>
<div id="background"></div>
<div class='section'>
<div class='docs'><h1>sample.py</h1></div>
</div>
<div class='clearall'>
<div class='section' id='section-0'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-0'>#</a>
</div>
<p>Sample user-defined service.</p>
</div>
<div class='code'>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">core.service</span> <span class="kn">import</span> <span class="n">CoreService</span>
<span class="kn">from</span> <span class="nn">core.service</span> <span class="kn">import</span> <span class="n">ServiceMode</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-1'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-1'>#</a>
</div>
<h1>Custom CORE Service</h1>
</div>
<div class='code'>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">MyService</span><span class="p">(</span><span class="n">CoreService</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-2'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-2'>#</a>
</div>
<h2>Service Attributes</h2>
</div>
<div class='code'>
<div class="highlight"><pre></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-3'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-3'>#</a>
</div>
<p>Name used as a unique ID for this service and is required, no spaces.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;MyService&quot;</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-4'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-4'>#</a>
</div>
<p>Allows you to group services within the GUI under a common name.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">group</span> <span class="o">=</span> <span class="s2">&quot;Utility&quot;</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-5'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-5'>#</a>
</div>
<p>Executables this service depends on to function, if executable is not on the path, service will not be loaded.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">executables</span> <span class="o">=</span> <span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-6'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-6'>#</a>
</div>
<p>Services that this service depends on for startup, tuple of service names.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">dependencies</span> <span class="o">=</span> <span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-7'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-7'>#</a>
</div>
<p>Directories that this service will create within a node.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">dirs</span> <span class="o">=</span> <span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-8'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-8'>#</a>
</div>
<p>Files that this service will generate, without a full path this file goes in the node's directory.
e.g. /tmp/pycore.12345/n1.conf/myfile</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">configs</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;sh myservice1.sh&quot;</span><span class="p">,</span> <span class="s2">&quot;sh myservice2.sh&quot;</span><span class="p">)</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-9'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-9'>#</a>
</div>
<p>Commands used to start this service, any non-zero exit code will cause a failure.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">startup</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;sh </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">configs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s2">&quot;sh </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">configs</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-10'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-10'>#</a>
</div>
<p>Commands used to validate that a service was started, any non-zero exit code will cause a failure.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">validate</span> <span class="o">=</span> <span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-11'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-11'>#</a>
</div>
<p>Validation mode, used to determine startup success.
<em> NON_BLOCKING - runs startup commands, and validates success with validation commands
</em> BLOCKING - runs startup commands, and validates success with the startup commands themselves
* TIMER - runs startup commands, and validates success by waiting for "validation_timer" alone</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">validation_mode</span> <span class="o">=</span> <span class="n">ServiceMode</span><span class="o">.</span><span class="n">NON_BLOCKING</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-12'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-12'>#</a>
</div>
<p>Time for a service to wait before running validation commands or determining success in TIMER mode.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">validation_timer</span> <span class="o">=</span> <span class="mi">0</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-13'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-13'>#</a>
</div>
<p>Shutdown commands to stop this service.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">shutdown</span> <span class="o">=</span> <span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-14'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-14'>#</a>
</div>
<h2>On Load</h2>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">on_load</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-15'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-15'>#</a>
</div>
<p>Provides a way to run some arbitrary logic when the service is loaded, possibly to help facilitate
dynamic settings for the environment.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="k">pass</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-16'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-16'>#</a>
</div>
<h2>Get Configs</h2>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">get_configs</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-17'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-17'>#</a>
</div>
<p>Provides a way to dynamically generate the config files from the node a service will run.
Defaults to the class definition and can be left out entirely if not needed.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">configs</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-18'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-18'>#</a>
</div>
<h2>Generate Config</h2>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">generate_config</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">node</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-19'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-19'>#</a>
</div>
<p>Returns a string representation for a file, given the node the service is starting on the config filename
that this information will be used for. This must be defined, if "configs" are defined.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">cfg</span> <span class="o">=</span> <span class="s2">&quot;#!/bin/sh</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="k">if</span> <span class="n">filename</span> <span class="o">==</span> <span class="bp">cls</span><span class="o">.</span><span class="n">configs</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
<span class="n">cfg</span> <span class="o">+=</span> <span class="s2">&quot;# auto-generated by MyService (sample.py)</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="k">for</span> <span class="n">ifc</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">netifs</span><span class="p">():</span>
<span class="n">cfg</span> <span class="o">+=</span> <span class="s1">&#39;echo &quot;Node </span><span class="si">%s</span><span class="s1"> has interface </span><span class="si">%s</span><span class="s1">&quot;</span><span class="se">\n</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">ifc</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">filename</span> <span class="o">==</span> <span class="bp">cls</span><span class="o">.</span><span class="n">configs</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">cfg</span> <span class="o">+=</span> <span class="s2">&quot;echo hello&quot;</span>
<span class="k">return</span> <span class="n">cfg</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-20'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-20'>#</a>
</div>
<h2>Get Startup</h2>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">get_startup</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-21'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-21'>#</a>
</div>
<p>Provides a way to dynamically generate the startup commands from the node a service will run.
Defaults to the class definition and can be left out entirely if not needed.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">startup</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-22'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-22'>#</a>
</div>
<h2>Get Validate</h2>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">get_validate</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-23'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-23'>#</a>
</div>
<p>Provides a way to dynamically generate the validate commands from the node a service will run.
Defaults to the class definition and can be left out entirely if not needed.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">validate</span>
</pre></div>
</div>
</div>
<div class='clearall'></div>
</div>
</body>

View file

@ -20,6 +20,7 @@ CORE is typically used for network and protocol research, demonstrations, applic
* [Python Scripting](scripting.md) * [Python Scripting](scripting.md)
* [Node Types](machine.md) * [Node Types](machine.md)
* [CTRLNET](ctrlnet.md) * [CTRLNET](ctrlnet.md)
* [Services](services.md)
* [EMANE](emane.md) * [EMANE](emane.md)
* [NS3](ns3.md) * [NS3](ns3.md)
* [Performance](performance.md) * [Performance](performance.md)

View file

@ -16,7 +16,7 @@ CORE files are installed to the following directories, when the installation pre
Install Path | Description Install Path | Description
-------------|------------ -------------|------------
/usr/local/bin/core-gui|GUI startup command /usr/bin/core-gui|GUI startup command
/usr/bin/core-daemon|Daemon startup command /usr/bin/core-daemon|Daemon startup command
/usr/bin/|Misc. helper commands/scripts /usr/bin/|Misc. helper commands/scripts
/usr/lib/core|GUI files /usr/lib/core|GUI files
@ -66,8 +66,8 @@ sudo apt-get install quagga
Install the CORE deb packages for Ubuntu from command line. Install the CORE deb packages for Ubuntu from command line.
```shell ```shell
sudo dpkg -i python-core_systemd_5.1_all.deb sudo dpkg -i python-core_*.deb
sudo dpkg -i core-gui_5.1_amd64.deb sudo dpkg -i core-gui_*.deb
``` ```
Start the CORE daemon as root, the systemd installation will auto start the daemon, but you can use the commands below if need be. Start the CORE daemon as root, the systemd installation will auto start the daemon, but you can use the commands below if need be.
@ -122,8 +122,8 @@ yum install quagga
Install the CORE RPM packages and automatically resolve dependencies: Install the CORE RPM packages and automatically resolve dependencies:
```shell ```shell
yum install python-core_sysv_5.1_noarch.rpm yum install python-core_*.rpm
yum install core-gui_5.1_x86_64.rpm yum install core-gui_*.rpm
``` ```
Turn off SELINUX by setting *SELINUX=disabled* in the */etc/sysconfig/selinux* file, and adding *selinux=0* to the kernel line in your */etc/grub.conf* file; on Fedora 15 and newer, disable sandboxd using ```chkconfig sandbox off```; you need to reboot in order for this change to take effect Turn off SELINUX by setting *SELINUX=disabled* in the */etc/sysconfig/selinux* file, and adding *selinux=0* to the kernel line in your */etc/grub.conf* file; on Fedora 15 and newer, disable sandboxd using ```chkconfig sandbox off```; you need to reboot in order for this change to take effect
@ -179,8 +179,8 @@ sudo apt-get install
You can obtain the CORE source from the [CORE GitHub](https://github.com/coreemu/core) page. Choose either a stable release version or the development snapshot available in the *nightly_snapshots* directory. You can obtain the CORE source from the [CORE GitHub](https://github.com/coreemu/core) page. Choose either a stable release version or the development snapshot available in the *nightly_snapshots* directory.
```shell ```shell
tar xzf core-5.1.tar.gz tar xzf core-*.tar.gz
cd core-5.1 cd core-*
./bootstrap.sh ./bootstrap.sh
./configure ./configure
make make

13
docs/services.md Normal file
View file

@ -0,0 +1,13 @@
# CORE Services
* Table of Contents
{:toc}
## Custom Services
CORE supports custom developed services by way of dynamically loading user created python files.
Custom services should be placed within the path defined by **custom_services_dir** in the CORE
configuration file. This path cannot end in **/services**.
Here is an example service with documentation describing functionality:
[Example Service](exampleservice.html)