XCode 中為 macOS Command Line Tool 專案加入 Unit Test

XCTest module 是 XCode 內建提供的單元測試框架模組,如果是建立一個 iOS App 或 macOS Cococa App 這種帶有視窗畫面的應用程式專案,XCode 會自動在創建專案時一併建立測試專案,但如果在 XCode 中建立一個 macOS Command Line Tool,預設是不會自動建立 XCTest Unit Test 的

如果直接在專案中新增一個 Unit Test 檔案,會發生 Connot load underlying module for 'XCTest'

正確做法是在左邊的 Project Navigator 中,切換到 “Show the Test navigator",小圖示是:

接著在最左下方點選 + 的符號,選擇第一個 New Unit Test Target...

輸入 Test class name

按下 Finish 後,就可以在 Show the Project navigator (左上第一個資料夾圖示) 中看到多了一個 Group、Test class 和 Info.plist,其中 Test class 已經繼承了 XCTestCase,import 的 XCTest 模組也沒有錯誤了

接著進入上方的 Scheme 選單,點選 Edit scheme,編輯當前的 scheme,在 Test 的地方加入 Test target

然後在 show the Test navigator 中就會出現新增的 Unit Test 了

在 A.swift 使用 B.swift 的 class

BeImported.swift

public class BeImported {
  static func show_message() -> Void {
    print("Jello!")
  }
}

main.swift

(BeImported.show_message())

In swift, you can’t import a typical *.swift file.

Swift 中的 import 是對 module 有效,不是檔案

所以如果你要在 main.swift 中使用 BeImport.swift 的 class:

Works

$ xcrun -sdk macosx swiftc -emit-executable -o a BeImported.swift main.swift
$ ./a
Hello!

$ swiftc -o a main.swift BeImported.swift
$ ./a
Hello!

Not Works

# swift main.swift BeImported.swift
(Got some errors..)

因為 swift 是 Swift executer,要用 swiftc 先 compile 才能執行

(Java 好像也是這樣? 但 javac 編譯好後,要用 java 執行,而 swift a 會錯誤)

為 xshogi 官網的第二個 domain 加入 ssl

實驗域名:xshogi.com

已經有了上次的經驗後,要為另一個 xshogi.com 加入 ssl 憑證,過程記錄如下。

第一階段:購買 SSL 憑證

  1. openssl req -nodes -newkey rsa:2048 -keyout xshogi.com.key -out xshogi.com.csr
↪ openssl req -nodes -newkey rsa:2048 -sha256 -keyout xshogi.com.key -out xshogi.com.csr
Generating a 2048 bit RSA private key
............................+++
............+++
writing new private key to 'xshogi.com.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:TW
State or Province Name (full name) []:Taipei
Locality Name (eg, city) []:city
Organization Name (eg, company) []:xshogi
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:www.xshogi.com
Email Address []:xshogi.it@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
  1. 到 Gandi SSL 購買介面,選擇類型為 “基本" 和 “單一位址",然後到貼上 CSR 的地方

這邊如果把上次的貼上(in .ssl/xshogi_heroku.csr),會解析簽署名稱(CN)成 http://www.xshogi.com.tw,所以要貼上新的 xshogi.com.csr

  1. 下一步以後付完款,接著就是等待 域名所有權驗證

會收到一封信說,有三種方法可以驗證您擁有域名。您可以在憑證控制面板中的 “編輯" 選擇要驗證的方式。

經由DNS 認證
必須將此介面提供的 CNAME 記錄加入 xshogi.com 的 DNS 區域檔。若為多重域名憑證,則每個域名都必須完成此操作。第一次驗證的時間將會在三小時之後開始。

經由電子郵件認證(最快)
重要:您必須建立一個電子郵件地址 admin@xshogi.com (若為多重域名憑證,每個域名都需要一個電子郵件地址) 以接收認證訊息 (內含需點擊的連結,會連線到 Comod 的網站)。注意:若電子郵件地址建立速度太慢,可能會漏收郵件:也可以於此介面重新發送認證電子郵件。

檔案認證
您必須到憑證詳細資訊中取得認證的 .TXT 檔並且把它放置到需驗證網站的根目錄。若為多重域名憑證,則上述的每個域名與網站都必須完成此操作。

若完全不需進行這些操作,這表示您是使用免費的憑證並且由 Gandi 自動驗證。

我選擇使用 DNS:

切到區域檔紀錄,會發現已經自動幫我們加入一筆新的 CNAME 了

