2013年11月12日火曜日

rails with devise - ログアウトでエラー

最近rails4を学習中。
認証機能にdeviseを使用していてログアウトのリンクを生成しクリックするとエラーとなる。
No route matches [GET] "/users/sign_out"
rake routesを確認すると
destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
となっているということは、DELETEがうまく無いってことらしい。
そこで、config/initializers/devise.rb の該当箇所をdeleteから
config.sign_out_via = :get
に変更し、serverを再起動してみたら上手くいった。

2013年11月5日火曜日

instagram api

instagramのapiを使う

ハッシュタグで検索した結果を出力する。
access_tokenが必要なので先に取得をしておく。
jqueryを使ってこんな感じで関数を準備。
id=instagram があればapiを叩く様にする。
jQuery(function ($) {
        if ($('#instagram').length > 0) {
            ajaxSearchInstagram();
        }
    });
});
function searchInstagram() {
    var tag = 'piaggio';
    var url = 'https://api.instagram.com/v1/tags/'+tag+'/media/recent';
    var params = new Object();
    params['access_token'] = 'ここに取得したaccess_token入れる';
    $.ajax({
        type: "GET",
        url: url,
        data: params,
        dataType: 'jsonp',
        cache: true,
        async: true,
        global: true,
        success: jsonInstagramDrawLightBox,
    });
    return false;
}
function jsonInstagramDrawLightBox(ua) {
    var va = ua.data;
    $.each(va, function (i) {
        $('#instagram > ul').append($('<li/>').append($('<a/>').attr({
            'data-lightbox': 'ciao',
            'rel': 'lightbox',
            'href': va[i].images.standard_resolution.url,
            'title': va[i].caption.text
        }).append($('<img />').attr({
            src: va[i].images.thumbnail.url,
        }))));
    });
    return true;
};

サンプル

http://cramps.psychobil.ly/instagram.html

2013年10月31日木曜日

appspot sample

昔appspotで作ったまとめページ。

http://2channelbuster.appspot.com/

最初で最後のpython。

2013年10月28日月曜日

Googleトレンドのキーワードを元に2ちゃんを検索してまとめる#1

トレンド・キーワードを元に2ちゃんの記事を自動でまとめる(まとめてみた)

Googleトレンドを取得するrubygemsを作る


gemの雛形生成

なんとなくoreを使い続けているのでmineで生成。
gem名はpsychobilly-googleにした
sudo gem install ore
mine psychobilly-google --rubygems-tasks --bin --version=0.0.1

http://www.google.co.jp/trends/hottrends/atom/feed をパースしてオブジェクトに詰め込むのみのものを作成。
http://git.psychobil.ly/psychobilly-google

build

gem build psychobilly-google.gemspec

gemsサーバにupload

プライベートgemsサーバを用意したのでそこにuploadする
gem inabox psychobilly-google-0.0.1.gem --host http://gems.psychobil.ly/

インストール

gem sources -l | grep gems.psychobil.ly || sudo gem sources --add http://gems.psychobil.ly/
sudo gem install psychobilly-google

使用例

require 'rubygems' if RUBY_VERSION < "1.9"
require 'psychobilly/google'

Psychobilly::Google.getTrends.sort_by{rand}.each do |item|
  p item.to_s
end

2013年10月26日土曜日

nginx plus::statusモジュールを作る#4

repositoryをgithubからbitbucketに変更した。
変更した理由は独自ドメインが使えたから。
新repository -> git.psychobil.ly


deb packageに自作モジュールを組み込む

コーディングをしていると早く動かしたい衝動にかられることが多いので、nginx.orgが提供しているdebパッケージを元に自作モジュールを組み込む方法

ubuntu12.10

aptの設定

cat /etc/issue.net
Ubuntu 12.10
cat /etc/apt/sources.list.d/nginx.list
deb http://nginx.org/packages/ubuntu/ quantal nginx
deb-src http://nginx.org/packages/ubuntu/ quantal nginx
wget -O - http://nginx.org/keys/nginx_signing.key | sudo apt-key add -
sudo apt-get update

