モヒカンメモ

髪色が定期的に変わることに定評のある(比較的)若者Webエンジニアの備忘録

プライベートプロダクトのpackage.jsonのlicenseフィールドには "license: UNLICENSED" と指定すればいいらしい

package.jsonのlicenseフィールドに何も指定しないと、npm install or yarn installしたときに下記のような警告が出てしまって地味に目障り

warning package.json: No license field

プライベートプロダクトでpackage managerとしてnpm / yarnを使っているだけで、publishしたりオープンソースにするつもりはない。そういう時にどうすれば良いんだろうかと思って長らくモヤモヤしていたが... 普通に公式ドキュメントに書いてあったw

docs.npmjs.com

Finally, if you do not wish to grant others the right to use a private or unpublished package under any terms: { "license": "UNLICENSED" }

雑訳: 他人に権利を譲らないプライベートな奴だったら "license": "UNLICENSED" を指定してね

Consider also setting "private": true to prevent accidental publication.

雑訳: "private": true を指定しとくと、意図しない公開を防げるよ (誤npm publish対策)

{
  ...snip...
  "license": "UNLICENSED",
  "private": true
}

みたいな感じか

$ yarn install
yarn install v1.6.0
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.35s.

確かに出なくなった✌

2つの設定ファイルから空行やコメントを除いていい感じにdiffを表示するプチテクニック

▼ アイキャッチ画像は適当です

f:id:pinkumohikan:20180212222252p:plain

ミドルウェアなどのバージョンアップやマイグレーションなどの際に、「今の設定ってデフォルトからどこがどう変わってるんだっけ?」って気になることありますよね? でも、単純に diff コマンドで差分を出すだけだと改行やコメントが邪魔をして差分が分かりづらいですよねー。キレそう。

そういうときに使えるおまじないを教えます。

ドン

diff <(grep -v '^;' setting-a.ini | grep -v '^$') <(grep -v '^;' setting-b.ini | grep -v '^$')

(空行や ; で始まるコメント行を除いた結果をdiffしてるだけなんですけど、案外grepした結果でdiff取るの知られてなさそうだったので記事にしてみました)

動かしてみる

前提

こんな感じの設定ファイルがあったとして

setting-a.ini

; owner's name
owner = pinkumohikan

; owner's age
age = 24

setting-b.ini

; ie-i, miteru---?



; owner's name
owner = pinkumohikan

; owner's age
;
age = 25

単純にdiff取ると

$ diff setting-a.ini setting-b.ini
0a1,4
> ; ie-i, miteru---?
>
>
>
5c9,10
< age = 24
---
> ;
> age = 25

こんな感じで空行やコメントの差分が邪魔ですね、減給。

でもさっきのコマンドなら

$ diff <(grep -v '^;' setting-a.ini | grep -v '^$') <(grep -v '^;' setting-b.ini | grep -v '^$')
2c2
< age = 24
---
> age = 25

なるほど、ageが24から25に変わってるんやなーっていうのがひと目でわかりますね。

(1月18日の) 誕生日おめでとうありがとうございます!

dockerコンテナ内から /dev/stdout へ書き込もうとすると "Permission denied" になる

PHP Laravel 5.5系のアプリをdockerコンテナにして、所定のログファイルpathから /dev/stdout へのsymlinkを貼って動かしたところ Permission denied エラーが出た。原因を調べたところそれなりにめんどくさかったので調べたことをまとめておく。

症状

  • dockerコンテナ内のアプリから /dev/stdout へログを吐こうとしたときに Permission denied エラーになる
  • コンテナに入ってディレクトリとパーミンションを確認すると、パット見問題無さそう

原因

/dev/stdout の最終的な向き先が自分のpts (仮想端末) ではないことがあり (バグ?)、自分のものでないptsには当然書き込めないのでエラーとなる。

▼ ptsってなんやねん的な人向け

takuya-1st.hatenablog.jp

▼ 神記事

qiita.com

どうすればいいか

