Goalist Developers Blog

Swaggerを使ってRestful APIを記述する

こんにちは、ゴーリストのトゥアンです。

ウェブ開発でRestful APIはだんだん普及していると共に、Resful APIを記述するためにいろいろな仕方があります。

Swaggerを使うことは下記の通りに、いくつかの利点があります。

  • Amazon API Gatewayへ展開できる
  • フロントエンド開発のため、モックサーバーを作りやすい
  • OpenAPI仕様の基準に基づくAPIの入力(リクエスト)・出力(レスポンス)を定義できる

Swagger 3.0 は2017年07月にリリースされましたが、現在AWSはSwagger 2.0だけサポートしているので、今回の記事でSwagger 2.0について説明します。

Swaggerファイルのフォーマット

SwaggerでサポートしているフォーマットはYAMLとJSONです。

Swaggerファイルの構造は複数階層のオブジェクトです。ルートオブジェクトは「Swagger」というオブジェクトです。

1. Swagger オブジェクト

詳しい情報は下記のリンクにご参考ください。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object

大切なフィールドは:

フィールド名 タイプ 説明
swagger String 必須です。"2.0"という固定な価値があります。
info Object 必須です。情報のオブジェクトです。後で説明します。
host String ホスト名又はホストのIPアドレスです。
basePath String 全部APIの共有なパスです
schemes String 全部APIのプロトコル(httpやhttps, ws, wssなど)です
paths Object 必須です。
全部APIを一つずつ記述するためのオブジェクトです。
後で説明します。
definitions Object 自由なオブジェクトを定義できます。後で説明します。

2. info オブジェクト

APIについてのメタデータです。 詳しい情報は下記のリンクにご参考ください。 https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#info-object

大切なフィールドは:

フィールド名 タイプ 説明
title String 必須です。アプリケーションのタイトルです
version String 必須です。API記述仕様書のバーションです。

3. paths オブジェクト

APIの記述情報です。 詳しい情報は下記のリンクにご参考ください。 https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#paths-object

大切なフィールドは:

フィールド名 タイプ 説明
/{path}
{path}は任意に定義できる
Object 定義されたpathに該当するAPIの記述です。
「Path Item」 というオブジェクトです。
後で説明します。

Path Itemオブジェクトの詳しい情報は下記のリンクにご参考ください。 https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#paths-item-object

大切なフィールドは:

フィールド名 タイプ 説明
get Object 定義されたpathに該当するGETメソードの記述です。
「Operation」というオブジェクトです。後で説明します。
put Object pathに該当するPUTメソードの記述です。
タイプはgetのOperationオブジェクトと同じです。
post Object pathに該当するPOSTメソードの記述です。
タイプはgetのOperationオブジェクトと同じです。
delete Object 定義されたpathに該当するDELETEメソードの記述です。
タイプはgetのOperationオブジェクトと同じです。
options Object pathに該当するOPTIONSメソードの記述です。
タイプはgetのOperationオブジェクトと同じです。
head Object pathに該当するHEADメソードの記述です。
タイプはgetのOperationオブジェクトと同じです。
patch Object pathに該当するPATCHメソードの記述です。
タイプはgetのOperationオブジェクトと同じです。
parameters Array 全部のメソッドの共有なリクエストパラメーターです。
配列要素のタイプは以下のいずれかです。
・definitionsに自由に定義したオブジェクトに参考
・「Parameter」というオブジェクト。後で説明します。

4. operation オブジェクト

定義されたパスの一つのメソッドのリクエスト・レスポンスの記述です。
詳しい情報は下記のリンクにご参考ください。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#operation-object

大切なフィールドは:

フィールド名 タイプ 説明
parameters Array メソードのリクエストパラメーターです。
配列要素のタイプは以下のいずれかです。
・definitionsに自由に定義したオブジェクトに参考
・「Parameter」というオブジェクト
responses Object レスポンスを記述するためのオブジェクトです。
後で説明します。

5. parameter オブジェクト

リクエストパラメーターの記述です。
詳しい情報は下記のリンクにご参考ください。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameter-object

大切なフィールドは:

フィールド名 タイプ 説明
name String 必須です。パラメーターの名前です。
in String 必須です。リクエストにパラメーターを含める場所です。
価値は以下のいずれかです。
・"query"
・"header"
・"path"
・"formData"
・"body"
required Boolean 定義されたパラメーターは必須かどうか記述です。

