2017年8月8日火曜日

linker command failed with exit code 1が出た時の解決方法案

どうも、俺です。

Xcodeで開発してて目にすると1時間はその解決に費やしてしまうこともある地獄のエラー文言。
そう、それが
linker command failed with exit code 1


※Xcode 8.3.3

今日はこのエラーが出た時「これやったら直った」というあらゆる手段をお伝えします。


■プロビジョニングプロファイルは正しく設定されているか

人により設定方法は様々ですが、僕の場合、
・General>SigningにあるAutomatically manage signingのチェックをはずす

・Build Settings内、
 ProvisioningProfile (Deprecated)とProvisioning Profileの2箇所に適切なプロビジョニングプロファイルを設定。
 Code Signing Identityに正しい証明書を設定。
 最後にDevelopment Teamにチーム名を設定。

としています。
このミスの際は、ちゃんと「プロビジョニングプロファイル間違えているよ」というエラーが出ることが多い...。


■Enable Bitcodeの設定を間違えていないか

Build Settings>Build Options内にあるEnable Bitcodeが「Yes」になっているとアカン場合がある。
組み込んだフレームワークがbitcodeとやらに対応していないかもしれないので、速攻「No」に設定し直す。




■存在しないリソース(画像etc)を取り入れようとしていないか

Build Phases>Copy Bundle Resources内に存在しないリソースがないか要チェック。
無いものが含まれている場合は削除します。



■Deployment Targetを間違えていないか

General>Deployment InfoにあるDeployment Targetに無茶な値を入れていないか。
古すぎるターゲットなどに設定している場合は、よく考えて適切な値にします。



■Info.plistの設定Target Membershipは大丈夫か

Info.plistを選択してTarget Membershipにチェックが入っているとアウト。
チェックを外します。



■Xcodeを再起動しよう

この方法を使うと90%の確率でビルドが成功します。
試してみる価値あり。



■Mac本体ごと再起動しよう

この方法を使うと50%の確率でビルドが成功します。
試してみる価値あり。




上記以外でこのエラーの対処方法があれば教えてください。


※※※2017.08.18追記
このエラーが出た時に詳細ログが見れないのでモヤモヤしてたのですが、ログを見る方法が分かりました!
command+8 !!
LogNavigatorというやつらしいです!
これで具体的にエラー内容確認できます!


以上でぇぇぇぇす。

2017年5月1日月曜日

Macでgem installしたら "Operation not permitted" エラー

どうも、俺です。

 Mac(Sierra)でターミナルから
$ sudo gem install XXXX

とコマンドを打つと
Password:
ERROR:  While executing gem ... (Errno::EPERM)
    Operation not permitted - /usr/bin/XXXX
というエラーが出る場合の対処法。

以下のようにすればOK。
$ sudo gem install -n /usr/local/bin XXXX
これは、インストールディレクトリを
/usr/bin
から
/usr/local/bin
へ変更してインストールを行います。


MacのrootlessというSystem Integrity Protection(rootless)という機能があり、
/System
/bin
/usr
/sbin
フォルダ以下にファイルを作成できないという仕様のためです。

他にもrootlessを無効にする方法もありますが、セキュリティ的に望ましくはないので割愛します。


以上でぇぇぇぇぇす。

2017年3月13日月曜日

php: error while loading shared libraries: libpq.so.5: cannot open shared object fileが出る

どうも俺です。

構築したばかりのサーバーで
$ php -v
と打ってphpのバージョンを確認しようとしたら、

php: error while loading shared libraries: libpq.so.5: cannot open shared object file: No such file or directory
というエラーが出ちゃいました。

エラー内容のとおり、
何かしらの共有ライブラリ(今回はlibpq.so.5)が読み込めないというエラーです。

ちなみにrootになって同じコマンドを打つと

# php -v
PHP 5.6.24 (cli) (built: Mar  2 2017 15:32:45) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
と問題なく実行されます。
つまり、今回のエラーは何かしらのPermissionが関係してるだろうと予想つきました。