アプリから /dev/stdout へ直接ログを吐かず、プログラミング言語が用意している標準出力用streamへ向けてログを吐くようにする (phpでいうと php://stdout ってやつ)。

そうするといい感じに実行ユーザのptsを解決して、自分のptsへ向けて標準出力を吐いてくれる。


Laravelの場合、 bootstrap/app.php に下記のような設定を加えればOK。

$app->configureMonologUsing(function ($monolog) {
    $monolog->pushHandler(
        new \Monolog\Handler\StreamHandler(
            'php://stdout',
            \Monolog\Logger::WARNING // TODO: 適切なログレベルを設定
        )
    );
});

▼ configureMonologUsingってなんやねん的な人向け

laravel.com

memo

▼ 同じような事象を相談していた stack overflow。この人はSymfonyだけど同じ原因。

stackoverflow.com

DockerHubのnginx:latestイメージでpsコマンド叩いたら「そんなもの無い」って言われたのでインストールする

背景

DockerHubにある nginx:latest イメージから起動したコンテナ内で ps を叩いたら

root@de0ff7733246:/# ps
bash: ps: command not found

と言われてしまったので、インストールする

インストール

apt update && apt install -y procps

エイヤ

root@de0ff7733246:/# ps
  PID TTY          TIME CMD
   11 pts/0    00:00:00 bash
  340 pts/0    00:00:00 ps

やったね

余談

apt update って、文字からはインストール済みパッケージを文字通りupdateするかのような印象を受けるけど、実はパッケージ情報を取得するだけの模様

# apt
apt 1.4.8 (amd64)
Usage: apt [options] command

apt is a commandline package manager and provides commands for
searching and managing as well as querying information about packages.
It provides the same functionality as the specialized APT tools,
like apt-get and apt-cache, but enables options more suitable for
interactive use by default.

Most used commands:
  list - list packages based on package names
  search - search in package descriptions
  show - show package details
  install - install packages
  remove - remove packages
  autoremove - Remove automatically all unused packages
  update - update list of available packages
  upgrade - upgrade the system by installing/upgrading packages
  full-upgrade - upgrade the system by removing/installing/upgrading packages
  edit-sources - edit the source information file

See apt(8) for more information about the available commands.
Configuration options and syntax is detailed in apt.conf(5).
Information about how to configure sources can be found in sources.list(5).
Package and version choices can be expressed via apt_preferences(5).
Security details are available in apt-secure(8).
                                        This APT has Super Cow Powers.

インストール済みパッケージを文字通りupdateしたければ upgradefull-upgrade を使うらしい

PHP用HTTPクライアント「HTTP_Request2」をcomposerでinstallする

PHPで使える 古参 HTTPクライアント、 HTTP_Request2 をcomposerを使ってインストールする方法を紹介します。

今時composerを使っていないPHPプロジェクトなんて有るわけないですからね!

f:id:pinkumohikan:20170719230314p:plain

pearライブラリをcomposerでinstallするには事前にリポジトリを追加したりする必要がある聞いていたので面倒だなーと思っていたのですが、v2.2.0以上なら普通に composer require で入るようです。

packagist.org

手順

1. composerをダウンロードする

getcomposer.org

$ ls
composer.phar

ちなみに、 programmaticにdownloadしたいときはこうするのが良いらしい (今日知った)

getcomposer.org

2. composer requireする

$ ./composer.phar require pear/http_request2
Using version ^2.3 for pear/http_request2
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
  - Installing pear/pear_exception (v1.0.0): Loading from cache
  - Installing pear/net_url2 (v2.2.1): Loading from cache
  - Installing pear/http_request2 (v2.3.0): Loading from cache
Writing lock file
Generating autoload files

↑が正常に終わると、こんな感じに仲間が増えているはず

$ ls
composer.json  composer.lock  composer.phar  vendor

3. 使える

$ php -r "require_once __DIR__.'/vendor/autoload.php'; var_dump(class_exists('HTTP_Request2'));"
bool(true)

あとはいい感じにDocumentを見て使って下さい。

Manual :: HTTP_Request2

/etc/cron.dへ置くファイルにはownerとpermissionに制約があるっぽい

crontabファイルを etc/cron.d へ置いても期待通り動かなかったことがあって調べたメモ

f:id:pinkumohikan:20170708185525p:plain

まとめ

/etc/cron.dへ置くファイルは

  • ownerは、rootでなければならない
  • permissionは、owner以外に書き込み権限があってはならない

検証

ownerがroot、かつowner以外のwrite権限無しなら怒られない

$ sudo tee /etc/cron.d/hoge << EOM
> * * * * * root echo 'hoge' > /dev/null
> EOM
* * * * * root echo 'hoge' > /dev/null

$ sudo chmod 600 /etc/cron.d/hoge

$ sudo ls -al /etc/cron.d/hoge
-rw------- 1 root root 39  7月  8 18:41 /etc/cron.d/hoge

結果

$ sudo tail -f /var/log/cron
...
Jul  8 18:42:01 marlin CROND[10186]: (root) CMD (echo 'hoge' > /dev/null)
...

permissionがgroup write有りだと怒られる

$ sudo chmod 660 /etc/cron.d/hoge

$ sudo ls -al /etc/cron.d/hoge
-rw-rw---- 1 root root 39  7月  8 18:42 /etc/cron.d/hoge

結果

$ sudo tail -f /var/log/cron
...
Jul  8 18:43:01 marlin crond[7153]: (root) BAD FILE MODE (/etc/cron.d/hoge)
...

ownerがroot以外だと怒られる

$ sudo chmod 600 /etc/cron.d/hoge

$ sudo chown h-shinoda /etc/cron.d/hoge

$ sudo ls -al /etc/cron.d/hoge
-rw------- 1 h-shinoda root 39  7月  8 18:42 /etc/cron.d/hoge

結果

$ sudo tail -f /var/log/cron
...
Jul  8 18:48:01 marlin crond[7153]: (root) WRONG FILE OWNER (/etc/cron.d/hoge)
...

参考にした資料

Matz氏による「若手エンジニアの生存戦略」勉強会に行って来た #colab_matz

f:id:pinkumohikan:20170611160204p:plain

エンジニアにはお馴染みRubyのパパ、Matz氏による「若手エンジニアの生存戦略」勉強会に行って来た

講師: まつもとゆきひろ 提供: サポーターズ 特別協賛: Speee 会場提供: DRECOM

f:id:pinkumohikan:20170611160214j:plain ↑ 会場設営中の様子。素敵な空間でした!DRECOMさんありがとうございます!


公演内容

先にブログを書いた人たちがいい感じにまとめてくれているので、そちらに譲りますw

あとは、 ハッシュタグ #colab_matz で、会場の雰囲気の8割ぐらいは伝わりそう

https://twitter.com/search?f=tweets&vertical=default&q=%23colab_matz&src=tyah


特に刺激を受けた / 共感したところをpick up

基本的な考え方

  • 生き残ること = 死なないこと

シリコンバレーで成功した人達の共通点

  • 知能の高さより、パターン認識
  • 成功者の猿真似をしても、同じように成功はできない
    • 「こういうシチュエーションだったら、あの時のアプローチが使えるんじゃないか!?」って考えるようにする

我慢に価値はない

  • "我々は我慢しがちだが、我慢することに価値はない。"
    • e.g. 客に合わないのにスーツを着る、新人だからという理由でアレな待遇を受ける、etc...
    • 事なかれ主義、「俺も我慢してるんだから、お前も我慢しろ」系は、すなわち ただの理不尽
      • 理不尽は拒否しなければならない
  • 我々は会社に養われている訳ではない
    • 労働は我慢の対価ではなく、提供したvalueに対する対価
      • valueを高めることだけ、追い求めるべき
      • ~~言いたいことも言えない、そんな世の中じゃポイズン〜~~
  • (会社の) 言うことを聞かないと捨てられるか?
    • 雇用者側は、そんなに簡単には (労働者を) 捨てられない
    • 我々の業界には、転職先はいくらでもある

インプットとアウトプット

  • 大前提として、インプットは必要
  • インプットはみんなやっているので、 他者と差別化しにくい
  • ではどうするか?
    • アウトプット頑張る
      • e.g. ブログ、OSS活動、etc...
      • 怖い人からツッコミを受けても、それも成長機会

No deal、という選択


感想

世界的に有名な日本人エンジニアが考える生存戦略ってどんなのだろう?と思って参加したが、文字通りの「生き残るには」というテーマで安心した (「グローバルに活躍できる超すごいエリートになるには!」みたいなテーマだったらどうしようかと思ったw)

自分もどちらかと言うと「我が道を行く」スタイルなのでMatz氏の考え方に似ているのか、基本「分かる分かる」と思いながら聞いていたが、 我慢に価値はない という話が特に刺さった

自分の周りの知人でも、客に合わないのにスーツ着用の強要や、ヘアカラー禁止、謎文化の強制で疲弊している人を数人見ていたので、「そういうの必要なの?仕事の効率やモチベーション、それによって落ちてない?」と思っていた矢先で、タイムリーだった。話を聞いてすぐ、数人にその話をシェアしたw

あとは、、、

参加者が自発的にこういう働き掛けをするイベントって正直見たことがなかったので、素直にいいなあと思った (その後に予定があって参加できなかったのが悔やまれる)

CentOSへaws-cliを入れようとしたらPython.h,pyconfig.hが無いって怒られた

f:id:pinkumohikan:20170611155843p:plain

CentOSへpipでaws-cliを入れようとしたら、下記のようなエラーが出た。

$ pip install aws
Collecting aws
  Downloading aws-0.2.5.tar.gz

...snip...

  No package 'libffi' found
  c/_cffi_backend.c:2:20: 致命的エラー: Python.h: そのようなファイルやディレクトリはありません
   #include <Python.h>
                      ^
  コンパイルを停止しました。

...snip...

  gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python2.7 -c build/temp.linux-x86_64-2.7/_openssl.c -o build/temp.linux-x86_64-2.7/build/temp.linux-x86_64-2.7/_openssl.o
  build/temp.linux-x86_64-2.7/_openssl.c:12:24: 致命的エラー: pyconfig.h: そのようなファイルやディレクトリはありません
   #  include <pyconfig.h>
                          ^
  コンパイルを停止しました。
  error: command 'gcc' failed with exit status 1

aws-cliの依存パッケージが足りないから自動で追加インストールしようとしたけど、Python.h, pyconfig.hが無くてコンパイルに失敗している模様

パッケージインストール中に出る「○○が無い」系のエラーは、単純に足りないパッケージをインストールしてあげれば機嫌が治るはず

今回は名前からして、いかにもpythonのヘッダファイルが足りないっぽいので python-devel をインストールしてみる (補足: CentOSで言う *-devel 系のパッケージは開発者向けのアレコレが入ったもの。今回足りないって言われているヘッダファイルも、コンパイル時しか要らないのでこっちに入っているはず)

$ sudo yum install python-devel
読み込んだプラグイン:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ python-devel.x86_64 0:2.7.5-48.el7 を インストール
--> 依存性解決を終了しました。

依存性を解決しました

======================================================================================================================
 Package                        アーキテクチャー         バージョン                      リポジトリー            容量
======================================================================================================================
インストール中:
 python-devel                   x86_64                   2.7.5-48.el7                    base                   393 k

トランザクションの要約
======================================================================================================================
インストール  1 パッケージ

総ダウンロード容量: 393 k
インストール容量: 1.0 M
Is this ok [y/d/N]: y
Downloading packages:
python-devel-2.7.5-48.el7.x86_64.rpm                                                           | 393 kB  00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  インストール中          : python-devel-2.7.5-48.el7.x86_64                                                      1/1
  検証中                  : python-devel-2.7.5-48.el7.x86_64                                                      1/1

インストール:
  python-devel.x86_64 0:2.7.5-48.el7

完了しました!

いざ、リトライ

$ pip install aws
Collecting aws

...snip...

Successfully built cryptography
Installing collected packages: prettytable, cryptography, paramiko, fabric, aws
Successfully installed aws-0.2.5 cryptography-1.7.2 fabric-1.13.1 paramiko-2.1.2 prettytable-0.7.2

今度はちゃんとコンパイルが通って、インストール完了したっぽい

$ aws --version
aws-cli/1.11.82 Python/2.7.5 Linux/3.10.0-514.16.1.el7.x86_64 botocore/1.5.45

わーい、aws-cli入ってる

正規表現 "?:" の意味 #些細な検証メモ

f:id:pinkumohikan:20170611155505j:plain

正規表現って構文が色々あって、読むごとに学びがありますよね。 今回は “?:” っていう構文について調べたので、備忘録がてらメモっときます

(写真は昨日の夜に行った 七志 とんこつ編 渋谷道玄坂店 です)

正規表現 “?:” の意味

MSDNによると、

(?:pattern) pattern と一致しても、その文字列は記憶されず、後で使用することはできません。"or" を意味する (|) を使用してパターンの一部を結合するときに便利です。たとえば、'industry|industries' と指定する代わりに、'industr(?:y|ies)‘ と指定する方が簡単です。

https://msdn.microsoft.com/ja-jp/library/cc392020.aspx

とのこと

要は、「 () のようにマッチングには使えるが、マッチした文字列の情報を保持しないよ」っていう表現ですね

“?:” は、どういう時に使うのか?

  • メモリを節約したいとき
  • この部分は要らない、っていうのを読んだ人に伝えたいとき

たとえば

Gmailメールアドレスから、エイリアスの部分を除く文字列を取得したいとき、何も考えないと下記のような表現になると思います

([a-zA-Z0-9-\.]+)(\+[a-zA-Z0-9-\.]+)?@gmail\.com

↑に対して example+aaa@gmail.com っていう文字列を与えると、example+aaa の2つがマッチング結果になります。 欲しかったのは example だけなので +aaa は余計です。

こういう時に “?:” を使って下記のように書くと example だけを求められます。

([a-zA-Z0-9-\.]+)(?:\+[a-zA-Z0-9-\.]+)?@gmail\.com

sudoコマンドをパスワードなしで使えるようにする

f:id:pinkumohikan:20170611155236p:plain

unix系OSには任意のユーザとしてコマンドを実行する sudo というコマンドがあります。

Linuxコマンド集 - 【 sudo 】指定したユーザーでコマンドを実行する:ITpro

このコマンドは、一般ユーザでログインした状態でroot権限でコマンドを実行したいときに良く使われますが、デフォルトだと下記のようにユーザのパスワードを要求されます。

$ sudo whoami
[sudo] password for h-shinoda:
root # rootユーザとして実行されている

プロビジョニング時など、何度もsudoを叩く必要があるときに都度パスワードを要求されるとキレそうになりますが、下記のように設定をすることによってパスワードを要求させないように出来ます。

注意 パスワードが要求されない = その一般ユーザアカウントがハックされる = rootが乗っ取られると同義なので、リスクを承知のうえで行って下さい。

方法

誰がどのようにsudo出来るかという情報は /etc/sudoers というファイルで管理されています。が、このファイルを決して手動で編集してはいけません (詳しくは最下部の補足を参照)。

今回やろうとしている変更は「特定のユーザに対して、パスワードなしで(すべてのコマンドを)sudoできるようにする」というものですので、ユーザ名を h-shinoda とすると、追加する設定としては下記のようになります。

h-shinoda ALL=(ALL) NOPASSWD: ALL

上記を visudo コマンドを使って /etc/sudoers へ設定します

$ sudo visudo

90行目辺りのrootユーザに対する設定の直下辺りにでも追加します。

## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
h-shinoda ALL=(ALL) NOPASSWD: ALL # コイツを追加

追加したら (vimの場合) :wq で write & quit しますが、この時、設定ファイルとしてのvalidationが走り、問題なければ /etc/sudoers へ変更が適用されます。

ここまで設定できれば、sudoでパスワードを要求されることはありません!

$ sudo whoami
root

おつかれさまでした!

補足

補足1: どうして手動で /etc/sudoers を編集してはいけないのか

sudoコマンドを実行するたびにsudoersファイルが読まれるため、変更は即時反映されます。 つまり、誤った設定や構文エラーなどで一度設定を壊してしまうとそれ以降sudoコマンドが使えなくなりますΣ

インターネットへ公開されているサーバの場合、セキュリティ的に普通はrootによるssh接続を禁止していると思うので、その状況でsudoが使えないとなると... 考えるだけでもゾクゾクしますね!(遠い目)

補足2: 実際には /etc/sudoers はあまりイジらない

一つのファイルにいろんな設定を書くと、可読性が下がってしまいます。 じゃあどうするでいうと /etc/sudoers.d 下に、ユーザごとに設定ファイルを持つことが多いと思います。

その場合、visudoコマンドの-fオプションでファイル名を指定します。

$ sudo visudo -f /etc/sudoers.d/h-shinoda

補足3: visudoで誤った設定を保存してしまった場合

問題があれば下記のようにでます。

$ sudo visudo
visudo: >>> /etc/sudoers: syntax error near line 92 <<<
What now?

この時の選択肢としては、下記の3つがあります。

  • e: 再編集する (再度vimが開き、問題点を直す)
  • x: sudoersを変更をせずに終了する
  • q: 構わずsudoersを変更をして終了する (DANGER!)

補足4: アレェ?設定したのにパスワードが要求される...

ユーザが wheel グループに属している場合、 wheel に対する設定のほうが後に書かれているのでNOPASSWD指定が上書きされて、パスワードが要求されてしまいます。 自分が wheel グループに属しているかどうかは id コマンドで確認できます。

$ id
uid=1000(h-shinoda) gid=100(users) groups=100(users),10(wheel)

この場合の選択肢としては、下記のようなものがあります。

  1. wheel グループからユーザを外す
    • usermod コマンドを使って wheel グループから外す
  2. 追加したNOPASSWDの設定を、sudoersの %wheel ALL=(ALL) ALL 行以降へ移動させる