星期三, 2月 14, 2018

DNS SRV record missing

在 CentOS 7 新裝的 Openfire 有這樣的問題

點進去看到的是

意思是 Openfire 本身希望能找到最下面兩行類似的資訊,所以來幫忙如願即可。首先需要安裝名稱解析伺服器:
  • sudo yum install bind bind-utils
裝好後先增加設定,依據網域名稱(假設是 acme.com)修改 /etc/named.conf,增加以下幾行新增一個區域:
  • zone "acme.com" {
  •     type master;
  •     file "/etc/named/acme.com.hosts";
  • };
依據該主機名為 openfire.acme.com,IP 位址為 10.1.2.3,管理者郵件位址為 root@mail.acme.com 的前提,再新增這個區域的設定檔 /etc/named/acme.com.hosts,內容如下:
  • $ORIGIN acme.com.
  • @ IN SOA openfire root.mail (
  • 180214 ; serial
  • 21600 ; refresh after 6 hours
  • 3600 ; retry after 1 hour
  • 604800 ; expire after 1 week
  • 86400 ) ; minimum TTL of 1 day
  • IN NS openfire
  • openfire IN A 10.1.2.3
  • _xmpp-client._tcp 86400 IN SRV 0 5 5222 openfire
  • _xmpp-server._tcp 86400 IN SRV 0 5 5269 openfire
其實最後兩行就是照抄管理介面上的提示,要特別注意的是很多結尾處的 . 不可省略。接著啟動服務並測試看看:
  • systemctl start named
  • nslookup -type=srv _xmpp-client._tcp.acme.com
如果找不到,可以試試指定本機擔任名稱伺服器:
  • nslookup -type=srv _xmpp-client._tcp.acme.com localhost
若這樣才行,代表預設的名稱伺服器在別處,不是剛裝的這套,可以修改 /etc/resolv.conf 以解決。

星期日, 2月 04, 2018

application as a service on CentOS 6 / 7

在部署要求中,常會希望某個指令啟動的應用程式,不會因重開機而停止服務。以 Single Sign-On CAS 為例,若在 CentOS 6,可參考這篇準備以下內容的 /etc/rc.d/init.d/<serviceName>:
  • #!/bin/bash
  • # chkconfig: 35 90 10
  • # description: CAS server

  • . /etc/init.d/functions

  • SERVICE=cas
  • WORKDIR=/opt/$SERVICE
  • LOCK=/var/lock/subsys/$SERVICE

  • start() {
  •   cd $WORKDIR
  •   /usr/bin/java -jar cas.war &
  •   touch $LOCK
  • }

  • stop() {
  •   killproc $SERVICE
  •   rm -f $LOCK
  • }

  • case "$1" in
  •   start)
  •     start
  •     ;;
  •   stop)
  •     stop
  •     ;;
  •   status)
  •     status $SERVICE
  •     ;;
  •   restart)
  •     stop
  •     start
  •     ;;
  •   *)
  •     echo "Usage: $0 {start|stop|restart|status}"
  •     exit 1
  • esac

  • exit 0
下指令載入為服務:
  • chmod +x /etc/rc.d/init.d/<serviceName>
  • chkconfig --add <serviceName>
  • service <serviceName> start
若是 CentOS 7 環境下,似乎更簡單一些,準備 /etc/systemd/system/<serviceName>.service
  • [Unit]
  • Description=CAS Service
  • After=network.target
  • [Service]
  • WorkingDirectory=/opt/cas
  • "ExecStart=/usr/bin/java -jar cas.war"
  • Restart=on-failure
  • [Install]
  • WantedBy=multi-user.target
下指令載入為服務:
  • chmod +x /etc/systemd/system/<serviceName>.service
  • systemctl enable <serviceName>
  • systemctl start <serviceName>

星期四, 1月 04, 2018

LDAP search result size limit

照預設的 OpenLDAP,查詢結果若很多時,會限制僅回傳 500 筆資料,這原本不是什麼大問題,不過最近遇到了查詢結果多於上限,且在交易中不得分批處理的問題。原來改變上限也不是什麼困難的事,可先準備以下的 changeSizeLimit.ldif:
  • dn: cn=config
  • changetype: modify
  • replace: olcSizeLimit
  • olcSizeLimit: nnn
再下指令執行:
  • sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f changeSizeLimit.ldif
更進一步,也可以把產 ldif 跟下指令都放在一個 shell script。

星期日, 12月 31, 2017

Extract binary data from MS SQL

