set setting reset

インフラ関連の小ネタと備忘録

list を CSV っぽく置換する

python バージョンは

>>> sys.version
'3.6.2 (default, Oct  5 2017, 11:51:36) \n[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)]'

です。
やりたいことは

l = ['aoba', 'nene', 'hotaru']

といったリストを

'aoba','nene','hotaru'

というふうにしたい。 (例えば SQL の IN 句を生成したい時など)
単純に join すると先頭と末尾に ' が付与されない。

>>> print("','".join(l))
aoba','nene','hotaru

しかたなく format を使います。

>>> print("'{}'".format("','".join(l)))
'aoba','nene','hotaru'

こんなんでいいのかわからないけど、やりたいことはできました。

A client error (AuthFailure) occurred when calling the DescribeInstances operation: AWS was not able to validate the provided access credentials

はじめに

何気なく awscli を叩いたら表題のエラーが出たので調査しました。

つい先日当該アカウントの IAM User 棚卸しをしてアクセスキーの整理をしたのでその影響だろうと思われました。
当該インスタンスには IAM Role が付与されてはいたものの、実際はローカルに残存していたアクセスキーで API を叩いているのでは?という状況です。

環境

  • EC2
  • CentOS 6.7
  • やりたい操作を許可する IAM Role 付与済み

調査

まず、アクセスキーが残存しているのだろうと思い、 ~/.aws/credentials を確認。
たしかに鍵の記述があったのでそれを削除。ただ、依然としてエラーのまま。

よくわからないためぐぐると awscli には --debug オプションがあることがわかり、早速実行すると以下のメッセージを発見。

MainThread - botocore.credentials - INFO - Found credentials in boto config file: ~/.boto

なるほどと ~/.boto を確認すると、こちらにもアクセスキーが記述されていました。

対応

~/.boto を削除してエラーが解消されました。

さいごに

--debug 便利ですね。

富士そば 渋谷明治通り店

TLを眺めていたらなんだか目に止まってしまった富士そばアドベントカレンダー
18日めが空いていたので参加させていただきます。
富士そばしゅき度で言えば富士そばカレーうどんを1日3食したことがある程度の者です。 adventar.org

ぼくは google map にごはん写真が自動でアップロードされてしまう人なのですが、
もっとも閲覧回数の多い写真が 富士そば 渋谷明治通り店でいただいた赤富士 であり、
空腹と承認欲求を満たしてくれてシンプルに素晴らしいと思います。

というわけでおひひ富士そば

紅生姜天そば + いなりにしました。
美しポップなピンク色した紅生姜の爽やかな酸味と意外にオイリーな天ぷらと、どこにでもあるような質実剛健なおいなりさん、控えめに言って最強では。

また、渋谷明治通り店は老若男女問わない広い客層で、いつも店員さんが何やら楽しそうでとても雰囲気のよい店内となっております。
本日もごちそうさまでした。明日は musumi_takuma さんの担当です。よろしくおねがいします。

こちらからは以上です。

第35回 PostgreSQL 勉強会に行ってきました

初めて PostgreSQL 勉強会にお邪魔させていただきました。

connpass.com

殴り書きメモですが、記録として。

トランザクション入門

oss-db silver の出題範囲とのことでした

同時実行制御

  • 完了しない状態のデータが残ってしまう
    • 一連の処理が完了した上で COMMIT する
  • 一貫性がないデータが読めてしまう
  • 不正な更新データが書き込まれてしまう
    • dirty read
    • 一連の処理に割り込まない

トランザクションの使い方

  • 一貫した処理を保証するためのDB処理の集合
    • begin ~ commit or rollback
  • ACID 特性
    • 更新データは処理が完了した状態でのみ保存できる
    • 一貫性のあるで0多の読み書きを保証する
    • 同時に1つのトランザクションだけが実行しているように見える
    • 書き込んだデータは確実に保存する
  • begin は postgres 独自コマンド
  • トランザクションとエラー
  • SAVEPOINT による部分的 ROLLBACK
    • 使ってるアプリケーションはあるんだろうか。。
begin;
intert into ...
SAVEPOINT SP1;
insert into ...
-> ERROR
ROLLBACK TO SP1;
-> ROLLBACK

トランザクションの分離

  • 分離性
  • 分離レベル
    • Serializable
      • 遅い
    • Repeatable read
      • 直列化の失敗
    • Read committed
      • 反復不能読み取り
      • ファントムリード
        • 行の集合として見た場合、再度読み込むと1回目にはなかった行が読み込まれることがある
      • 直列化異常
  • 分離レベルの使い方
    • SET TRANSACTION ISOLATION LEVEL ****
  • 分離レベルと性能はトレードオフ

ロック


postgresql 10 がやってくる

logical replication

  • pgpool-II / slony-I
  • logical decoding
    • BDR(Bi-Direction Replication)
    • logical replication(postgresql10)
  • logical decoding
    • wal -> wal の変換プラグイン -> 論理ログ -> 論理ログの適用
  • logical replication
    • postgresql.conf
      • wal_level = logical
        • デカい
      • max_wal_senders
      • max_replicaiton_slots
    • pg_hba.conf
      • いつもの
    • create database
      • logical replication は DB 単位で設定
    • create table
    • logical replication の設定
      • 複製元
        • create publication
        • insert update delete が複製
        • 複製させない指定も可能
      • 複製元
        • create subscription
          • CONNECTION に接続文字列を書く
    • レプリケーション非対象
      • trancate
      • DDL
      • vacuum
    • meta-data
      • pg_stat_subscriptino
    • conflict
      • conflict が発生したら伝搬があぼーん
      • ぐえーむずい
    • 異なる構造間のレプリケーションが可能
      • ただし複製元にある列は複製先にもなければならない
      • 文字コード間の複製が可能
    • 応用編
  • declarative partitioning
  • others
    • GUC に多数いろいろ
    • パラレルクエリの改善
    • pg_hba_rules いいじゃん
    • hash index の wal 対応
      • uuid にはいいかも
      • イコール比較しかできない
    • JSON/JSONB + textsearch

togetter

ぬこ@横浜さんが当日の #jpug_study をまとめておられます。

togetter.com

vim のヤンクでクリップボードにコピーしたかった話、あるいは vim 8 へのアップグレード (mac)

環境

OS vim version
OSX 10.11.6 7.3

目的

macvim でヤンクしてクリップボードにいれたかった。

記事にしようと思ったきっかけ

よくある設定を .vimrc に書いてみましたが、有効にならず。

set clipboard=unnamed,autoselect
$ vim --version | grep clipboard
-clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments
 -xterm_clipboard -xterm_save

記録しておこうと思いました。


ぐぐった

homebrew を update して、 vim をインストールしなおすのが手っ取り早いようでした。 http://djangoapplab.com/43/


homebrew の update

まず、sudo brew update してみたら怒られました。

Error: Running Homebrew as root is extremely dangerous and no longer supported.
As Homebrew does not drop privileges on installation you would be giving all
build scripts full access to your system.

そうなんですね。ごめんなさい。
なので一般ユーザで update してみます。

$ brew update
Error: /usr/local is not writable. You should change the
ownership and permissions of /usr/local back to your
user account:
  sudo chown -R $(whoami) /usr/local

そうなんですね。
では、と chown して update すると進みはじめ、どかどか色々とインストールされていきます。

$ brew update
==> Homebrew has enabled anonymous aggregate user behaviour analytics.
Read the analytics documentation (and how to opt-out) here:
  http://docs.brew.sh/Analytics.html

