kidoOooOoooOOom

ゲーム開発やってます

sudoersの文法メモ

serverspecやansibleでsudoの動作設定を変更することがあるので、一応 sudoers の文法について整理しておく。

sudoの動作設定は /etc/sudoers に記述されており、visudo コマンドでのみ編集を行うことができる。visudo コマンドは保存時に自動的に構文チェックするようなので、文法ミス等があっても保存時に即sudoが動かなくなるということは無い。

文法と設定例は下記の通り。

文法

ユーザ名 ホスト=(変身可能ユーザ) 実行可能コマンド

設定例

root   ALL=(ALL)   ALL
%hoge   ALL=(ALL)   NOPASSWD: ALL

1つ目の設定では、「rootユーザ」が「全てのホスト」から「全てのユーザに変身」でき、「全てのコマンドを実行可能」となる。
2つ目の設定はユーザ名の頭に % をつけているため、hogeグループの指定になる。
また、NOPASSWDをつけることでsudo実行時に パスワードを聞かれない。

sudo自体のパラメータ変更もできる。
sudo コマンドを実行する時に毎回パスワードを求めるようにするには次のようにする。

Defaults timestamp_timeout = 0

timestamp_timeout のデフォルト値は 5 で、パスワードを入力すると 5 分間は入力を求められない。0 にすることで毎回パスワードを求められるようになる。

serverspec v2で複数ホストにrole別にtest実行

serverspec v1からv2でいくつか変更点があり、v1のソースではそのまま実行できない箇所があったので、変更点を見つつ v2 で基本的なテストを実行できるようにした。

ディレクトリ構成は下記の通り。最低限のwebのテストを用意する。

├── Gemfile
├── Gemfile.lock
├── Rakefile
├── properties.yaml
├── spec
│   ├── spec_helper.rb
│   └── web
│        └── node_spec.rb

Rakefile では ask を使って sshのusernameとpasswordを聞いておき、properties.yamlをロードしてホスト情報をRakeTaskに渡しておく。

require 'rake'
require 'rspec/core/rake_task'
require 'yaml'
require 'highline/import'

properties = YAML.load_file('properties.yaml')

ENV['SSH_USER'] = ask("Enter ssh user: ") { |q| q.echo = true }
ENV['SSH_PASSWORD'] = ask("Enter ssh password: ") { |q| q.echo = false }

desc "Run serverspec to all hosts"
task :serverspec => 'serverspec:all'

namespace :serverspec do
  task :all => properties.keys.map {|key| 'serverspec:' + key }
  properties.keys.each do |key|
    desc "Run serverspec to #{key}"
    RSpec::Core::RakeTask.new(key.to_sym) do |t|
      ENV['TARGET_HOST'] = properties[key][:hostname]
      t.pattern = 'spec/{' + properties[key][:roles].join(',') + '}/*_spec.rb'
    end
  end
end

properties.yaml では hostname と rolesを定義しておく

################################
#    staging
################################
stg-hoge-web01:
  :roles:
    - web
  :hostname: hogeweb01
stg-hoge-web02:
  :roles:
    - web
  :hostname: hogeweb02

spec_helper.rb で、ssh_optionsを組み立てて渡してあげる。
v2から使えるようになった記述にコメントしています。

# coding: utf-8

require 'serverspec'
require 'pathname'
require 'net/ssh'
require 'yaml'

set :backend, :ssh # v2から
set :path, '/sbin:/usr/sbin:$PATH' # v2から

RSpec.configure do |c|
  c.before :all do
    set :host, ENV['TARGET_HOST']
    options = Net::SSH::Config.for(c.host)
    options[:user] = ENV['SSH_USER']
    options[:password] = ENV['SSH_PASSWORD']
    set :ssh_options, options # v2から
  end
end

後は、テスト本体のコードをガリガリ書いていけばおk。
とりあえず確認用に簡単なテストコードを書いて実行すれば無事テスト通った。

require 'spec_helper'

describe package('nodejs') do
  it { should be_installed }
end

describe port(2000) do
  it { should be_listening }
end


Serverspec

Serverspec

Macのターミナル上でマウス操作を有効にする

tmuxを使っていて、分割したウインドウにマウス操作で移動できないのが不便だったので下記対応をした。

  • EasySIMBLをインストール

https://github.com/norio-nomura/EasySIMBL/

  • MouseTerm をインストール

https://bitheap.org/mouseterm/
自分の場合は解凍したできた app ファイルが壊れていると出たので、直接拡張子が「.bundle」のファイルをEasySIMBLの画面にドラッグアンドドロップした。

.vimrcに次の記述を追加する

set mouse=a
set ttymouse=xterm2

これでtmuxを起動しているコンソール上でマウスによるウインドウ移動ができるようになった。

参考URL: http://takaaki-kasai-tech.blogspot.jp/2014/03/use-mouse-wheel-to-scroll-at-vim-in-terminal-on-mac.html

rubyのhighlineでパスワード入力を隠すなど

rubyのコンソールアプリでユーザ名とパスワードを入力させる際に、タイプしたパスワードは隠しておきたい場合は highlineを使えばすぐできるとのこと。

require 'highline/import'

username = ask("Enter user: ") { |q| q.echo = true }
password = ask("Enter password: ") { |q| q.echo = false }

これでおk。
highlineの公式を見ると、バリデーションや色づけ表示、選択肢などの機能もあるみたい。

  • バリデーション
ask("retry number?: ", Integer) { |q| q.in = 0..10 }
  • 関数実行
interests = ask("Interests?  (comma sep list)  ", lambda { |str| str.split(/,\s*/) })
  • ANSI color色付けで出力
say("This should be <%= color('bold', BOLD) %>!")
  • 選択肢を手配
choose do |menu|
  menu.prompt = "Please choose your favorite programming language?  "

  menu.choice(:ruby) { say("Good choice!") }
  menu.choices(:python, :perl) { say("Not from around here, are you?") }
end

zshの導入と初期設定

今までbashを使っていてそんなに不便に感じることはなかったけど、開発効率化のため zshに入れ替えてみることにした。
参考にしたのは WEB+DB PRESSzsh大活用の記事。コマンドを書き写すのがちょっと大変だったけれど、分かり易くて良い記事だと思った。

WEB+DB PRESS Vol.83

WEB+DB PRESS Vol.83

zshはMaxに既にインストールされていたが、一応 brew で最新版にアップデート

% brew install zsh

zshのパスを起動して、chshでログインシェルを変更する。

% which zsh
/bin/zsh
% chsh -s '/bin/zsh'

.bashrcの内容を .zshrcにコピーする。bash独自の設定はもちろん除くかpathを適宜変えておく。

デフォルトではプロンプトの表示が非常に寂しいので、ホスト名・ユーザ名・カレントディレクトリのパス・現在時間を表示されるように設定を .zshrcに追加する。

PROMPT="[%n%m](%*%) %~ %% "

zshは補完機能が bashより強力で、コマンドのオプションもtabで補完をしてくれる。強力な補完機能を有効にするため、下記の設定を追加する。

autoload -Uz compinit
compinit -u

zshはデフォルトでコマンド履歴が30件しか保存されず、これでは全然足りないので一気に増やしておく。

HISTFILE=~/.zsh_history
HISTSIZE=1000000
SAVEHIST=1000000


zshにはプラグイン機構があり、標準ではサポートしていない補完機能を更に拡張するプラグインもある。zsh-completionsをインストールし、

% brew install zsh-completions

.zshrcに設定する。

fpath=(/usr/local/share/zsh-completions(N-/) $fpath)


コマンドラインシンタックスハイライトをつけるプラグインも入れておく。
ソースがgitで管理されているため、一旦cloneした後、

% cd $HOME/.zsh/
% git clone git://github.com/zsh-users/zsh-syntax-highlighting

.zshrcに設定を追加する

[[ -f $HOME/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]] && source $HOME/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh


とりあえずこのあたりの設定を追加した .zshrc は以下の通り。

# zsh
setopt SHARE_HISTORY
setopt AUTO_CD
setopt AUTO_PUSHD
setopt PUSHD_IGNORE_DUPS
setopt IGNORE_EOF
setopt NO_FLOW_CONTROL
setopt NO_BEEP

fpath=(/usr/local/share/zsh-completions(N-/) $fpath)

autoload -Uz compinit
compinit -u

zstyle ':completion:*:default' menu select=2
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

autoload -Uz select-word-style
select-word-style default
zstyle ':zle:**' word-chars " /=;@:{},|"
zstyle 'zle:*' word-style unspecified

PROMPT="[%n%m](%*%) %~ %% "

HISTFILE=~/.zsh_history
HISTSIZE=1000000
SAVEHIST=1000000

[[ -f $HOME/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]] && source $HOME/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

オプションが補完されるのが嬉しい。
今後もzshカスタマイズして開発効率上げていこう。

zsh最強シェル入門

zsh最強シェル入門

serverspec実行できるところまで試してみる

serverspecとは、サーバの状態をテストするためのフレームワークで、Rubyで実装されておりRSpecの書き方に準拠している。
公式サイトはこちら http://serverspec.org/

今回、インストールをして簡単なテストが実行できるところまでを試してみたのでメモ。

  • インストール
$ gem install serverspec

するだけでOK.

  • 初期化

serverspecを実行するサーバ上でserverspecの初期化処理を実施。

$ 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  ←SSH接続をしてリモートのサーバに対してテスト実行する場合は1を
 