こういう場合は共有ライブラリの依存関係を確認してみます。

$ ldd /usr/local/bin/php
        linux-vdso.so.1 =>  (0x00007ffda23d7000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f2982411000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f29821fa000)
        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f2981fe0000)
        libpq.so.5 => not found
        librt.so.1 => /lib64/librt.so.1 (0x00007f2981dd7000)
        libcurl.so.4 => /lib64/libcurl.so.4 (0x00007f2981b6e000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f298186c000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f2981667000)
        libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f298144e000)
        libxml2.so.2 => /lib64/libxml2.so.2 (0x00007f29810e4000)

注目すべきは、libpq.so.5 => not found となっているところです。


今度はrootになって確認してみます。

# ldd /usr/local/bin/php
        linux-vdso.so.1 =>  (0x00007ffce4d60000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f0d05ff1000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f0d05dda000)
        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f0d05bc0000)
        libpq.so.5 => /usr/local/pgsql/lib/libpq.so.5 (0x00007f0d05997000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f0d0578e000)
        libcurl.so.4 => /lib64/libcurl.so.4 (0x00007f0d05525000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f0d05223000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f0d0501e000)
        libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f0d04e05000)

今度は libpq.so.5 => /usr/local/pgsql/lib/libpq.so.5 と表示されました。

ということで/usr/local/pgsqlディレクトリを確認してみます。


$ ls -l /usr/local
drwxr-xr-x   7 root     root       62  3月  2 15:44 bin
drwxr-xr-x.  2 root     root       22  7月 29  2016 etc
drwxr-xr-x.  2 root     root        6  8月 12  2015 games
drwxr-xr-x.  3 root     root       16  7月 29  2016 include
drwxr-xr-x.  3 root     root       30 12月  6 15:26 lib
drwxr-xr-x.  2 root     root        6  8月 12  2015 lib64
drwxr-xr-x.  2 root     root        6  8月 12  2015 libexec
drwx------   6 postgres postgres   52  3月  2 14:41 pgsql
drwxr-xr-x   3 root     root       16  3月  2 15:33 sbin
予想通りpgsqlユーザーのみ読み書きできる状態になってしまっていました。

適切に権限を追加して完了。




以上でぇぇぇぇす。

2017年3月1日水曜日

公開鍵認証を使い、sshで2段階ログイン(多段ログインもできちゃう)

どうも、俺です。

今日は、
~/.ssh/config
を使って、2段階先のサーバーへsshログインする方法をメモ。

<クライアント> → <サーバーA(192.168.0.2)> → <サーバーB(192.168.0.3)>
のように接続する際に

$ ssh サーバーB
と打てばサーバーBへsshログインできます。

(1) .ssh/configを編集


$ vim ~/.ssh/config

Host <サーバーA>
  HostName 192.168.0.2
  User ユーザー名
  Port 22
  IdentifyFile ~/.ssh/serverA_id_rsa

Host <サーバーB>
  HostName 192.168.0.3
  User ユーザー名
  Port 22
  ProxyCommand ssh -W %h:%p <サーバーA>
  IdentifyFile ~/.ssh/serverB_id_rsa

※クライアント側のPCにはサーバーAとサーバーBの認証鍵
~/.ssh/serverA_id_rsa
~/.ssh/serverB_id_rsa
があることが前提です。

(2) ログインする

$ ssh サーバーB

複数先のサーバーへログインする場合は、
上記の.ssh/config内に踏み台にするサーバーをドンドン追記していけばOKです。


以上でぇぇぇえぇぇす。

2017年2月20日月曜日

LumenでPHPのerror_reporting(エラーレベル)を設定する

どうも、俺です。

Lumenはデフォルトで全てのエラーが出力されます。
本番環境では出力されるエラー内容を設定したいのですが、その場合は、