過一陣子後驗證就會自動完成並啟用了。

  1. 下載 .crt 和 .pem 並將他們連接在一起 cat GandiStandardSSLCA2.pem http://www.xshogi.com.crt > all_xshogi.com.crt

第二階段:設定 Heroku

  1. 新增 certification 和 key 到 heroku
↪ heroku certs:add all_xshogi.com.crt xshogi.com.key --app xshogi
 ›   Warning: heroku update available from 7.16.4 to 7.16.6
Resolving trust chain... done
Adding SSL certificate to ⬢ xshogi... !
 ▸    Only one SNI endpoint is allowed per app (try certs:update instead).

Oops! 因為已經有一組了,只能用 update 來替換掉原本的

↪ heroku certs:update all_xshogi.com.crt xshogi.com.key --app xshogi
 ›   Warning: heroku update available from 7.16.4 to 7.16.6
Resolving trust chain... done
 ▸    Potentially Destructive Action
 ▸    This command will change the certificate of endpoint ceratosaurus-25252 from ⬢ xshogi.
 ▸    To proceed, type xshogi or re-run this command with --confirm xshogi

> xshogi
Updating SSL certificate ceratosaurus-25252 for ⬢ xshogi... done
Updated certificate details:
Common Name(s): www.xshogi.com
                xshogi.com
Expires At:     2019-10-26 07:59 UTC
Issuer:         /C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
Starts At:      2018-10-25 08:00 UTC
Subject:        /OU=Domain Control Validated/OU=Gandi Standard SSL/CN=www.xshogi.com
SSL certificate is verified by a root authority.

還要在 add 一次:

↪ heroku certs:add all_xshogi.com.crt xshogi.com.key --app xshogi
 ›   Warning: heroku update available from 7.16.4 to 7.16.6
Resolving trust chain... done
Adding SSL certificate to ⬢ xshogi... done
Certificate details:
Common Name(s): www.xshogi.com
                xshogi.com
Expires At:     2019-10-26 07:59 UTC
Issuer:         /C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
Starts At:      2018-10-25 08:00 UTC
Subject:        /OU=Domain Control Validated/OU=Gandi Standard SSL/CN=www.xshogi.com
SSL certificate is verified by a root authority.

=== The following common names already have domain entries
www.xshogi.com
xshogi.com

=== Your certificate has been added successfully.  Update your application's DNS settings as follows
Domain             Record Type  DNS Target
─────────────────  ───────────  ──────────────────────────────────────────────────────────────
www.xshogi.com     CNAME        marine-procompsognathus-l8xr054mis0egvrf5l7q8pks.herokudns.com
www.山角行.com        CNAME        www.xn--rhto43ho7a.com.herokudns.com
xshogi.com.tw      ALIAS/ANAME  xshogi.com.tw.herokudns.com
www.xshogi.com.tw  CNAME        www.xshogi.com.tw.herokudns.com
山角行.com            ALIAS/ANAME  xn--rhto43ho7a.com.herokudns.com
xshogi.com         ALIAS/ANAME  opaque-owl-6ikxb7mtjg47hg8u6mcu5g2x.herokudns.com
  1. 檢查憑證
↪ heroku certs:info -a xshogi
 ›   Warning: heroku update available from 7.16.4 to 7.16.6
Fetching SSL certificate velociraptor-96982 info for ⬢ xshogi... done
Certificate details:
Common Name(s): www.xshogi.com
                xshogi.com
Expires At:     2019-10-26 07:59 UTC
Issuer:         /C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
Starts At:      2018-10-25 08:00 UTC
Subject:        /OU=Domain Control Validated/OU=Gandi Standard SSL/CN=www.xshogi.com
SSL certificate is verified by a root authority.
  1. 修改 Gandi 的網頁轉址使用 https

Result

Porting FreeRTOS to STM32F429Discovery

工具:

  • stlink:用來燒錄和 debug 的工具(a chip)
  • openocd:用來執行 GDB server 與啟用 ARM semihosting
  • gcc-arm-none-eabi: ARM GCC
  • FreeRTOS source code
  • Board: STM32F429 Discovery

OS X 上安裝 gcc-arm-none-eabi、stlink、openocd

方法一

$ brew tap PX4/homebrew-px4    
$ brew update    
$ sudo brew install gcc-arm-none-eabi    (might not the latest version)

方法二

  1. Download “Mac installation tarball"
  2. Decompress tar
  3. set PATH of gcc-arm-none-eabi

Porting

