社内勉強会を開催しました
10/9の20時より、サーバ・インフラ社内勉強会を開催しました。
(自分が面接官をやらないといけなかった関係で、こんな時間になってしまいました)
参加者は下記のような感じ。
- 中堅Android・サーバエンジニア
- 中堅サーバ・インフラエンジニア(鹿児島からリモート!)
- 若手エンジニア
- 若手ビジネスプロデューサー(いわゆる営業)
- 中堅?フロントエンドエンジニア(最後の数分のみ参加)
スライドはこちら。
結構初歩的なことしか喋ってないですが、サーバやインフラのことを理解してない人には勉強になったんじゃないかな、と思います。
中堅の人にはツッコミを入れてもらい、私も勉強になりましたし。
「勉強会開いて下さい!」って言ってきたフロントエンドエンジニアが参加できなかったのは残念でしたがw
鹿児島からも発表してもらって、自分も勉強出来ました。
続くかも、って書いてますが、社外への常駐が増えそうなので、難しいかなーと思います。
まぁ、機会があればまたやってみたいと思います。
SlideViewerをリリースしました
本日、SlideViewerというAndroidアプリをリリースしました。
とりあえず、Speaker Deckのクライアントアプリです。
GitHub にコードは一通り置いてあります。
Speaker Deckのスライドページを開く際に、SlideViewerアプリが選択できます。
APIなどが提供されていなかったので、スクレイピングしています。
そのため、初回の読み込みは遅いのですが、スライド表示中にある程度先読みするため、読んでる間にストレスは溜まりづらいかと思います。
何より、標準ブラウザで見た時は大きさが中途半端になってしまうのが、幅いっぱいに表示されます。
ただ、最低限必要な機能は実装したのでリリースしましたが、もうちょっと改修する予定です。
画面回転に対応できてなかったり、改めて見ると、残念なところが多いですね。。。
で、そこら辺も完了したら、Slide Shareとか、他?も閲覧できるようにしたいと思います。どこまでモチベーションが持つかが勝負ですが。
そもそも、一番の問題は、スクレイピングしていることを怒られないか、という点ですが。
Integerを"=="で比較してはいけない
追記:Javaの話です。
public class Main { public static void main(String args[]) throws Exception { Integer i1 = 1; Integer i2 = get1(); if (i1 == i2) { System.out.println("equal"); } else { System.out.println("not equal!!"); } } public static Integer get1() { // DBとかから取ってきたつもり return new Integer(1); } }
は、"not equal!!"と言われてしまいます。
(ただし、コンパイラや実行環境に依存するかもしれません。)
Integerはプリミティブ型ではないので、==
では、同一のインスタンスかどうかを確認してしまっているんですね。(たぶん
普通、比較といえば、値の同一性を知りたいと思うので、
public class Main { public static void main(String args[]) throws Exception { Integer i1 = 1; Integer i2 = get1(); if (i1.equals(i2)) { // ←ここを変えた System.out.println("equal!!"); } else { System.out.println("not equal!!"); } } public static Integer get1() { // DBとかから取ってきたつもり return new Integer(1); } }
まぁ、こうしますよね。
ただ、上記の場合は i1
がnullの場合はNullPointerExceptionが発生します。当たり前ですね。
なので、 i1
が必ずnullでは無い場合にしか使えないです。
nullの場合、一致とみなすか、不一致とみなすかは文脈によるかと思いますので、割愛します。
org.apache.commons.lang.ObjectUtils.equals
を利用するのも手ですね。
8/10追記 java.util.Objects.equals ってのがJava7からあるみたいです。(コメントで教えていただきました。)
ちゃんと考えれば当たり前なんですが、誰かの書いたコードで、ぼんやり読んでるとハマりますね。(というか、ハマりました。
Travis CIでAndroidアプリをビルドしてDeployGateに置く
継続的インテグレーションをAndroidでもしたい!ということで、
- Travis CI - Free Hosted Continuous Integration Platform for the Open Source Community
- DeployGate - An incredibly easy way to deploy apps in development!
ここらへんを使い、
ということを実現したいと思います。
対象は、現在全リファクタリング中のこちら。
https://github.com/noboru-i/kyouen-android/tree/renew
.travis.yml の設定
language: android env: global: # deploygate - DEPLOYGATE_USER=noboru-i - secure: "SOev0rrhdJ6fp5CkJeQAh6mm6EmmWEWCVrSt7hn3mvjSbaz/yKdmiGsHp8NcTeLZrXuk6ay6mFee3TVqsT17Xn5+cGG5nnWFPqI2Os3AlSWdHkhLrv8f3KdfwJeTiBSymw4TDWSd/kVCB42q51BdnODda+GozCymA6qoZpf/GQs=" # secret_strings.xml - secure: "ZXnouETJ67n/DCjCFPdWoIm3eo0WsYhfuy9Y25IjYn6gij4F8v038bjYr+Z5QBsnLri1mU0QQeNy14cPaaYBoblTsmPm0cZ+Vv0wmYgAkVc2C+E67k/YUAD0puvUzUGsQ1z6N7gQ0tFjL4l4map/4iEkGtney6OYdyuljE75D2g=" - secure: "Sqi+dwZcd6qGpBLYUq+deqQBSX056N0eoQ9RfMjWB7gG/WfQn4XQaTF13jKdqp0MKzRj8P61uunoxZIpHNYNWeqzxfIpXKrzOdGv85r8PnbjDgH87N22ufqwPdbfAVydUEPP8hEEJ5vbCN2Fyoq1CHPNjwBpMIiD27LMVjiytn8=" - secure: "iUO0ldYPT3jYjoRafH0Milc3DNhgqzZQGk7tFkvg7WPF+YPEYDOMjwmhY0kTDjbxU+iqkHE7WOL66MtJSlvTJjNfs2uWqrXrmgMAXLusbRukscJmL2ZwGhNwBi4tOOl4V1FO8NRqYcdRkkHgJRUXyKAafLrdNePVm7uWUwjl2e0=" - secure: "PCeJAQ8/XrDWktlTbKtJLCcjhjOfsw/tcPPCrG1urvQMJrgzi6m6pTWo62RSpWVo1iYePiqvDgPGACrT082vtnoJ7TJ3FZEhty1xsDUhDBJ9qvmHEPpxLrtLGwZ1+doT/yxinQAqqucx8vsFJcTh8zOrGLknwEvqxhNj5HHKzkg=" - secure: "MyGGNdkyv+qEf8yhORcSzjsHbDjT2yILka/aMYgInt0oyF3T6O6JwwRvrXHEulPVHWsWu4LCxX8e3HeyyQ0OkIjc67nwIsajCDwDlVUcnkjqyV3r9xPn0HlltwvS63QuQGln6NQIUBk9nVIuaA+vno7bod1Px0VESu9kDgUiqgI=" notifications: email: false android: components: - build-tools-19.1.0 - android-19 - sysimg-19 - extra-android-support licenses: - android-sdk-license-5be876d5 - '.*intel.+' before_install: - android list sdk --no-ui --all --extended script: - ./gradlew uploadDeployGateDebug
env.globalには下記を記載しています。
作成については、下記のコマンドで。
travis encrypt GCM_SENDER_ID=9999999999999
これを、後述のgradle taskでxmlに書き込みます。
Projectのbuild.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:0.12.+' // deploygate classpath 'com.deploygate:gradle:0.6' } } allprojects { repositories { jcenter() } }
DeployGateのgradle pluginをここで設定しています。
アプリのbuild.gradle
apply plugin: 'com.android.application' apply plugin: 'deploygate' android { // Error:duplicate files during packaging of APK /XXX/app-debug-unaligned.apk 対策 packagingOptions { exclude 'META-INF/license.txt' exclude 'META-INF/notice.txt' } compileSdkVersion 19 buildToolsVersion "19.1.0" defaultConfig { applicationId "hm.orz.chaos114.android.tumekyouen" minSdkVersion 12 targetSdkVersion 19 versionCode 18 versionName "0.10.0" } buildTypes { release { runProguard false // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:support-v4:19.0.+' compile 'com.android.support:appcompat-v7:19.+' // deploygate compile 'com.deploygate:sdk:3.1' } apt { arguments { androidManifestFile variant.processResources.manifestFile resourcePackageName 'hm.orz.chaos114.android.tumekyouen' } } deploygate { userName = "$System.env.DEPLOYGATE_USER" token = "$System.env.DEPLOYGATE_TOKEN" apks { debug { sourceFile = file("${project.buildDir}/outputs/apk/app-debug-unaligned.apk") } } } uploadDeployGateDebug.dependsOn assembleDebug task secretKeyReplace { description 'Replace secret keys from system environment.' doLast { def filePath = "app/src/main/res/values/secret_strings.xml" def br = new BufferedReader(new FileReader(filePath)) def lines = br.readLines() br.close() // key情報の抽出 def secretKeys = new HashSet() def rExpression = /INPUT_YOUR_([A-Z_]+)/ for (String line : lines) { if (line.contains("INPUT_YOUR_")) { def matcher = (line =~ rExpression) secretKeys << matcher[0][1] } } // 文字列の置換 def newLines = new ArrayList<String>() for (String line : lines) { String newLine = line for (String key : secretKeys) { if (!System.getenv()[key]) { continue } newLine = newLine.replace("INPUT_YOUR_" + key, System.getenv()[key]) } newLines << newLine } def pw = new PrintWriter(new BufferedWriter(new FileWriter(filePath))) for (def line : newLines) { pw.println(line) } pw.close() } } preBuild.dependsOn secretKeyReplace
buildToolsVersion は、最新が20.0.0だけど、ymlに書いた android-sdk-license-5be876d5
がまだ対応してないようなので、19.1.0になってます。
deploygateタスクの設定(ユーザ名 / パスワード)は環境変数から取得しています。
環境変数への設定は.travis.ymlに書いてあります。
DEPLOYGATE_TOKEN も、暗号化して書いてあります。
secretKeyReplace taskで、secret_strings.xmlにある、"INPUT_YOUR_XXX"を取得、その"XXX"をキーとして環境変数を取得、replaceして同じファイルを置き換えます。
きっと、もっと良いやり方あると思うんだけど、ググっても出てこなかったので、力技です。
Publicリポジトリにキー情報は置けないけど、Travis CIでapkを作るときには必要。みんなどうやってるんだろう?
まとめ
というわけで、GitにPUSHするとDeployGateでアプリが配布されるところまで出来ました。
Publicリポジトリに置けない認証情報を設定する方法が、あんまりいけてないのはなんとかしたいところ。
あとは、テストコード書いて、リグレッションテストを回していきたいと思います。
Robolectricを使うつもりで書いてるので、まとまったらまた書こうと思います。
CocoaPodsでインストールしたのにヘッダが file not found
何故かpod installしてあるのに、 いろいろな書き方でやってみたけど、どれもヘッダがnot foundになってしまった。
#import "AFNetworking.h" #import <AFNetworking.h> #import "AFHTTPRequestOperationManager.h" #import <AFHTTPRequestOperationManager.h> #import <AFNetworking/AFHTTPRequestOperationManager.h>
よくよく考えると、とりあえずpod installだけしてあって、その機能を使おうとしたのは初めてだった。
いろいろ探してると、
objective c - iOS - Build fails with CocoaPods cannot find header files - Stack Overflow
こんなのを見つけた。
なので、それを設定しようとして、その画面を開いたら、
そんなもん無いんですけどー。。。
で、既にあるプロジェクトファイルといろいろ見比べたけど、それっぽい違いが見つからない。
そもそもどうやったら、ここに表示されるものが出来るのか調べたら、
複数のTarget/Configurationを持つiOSプロジェクトの構成Tips - やらなイカ?
こんなの見つけた。
で、動いているプロジェクトには「Pods.xcconfig」があるのに、今のプロジェクトには無い。
Pods/Pods.xcconfig のものをインポートしているようだったので、同じようにプロジェクトに追加したら動いた!
なんで無くなってたんだろう。。。
Bootstrap3ベースの管理画面を作る
まずは、Railsアプリケーションの作成。
- irkitというプロジェクト名
- unit testをスキップ
- データベースはsqlite3
- bundle installを行わない
rails new irkit -T -d sqlite3 --skip-bundle cd irkit
とりあえず、git管理下に置きましょう。
git init git add . git commit
Gemfileに下記を追加します。
# 認証処理 gem 'devise', '~> 3.2.4' # bootstrap gem 'bootstrap-sass', '~> 3.1.1.1' gem 'bootstrap-sass-extras', '~> 0.0.6'
vendor/bundle以下にbundle install。
bundle install --path=vendor/bundle
.gitignore に下記を追加します。
/vendor/bundle
また、一旦gitにコミットします。
git add . git commit
deviseの設定を行います。
rails generate devise:install rails generate devise user bundle exec rake db:migrate
rootページが必要なので、controllerを作成します。
rails generate controller welcome index
config/routes.rb にコメントがたくさん書いてあるのを消して、下記のようにします。
Rails.application.routes.draw do root 'welcome#index' devise_for :users get 'welcome/index' end
app/controllers/application_controller.rb を下記のようにします。
class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception before_action :authenticate_user! end
とりあえず、一回サーバを起動してみます。
rails s
http://localhost:3000/ にアクセスして、 http://localhost:3000/users/sign_in にリダイレクトされ、認証画面が出て来れば、とりあえずOKです。
次に、bootstrapの設定です。
app/assets/stylesheets/application.css を application.css.scss にリネームし、下記を追加します。
@import "bootstrap";
app/assets/javascripts/application.js のrequire部分を下記のようにします。
//= require jquery //= require jquery_ujs //= require turbolinks //= require bootstrap //= require_tree .
bootstrapの設定を行います。
app/views/layouts/application.html.erb がコンフリクトしていると言われますが、y で。
rails g bootstrap:install rails g bootstrap:layout application fluid
エラーメッセージがぎりぎりに出てくるのが嫌なので、application.css.scss で全体的にずらします。
body { padding-top: 70px; }
というより、deviseの画面でメニューとかが出てるのがおかしいので、layoutを変えます。
app/controllers/application_controller.rb を下記のように変更します。
class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception before_action :authenticate_user! layout :layout_by_resource protected def layout_by_resource if devise_controller? "devise" else "application" end end end
app/views/layouts/devise.html.erb を作成します。
基本的には、app/views/layouts/application.html.erb をコピペ。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <%= viewport_meta_tag %> <title><%= content_for?(:title) ? yield(:title) : "Irkit" %></title> <%= csrf_meta_tags %> <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> <!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.1/html5shiv.js" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.3.0/respond.js" type="text/javascript"></script> <![endif]--> <%= stylesheet_link_tag "application", :media => "all" %> <!-- For third-generation iPad with high-resolution Retina display: --> <!-- Size should be 144 x 144 pixels --> <%= favicon_link_tag 'apple-touch-icon-144x144-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '144x144' %> <!-- For iPhone with high-resolution Retina display: --> <!-- Size should be 114 x 114 pixels --> <%= favicon_link_tag 'apple-touch-icon-114x114-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '114x114' %> <!-- For first- and second-generation iPad: --> <!-- Size should be 72 x 72 pixels --> <%= favicon_link_tag 'apple-touch-icon-72x72-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '72x72' %> <!-- For non-Retina iPhone, iPod Touch, and Android 2.1+ devices: --> <!-- Size should be 57 x 57 pixels --> <%= favicon_link_tag 'apple-touch-icon-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png' %> <!-- For all other devices --> <!-- Size should be 32 x 32 pixels --> <%= favicon_link_tag 'favicon.ico', :rel => 'shortcut icon' %> <%= javascript_include_tag "application" %> </head> <body> <div class="container"> <%= bootstrap_flash %> <%= yield %> <footer> <p>© Company 2014</p> </footer> </div> <!-- /container --> </body> </html>
とりあえず、もう一回コミットしておく。
git add . git commit
deviseのviewをファイルに出力しておきます。
rails generate devise:views
ためしに、app/views/devise/sessions/new.html.erb を下記のように書き換えます。
(基本的に、 http://getbootstrap.com/examples/signin/ のパクリ)
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: {role: 'form', class: 'form-signin'}) do |f| %> <h2>Sign in</h2> <%= f.email_field :email, autofocus: true, class: 'form-control', required: true, placeholder: 'Email address' %> <%= f.password_field :password, class: 'form-control', required: true, placeholder: 'Password' %> <% if devise_mapping.rememberable? -%> <div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div> <% end -%> <div><%= f.submit "Sign in", class: 'btn btn-lg btn-primary btn-block' %></div> <%= render "devise/shared/links" %> <% end %>
なんとなく、それっぽくなります。
あと、jsとcssがバラバラにダウンロードされると、ログがウザいので、 config/environments/development.rb を変更します。
config.assets.debug = false
適当なモデルを作成します。
rails g scaffold command name:string json:text bundle exec rake db:migrate rails g bootstrap:themed commands
app/views/layouts/application.html.erb のli部分を下記に変更します。
ついでに、"col-md-3"で作成されているサイドバー部分を削除します。
<li><%= link_to "command", commands_path %></li>
あと、ボタンの文字色が変なので、app/assets/stylesheets/scaffolds.css.scss にある下記のaタグの部分を削除します。
a { color: #000; &:visited { color: #666; } &:hover { color: #fff; background-color: #000; } }
なんとなくデータを入れると、それっぽく見えます。
とりあえず、ここまでの作業時点のタグは下記の通り。 https://github.com/noboru-i/irkit/tree/hatena-20140505
メモ取りながら開発するって、凄い疲れる。。。
Ruby on Rails 4 アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/11
- メディア: 大型本
- この商品を含むブログを見る
RailsによるアジャイルWebアプリケーション開発 第4版
- 作者: Sam Ruby,Dave Thomas,David Heinemeier Hansson,前田修吾
- 出版社/メーカー: オーム社
- 発売日: 2011/12/01
- メディア: 単行本(ソフトカバー)
- 購入: 12人 クリック: 206回
- この商品を含むブログ (39件) を見る
既にローカルでgit管理しているものをgithubにpushする
想定している状況
- とりあえず、ローカルで開発をしていた
- もちろん、git initして、作業毎にgit commitをしている
- ブランチは切ってなくて、masterブランチで作業している
- 一通り実装したので、githubに公開しようと思った
- githubでリポジトリを作ったけど、どうやってpushしていいかわからん
- githubでリポジトリを作った時の、LICENSEやらREADME.mdは残しておきたい*1
手順
github上でSSHのclone URLをコピーしてきます。
例:git@github.com:noboru-i/irkit.git
git管理しているディレクトリにて、下記のコマンドを実行します。
git remote add origin git@github.com:noboru-i/irkit.git git fetch
これにより、origin/masterとして、github上のmasterブランチを参照できるようになりました。
なので、origin/masterを、ローカルのmasterにリベースします。*2(masterブランチをチェックアウトしている前提)
git rebase origin/master
これで、ローカルのmasterブランチはLICENSEやらREADME.mdが存在している状態になります。
なので、これをpushします。
git push origin master
一本道になりました。
一番左のコミットがgithubで自動的にコミットされたもので、それ以降のものがローカルでコミットしていたものです。
時系列はひっくり返ってしまいますが、意味的にはこんな感じでいいんじゃないでしょうか?
ちなみに、mergeしたらこんな感じに、入り口2つになったので、なんか微妙だなーと。
もっといいやり方があるような気はします。
余談
マージしてpushしちゃったあとの復旧方法は下記の通りです。
git reset --hard c62d6a3 git co -b o_master git reset --hard e14b7566ca35c5910dd0769d3bdadb59f1499231 git push -f origin o_master:master git co master git b -d o_master
- c62d6a3:1個前(margeする前)のコミット
- e14b7566ca35c5910dd0769d3bdadb59f1499231:githubの初期コミット
なにをやっているかというと、下記のような感じ。
- masterのマージコミットを破棄
- o_masterブランチにて、元のorigin/master を再現し、強制push
- masterをチェックアウトしなおし、不要になったo_masterブランチを削除
- 作者: 松下雅和,船ヶ山慶,平木聡,土橋林太郎,三上丈晴
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2014/04/09
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
GitHub実践入門 ~Pull Requestによる開発の変革 (WEB+DB PRESS plus)
- 作者: 大塚弘記
- 出版社/メーカー: 技術評論社
- 発売日: 2014/03/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (5件) を見る
Play framework 2でinMemory以外のDBでテストを行う
下記を買って、Play Framework 2を使っています。
Play Framework 2徹底入門 JavaではじめるアジャイルWeb開発
- 作者: 掌田津耶乃,原一浩
- 出版社/メーカー: 翔泳社
- 発売日: 2013/12/17
- メディア: 大型本
- この商品を含むブログ (6件) を見る
テストを書こうと思って、Chapter7のFakeAppをコピーしてやってみました。
で、実行してみたところ、PostGIS関連の特殊カラム関係でエラーになってしまいました。
そのため、inMemoryDatabaseをやめて、実際のPostgreSQLを利用しようと思って、ハマりまくりました。
あと、GlobalSettingsを継承したクラスでDBアクセスしてたので、さらにわけのわからんエラーが出ました。
まず、startAppでFakeApplicationを作成。
@BeforeClass public static void startApp() throws IOException { Map<String, Object> map = new HashMap<>(); map.put("db.default.url", "jdbc:postgresql://127.0.0.1:5432/sample_db"); map.put("db.default.user", "web_dev"); map.put("db.default.password", "password"); app = fakeApplication(map, new GlobalSettings()); start(app); String evolutionContent = FileUtils.readFileToString(app .getWrappedApplication().getFile( "conf/evolutions/default/1.sql")); String[] splitEvolutionContent = evolutionContent.split("# --- !Ups"); String[] upsDowns = splitEvolutionContent[1].split("# --- !Downs"); createDdl = upsDowns[0]; dropDdl = upsDowns[1]; }
これで、リクエスト時のDBはPostgreSQLに向く。
あと、DDL文を実行し、テーブルを作成。
@Before public void createCleanDb() { final DataSourceConfig dataSourceConfig = new DataSourceConfig(){{ setDriver("org.postgresql.Driver"); setUrl("jdbc:postgresql://127.0.0.1:5432/sample_db"); setUsername("web_dev"); setPassword("password"); }}; ServerConfig serverConfig = new ServerConfig(){{ setName("test"); setDataSourceConfig(dataSourceConfig); setRegister(false); setDdlRun(false); setDdlGenerate(false); setDefaultServer(false); }}; // transactionで囲み、commitしないと反映されなかった EbeanServer ebeanServer = EbeanServerFactory.create(serverConfig); ebeanServer.beginTransaction(); ebeanServer.execute(ebeanServer.createCallableSql(dropDdl)); ebeanServer.execute(ebeanServer.createCallableSql("commit;")); ebeanServer.execute(ebeanServer.createCallableSql(createDdl)); ebeanServer.execute(ebeanServer.createCallableSql("commit;")); ebeanServer.commitTransaction(); }
DROP文→CREATE文をとりあえず投げておけばOKかと思ったら、コメントで書いてあるように、transactionで囲んでそれぞれcommitしないとうまく動かなかった。
もっと普通のやり方があってもいいと思うけど、調べててもなかなか出てこなくて困った。
Play Framework自体あんまり情報が見つからないイメージ。しかも、バージョンごとに結構違ってて困る。
公式を探すしか無い印象。
テストのやり方とか、Ruby on Railsほど整ってない感じ。
とはいえ、Rubyの開発者よりはJavaの開発者の方が調達しやすいとかの関係で、Javaの案件もやらざるを得ない感じ。 (PHPは個人的に好きでない。。。)
Springもそのうちまともにやってみたいとは思うけど、「Play」だったり「Spring」だったり、なんでこんなにググラビリティの悪いものが多いんだろう。。。
chefでデータベースとかユーザとか作りたい
Vagrantで開発環境を共有したりしているのですが、
- データベースの作成
- ユーザの作成
とかってどこでやるべきなんでしょう?
「本来ここでやるべき」とか知ってる人がいたら教えて下さい。
とりあえず現状は、MySQLのインストールとかをchefでやっているので、ついでにchefでやってしまおうと思います。
knife cookbook create database-prepare -o site-cookbooks/ vim site-cookbooks/database-prepare/recipes/default.rb
mysql-clientのインストールと、SQL文の実行を記述しておきます。
package 'mysql-client-5.5' do action :upgrade end package 'libmysqlclient-dev' do action :upgrade end template '/tmp/mysql-schema.sql' do source 'mysql-schema.sql.erb' end bash 'apply schema' do code "mysql -uroot -h#{node[:database][:host]} #{"-p" + node[:database][:password] if node[:database][:host] != 'localhost'} < /tmp/mysql-schema.sql" end
templateは下記のように。
<% host = node[:database][:host] name = node[:database][:name] user = node[:database][:user] password = node[:database][:password] %> <% if host == 'localhost' %> CREATE DATABASE IF NOT EXISTS `<%= name %>` DEFAULT CHARACTER SET utf8; CREATE DATABASE IF NOT EXISTS `<%= name %>_test` DEFAULT CHARACTER SET utf8; GRANT ALL PRIVILEGES ON `<%= name %>_test`.* TO <%= user %>@localhost IDENTIFIED BY '<%= password %>'; GRANT ALL PRIVILEGES ON `<%= name %>_test`.* TO <%= user %>@"%" IDENTIFIED BY '<%= password %>'; <% end %> GRANT ALL PRIVILEGES ON `<%= name %>`.* TO <%= user %>@localhost IDENTIFIED BY '<%= password %>'; GRANT ALL PRIVILEGES ON `<%= name %>`.* TO <%= user %>@"%" IDENTIFIED BY '<%= password %>'; FLUSH PRIVILEGES;
localhost の場合のみ"CREATE DATABASE"を行っているのは、RDSだと勝手に作られるから。 あと、"_test"ってのを作ってるのも、ローカルでのみテストを行うから。 そのへんはプロジェクト・案件によって変わってくるのかなー、と。
で、MySQLはこんな感じで簡単に出来たんだけど、PostgreSQL が面倒だった。
- "IF EXISTS"的なものが見つからない。
- 同じようにSQLファイルを用意しても、エラーになってしまった。
というわけで、毎回コマンドを発行することに。
package 'postgresql-client-common' do action :upgrade end execute "create-role" do exists = <<-EOH su - postgres -c "psql -c\\"SELECT * FROM pg_user WHERE usename='#{node[:database][:user]}'\\" | grep -c #{node[:database][:user]}" EOH command <<-EOC su - postgres -c "psql -c\\"CREATE ROLE #{node[:database][:user]} WITH LOGIN PASSWORD '#{node[:database][:password]}';\\"" EOC not_if exists end execute "create-database" do exists = <<-EOH su - postgres -c "psql -c\\"SELECT * FROM pg_database WHERE datname = '#{node[:database][:name]}'\\" | grep -c #{node[:database][:name]}" EOH command <<-EOC su - postgres -c "psql -c\\"CREATE DATABASE #{node[:database][:name]} OWNER #{node[:database][:user]} ENCODING 'UTF8' LC_CTYPE 'en_US.UTF-8' LC_COLLATE 'en_US.UTF-8' TEMPLATE template0;\\"" su - postgres -c "psql -d #{node[:database][:name]} -f /usr/share/postgresql/9.3/extension/postgis--2.1.2.sql" EOC not_if exists end
ちなみに、Vagrantfileにはパラメータを設定しておく。
chef.json = { :database => { # :type => "mysql", :type => "postgresql", :host => "localhost", :name => "sample_db", :user => "web", :password => "password" } }
入門Chef Solo - Infrastructure as Code
- 作者: 伊藤直也
- 出版社/メーカー: 伊藤直也
- 発売日: 2013/03/11
- メディア: Kindle版
- 購入: 16人 クリック: 1,027回
- この商品を含むブログ (17件) を見る
chefで頑張って冪等性を確保する
packageリソースなどは、勝手に冪等になってくれるけど、executeとかは自分で冪等になるように書かないといけない。
特定の文字列を、ファイルの末尾に追記したい場合
例:/etc/resolv.conf に 'options single-request-reopen' を追加する。 二重に追加されないように not_if で制限する。
execute 'add single-request-reopen' do command "echo 'options single-request-reopen' >> /etc/resolv.conf" not_if "cat /etc/resolv.conf | grep 'options single-request-reopen'" end
パスを通す場合
例:rbenvコマンドにパスを通す。 パスが通っている場合は not_if で制限する。
user = 'vagrant' home_dir = "/home/#{user}" execute 'export path' do not_if 'which rbenv' user user group user command <<-EOC echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> #{home_dir}/.bash_profile echo 'eval "$(rbenv init -)"' >> #{home_dir}/.bash_profile EOC end
とりあえず、このへんを知っておくと、たいていは冪等に書けるんじゃないかと。