依存を解消するために一度インストールしておく

sudo apt-get install nginx

ソースコードをDLして組み込む

cd /path/to/work
apt-get source nginx
rm nginx_1.4.3*
cd nginx-1.4.3
git clone https://bitbucket.org/psychobilly/ngx_http_json_status_module.git
diff debian/{rules.orig,rules}
54c54,55
<               --with-ipv6
---
>               --with-ipv6 \
>     --add-module=./ngx_http_json_status_module
92c93,94
<               --with-debug
---
>               --with-debug \
>     --add-module=./ngx_http_json_status_module

diff debian/source/{format.orig,format}
1c1
< 3.0 (quilt)
---
> 3.0 (native)
build & install
sudo apt-get -y install libssl-dev libpcre3-dev zlib1g-dev
debuild -us -uc && debclean
sudo dpkg -i ../nginx_1.4.3-1~quantalubuntu2_amd64.deb
#5に続く

nginx plus::statusモジュールを作る#3

create main configuration

モジュール内のメインの設定用の構造体を生成する。


ngx_http_json_status_module.h


struct  ngx_http_json_status_main_conf_s {
  char            hostname[NGX_MAXHOSTNAMELEN];
  u_char          addr[16]; /* xxx.xxx.xxx.xxx\0 */
};
...
static void *ngx_http_json_status_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_json_status_init_main_conf(ngx_conf_t *cf);

ngx_http_json_status_module.c


  • ngx_http_json_status_module_ctxのcreate_main_confに構造体を生成する関数を指定
  • ngx_http_json_status_create_main_confでhostnameとip addressを取得してセットする
  • 今回はinit_main_conf使用しないけど一応用意しておいた

static ngx_http_module_t ngx_http_json_status_module_ctx = {
NULL,                              /* preconfiguration */
NULL,                              /* postconfiguration */

ngx_http_json_status_create_main_conf, /* create main configuration */
ngx_http_json_status_init_main_conf,   /* init main configuration */

NULL,                              /* create server configuration */
NULL,                              /* merge server configuration */

NULL,                              /* create location configuration */
NULL                               /* merge location configuration */
};
...
static void *
ngx_http_json_status_create_main_conf(ngx_conf_t *cf)
{
  ngx_http_json_status_main_conf_t *jsmcf;
  struct hostent *host;
  
  jsmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_json_status_main_conf_t));
  if (jsmcf == NULL) {
    return NULL;
  }

  if (gethostname(jsmcf->hostname, NGX_MAXHOSTNAMELEN) == -1) {
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "gethostname() failed");
    return NULL;
  }
  host = gethostbyname(jsmcf->hostname);
  if (host == NULL) {
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "gethostbyname() failed");
    return NULL;
  }
  ngx_sprintf(jsmcf->addr, "%d.%d.%d.%d",
        (BYTE)*(host->h_addr),
        (BYTE)*(host->h_addr + 1),
        (BYTE)*(host->h_addr + 2),
        (BYTE)*(host->h_addr + 3));

  ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "hostname:%s, address:%s", &jsmcf->hostname, jsmcf->addr);

  return jsmcf;
}

static char *
ngx_http_json_status_init_main_conf(ngx_conf_t *cf, void *conf)
{
  return NGX_CONF_OK;
}
#4に続く 

2013年10月22日火曜日

nginx plus::statusモジュールを作る#2

ヘッダファイルを追加

ヘッダファイルを作りたくなった場合configに一行追加する。
今回はngx_http_json_status_module.hを追加するのでconfigに以下を追加。
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/ngx_http_json_status_module.h"

ngx_command_t

ディレクティブの定義をした ngx_command_t 構造体は以下の様になっている。
typedef struct ngx_command_s     ngx_command_t;

struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};
set要素はname要素のディレクティブが設定されたときに呼び出される関数。

ngx_command_tのset要素:ngx_http_json_status

status; が設定されているときに呼び出す関数。
内部でhandlerを設定する。

ngx_http_json_status_module.h

