星期五, 12月 25, 2015

Jenkins + Central Authentication Service, CAS

在 Windows 伺服器上的 Jenkins 要由 https://abc.com/cas 單一簽入的做法:
  1. 取得 https://abc.com 憑證簽署單位的憑證,假設檔名為 StartCom.crt。
  2. 以系統管理員身分在 Jenkins 安裝目錄下命令:jre\bin\keytool.exe -keystore jre\lib\security\cacerts -import -trustcacerts -file StartCom.crt -alias StartCom。
  3. 在 Jenkins 安裝 CAS Plugin,並設定 Security Realm CAS 的 URL、Protocol。

星期二, 12月 15, 2015

CentOS 6 as a Selenium node with Chrome

過去已有 Windows 當 Selenium (web driver) node 的經驗,原本以為換到 Linux 是件很簡單的事,不過實際試著做下來,才知若是 Firefox 還好,Chrome 就很麻煩了:
  1. 若 CentOS 6 還沒有 GUI,要下指令安裝:yum groupinstall "X Window System" "GNOME Desktop Environment" "Desktop" "Chinese Support"。
  2. 若要從遠端操控 CentOS 6 的圖形介面,可以用 VNC。在 CentOS 6 安裝 VNC Server,執行 vncserver :1,用 vncpasswd 命令設遠端連線密碼。從 Mac 連過去甚至 VNC Viewer 都不用裝,在 Safari 瀏覽 vnc://hostname:5901 就可以了。
  3. 在 CentOS 6 安裝 Chrome 已不被 Google 原廠支援,幸好還有位大師指導
  4. 不像 Firefox,所有其他的瀏覽器都需要 Driver 才能與 Selenium hub 溝通,所以要另外下載。所謂「安裝」就是把下載的檔案放在 PATH 所指的路徑即可。
  5. 以上都做了,結果還是不通?可以直接在終端機執行 chromedriver 看是什麼問題,原來還是 libstdc++.so.6 惹的禍。經過上述大師的修正,應該會有兩個以上,可以透過「find / -name libstdc++.so.6」來確認,而且每一個的差異可透過「strings <PATH>/libstdc++.so.6 | grep GLIBC」識別,換另一個版本的也許就好了。
[2016/09/10 補充]
  • CentOS 7 安裝各種 GUI 的說明可參考這篇
  • Chrome 有自動更新的機制,每次事後都要把 /usr/lib64 目錄下的 libstdc++.so.6 指到 /opt/google/chrome/lib 去,否則就是找不到 Chrome Web Driver 的錯誤。

星期六, 12月 12, 2015

Convert .bat to .sh

有一行很簡單的命令:

java -jar a.jar fileB

以上就是 c.bat 批次檔的內容,與 a.jar、fileB 都在同一目錄下,在 Windows 的環境沒問題。既然 Java 是跨平台的,想必可移到 Linux / Mac 的指令稿,但一直不行?也確定這行直接放在終端機跑過沒問題,只是不能從 c.sh 間接地執行。除了 chmod +x 還有別的事要做?後來改成這樣:

#!/bin/bash
java -jar a.jar fileB

結果在 Mac 上是出現這個訊息:

-bash: ./c.sh: /bin/bash^M: bad interpreter: No such file or directory

半信半疑,加了到底是有幫助還是把事情搞得更複雜?幸好看到這篇,在 vi 編輯 c.sh 下兩道指令:

:set ff=unix
:x

終於修好了!

星期三, 12月 09, 2015

C# 對民國年的處理

最近看到很多人自成一格的處理民國年,很醜的就不提了,有的猛一看還不錯:

private string FormatDate0(DateTime dateTime)
{
return dateTime.AddYears(-1911).ToString("yyy/MM/dd");
}

以今天為例,結果是 104/12/09,看來沒問題?但試試 FormatDate0(new Date(2016, 2, 29)) => 105/02/28,知道不行了吧?改進如下:

private string FormatDate1(DateTime dateTime)
{
string returnValue = null;
Calendar taiwanCalendar = new TaiwanCalendar();
int year = taiwanCalendar.GetYear(dateTime);
int month = taiwanCalendar.GetMonth(dateTime);
int day = taiwanCalendar.GetDayOfMonth(dateTime);
returnValue = String.Format("{0:000}/{1:00}/{2:00}", year, month, day);
return returnValue;
}

雖然有點長,但感覺是用比較「正統」的方式在處理。如果真要挑毛病的話,就是年月日必須分開處理,難道沒辦法保留在一起嗎?有人介紹了以下這種:

[SecurityPermission(SecurityAction.Assert, ControlThread = true)]
private string FormatDate2(DateTime dateTime)
{
string returnValue = null;
CultureInfo taiwanCulture = new CultureInfo("zh-TW");
DateTimeFormatInfo formatInfo = taiwanCulture.DateTimeFormat;
Calendar taiwanCalendar = new TaiwanCalendar();
formatInfo.Calendar = taiwanCalendar;
Thread currentThread = Thread.CurrentThread;
currentThread.CurrentCulture = taiwanCulture;
returnValue = dateTime.ToString("yyy/MM/dd");
return returnValue;
}

真的是複雜但優雅!但別急著高興,先不論 SecurityPermission 帶來的一絲不安,有個測試案例結果不太妙,FormatDate2(new Date(2010, 1, 23)) => 99/01/23,開頭的零跑哪去了?怎麼看都是微軟的問題,自力救濟吧:

...
// bugfix begin
//returnValue = dateTime.ToString("yyy/MM/dd");
int year = taiwanCalendar.GetYear(dateTime);
returnValue = String.Format("{0:000}", year);
returnValue += dateTime.ToString("/MM/dd");
// bugfix end
return returnValue;
}

有些畫蛇添足的感覺,看得真不舒服。