6. responses オブジェクト

APIレスポンスの記述です。 詳しい情報は下記のリンクにご参考ください。 https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#responses-object

大切なフィールドは:

フィールド名 タイプ 説明
{HTTP ステータスコード}
(400や404, 500など)
Object 定義されたHTTPステータスコードに該当するレスポンスの記述です。
タイプは以下のいずれかです。
・definitionsに自由に定義したオブジェクトに参考 
・「Response」 というオブジェクトです。後で説明します。

Responseオブジェクトの詳しい情報は下記のリンクにご参考ください。 https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#responseObject

大切なフィールドは:

フィールド名 タイプ 説明
description String 必須です。レスポンスの概念記述です。
schema Object APIレスポンスの構造詳細記述です。後で説明します。

7. definitions オブジェクト

自由なオベジェクトの定義です。
詳しい情報は下記のリンクにご参考ください。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#definitionsObject

definitions オブジェクトのフィールドは:

フィールド名 タイプ 説明
{name}
name: 定義したいオベジェクトの名前です。
Object 指定されたnameがあるオブジェクトの記述です。
タイプはresponseのschemaオブジェクトと同じです。
後で説明します。

SchemaオブジェクトはJSON Schema仕様書に基づいて定義されます。
JSON Schema仕様書は下記のリンクにご参考ください。
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#definitionsObject 
また、JSON Schema仕様書の他にSwaggerのSchemaオブジェクトは特別なフィールドもあります。
詳しい情報は下記のリンクにご参考ください。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schema-object

大切なフィールドは:

フィールド名 タイプ 説明
type String 定義したいオブジェクトのタイプです。
サポートしているタイプは:
原始タイプ("integer"や"string"など)、
"array"と"object"です

typeが"array"である場合、下記のフィルードがあります。

フィールド名 タイプ 説明
items Object 配列要素を定義するためのSchemaオブジェクトです。

typeが"object"である場合、下記のフィルードがあります。

フィールド名 タイプ 説明
required Array 必須なフィルード名の配列です。
properties Object オブジェクトのフィルードを定義するための各Schema オブジェクトです。

サンプル

課題:https://example.swagger.io/v1/users/{user_id} パスのGETメソッドとPUTメソッドを記述します。

GETメソッド:
リクエストのパラーメータ:
+ user_id : パスにある
レスポンスのオブジェクト:ユーザの名前とユーザのメールアドレス

PUTメソッド:
リクエストのパラーメータ:
+ user_id : パスにある
+ name: ボディにある
+ email: ボディにある
レスポンスのオブジェクト:成功な場合に200コードを返却して、失敗な場合に400コードと404コードを返却します。

上記のAPIを記述するために、下記のSwaggerファイルを作ります。

swagger: "2.0"
info: # infoオブジェクト
  title: "Swaggerの例"
  version: "1.0.0"
host: "example.swagger.io"
basePath: "/v1"
schemes:
- "https"
paths: # pathsオブジェクト
  /user/{user_id}:
    get: # getメソッドのoperationオブジェクト
      tags:
      - "userAPI"
      summary: "ユーザーIDによって、ユーザー情報を取得する"
      operationId: "getUserByUserId"
      produces:
      - "application/json"
      parameters: # parameterオブジェクトの配列
      - name: "user_id"
        in: "path"
        description: "ユーザーID"
        required: true
        type: "number"
      responses: # responsesオブジェクト
        200:
          description: "成功なレスポンス"
          schema: # schemaオブジェクト
            $ref: "#/definitions/User" 
            # definitionsに定義されたオブジェクトの参考
        400:
          description: "無効なユーザーID"
        404:
          description: "ユーザーを見つけていません"
    put: # putメソッドのoperationオブジェクト
      tags:
      - "userAPI"
      summary: "ユーザーIDによって、ユーザー情報を更新する"
      operationId: "updateUserByUserId"
      produces:
      - "application/json"
      parameters: # parameterオブジェクトの配列
      - name: "user_id"
        in: "path"
        description: "ユーザーID"
        required: true
        type: "number"
      - in: "body"
        name: "body"
        required: true
        schema: # schemaオブジェクト
          $ref: "#/definitions/UpdateUserReq" 
          # definitionsに定義されたオベジェクの参考
      responses: # responsesオブジェクト
        200:
          description: "成功なレスポンス"
        400:
          description: "無効なユーザーID"
        404:
          description: "ユーザーを見つけていません"
