- 普段は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