星期日, 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

星期二, 11月 28, 2017

Docker shared folder between host and containers

因為很多 Docker Image 都陽春到沒有方便的交換檔案做法,像是要從 Host 複製檔案進 Docker Container,或反方向,或是 Docker Container 之間互相分享檔案,也許連平常視為基本的 SCP SSH 都沒有。幸好 Docker 有專門設計 Volume 給我們用,方法也不只一種,這邊講個最簡單又通用的:
  • docker volume create <your_volume_name> 建立新的共享目錄
  • docker volume ls 查詢目前有哪些共享目錄
  • docker volume inspect <your_volume_name> | grep Mountpoint 查詢共享目錄在主機上的實體路徑
  • docker volume rm <your_volume_name> 刪除共享目錄
當我們要開一個新的 Container,可以掛上這個共享目錄,如:
  • docker run
    • -d
    • --name <your_container_name>
    • -v <your_volume_name>:/tmp
    • <your_image_name>
就能在 Container 的 /tmp 找到我們放在 Mountpoint 的檔案。

星期六, 11月 18, 2017

Intranet jail break

我們常開發了一些網站應用程式,部署在個人開發環境、內網測試環境與客戶測試環境,因為各有各的用途與限制,三者缺一不可,但又瑣碎費時。
  • 個人開發環境:通常與開發工具結合,不太需要擔心如何部署,但配備要夠(資料庫不一定是隨便一部電腦就跑得動吧?)。
  • 內網測試環境:為了整合測試,或給 SA 驗收確認,可以搭配 Jenkins 持續部署。
  • 客戶測試環境:為了給客戶 Prototyping,請工程師帶個人開發環境(筆電)秀給客戶看?或請客戶提供機器讓我們去裝一套?或請公司的 MIS 把內網開給客戶?
現在有個神器 ngrok 能幫忙,原理應該是與分享檔案的 JustBeamIt 類似,只要是內網測試環境,我們自己就能把內網開給客戶。下載解壓之後,只有一個執行檔,請在內網執行環境的主機上開終端機/命令提示字元,執行類似如下的指令:
  • ./ngrok http 80
就會把本機的 http port 80 公開在 Internet 上,網址是隨時産生的。這時再把網址傳給客戶,我們這些廢宅工程師就免出門吹風了。

星期三, 10月 25, 2017

VirtualBox VT-x

對於這個選項放在每個 Guest VM 上,一直以來引人誤解為「只要勾選就能讓 Guest VM 相當於 BIOS 設定啟用 VT-x」,其實只是代表「Host 在啟動 Guest 時能用到 VT-x」,這篇有比較詳細的討論。
如果想讓 Guest VM 支援 VT-x,專業術語叫 nested virtualization,大家已對 VirtualBox 喊話很久了。

星期四, 10月 19, 2017

Confirm your Jenkins Deploy

以我大多接觸的都是 Web Application 而言,可概分
  • 淺層-網路通暢
  • 中層-版本正確
  • 深層-功能正確
淺層在 Jenkins 有個好用的 Http Request Plugin,只要輸入任一頁的 URL,這個外掛就可以試著要求,並檢查回傳的 Http Status Code 是否在預期內,通常是 2xx 或 3xx。
最近有個特例是要檢查部署的結果,但對面並不接受 http(s) 協定,在 Linux 上的 Jenkins Slave 可以用 nc -vz <IP> <Port>。
中層的話,如果部署的 Web Application 除了服務人,也服務機器(Web API),建議就考慮增加一個供外界查詢版本的 Web API,Jenkins 可透過核對 curl <Web API> 確認部署的狀況;如果是只服務人又不想改得多,可以挑一個靜態網頁的角落放版號,用 Selenium BDD 簡單的腳本確認。
深層的話,要準備 Selenium BDD 比較複雜的腳本,錄製工具似乎有些變化,所幸直接用 Node.js 來寫也不太困難。

[2017/10/23 補充]
有些 Linux 版本上 nc 似乎相容性不是很好,可用 nmap <IP> -p<Port> | grep open 試試能否取代?

星期二, 10月 17, 2017

Samba cannot communicate with Windows WINS servers