$ vim /PATH/TO/vendor/laravel/lumen-framework/src/Concerns/RegistersExceptionHandlers.php
を開き、


    protected function registerErrorHandling()
    {   
        error_reporting(-1);

        set_error_handler(function ($level, $message, $file = '', $line = 0) {
            if (error_reporting() & $level) {
                throw new ErrorException($message, 0, $level, $file, $line);
            }   
        }); 

        set_exception_handler(function ($e) {
            $this->handleUncaughtException($e);
        }); 

        register_shutdown_function(function () {
            $this->handleShutdown();
        }); 
    }   
にある、error_reporting(-1)を変更します。

本番の場合は「何も出力しない or 重大なエラーだけ出力」、で良いと思うので、

  // 何も表示しない
  error_reporting(0);

  // 重大な実行時エラーを出力
  error_reporting(E_ERROR);

になります。


以上でぇぇぇぇぇぇす!

2017年2月9日木曜日

Lumenでcron処理

どうも、俺です。

Lumen(多分5.3.1)でcronプログラムを作って登録する方法について。
おそらくLaravelはもうちょっと楽に出来そうですが、基本は同じはず。


Laravelの公式HP参照

【手順1】app/Console/Commands/以下にphpファイルを作成


$ vim app/Console/Commands/MyScript.php

内容は以下のような感じ。

<?php
namespace App\Console\Commands;

use Illuminate\Console\Command;

class MyScript extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'my_script_signature';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // ここに処理を書く
        echo "HELLO!\n";
    }
}


【手順2】app/Console/Kernel.phpに登録


$ vim app/console/Kernel.php

内容は以下。

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        // ここに作成したコマンドクラスを追記していく。
        \App\Console\Commands\MyScript::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // ここに実行させたいコマンドクラスのシグネチャを記す。
        $schedule->command('my_script_signature')->cron('* * * * * *');
    }
}

【手順3】動作を試してみる


$ php artisan my_script_signature
HELLO!

問題なし!

【手順4】cronに登録する


* * * * * php /path/to/artisan schedule:run 1>> /path/to/cron.log 2>&1

これで定期的に処理をさせることが出来ます。



以上でぇぇぇぇす!

2017年2月8日水曜日

pgpool-2のオンラインリカバリを試す

どうも、俺です。

pgpool-2でオンラインリカバリを試したのでその方法をメモ。
若干ややこしかった...。

【環境】
・postgresql v9.5.3
・pgpool-2 v3.5.4
・ノード1のあるサーバー 192.168.0.1
・ノード2のあるサーバー 192.168.0.2
・pgpool-2のあるサーバー 192.168.0.1
※PostgreSQLとpgpool-2はすでに稼働中とします。
※pgpool-2の公式HP参照


手順1) C言語関数インストール

各ノードのPostgreSQLデータベースに関数をインストールします。
すべてのノードのあるサーバーで以下を行います。

# su - postgres
% cd /path/to/pgpool-II-3.5.4/src/sql/pgpool-recovery
% make install
% psql -p ポート番号 -f pgpool-recovery.sql template1 


手順2) pgpool.confの設定

オンラインリカバリを行うための設定を追加します。

# vim /path/to/pgpool/etc/pgpool.conf

--- 以下pgpool.conf内容 ---

# PCPの設定
pcp_listen_addresses = '*'
pcp_port = 9898
pcp_socket_dir = '/tmp'

# リカバリを行うPostgreSQLのユーザとパスワード。
recovery_user = 'postgres'
recovery_password = 'postgres'
# オンラインリカバリを実行するスクリプト名。
recovery_1st_stage_command = 'recovery_1st_stage.sh'
recovery_2nd_stage_command = 'recovery_2nd_stage.sh'
# オンラインリカバリのタイムアウト秒数。
recovery_timeout = 120 
# リカバリ中にアイドル状態のクライアントを何秒で切断するか。0は無効。-1は即時切断。
client_idle_limit_in_recovery = 1 