在微軟範例 AdventureWorks,Production Schema 有個 Document 資料表,其中有一個欄位 Document 型態是 varbinary,儲存著 FileName 欄位所記載的檔案內容。藉由工具程式與適當的對話,可以取出內容復原:
  • bcp "SELECT Document FROM AdventureWorks.Production.Document WHERE FileName = 'Introduction 1.doc'" queryout /tmp/Introduction_1.doc -S localhost -U sa -P ...
  • Enter the file storage type of field Document [varbinary(max)]:
  • Enter prefix-length of field Document [8]: 0
  • Enter length of field Document [0]:
  • Enter field terminator [none]:
  • Do you want to save this format information in a file? [Y/n]
  • Host filename [bcp.fmt]:
雖然大多是預設值,唯一要特別注意的是 prefix-length,這裡有可能自作主張地把檔案前面多加了八位元組,讓 Word 開不起來或形成一堆亂碼的內容,因此必須輸入 0 覆蓋掉預設的 8 才能得到正常的檔案結果。在此之後,我們可以再利用 bcp.fmt:
  • bcp "SELECT Document FROM AdventureWorks.Production.Document WHERE FileName = 'Introduction 1.doc'" queryout /tmp/Introduction_1.doc -f bcp.fmt -S localhost -U sa -P ...
可惜的是除此之外,參數無法讓這段過程無需人工介入又産生正確的結果。另一個變通的做法:
  • bcp "SELECT Document FROM AdventureWorks.Production.Document WHERE FileName = 'Introduction 1.doc'" queryout /tmp/Introduction_1_with_prefix.doc -n -S localhost -U sa -P ...
  • tail --bytes=+9 /tmp/Introduction_1_with_prefix.doc > /tmp/Introduction_1.doc

星期二, 12月 26, 2017

JMeter JSR223 Pre / Post Processor

過去以為在 JMeter 裡會用 RegEx 處理動態 SessionId 就很高段了?這次遇到了些更有挑戰性的需求,不得不研究了一下何謂 JSR223?基本上就是一個在 Java 執行腳本程式語言的環境。結合 Groovy,能解決:
  • 取亂數
    • def uuid = UUID.randomUUID().toString();
    • vars.put("id", uuid);
  • 字串拆解、合併,Base64 編碼
    • char0 = (char)0
    • jid = vars.get("jid")
    • token = vars.get("token")
    • def(name, domain) = jid.split("@")
    • plain = jid + char0 + name + char0 + token
    • encoded = plain.bytes.encodeBase64().toString()
    • vars.put("encoded", encoded)

星期一, 12月 11, 2017

git sparse checkout

有時候我們只想拿 Git 上的一兩個檔案,但整個儲存庫很大,或歷史悠久,實在有點浪費。首先有個下指令 sparse checkout 指定要取的路徑,也可以搭配深度省略不需要的歷史:
  • git init <repository_name>
  • cd <repository_name>
  • git config core.sparseCheckout true
  • echo '/path/to/file1' > .git/info/sparse-checkout
  • echo '/path/to/files/*' >> .git/info/sparse-checkout
  • git remote add origin https://<repository_url>
  • git pull --depth 1 origin master
指令有點多,用 api 看有沒有好一點?以無需認證的 GitHub repository 為例:
  • curl -H 'Accept: application/vnd.github.v3.raw' -O -L https://api.github.com/repos/:owner/:repo/contents/:path
需認證的 GitLab 比較麻煩些:
  • curl -H 'PRIVATE-TOKEN: <token>' https://<git_host>/api/v4/projects/:id/repository/files/<url_encoded_file_path>/raw?ref=master -o output.ext
    • token 要取一個 scope 包含 api,尚在有效期限內的 personal access token
    • project id 可在專案的一般設定找到,通常是個數字
    • 以專案第一層 a 目錄下的 b.txt 為例,url_encoded_file_path 會是 a%2Fb.txt
    • master 是分支名,也可以是 tag 或 commit id
    • output.ext 是輸出檔名

星期一, 12月 04, 2017

GIT_ASKPASS timeout on Jenkins

有些 Jenkins Project 在運作一陣子之後,某天突然出現取不到 Git 原始碼(逾時)的問題,目前只找到兩個共同特徵:
  • using GIT_ASKPASS to set credentials
  • Jenkins node on Windows
在一些文章中提到,若在 Jenkins 使用帳密(非 ssh token)登入 Git,事實上只能由 GIT_ASKPASS 傳遞帳密,但這機制又不是那麼穩,有時會壞的。解法是:
  • Command Prompt (Admin) > git config --system --unset credential.helper