不敢令人相信的標題!出自於
當 Windows 與 Linux 混處於同個網段上,Linux 想識別那些 WINS server 掌管的 NetBIOS 機器名稱,竟然不是我一直肖想的架個 Samba 就好?目前只知一種解法(在安裝 Samba 之後):
  • nmblookup -U <WINS_ip> -R <NetBIOS_name>

星期四, 9月 07, 2017

update configuration in jar / war

jar / war 能帶著 configuration 一起其實是把雙面刃:好處是開發人員能提供一種「預設組態」期待在任何環境都可運作;壞處則是非改不可又不會改的時候變成累贅。這時我們就可以思考如何因應這些情境:
  1. 組態內容預期在任何環境都適用
  2. 組態內容必須為各環境調整
    1. 開發人員為各環境提供不同的 jar / war 包含各自的組態內容
    2. 部署人員為單一的 jar / war 修改組態以適應其環境
首先看 2-1 情境:開發人員可以在 Jenkins 封裝 jar / war 之前用一個 Ant Task 讀環境變數,並將結果取代掉該改的地方,例如在 cas/src/main/resources/application.properties 有一行內容如下:
  • cas.server.name=https://acme.com
但這行右邊的內容每次都不一樣,可先修正為:
  • cas.server.name=https://@hostName@
當然只有這樣並不夠,必須搭配 build.xml,內容如下:
  • <?xml version="1.0" encoding="UTF-8"?>
  • <project default="replaceToken">
    • <property environment="env" />
    • <target name="replaceToken">
      • <replace file="cas/src/main/resources/application.properties" token="@hostName%" value="@{env.hostName}" />
    • </target>
  • </project>
另外,在 Jenkins Build 段落必須在編譯封裝 jar / war(假設是用 Gradle)之前安排:
  • Build
    • Inject environment variables
      • Properties Content
        • hostName=acme.com
    • Invoke ant
    • Invoke Gradle script
當然,實際上要再進一步整合到純粹用 Ant 或 Gradle,不再混搭會更好。