definitions: # definitionsオブジェクト
  User: # schemaオブジェクト
    type: "object"
    properties:
      id: # schemaオブジェクト
        type: "integer"
        format: "int64"
      name: # schemaオブジェクト
        type: "string"
      email: # schemaオブジェクト
        type: "string"
  UpdateUserReq: # schemaオブジェクト
    type: "object"
    required:
      - "name"
      - "email"
    properties:
      name: # schemaオブジェクト
        type: "string"
      email: # schemaオブジェクト
        type: "string"

Swagger UI」を使って、記述したAPIは綺麗に表示できます。

API概要の表示 f:id:t-nguyen:20180709155906p:plain GETメソッドの表示 f:id:t-nguyen:20180709154630p:plain PUTメソッドの表示 f:id:t-nguyen:20180709154752p:plain

ツール

Swaggerを書くために、「Swagger Editor」を使って、エラーがある場合、すぐ報告は出ます。

Swaggerファイルを作成した後で、「Swagger UI」を使って、記述したAPIは綺麗に表示できます。

この二つのツールをローカル環境にダウンロードすることと、ウェブブラウザーにオンラインで使うことと、どちらもできます。

参考書類

今回の記事でSwagger 2.0について少し説明しました。
詳しい情報は下記のリンクにご参考ください。

バーション2.0 : https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
バーション3.0 : https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md

【求人情報ビッグデータ】HR EXPO 2018出展しています

こんにちは、開発部の飯尾です。
昨日7月11日水曜日、タイトル通りHR EXPOに参加してきました!

www.hr-expo.jp

企業の人事担当者さま向けに、サービス紹介・商談を行うイベントです。
ゴーリストもHR Tech領域で自社サービスを紹介してきました。

日本中の求人情報ビッグデータから、採用を読み解くHRogシリーズ

f:id:y-iio:20180712120616p:plain

https://chart.hrog.net/chart.hrog.net

map.hrog.net

ブースの様子
自社メディアのキャラクター「ふろぐん」カラーのTシャツで目立つ…

f:id:y-iio:20180712113445j:plain

私は現在、HRogチャートHRogマップの開発・運用を担当しています。
ときおり既存ユーザーの営業訪問に同行することはありますが
ど新規の営業イベントに参加するのは初です!

あんまり力になれてるわけでは無いですが

  • 呼び込みスクリプトの考案
  • とりあえず声出して足を止めてもらう

などなど、自分にもできることをがんばりました〜
普段営業メンバーがさらっとサービス紹介していることのすごさを実感ですね。

とはいえ「アルバイト採用担当されてるんですか?私が作ったサービスでこういうのあるんです!よかったらデモ触っていきませんか!」の最高の流れが実現できたので
個人的には満足です、ガハハ


このHR EXPOは明日13日金曜日まで開催中です。
ぜひゴーリストブースへ遊びに来てください!
\カワイラシイふろぐんうちわも配ってます/

こういうお祭り的なイベントもオモチロイものですね。
窓の外に出ると己の姿もよく見えると思います。

技術ブログとはいえ、採用のためにやってるものなので
社内エンジニアがどんな仕事してるかとか会社の雰囲気もこんなかんじで紹介していきます💪('ω'💪)

Gitがやばい!(1/3)

最近初めての開発者が多いプロジェクトに参加しました、そのためgitの強さがよ〜くわかりました(やらかしながらね)。シンプルから複雑な動き:つまり、「自分一人でバージョ二ングだけのために使ってる」場合(シンプル)から「ヤベー、いろんな人がいるし、ギットからデプロイされてるし、何が起きてる?!」(複雑)な状況に便利なものを軽く通しておくと便利かなと思いました。(以外と長かったため、この記事には基本:Level 0 とLevel 1を書いて見ました)

https://assets-cdn.github.com/images/modules/open_graph/github-mark.png

Level 0: init, .gitignore, status, remote

まずは環境設定みたいなものですね。プロジェクトフォルダーに git initを書きますとそのフォルダーがレポジトリとして初めて使えるようになります。 最初の状態で何も「トラッキング」されてないです。

status

git statusは現在の状況を確認するためのコマンドです。 git status を打ちますと、そのフォルダーの内容が全部出て、”untracked files”としての一覧になってます。 f:id:c-pattamada:20180705160140p:plain

.gitignore

