COREのCustom Serviceを使ってみる

### CORE(Common Open Research Emulator)とは？
気軽にネットワークを構築して試すことができるOSSのエミュレータ，ネットワーク系の研究とかで使うかも．
https://www.nrl.navy.mil/itd/ncs/products/core

### カスタムサービスとは?
COREはエミュレートするホスト上でサービスを実行することができ，ルーティング・プロトコルやHTTPサーバ，SSHサーバ，ファイアウォールなど様々な役割のサービスが予め用意されている．
ホストは設定から実行したいサービスにチェックを入れるだけで手軽にその機能を使えるのが魅力的だ．
一方で自作したアプリケーションを試したい，自作のプロトコルを作成して試したい，といった場合はユーザ定義であるカスタムサービスを定義しなくてはならない．

### 環境
- OS: Manjaro 18.0.4 Illyria
- Software:
    - core-daemon v.5.1
    - core-gui v.5.1
- Runtime:
    - Python2.7.16

### 手順
やるべきことは`~/.core/myservices/README.txt`に書いてある．
(随分と大雑把なのでちょっと分かりづらい...)

#### COREにカスタムサービスを認識
`/etc/core/core.conf`に以下の行を追加
(ユーザ名が`hetare`の場合)

```conf
custom_services_dir = /home/hetare/.core/myservices
```

#### サービスファイルを作成
サービスファイルではサービスに対応するクラスを作成し，各設定をプロパティに，動的設定はメソッドに記述する．
各プロパティやメソッドの説明は次のファイルにかかれている．
https://github.com/coreemu/core/blob/master/docs/exampleservice.html

`~/.core/myservices/hogehoge.py`に以下のソースを記述.

```python
"""
HogeHoge user-defined service.
"""

from core.misc.ipaddress import Ipv4Prefix
from core.misc.ipaddress import Ipv6Prefix
from core.service import CoreService
from core.service import ServiceManager


class HogeHoge(CoreService):
    """
    This is a sample user-defined service.
    """
    # a unique name is required, without spaces
    _name = "HogeHoge"
    # you can create your own group here
    _group = "Utility"
    # list of other services this service depends on
    _depends = ()
    # per-node directories
    _dirs = ("/tmp/hogehoge/",)
    # generated files (without a full path this file goes in the node's dir,
    #  e.g. /tmp/pycore.12345/n1.conf/)
    _configs = ('hoge.sh',)
    # this controls the starting order vs other enabled services
    _startindex = 50
    # list of startup commands, also may be generated during startup
    _startup = ('sh hoge.sh',)
    # list of shutdown commands
    _shutdown = ()

    @classmethod
    def generateconfig(cls, node, filename, services):
        """
        Return a string that will be written to filename, or sent to the
        GUI for user customization.
        """
        cfg = "#!/bin/sh\n"
        cfg += "# auto-generated by HogeHoge (hogehoge.py)\n"

        for ifc in node.netifs():
            cfg += 'echo "Node %s has interface %s"\n' % (node.name, ifc.name)
            # here we do something interesting
            cfg += "\n".join(map(cls.subnetentry, ifc.addrlist))
            break
        return cfg

    @staticmethod
    def subnetentry(x):
        """
        Generate a subnet declaration block given an IPv4 prefix string
        for inclusion in the config file.
        """
        if x.find(":") >= 0:
            net = Ipv6Prefix(x)
            return 'echo "  network %s" > prefix.txt' % net
        else:
            net = Ipv4Prefix(x)
            return 'echo "  network %s" > prefix.txt' % net

# this is needed to load desired services when being integrated into core, otherwise this is not needed
def load_services():
    # this line is required to add the above class to the list of available services
    ServiceManager.add(HogeHoge)
```

#### カスタムサービスを登録
COREは`~/.core/myservices/__init__.py`で読み込むカスタムサービスのリストを読み取る．

```python
"""myservices

Custom services that you define can be put in this directory.  Everything
listed in __all__ is automatically loaded when you add this directory to the
custom_services_dir = '/full/path/to/here' core.conf file option.
"""
__all__ = ["sample", "hogehoge"]
```

#### core-daemonの再起動
core-daemonを再起動して設定を反映．

```shell
$ sudo systemctl restart core-daemon
```
core-guiを起動，適当なノードを配置してConfig→ServiceからHogeHogeサービスが追加されていることを確認し，HogeHogeサービスをONにする．
![DeepinScreenshot_select-area_20190529001924.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173763/eaf6804c-fc5b-c9f9-987f-8029183ca0bc.png)
ネットワークを稼働させ，n1ノードのコンソールから`prefix.txt`を確認すると，起動時に`hoge.sh`が実行されていることがわかる．
![DeepinScreenshot_select-area_20190529002000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173763/c54a416b-2ec4-572f-aae1-421189792677.png)

#### 使いどころ
COREは全てのディレクトリツリーを分離しているわけではなく，ここでdirsやconfigsに記述されたものだけがnamespaceでホストとは異なる空間を利用することになる．
そのため，サービスでエントリーポイントとconfigだけ配置しておき，実行ファイル自体はホストの適当なところに置くというスタイルになりそう．