Sharing

2012年7月27日 星期五

Avahi 筆記

Avahi 是一個在內網內, 用來廣播自己是什麼服務以及用來尋找那些服務的一個工具, 有點像是在一個社區內有個廣播系統, 大家利用他就可以找到郵局在那裡, 醫院在那裡, 而不必事先知道郵局或醫院的名字. 據了解 avahi 是利用 multicast 來做到這件事,安裝上要細分的話可以分成 server 以及 client.


client 的部份主要是用來聽廣播, 得到網路上所有可使用的服務.
pjack@ubuntu:~$ sudo apt-get install avahi-utils
pjack@ubuntu:~$ avahi-browse --help
avahi-browse [options] <service type>
avahi-browse [options] -a
avahi-browse [options] -D
avahi-browse [options] -b

    -h --help            Show this help
    -V --version         Show version
    -D --browse-domains  Browse for browsing domains instead of services
    -a --all             Show all services, regardless of the type
    -d --domain=DOMAIN   The domain to browse in
    -v --verbose         Enable verbose mode
    -t --terminate       Terminate after dumping a more or less complete list
    -c --cache           Terminate after dumping all entries from the cache
    -l --ignore-local    Ignore local services
    -r --resolve         Resolve services found
    -f --no-fail         Don't fail if the daemon is not available
    -p --parsable        Output in parsable format
    -k --no-db-lookup    Don't lookup service types
    -b --dump-db         Dump service type database

# 不間斷的聽取廣播內容, 一但有更新就會顯示出來
pjack@ubuntu:~$ avahi-browse -a
+   eth0 IPv6 Virtualization Host centos                    Virtual Machine Manager local
+   eth0 IPv4 Virtualization Host centos                    Virtual Machine Manager local

# 你也可以只聽特定的服務, 並且加上 -t 參數, 表示不需要持續的聽廣播
pjack@ubuntu:~$ avahi-browse -t _nodeinfo._tcp
+   eth0 IPv6 bmc-00:26:2d:0a:35:a4                         _nodeinfo._tcp       local
+   eth0 IPv4 bmc-00:26:2d:0a:35:a4                         _nodeinfo._tcp       local


# 可以再加上 -r, 除了可以獲得該服務的 ip address/hostname 之外, 
# 其實有時候該服務也會加上更多有關自己的訊息在 "txt" 欄位
pjack@ubuntu:~$ avahi-browse -r -t _mongodb._tcp
+   eth0 IPv4 db on mongodb-001                              _mongodb._tcp      local
=   eth0 IPv4 db on mongodb-001                              _mongodb._tcp      local
   hostname = [mongodb-001.local]
   address = [172.17.255.33]
   port = [0]
   txt = []

# -p 這個參數是把 output 格式變成方便處理一點, 但在舊一點的版本還沒有這個功能
pjack@ubuntu:~$ avahi-browse -r -p -t _mongodb-db._tcp
+;eth0;IPv4;db\032on\032mongodb-001;_mongodb._tcp;local
=;eth0;IPv4;db\032on\032mongodb-001;_mongodb._tcp;local;mongodb-001.local;172.17.255.33;0;


server 的部份主要是要告訴大家你自己是誰, 提供什麼服務
pjack@ubuntu:~$ sudo apt-get install avahi-daemon

裝好 package 之後, 就可以開始編寫你自己的服務, 預設是放在 /etc/avahi/services 下, 而在 /usr/share/doc/avahi-daemon/examples 裡有一些現成的範例
主要需要設定的
1. service protocol, ipv4/ipv6/all
2. service 名稱,
3. port number
其它細節可以參考這裡
http://manpages.ubuntu.com/manpages/precise/man5/avahi.service.5.html
<service-group>

  <name replace-wildcards="yes">%h</name>

  <service protocol="ipv4">
    <type>_ssh._tcp</type>
    <port>22</port>
  </service>

</service-group>

在顯示上不想要顯示 _xxxx._tcp 可以透過設定 /usr/share/avahi/service-types
那就可以讓別人看到 Human readable 的文字
pjack@ubuntu:~$ avahi-browse -t _libvirt._tcp
+   eth0 IPv6 Virtualization Host localhost                 Virtual Machine Manager local

實際應用上, 我曾因為 ipv6 打開的關係造成了一些困擾, 所以如果想要把 ipv6 關掉, 可以在 /etc/avahi/avahi-daemon.conf 內關掉 ipv6. 也可以設定只對那些 interface 發送廣播.
[server]
#host-name=foo
#domain-name=local
#browse-domains=0pointer.de, zeroconf.org
use-ipv4=yes
use-ipv6=no
allow-interfaces=eth0

因為 avahi 是一個 daemon, 如果想要和這個 daemon 溝通, 可以通過 dbus. 下面是 Python 的範例. 有一次我無法將 avahi-daemon 叫起來, 後來才發現是 dbus 這個 service 死掉了, 一但把 dbus 叫起來之後, avahi 就可以啟動了
http://stackoverflow.com/questions/3430245/how-to-develop-an-avahi-client-server
pjack@ubuntu:/etc/avahi$ ps aux | grep daemon
102        506  0.0  0.0  23908  1000 ?        Ss   08:48   0:00 dbus-daemon --system --fork --activation=upstart
avahi      523  0.0  0.0  32560  1952 ?        S    08:48   0:00 avahi-daemon: running [wistor.local]
avahi      524  0.0  0.0  32172   472 ?        S    08:48   0:00 avahi-daemon: chroot helper

如果覺得透過 dbus 溝通有點麻煩的話, 也可以直接透過 bash command, 下面是我寫的一個小程式
def _avahi_browse(service):
    output = subprocess.check_output('avahi-browse -r -t %s' % service, shell=True)

    node = {}
    nodes = []
    for line in output.splitlines():
        if line.startswith(' '):
            key,value = line.split('=')
            key = key.strip(' ')
            value = value.strip(' []')
            node.update({key:value})
        else:
            if node:
                node['hostname'] = node['hostname'].strip('.local')
                nodes.append(node)
            node = {}
    if node:
        node['hostname'] = node['hostname'].strip('.local')
        nodes.append(node)
    return nodes


最後分享的一個經驗是, 在使用 avahi 要注意的一點就是他為了要降低 loading, 所以更新的速度並不是很快, 一般他都是直接從 cache 裡面抓資料給你, 所以有時你會發現有的服務不存在了, 但從 avahi-browse 還是會看到它, 所以拿到資料後, 你還是要處理有可能服務已經不存在的情況. 不過如果有新的服務加進來, 因為是主動 broadcast, 所以你一定會接到更新. 如果你一定要拿到最新的情況, 目前我已知的方法就只有重啟 avahi-daemon, 比較耗時間.



Reference link:

http://manpages.ubuntu.com/manpages/precise/man5/avahi.service.5.html
http://manpages.ubuntu.com/manpages/precise/man8/avahi-daemon.8.html
http://manpages.ubuntu.com/manpages/precise/man1/avahi-browse.1.html
http://en.gentoo-wiki.com/wiki/Avahi


沒有留言: