kidoOooOoooOOom

ゲーム開発やってます

mongodbで正規表現でcollectionを指定してremove

mongodbで正規表現を指定して特定のcollectionsだけremoveしたいケースがあったので、それのメモ。
コンソールからmongoシェルを立ち上げて下記を宣言し、宣言した関数を実行してあげるとok.

var removeUserCollections = function() {
  var removeTargets = [];
  db.getCollectionNames().forEach(function(coll){
    if(coll.match(/^user_*/)){
      removeTargets.push(coll);
    }
  });
  print('remove following collctions');
  print(removeTargets);

  removeTargets.forEach(function(target) {
    db[target].remove();
  });

  print('remove done!');
};

mongodb設定周りメモ

パラメータの設定方法について。
mongod( or mongos)起動時に、コマンドライン引数か config ファイルで設定する。両方に同じパラメータの設定があった場合、configファイルが優先される。

$ mongod --plogappend true --verbose
  • configファイルの場合

まず、/etc/mongod.cnf ファイルを用意しておき、

$ mongod --config /etc/mongod.cnf

で読み込み。


今回メモったパラメータは下記の通り。

パラメータ名 説明 デフォルト値
dbpath DBファイルを格納するディレクトリのパス。 /data/db
port 待ち受けポート番号 27017
logpath ログ出力先 標準出力
logappend ログに追記するかどうか flase
directoryperdb データベースごとにデータファイルを作るかどうか false
pidfilepath pidファイルのパス。指定しないとpidファイルが作られない none
rest restインターフェースを有効にするかどうか。http://localhost:28017/{db_name}/{collection_name}/ で GETするとJSONが返ってくる false
journal trueだとジャーナルを確実に永続化し、一貫性を保つ。一貫性を保証しなくてもよい場合は、nojournal=trueとしてジャーナルを無効にする。パフォーマンスとのトレードオフで選択する。 (64bit)true, (32bit)false
configdb mongos用パラメータ。使用するconfig dbのホスト名を書く

Node.jsでエクセルparseして出力など

本来はやりたくないことだが、大量のエクセルファイルで用意されてしまったデータから必要なものだけ抜き出して整形して出力する必要性があったので対応した。
使用したのは xlsx モジュール

例えば、下記のようなテンプレートのエクセルファイルがあるとする。
f:id:gidooom:20150213162534p:plain

このエクセルファイルを開いて、指定の要素を取り出すコードは下記の通り。

var fs = require("fs");
var XLSX = require('xlsx');

var PROP_MAP = {
  'C2': 'master_id',
  'C4': 'name',
  'C5': 'description',
  'C6': 'age',
  'C7': 'height',
  'C8': 'weight',
};

var workbook = XLSX.readFile('hogehoge.xlsx');

workbook.SheetNames.forEach(function(y) {
  var worksheet = workbook.Sheets[y];
  for (var z in worksheet) {
    if(z[0] === '!') continue;
    console.log(z + "=" + JSON.stringify(worksheet[z].v));
  }
});

出力結果は下記の通り。

B2="master_id"
C2=1000
B4="name"
C4="hogehoge man"
B5="description"
C5="saying hogehoge"
B6="age"
C6=35
B7="height"
C7="180cm"
B8="weight"
C8="75kg"

後は取得できたデータをごにょごにょ整形して出力してあげればおk。

Node.jsでBasic認証

basic-auth-connect モジュールを使うと簡単にできる。
そのまま user名とpasswordを渡すと、認証エラーの場合は 401を返してくれる。

var basicAuth = require('basic-auth-connect');
app.use(basicAuth(username, password));

ちょっと特殊な処理をかましたい場合は、callback関数渡しでもok.

connect()
.use(basicAuth(function(user, pass){
  return 'tj' == user && 'wahoo' == pass;
}))

デフォルトのエラーハンドリング処理を変えたい場合は、エラーハンドリング用の関数を渡すことも可能。

connect()
.use(basicAuth(function(user, pass, fn){
  User.authenticate({ user: user, pass: pass }, fn);
}))

serverspec v2で NICのリンク速度テスト

serverspecでNICのリンク速度設定のテストを行う場合は下記のように書く。

describe interface('eth0') do
  its(:speed) { should eq 1000 }
end

Ubuntu 12.04 のサーバで実行してみると、ethtool が無いよと怒られたので、ansible の taskに追加。

- name: Install ethtool
  apt: pkg=ethtool state=installed
  tags: packages

次は gawk が無いよと怒られたので、更に task追加

- name: Install gawk
  apt: pkg=gawk state=installed
  tags: packages

これで実行できるようになった。

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