Porting FreeRTOS 到 STM32F429-Discovery 主要是有幾個重點:

  • Utility: 來自 STM32F429I-Discovery_FW_V1.0.1(官方 driver),用途是提供一些操作硬體周邊的函式庫(API),例如 LCD
  • FreeRTOS:FreeRTOS 的 source code,在下載回來的包中 FreeRTOSV8.2.1/FreeRTOS/Source
  • CORTEX_M4F_SK: 在下載回來的包中 FreeRTOSV8.2.1/FreeRTOS/Demo,用途是提供平台 CORTEX_M4F_SK 上的驅動函式庫,是屬於 FreeRTOS 軟體方開發的接口

應用程式的開發

以 Lab39 的 freertos-basic 中 FreeRTOS 應用程式原始碼 src/ 與 include/ 為例,我們整合成 app/,並把 src/ 中的 main.c 單獨拉出來,延續 myFreeRTOS (branch: game) 的檔案架構下,應用程式 game/ 和 main.c 是放在這裡 CORTEX_M4F_SK 中,所以專案結構如下:

.
|___CORTEX_M4F_SK
|               |__ app/
|               |__ main.c
|               |__ others C files
|___ FreeRTOS
|___ Utility

Hint:main.c 有樣板,在 STM32F429I-Discovery_FW_V1.0.1/Projects/Template

參考

AJAX state 和 readyState

Key

  • AJAX 中的 request 是由 XMLHttpRequest 這個類別的物件處理的
  • 所謂 AJAX 最主要就是要跟伺服器做溝通(request)

readyState

一個溝通一定會有幾個步驟,一開始在跟伺服器進行溝通時,我們需要透過檢查 readyState 這個 XMLHttpRequest 物件的屬性值,來判斷目前的溝通進行到第幾步驟,有以下幾個步驟:

  • 0 還沒開始
  • 1 存取中
  • 2 已存取
  • 3 資訊交換中
  • 4 一切完成

伺服器會回應目前溝通做到第幾步驟給 httpRequest,httpRequest 把回應的值放到 httpRequest.readyState 這個屬性中,所以我們可以透過檢查他的值來判斷現在是做到第幾步驟,其中步驟 4 在 XMLHttpRequest 中有定義一個屬性代表它,用來給我們做判斷

// 建立一個 XMLHttpRequest 物件叫做 httpRequest
var httpRequest = new XMLHttpRequest();

// (跟伺服器進行溝通中..)
...

// 檢查伺服器回應目前溝通做到第幾步驟    
// (下面 if 中把 XMLHttpRequest.DONE 替換成 4 效果一樣)
if(httpRequest.readyState == XMLHttpRequest.DONE){       
    // 一切 OK,完成溝通,繼續解析伺服器回傳結果
} else {
    // 還沒完成
}

state

確認溝通完畢後,接下來我們要做的就是解析伺服器回傳(response)了什麼給我們,第一個要檢查的就是回傳的結果是不是正常,如果正常我們才有必要進一步解析回傳的內容,不正常就要去檢查為什麼不正常,這個正不正常的狀態,就是透過 XMLHttpRequest 物件的 state 這個屬性的值判斷,我們又稱之為 HTTP status code(狀態碼),可以參考這裡有完整的狀態碼列表

所以我們可以繼續完成前面的程式:

// 建立一個 XMLHttpRequest 物件叫做 httpRequest
var httpRequest = new XMLHttpRequest();

// (跟伺服器進行溝通中..)
...

// 檢查是否到最後一個步驟了
if(httpRequest.readyState == XMLHttpRequest.DONE){
    // 一切 OK,完成溝通,繼續解析伺服器回傳結果
    if (httpRequest.status === 200) {
        // HTTP status 200 表示一切正常,可以安心解析伺服器回傳內容啦!
    } else {
        // 似乎有點問題。
        // 或許伺服器傳回了 404(查無此頁)
        // 或者 500(內部錯誤)什麼的
        // 或是 ...
    }
} else {
    // 還沒完成
}

[AWS ECS] 將建立的 EC2 instance 加入指定的 Cluster

要使用 ECS,需要先有 Cluster,然後才在 Cluster 中建立 Containers,在 Container 中才去開 task 運行服務

Create Cluster

先到 ECS 的介面,選擇 Cluster 去建立一個新的 Cluster,Cluster name 輸入完以後可以直接建立

不填寫其他項目的話勾選 Create an empty cluster


如此會建立一個不含任何 container instance 的 cluster


如果建立的不是 empty cluster,則預設會建立個 EC2 instance 到這個 cluster