このファイルの中に、gitを無視して欲しいファイル・パスなどを書きます。特に、プロジェクのlibフォルダーのような、外部ライブラリーのファイルを普通はのぞいて欲しいために、そういうパスを入力すれば良いです。 また、個人エディタ用のフォルダー(.ideaなど)も含めた方がいいかと思います。 この場合は ‘fileToIgnore.txt’を無視しましょう、ご覧の通り、lsには見えますがgitの方がむししているのです。

f:id:c-pattamada:20180705160159p:plain

入力後、またgit statusを打つと、ちゃんと無視してると確認できます。

f:id:c-pattamada:20180705160213p:plain

remote

Gitが複数の人たちが同じプロジェクトに開発できるために作られてますのでオンライン上にも置かれてるケースが多いです。ローカルのgit repositoryをオンラインに繋ぐのに githubでrepositoryを作る必要があります。 これを行うために、githubでのrepositoryも存在する必要があります。以下の記事のstep 2の画像を参考にしてください)

Deploying an Angular app to GitHub Pages - Goalist Developers Blog

Repository のurl をコピーして、
git remote add origin <url>
のようにローカルのgitのremoteを設定できます(originがそのサーバーの名前になりますが、他の名前でも大丈夫です)。

Level 1: Add, Commit, push, checkout, reset/revert.

残りのファイルを「トラッキング」したいと思いますので一旦プロジェクトフォルダから git add . を打ちましょう、そして、git statusで…. 緑! (ファイル一個ずつもadd できます。git add <ファイル名>)

f:id:c-pattamada:20180705160239p:plain

現在の緑のファイルをcommit する準備が整ってる。

と言っても… commitとは?

Commitはギットの基本技です。「add」されたファイルの状況を保存するようなことです。まさにゲームでボスの前に保存してから、ボスを倒した後でまた保存するように使うイメージです。何かがうまく行かなかった場合に、ボスの前のコミットに戻せます。

Commitするとどういう情報が保存されてるでしょう? それは以前のコミットと比べて、変更したファイル(何行目を変更したなど)の情報です。後に現れる「Merge」でこれが重要となります

Commitするために: git commit -m "コミットについての一言" を使えば便利だと思います -m は 「メッセージ」(コミットについての一言)を追加するためにあります。

Commitがそれぞれユニークなhashをもつ、これによってギットがコミットを管理します(英語ですが、How is git commit sha1 formed · GitHub で、そのハッシュがどうやって作られてるのかを調べた人もいました)

では、git log でコミット歴史を見ましょう

f:id:c-pattamada:20180705160518p:plain

黄色文字列が今回のコミットハッシュです。あとでハッシュを使うものも見ましょう! (ボーナス:githubのコミットの管理画面からいかの画像のようなコミットが見れます、そこで右側の青いものをクリックするとhashをコピーできます ^^) f:id:c-pattamada:20180705160748p:plain 

Commitしました!で..?

ローカルのgitを定期的にオンラインにpushしましょう!これで、バックアップとなり、他の人とシェアしたり共同開発ができるようになります! 先ほどのlevel 0で設定したoriginがpush先になります。 では、pushしましょう! git push -u origin masterを打てば、現在使ってるmasterのbranch(後で詳細書きます)がオンラインにも現れます。 -u が最初の時に使った方がいいですが、その後でgit pushでできます。

これでオンライン上のgit repositoryに行きますと、自分のpushの結果が見れます。

あー間違いました!

だいたい二つの状況があるかと思います。

コミットする前に、やっぱりいまの変更が失敗だと判断して、前のセーブに戻りたい

つまり、ボスに倒されて、直前のセーブの状態にresetをしたい。 まだコミットしてない状態なら、 git checkout <ファイル名> を使って、ローカルの変更を捨てられます。 注意:捨てられた変更は失われます。

一つのファイルではなく、全ファイルの場合に git checkout .が使えます。(両方ともremoteが設定されてる前提です。)

コミットをした後で後悔中です!

こういうのもよくあるかと思います。間違ったファイルをcommitしたり、アップしたら他の人が作ってる部分がなぜか壊れたりするケースもあるかと思います。ボスに負けたのに、間違って保存しちゃった気分って最悪ですが、gitの場合には問題ありません。

手段1: git reset そのままに使うと、「add」されたファイルが全てaddされてない状態になるのですが、ローカルの内容を全て捨てたい場合もあります(他の人とかぶりがありました!など)。

