2015年5月31日 星期日

初探 Ubuntu Snappy


最近 Canonical 公司在 IoT 的浪潮下,也開始力推自己的系統,稱為 Snappy ;例如這個 Canonical 的創辦人在 youtube 的介紹影片。喜歡湊熱鬧的我,也跳進來攪和了一下,瞧瞧 Snappy 究竟是什麼。

這次湊熱鬧所選用的硬體為 Raspberry Pi 2 (RP2)。下面的 demo 主要是參考 Snappy 官方文件,加上一些個人心得。



事前準備

Snappy 在 RP2 上面目前(2015五月)還沒有官方釋出,不過已經有開發者準備好了移植到 RP2 的映像檔案,可以從這裡下載,取得映像檔 pi2.img.gz 。解壓縮後取得檔案 pi2.img ,將 pi2.img 透過指令 dd 寫入 micro SD 裝置 /dev/sdX (根據你的系統狀況,請自行用適當字串代換 sdX ) [1][2]

sudo dd if=pi2.img of=/dev/sdX

映像檔接近 4G ,讀寫要花上一點時間。如果想知道 dd 的進度,可以用這個技巧偷看一下寫入進度。讀寫完畢後,將 micro SD 插到 RP2 上面、開啟電源。預設帳號、密碼都是 ubuntu ,登入後就可以開始玩了。

因為設計上是給物連網 client 端產品使用,基於效能考量,當然不會有圖形介面。操作上可以選擇使用 RP2 的 HDMI 輸出,或是像我所採取的作法:第一次使用 HDMI 登入,登入後使用 ifconfig 取得 RP2 Snappy 的 IP ,之後都透過自己慣用的作業系統,透過 ssh 登入 RP2 Snappy 。RP2 Snappy image 已經將 ssh server 服務事先準備好,因此直接從慣用的作業連過去就好。[3] 例如使用這個指令(IP 位置視您的環境而定):

ssh ubuntu@<您的 RP2 Snappy IP>
ex.
ssh ubuntu@192.168.1.23



Let's party!!

接下來就是今天的重頭戲了。下達指令 snappy info

(RaspberryPi2)ubuntu@localhost:~$ snappy info
release: ubuntu-core/devel
architecture: armhf
frameworks: 
apps: 

release 和 architecture 分別就是 image release 版本和適用的平台類型,RP2 使用 ARM ,所以是 armhf 版本。frameworks 和 apps 分別是什麼意思呢? 望文生義, apps 很明顯就是 applications ,那 frameworks 呢?

簡而言之,根據官方文件,framework 在這邊指的是一個獨立的、因目的導向而事先配置好所需軟硬體資源存取管道的「環境」。

「獨立的」,意指各個 framework (與該 framework 下的 apps) 彼此之間不互相影響,所以可以顧及安全問題(檔案權限不會被亂改、存放密碼的檔案別人讀不到等)。

一般 IoT client side device,通常為了滿足某種目的,都會依照該目的,去設計、製造、配置所需的對應資源。例如,假設有個瓦斯洩漏偵測器,可以在偵測到一氧化碳時,將警告與一氧化碳濃度值送到我們的手機裡面。所以這個裝置,起碼必須要有一氧化碳偵測器、網路連線(此處假設我們選用乙太網路)。而一個這樣的瓦斯洩漏偵測器 framework ,就會保證所有在這個偵測器下的 applications ,可以取用到一氧化碳偵測器的讀數、和取用系統乙太網路資料。

說得落落長又很抽象,直接舉例,docker 就可以是一個提供 framework 服務的工具。

接著我們看一下這個 snappy 系統中,裝了什麼 snappy 套件

(RaspberryPi2)ubuntu@localhost:~$ snappy list
Name        Date       Version Developer 
ubuntu-core 2015-04-10 4                 
pi2         2015-04-15 0.11    lool

系統還很乾淨,就只有 ubuntu-core (官方文件稱這是一種 system-layer)和 pi2 (官方文件稱這個叫做 OEM snappy package or device) 而已。[4]

好吧!我們來裝 framework 和 app 吧!

framework 我們選擇使用 docker ;可以看出來裝了 docker 之後, snappy list 就多了這個 snappy package 。

(RaspberryPi2)ubuntu@localhost:~$ sudo snappy install docker
Installing docker
Starting download of docker.canonical
8.36 MB / 8.36 MB [====================================] 100.00 % 41.93 KB/s 
Done
Name        Date       Version   Developer 
ubuntu-core 2015-04-10 4                   
docker      2015-05-31 1.6.1.002           
pi2         2015-04-15 0.11      lool  
    