可以發現後面也是用到 CloudFormation 來建構基礎架構


Launch Container Instance into cluster

http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html

這裡我們直接到 EC2 console 去建立一個 instance,其中在 Step 3: Configure Instance Details 的地方:

1. 在 IAM 選 ecsInstanceRole

2. 在下面的 Advanced Details 設定 User data

#!/bin/bash
echo ECS_CLUSTER=[CLUSTER_NAME] >> /etc/ecs/ecs.config # 不可以寫成 ecs_config 喔!

這邊只要一個地方寫錯,就會自動變成開到 default cluster (原本沒有 default cluster 就會自動建立一個),而不是我們自己開的 cluster


  • Windows 的話是:
shell
<powershell>
Import-Module ECSTools
Initialize-ECSAgent -Cluster ‘[CLUSTER_NAME]’ -EnableTaskIAMRole
</powershell>

接著就一路 launch

NOTICE 1

etc/ecs/ecs.confog 這是 Optimized Linux 已經開好的檔案[由安裝 ecs-init 建立),使用別的 AMI 建立的 instance 沒有這個檔案,所以如果是其他 AMI 得話這步驟可以跳過,啟動 instance 後在 `sudo start ecs`[1] 之前再自己去建立並且填入資料

NOTICE 2

正常來說應該這樣就會在 Cluster 那邊見到有一個 Registered Container instances 了,但是卻沒有


Troubleshooting 的方式我們可以先 ssh 進去這個 instance

照理來說應該已經註冊了

我們去看 /var/log/ecs/ecs-init.log

bash
[ec2-user@ip-172–31–20–243 ~]$ cat /var/log/ecs/ecs-init.log
2017–11–21T09:07:12Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:14Z [INFO] Agent exited with code 1
2017–11–21T09:07:14Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:14Z [INFO] Removing existing agent container ID: 3c5290616ea532736f2d8d02465b223a0d148eea4741b3453b7381f3ff563f26
2017–11–21T09:07:14Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:15Z [INFO] Agent exited with code 1
2017–11–21T09:07:15Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:15Z [INFO] Removing existing agent container ID: 2f946d1903237e5380387032faef443e6a649e11f1066e7bceb7257420321949
2017–11–21T09:07:15Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:15Z [INFO] Agent exited with code 1
2017–11–21T09:07:15Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:15Z [INFO] Removing existing agent container ID: 7d68f5125d14e73b820ce1eeef48f933c564e6ced416512ce7728ee61154ce2c
2017–11–21T09:07:15Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:16Z [INFO] Agent exited with code 1
2017–11–21T09:07:16Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:16Z [INFO] Removing existing agent container ID: 8f69f81fa411317e28864da8a536b031cc2cc1bfbc6936400eb8e8b44abed603
2017–11–21T09:07:16Z [INFO] Starting Amazon EC2 Container Service Agent
.
.
.

可以發現一直是以 code 1 結束 (return 0 才是正常結束),接著我們去看 agent log:

$ [ec2-user@ip-172–31–20–243 ~]$ cat /var/log/ecs/ecs-agent.log.2017–11–21–09
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:50Z [INFO] Registering Instance with ECS
2017–11–21T09:11:50Z [ERROR] Could not register: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:50Z [CRITICAL] Could not create cluster: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:50Z [ERROR] Error registering: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [INFO] Loading configuration
2017–11–21T09:11:51Z [INFO] Loading state! module=”statemanager”
2017–11–21T09:11:51Z [INFO] Event stream ContainerChange start listening…
2017–11–21T09:11:51Z [WARN] Error getting valid credentials (AKID ): NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [INFO] Registering Instance with ECS
2017–11–21T09:11:51Z [ERROR] Could not register: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [CRITICAL] Could not create cluster: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [ERROR] Error registering: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
.
.
.

一直都是 CredntialsChainVerboseErrors,就知道是權限沒有給,要到 EC2 去 Attach IAM Role `ecsInstancerole`



attach 後 cluster 那邊馬上就會更新了


NOTICE 3

如果是用一般的 AMI 起的 EC2 instance,到了 attach IAM role 完還是會沒有出現在 ECS cluster 中,這就是為什麼推薦使用 ECS optimized AMI 的原因

EC2 instance 要成為 Container instance 跑在 ECS 能管得到的 cluster 上,需要再 instance 中安裝 ECS agent,因為這個 AMI 已經安裝好 ECS agent,這樣你就不需要自己安裝 agent 了