git reset --hard origin/<branch_name> [(branch_name_)を確認するために git branch を書いて、*がついてるのが現在のブランチ] 
注意:このやり方でローカルのものが無くなります。 十分注意してください。

手段2: もし、すでにプッシュされた、昔のものであれば、git revert <commit hash> で昔にあったコミットを戻すような新しいコミットを作成します。このやり方では何も無くなりませんが、実装がちょっとめんどいです。 例えば、今回のコミットをrevertしたい場合には git revert 0e7cfc6b8cac249f8fd2445c86660d6805045b9d を書きますと....

f:id:c-pattamada:20180705161159p:plain

あら...コミットが消えましたね。今回作成したファイルも消えました!

まとめ

今回Gitの基本コマンドについて書きました。init, status, add, push, commit, resetなどを使って見てください! 以外と説明が長くなってしまいました。そのため、全部一つに記事に打っ込むよりみつに分けることにしました!続きも楽しみにしてください!今度はLevel 2: branch, merge, fetch, pullなどについて書きますね!

IaC by Terraform ~DAY5: Terraform Commands (4)~

どうも,エンジニアのナカノです.

今月は梅雨の時期でしたね。洗濯物を外に干せないことが多く、悶々としておりました.

天気予報を見ると今週から天気が良いみたいなので、少しホッとしております.

さて,今回も前回の記事の内容の続きとなります.

前回はterraform.tfstateの管理/運用コマンド (1)に関する内容でした.

今回の内容は,terraform.tfstateの管理/運用コマンド (2)に関してです.

目 次
  • `terraform.tfstate`の管理/運用コマンド (2)
    • taint
    • untaint
    • refresh
    • workspace
      • list
      • select
      • new
      • delete
  • 最後に

terraform.tfstateの管理コマンド (2)

taint

Terraformを使っていると,applyの実行でエラーが出てしまって適当なリソースが想定とは異なる形で作成されることがしばしばあります.

そういった時は,まずはエラー箇所を修正し,次にそのリソースを作り直して想定通りの状態でデプロイしたい欲求に駆られるでしょう.

taintというコマンドはその様な時に役に立ちます.例えば,訳あって作成済みのリソースxxxxxxxxを作り直したいとします.

そのためにterraform taint xxxxxxxxを実行すると,terraform.tfstateに記載されているxxxxxxxxの項目taintedの値がfalseからtrueに変わります。

taintedの値がtrueになると,xxxxxxxxはまずTerraformによって削除され,次にxxxxxxxxが再作成されます.

こういった状況ではゴリ押しでapplyを実行しまくるのも一つの手ですが,taintコマンドを上手く使う方が得策かもしれません.

www.terraform.io

  

untaint

untaintコマンドは,文字から分かる様に,taintとは反対の挙動を起こすコマンドです.

まずはtaintの挙動を思い起してみましょう.このコマンド実行すれば,指定されたリソースがtaintedな状態になります.

一方,untaintを実行すると,指定されたリソースがuntaintedな状態であるとしてterraform.tfstateに記録されます.

taintedなリソースはTerraformにより再作成されるのですから,untaintedなリソースはそのままの状態で保持されます.

このことをterraform.tfstateの観点で言えば,taintはtaintedの値をtrueに変えるがuntaintはtaintedの値をfalseに変えます.

www.terraform.io

  

refresh

一般に,Terraformで管理されているリソースの情報はterraform.tfstateで管理されています.

しかし,Terraform以外の手段によってTerraformの管轄対象のリソースが更新された場合,`terraform.tfstate‘の内容は古いものとなります.

この様な状況では,applyの実行の際に思わぬ挙動が起きて痛い目を合うことがあります.そういう時こそrefreshコマンドの出番です.

このコマンドは,Terraformが管轄するリソースに合わせてterraform.tfstateの内容を更新してくれます.

例えば,何らかの問題が起こって,管理コンソールでTerraformに管理されているリソースの更新を行うことがあります.

そんな時にrefreshコマンドを実行すると,実態のリソースたちとterraform.tfstateの間に差分が生まれない様にすることが出来ます.

このコマンドは,問題が起きた時に威力を発揮することが多いので,覚えておくべきものかと思います.

www.terraform.io

  

workspace

workspaceを使うと,terraform.tfstateの切り替えを実現することが出来ます.このことをもう少し具体的に説明します.

初めはdefaultというworkspaceしかないのですが,新しく作成してworkspace1workspace2というworkspaceを作ったとします.

そして,workspace1workspace2の各々でリソースを作成すると,各々のworkspaceに応じた‘terraform.tfstate`が生成されます.

