- 普段はCloud Foundryの業務
- すきなもの: Music Movie Game
- Cloud Foundryにアプリをデプロイする際などに利用するツール
- 元々はvmcやcfコマンドというコマンドでruby実装だった
- gcfはGo言語実装
- つい先日までgo-cfというコマンド名でした
- 最新版は公式がビルドしたバイナリファイルがダウンロード可能
- 上記の最新版はversion 6.0.0.rc1
- cliのtracker
- 開発をしている際にどのdea上でアプリが動いているか知りたい
- cfコマンドやvmcではrubyの部分をちょこちょこっと直すだけでOKだった
- gcfでも同じ部分を直すことでgcfの構成を把握
- gcfのgcf app hogehogeにDEAのIPとPortを表示するようにする
- まずはソースを取ってくる(https://github.com/cloudfoundry/cli)
git clone https://github.com/cloudfoundry/cli.git
- go言語のインストールは、gvmなりで1.1以上のgoを入れておいてください
- cf コマンドの場合
cf stats hogehoge --trace
- gcfコマンドの場合
CF_TRACE=true ./gcf app hogehoge
前提:各インスタンス毎に起動するDEAのIPとPortがある
RESPONSE:
HTTP/1.1 200 OK
Content-Length: 282
Content-Type: application/json;charset=utf-8
Date: Fri, 29 Nov 2013 03:01:51 GMT
Server: nginx
X-Content-Type-Options: nosniff
X-Vcap-Request-Id: 8ed08e07-f6e9-40bb-a339-27fb8e08a4c2
{"0":{"state":"RUNNING","stats":{"name":"sinatra","uris":[],"host":"192.168.12.129","port":61001,"uptime":50482,"mem_quota":268435456,"disk_quota":1073741824,"fds_quota":16384,"usage":{"time":"2013-11-29 12:01:51 +0900","cpu":2.894267113919665e-05,"mem":18698240,"disk":56041472}}}}
Cloud Foundryに関連したデータ構造の定義がされている
- HostとPortの宣言追加
98 type ApplicationInstance struct {
99 State InstanceState
100 Since time.Time
101 CpuUsage float64 // percentage
102 DiskQuota uint64 // in bytes
103 Host string
104 Port int
105 DiskUsage uint64
106 MemQuota uint64
107 MemUsage uint64
108 }
src/cf/apiの下が各コマンドを実行した際のapiとやり取りする部分
trace結果の並びでdisk_quotaと近い並びになっているので同じように記載
- 132と133行目をDiskQuotaの真似をして記述
128 type StatsApiResponse map[string]InstanceStatsApiResponse
129
130 type InstanceStatsApiResponse struct {
131 Stats struct {
132 Host string `json:"host"`
133 Port int `json:"port"`
134 DiskQuota uint64 `json:"disk_quota"`
135 MemQuota uint64 `json:"mem_quota"`
136 Usage struct {
137 Cpu float64
138 Disk uint64
139 Mem uint64
140 }
141 }
142 }
- v2/apps/アプリ名/statsで情報を取得
- domainで定義したHostとPortで値をとれるようにstatsの結果を格納
- instance.Hostとinstance.Portが domainのApplicationInstanceで宣言したもの
- v.Stats.Hostとv.Stats.Portがtype InstanceStatsApiResponse struct {Stats struct {
144 func (repo CloudControllerAppSummaryRepository) updateInstancesWithStats(app cf.Application, instances []cf.ApplicationInstance) (updatedInst []cf.Applicati onInstance, apiResponse net.ApiResponse) {
145 path := fmt.Sprintf("%s/v2/apps/%s/stats", repo.config.Target, app.Guid)
146 statsResponse := StatsApiResponse{}
147 apiResponse = repo.gateway.GetResource(path, repo.config.AccessToken, &statsResponse)
148 if apiResponse.IsNotSuccessful() {
149 return
150 }
152 updatedInst = make([]cf.ApplicationInstance, len(statsResponse), len(statsResponse))
153 for k, v := range statsResponse {
154 index, err := strconv.Atoi(k)
155 if err != nil {
156 continue
157 }
158
159 instance := instances[index]
160 instance.CpuUsage = v.Stats.Usage.Cpu
161 instance.DiskQuota = v.Stats.DiskQuota
162 instance.DiskUsage = v.Stats.Usage.Disk
163 instance.MemQuota = v.Stats.MemQuota
164 instance.MemUsage = v.Stats.Usage.Mem
165 instance.Host = v.Stats.Host
166 instance.Port = v.Stats.Port
コマンドを実際にたたいた際の結果表示部分
- tableのdiskの後に"host:port"を追加
80 table := [][]string{
81 []string{"", "status", "since", "cpu", "memory", "disk", "host:port"},
82 }
- fmt.Sprintfのinstance.DiskUsageの下に追加
84 for index, instance := range summary.Instances {
85 table = append(table, []string{
86 fmt.Sprintf("#%d", index),
87 coloredInstanceState(instance),
88 instance.Since.Format("2006-01-02 03:04:05 PM"),
89 fmt.Sprintf("%.1f%%", instance.CpuUsage),
90 fmt.Sprintf("%s of %s", formatters.ByteSize(instance.MemUsage), formatters.ByteSize(instance.MemQuota)),
91 fmt.Sprintf("%s of %s", formatters.ByteSize(instance.DiskUsage), formatters.ByteSize(instance.DiskQuota)),
92 fmt.Sprintf("%s:%d", instance.Host, instance.Port),
93 })
94 }
- src/cf/commands/application/show_app.goと同じパス
- テスト対象_test.goという命名
- 今回は表示部分のみにテストを追加
65 instances := []cf.ApplicationInstance{
66 cf.ApplicationInstance{
67 State: cf.InstanceRunning,
68 Since: time1,
69 CpuUsage: 1.0,
70 DiskQuota: 1 * formatters.GIGABYTE,
71 DiskUsage: 32 * formatters.MEGABYTE,
72 Host: "192.168.1.200",
73 Port: 12345,
74 MemQuota: 64 * formatters.MEGABYTE,
75 MemUsage: 13 * formatters.BYTE,
105 assert.Contains(t, ui.Outputs[7], "#0") 106 assert.Contains(t, ui.Outputs[7], "running") 107 assert.Contains(t, ui.Outputs[7], "2012-01-02 03:04:05 PM") 108 assert.Contains(t, ui.Outputs[7], "1.0%") 109 assert.Contains(t, ui.Outputs[7], "13 of 64M") 110 assert.Contains(t, ui.Outputs[7], "32M of 1G") 111 assert.Contains(t, ui.Outputs[7], "192.168.1.200:12345")
- cli直下でbin/testを実行
- 中でgo fmtが入っているのでコミット後に実施するとソースが変わる可能性があるので注意
- インデントはタブで入れる等を調べずに書いていたのではまった
git submodule update --init --recursive ./bin/test
ok cf 0.027s ok cf/api 13.024s ok cf/app 7.787s ok cf/commands 0.039s ok cf/commands/application 4.058s ok cf/commands/buildpack 0.033s ok cf/commands/domain 0.033s ok cf/commands/organization 0.033s ok cf/commands/route 0.041s ok cf/commands/service 0.039s ok cf/commands/serviceauthtoken 0.035s ok cf/commands/servicebroker 0.034s ok cf/commands/space 0.033s ok cf/commands/user 0.038s ok cf/configuration 0.015s ok cf/formatters 0.011s ok cf/net 0.324s ok cf/requirements 0.025s ok cf/terminal 0.015s Vetting packages for potential issues...
- 現状の構成概要とコマンド実装追加の良いサンプル
- src/cf/commands/space/create_space.goとのこと
- ファイルの命名等
- コマンドファイルとメソッドはCRUDに合わせて
- spaceコマンドの場合はCreateSpace, ListSpaces等
- 詳細は以下を参照
src/ cf/ api/ ccng等との実際のapiのやり取り部分 app/ commands/ リソース毎にコマンドのファイルが分かれている configuration/ formatters/ net/ requirements terminal