手順3) postgresql.confの設定

archive_logを取るように設定します。
既に設定済みであれば不要です。

# vim /path/to/pgsql/data/postgresql.conf

--- 以下postgresql.confの内容 ---

archive_mode = on

# /usr/local/pgsql/data/archive というディレクトリ以下にarchive_logがコピーされる
archive_command = 'cp %p /usr/local/pgsql/data/archive/%f'


手順4) リカバリスクリプトの作成

・recovery_1st_stage.sh
・recovery_2st_stage.sh
・pgpool_remove_start
の3ファイルを作成します。

pgpoolレプリケーションモード | PostgreSQL関連情報のスクリプトを使わせて頂きました。ありがとうございます。

recovery_1st_stage.sh

#!/bin/sh

PSQL="/usr/local/pgsql/bin/psql"
PORT=5432
MASTER_BASEDIR=$1
RECOVERY_HOST=$2
RECOVERY_BASEDIR=$3

$PSQL -p $PORT -c "SELECT pg_start_backup('pgpool-recovery')" postgres

echo "restore_command = 'cp /usr/local/pgsql/data/archive/%f %p'" > $MASTER_BASEDIR/recovery.conf

ssh -l postgres -T $RECOVERY_HOST rm -rf $RECOVERY_BASEDIR.bk
ssh -l postgres -T $RECOVERY_HOST mv -f $RECOVERY_BASEDIR{,.bk}

rsync -az -e ssh -l postgres $MASTER_BASEDIR/ $RECOVERY_HOST:$RECOVERY_BASEDIR/

ssh -l postgres  -T $RECOVERY_HOST cp -f $RECOVERY_BASEDIR.bk/postgresql.conf $RECOVERY_BASEDIR
ssh -l postgres  -T $RECOVERY_HOST rm -f $RECOVERY_BASEDIR/postmaster.pid

rm -f $MASTER_BASEDIR/recovery.conf

$PSQL -p $PORT -c "SELECT pg_stop_backup()" postgres

recovery_2nd_stage.sh

#!/bin/sh

PSQL="/usr/local/pgsql/bin/psql"
PORT=5432
ARCHIVEDIR=/usr/local/pgsql/data/archive/
MASTER_BASEDIR=$1
RECOVERY_HOST=$2
RECOVERY_BASEDIR=$3

$PSQL -p $PORT -c 'SELECT pg_switch_xlog()' postgres

rsync -az -e ssh  -l postgres $ARCHIVEDIR $RECOVERY_HOST:$ARCHIVEDIR 

pgpool_remove_start

#! /bin/sh

PGCTL=/usr/local/pgsql/bin/pg_ctl
RECOVERY_HOST=$1
RECOVERY_BASEDIR=$2

ssh -l postgres -T $RECOVERY_HOST $PGCTL -w -D $RECOVERY_BASEDIR start 2>/dev/null 1> /dev/null < /dev/null &

これら3ファイルに実行権限を付けて、各ノードサーバーのデータディレクトリ以下に配置します。

以上で、オンラインリカバリの準備は完了です。


では実際にオンラインリカバリを試してみます。
オンラインリカバリを行うには、いずれかのノードサーバーがpgpool側で異常検知されている必要があります。
今回は192.168.0.2のPostgreSQLを止めてからオンラインリカバリをしてみます。


% /usr/local/pgsql/bin/pg_ctl -D /path/to/pgsql/data stop

% /usr/local/pgsql/bin/psql -p 9999  // ←pgpoolへ接続
postgres=# show pool_nodes;
 node_id |   hostname   | port | status | lb_weight |  role  | select_cnt 
---------+--------------+------+--------+-----------+--------+------------
 0       | 192.168.0.1  | 5432 | 2      | 0.500000  | master | 1200
 1       | 192.168.0.2  | 5432 | 3      | 0.500000  | slave  | 884