これらのファイルは,ローカルでは

  • ./terraform.tfstate.d/workspace1/terraform.tfstate
  • ./terraform.tfstate.d/workspace2/terraform.tfstate

の様に配置されます.一方で,バックエンド設定をしている場合でも殆ど同様な感じで各々のterraform.tfstateが格納されます.

この時,workspace毎のterraform.tfstateは互いに独立しており,リソース作成の状態の上書きは起こりません.

よって,このコマンドを使えば,リソース作成の状態を適切に管理/運用することが出来る様になります.

しかし,.tfファイルの内容はworkspaceでは切り替わらないため,現状では共通の設定をステージ毎に管理する場合に役立つという感じでしょうか.

さて,以下はworkspaceのサブコマンドlistselectnewdeleteの説明となります.

  

list

このサブコマンドは,存在する全てのworkspaceをリストします.また,現在のworkspaceには*が付いています.

例えば,存在するworkspaceがdefalutworkspace1workspace2であり,現在のworkspaceがworkspace1であるならば,listの実行結果は下記の様になります.

$ terraform workspace list
  default
* workspace1
  workspace2

www.terraform.io

  

select

現在のworkspaceから別のworkspaceに切り替えたい時に,このサブコマンドを使用します.

例えば,存在するworkspaceがdefalutworkspace1workspace2であり,現在のworkspaceがworkspace1であるとします.

この時に,現在のworkspaceからworkspace2に切り替えたい時は,以下の様に実行します.

$ terraform workspace select workspace2
Switched to workspace "workspace2".

www.terraform.io

  

new

これを実行すると,新しいworkspaceを作成することが出来ます.例えば,new_workspaceというworkspaceを作成する場合は下記を実行します.

$ terraform workspace new new_workspace
Created and switched to workspace "new_workspace"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

www.terraform.io

  

delete

workspaceを削除する場合は,このサブコマンドを利用します.ただし,以下の点に注意する必要があります.

  • 削除対象のworkspaceがそもそも存在する
  • 削除対象のworkspaceに対応するterraform.tfstateの内容が空である
  • 削除対象のworkspaceは現在のworkspaceではない

これらの点を守った上で,例えばworkspace_to_deleteを削除したい場合は以下を実行します.

$ terraform workspace delete workspace_to_delete
Deleted workspace "workspace_to_delete".

もしterraform.tfstrateの内容が空ではない場合にworkspace_to_deleteを削除したいならば,-forceオプションを使えばよいです.

ただし,このオプション付きでdeleteを実行すると,workspace_to_deleteの場合でTerraformにより作成されたリソースはTerraformの管理外となってしまいます.

www.terraform.io

  

最後に

今回はterraform.tfstateの管理/運用コマンド (2)を紹介させて頂きました.

前回と同様で,使い所を適切に考えれば割と役に立つコマンドばかりです.

直近はTerraformコマンドを紹介してきましたが,コマンドの紹介は今回で終わりです.

次回からは,また別のトピックを扱おうかと思います.

それでは,今回はこの辺りで筆を置かせて頂きます.

次回に乞うご期待下さい.

Deploying an Angular app to GitHub Pages

Being a programmer I can't stop myself greeting you with Hello World so

f:id:vivek081166:20180620155225p:plain

Do you want to tell the world about all the great things you are building?
Well, GitHub Pages might help you to do that.

In this blog, I would like to share the process of bringing your Angular app from local to the internet

http://localhost:4200 ==> https://<username>.github.io/<repository-name>

Let's walk through the following steps to deploy our test-app on GitHub Pages

f:id:vivek081166:20180620142950p:plain

So let's get started...

Step 1 : Build your Angular app

With Angular CLI, using the following command; build your Angular app

ng build

After building your app all we need is the contents of the dist folder

f:id:vivek081166:20180620130056p:plain

Step 2 : Create a repository

For the purpose of demoing your app, it is good idea to have a separate repository.
So, let's create one for our test-app and name it as test-app-demo

f:id:vivek081166:20180620143918p:plain

Step 3 : Initialize repository for file upload

The simplest way to initialize files upload via GitHub will be to add .gitignore to your repository.

f:id:vivek081166:20180620155443p:plain

