【Golang】RequestからQueryStringを取得するには

最近Golangでコマンドラインツールを作りたくて、Golangのサンプルコードとかを動かしていろいろ遊びながら覚えているところなのですが、たまたまEchoサーバーのプログラムがあったので試したのですがすごく簡単にかけますね!

そのとき、リクエストからQuery Stringをどう抜き出すんだろと思って試しに書いてみました。

package main

import (
    "net/http"
    "log"
    "fmt"
)

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
    v := r.URL.Query()
    if v == nil {
        return
    }
    for key, vs := range v {
        fmt.Fprintf(w, "%s = %s\n", key, vs[0])
    }
}

r.URL.Query()type Values map[string][]string を受け取ることができるので、rangeでループ回して表示しています。

個別にキーを指定して取得したい場合は以下のようにキーを指定してあげれば取得できるはず

r.URL.QUuery().Get(キー)

EC2のユーザーデータ内でcloud-initとシェルスクリプトを使いたい

こんにちは。こんばんは。

たまたま、CloudFormationのテンプレートから起動されるEC2のユーザーデータを利用して、インストールしておきたいモジュールがありました。

ユーザーデータには、cloud-initシェルスクリプト で何らかの処理を書くことができるのですが、 テンプレートにはすでにcloud-initの形式で書かれており、シェルスクリプトを書こうとするとエラーとなりユーザーデータで書いた内容は実行されません。

EC2のユーザーデータ内で、cloud-initシェルスクリプト を併用したいけどそんなことができるのかといろいろ調べていくうちに、この記事に行き着きました。

cloud-initでシェルスクリプトとcloud-configを同時に使う

はい、やりたかったことはこれです!!

ってことで、実際に自分でやってみた手順を書いていきたいと思います。

cloud-utils パッケージをインストールする

まず、cloud-utils パッケージをインストールしましょう。

$ sudo yum install cloud-utils

※ 上記は、Amazon Linux AMI 2018.03.0 から作成したEC2内で作業をしています。

cloud-init 形式で書いてファイルを作成

viを立ち上げてファイルを作成します。

$ vi cloud-config.txt

そして、以下の内容をコピペして保存してください。

#cloud-config
packages:
  - sl

runcmd:
  - echo "HELLO Cloud Config"

シェルスクリプトで書いてファイルを作成

viを立ち上げてファイルを作成します。

$ vi shell.txt

そして、以下の内容をコピペして保存してください。

#!/bin/bash -xe

touch /home/ec2-user/create-by-shellscript.txt
echo "HELLO ShellScript" >> /home/ec2-user/create-by-shellscript.txt

write-mime-multipart で MIMEマルチパート形式のファイルを作成

先ほど作成した、cloud-config.txtshellscript.txt を使って、 MIMEマルチパート形式のファイルを作成します。

以下のコマンドを実行してみましょう。

$ write-mime-multipart --output=output.txt cloud-config.txt:text/cloud-config shell.txt:text/x-shellscript

するとカレントディレクトリに、output.txt が作成されていると思います。

ファイルの内容を確認するとこのように記述されています。

Content-Type: multipart/mixed; boundary="===============2433150631494388583=="
MIME-Version: 1.0

--===============2433150631494388583==
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
packages:
  - sl

runcmd:
  - echo "HELLO Cloud Config"

--===============2433150631494388583==
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="shell.txt"

#!/bin/bash -xe

touch /home/ec2-user/create-by-shellscript.txt
echo "HELLO ShellScript" >> /home/ec2-user/create-by-shellscript.txt

--===============2433150631494388583==--

このファイルの内容をそのままEC2のユーザーデータにコピペして起動してあげると、 処理が自動で実行されます。

f:id:ryskit:20180516203222p:plain

立ち上げたインスタンスにSSHで入って確認してみましょう!

ユーザーデータの内容が実行されたかどうかは、/var/log/cloud-init-output.txt を見れば確認できます。

$ less /var/log/cloud-init-output.log
:
:
Existing lock /var/run/yum.pid: another copy is running as pid 2597.
Another app is currently holding the yum lock; waiting for it to exit...
  The other application is: yum
    Memory :  38 M RSS (286 MB VSZ)
    Started: Wed May 16 11:30:54 2018 - 00:00 ago
    State  : Running, pid: 2597
Resolving Dependencies
--> Running transaction check
---> Package sl.x86_64 0:5.02-1.6.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package     Arch            Version                   Repository          Size
================================================================================
Installing:
 sl          x86_64          5.02-1.6.amzn1            amzn-main           13 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 13 k
Installed size: 15 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : sl-5.02-1.6.amzn1.x86_64                                     1/1
  Verifying  : sl-5.02-1.6.amzn1.x86_64                                     1/1

Installed:
  sl.x86_64 0:5.02-1.6.amzn1

Complete!
Cloud-init v. 0.7.6 running 'modules:final' at Wed, 16 May 2018 11:30:58 +0000. Up 25.17 seconds.
HELLO Cloud Config
+ touch /home/ec2-user/create-by-shellscript.txt
+ echo 'HELLO ShellScript'
Cloud-init v. 0.7.6 finished at Wed, 16 May 2018 11:30:58 +0000. Datasource DataSourceEc2.  Up 25.50 seconds

正しくログが吐かれていますね!!

CloudFormationのEC2インスタンスのユーザーデータでも同じことをしたい場合は、 作成したMIMEマルチパート形式のファイルの内容を同じようにコピペしてあげれば動作します。 ただし、JSON形式だとダブルクオテーションで一文一文を囲ってあげないと動作しないと思うのでそこは注意してくださいね。

では!!

Railsのbelongs_toに指定できるoptional: trueとは?

今年1月に転職して新しい環境で働き始めていて、そこのプロジェクトではRuby on Railsを使っています。

今までRuby on Railsでサービス等を作った経験があまりがなくRailsを知る必要が出てきで、最近出版された「Ruby on Rails5の上手な使い方」という本を買いました。

この本にはモデルのbelongs_to に以下のようなオプションが書かれていました。

class Customer < ApplicationRecord
  has_many :orders
end

class Address < ApplicationRecord
  belongs_to :customer, optional: true
end

この optional: true ってなんなのか。

結論から言うと、belongs_toの外部キーnilを許可するというものです。

上記のコードであればAddress.customer_idが外部キーになり、値がセットされていない場合はバリデーションではじかれますが、optional: trueを設定しておくと、外部キーがnilであってもDBに保存できます。

ただDBの設計上、外部キーのnilを許可することが少ない気がするので、あまり使う設定ではないかもしれません。