つぶやきテック

日々のつぶやきアウトプット

つぶやきpackage-lock.json

package-lock.jsonって?

  • npm でインストールしたパッケージ情報が記載されるファイルです。
  • 以下のコマンドで作成・更新されます。
$ npm install

実行時は以下のような挙動をしています。

  1. package.json の内容を更新する
  2. package.json の内容をもとに node_modules のディレクトリにパッケージをインストールする
  3. node_modules に実際にインストールされたパッケージのバージョン情報が package-lock.json に記述される

(引用元:package-lock.json ってなに? - Qiita)

  • package-lock.json をもとにパッケージ群をインストールするには、以下のコマンドを使います。開発者それぞれの環境で違ったバージョンがインストールされるのを防げます。
$ npm ci

つぶやきpackage.json

package.json とは

  • 自分のNode.jsプロジェクトが依存する(参照したり、利用したりする)パッケージの管理に主に用いられるファイルです。
  • 一般的に、パッケージレジストリ(npm, apt, pip...) ではパッケージ同士が「依存のネットワーク」を構成しています。例えば babel-cli の依存マップはこんな感じ。

f:id:fugithora812:20210422050325p:plain
参考:https://npmgraph.js.org/?q=babel-cli

dependencies と devDependencies

# dependencies に追加
$ npm install express

# devDependencies に追加
$ npm install --save-dev nodemon
  • パッケージの依存関係を記入するためのプロパティとして、dependencies と devDependenciesがあります。

この2つには以下の違いがあります。