(2 rows)

192.168.0.2が停止しています。

この状態で、pcp_recovery_nodeコマンドでオンラインリカバリを行います。

% /path/to/pgpool/bin/pcp_recovery_node -h 192.168.0.1 -p 9898 -U postgres -n 1

-h ... PCP(pgpool Communication Manager Connection)の稼働ホスト?
-p ... PCPの稼働ポート
-U ... pgpoo.confに記したrecovery_user名
-n ... 何番のノードを起動させるか。今回はnode_id=1の192.168.0.2

以上で、問題なければオンラインリカバリが成功するはずです。
ただ、オンラインリカバリを行うのは意外と時間かかる場合があるので気長に待つ必要も大切です。


【実際に試してみた】

サービス稼働中を模して、
無限ループでINSERTさせながらオンラインリカバリをやってみました。
...が、ターミナル上はSuccess!と出たのですが、
実際にデータを確認してみると2件レコードのズレがありました...。
やはり、データ誤差が出た場合は一旦サービス止めてdata/ディレクトリ丸ごとコピーの方が安全なのでしょうか。。?


以上でぇぇぇぇす!

2017年2月7日火曜日

tmuxですべてのペインに同じコマンドを同時入力!

どうも、俺です。

タイトルの通り、tmuxで複数のペイン分割した状態で
全てのペインに同じコマンドを送ってやりたいとき。



: set-window-option synchronize-panes on
これです!


ちなみにやめたい時は

: set-window-option synchronize-panes off
です。

複数のペイン上で複数の作業を同時進行したい時、
とかに使えます。

以上でぇぇぇぇす!

2017年1月31日火曜日

Lumen(Laravel)でview()に渡した値を参照する

どうも、俺です。

変数の値を
view()->share("myName", $myName);
のように渡したあとで、
「あ、やっぱまたview()から取って使いたい〜〜!」となった場合。

view()->shared("myName");
で取得できるさかいに。

以上でぇぇぇぇす!

2017年1月27日金曜日

LumenのEloquentでupdate()を呼ぶとMassAssignmentExceptionが出てまう

どうも、俺です。

最近は軽量PHPフレームワークのLumenを使っています。
(※バージョンはたぶん5.2。確認の仕方が分からない...)

最近もっぱらPHP界隈を賑わしているLaravelから派生したフレームワークで、
機能が少ない分、軽量で処理速度も速いそうです。

LaravelもLumenもデータベースモデルはEloquentという機能を使って開発することができ、僕もそれを使っています。

で、データを更新するために
$userObject->update(["name"=>"山田さん", "age"=>30]);
のように実装すると、

 MassAssignmentException
が発生し小一時間ハマりました。

この場合は、その該当のモデルクラスに

// 変更可能なカラム名
protected $fillable = ["name", "age", "その他カラム名"];

// または変更不可能なカラム名
protected $guarded = ["id", "create_at"];

のどちらか(または両方)を記述すればOKです。

ただ、上記の変数を指定しなくてもupdate()メソッドが使える場合もあり、
その理由は未だ不明です...。



ちなみに、insert()またはsave()メソッドでは上記の例外の発生は未確認です。




以上でぇぇぇぇす!

2017年1月23日月曜日

vimでファイルを開いている最中にdiffを見る

どうも、俺です。

2つのファイルにある差分をチェックする場合、
$ diff aaa.txt bbb.txt
またはvimをつかって

$ vimdiff aaa.txt bbb.txt
とやることが多いです。

今回は、vimでファイルを開いてしまった状態からdiff(vimdiff)を見る方法について。
とあるファイルをvimで開いてから、
:vsp ファイル名

または
:sp ファイル名

で、分割表示している状態で、
:windo diffthis
と打てばdiffを確認できます!

ちなみに、
:windo
は、vimで分割しているすべての画面に同じコマンドを打つ時に使えます。


以上でぇぇぇぇす!

amazon