3年前に作った、DigitalOceanで毎月の請求額をシェルスクリプトでSlack通知(CircleCI/スケジュールトリガー)させていましたが、勉強がてらGoに移行してみました。かつ、今ChatGPTが流行りまくっていますが、コードのベースは作ってくれたとしても全く動かなかったので、デバッグして修正してみました。
ChatGPT使ってGo書いてるけど、全く動かなくて吹いた。
— adachin👾SRE (@adachin0817) April 30, 2023
add billing/main.go
- go version 1.20.3
- 流れ
- APIのHTTPリクエストを作成/送信
- レスポンスボディをJSONとしてパース
- 請求履歴を取得
- 取得した請求履歴を使用
- Slackに通知するメッセージを作成
- Slack Incoming Webhook URLを設定
- SlackにPOSTするJSONデータを作成
- SlackのHTTPリクエストを作成/Slackに通知。
- APIのHTTPリクエストを作成/送信
- 環境変数
- DO_TOKEN
- SLACK_URL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" "strings" ) type Attachment struct { Color string `json:"color"` Text string `json:"text"` } func main() { endpoint := "https://api.digitalocean.com/v2/customers/my/billing_history" token := os.Getenv("DO_TOKEN") slack_url := os.Getenv("SLACK_URL") // HTTPリクエストを作成 req, err := http.NewRequest("GET", endpoint, nil) if err != nil { panic(err) } // アクセストークンをHTTPリクエストヘッダーに設定 req.Header.Set("Authorization", "Bearer "+token) // HTTPリクエストを送信 client := &http.Client{} res, err := client.Do(req) if err != nil { panic(err) } // レスポンスボディを読み取り defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err) } // レスポンスボディをJSONとしてパースして、請求履歴を取得 var data map[string]interface{} err = json.Unmarshal(body, &data) if err != nil { panic(err) } // 請求履歴を取得 billingHistory := data["billing_history"].([]interface{}) latestBill := billingHistory[0].(map[string]interface{}) date := latestBill["date"].(string) amount := latestBill["amount"].(string) // Slackに通知するメッセージを作成 message := fmt.Sprintf("https://hoge \n ・ %s \n ・ $%s ", date, amount) // debug //fmt.Println(message) // SlackにPOSTするJSONデータを作成 attachment := Attachment{ Color: "#240bde", Text: message, } attachments := []Attachment{attachment} payload := map[string]interface{}{ "text": "Check billing! :cloud:", "attachments": attachments, } jsonValue, err := json.Marshal(payload) if err != nil { panic(err) } reader := strings.NewReader(string(jsonValue)) // Slack HTTPリクエストを作成 req, err = http.NewRequest("POST", slack_url, reader) if err != nil { panic(err) } // Content-Typeを設定 req.Header.Set("Content-Type", "application/json") // Slack HTTPリクエストを送信 res, err = client.Do(req) if err != nil { panic(err) } } |
ちなみに latestBillを fmt.Println
すると以下のように出てきます。
1 |
map[amount:-73.66 date:2023-05-01T10:26:11Z description:Payment (Visa xxxxx) receipt_id:xxxxxxx type:Payment] |
CircleCI
- .circleci/config.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
version: 2.1 orbs: slack: circleci/slack@4.10.1 references: default_config: &default_config docker: - image: golang:1.20.3 working_directory: ~/project commands: slack-notify-fail: description: "Slack notify fail" steps: - slack/notify: channel: ci_cd event: fail template: basic_fail_1 slack-notify-success: description: "Slack notify success" steps: - slack/notify: channel: ci_cd event: pass template: basic_success_1 jobs: billing_run: <<: *default_config steps: - checkout - run: name : update and install curl jq command: | apt-get update && apt-get install curl jq -y - run: name : DigitalOcean billing_run command: | go run ~/project/billing/main.go - slack-notify-fail - slack-notify-success workflows: version: 2.1 cron_schedule: triggers: - schedule: cron: "0 0 2 * *" filters: branches: only: master jobs: - billing_run |
golangコンテナに変更してSlack Orbsもバージョン3だったので、4にバージョンアップしました。(通知方法はTemplates)ジョブのスケジュールトリガーは毎月2日0時のまま実行となります。
Test
- CircleCI
- Slack
$73か…高え…
まとめ
おっし、シェルからGoに移行できたからブログ書こう。久しぶりにGo書いたけどわからん。
— adachin👾SRE (@adachin0817) May 2, 2023
シェル芸からChatGPTを使ってGoに移行することができました。ChatGPTのメリットはプログラムを書く際に、静的型付け言語ってどうやって書くんや…なるほどこんな風に書けばいいのか〜と学習の速度が向上します。やはり人のコードを真似して書くのが手っ取り早いので、ChatGPTはバシバシ活用していきましょう!てか機能ごとに関数にしたほうが可読性が良いので、後でリファクタリングします。深夜3時のブログは眠いんだわ。
0件のコメント