Updated 3 taps (caskroom/cask, homebrew/binary, homebrew/core).
==> Cleaning up /Library/Caches/Homebrew...
Removing: /Library/Caches/Homebrew/gcc-5.3.0.tar.bz2... (91M)
Removing: /Library/Caches/Homebrew/gmp-6.1.0.el_capitan.bottle.tar.gz... (1M)
Removing: /Library/Caches/Homebrew/isl-0.15.el_capitan.bottle.tar.gz... (1.2M)
Removing: /Library/Caches/Homebrew/mpfr-3.1.3.el_capitan.bottle.tar.gz... (862.5K)
Removing: /Library/Caches/Homebrew/openssl-1.0.2g.el_capitan.bottle.tar.gz... (3.6M)
Removing: /Library/Caches/Homebrew/packer-0.10.0_1.el_capitan.bottle.tar.gz... (8.4M)
Removing: /Library/Caches/Homebrew/pkg-config-0.29.1.el_capitan.bottle.tar.gz... (235.8K)
Removing: /Library/Caches/Homebrew/ruby-build-20160330.tar.gz... (43.7K)
Removing: /Library/Caches/Homebrew/sshrc-0.5.tar.gz... (3.4K)
Removing: /Library/Caches/Homebrew/terraform-0.6.14.el_capitan.bottle.tar.gz.incomplete... (94.2M)
Removing: /Library/Caches/Homebrew/tig-2.1.1.el_capitan.bottle.2.tar.gz... (154.4K)
==> Migrating /Library/Caches/Homebrew to /Users/rriifftt/Library/Caches/Homebrew...
==> Deleting /Library/Caches/Homebrew...
中略

/Library/ からホームディレクトリにマイグレーションしています。とても親切です。
さらに Formulae も新しくなっているようでした。

==> Migrating d-bus to dbus
==> Unlinking d-bus
Moving to: /usr/local/Cellar/dbus
==> Linking dbus
Error: Could not link:
/usr/local/share/doc/homebrew

Please delete these paths and run `brew update`.
==> Migrating HOMEBREW_REPOSITORY (please wait)...
Error: Could not link:
/usr/local/share/doc/homebrew

Please delete these paths and run `brew update`.
==> Migrated HOMEBREW_REPOSITORY to /usr/local/Homebrew!
Homebrew no longer needs to have ownership of /usr/local. If you wish you can
return /usr/local to its default ownership with:
  sudo chown root:wheel /usr/local

最後には ↑ のログが出力されました。
ご案内の通りにします。

$ rm -rf /usr/local/share/doc/homebrew
$ brew update
Already up-to-date.

成功しました。
さらにご案内の通り /usr/local の権限を元に戻しておきます。

$ sudo chown root:wheel /usr/local

vim のインストール

vim は upgrade すればいいでしょと思ってやってみるとインストールされていないって言われました。

$ brew upgrade vim
Error: vim not installed

clipboard が有効にならないのはこれが原因っぽいような。
ないなら install します。

$ brew install vim
==> Installing dependencies for vim: perl, readline, libyaml, openssl, ruby, pkg-config, sqlite, gdbm, python
==> Installing vim dependency: perl
==> Downloading https://homebrew.bintray.com/bottles/perl-5.24.0_1.el_capitan.bottle.1.tar.gz
######################################################################## 100.0%
==> Pouring perl-5.24.0_1.el_capitan.bottle.1.tar.gz
略
==> Pouring vim-8.0.0329.el_capitan.bottle.tar.gz
🍺  /usr/local/Cellar/vim/8.0.0329: 1,713 files, 23.3M

vim 8 が降ってきました。


バイナリの切替

clipboard が有効になっているか確認してみると、変わっていません。

$ vim --version | grep clipboard
-clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments
 -xterm_clipboard -xterm_save

vim インストール時のログを見ると別の場所にインストールされたようです。
こちらのバイナリで確認してみると有効になっています。

$ /usr/local/Cellar/vim/8.0.0329/bin/vim --version | grep clipboard
+clipboard       +job             +path_extra      +user_commands
+eval            +mouse_dec       +statusline      -xterm_clipboard

入れ替える必要がありそうなので入れ替えてみます。

$ mv /usr/local/bin/vim{,.bk}
$ ln -s /usr/local/Cellar/vim/8.0.0329/bin/vim /usr/local/bin/vim

vim を起動する

と、エラーが出ました。

$ vim

Command terminated

Error detected while processing /Users/rriifftt/.vim/bundle/open-browser.vim/plugin/openbrowser.vim:
line   19:
E484: Can't open file /var/folders/g5/hsvhp9155l1c6sdc01rgqd4jwp37f2/T/v7qsLTu/0
Press ENTER or type command to continue

さらに iTerm で新しいタブを開くとローカルホストにログインできなくなりました。

Last login: Tue Feb 14 11:15:10 on ttys019
dyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.6.dylib
  Referenced from: /usr/local/bin/bash
  Reason: image not found

やさしい人に readline を切り替えるとよくなるかもしれないと教えてもらいました。
確かに brew update した時に readline が更新されています。