and commit your file

f:id:vivek081166:20180620155529p:plain

Step 4 : Upload your build files

Having done the previous step you can now upload the build files via GitHub

Click the Upload Files button on master branch

f:id:vivek081166:20180620155853p:plain

Drag your build files here or simply click choose your files

f:id:vivek081166:20180620155938p:plain

Go to the project source folder and choose dist folder

f:id:vivek081166:20180620160410p:plain

f:id:vivek081166:20180620160656p:plain

Select all the build content and upload

f:id:vivek081166:20180620161209p:plain

Commit your uploaded file to mater-branch

f:id:vivek081166:20180620161629p:plain

Step 5 : Update the base URL

Since we uploaded build files into the separate repository, we need to update the base URL to let angular know about the root directory

Update index.html file

f:id:vivek081166:20180620162455p:plain

Change base tag from
<base href="/">
to the name of the repository
<base href="/test-app-demo/">

f:id:vivek081166:20180620162627p:plain

f:id:vivek081166:20180620162704p:plain

Step 6 : Set up the GitHub Pages

This is the final step and we are almost done!

Navigate to the Settings tab of the repository for setting up a GitHub Page for our Angular app

Settings option is only visible to the owner of the repository

f:id:vivek081166:20180620162851p:plain

scroll down a little and you are almost there...

f:id:vivek081166:20180620163319p:plain

f:id:vivek081166:20180620163456p:plain

Select master-branch as the source of GitHub Pages

f:id:vivek081166:20180620163835p:plain

Save the changes and you are done!!

f:id:vivek081166:20180620163958p:plain

しばらくお待ちください。。。
Wait while GitHub sets up everything for you and holla!! your app is live

f:id:vivek081166:20180620164139p:plain

Your app will be live on the web address shown in the GitHub Pages' section. https://<username>.github.io/<repository-name>
Yes!! we did it.

f:id:vivek081166:20180620164542p:plain

Thank you very much for reading all to the end.

I'll be coming back soon with another such topic. Till then
Happy Learning :)

VPCピアリングして別AWSアカウントのセキュリティグループを使う

こんにちは
Webの開発者だけどインフラも知りたいお年頃のイイオです

やりたいこと

  • とあるEC2たちを別AWSアカウントに移し、そっち側からssh接続したい
  • このEC2たちは生まれては消えるさだめなので、セキュリティグループのソースにIPアドレスとかいちいち設定できない
  • というわけでセキュリティグループのソースに別AWSアカウントのセキュリティグループ指定したい

f:id:y-iio:20180614181210p:plain

手順

いいからVPCピアリングだ!

docs.aws.amazon.com

0. 前提

アカウントA

  • VPC CIDR 10.0.0.0/16
  • サブネット 10.0.10.0/24, 10.0.20.0/24

アカウントB

  • VPC CIDR 172.30.0.0/16
  • サブネット 172.30.10.0/24, 172.30.20.0/2

VPCのCIDRが被っているとピアリングできないよ
最初てきとうにVPC切ってしまってたいへん後悔したよ
このあたりをちゃんとべんきょうしてからやるべきだったよ

dev.classmethod.jp

リージョンも同じじゃないといろんな制限をくらうよ

1. アカウントAでVPCピアリングの申請

VPC > ピアリング接続 > ピアリング接続の作成

f:id:y-iio:20180614182341p:plain

AWSのアカウントIDはアカウント設定画面からみれる

2. アカウントBでVPCピアリングの許可

VPC > ピアリング接続

f:id:y-iio:20180614182806p:plain

f:id:y-iio:20180614182910p:plain

f:id:y-iio:20180614182932p:plain

3. アカウントBでルートテーブルを指定

VPC > ルートテーブル

送信先は相手のVPC全体にもできるし、もっと小さくサブネットとかIP単位にも絞れる、ゴイス〜

f:id:y-iio:20180614183259p:plain

4. アカウントAでルートテーブルを指定

VPC > ルートテーブル

こちらでもルートを追加、これ忘れてて詰まってたことは内緒

f:id:y-iio:20180614183316p:plain

5. アカウントAのセキュリティグループの設定

EC2 > セキュリティグループ

向こうのアカウントのセキュリティグループを入力できるようになっている!

f:id:y-iio:20180614184215p:plain

アカウントBのサーバーから接続確認だ〜〜〜

ssh ec2-user@ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com(パブリックDNS)