(RaspberryPi2)ubuntu@localhost:~$ snappy list
Name        Date       Version   Developer 
ubuntu-core 2015-04-10 4                   
docker      2015-05-31 1.6.1.002           
pi2         2015-04-15 0.11      lool      

請注意這時候已經有 framework docker 了[5]

(RaspberryPi2)ubuntu@localhost:~$ snappy info
release: ubuntu-core/devel
architecture: armhf
frameworks: docker
apps: 

app 我們選用 go-example-webserver

(RaspberryPi2)ubuntu@localhost:~$ sudo snappy install go-example-webserver
Installing go-example-webserver
Starting download of go-example-webserver.canonical
3.06 MB / 3.06 MB [================================] 100.00 % 44.75 KB/s
Done
Name                 Date       Version   Developer 
ubuntu-core          2015-04-10 4                   
docker               2015-05-31 1.6.1.002           
go-example-webserver 2015-05-31 1.0.7               
pi2                  2015-04-15 0.11      lool  
(RaspberryPi2)ubuntu@localhost:~$ snappy list
Name                 Date       Version   Developer 
ubuntu-core          2015-04-10 4                   
docker               2015-05-31 1.6.1.002           
go-example-webserver 2015-05-31 1.0.7               
pi2                  2015-04-15 0.11      lool    

這時候 apps 果然也補上了 go-example-webserver

(RaspberryPi2)ubuntu@localhost:~$ snappy info
release: ubuntu-core/devel
architecture: armhf
frameworks: docker
apps: go-example-webserver

go-example-webserver 是一個用 go 寫成、用來做 snappy 打包教學的 snappy 套件,原始碼可以在 Launchpad 上面找到。

當初以為裝了 go-example-webserver 以後,web server 的服務會自己啟動,搞了半天發現根本沒有自己啟動,不曉得這是 by-design 還是一個 bug 。最後我直接參考原始碼(裡面有 README),手動尋找執行 web 服務的指令、並且啟用服務:

尋找可能可以用的指令

root@localhost:/# find ./ -name go-example-webserver
./var/lib/apps/go-example-webserver
./writable/system-data/var/lib/apps/go-example-webserver
./writable/system-data/apps/go-example-webserver
./writable/system-data/apps/go-example-webserver/1.0.7/magic-bin/go-example-webserver
./writable/system-data/apps/go-example-webserver/1.0.7/magic-bin/arm-linux-gnueabihf/go-example-webserver
./writable/system-data/apps/go-example-webserver/1.0.7/magic-bin/x86_64-linux-gnu/go-example-webserver
./apps/go-example-webserver
./apps/go-example-webserver/1.0.7/magic-bin/go-example-webserver
./apps/go-example-webserver/1.0.7/magic-bin/arm-linux-gnueabihf/go-example-webserver
./apps/go-example-webserver/1.0.7/magic-bin/x86_64-linux-gnu/go-example-webserver

這裡有兩點滿有意思,第一是 /var/lib/apps/go-example-webserver 是空的,不曉得在其他 Snappy package 中,實際上會放入什麼樣類型的檔案。第二是整個 app 程式似乎就是集中在 /apps 這個資料夾裡。

找到疑似可以用的可執行檔後,直接給他執行下去啦!

(RaspberryPi2)ubuntu@localhost:/apps/go-example-webserver/1.0.7$ ./magic-bin/go-example-webserver 
snapp_name: go-example-webserver
snapp_bin: go-example-webserver
snapp_dir: /apps/go-example-webserver/1.0.7
snapp_org_bin: go-example-webserver
plat_abi: arm-linux-gnueabihf
2015/05/31 10:06:53 Starting webserver on :8081

最後開啟本地端(不是 RP2 ,而是,例如說,你慣用的作業系統)的瀏覽器,瀏覽器 url 填入 RP2 的 IP ,port 8081 (這是上面執行時,程式告訴我的)。一切順利的話,應該就可以看到下面的畫面。另外,在 RP2 中可以使用 ctrl+c 以中斷程式伺服器服務的運行。





[1] 注意!!這個指令在使用之前務必確定知道自己在做什麼。這個指令操作錯誤的話有可能抹除您系統裡面的資料。