Vagrant instance y/n: n
Input target host name: dev1-web1
+ spec/
+ spec/server-01/
+ spec/server-01/httpd_spec.rb
+ spec/spec_helper.rb
+ Rakefile


~/.ssh/config に 上記で設定したhost name と、実際のテスト対象のserver host情報、ログインユーザ情報を書いておく。

Host dev1-web01
HostName dev-web01.hoge.hoge.hoge
User watashi

serverspecのテストでは sudo 実行環境が必要なので、テスト対象のサーバで visudoを実行し、test実行ユーザのSUDO権限を設定しておく

$ sudo visudo
watashi ALL=(ALL) ALL

この設定の場合、sudo実行時にパスワード入力が必要になる。
serverspecの実行時に、SUDO_PASSWORDもしくは、ASK_SUDO_PASSWORD環境変数を設定することでテスト実行が可能となる。
パスワードを環境変数に設定したくない場合には、環境変数「ASK_SUDO_PASSWORD」を1に設定することでテスト実行時に対話式でsudoパスワードを入力することが可能。

$ export ASK_SUDO_PASSWORD=1
  • サンプルテストコード

serverspecがちゃんと動くかどうか確認するための簡単なテストを実行してみよう。
初期化で作成された sample_spec.rbを下記のように書き換える。

require 'spec_helper'
 
set :request_pty, true
  
describe package('nodejs'), :if => os[:family] == 'ubuntu' do
  it { should be_installed }
end
 
describe service('hogehoge'), :if => os[:family] == 'ubuntu' do
  it { should be_running }
end
 
describe port(2000) do
  it { should be_listening }
end

これで rake specを実行すると、
「highline is not available. Try installing it.」
と、'highline'が無いと怒られたので、gem install highline でインストール。
その後、rake specでテストが無事実行されることを確認。

$ rake spec
Package "nodejs"
  should be installed
 
Service "hogehoge"
  should be running
 
Port "2000"
  should be listening
 
Finished in 0.27195 seconds (files took 3.97 seconds to load)
3 examples, 0 failures

Serverspec

Serverspec

node.jsで objectをyamlで出力

node.js で形成した objectを yamlフォーマットで出力したいケースがあったのでメモ。
やりたいこととしては、ansibleのinventoryに記載したhosts情報を元に、tmuxinatorの設定ファイル(yaml)を自動生成すること。
yaml出力には js-yaml モジュールを使えば簡単。

var yaml = require('js-yaml');
var fs = require('fs');
var ini = require('ini');
var _ = require('lodash');
var hosts = ini.parse(fs.readFileSync('./data/config.ini', 'utf-8'));

var dump = {
  name: 'hoge-dev',
  root: '~/',
  windows: [
    {
      web: {
        layout: "main-vertical",
        panes: []
      }
    },
    {
      db: {
        layout: "main-vertical",
        panes: []
      }
    }
  ]
};

_.each(_.keys(hosts.webservers), function(host) {
  var sshCommand = 'ssh $SSH_USERNAME@' + host;
  dump.windows[0].web.panes.push(sshCommand);
  dump.windows[0].web.panes.push(sshCommand + ' -t tailf /var/log/hoge/error.log');
});

_.each(_.keys(hosts.dbservers), function(host) {
  var sshCommand = 'ssh $SSH_USERNAME@' + host;
  dump.windows[1].db.panes.push(sshCommand);
  dump.windows[1].db.panes.push(sshCommand + ' -t tailf /var/log/db/db.log');
});

console.log(yaml.safeDump(dump));

最後の、yaml.safeDump() で objectをyamlに変換している。
出力結果は下記の通り。

name: hoge-dev
root: ~/
windows:
  - web:
      layout: main-vertical
      panes:
        - "ssh $SSH_USERNAME@foo.example.com"
        - "ssh $SSH_USERNAME@foo.example.com -t tailf /var/log/hoge/error.log"
        - "ssh $SSH_USERNAME@bar.example.com"
        - "ssh $SSH_USERNAME@bar.example.com -t tailf /var/log/hoge/error.log"
  - db:
      layout: main-vertical
      panes:
        - "ssh $SSH_USERNAME@one.example.com"
        - "ssh $SSH_USERNAME@one.example.com -t tailf /var/log/db/db.log"
        - "ssh $SSH_USERNAME@two.example.com"
        - "ssh $SSH_USERNAME@two.example.com -t tailf /var/log/db/db.log"
        - "ssh $SSH_USERNAME@three.example.com"
        - "ssh $SSH_USERNAME@three.example.com -t tailf /var/log/db/db.log"

サーバサイドJavaScript Node.js入門 (アスキー書籍)

サーバサイドJavaScript Node.js入門 (アスキー書籍)