- 投稿日:2019-10-26T23:16:09+09:00
react-dropzone、Express、Firebaseを使った画像のアップロード
components/FileUpload.tsconst onDrop = (acceptedFiles: File[]) => { console.log(formData) } return ( <div> <DropZone onDrop={onDrop}> {({getRootProps, isDragActive}) => ( <div {...getRootProps()}> {isDragActive ? "Drop it like it's hot!" : 'Drag a file to upload!'} </div> )} </DropZone> </div> )react-dropzoneを使ってこんな感じに書いて、描画された部分に画像をドロップしてみると
lastModified: 1571463132902 lastModifiedDate: Sat Oct 19 2019 14:32:12 GMT+0900 (日本標準時) {} name: "hoge.PNG" path: "hoge.PNG" size: 353348 type: "image/png" webkitRelativePath: ""こんな感じのFileっていう型の配列がもらえる。
んじゃあこのデータ配列そのままサーバ側にぶん投げて、サーバ側でfirebase storageにpath指定してあげりゃあ画像のアップロード実装できんじゃん!
って思ってたんだけど、見てわかる通りpathがfullpath(?)になってない。どうしよう...最終的に、サーバ側に一時的に画像を保存して、そこで生成されたpathをfirebase側に指定してあげたらうまく行った。
そのために、まずはreact-dropzoneから受け取ったFile配列をFormDataとやらに変換して、それをPOSTデータとしてぶん投げた。
components/FileUpload.tsconst onDrop = (acceptedFiles: File[]) => { const formData = new FormData(); acceptedFiles.forEach(file => { formData.append('Files', file) }) dispatch(postFiles.request(formData)) }参考にさせていただいたサイト様様 → https://qiita.com/uryyyyyyy/items/9954205a620b6f3c1f24
んで、これをExpress側で受け取るんだけど、このデータはmultipart/form-dataというものらしく、普通にやったらうまく受け取れなかった。なんやそれ。知らんがな。
app.tsimport multer from 'multer'; const upload = multer({ dest: './uploads/' }); app.post('/files', upload.fields([ { name: 'Files' } ]), postStorageController);controller/postStorageController.tsexport function postStorageController(req: Request, res: Response, next: NextFunction) { const files: Express.Multer.File[] = req.files['Files'];こういう風に書いてあげると、filesの部分で以下のような感じで値がもらえる
[Object: null prototype] { Files: [ { fieldname: 'Files', originalname: 'hoge.PNG', encoding: '7bit', mimetype: 'image/png', destination: 'uploads/', filename: 'd18eb9674f13a81898e7c25bb0c3bda6', path: 'uploads/d18eb9674f13a81898e7c25bb0c3bda6', size: 353348 } ] }参考にさせていただいたサイト様様 → https://qiita.com/uryyyyyyy/items/9954205a620b6f3c1f24
(さっきと同じ記事。圧倒的感謝)あとは、Google先生の解説を見ながらfirebase storageにあげれば終わり!
controller/postStorageController.tsexport function postStorageController(req: Request, res: Response, next: NextFunction) { const files: Express.Multer.File[] = req.files['Files']; files.forEach(fileInfo => { const uploadFilePath = `files/${fileInfo.originalname}` bucket.upload(fileInfo.path, { destination: uploadFilePath, contentType: fileInfo.mimetype }, error => { if (error) { console.log(`failed storage post ${fileInfo.originalname}`); console.log(error.message); return res.sendStatus(404); } else { console.log(`success storage post ${fileInfo.originalname}`); return res.sendStatus(200); } } }↓↓↓今回書いたソースコード
(フロント)
https://github.com/ShotaroOkada/fileupload_react_client(サーバ)
https://github.com/ShotaroOkada/fileupload_express_api
- 投稿日:2019-10-26T23:16:09+09:00
react-dropzone、Express、firebaseを使った画像のアップロード
components/FileUpload.tsconst onDrop = (acceptedFiles: File[]) => { console.log(formData) } return ( <div> <DropZone onDrop={onDrop}> {({getRootProps, isDragActive}) => ( <div {...getRootProps()}> {isDragActive ? "Drop it like it's hot!" : 'Drag a file to upload!'} </div> )} </DropZone> </div> )react-dropzoneを使ってこんな感じに書いて、描画された部分に画像をドロップしてみると
lastModified: 1571463132902 lastModifiedDate: Sat Oct 19 2019 14:32:12 GMT+0900 (日本標準時) {} name: "hoge.PNG" path: "hoge.PNG" size: 353348 type: "image/png" webkitRelativePath: ""こんな感じのFileっていう型の配列がもらえる。
んじゃあこのデータ配列そのままサーバ側にぶん投げて、サーバ側でfirebase storageにpath指定してあげりゃあ画像のアップロード実装できんじゃん!
って思ってたんだけど、見てわかる通りpathがfullpath(?)になってない。どうしよう...最終的に、サーバ側に一時的に画像を保存して、そこで生成されたpathをfirebase側に指定してあげたらうまく行った。
そのために、まずはreact-dropzoneから受け取ったFile配列をFormDataとやらに変換して、それをPOSTデータとしてぶん投げた。
components/FileUpload.tsconst onDrop = (acceptedFiles: File[]) => { const formData = new FormData(); acceptedFiles.forEach(file => { formData.append('Files', file) }) dispatch(postFiles.request(formData)) }参考にさせていただいたサイト様様 → https://qiita.com/uryyyyyyy/items/9954205a620b6f3c1f24
んで、これをExpress側で受け取るんだけど、このデータはmultipart/form-dataというものらしく、普通にやったらうまく受け取れなかった。なんやそれ。知らんがな。
app.tsimport multer from 'multer'; const upload = multer({ dest: './uploads/' }); app.post('/files', upload.fields([ { name: 'Files' } ]), postStorageController);controller/postStorageController.tsexport function postStorageController(req: Request, res: Response, next: NextFunction) { const files: Express.Multer.File[] = req.files['Files'];こういう風に書いてあげると、filesの部分で以下のような感じで値がもらえる
[Object: null prototype] { Files: [ { fieldname: 'Files', originalname: 'hoge.PNG', encoding: '7bit', mimetype: 'image/png', destination: 'uploads/', filename: 'd18eb9674f13a81898e7c25bb0c3bda6', path: 'uploads/d18eb9674f13a81898e7c25bb0c3bda6', size: 353348 } ] }参考にさせていただいたサイト様様 → https://qiita.com/uryyyyyyy/items/9954205a620b6f3c1f24
(さっきと同じ記事。圧倒的感謝)あとは、Google先生の解説を見ながらfirebase storageにあげれば終わり!
controller/postStorageController.tsexport function postStorageController(req: Request, res: Response, next: NextFunction) { const files: Express.Multer.File[] = req.files['Files']; files.forEach(fileInfo => { const uploadFilePath = `files/${fileInfo.originalname}` bucket.upload(fileInfo.path, { destination: uploadFilePath, contentType: fileInfo.mimetype }, error => { if (error) { console.log(`failed storage post ${fileInfo.originalname}`); console.log(error.message); return res.sendStatus(404); } else { console.log(`success storage post ${fileInfo.originalname}`); return res.sendStatus(200); } } }↓↓↓今回書いたソースコード
(フロント)
https://github.com/ShotaroOkada/fileupload_react_client(サーバ)
https://github.com/ShotaroOkada/fileupload_express_api
- 投稿日:2019-10-26T15:21:10+09:00
JSON形式のAPIレスポンス構造をNode.jsのREPLで理解する
この記事の対象者
JSON形式のレスポンスをJavaSciptで処理する際に、
- どういう書き方で書けば欲しい情報が取り出せるのか知りたい
- JSONレスポンスが大きすぎて構造がよくわからない
- APIリクエスト制限が厳しくて何度もリクエストを投げられない
- 参考記事には結果のコードしか載ってなくて初見のAPIをどうやればいいのか
ということがある場合。JSON形式のAPIの扱いに慣れていない人向けです。
どうやって理解するのか
一旦APIレスポンスをJSONファイルとして出力した後にNode.jsのREPLで読み込んで、対話形式で解析します。
一度JSONファイルとして書き込むことで何度もAPIリクエストを投げる必要がないのでAPIリクエスト制限に引っかかる心配がありません。やり方
例としてGitHub APIにて
reactで検索した時の結果をAPIで取得します。
https://developer.github.com/v3/search/#search-repositoriesターミナルで下記のコマンドを入力します。
JSON形式のデータ整形にjqというツールを使っているので無い場合はコマンドbrew install jqで入れてください。$ curl https://api.github.com/search/repositories?q=react | jq .ターミナルを埋め尽くすほどのAPIレスポンスが帰ってきました。
この状態だと何が何だか分からないので一回JSONファイルに出力します。$ curl https://api.github.com/search/repositories?q=react | jq . > result.jsonresult.json{ "total_count": 1054700, "incomplete_results": false, "items": [ { "id": 10270250, "node_id": "MDEwOlJlcG9zaXRvcnkxMDI3MDI1MA==", "name": "react", "full_name": "facebook/react", "private": false, "owner": { "login": "facebook", "id": 69631, ... } ... } ] }ざっくり構造が見えてきました。まずトップ階層に検索件数が表示され、具体的な中身は
itemsの中にObject[]として格納されているので、items[n]またはmap関数で取り出せそうだなという目安がつきます。これからNode.jsのREPLでデータを取り出してみます。
$ node Welcome to Node.js v12.3.0. Type ".help" for more information. > const data = require("./result") > data ... // Object形式で出力JSONファイルは
requireで読み込むことでJavaScriptのObjectとして読み込まれます。Object形式なので下記のように入力するとデータを取り出すことができます。
> data.total_count 1054700ここで
itemsの中からfull_nameのみ取り出してみます。> data.items.map(item => item.full_name) [ 'facebook/react', 'duxianwei520/react', 'reactphp/react', ... 'reduxjs/react-redux' ]条件を絞ってみます。
獲得スターが30k以上のリポジトリのfull_nameのみ取り出してみます。> data.items.filter(item => item.stargazers_count >= 30000).map(item => item.full_name) [ 'facebook/react', 'facebook/react-native', 'ReactTraining/react-router', 'zeit/next.js', 'facebook/create-react-app', 'enaqx/awesome-react' ]
data.items.filter(item => item.stargazers_count >= 30000)では条件に合致するObject[]が帰ってくるのでそれをmap関数で取り出しました。これを実際のAPIレスポンスを扱うスクリプトに適応するとこんな感じです。
const axios = require("axios"); const http = axios.create({ baseURL: "https://api.github.com" }); async function main() { try { const response = await http.get("/search/repositories", { params: { q: "react" } }); const data = await response.data const result = await data.items.filter(item => item.stargazers_count >= 30000) console.log(`30000 over stars Repository search by 'react'`); result.map(item => console.log(item.full_name)) } catch (error) { console.log(error) } } main();$ node index.js 30000 over stars Repository search by 'react' facebook/react facebook/react-native ReactTraining/react-router zeit/next.js facebook/create-react-app enaqx/awesome-reactまとめ
これで初見のJSON形式のAPIでも対応できると思います。
REPLはレスポンス構造を解析するだけでなく構文のチェックも簡単にできるのでド忘れしやすい僕は多用してます。
- 投稿日:2019-10-26T01:35:49+09:00
React+Firebase+material-UIでWebアプリを作成する①
初投稿です。
身内用にReact+firebaseの環境作成方法を共有するために投稿してみました。要するに、
Node.jsでサーバーを動かせるようにして、
Reactでフロントの動きを作って、
material-UIで画面をお洒落に仕上げて、
firebaseのデータべースや、認証機能サービスなどを使い、
世界中に公開できるようにしましょうということです。実行環境はwindows10です。
①まず下記URLからnode.jsのインストーラーをダウンロードしましょう。
今回は左の推奨版でOKです。
https://nodejs.org/ja/インストーラーを実行したら、ひとまず全てデフォルトの設定でインストールを完了させましょう。
コマンドプロンプトを開いて、node -v
でバージョンが表示されていればインストールは成功です。
次にそのままコマンドで下記コマンドを実行します。
npx create-react-app my-app
(my-appの部分は任意のディレクトリ名でOKです)
happy hackingができれば完了です!するとReactの実行環境が作成されます。
そのまま
cd my-app
npm start
で下記画面が表示されればReactの導入も成功です。
※パッケージマネージャーとしてyarnを導入しておくと、npmよりも早く、エラーも発生しづらいので色々便利です。
npm install -g yarn
コマンドでyarnを導入しておきましょう。
②次にFirebaseで自分のプロジェクト作成します。
下記のリンクで使ってみるを選択します。
https://firebase.google.com/?hl=jaプロジェクト名はなんでもOKです。
アナリティクスはひとまず不要で大丈夫です。
そうすると下記のメイン画面に入ります。ここから3つのことをやっておきましょう。
1.中央にある</>マークを選ぶとwebアプリの登録に進めます。適当な名前をつけて、登録しましょう。
2.Databaseを選択してcloudfirestoreを使えるようにしておきましょう。こちらも適当な名前で。
3.任意の名前で作成したReactのディレクトリの中の「src」ディレクトリの中に「plugins」ディレクトリを作成し、その中に「firebase.js」というjavascriptのファイルを作成します。
「firebase.js」にProject Overviewの横にある歯車(設定)アイコンをクリックし、「プロジェクトの設定」の全般の一番下にあるコードをコピーしてapiKeyからappIdを丸ごと貼り付けます。【任意のReactディレクトリ】⇒【srcディレクトリ】⇒【pluginsディレクトリ】⇒【firebase.js】※このファイルに下記コードをコピーして保存
firebase.jsimport firebase from 'firebase'; const config = { var firebaseConfig = { //ここから apiKey: "****************************", authDomain: "****************************", databaseURL: "****************************", projectId: "****************************", storageBucket: "****************************", messagingSenderId: "****************************", appId: "****************************", //ここまでコピーして書き換え }; const firebaseApp = firebase.initializeApp(config); export const firestore = firebaseApp.firestore();そしたらsrcディレクトリの中のApp.jsというファイルでインポートさせます。
後々、使う認証機能も一緒にインポートしておきましょう。App.jsimport firebase from "firebase/app" import "firebase/auth" import "firebase/firestore" import { firestore } from './plugins/firebase';これでfirestoreというデータベースのサービスを利用することができます。
※注意
firebaseの料金プランは無料プランのままにしておいて下さい。
誤って従量課金プランに変えてしまうと、
とんでもない請求がいくかもしれません…③FirebaseとReactを接続する。
FirebaseCLIを使うことで、ローカルからfirebaseプロジェクト更新できるようにします。
下記コマンドを入力しましょう。↓
npm install -g firebase-tools
もしくは
yarn add -g firebase -tools
CLIが導入できたら、
↓firebase login
↓
firebase init
とコマンドを続けましょう。
そうすると選択項目が出てきます。ここはキーボードの方向キーで指定して、スペースキーで選択、enterで決定できます。
下記の順に選びましょう。Hosting
↓
Use an existing project (先ほど名前を付けたFirebaseのアプリの名前を選択)
↓
What do you want to use as your public directory?(ディレクトリを選択します。buildと入力しておきましょう)
あとはすべてyesで問題ないです。
終了したら
npm run build
firebase deploy
(もしくはyarn build && firebase deploy)
deployが完了したら表示されたURLにアクセスできます
あとは更新するたびに、buildとfirebase deployを行えば更新することができます。
あとはついでにフロント用にmaterial-UIをインポートしておきましょう。
https://material-ui.com/getting-started/installation/
1.上記のリンクの上部にあるコマンドでインストール
npm install @material-ui/core
もしくは
yarn add @material-ui/core
2.任意の名前で作成したReactディレクトリの「public」の中の「index.html」のhead内に、RobotoFontを読み込むコードを張り付けます。
3.必要なライブラリだけimportとしていきます。あとはコードで囲えば使用できます。
App.js//例 import Button from '@material-ui/core/Button'; import TextField from '@material-ui/core/TextField'; <TextField value="入力"/> <Button>登録</Button>これで準備はだいたいOKです。
続きはまた次回に投稿いたします。
- 投稿日:2019-10-26T01:35:49+09:00
Node.js+React+Firebase+Material-UIでWebアプリを作成する①
初投稿です。
React+Firebase+Material-UIの環境作成方法に関する記事です。実行環境はwindows10です。
①Reactを使うにはNode.jsが必要です。
まず下記URLからNode.jsのインストーラーをダウンロードしましょう。
今回は左の推奨版でOKです。
https://nodejs.org/ja/インストーラーを実行したら、ひとまず全てデフォルトの設定でインストールを完了させましょう。
コマンドプロンプトを開いて、node -v
でバージョンが表示されていればインストールは成功です。
次にそのままコマンドで下記コマンドを実行します。
npx create-react-app my-app
(my-appの部分は任意のディレクトリ名でOKです)
happy hackingができれば完了です!するとReactの実行環境が作成されます。
そのまま
cd my-app
npm start
で下記画面が表示されればReactの導入も成功です。
※パッケージマネージャーとしてyarnを導入しておくと、npmよりも早く、エラーも発生しづらいので色々便利です。
npm install -g yarn
コマンドでyarnを導入しておきましょう。
②次にFirebaseで自分のプロジェクト作成します。
下記のリンクで使ってみるを選択します。
https://firebase.google.com/?hl=jaプロジェクト名はなんでもOKです。
アナリティクスはひとまず不要で大丈夫です。
そうすると下記のメイン画面に入ります。ここから3つのことをやっておきましょう。
1.中央にある</>マークを選ぶとwebアプリの登録に進めます。適当な名前をつけて、登録しましょう。
2.Databaseを選択してcloudfirestoreを使えるようにしておきましょう。こちらも適当な名前で。モードはテストモード。ロケーションはとりあえずasia-northeast1で。3.任意の名前で作成したReactのディレクトリの中の「src」ディレクトリの中に「plugins」ディレクトリを作成し、その中に「firebase.js」というjavascriptのファイルを作成します。
「firebase.js」にProject Overviewの横にある歯車(設定)アイコンをクリックし、「プロジェクトの設定」の全般の一番下にあるコードをコピーしてapiKeyからappIdを丸ごと貼り付けます。【任意のReactディレクトリ】⇒【srcディレクトリ】⇒【pluginsディレクトリ】⇒【firebase.js】※このファイルに下記コードをコピーして保存
firebase.jsimport firebase from 'firebase'; const config = { var firebaseConfig = { //ここから apiKey: "****************************", authDomain: "****************************", databaseURL: "****************************", projectId: "****************************", storageBucket: "****************************", messagingSenderId: "****************************", appId: "****************************", //ここまでコピーして書き換え }; const firebaseApp = firebase.initializeApp(config); export const firestore = firebaseApp.firestore();そしたらsrcディレクトリの中のApp.jsというファイルでインポートさせます。
後々、使う認証機能も一緒にインポートしておきましょう。App.jsimport firebase from "firebase/app" import "firebase/auth" import "firebase/firestore" import { firestore } from './plugins/firebase';これでfirestoreというデータベースのサービスを利用することができます。
※注意
firebaseの料金プランは無料プランのままにしておいて下さい。
誤って従量課金プランに変えてしまうと、
とんでもない請求がいくかもしれません…③FirebaseとReactを接続する。
FirebaseCLIを使うことで、ローカルからfirebaseプロジェクト更新できるようにします。
下記コマンドを入力しましょう。↓
npm install -g firebase-tools
もしくは
yarn add -g firebase -tools
CLIが導入できたら、
↓firebase login
↓
firebase init
とコマンドを続けましょう。
そうすると選択項目が出てきます。ここはキーボードの方向キーで指定して、スペースキーで選択、enterで決定できます。
下記の順に選びましょう。Hosting
↓
Use an existing project (先ほど名前を付けたFirebaseのアプリの名前を選択)
↓
What do you want to use as your public directory?(ディレクトリを選択します。buildと入力しておきましょう)
あとはyesで問題ないです。
そうすると「build」というディレクトリが生成されているので、その中のindex.htmlをごっそり書き換えましょう。
index.html<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"/> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/> <meta name="viewport" content="width=device-width,initial-scale=1"/> <meta name="theme-color" content="#000000"/> <meta name="description" content="Test"/> <title>React Sample</title> </head> <body> <div id="root"> </div> </body> </html>App.jsのreturn()の記述が、最終的にindex.htmlのid ="root"に渡ってきます。
App.jsも書き換えてみましょう。App.jsimport React from 'react'; import './App.css'; import firebase from "firebase/app" import "firebase/auth" import "firebase/firestore" import { firestore } from './plugins/firebase'; class App extends React.Component{ constructor(props){ super(props); } render(){ return( <h1>Hello React</h1> ); } } export default App;完了したら
npm run build
firebase deploy
(もしくはyarn build && firebase deploy)
deployが完了したら表示されたURLにアクセスできます.
あとは更新するたびに、buildとfirebase deployを行えば更新することができます。
④最後にmaterial-UIをインポートしておきましょう。
https://material-ui.com/getting-started/installation/
1.上記のリンクの上部にあるコマンドでインストール
npm install @material-ui/core
もしくは
yarn add @material-ui/core
2.任意の名前で作成したReactディレクトリの「build」の中の「index.html」のhead内に、RobotoFontを読み込むコードを張り付けます。
※先ほどApp.jsを書き換えた際、じつはもう記載してあります。3.必要なライブラリだけimportとしていきます。あとはコードで囲えば使用できます。
App.js//例 import Button from '@material-ui/core/Button'; import TextField from '@material-ui/core/TextField'; <TextField value="入力"/> <Button>登録</Button>これで準備はだいたいOKです。
続きはまた次回に投稿いたします。
- 投稿日:2019-10-26T01:35:49+09:00
React+FirebaseでWebアプリを作成する①
※この記事は編集中です。
初投稿です。
身内用にReact+Firebaseの環境の作成方法を共有するための投稿です。実行環境はwindows10のものです。
①まず下記URLからnode.jsのインストーラーをダウンロードしましょう。
今回は左の推奨版でOKです。
https://nodejs.org/ja/インストーラーを実行したら、ひとまず全てデフォルトの設定でインストールを完了させましょう。
コマンドプロンプトを開いて、code - node -v
↑が実行できればインストールは成功です。
次にそのままコマンドで下記コマンドを実行します。
npx create-react-app my-app
(my-appの部分は任意のディレクトリ名でOKです)
するとReactの実行環境が作成されます。
そのまま
cd my-app
npm start
で下記画面が表示されればReactの導入も成功です。
※パッケージマネージャーとしてyarnを導入しておくと、npmよりも早く、エラーも発生しづらいので後々便利です。
npm install -g yarn
コマンドで導入しておきましょう。
②次にFirebaseで自分のプロジェクト作成します。
下記のリンクで使ってみるを選択します。
https://firebase.google.com/?hl=jaプロジェクト名はなんでもOKです。
アナリティクスはひとまず有効にしないで大丈夫です。プロジェクトが作成されたら</>マークを選ぶとwebアプリの登録に進めます。
こちらも適当な名前をつけて、登録しましょう。
③FirebaseとReactを接続する。
FirebaseCLIを使うことで、ローカルからfirebaseプロジェクト更新できるようにします。
下記コマンドを入力しましょう。↓
npm install -g firebase-tools
もしくは ####yarn add -g firebase -tools
↓
firebase login
↓
firebase init
↓
- 投稿日:2019-10-26T00:29:27+09:00
インフラ自動テストツール ServerSpec 個人メモ
Ansibleを使用し、Node.jsのインストールを行なった以下記事の続きです。
ServerSpecはサーバテストを自動化することができるフレームワークです。
今回は、前回の記事でインストールしたNode.jsが正常に入っているかどうかServerSpecを使用し、確認したいと思います。
構成の確認
前回に引き続き、MacOSに仮想マシンを二つ立てている構成です。
- Vagrantfile
Vagrant.configure(2) do |config| config.vm.define "ConfigurationManagementServer" do |node| node.vm.box = "bento/ubuntu-18.04" node.vm.hostname = "ConfigurationManagementServer" node.vm.network :private_network, ip:"192.168.7.7" node.vm.provider "virtualbox" do |vb| vb.customize ["modifyvm", :id, "--memory", "1024"] end node.vm.provider "virtualbox" do |vb| vb.gui = false end end config.vm.define "AnsibleClient" do |node| node.vm.box = "bento/ubuntu-18.04" node.vm.hostname = "AnsibleClient" node.vm.network :private_network, ip:"192.168.8.8" node.vm.provider "virtualbox" do |vb| vb.customize ["modifyvm", :id, "--memory", "1024"] end node.vm.provider "virtualbox" do |vb| vb.gui = false end end end192.168.8.8が割り当てられている
AnsibleClientには既にNode.jsがインストールされています。$ vagrant ssh AnsibleClient vagrant@AnsibleClient:~$ node -v v10.17.0上記では、手動でコマンドを打ちversionを確認しましたが、もう一つの仮想マシンからServerSpecを使用しテストを行います。
ServerSpecインストール・ファイルの編集
AnsibleClient環境から抜け、ConfigurationManagementServer環境に入ります。$ vagrant ssh ConfigurationManagementServer vagrant@ConfigurationManagementServer:~$Rubyのインストールを行います。
今回はrbenvなどは使用せず、aptでインストールします。vagrant@ConfigurationManagementServer:~$ sudo apt-get install ruby vagrant@ConfigurationManagementServer:~$ ruby --version ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]必要なライブラリをインストールします。
vagrant@ConfigurationManagementServer:~$ sudo gem install serverspec rakeファイル群を作成します。
target host nameでは、テストを行う対象のIPアドレスを指定しますが、ここで入力された値がそのままディレクトリ名になるみたいです。vagrant@ConfigurationManagementServer:~$ serverspec-init Select OS type: 1) UN*X 2) Windows Select number: 1 Select a backend type: 1) SSH 2) Exec (local) Select number: 1 Vagrant instance y/n: n Input target host name: 192.168.8.8 + spec/ + spec/192.168.8.8/ + spec/192.168.8.8/sample_spec.rb + spec/spec_helper.rb + Rakefile + .rspecテスト項目を記述するファイルは
spec/192.168.8.8/sample_spec.rbです。
ファイルを以下のように編集します。
node -vというコマンドを実行し、特定のバージョンがインストールされているか確認するテスト項目です。spec/192.168.8.8/sample_spec.rbrequire 'spec_helper' describe command('node -v') do its(:stdout) { should match /v10.17.0/ } endファイル編集完了後、
Rakefileがあるディレクトリで以下コマンドを実行します。
パスワードを聞かれるので、接続先のパスワードを入力します。今回はvagrantです。vagrant@ConfigurationManagementServer:~$ rake vagrant@192.168.8.8's password: Command "node -v" stdout is expected to match /v10.17.0/ Finished in 48.27 seconds (files took 1.33 seconds to load) 1 example, 0 failures上記結果から、
AnsibleClientサーバにはNode.js v10.17.0がインストールされていることがわかりました。
テスト方法は他にも様々存在するため、詳細は以下を参照してください。ServerSpecはデフォルトで一つのサーバしか実行できない仕様なので、以下に複数サーバ対応方法を記載します。
複数サーバ対応方法
上記で記述した通り、デフォルトでは一つのサーバしかテストを行えないので、以下方法で複数対応を行います。
ファイルの編集を行う前に、仮想マシンをもう一つ立ち上げ、Node.js v10.17.0のインストールを予め行なっています。
今回は192.168.9.9を割り当てたAnsibleClient2を立ち上げています。$ vagrant ssh AnsibleClient2 vagrant@AnsibleClient2:~$ node -v v10.17.0次に、ServerSpecを実行するサーバに戻り、以下ディレクトリ構成に変更します。
. ├── Rakefile ├── properties.yml # 新規作成 └── spec ├── ansibleclient # 192.168.8.8というディレクトリ名を変更 │ └── node_ver_spec.rb # sample_spec.rbというファイル名を変更 ├── ansibleclient2 # 新規作成 │ └── node_ver_spec.rb # 新規作成 └── spec_helper.rbspec_helper.rbファイルにライブラリの読み込みを追記します。
spec/spec_helper.rbrequire 'serverspec' require 'net/ssh' require 'pathname' # 追記 require 'rspec/its' # 追記 set :backend, :ssh set :disable_sudo, true # 追記次に、Rakefileを以下のように編集します。
どこかのサイトから参照しています。require 'rake' require 'rspec/core/rake_task' require 'yaml' properties = YAML.load_file('properties.yml') task :spec => 'spec:all' task :default => :spec namespace :spec do task :all => properties.keys.map {|key| 'spec:' + key.split('.')[0] } properties.keys.each do |key| desc "Run spec to #{key}" RSpec::Core::RakeTask.new(key.split('.')[0].to_sym) do |t| ENV['TARGET_HOST'] = key puts "\n========================================" puts "HOSTNAME: #{key}" t.fail_on_error = false t.pattern = 'spec/{' + properties[key][:roles].join(',') + '}/*_spec.rb' end end endファイル編集完了後、Rakefileと同じディレクトリに properties.ymlを作成し、本ファイルに接続先の定義を行います。
properties.ymlでは、テストを実行するファイル内で使用できる変数を定義することが可能です。
今回は、ansibleclient2のテストで変数node_verを定義しています。properties.yml192.168.8.8: # 接続先を指定 :roles: # 実行するroleを指定 - ansibleclient 192.168.9.9: :roles: - ansibleclient2 :node_ver: "v10.17.0"ansibleclient2のテストは以下の通りです。
こちらもnode.jsのversionを確認しているテスト項目です。spec/ansibleclient2/node_ver_spec.rbrequire 'spec_helper' describe command('node -v') do its(:stdout) { should match /#{property[:node_ver]}/ } endファイル編集は上記で完了です。
テストを再度実行します。$ rake1回目のテストが終了後、
ansibleclient2のテストが開始されたでしょうか。
特に問題がなければ、両方のサーバ共にテストは成功していると思います。おわりに
個人的なメモとして残しているため、わかりにくい箇所があるかもしれません。