==> Pouring readline-7.0.1.el_capitan.bottle.tar.gz
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local.

macOS provides the BSD libedit library, which shadows libreadline.
In order to prevent conflicts when programs look for libreadline we are
defaulting this GNU Readline installation to keg-only.


For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/readline/lib
    CPPFLAGS: -I/usr/local/opt/readline/include

==> Summary
🍺  /usr/local/Cellar/readline/7.0.1: 46 files, 2M
==> Installing vim dependency: libyaml
==> Downloading https://homebrew.bintray.com/bottles/libyaml-0.1.7.el_capitan.bottle.tar.gz

readline の切替

readline を切り替えてみます。

$ brew switch readline 7.0
Error: readline does not have a version "7.0" in the Cellar.
Versions available: 6.3.6, 6.3.8, 7.0.1

コマンドエラーになってしまいましたが、3 つのバージョンがあることがわかりました。
そして現在のバージョンは以下です。

$ brew list readline
/usr/local/Cellar/readline/7.0.1/include/readline/ (8 files)
/usr/local/Cellar/readline/7.0.1/lib/libhistory.7.0.dylib
/usr/local/Cellar/readline/7.0.1/lib/libreadline.7.0.dylib
/usr/local/Cellar/readline/7.0.1/lib/ (6 other files)
/usr/local/Cellar/readline/7.0.1/share/doc/ (3 files)
/usr/local/Cellar/readline/7.0.1/share/info/ (3 files)
/usr/local/Cellar/readline/7.0.1/share/man/ (2 files)
/usr/local/Cellar/readline/7.0.1/share/readline/ (15 files)

最新版は色々とアレなんでしょうか。
6.3.8 に切り替えてみます。

$ brew switch readline 6.3.8
Cleaning /usr/local/Cellar/readline/6.3.6
Cleaning /usr/local/Cellar/readline/6.3.8
Cleaning /usr/local/Cellar/readline/7.0.1
Opt link created for /usr/local/Cellar/readline/6.3.8

再度 vim を起動する

と、エラーなく起動できました。
iTerm の新規タブも問題なく開くことができています。

いまのところはこれで問題なさそうです。

boto3 で指定された日付以前の snapshot を削除する

という python script を晒してみます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
指定された日付以前の snapshot を削除します
ただし ami に紐付いている snapshot は削除しません

example:
    $ python delete_expired_snapshots.py -p profile_name -o owner_id -e expire_date (--dry-run True|False)
