• Android Expansion files(拡張ファイル) アップロード

    拡張ファイルのアップロード方法がわかりません。
    Devleloper Consoleのヘルプを見ると

    注: 現在のところ、新しい Google Play デベロッパー コンソールの制限により、新しいアプリをアップロードする最初の APK ファイルに拡張ファイルを追加することはできません。この問題を回避するには、まず APK ファイルのみをアップロードし、必要に応じて拡張ファイルを追加した APK ファイルで置き換えてください。これらの操作はドラフト状態の APK でも行えますので、既存ユーザーや潜在ユーザーに影響が及ぶことはありません。

    どうやら拡張ファイルを追加できない事はわかります。しかし回避するための方法がわかりません。
    「拡張ファイルを追加したAPKファイルで置き換えてください」?
    それじゃあ、APKと拡張ファイルが一体化しているじゃないですか!

    頑張って調べてみると

    http://stackoverflow.com/questions/15109191/how-to-upload-apk-expansion-files-in-new-developer-console

    がヒット。

    it’s a dummy apk. When you first upload your apk you will not have any option for the expansion files. From second apk onwards you will have that option. It looks weird

    ...
  • TortoiseGit + GitHub + port 443

    TortoiseGitとGitHubで快適にGit生活を送っていたのですが、ある日突然pullできなくなりました。
    どうも GitHubとの22番ポート経由での通信ができなくなった模様。

    なぜ?

    22番といえばsshのポート。AWS上のサーバーにもガシガシsshしているので、社内ネットワークの
    どこかで閉じているとは考えられません。GitHub側から締め出しをくらったのかなぁ?
    仮にも有料プランユーザーなのにそんなことあるの??

    結局原因不明ながらも 443番ポート経由で通信するように環境を変更することで対応しました。
    TortoiseGitとGitクライアントはインストールされている前提です。

    インストール方法は以下にとっても良くまとまっています。

    TortoiseGitを日本語化するまでの手順

    - ssh クライアントを切り替える

    0 右クリックしコンテキストメニューを開き、そこからTortoiseGitの設定を開きます。

    1
    左ペインのネットワークを選択し、右ペインに表示されたsshクライアントが以下でなければ変更します。

    C:\Program Files (x86)\Git\bin\ssh.exe

    - 鍵を再作成する
    TortoiseGitを使っている場合おそらく標準であろうTortoisePlink.exeをSSHクライアントに設定している場合
    証明書に自動的にパスフレーズが設定されるらしく他のsshクライアントでは再利用できないので、再作成します。

    2
    $ ssh-keygen -t rsa -C “メールアドレス”

    - GitHubに公開鍵を登録する

    3
    GitHubのサイトに行き先程作成した公開鍵(*.pub)の内容をコピペします。

     

    - ssh設定ファイルを作成する
    以下のファイルを作成します。

    ...
  • CloudFormationを使いredmineのインスタンスを起動する

    おはようございます。インフラの宮下です。

    社内向けredmineが古いのでリプレイスを検討しています。
    できるだけ手間をかけずに検証環境を用意したいと思い、AWSのcloudformationを使って
    redmineを用意してみました。


    目次

    1. はじめに
    2. CloudFormationでインスタンスを作成する
    3. インスタンスが起動してからの設定

    はじめに

    現在稼働しているredmine環境が物理サーバにバージョンがRedmine 1.1.2.stable (MySQL)ととても古いので最終的には入替まで実施したいと思います。

    CloudFormationでインスタンスを作成する

    ManagementConsoleからCloudformationの画面を開きます。
    「Create Stack」で新規作成を開始します。

    ・Name→管理しやすい名前を自由につける。

    ・Template→Use sample templateの中のSingleInstanceSamplesの中から「Redmine Project Management System」を選ぶ。
    ※検証環境なので今回は最小化された構成で構築します

    「Next Step」で次に進みます。

    Specify Parametersにそれぞれ値を入れていくのですが、デフォルトではkeyを指定する事ができませんでした。

    という事で一旦「Back」で戻ります。

    amazonが公開している下記のテンプレートをローカルPCに保存します。
    https://s3.amazonaws.com/cloudformation-templates-us-east-1/Redmine_Single_Instance.template
    サンプルとの違いは、KeyNameの定義が入っているだけですのでSSHログインしないというのであれば
    この作業は不要です。

    [shell](8行目) “KeyName”: { “Description” : “Name of an existing EC2 KeyPair to enable SSH access to the instances”, “Type”: “String”, “MinLength”: “1”, “MaxLength”: “255”, “AllowedPattern” : “[\\x20-\\x7E]*”, “ConstraintDescription” : “can contain only ASCII characters.” },

    ...
  • SSHでforced-commands-onlyを使ってVIPを付けてみる

    おはようございます。インフラの宮下です。

    今回は端末機からサーバの仮想IPを付けたり削除する時のSSH設定に関する手順です。
    MHAの内部でIPをfailoverする所をお手製で実施するイメージです。

    SSH接続でroot権限を実行する方法としては、

    ・rootで公開鍵認証が出来るようにする。
    ・ログインユーザがsudo出来るようにしてrootにスイッチする。
    ・rootで特定のコマンドだけ実施出来るようにする。

    の3通りありますが、今回はセキュリティレベルがそんなに変わらない3番目の方法を適用したいと思います。
    既にsudo出来る環境なら良かったのですが、sudoできない環境なのでforced-commands-onlyを使用します。

    作業環境は以下の通りです。

    接続元のOS:SunOS test 5.10 Generic_147440-19 sun4v sparc sun4v
    →端末機と呼びます
    接続先のOS:Red Hat Enterprise Linux Server release 6.2 (Santiago)
    →サーバ呼びます

    今時珍しいsolarisが端末と言う事でレトロ感満載の環境と言う事はお察し下さい。

    (端末機の設定)

    ・ログインするユーザの公開鍵を作成します。コマンド毎に鍵を分けるので2個用意します。

    [shell]# ssh-keygen -t rsa -N "" -f ~/.ssh/ipadd_command 公開/非公開 rsa 鍵のペアを生成しています。 識別情報が /export/home/test/.ssh/ipadd_command に保存されました。 公開鍵が /export/home/test/.ssh/ipadd_command.pub に保存されました。 鍵のフィンガープリント: 80:1e:4f:8b:2a:0d:22:fb:e2:c7:22:75:70:ef:db:a2 test@test

    ...
  • 要素が1つしかない連想配列のネストを解消する

    WordPress関数(特に$wpdbクラスなどに多い。get_results()メソッドでDBの値をとって来たときなど)を使っていて、戻り値の配列が一つしか要素持ってないのに連想配列になっていたりする場合、値を取り出すときにネストしたループ処理を書くケースが結構ある。 以前からコード的に冗長で非効率だよなぁ…と思っていて、今回改善方法を見出してスッキリしたので、ここにTIPSとして残しておこうかと。

    $array = array(
        array(
            'key_1' => 'value_1', 
            'key_2' => 'value_2', 
        ), 
    );
    
    foreach ($array as $nested_array) {
        foreach ($nested_array as $key => $value) {
            echo 'array["' . $key . '"] => "' . $value . '"<br />';
        }
    }
    

    今まではこんな感じに(無駄ではないのだが、効率的ではない)foreachループを連想配列の入れ子分回して値取ってた…。 で、この連想配列とループのネストを解消してシンプルに処理を書けないものか…とPHPのarray関数を色々と試してみた。array_reduce()とかarray_walk()とかあんまり使わない関数で、独自にネスト解消用の関数組んでもできるんだが、別途独自関数用意しなきゃならなくてまるでスマートでない…。なんかスパっと1ラインで解決できないかと試行錯誤してみたところ、ありました! array_shift()で先頭要素取得して元の配列変数を上書きしてしまえばいいのです。

    $array = array_shift($array);
    

    たったこれだけ(笑) でも、これだけだと配列の要素数が1つ以上でも上書きしてしまうので、要素数の判定を入れておく。

    $array = (count($array) == 1) ? array_shift($array) : $array;
    

    最初のコードをこのコード使って書き直してみると、

    ...
  • InternetExplorer11で変更されたUserAgent書式に対応する

    今まで問題なく稼動していたとあるシステムにて、InternetExplorer11(以下IE11)のブラウザにて不具合が発生する旨の報告を受けて調べたところ、IE11ではユーザーエージェントの書式が変更になっていて、ブラウザ判定処理が「不明なブラウザ」として処理されていたことがわかった。
    今までユーザーエージェントのブラウザバージョントークン(UAの"MSIE 9.0"とか書いてある部分)でIEブラウザの判定とIEバージョンを取得していたのだが、IE11からはこのブラウザバージョントークンがなくなってしまい、新たに"rv"というリビジョントークンが設けられてました(※IE11標準ブラウザモード)。
    今後IE11を含めてユニークにIEを判定するには、ブラウザエンジンであるトライデントトークン(UAの"Trident/7.0"とか書いてある部分)の存在確認もOR条件で判定しないといけなくなった。

    IE11のUserAgent

    • [ブラウザモード:標準] Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko
    • [ブラウザモード:互換表示] Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0)

    問題なのが、IEの互換表示モードだ。IEの互換表示モードはIE9から導入された機能だが、このモードにすると現状の全てのIEにおいてUAのブラウザバージョントークンがIE7となってしまう。互換表示の際についても正確にIE11と判定させるには、まずトライデントトークンを先に判定して、トライデントのバージョンが7.0以上だったらIE11として判定しリビジョントークンからブラウザバージョンを取得し、それ以外はブラウザバージョントークンからバージョンを取得するという処理にする必要がある。さらにIE11より下位の互換表示モードをもつIE9とIE10用の処理も必要だ。
    また、IE7以下はトライデントトークンを持っていないので、IE7用の判定処理も別途必要となる…(いやはや、まるで嫌がらせのような仕様だな…)。

    試しにこのDEVLABで利用している独自のクライアントデバイス判定処理(PHP)で、IE11にも対応した判定処理に修正してみた。

    まずは、今までのIE判定処理内容。
    [php] $ua = $_SERVER[‘HTTP_USER_AGENT’]; $results[‘browser’] = ‘’; $results[‘version’] = ‘’; if (preg_match(’/(MSIE \d{1,}?(.\d{1,}?){1,}?;)/’, $ua, $mtcs)) { $results[‘browser’] = ‘msie’; list(, $vstr) = explode(’ ‘, str_replace(’;’, ‘’, $mtcs[0])); $results[‘version’] = $vstr; } [/php]

    ...
  • Android アプリに設定されたパーミッションを取得する

    もしmanifestに設定されていないパーミッションが必要な機能を使うと無慈悲なSecurityExceptionが発生します。
    それはもう、catch節をスルーするくらい無慈悲です。
    
    このExceptionが発生するという事は、manifestとコードが不一致だということなので、コード直せボケ!
    なのかもしれませんが、やはりコード内でパーミッションをチェックして条件分岐したい事もあるものです。
    例えばライブラリとして公開する場合とか。
    
    そんなわけで、パーミッションのリストを取得するメソッドと、お目当てのパーミッションがmanifestに存在するのか確認するメソッドをお届けします。
    [code lang="java" light="true"]
       /**
         * 指定されたパーミッションがmanifestに記載されているかどうか確認します。
         * 
         * @param checkPermission 調査するパーミッション
         * @param context コンテキスト
         * @return true:記載されている /false:記載されていない
         */
        public boolean hasPermission(String checkPermission, Context context) {
            if (checkPermission == null || context == null) {
                // 引数が渡されていないケース
                return false;
            }
            String[] requestedPermissions = getPermissionList(context);
            if (requestedPermissions == null) {
                // manifestに一件もpermissionが設定されていないケース
                return false;
            }
            for (String str : requestedPermissions) {
                if (str.equals(checkPermission)) {
                    // 調査するパーミッションが存在したケース
                    return true;
                }
            }
            // 調査するパーミッションが存在しなかったケース
            return false;
        }
    
        /**
         * manifestに記載されているパーミッションのリストを返します。
         * 
         * @return パーミッションのリスト
         */
        public String[] getPermissionList(Context context) {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = null;
            try {
                packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
            } catch (NameNotFoundException e) {
                return null;
            }
            return packageInfo.requestedPermissions;
        }
    [/code]
    
    
    
    
    使い方
    
    [code lang="java" light="true"]
    String checkPermisson = "android.permission.READ_PHONE_STATE";
    
    if (hasPermission(checkPermisson, context)) {
        Log.d("TAG", checkPermisson + " exist!");
    } else {
        Log.d("TAG", checkPermisson + " not exist!");
    }
    [/code]
    
    
    
    お役に立てば。
    
    ...
  • GitHubでpush時にAWS OpsWorksで自動デプロイする方法

    開発の平形です。

    今日は、GitHubでpush時にAWS OpsWorksで自動デプロイする方法をお教えします。

    OpsWorksはAWSで提供されているデプロイのサービスです。

    *OpsWorksについては、こちらのサイトが詳しいです。

    この話は、OpsWorksにスタックとレイヤとインスタンスが存在する前提です。

    OpsWorks自体、最近触ったばかりですが、
    デプロイがすごく簡単にできるという事はよくわかりました。

    でも、欲張りな僕は、もっと自動化できないのかな?と思ったのです。

    普段、ソースはGitHubでバージョン管理しているので、
    GitHubにpushしたら同時にデプロイできないのかな?と。

    そしたら、ビックリするほど簡単に実現できました。

    GitHub側で設定が可能です。
    アプリケーションのリポジトリのページの「Settings」

    bigplants_opsworks-demo-php-simple-app-2

    「Service Hooks」

    Options

    AWS OpsWorks

    Service_Hooks-2

    以下の項目は全て必須なので、全部入力します。

    Service_Hooks-4

    ここで、OpsWorks側の情報が必要になります。

    まずは、Stack Idですが、一見これがわかるところが、AWS Managed Consoleの画面上にはありません。
    手っ取り早くこれを確認する方法はStackの画面のURLをみる事です。

    Stack_-_ops_stack_01_–_AWS_OpsWorks_と_Bootstrap_101_Template-7

    次にApp Idですが、同じくOpsWorksの画面で、「Apps」=>「アプリケーション名」をクリック

    Apps_-_ops_stack_01_–_AWS_OpsWorks-5

    OpsWorks IDがApp Idです。

    ...
  • redisのソースインストール(chef-solo)

    こんにちは。opsのほうの小宮です。
    redisのソースインストールをご依頼いただきCHEF-SOLOったのでその記録をのこしておきます。

    ★要件
    バージョンについては2.8.4でお願いします。(2014/1時点で最新のソース)

    ★以下作業
    ・rpmで入るバージョンの確認(※同環境のサーバでyumで確認)
    redis.x86_64 0:2.4.10-1.el6

    ※要件に合わないためソースインストールする必要がある

    ・chef-soloの下準備

    [shell]$ ssh-copy-id -i ~/.ssh/id_dsa.pub server2 $ ssh-copy-id -i ~/.ssh/id_dsa.pub server1

    $ knife solo prepare server1 $ knife solo prepare server2[/shell]

    ・role作成
    [shell]$ vi roles/rankingAPI.json { “name”:“rankingAPI”, “chef_type”: “role”, “json_class”:“Chef::Role”, “default_attributes”:{ “base_setting”: { “swappiness”: “0”, “tcp_tw_reuse”: “0”, “tcp_tw_recycle”: “0”, “tcp_fin_timeout”: “10”, “tcp_max_syn_backlog”: “8192”, “somaxconn”: “8192”, “ntpserver1”: “ntp.nict.jp” } }, “override_attributes”:{}, “description”:“rankingAPI’s role”, “run_list”: [ “recipe[roles::rankingAPI]” ] }

    ...
  • gitでクローンと同時にサブモジュールを初期化、アップデートする

    こんにちは。
    開発の平形です。

    初投稿になります。

    Gitでcloneした後に、何かが足りなくてうまく動かない事がよくあります。

    そして気づくのです。

    あ、submoduleをクローンしてねーじゃん!
    ※submoduleについてはこちらの記事が参考になります。

    このパターン何回目だよ!
    と自分が嫌になってしまいます。

    そしていつも、

    git clone git://github.com/foo/bar.git
    git cd bar
    git submodule update --init --recursive
    

    といったお決まり作業をする訳です。
    でもついつい忘れてしまうんですよね。

    で、調べてみるとちゃんとあるんですね。

    git clone --recursive git://github.com/foo/bar.git
    

    これで、クローンと同時にサブモジュールもクローンされます。
    通常のクローンと使い分ける必要も特にないので、これからはこれを使っていこうと思います。

    読んでいただいてありがとうございました。

    まだまだ、寒い日が続いておりますが、お体にご自愛くださいませ。

    参考にしたページ

    http://stackoverflow.com/questions/3796927/how-to-git-clone-including-submodules

    ...
  • cpuコア数に応じたrps_cpusに入れる値の計算方法

    こんにちは。OPSのほうの小宮です。
    cpuコア数に応じたrps_cpusに入れる値の計算方法です。

    ネットワークの割り込み処理を複数コアに分散したいという要望がありまして。(特にキャッシュサーバ)

    できる人に頼って、ここ↓まで頑張ってもらいました。

    [shell]# core=1 # echo “obase=16; ibase=10; $(( 2 ** ${core})) -1” | bc | tr ‘[A-Z]’ ‘[a-z]’ 1 # core=2 # echo “obase=16; ibase=10; $(( 2 ** ${core})) -1” | bc | tr ‘[A-Z]’ ‘[a-z]’ 3 # core=4 # echo “obase=16; ibase=10; $(( 2 ** ${core})) -1” | bc | tr ‘[A-Z]’ ‘[a-z]’ f # core=5 # echo “obase=16; ibase=10; $(( 2 ** ${core})) -1” | bc | tr ‘[A-Z]’ ‘[a-z]’ 1f[/shell]

    ...
  • Mondo Rescue使ってみました(その2)

    おはようございます。インフラの宮下です。

    前回「Mondo Rescue」で取得したバックアップデータを使用して、レストアするまでを紹介します。


    目次

    1. はじめに
    2. レストア実施
    3. 参考サイト

    はじめに

    バックアップをとるまでは実行しますが、物理環境だとレストアまではなかなか検証する環境が無いので最初にしっかりとレストアしておくのが賢明だと思います。クラウドはその辺いいですね~♪

    バックアップをNFS先に出力した方がMondo Rescueぽいですが、今回はネットワーク環境の都合と作業時間が限られていた為に
    ローカル出力してDVDメディアからレストアする方法を選択しました。

    前回作成したしたisoイメージをDVDに書き込んでおきます。
    DVDへの書き込みですが、私は昔からDeepBurnerを愛用しています。

    DeepBurner

    レストア実施

    DVDメディアを挿入して、サーバを起動します。
    mondoのOSが立ち上がってきたら「boot:」プロンプトが出てきますので下の中から方式を選択します。

    nuke全自動でリストア。ただ見てるだけで終わります。元データは完全に消去されるので注意は必要。
    interactive対話形式でリストア。カスタマイズやNFS上のISOを指定する時に選択します。
    expertシェルプロンプトを起動する。fdiskとかも実施する場合はこちらで。

    [shell] boot: nuke [/shell]
    今回は全て自動でレストアします。実際「nuke」を入力する以外に何もする事はありませんでした。
    DVDメディア1枚(約4GB)なら30分もあればレストアまで完了しました。

    DVDドライブの書き込み速度が24倍速だと、全ての工程が1時間くらいで終わります。

    今後の使い方ですが、ISOデータをAWSで保管するとか
    クラウド上での利用方法(AMI作れるからプライベート上)とか
    その他の商用ソフトとの比較も実施してみたいです。

    AWS Storage Gateway

    また、「Mondo Rescue」はUNIXに対応していないのでSolarisでufsdumpの他にもっと快適にできる
    方法も探したいと思います。

    参考サイト

    Mondo rescueを用いたシステムリカバリの方法
    Mondo Rescueのバックアップデータをリストアするには
    Mondo Rescue

    ...
  • DEVLABをリニューアルしました

    2014年 明けましておめでとうございます。

    年末年始の休暇を利用してDEVLABのサイトリニューアルを行いました。

    何気に3回目のリニューアルなのですが、今回はWordPressのテーマ自体を新しく作り直したので結構大規模リニューアルになりました。正月の後半は半ば家族サービス放棄で連日徹夜気味に作業してました・・・(笑)

    また、今回のリニューアルタイミングにてWordPressも3.7.1へアップグレードしました。実は年末にバージョン3.8も出ていたのですが、まだ日本語ローカライズ版は提供されていないので、最新安定版の3.7.1までとしてあります。

    昨年は多忙にかまけて投稿機会を逸してなかなか投稿数が伸びなかった私maenoですが、今年は心機一転して色々と投稿して行きたいと思いますので、本年もDEVLABともども弊社デベロッパーメンバーをよろしくお願いいたします。

    ...
  • MySQLでALTER TABLEでINDEXを作成するときの注意事項

    こんにちは。Ops側の小宮です。
    ある日朝来たら突然開発の方から相談いただいたので、後のために記録しておこうと思います。

    相談内容:
    jenkinsで本番デプロイを行ったが、処理を途中停止した。
    (CakeのDBマイグレーションスクリプトでデプロイした)
    KEYカラムにINDEXをはろうとしたがDBの応答がなくなり接続できなくなった。
    結果としてテーブルが破損したためRDSの時刻指定してロールバックする機能を用いた。
    (ALTERが終わってたかどうかとかはロールバックしたので不明)
    同じレコード数の試験環境で同じ操作をしたら特に異常なくすんなり終わった。
    もう一回同じことを本番でやりたいけどどうしましょう。
    MySQLのバージョンは5.5.27。

    私の個人的認識:
    普通、ALTERする時はロックがかかるから、
    事前に同じ構成と件数の試験環境でかかる時間を見積もってから
    その時間サービス止めてメンテ入れるべきです。
    (※5.5まで。5.6から一部のALTERはオンラインで大丈夫になったようです。)
    sorry表示に切り替えて更新のない環境でやってみましょう。
    (既存のELBの下のwebを全部はずして、別のサブドメインのwebにvhost切ってsorryコンテンツおいてELBに入れるとか)
    途中で強制終了とかするとMyISAMだとテーブル壊れやすそう。
    show full processlist;で現在のクエリとかかってる時間は見ることができる
    けどkillするのは最終手段かと。

    alter table mysqlとか、それプラス5.6とかでググると色々わかります。

    sh2さんのブログを見ると、以下のように書かれています。
    MySQLでALTER TABLE文の進捗状況を確認する - SH2の日記
    -————— MySQLでは
    変更後の定義にもとづく作業用テーブルを作成し、
    変更前のテーブルから作業用テーブルへデータをコピーして、
    最後に二つのテーブルを入れ替えるという仕組みになっています。
    テーブルへのインデックス追加についても、現在のところ大半の
    ケースで内部的にALTER TABLE文が実行されています。

    どこまですすんでるのか確認する方法:
    SHOW GLOBAL STATUS LIKE ‘Handler_write’;
    作業開始前にHandler_writeの値と対象テーブルのレコード件数を控えておけば、
    どこまで処理が進んだのかを確認することができるのです。

    InnoDBならinnotopをつかうと、row operationsのビューにズバリIns/Secがあるので、
    同様にしてALTER TABLEの完了予想が立てられますね。
    差を自分で計算しなくてもいいし、標準的なツールなので便利
    -—————

    ...