[2] 如果使用上有問題,例如 Snappy 操作起來怪怪的,像我遇到的問題就是明明已經把 docker 裝上去了,但是 snappy list 卻看不到這個訊息。遇到這種情況的話,可以試試 dd 前先把 micro SD 上面的 partition 全部清掉之後,再用 dd 寫入。寫入完畢後,下達兩三次 sync 指令,確認所有必要的訊息都寫進 micro SD ,再將 micro SD 退出、插到 RP2 上面。

[3] 在這之前,當然要先確定慣用的作業系統和 RP2 在同一個、彼此可以看見彼此、允許 ssh 通訊 port 的網域。

[4] 根據官方文件,在未來 system-layer 和 device package 會整合成一個 snappy package 。

[5] Snappy for RP2 似乎不太穩定;有時候我明明已經裝了 docker ,但是把系統放在那邊一陣子,大約二十分鐘, snappy info 卻看不到 docker 了。reboot 之後再安裝一次 docker 還會報錯。不太確定是不是自己有哪裡不清楚,或是真的是一個 bug ;需要更多測試與資訊。

2015年5月29日 星期五

找不到,等於沒有擁有 - 談日常生活中的知識管理 (一)(針對日期使用 find 指令)

檢索能力,其實本質上是提高自己行事效率的手段之一:自己不必重新蒐集、思考自己曾經從資訊中提煉出來、成為知識的東西。在資訊爆炸時代的現在,四周有著更多 buzz words 、各種產業、技術不斷地翻新,前進速度不夠快、一直耗在重新提煉舊知識的人,最終就是跟不上時代。因此,在當代,檢索能力更顯得重要。

出處我已經想不起來了,記得很久以前,曾經聽來一句話,大意是說

「當你需要使用的時候,卻沒辦法找出來的資訊、物品,等價於你沒有擁有他」

這句話滿深刻地改變了我的一些生活哲學,包括自我知識庫(包括照片等回憶)的管理。現在我在評估檢索資訊效率時,所採納的標準為:「自己需要的資訊,能不能夠從自己的知識庫中,在九十秒內取出。如果不能,該次知識的建立就是失敗的。」

小學還是國中時做的剪報(天啊好老派),過去重新取用裡面資訊的次數大概一隻手數得完,而且,裡面的資料我幾乎只能從第一頁翻到最後一頁才能決定哪些是我要的資訊。這顯然是個非常失敗的建立自我資料庫行為。類似這樣不斷囤積資料的習慣在我的一生中持續地進行著至今。幸好,今日資訊系統的軟、硬體效能與普及率,已經不像是當年,那個可能只能選擇剪報的時代,而因此讓我可以不斷改進自己的檢索方式。

從這篇起,我打算陸續整理一些自己日常生活中,所使用的知識管理方式。這些方式不一定是最好的方式,所以也歡迎大家批評、賜教。




案例:

  • 我想要找一張某次我收看網路直播的活動時,自己的螢幕截圖。


手上有的索引資訊:
  • 不記得自己的螢幕截圖是否有好好重新把檔案命名,以便索引。
  • 記得活動名稱、當時的主持人名字。
  • 不記得活動日期。

檢索過程:

  • 手動大概翻一些可能的資料夾未果。不願意投入更多時間成本做土砲搜尋。
  • 大概用關鍵字對自己的電腦做搜尋,但因為知道不記得自己的螢幕截圖是否有好好重新把檔案命名
  • 使用活動名稱、當時的主持人名字,因此取得活動時大概的日期。
  • 使用日期,在可能的資料夾下,針對檔案更動、讀寫日期做搜尋。請見下面指令。
  • 只有不到十筆資料,經檢視後順利取得自己想要的圖片。
find ./Documents/ ./Pictures/ -type f -newermt 2011-09-22 ! -newermt 2011-09-23




指令參考:
http://stackoverflow.com/questions/158044/how-to-use-find-to-search-for-files-created-on-a-specific-date

2015年5月25日 星期一

64-bit Ubuntu booting failure - workaround

A known UEFI BIOS issue like Bug No. 1444834 of Launchpad[1] will make systems failed to boot. A workaround[2][3][4] is:

1. cp /EFI/ubuntu/*.efi /EFI/boot/
2. mv /EFI/boot/shimx64.efi /EFI/boot/bootx64.efi
3. reboot. then you should boot into the system.


[1] install 64-bit Ubuntu on a 64-bit machine with UEFI mode.
[2] https://www.facebook.com/groups/ubuntu.zh.hant/permalink/897991146922875/
[3] Thanks for the trick! $4!
[4] Facebook is so hard to search. This is creating a knowledge black hole.






在 UEFI 模式下安裝 Ubuntu 如果遇到像是 Bug No. 1444834 of Launchpad[1] 這種本質上是 BIOS 的臭蟲導致不能順利開機時,可以試試這個 workaround[2][3][4]:

1. cp /EFI/ubuntu/*.efi /EFI/boot/
2. mv /EFI/boot/shimx64.efi /EFI/boot/bootx64.efi
3. 重開機。這樣就可以順利進入系統了。

[1] 在 64 位元的機器上、使用 UEFI mode 安裝 64 位元版本的 Ubuntu
[2] https://www.facebook.com/groups/ubuntu.zh.hant/permalink/897991146922875/
[3] 謝謝 $4 提供 workaround
[4] 使用臉書做搜尋效果很差,這正在導致知識黑洞的產生。

2015年5月1日 星期五

正規表示式:描述「空白或是數字」




今天遇到一個 bug:一個用來抽取 iso 檔案並加以分析的 python script,錯誤回報說在該 iso 找不到必要的檔案 intrd.lz ,但我手動使用指令去抽取該 iso 檔,確認了裡面明明就有這個檔案。

後來發現 bug 在於以往成功提取資訊的時候,該 script 利用下面正規表示,分析下面的字串:

file_re = re.compile(

    "(?P[ldrwx-]{10})\s+\d+\s+\d+\s+\d+\s+\d+\s[A-Za-z]{3}"+ 

    "\s+\d+\s\d+\s+\[\s+\d+\s\d\d\](\s\s(?P.*))?")

其實就是這串

(?P[ldrwx-]{10})\s+\d+\s+\d+\s+\d+\s+\d+\s[A-Za-z]{3}\s+\d+\s\d+\s+\[\s+\d+\s\d\d\](\s\s(?P.*))?

去分析

-r--r--r--   1    0    0        16242610 Aug  9 2013 [ 601511 00]  initrd.lz

目的是希望可以分別找出匹配字串「-r--r--r--」與「initrd.lz」。


而出問題的是,當 script 嘗試去分析這個字串的時候,沒有得到預期的答案。

-r--r--r--   1    0    0        16437443 Nov 12 2013 [1062241 00]  initrd.lz

請注意會引起問題的字串中,有個被標示成紅色的「1」,相對於不會引起問題的字串,那個地方是個空白。所以要解決這個 bug ,只要把原本硬性描述「該空白處必須是一個或是多個空白」而使用「\s+」,換成「該地方可以是空白或是數字」。

以下兩個方法在這個問題中等價,都可以匹配出第一個 pattern 是 「-r--r--r--」而第二個是「initrd.lz」。

原本的字串:標紅色表示要被修改的部份

(?P[ldrwx-]{10})\s+\d+\s+\d+\s+\d+\s+\d+\s[A-Za-z]{3}\s+\d+\s\d+\s+\[\s+\d+\s\d\d\](\s\s(?P.*))?



解法一:改成「一個空白」加上一個星號

(?P[ldrwx-]{10})\s+\d+\s+\d+\s+\d+\s+\d+\s[A-Za-z]{3}\s+\d+\s\d+\s+\[ *\d+\s\d\d\](\s\s(?P.*))?



解法二:注意「0-9」的前面也有一個空白,使用數字 5、8 是給實際數字位數一點容忍量,在這個案例中,一個 7 就夠用了。

(?P[ldrwx-]{10})\s+\d+\s+\d+\s+\d+\s+\d+\s[A-Za-z]{3}\s+\d+\s\d+\s+\[[ 0-9]{5,8}\s\d\d\](\s\s(?P.*))?



附錄資料:

  • 好用的線上正規表示式解讀器;若完全只用人腦翻譯真的實在太辛苦了。
  • https://atedev.wordpress.com/2007/11/23/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%A4%BA%E5%BC%8F-regular-expression/
  • http://notepad.yehyeh.net/Content/Program/RegularExpression/8.php
  • http://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F
  • http://stackoverflow.com/questions/18701992/regex-space-or-no-space
  • python 2 的 re module 說明文件
  • 簡易語法參考:
    • \s 一個空白,\s+ 多個空白
    • \d 一個數字,\d+ 多個數字
    • \[ 跳脫字元和一個「[」,表示我想要匹配「[」
    • * 星號表示星號前面的元素有沒有出現、而且可以出現多次。一個空白加一個星號就是「有沒有空白無所謂,也可以有多個空白」
    • [ 0-9]{5,8}  允許一個空白(注意 0 前面有個空白)、數字零到九,並且只匹配出現那樣的元素 5 到 8 個。