再來是情境 2-2「一個 jar / war 到處使用」,藉由很基本的 JDK 工具即可:
  • mkdir working
  • cd working
  • mv ~/Downloads/cas-1.0.0-SNAPSHOT.war .
  • jar xf cas-1.0.0-SNAPSHOT.war WEB-INF/classes/application.properties
  • vi WEB-INF/classes/application.properties(改成適合環境的內容)
  • jar uf cas-1.0.0-SNAPSHOT.war WEB-INF/classes/*
  • mv cas-1.0.0-SNAPSHOT.war ~/Downloads
  • cd ..
  • rm -rf working
有的環境只有 JRE 但沒有 JDK,需要為此下載安裝嗎?別急,找找有沒有 zip / unzip 也可當做替代品:
  • unzip cas-1.0.0-SNAPSHOT.war WEB-INF/classes/application.properties
  • zip -u cas-1.0.0-SNAPSHOT.war WEB-INF/classes/*

星期一, 9月 04, 2017

星期五, 9月 01, 2017

Maven install reference

在舊版(3.0.5)mvn install 遇到以下問題:

  • [ERROR] ...
  • The following artifacts could not be resolved:
    • com.dummy:packageA:jar:1.0.0-SNAPSHOT,
    • com.dummy:packageB:jar:1.0.0-SNAPSHOT
    • ...
  • Could not find artifact ... in snapshots (http://your.artifact.com/libs-snapshot)

如果我們明明在本地端 Maven Repositories 能找到那些 JAR,但以上的指令固執地只找遠端,可以這麼修正:

  • rm ~/.m2/repository/com/dummy/packageA/1.0.0-SNAPSHOT/_maven.repositories
  • rm ~/.m2/repository/com/dummy/packageB/1.0.0-SNAPSHOT/_maven.repositories

星期三, 8月 09, 2017

星期三, 8月 02, 2017

Node.js + Selenium + Headless Browser

接續這篇的話題,既然準備好了 System Under Test SUT,那就來自動化測試吧!這次為了遷就 Linux 可能沒有 UI,先把環境需求降到最低:
  • Linux
  • Docker (Optional)
  • Node.js
  • Internet Access
別忘了 Node.js 支援跨平台,Linux 也只代表作業系統,不是非君不嫁。正好上一篇的結果可以拿來加工再利用,要補三個東西:
  • 基於 Node.js 的測試程式-checkHello.js
  • 瀏覽器
  • selenium-webdriver (for Node.js)
checkHello.js 也是愈簡單愈好,第一版只有這樣:

const assert = require('assert');
var webdriver = require('selenium-webdriver'),
    By = webdriver.By;
var driver = new webdriver.Builder()
    .forBrowser('phantomjs')
    .build();
driver.get('http://172.17.0.2:8080');
var byH1 = By.css('h1');
var h1 = driver.findElement(byH1);
var h1Text = h1.getText();
var h1Handler = function (text) {
    assert.equal(text, "Hello World!");
}
h1Text.then(h1Handler);
driver.quit();

應該很好猜在測什麼?就是比對 <h1>Hello World!</h1> 而已。瀏覽器也先挑簡單的 PhantomJS,一是不需依賴圖形介面,一是大部份瀏覽器還要再搭配驅動程式,比較麻煩。安裝指令其實源出於,改編如下:
  • docker exec -it myNode sh
  • curl -L https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 | tar -xj --strip-components=2 -C /usr/local/bin phantomjs-2.1.1-linux-x86_64/bin
  • exit
其中 PhantomJS 下載目錄來自這裡,/usr/local/bin 是環境變數 PATH 所指向的路徑之一。本段前後這些提到指令的部份,都是針對上一篇名為 myNode 的 docker container,如果不是,例如只在本機,可以忽略灰底的部份。至於 selenium-webdriver 安裝,指令是:
  • docker exec -it myNode npm install selenium-webdriver
萬事俱備,執行測試的指令是:
  • docker exec -it myNode node checkHello.js
順利的話,會讓人誤以為沒反應?可以故意弄錯一些東西來驗證,例如換個 IP,換個 port,關掉 Web Server,Hello World! 改個大小寫什麼的。

星期二, 8月 01, 2017

Simplest Node.js Web Server (in Docker or not)

這篇實在是一年多前就不該偷懶好好寫的(與這篇有關),在參考了這篇這篇之後,覺得以下的內容還算能用:

var http = require('http');
var port = 8080;
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end('<html><head></head><body><h1>Hello World!</h1></body></html>');
}).listen(port);
console.log('Server running at http://localhost:' + port);

要能執行的前提僅需安裝 Node.js,因為 http 是內建的,也不需要再補 npm install http。假設存檔名為 helloServer.js,執行時只要切到該目錄,在命令列下 node helloServer.js,之後就可用瀏覽器訪問 http://localhost:8080 看到這個超陽春網頁。

想更乾淨一點,不要直接在本機安裝 Node.js?用 Docker 再適合不過了,而且官方支援就提到如何直接執行單一程式,我稍做修改的命令與簡略說明:
  • docker run -it --rm --name myNode -v "$PWD":/usr/src/app -w /usr/src/app node:latest node helloServer.js
  • 命名為 myNode,可以修改。
  • /usr/src/app 是 container 裡面的目錄,對應外面的現行目錄,也是裡面的工作目錄。
  • image 名稱 node:latest,因為這個簡單範例不挑版本。
  • 最後的 node helloServer.js 就是下到 container 裡面去執行的命令。
但這次瀏覽器看不到網頁了?別急,先另開一個 Terminal 下指令查 container 用哪個 IP:
  • docker inspect myNode | grep IPAddress
瀏覽器在 docker 外面,所以 localhost 要換成這樣查來的 IP 才會通。


Jenkins current users

如何能得知 Jenkins 目前有哪些使用者登入?只要安裝了 Monitoring Plugin,管理者就可以在 Manage Jenkins -> Monitoring of Jenkins master -> System information -> View http sessions 看到多個 session id,點進去就有 Username 了。

星期六, 7月 29, 2017

Mac as a Selenium Node

過去在 Windows / Linux 上有不少 Selenium Node 的經歷,都不像最近為了 Safari 加開 Mac 如此挫折,總是幾分鐘到幾小時之後會斷線,還沒撐過一天的。經歷了幾個階段:

  • 懷疑其他同事「不小心」關了我的 Terminal,時常檢查,偶有一兩次真的,但大部份並不是。
  • 不要隔太久都沒用到這些節點,至少一小時一次(但這對嗎?以前都是一天一次,其他作業系統都沒這問題)。
  • Mac 所在網段不同,與 Selenium Grid 隔了 VPN,想說最後一招就是搬家再試。
  • 另開帳號與其他人的使用介面隔絕,還是會斷,懷疑是機器太忙?renice -10 有明顯改善,但不能根本解決。
  • 用 caffeinate 防止睡眠(參考這篇文章),終於先撐過一天了,繼續觀察。
  • 用 NodeJS + Selenium + Chrome 監看 Selenium Grid Dashboard。

星期三, 7月 26, 2017

Microsoft Remote Desktop + VNC on Linux

Remmina 太強了,以前在 Mac 上分兩邊管 Windows / Linux 的遠端,現在整合在一起了。

Customized Notebook

為了追求更高效能的筆電,選擇 System76,不過代價有點高:
  • Galago Pro 原價 USD $999,等到美國國慶特價 USD $899
  • 加了一堆配備 USD $999
  • 運費二選一,都是 UPS,看不出差別,所以挑稍微便宜的 USD $106.5
  • 以上小計 USD $1,904.5,折合 NTD $58,038
  • 刷了兩張較優惠的 JCB 都不過,錯誤訊息也莫名其妙,最後只好用國泰世華信用卡,國外交易手續費 NTD $871
  • 貨到台灣,UPS 通知要 BSMI NCC?急忙寫信問原廠要無線網卡的規格,回覆只有製造商與型號,自己上 IBM 網站找了半天,總算會填申請書了。委託報關 NTD $1,400 可轉帳,加值營業稅 NTD $2,762 必須取貨面交,所以也不能委託管理員代收了,只好親自跑一趟。

總計是 NTD $63,071

星期四, 6月 22, 2017

Windows Schedule Reliability / Chain

Windows「工作排程器」可用來安排一些需要自動執行的工作,需要注意的是:
  • 何時?(開機後還是每天固定幾點)
  • 登入與否?(通常是設「無需登入」)
  • 執行身分是否有適當權限?
  • 重試次數與逾時是否足夠?(尤其要考慮 Windows Update 可能讓開機耗時很久)
  • 成功啟動的紀錄中應有 ProcessID 可供比對,如果在工作管理員沒看到,可能是事後當了。
另一個問題:有幾個每日工作排程,因為它們必須在晚上,又是有必要順序的,但需要的時間很難估準,就常落入「多等排不下」或「少等來不及」的掙扎。其實可參考這篇的說明,讓這些工作一個接一個地完成。若缺一個不至於太快完成的「前一個工作」,可以用 defrag %SystemDrive% /v 來充數。

星期四, 5月 18, 2017

BOM break iconv

BOM, byte-order mark 是用來標示 Unicode 檔案的記號。例如我們常用的 UTF-8 文字檔,前三碼應該會是 EF BB BF,在 Linux / Mac Terminal 可以這麼看:
  • xxd fileName | head -n 1
這種檔案要交給 iconv 轉碼會遇到問題,例如:
  • iconv -f utf8 -t big5 fileName > fileName.big5
  • iconv: fileName:1:0: cannot convert
所以要先去頭三碼:
  • mv fileName fileName.bom
  • tail -c +4 fileName.bom > fileName
再轉碼就可以了。但有時候是需要反過來,為轉碼結果補 BOM,可以這麼做:
  • echo -ne '\xEF\xBB\xBF' > fileName.utf8
  • iconv -f big5 -t utf8 fileName.big5 >> fileName.utf8
[2017/06/02]
在中文版 Windows 要一次將許多 Big5 編碼的文字檔轉成 UTF-8 編碼,可參考這篇以 Powershell 解答的作法。

星期三, 5月 17, 2017

Web site time check

有些網路訂票、報名之類的頁面,往往秒殺,所以事先了解對方有沒有依網路校準時間相對重要。在 Linux 或 Mac 上可藉由以下指令探測對方的時鐘:
  • while sleep 1; do curl -sI http://... | grep Date; done

星期六, 5月 13, 2017

Visual Studio Team Services + Jenkins

除了 BitBucket 以外,Visual Studio Team Services 似乎也能成為雲端免費版控服務的提供者,平時用 Visual Studio 編輯程式,持續整合時用 Jenkins 往 VSTS 取程式下來。但一開始試得不那麼順利,原來是有許多秘辛:
  • VSTS 預設使用名為 Personal Access Tokens 的認證機制,不能與 Jenkins GIT_ASKPASS 相通,但若搭配 GitHub 上一個叫 Git-Credential-Manager-for-Windows 的用戶端軟體,在安裝時它會順道帶一個版本合適的 Git for Windows,省去許多麻煩。
  • 在某部電腦上若已用 Microsoft Account 連過 VSTS 並有版控存取權,也裝了上述的 GCM for Windows,就可透過命令列 git ls-remote -h https://yourVSTSAccount.visualstudio.com/DefaultCollection/_git/yourProject 測通。這時由於是透過 Personal Access Tokens 認證的,所以不需輸入帳密。
  • 即然不輸入帳密就能連有點不踏實,可以系統管理員身分下指令「git config --system --unset credential.helper」關閉,之後每次存取 VSTS 就要輸入帳密,而且輸入正確也沒用。
  • 會慌嗎?沒事的,同樣以系統管理員身分下指令「git config --system credential.helper manager」,一切又恢復不需帳密即可存取的原樣。
  • 此時可到 VSTS 網頁介面,右上角登入者的頭像下拉選單,Security -> Alternate authentication credentials -> Enable,輸入密碼兩次並儲存,未來即可在不依賴 credential.helper 的情況下存取 VSTS。
  • 回到 Jenkins,GIT_ASKPASS 的條件之一就是沒有 credential.helper,所以就通了。

星期五, 5月 12, 2017

Minimum and vulnerability-free .NET web project


為了驗證 Checkmarx 掃出的資安弱點與解法,需要這樣的 .NET 基礎專案當底:
  1. Solution 方案內僅有一個 Web Application 專案。
  2. 專案內僅有 Web.config,沒有其他任何網頁、樣式、前後端程式。
  3. Web.config 僅有如附圖的必要內容。
  4. 若以上條件皆符合,Visual Studio 能通過建置,且 Checkmarx 掃描沒有任何資安弱點。

星期五, 5月 05, 2017

Jenkins Node @ CentOS 6.7 can't fetch git via GIT_ASKPASS

最近忙著將 Jenkins 的工作分散到幾個 Node 上,其中一個要去 Git 抓原始碼總是卡在 git fetch 401,但若在 Terminal 下 git fetch ... https://user@githost... 又都沒問題?
我想錯誤應是來自於 Jenkins 的 Git Plugin,從 log 來反推它的決策過程:
  • > git --version
  • using GIT_ASKPASS to set credentials
  • > git fetch ...
以上是指出 Git Plugin 下了 git --version 命令取得結果之後,決定用 GIT_ASKPASS 這種比較新的做法來傳遞帳密,但我的 git --version 是 1.7.1,其實並不支援 GIT_ASKPASS(有個說法是 1.7.1.1 才開始),參考這篇到 WANDisco's CentOS repository 裝上新版 git 立刻就解決了。

星期五, 4月 21, 2017

Initial Docker on CentOS

安裝
  • sudo yum install docker
啟動 docker service
  • sudo systemctl start docker 或是舊指令 sudo service docker start
開機後自動啟動 docker service
  • sudo systemctl enable docker
省略當前使用者未來每個 docker 指令都要 sudo
  • sudo groupadd docker
  • sudo gpasswd -a ${USER} docker 或是另一種寫法 sudo usermod -aG docker ${USER}
  • sudo systemctl restart docker
  • logout / login

星期一, 4月 17, 2017

7 lines JavaScript crash SonarJs

如下圖的程式碼:
在 SonarQube 掃描會異常中止,得到如此的錯誤訊息:

java.lang.IllegalStateException: At least one branch of condition should be executed (condition on line 4)

現實中當然沒有這麼白痴的程式,這段其實出自於 primitives.latest.js 兩萬行之中精簡而來,幸好是可以排除的對象。

星期四, 4月 13, 2017

VPN establish connection difficulty?

即使所有參數(主機位址、帳密、協定...)設對,在 VM 裡的 Windows 要掛上 VPN 也很困難?除了要注意虛擬機器必須至少有一 Bridged 網卡之外,多網卡可能也會造成不當的權重導致 VPN 永遠走不上正確的路,例如附圖。解決之道是暫時先關閉其他不相干的(ex: NAT)網路介面,等 VPN 通了再復原不遲。

星期三, 3月 29, 2017

Docker-based GitLab hostname

如果「冒然地」使用 Docker 起一部新的 GitLab 伺服器,而沒有太注意參數的話,日後專案的 URL 可能含有一段像亂碼的主機名稱。有兩種解法:
  • 事前:docker run -h yourHostName ...
  • 事後:編輯 /etc/gitlab/gitlab.rb 其中一行 external_url 'http://yourHostName',當然也別忘了 gitlab-ctl reconfigure 套用生效。

星期四, 3月 02, 2017

Encrypting and Decrypting Configuration Sections

要透過加密來保護 web.config 資料庫帳密之類的機敏資訊,又懶得再寫一堆程式?其實微軟已有一套機制,這個題目在 MSDN 上有篇一模一樣的,那為何還要抄一遍?因為有幾個重點若遺漏了,很容易讓人沮喪:
  • 在 Windows 7 / Windows Server 2008 R2 安裝的 IIS 7.5,或更新的版本,當我們不是用正規的部署工具將網站內容搬到伺服器上,可能要考慮實體目錄的授權問題,如我過去偷懶開給 EveryOne Full Control,或正經地參考這篇
  • 一定要用管理者身分執行 aspnet_regiis.exe,否則就等著被那些錯誤訊息誤導吧!
  • 關於 -site,雖然大多數情況下可以省略,但若是反覆設定使用的舊伺服器上,又尤其是中文介面,比較不能放心交給預設值。保險起見,最好在 IIS Manager > Sites > Default Web Site > Basic Settings... 確認一下,站台名稱是否還是預設(可省略)的 "Default Web Site"(參數值含空白,頭尾必須有雙引號包著)?
  • 關於 -app,指的是「應用程式別名」或稱虛擬路徑,一定要以斜線開頭。
  • 關於 -prov,指的是某「受保護組態提供者」,省略就會使用預設的程式與亂數產生的金鑰對,若不考慮移機是最簡單有效的。
  • 當上述程式的執行結果成功,也別高興太早,例如 -app / 這樣明顯找錯對象,但結果成功?其實這會去 %systemdrive%\inetpub\wwwroot 目錄找另一個 web.config,找不到也不算有問題。還是在加/解密後,打開真正目標 web.config 再確認才放心。
  • 這種加解密做法其實與公文交換是一樣的,看來沒有必要自訂程式處理。若必須多考慮移機或 WebFarm 的情境,要注意金鑰也必須隨之搬家,到了新家還要授權,原則上可以參考官網這篇,不過要注意授權對象(參考第一點),configProtectedData 可落在根節點下的第一層,還有 Version=2.0.0.0 可以直接改 4.0.0.0,-prov SampleProvider 而不是 SampleKeys,還有 PublicKeyToken 後面少了逗號。也可以參考這篇部落格,但前提還是要自己清楚整個流程,把人家的整理當功德,否則傻傻地抓不出錯字還是做不出來的。


星期三, 2月 15, 2017

Building dynatrace easyTravel from Source (Windows)

上次談過在 Linux 平台上由原始碼重建 easyTravel,美中不足的是 B2B 後台不包含在內。為了讓這個主題更完整,花了近一週的時間摸索建置程序,除了幾個小蟲,還升級到 .NET 4 + Cassini 4,艱辛之路在此留下歷程:
  1. 在 Windows Server 2016 或 Win10 上,先安裝 .NET Framework 3.5。
  2. 安裝 Visual Studio 2015 Community with Updates,一切依預設值即可,裝完後沒有一定要 Launch(希望不用註冊也能撐久點)。
  3. 從官網下載 2.0.0.2542 版的原始碼,假設解壓到 D:\easyTravel-src-2542 目錄下。
  4. 下載安裝 Java SE 7,並設 JAVA_HOME 環境變數。
  5. 下載解壓 Ant 1.9.x,並設 PATH 指到 bin 目錄。
  6. 修改 D:\easyTravel-src-2542\commons-demo\resources\easyTravel.properties,version.buildnumber=2542。
  7. 修改 D:\easyTravel-src-2542\commons-demo\resources\easyTravelConfig.properties,cassini20/UltiDevCassinWebServer2 改為 cassiniDev4/CassiniDev4-console(共有兩處)。
  8. 修改 D:\easyTravel-src-2542\Launcher\src\com\dynatrace\easytravel\launcher\procedures\B2BFrontendProcedure.java,在 if(CONFIG.b2bFrontendServer.contains("cassini")) 條件符合時:
  9. 修改 D:\easyTravel-src-2542\Launcher\src\com\dynatrace\easytravel\launcher\procedures\PaymentBackendProcedure.java,在 if(CONFIG.paymentBackendServer.contains("cassini")) 條件符合時:
  10. 修改 D:\easyTravel-src-2542\dotNET45\build.xml,新增這一行:<property name="dotnet.framework.path" location="C:\Program Files (x86)\MSBuild\14.0\Bin" />。
  11. 切換到 D:\easyTravel-src-2542\Distribution 目錄下,執行 ant。
  12. 切換到 D:\easyTravel-src-2542\dotNET45 目錄下,執行 ant。
  13. 從別處取得同版本的 CreditCardAuthorization64.exe,複製到 D:\easyTravel-src-2542\Distribution\dist 目錄下。
  14. 修改 D:\easyTravel-src-2542\Distribution\dist\startDistributed.cmd,set-this-property 改為機器名稱(可用 hostname 指令取得);..\jre\bin\java 改為 "%JAVA_HOME%"\jre\bin\java,再執行。
  15. 在管理介面關閉所有測試流量,再啟動 Production 群組的 Standard 情境,應該沒有錯誤,而且前後台都能運作。

星期五, 2月 03, 2017

Modern.IE backup

雖然 Modern.IE 有許多實用的虛擬機映像,不過久了也會撤。幸好這裡可能保存得時間比較長。

星期四, 1月 26, 2017

Docker Volume + SELinux

在 Jenkins 的 Docker 官網首頁有一個參數引起我的興趣:
  • docker run -v /srv/jenkins:/var/jenkins_home jenkins
大意是說 Container 裡原本有個必要、可讀寫的 /var/jenkins_home 目錄,我們可以把它拉出來方便管理。太棒了!但一試之下發現不單純:
  • Permission denied
原來 /srv/jenkins 目錄是要先建好並授權:
  • sudo mkdir /srv/jenkins
  • sudo chown `whoami` /srv/jenkins
結果還是一樣?原來是 SELinux 的關係。在 CentOS 預設是開啟 SELinux 的,可以這麼確認:
  • getenforce
短期(到下次重啟前)的控制,可透過 setenforce 指令;長期就要編輯 /etc/sysconfig/selinux 設定檔並重啟。若不想關閉 SELinux,還要多些準備工夫:
  • docker run -v /srv/jenkins:/var/jenkins_home:Z jenkins
最後面的大寫 Z 代表「只有 Host 與那個 Container 分享」,若改小寫 z 代表「Host、那個 Container、其他 Container 都可分享」。

星期一, 1月 23, 2017

Owncloud Maximum upload size

新的 9.x 在管理介面上有個很貼心的設定,直接就可以設最大上傳檔案的大小,不過沒用?關鍵是上傳 30 秒之後超過了一個 PHP 的 max_execution_time 設定,若是像我一樣用 Docker-based ownCloud,Web Server 是 Apache,可以在 .htaccess 改成 0 代表沒有上限。
這個過程曲曲折折,主要是對 PHP + Apache 不熟,雖然這篇提到的 phpinfo.php 非常有用,不過被這篇的參數誤導很久,它建議:
  • max_input_time 3600
  • max_execution_time 3600
那如果想讓兩個都沒上限,從 phpinfo.php 看到原來的設定:
  • max_input_time -1
想當然爾,另一個這麼改:
  • max_execution_time -1
就在這裡落入陷阱。雖然不一致,但正確的是:
  • max_execution_time 0

Docker-based SonarQube can't change to non-embedded database?

依據 SonarQube 的說法,換掉預設的內嵌式資料庫並不困難,重點有以下幾個:
  • 準備空的資料庫
  • 準備權限足夠的一組帳密
  • 設定資料庫所在主機的網路接受外部連入(防火牆、資料服務)
  • 修改 conf/sonar.properties
一但所有條件都準備好,放眼設定檔,應該也只有三行要改(以 MySQL 為例):
  • sonar.jdbc.url=
  • sonar.jdbc.username=
  • sonar.jdbc.password=
但最近在試 SonarQube 6.2 來自於 Docker 的版本,自認以上都熟,但還是一直不成功?原來 docker inspect sonarqube 可看到以下段落:
  • [
  •     {
  •         ...
  •         "Config": {
  •             ...
  •             "Env": [
  •                 ...
  •                 "SONARQUBE_JDBC_USERNAME=sonar",
  •                 "SONARQUBE_JDBC_PASSWORD=sonar",
  •                 "SONARQUBE_JDBC_URL=",
  •                 ...
這裡的設定優先權高於 conf/sonar.properties,所以只能在第一次執行時加設環境變數才有效,如:
  • docker run -d -e "SONARQUBE_JDBC_URL=..." sonarqube

星期六, 1月 14, 2017

Compile Error CS1012

原本一個使用 C# 撰寫,確定可以編譯成功的專案,沒改任何程式碼,換了新的編譯環境後竟然失敗?
  • error CS1012: Too many characters in character literal
依據官方說法,單引號裡只能包一個字元,不能是字串(字元陣列)。但確實沒改程式碼,怎會字元變字串?來看一下程式:
  • string[] fixflds = fixfld.Split('、');
原來是中文全形符號,在 Big5 編碼算一個字元,但英文版作業系統會當做兩個字元。那要如何在編譯時指定 Big5 編碼?在此之前,我們可能要知道怎麼看「目前的編碼」?
  • C:\>chcp
  • Active code page: 437
試著改改看
  • C:\>chcp 950
  • Invalid code page
失敗了,難道只有換中文版作業系統可以嗎?還是偷懶一點補裝個中文語系?其實遠比這些簡單,在「地區設定」、「管理」可以變更 Language for non-Unicode programs 為 Chinese (Traditional, Taiwan),就可以改變編碼,讓編譯成功了。

星期三, 1月 11, 2017

ldapsearch

在練習對 ldap 查詢時,可以好好利用這裡介紹的測試伺服器(雖然不一定活著?)。首先要確認域名解析是否成功?
  • ping ldap.forumsys.com
網路能否連上?
  • ldapsearch -h ldap.forumsys.com -x
如果回應看起來是連到了主機,但沒有結果,可能是上面的寫法隱含著 -s sub -b "" 的關係,所以先別貪心:
  • ldapsearch -h ldap.forumsys.com -x -s base
可以了,再指定搜尋起點往下挖:
  • ldapsearch -h ldap.forumsys.com -x -b dc=example,dc=com
若運氣不錯,會得到幾筆資料。但不是所有地方都接受匿名查詢,所以也許需要表明身分:
  • ldapsearch -h ldap.forumsys.com -D cn=read-only-admin,dc=example,dc=com -w password -b dc=example,dc=com
嫌資料太多嗎?可以過濾:
  • ldapsearch -h ldap.forumsys.com -x -b dc=example,dc=com ou=*
另外遇到過一些範例建議各項參數前後要包雙引號的,例如 -b "dc=example,dc=com";或者大小寫比較講究,像是 DC=example,DC=com;也有帳號是郵件位址的,類似 admin@example.com,因為才疏學淺實在不敢亂寫,就請讀者們多多嘗試一番。

[2017/02/17]
要確認密碼,可這麼做:
  • ldapwhoami -h ldap.forumsys.com -D cn=read-only-admin,dc=example,dc=com -w password