static char *ngx_http_json_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

ngx_http_json_status_module.c

static char *
ngx_http_json_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
  ngx_http_core_loc_conf_t  *clcf;

  clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
  clcf->handler = ngx_http_json_status_handler;

  return NGX_CONF_OK;
}

handler:ngx_http_json_status_handler

status;が設定されたlocationにリクエストが来た時に実行される。

ngx_http_json_status_module.h

static ngx_int_t ngx_http_json_status_handler(ngx_http_request_t *r);

ngx_http_json_status_module.c

jsonで空データを返すところまで。
データを詰めてレスポンスを返すのはどれもこんな感じで実装している。
static ngx_int_t
ngx_http_json_status_handler(ngx_http_request_t *r)
{
  size_t       size;
  ngx_buf_t   *b;
  ngx_int_t    rc;
  ngx_chain_t  out;

  /* GET or HEAD only */
  if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
    return NGX_HTTP_NOT_ALLOWED;
  }

  /* request bodyは不要なので破棄する */
  rc = ngx_http_discard_request_body(r);
  if (rc != NGX_OK) {
    return rc;
  }

  size = sizeof("{}");

  b = ngx_create_temp_buf(r->pool, size);
  if (b == NULL) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  out.buf = b;
  out.next = NULL;

  b->last = ngx_sprintf(b->last, "{}");

  b->memory = 1;
  b->flush = 1;
  b->last_buf = 1;
  b->last_in_chain = 1;

  ngx_str_set(&r->headers_out.content_type, "application/json; charset=utf-8");
  r->headers_out.status = NGX_HTTP_OK;
  r->headers_out.content_length_n = b->last - b->pos;
  rc = ngx_http_send_header(r);
  if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
    ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "#return. %s:%d", __FUNCTION__, __LINE__);
    return rc;
  }

  return ngx_http_output_filter(r, &out);
}


repository


成果はここに置くことにした。


#3に続く

nginx plus::statusモジュールを作る#1

nginxの商用版nginx plusには魅力的な機能がありますが、個人利用ではお値段高め。
awsでインストール済みのイメージがある様なのでそれを使用してみるのも一つの手ではある。

もう一つの手として公開されている仕様を元に自作でモジュールを作ってしまう。

作ったものを公開するところまでやってみようと思った。

先ずはstatusモジュールから挑戦。

仕様は概ねこれをパクる。


雛形を作る

apacheの場合apxsで雛形が作れるのだけどnginxの場合は特に標準で用意されてなく、こういうのを作成している人が居たので使わせて頂く。
モジュール名はngx_http_json_status_module とする。
sudo gem install ngxmodgen
mkdir ngx_http_json_status_module
cd ngx_http_json_status_module
ngxmodgen -n json_status
tree
.
├── config
└── ngx_http_json_status_module.c

0 directories, 2 files

ディレクティブの設定

引数は取らないでlocation内にstatus;を記述すれば有効になるようにする。
ngx_http_json_status_module.cを編集。
static char *ngx_http_json_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
...
static ngx_command_t
ngx_http_json_status_commands[] = {
  {
    ngx_string("status"),
    NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
    ngx_http_json_status,
    0,
    0,
    NULL
  },
  ngx_null_command
};
仮にstatus on|off; で切り替えたい場合は以下の様にする。
static char *ngx_http_json_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
...
static ngx_command_t
ngx_http_json_status_commands[] = {
  {
    ngx_string("status"),
    NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
    ngx_http_json_status,
    0,
    0,
    NULL
  },
  ngx_null_command
};

#2に続く

2013年10月21日月曜日

aptサーバ構築::repreproのインストール(未完成)

プライベートaptサーバ構築手順

参照

http://davehall.com.au/blog/dave/2010/02/06/howto-setup-private-package-repository-reprepro-nginx

パッケージインストール

sudo apt-get install reprepro nginx 

ディレクトリ作成

sudo mkdir -p /srv/reprepro/{debian,ubuntu}/{conf,dists,incoming,indices,logs,pool,project,tmp}
sudo chown -R $USER /srv/reprepro/{debian,ubuntu}