npm install に --production が渡されたり環境変数が NODE_ENV=production にセットされているとき、devDependenciesはインストールされない
そのプロジェクトがnpmパッケージとしてインストールされたとき、dependenciesのパッケージは一緒にインストールされるが、devDependenciesはインストールされない
(引用元:npmのpackage.jsonと依存関係を理解しよう! - bagelee(ベーグリー)

  • つまるところ、開発・テストのシーンでのみ使うパッケージはdevDependenciesに追加するのが望ましいです。

主なプロパティ(随時更新)

lint-staged

  • コミット前のファイルのLintを強制できるプロパティです。

設定例:

  "lint-staged": {
    "linters": {
      "*.js": "eslint --max-warnings=0",
      "*.ts": [
        "eslint --max-warnings=0",
        "tslint"
      ],
      "*.scss": "stylelint",
    },

つぶやきFHS【Linux】

FHSって?

  • Filesystem Hierarchy Standardの略です。
  • Linuxにおける、ディレクトリの基本ルールを規定しています。

FHS の構造

ポイントとなる性質

  1. 静的(コマンド実行などで書き換らない)かどうか
  2. 複数マシンで共有できるか

代表的な / 直下のディレクトリ

実行するコマンド・共有ライブラリの保管

ディレクトリ名 利用目的 静的 共有可
/bin 必須なコマンドのバイナリ(一般ユーザ用)
/sbin 必須なコマンドのバイナリ(特権ユーザ用)
/lib 必須の共有ライブラリ(及びカーネルモジュール)

システム・ログ・アプリケーション

ディレクトリ名 利用目的 静的 共有可
/opt 追加のパッケージ
/var 可変なデータ*1 × *2
/run システム起動後の、システムに関する情報*3

第二の階層 /usr

  • /usr 以下は静的・共有可です。
  • 主なディレクトリは以下の通りです。*4
ディレクトリ名 利用目的
/usr/bin 大部分のユーザコマンド
/usr/include C言語で使うヘッダファイル
/usr/lib ライブラリファイル
/usr/local パッケージシステム管理外
/usr/sbin 管理者用コマンド
/usr/share アーキテクチャに依存しないデータ

/bin と /usr/bin はどう違う?

FHSの定義においては、/ 直下のディレクトリ側には、システムを起動・復元・復旧・修復するのに必要なコマンド群を置くべきだとされています。*5

*1:ログ(/var/log)やロックファイル(/var/lock)、キャッシュ(/var/cache)など。歴史的には、/usrの可変な部分を/varに切り出したことで、/usrは読み込み専用にできるようになったのだとか。

*2:共有できるサブディレクトリとそうでないもの両方があります。

*3:デーモンプロセスIDを記述したファイルや、マシン内のサービス用のUNIXドメインソケットなど。/runディレクトリ内のデータは起動時に削除される必要があります。

*4:https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04.html

*5:『SoftwareDesign 2021.4』「ディレクトリ構造とファイルシステム」

Djangoでのテスト実施

Djangoのテスト

Djangoにおけるテストについての勉強記録です。 誤記や不足はコメントで指摘いただければ幸いです!

テスト実行コマンド

python manage.py test [[アプリケーション名]]

testコマンドを実行すると・・・

  • Djangoは "test" ではじまるモジュールを見つける
  • そのモジュール内でdjango.test.TestCaseクラスを継承したクラスを見つける
  • その後、TestCaseクラスに定義されているメソッドを実行

TestCaseクラスのメソッド

  • setUp → テストメソッドが呼ばれるたびに実行される
  • tearDown → テストメソッド終了後、結果が記録された後に呼ばれる
  • test○○ → アサーションメソッドを用いてテスト実行するメソッド
from django.test import TestCase
from myapp.models import Animal

class AnimalTestCase(TestCase):
    def setUp(self):
        Animal.objects.create(name="lion", sound="roar")
        Animal.objects.create(name="cat", sound="meow")

    def test_animals_can_speak(self):
        """Animals that can speak are correctly identified"""
        lion = Animal.objects.get(name="li——on")
        cat = Animal.objects.get(name="cat")

        self.assertEqual(lion.speak(), 'The lion says "roar"')
        self.assertEqual(cat.speak(), 'The cat says "meow"')

Pythonユニットテストでのモック作成

  • バージョン3.3で追加されたunittest.mockライブラリを使えばいけそうです。

実装例:

from unittest.mock import MagicMock

thing = ProductionClass()
thing.method = MagicMock(return_value=3)
thing.method(3, 4, 5, key='value')
thing.method.assert_called_with(3, 4, 5, key='value')

内部でAPI呼び出しを行う関数の単体テスト【Python】

pytest勉強中

以下のような、「内部でAPI呼び出ししている関数」の単体テストを 書くというケースに最近はじめて出会ったので、備忘メモを残します。

テスト対象コード

import requests

def get_info(**kwargs):
    node = kwargs['auth']
    app = node.get_information('sample')

    app_id = app.get_app_id()

    if app_id is None:
        raise requests.exceptions.HTTPError()

    url = 'https://sample.com/v1/app/' + str(app_id)
    headers = {'Authorization': 'Bearer ' + app.get_sample_key()}
    response = requests.get(url, headers=headers)

    try:
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        raise e

    data = response.json()
    return {'data': {'id': app.id, 'type': data} # 'type': 'sample-status'

テストコード

今回学びになったのは、mock.patchにside_effectという属性があり、 それとモック用の関数を使ってAPI呼び出しの振る舞いを再現できること。

読む人は少ないかもしれませんが、下のような感じでAPI呼び出しを モックしてテストできるようです。

def mocked_requests_get(*args, **kwargs):
    class MockResponse:
        def __init__(self, json_data, status_code):
            self.json_data = json_data
            self.status_code = status_code

        def raise_for_status(self):
            response = requests.Response()
            response.status_code = self.status_code
            try:
                response.raise_for_status()
            except requests.exceptions.HTTPError as e:
                raise e

        def json(self):
            return self.json_data

    if kwargs['headers']['Authorization'] == 'Bearer valid':
        return MockResponse('sample-status', 200)

    return MockResponse('null', 410)

class TestGetInfo(unittest.TestCase)
    @mock.patch('requests.get', side_effect=mocked_requests_get)
    def test_get_info(self, mock_get):
        expected_res = {'data': {'id': app.id, 'type': 'sample-status'}}

        res = get_info(url=url, auth=app.auth)
        assert_equals(res.status_code, 200)
        assert_equals(res.json, expected_res)

    # 異常系は省略

参考サイト

つぶやきpybabel

pybabelとは

  • Djangoなど、Pythonベースのアプリケーションで国際化のロケール別カタログを管理するツールです。
  • 言い換えるなら、「アプリケーションのこの部分は英語ではこう、日本語ではこう表示するよ」ということをあれこれやってくれるという感じです。
  • 登場人物はPOTファイル・POファイル・MOファイルの3人。ざっくりいうと、Pythonファイル(.py)からPOTファイル(.pot)をつくり、POTからPO(.po)を、POからMO(.mo)を、という流れです。

pybabelコマンド

$ pybabel (コマンド) [オプション] [引数]

extract

  • .pyファイルから.potファイルを生成するためのコマンドです。
  • 指定したディレクトリ以下を再帰的に検索し、.pyファイルに含まれる "_(...)"の内容を抽出します。
  • 例えば以下の例では、.potファイルには "ABCDE" という文字列が記載されます。
_('ABCDE')

使用例:

# -o オプションで.potファイル名を指定(デフォルトはmessages.pot)
$ pybabel extract --input-dirs=sample/src -o hoge.pot

init

  • .potファイルから.poファイルを生成するためのコマンドです。
  • オプションでドメイン名、ロケール名(言語名)、入力ファイルパス、出力ディレクトリなどを指定できます。
# -lオプション:ロケール名
# -iオプション:入力ファイルパス
# -dオプション:出力ディレクトリ
$ pybabel init -l ja -i hoge.pot -d ./sample_app/translations

compile

  • 国際化定義情報をバイナリファイルにコンパイルします。
  • ファイル拡張子で言うと、.poファイルを基にして .moファイルを生成します。
# -dオプションでコンパイル元のファイルがあるディレクトリを指定します
$ pybabel compile -d ./sample_app/translations

update

  • .potファイルの変更内容を .poファイルに反映します。
  • イメージとしては "init" で初回の.poファイル生成、それ以降の更新は "update" で、という感じです。
# -iオプションで .potファイルのパスを指定します
$ pybabel update -i hoge.pot -d ./website/translations

参考

つぶやきIPsecパススルー

IPsecパススルーとは?

  • ESPによってIPパケットのカプセル化を行って通信するとき、ちょっとした問題が起こることがあります。
  • というのも、ESPヘッダにはポート番号のフィールドがないので、そのままだとNAPT環境(変換のため、ポート番号もチェックされる!)において通信することができないのです。
  • そんな時に、NAPT環境でもIPsecを行うための技術がIPsecパススルーです。
  • NAPT機能をもったブロードバンドルータ上などで動作します。

IPsecパススルーの機能と先着一名問題

  • ざっくり言うと、ESPでカプセル化されたパケットを特別扱いして、IPアドレスだけを変換します。
  • この時に、そのパケットの送信元IPアドレスを覚えておいて、戻りのパケットが送り主にちゃんと戻るように中継します。
  • しかしNAPT装置においてはセッションを識別できない(各パケットの関係性を知ることができない)ことから、1つのVPN先(IPsecでの通信先)に対しては一度に1つの送信元からしか通信できないという制限があります*1
  • この制約は先着一名問題と呼ばれます。

つぶやきLDAP

LDAP(Lightweight Directory Access Protocol) とは?

  • 情報を一元管理し情報提供を行う「ディレクトリサービス」を提供するサーバへアクセスする際に使うプロトコルです。
  • 複雑で処理が重いX.500シリーズ*1のDAP(Directory Access Protocol)を軽量化し(だから "Lightweight")、TCP/IPを用いるインターネットで使えるようにしたものです。

LDAPのキーワード

LDAP識別名(DN:Distributed Name)

  • LDAPによりディレクトリサービスにアクセスする際に、その対象を指定する手段です。
  • 複数のLDAP相対識別名(RDN) をカンマで区切って並べたものです。
  cn=poodle, cn=Dog, dc=sample, dc=com
  # ドメイン「sample.com」のコンテナ「Dog」に配置したデータ「poodle」を示すDN。
  # 因みにcnは "Common-Name", dcは "Domain-Component" のことです。

LDAP認証・LDAP連携

  • Apacheなどのグループウェアサーバで、LDAP連携の設定をしておくとグループウェアサーバ側にアカウント情報を入力しなくとも、LDAPに登録されたアカウント情報をもとに自動でアカウント作成できる機能です。

設定例*2

// sample-serverの設定を表示
# show running-config sample-server LDAP 
aaa-server LDAP protocol ldap
aaa-server LDAP (dmz) host 192.168.10.50
  ldap-base-dn dc=example,dc=com
  ldap-scope subtree
  ldap-naming-attribute sAMAccountName
  ldap-login-password *****
  ldap-login-dn cn=Administrator,cn=Users,dc=example,dc=com
  server-type microsoft
  ldap-attribute-map CSC

// LDAP Attribute Map の設定
# show running-config ldap attribute-map CSC
map-name memberOf Group-Policy
map-value memberOf CN=CSCO_VPN,OU=ENGINEERING,DC=example,DC=com GroupPolicy-CSC

// Connection Profile と Group Policy の設定
# show running-config tunnel-group TunnelGroup-CSC
tunnel-group TunnelGroup-CSC type remote-access
tunnel-group TunnelGroup-CSC general-attributes
authentication-server-group LDAP

つぶやきLACP

LACP(Link Aggregation Control Protocol)

  • リンクアグリゲーションを自動構成するためのプロトコルです。
  • IEEE802.3ad で規格化されていて、さまざまなベンダが混在したネットワーク環境で使用します。

2つのモード

Activeモード

  • いわば「肉食系」モードです。
  • PAgP(シスコ独自のLACP)のDesirableモードに相当します。
  • 自分からLACPDU(LACP Data Unit)を送信し、積極的に論理リンクをつくろうとします。

Passiveモード

  • 「草食系」モードです。
  • PAgPのAutoモードに相当します。
  • 自分からはLACPDUを送信しませんが、受け取ったら論理リンクをつくります。

◆一般的なネットワーク設定ではどちらもActiveにすることが多いです。*1

SWでの設定例

    (config)# vlan 300                               // ポートVLAN(ID300)を定義
      [vlan 300]
    (config)# untagged-port 0/0-6          // ポート0/0~0/6をUntaggedポートに設定
      [vlan 300]
    (config)# router-interface VLAN300  // VLAN名称 "VLAN300" を設定
      [vlan 300]
    (config)# ip 192.168.3.2/24                // VLAN300のIPアドレスを設定
      [vlan 300]
    (config)# exit
    (config)# link-aggregation 10            // LAG IDに10を定義
      [link-aggregation 10]
    (config)# mode lacp                           // LACPを使ったLAGだと設定
      [link-aggregation 10]
    (config)# lacp-activity passive            // Passiveモードを選択
      [link-aggregation 10]
    (config)# key 10                                 // LAGグループが所属するポートのkeyを10に設定
      [link-aggregation 10]
    (config)# aggregated-port 0/3-6       // 0/3~0/6をLAGグループに属するポートに指定
      [link-aggregation 10]
    (config)# exit

LACPリンクアグリゲーションの設定(レイヤ2&レイヤ3機能) より)

*1:みやたひろし『ネットワーク技術&設計入門』(SB Creative)

つぶやきIPsec

「属性」:IPsecとは?

  • IP Security Architecture、もしくはSecurity Architecture for IPの略です。
  • IETF(Internet Engineer Task Force)が中心となって標準化を行ったネットワークセキュリティ技術で、仮想プライベートネットワーク(VPN)の通信プロトコルなどとして幅広く採用されています。(https://www.otsuka-shokai.co.jp/words/ipsec.html)

「機能」:IPsecは何をするのか?

  • インターネットなどのTCP/IPネットワークで暗号通信を行います。
  • 暗号化や認証方法が複数用意されていることから、通信の用途や必要なセキュリティポリシーによって、自分の環境に合わせた設定が行えます。

「要素」:IPsecを支える概念・技術とは?

SA (Security Association)

  • IPsecピア間で確立される単方向のコネクションです。
  • 双方向通信の場合は2つのSAが確立されます。

SPI (Security Parameters Index)

  • 32ビットで構成されます。
  • IPsec通信の各パケットに挿入され、そのパケットに適用されたSAの識別キーとなります。

SP (Security Policy)

  • IPsecルータが選択する、パケット処理のポリシーです。
  • セレクタと呼ばれるキーを使ってポリシーを選びます。セレクタにはIPアドレス、プロトコル、ポート番号などが使われます。
  • ポリシーは下に示す3種類です。

  • PROTECT: IPsecを適用して送信

  • BYPASS: IPsecを適用せずに送信
  • DISCARD: パケットを廃棄する

IKE (Internet Key Exchange)

  • 共通鍵のもとになる値を交換するプロトコルです
  • DH鍵交換方式を改良しました
  • UDPのポート500番を使用します

ESP (Encapsulating Security Protocol)

  • IPsecにおいて暗号化・メッセージ認証を担うプロトコルです
  • 運用モードによって暗号化範囲は異なります

AH (Authentication Header)

  • データのメッセージ認証を行います
  • 暗号化通信が禁止されている国では、ESPの代わりにこのAHが使われます