"""

import boto3
import pytz
from argparse import ArgumentParser
from datetime import datetime, timedelta


def delete_expired_snapshots(profile, owner_id, expire_date, dry_run=False,):
    session = boto3.Session(profile_name=profile)
    client = session.client("ec2")
    snapshots = client.describe_snapshots(OwnerIds=[owner_id])
    """
    response example:
        "Snapshots": {
            u'Description': '***********',
            u'Encrypted': True,
            u'VolumeId': 'vol-*****',
            u'KmsKeyId': 'arn:aws:kms:region:*******:key/***********',
            u'State': 'completed',
            u'VolumeSize': **,
            u'Progress': '100%',
            u'StartTime': datetime.datetime(yyyy, mm, dd, hh, MM, SS, tzinfo=tzutc()),
            u'SnapshotId': 'snap-************',
            u'OwnerId': '*******'
        },...
    """
    expired_snapshot_ids = [ s["SnapshotId"] for s in snapshots["Snapshots"]
        if s["StartTime"] < expire_date ]
    for expired_snapshot_id in expired_snapshot_ids:
        try:
            res = client.delete_snapshot(SnapshotId=expired_snapshot_id, DryRun=dry_run)
            if res["ResponseMetadata"]["HTTPStatusCode"] == 200:
                print("INFO. delete Succeed id:{0}".format(expired_snapshot_id))
            else:
                print("ERROR. delete Failed id:{0} status_code:{1}".format(
                    expired_snapshot_id, res))
        except Exception as e:
            print("ERROR. exception occurd id:{0}".format(expired_snapshot_id))
            print("Exception. {0}".format(e))


def arg_parse_for_delete_expired_snapshots():
    parser = ArgumentParser()
    parser.add_argument(
        "-p", "--profile", dest="profile",
        type=str, required=True,
        help="specify snapshots aws profile"
    )
    parser.add_argument(
        "-o", "--owner-id", dest="owner_id",
        type=str, required=True,
        help="specify snapshots owner_id"
    )
    parser.add_argument(
        "-e", "--expire-date", dest="expire_date",
        type=int, required=True,
        help="specify expire date"
    )
    parser.add_argument(
        "--dry-run", dest="dry_run",
        type=bool,
        default=False,
        help="dry run switch"
    )
    return parser.parse_args()
    

if __name__ == "__main__":
    p = arg_parse_for_delete_expired_snapshots()
    expire_date = datetime.now(pytz.utc) - timedelta(p.expire_date)
    delete_expired_snapshots(p.profile, p.owner_id, expire_date, p.dry_run)

argparse をつかってコマンドライン引数をよしなにする

よくつかうのでメモとして残してみます。

argparse とは

python の組み込みライブラリで、引数をよしなにしてくれるいい人です。
python 2.7 から追加されました。

15.4. argparse — コマンドラインオプション、引数、サブコマンドのパーサー — Python 2.7.x ドキュメント

よくやること

コマンドラインで実行する系のスクリプトでオプションを指定するときなどに便利なので、そのように使うことが多いです。
ロングオプションを指定したり、変数に自動で格納してくれたり、位置をきにしなくて良かったり、 --help で Usage を自動で生成したりしてくれます。

例えば以下のようなコードを動かしてみます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from argparse import ArgumentParser

def argument_parser():
    parser = ArgumentParser(description="this is description")
    parser.add_argument(
          "-n", "--neko", dest="neko",
          type=str,
          help="specified neko")
    return parser.parse_args()


if __name__ == '__main__':
    p = argument_parser()
    print(p.neko)

help を表示してみます。

$ python test.py --help
usage: test.py [-h] -n NEKO

this is description

optional arguments:
  -h, --help            show this help message and exit
  -n NEKO, --neko NEKO  specified neko

オプションを正しく指定すると以下の様に普通に print() されます。

$ python test.py -n saba
saba
$ python test.py --neko mike
mike

必須オプションをつくる

require=True を指定すると必須オプションをつくれます。

          "-n", "--neko", dest="neko",
          type=str,
+          required=True,
          help="specified neko")

引数を与えずに実行すると、エラーになります。

$ python test.py
usage: test.py [-h] -n NEKO
test.py: error: argument -n/--neko is required

オプションの選択肢を固定する

choices=[] を使うと選択肢を固定できます。

          "-n", "--neko", dest="neko",
          type=str,
          required=True,
+          choices=["saba", "mike"],
          help="specified neko")

正しく実行すると、普通です。

$ python test.py --neko saba
saba
01:50:41 ~
$ python test.py --neko mike
mike

choices にないオプションを与えるとエラーになります。

$ python test.py --neko kuroneko
usage: test.py [-h] -n {saba,mike}
test.py: error: argument -n/--neko: invalid choice: 'kuroneko' (choose from 'saba', 'mike')

順番をきにしなくてよい

2 つのオプションを定義してみます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from argparse import ArgumentParser

def argument_parser():
    parser = ArgumentParser(description="this is description")
    parser.add_argument(
          "-n", "--neko", dest="neko",
          type=str,
          required=True,
          choices=["saba", "mike"],
          help="specified neko")
    parser.add_argument(
         "-i", "--inu", dest="inu",
         type=str, help="specified inu")
    return parser.parse_args()


if __name__ == '__main__':
    p = argument_parser()
    print(p.neko)
    print(p.inu)

help を見てみると、オプションが自動で追加されています。

$ python test.py --help
usage: test.py [-h] -n {saba,mike} [-i INU]

this is description

optional arguments:
  -h, --help            show this help message and exit
  -n {saba,mike}, --neko {saba,mike}
                        specified neko
  -i INU, --inu INU     specified inu

引数の位置を変えて実行しても結果は同じになります。らくちん。

$ python test.py -n mike --inu shiba
mike
shiba

$ python test.py -i shiba --neko saba
saba
shiba

おわり。
次は流行りの click を触ってみます。