gpg鍵生成

while : ; do echo xxx | mail $USER ; sleep 0.1 ; done

gpg --gen-key
...+++++
gpg: /home/$USER/.gnupg/trustdb.gpg: 信用データベースができました
gpg: 鍵E77D0B99を絶対的に信用するよう記録しました
公開鍵と秘密鍵を作成し、署名しました。

gpg: 信用データベースの検査
gpg: 最小の「ある程度の信用」3、最小の「全面的信用」1、PGP信用モデル
gpg: 深さ: 0  有効性:   1  署名:   0  信用: 0-, 0q, 0n, 0m, 0f, 1u
pub   2048R/E77D0B99 2013-09-20
                 指紋 = 6DE6 56D6 D208 F0EF 5FDD  B3A5 EB97 6907 E77D 0B99
uid                  $USER
sub   2048R/A7DFF5BF 2013-09-20

confファイル設定

cat /srv/reprepro/debian/conf/distributions
Origin: psychobilly
Label: psychobilly
Codename: squeeze
Architectures: i386 amd64 source
Components: main
Description: local repository
SignWith: E77D0B99 # 上で生成したgpgkey

cat /srv/reprepro/debian/conf/options
ask-passphrase
basedir .

リポジトリ準備/サンプルパッケージ登録

reprepro -Vb /srv/reprepro/debian export
reprepro -vb /srv/reprepro/debian includedeb squeeze sample-package.deb

loalhostでの設定

gpg -a --export E77D0B99 | sudo apt-key add -

remotehostでの設定

wget -O - http://remotehost/debian/signing.key | sudo apt-key add -

2013年10月13日日曜日

ubuntuにfessをインストール