**Use non-ECS optimized Amazon Linux AMI 起 Instance 加入 Cluster 完整步驟**

參考 Install ECS agent (both Amazon Linux or non-Amazon Linux) — https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-install.html

1. 以一般方式起 Instance
2. 到 EC2 console 將 ecsInstanceRole 這個 IAM policy attach 到這個 instance
3. 連線進入這個 EC2 instance
4. sudo yum install -y ecs-init
5. touch /etc/ecs/ecs.config,然後 vim /etc/ecs/ecs.config 並且填入 ECS_CLUSTER=<指定的 cluster name>
6. sudo service docker start
7. sudo start ecs

NOTICE 4

Windows 的 EC2 instance 註冊到 Cluster 需要一段時間 (5~10 min)

ecsInstanceRole IAM Role

{
“Version”: “2012–10–17”,
“Statement”: [
{
“Effect”: “Allow”,
“Action”: [
“ecs:CreateCluster”,
“ecs:DeregisterContainerInstance”,
“ecs:DiscoverPollEndpoint”,
“ecs:Poll”,
“ecs:RegisterContainerInstance”,
“ecs:StartTelemetrySession”,
“ecs:Submit*”,
“ecr:GetAuthorizationToken”,
“ecr:BatchCheckLayerAvailability”,
“ecr:GetDownloadUrlForLayer”,
“ecr:BatchGetImage”,
“logs:CreateLogStream”,
“logs:PutLogEvents”
],
“Resource”: “*”
}
]
}

[Ruby on Rails] Rails Puma + Nginx 的組合

首先要認識一下兩者分別是什麼東西:

* Puma 是一個專為 Rails 設計的高併發 web server
* Nginx 是一個廣泛使用的 reverse proxy
這個時候可以去查一下什麼事 reverse proxy,就可以發現一張圖說明了兩者之間的關係


所謂的反向代理,是在 server-side 根據 client-side 的 request,向後端的 web server 取得資源,然後再將這些資源 response 給 client-side

另外所謂的前向代理,通常是在 client-side 的軟體,例如瀏覽器會代替 client web page (program)去向CDN請求資源

使用後端代理伺服器的好處是,假設你有很多個 web server,都統一要由單一入口給 client-side 存取,則可以把存取的工作交給 reverse proxy,例如:

Web Server:

* Home Page Web Server
* Forum Web Server
* Wiki Web Server

然後你的客戶會連線到 www.my.domain.com,此時應該存取 Home Page Web Server,但當他連線到 www.my.domain.com/forum 時,應該要存取 Forum Web Server,可是如果把你的網域綁定到 Home Page Web Server,就無法另外連線到不同伺服器了,因此可以改用反向代理伺服器,把網域綁定到這台機器上,當反向代理判斷是要存取 Home Page,就會由他向那台伺服器請求資源,而要存取 Forum 時,就另外再向論壇的伺服器請求資源

另外,反向代理伺服器還有一些對於網站應用程式來說有很大幫助的功能,例如 load balancing、auto-scaling、failover 等

load balancing 會在流量大增的時候進行分流的動作,例如你有多台 forum web server,平時每天流量上萬,為了確保伺服器能夠穩定運作,不會因為短時間的存取量太大導致伺服器處理不及而癱瘓,就可以設定將一部分的存取流量導向 standby 的那台伺服器

auto-scaling 則是可以為你正在服務的伺服器自動依據目前的流量或運算量,最大化可以分配的資源,簡單來說,你有一台伺服器的記憶體有 32GB,分配給網頁伺服器的使用量只有 2GB,如果你的網頁服務需要大量運算(例如線上資料處理或機器學習),很有可能短時間內就把 2GB用完了,因此你可以設定當監測到記憶體快要用罄,系統會自動配置更多的記憶體來應付突發的運算量

failover 則是為了免除網站服務最擔心的事 — 中斷服務(downtime),你的伺服器很有可能被 DDoS 攻擊,或是程式有 bug,使用者不小心觸發導致伺服器掛了,這個時候假如你有一台 standby 的伺服器,有設定好 failover 功能,則會在監控到主要伺服器中斷服務的時候,立刻將存取要求導向那台 standby 的伺服器,縮短 downtime 的時間

說到 DDoS 攻擊,load balancing 或其他相關功能也可以在監控到瞬間變大的流量時,自動將(不正常)流量導向其他地方,就有專門的業者,是提供流量接收的服務,讓一些容易被 DDoS 攻擊的網站服務公司將流量導像他們的伺服器,這個功能的設定也可以在反向代理完成