沈黙

ssh ec2-user@54.xxx.xxx.xxx(パブリックIP)

繋がらないよ〜〜〜〜

はい

qiita.com

www.skyarch.net

セキュリティグループでセキュリティグループを許可する(セキュリティグループのソースにセキュリティグループ指定する)方法は、プライベートネットワーク内でのみ有効…!!!

VPC Aの中でディグる

dig ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.55.amzn1 <<>> ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37867
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. IN A

;; ANSWER SECTION:
ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. 20 IN A 10.0.10.123

VPC Aの外でディグる

dig ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

; <<>> DiG 9.10.6 <<>> ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8580
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. IN A

;; ANSWER SECTION:
ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. 589434 IN A 54.xxx.xxx.xxx

ピアリングしたVPC Bの中でディグる

dig ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34546
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. IN A

;; ANSWER SECTION:
ec2-54-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com. 60 IN A 54.xxx.xxx.xxx

今まで完全に同じVPC内でしか使ったことなかったから
接続先にパブリックDNSやパブリックIP指定しても、プライペートIPとして解決されていてたけど
VPCピアリングだとその解決できないから、プライペートIPを直指定しないとダメだったんだね、ハム太郎!へけ!

というわけで
アカウントBのサーバーから再度接続確認だ〜〜〜

ssh ec2-user@10.0.10.123

これでよろし〜〜〜なんだか全てにおいて己の知識不足って感じだ!へけ!

Play Frameworkで画像・アセットをユーザーに届ける

Play Frameworkが非常に便利ですので、Apiサーバーとして使ってます。この度、自分のサーバーに持ってる画像などなアセットをそのまま返したい場合(例え、アンギュラーのフロントで表示したいなど)にどうすればいいかを説明します。 それぞれの状況に合わせて、二つの方法を説明します。

とりあえず、…image.jpgに画像を出したい!

つまり、誰でもそのurlにいくとその画像がみれるような場合です。 この方法は割と簡単です。

conf/routesのファイルに

GET     /assets/*file               controllers.Assets.versioned(path="/public/images/", file)

これで、/public/images/のディレクトリーをベースにして、「ファイル」というパス変数に当てはまるファイルをそのまま出せます。

www.example.com/assets/cats/myCat.png/public/images/cats/myCat.pngにあるファイルを出します。(なかったら、404エラーが出ます)

ちなみに、Idea使ってる方々はこのようなdeprecatedという知らせを見ることもあると思いますが、Ideaのバグらしいです。(link: https://github.com/playframework/playframework/issues/7521)

このように、Angularのクライアントで、<img src="www.example.com/assets/cats/myCat.png" />

このイメージのアクセスを制限したいですが…

アクセス制限、何かのトラッキング・編集などのことがやりたい場合もあると思います。その場合は直接routesから返したらできなくなるかと思いますが、別な方法もあります!

では、routesにこう追加しましょう

 GET       /getImage                controllers.HomeController.getImage

getImageの中でバリデーションやアナリティクスなど、でもできます。 欲しいイメージや、アクセス権限の情報がGET変数で送られてるとしますと、FormFactoryとDynamicForm を使って、コントローラーからその変数のアクセスができます。

public class MyController extends Controller {

@Inject
private FormFactory formFactory;

public Result getImage() {
...
}

}

まずは、FormFactoryをInjectionで使えるようになる。そして、getImageの書き方は...

DynamicForm dynamicForm = formFactory.form.bindFromRequest();
// 適切なログインチェックを行う
if(!isLoggedIn(dynamicForm)) {
    // もしユーザーがログインしてない場合には、対応する。
        return ....; //アクセス制限する。
}

まずは、バリデーションができる、そしてアクセス制限したい場合にはふさわしい風に行える。 その後、ユーザーが頼んでるイメージの正式なパスを作成し、Resultを返す。

// ユーザーが送ってるファイル名的なパスと実際のサーバーのパスが違うのはず。
String path = getRealImagePath(dynamicForm.get("")); 
java.nio.file.Path deliveryPath = Paths.get(path);
// これはPlayFrameworkに存在する、ファイルをだす方法:
return new Result(
          new ResponseHeader(200, Collections.emptyMap()),
          new HttpEntity.Streamed(FileIO.fromPath(deliveryPath), Optional.empty(), Optional.of("image/png"))
);

こんな風に、画像や他のアセットのアクセスを制限することもできます。