特定のジャンルに特化した検索サイトを作りたくなり、ossの検索エンジン(http://fess.codelibs.org/ja/)を導入してみようと思い。

jreとその他ツールをインストールする

cat /etc/issue.net
Ubuntu 12.10

sudo apt-get update && sudo apt-get --yes --force-yes install openjdk-7-jre mysql-server-5.5 w3m

fessをダウンロードする

w3m http://sourceforge.jp/projects/fess/downloads/59462/fess-server-8.2.0.zip/
# または
# w3m http://sourceforge.jp/projects/fess/downloads/59462/fess-server-mysql-8.2.0.zip/

fessをインストールする

unzip fess-server-mysql-8.2.0.zip
cd fess-server-8.2.0/
chmod +x bin/*.sh
./bin/startup.sh

2013年10月1日火曜日

[mysql] databaseのcharacter変更

既存確認

mysql> status
...
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
...

Dbをutf8に変更

mysql> alter database {db_name} character set utf8;
mysql> status
...
Server characterset:    latin1
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8
...

2013年9月25日水曜日

non-interactive で /bin/sh を dash から bash に変更する方法

sudo sh -c 'echo "dash    dash/sh boolean false" | debconf-set-selections && dpkg-reconfigure --frontend=noninteractive dash'

プライベートIPアドレスのリストを抽出する

iprouteがない場合は入れる(debianの場合)


sudo apt-get install iproute


リスト抽出


ip -f inet -o addr show scope global | ¥
  sed 's/^.*inet \([0-9\.]\+\)\/[0-9]\+ .*/\1/' | ¥
  grep -E "^(10|172\.(1[6-9]|2[0-9]|3[0-1])|192\.168)\." | ¥
  sort -nr

2013年5月29日水曜日

ngx_array_tを使う

nginx moduleの開発をしていたときのメモ#1


nginx実装の配列ngx_array_tの使用例

使い方は、
  1. 配列の領域を確保する
    // ngx_str_t を10個保持する配列作成
    static void *
    ngx_sample_test(ngx_conf_t *cf) {
      ...
      ngx_array_t arr;
      if (ngx_array_init(&arr, cf->pool, 10, sizeof(ngx_str_t)) != NGX_OK) {
        return NULL;
      }
      ...
    

  2. 取り出して値を入れる
      // aにコピーして使う
      ngx_str_t *a;
      a = ngx_array_push(&arr);
      if (a == NULL) {
        return NULL;
      }
      ngx_memzero(a, sizeof(ngx_str_t));
      ngx_memcpy(a, コピー元, sizeof(ngx_str_t));
      ...
    

  3. 配列を回す
      // arr.eltsは配列のポインタ、arr.neltsは配列数を保持している
      // ngx_str_tを出力するときは %V を使う
      ngx_str_t *value;
      ngx_uint_t i;
      value = arr.elts;
      for (i=0; i<arr.nelts; i++) {
        ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "arr[%d]=%V", i, &value[i]);
      }
      ...
    

と意外と普通であった(もっと小難しいかと思っていた)。



2013年5月28日火曜日

stdoutに流れたログをチェックする

stdoutに流れたログをチェックするのはターミナルのスクロールバーで遡れば良いだけの話ですが、、
ここで一つ小技を。
tmux使っている前提で、"<prefix>+[" でコピーモードになる様なのだけど、emacsと同じ操作で上下左右自由に動ける。 
これは便利である。 

2013年5月7日火曜日

ngx_http_upstream_rr_peer_t 調査

nginxの構造体ngx_http_upstream_rr_peer_tはupstreamの情報を格納するのに使われている。
このメンバの ngx_str_t name; はupstreamのserver名を格納している。

ngx_str_tは
typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;
文字列と長さを格納している。

nginxをreloadするとこのname.dataにゴミが乗ることがある(version 1.2.8で確認)。
どこで混在するのか調べきれてないが、ngx_str_tのdataをそのまま信用するのは危ない感じである。
lenをチェックしてみたところlenは不正な値が入ることは無さそうで信頼できそうである。

これを踏まえて、ngx_str_tのdataを比較する場合は、単純にngx_strcmpだと上述のため危険であるので、
ngx_str_tのlenが同じ且つngx_strncmpで比較するのが正確そうである。

こんな感じのものを用意することにした。
int ngx_strtcmp(ngx_str_t *s1, ngx_str_t *s2) {
  if (s1->len == s2->len) {
    return ngx_strncmp(s1->data, s2->data, s1->len);
  }
  return ngx_strcmp(s1->data, s2->data);
}


2013年3月7日木曜日

nginxのupstreamでbackend serverをdns指定で登録した場合

nginxモジュールを作っていて気付いたこと proxyのbackendを例えば以下のように指定した場合
upstream backend {
 server yahoo.co.jp:80;
}
内部的には、vipで保持している。 上の例の場合だと以下の様な感じで保持している。
upstream backend {
 server 203.216.243.240:80;
 server 124.83.187.140:80;
}
nginx起動時に名前解決できないと落ちる理由が判明した。

2013年1月26日土曜日

cpu使用率制限

cpu使用率に制限をかけたい

cpuを馬鹿喰いするスクリプトをどうにか改善するためにあの手この手を尽くしたがどうしても改善せず。
niceやioniceでお茶を濁し、作り変えるには時間が無く途方に暮れていた。

何か使えるものは無いものかと探していたら、cpulimitなるものを発見。
眉唾かもしれないけど藁にもすがる思いで試したところ、cpu使用率に制限がかかる!
init scriptで起動したdaemonにcpulimitをかける様に修正して完了。

起動したdaemonにcpulimit(max10%)をかけるサンプル

cpulimit -p $(cat $PIDFILE) -l 10

2013年1月23日水曜日

cloudflareのACL

cloudflare 国単位でACLが掛けれるので便利。geoip要らず。



2013年1月3日木曜日

MySQLテーブル破損

いきなり壊れた。
プロセス監視だけでは対処できないトラブル。

エラーログ

130103 12:47:59 [ERROR] /usr/sbin/mysqld: Table './XXX/YYY' is marked as crashed and last (automatic?) repair failed

対処方法

mysql -uXXX -pYYY
mysql> repair table YYY;
mysql> unlock tables;