2024年5月8日水曜日

Cygwin 上に pyenv をインストールする方法

Cygwin 上に pyenv をインストールする方法

概要

pyenv はインストールできました
が Python のビルドは失敗しました
メモとして残しておきます

環境

  • Windows10 22H2
  • Cygwin 3.5.3
  • pyenv 2.4.0

pyenv インストール手順

  • apt-cyg install bash curl make automake gcc-core gcc-g++ zlib zlib-devel libffi-devel
  • wget -O pyenv_install.sh https://pyenv.run
  • vim pyenv_install.sh
  • curl に -k オプションを追加
  • vim ~/.bashrc
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

一度クローズして pyenv コマンドが使えることを確認

Python ビルド (失敗)

  • pyenv install --list
  • pyenv install 3.11.9
Downloading Python-3.11.9.tar.xz...
-> https://www.python.org/ftp/python/3.11.9/Python-3.11.9.tar.xz
Installing Python-3.11.9...

BUILD FAILED (CYGWIN_NT-10.0-19045 3.5.3-1.x86_64 using python-build 20180424)

Inspect or clean up the working tree at /tmp/python-build.20240507170209.2270
Results logged to /tmp/python-build.20240507170209.2270.log

Last 10 log lines:
Traceback (most recent call last):
  File "<frozen runpy>", line 189, in _run_module_as_main
  File "<frozen runpy>", line 148, in _get_module_details
  File "<frozen runpy>", line 112, in _get_module_details
  File "/tmp/python-build.20240507170209.2270/Python-3.11.9/Lib/ensurepip/__init__.py", line 4, in <module>
    import subprocess
  File "/tmp/python-build.20240507170209.2270/Python-3.11.9/Lib/subprocess.py", line 104, in <module>
    from _posixsubprocess import fork_exec as _fork_exec
ModuleNotFoundError: No module named '_posixsubprocess'
make: *** [Makefile:1865: install] Error 1

最後に

ビルドする方法はあるのだろうか
大人しく pyenv-win を使うのがいいと思います

2024年5月7日火曜日

RQ でジョブがエラーになった際の挙動を確認する

RQ でジョブがエラーになった際の挙動を確認する

概要

ジョブ内で raise した際の挙動を確認してみました

環境

  • macOS 11.7.10
  • Python 3.11.6
  • rq 1.16.1

サンプルコード

エンキューする側のコードは以下です

from datetime import timedelta

from redis import Redis
from rq import Queue
from rq_scheduler import Scheduler

from lib.util import Message

queue = Queue("default", connection=Redis(host="192.168.1.2"))
scheduler = Scheduler(queue=queue, connection=queue.connection)


scheduler.enqueue_in(timedelta(seconds=5), Message().say, msg="hello")

ジョブは単純に raise するようにしています

import time


class Message:
    def say(self, **kwargs):
        print("Start say")
        print(kwargs)
        time.sleep(10)
        raise ValueError()
        # print("End say")

起動

  • pipenv run rq worker
  • pipenv run rqscheduler
  • pipenv run app.py

動作確認

failed のジョブを確認

redis 内のキーの情報を確認すると failed したジョブの情報が格納されています

1) "rq:job:2c380d9c-c65b-41b8-8d92-3b85135782c0"
2) "rq:results:2c380d9c-c65b-41b8-8d92-3b85135782c0"
3) "rq:failed:default"
4) "rq:scheduler_instance:e276ed31a4434691b91c426e979a9e4d"
5) "rq:worker:86f028648da249c38de683f8ce10f865"
6) "rq:queues"

失敗したジョブは zset としてジョブIDが格納されています

127.0.0.1:6379> zrange rq:failed:default 0 -1
1) "2c380d9c-c65b-41b8-8d92-3b85135782c0"

結果には何も格納されていませんでした

ワーカーは自動でリトライすることはなさそう

オプションを付与していない限りリトライはしないようです

なおワーカー、スケジューラを再起動しても特にリトライはしませんでした

失敗したジョブの情報を確認するスクリプト

FailedJobRegistry として管理されています
以下のスクリプトを実行すると失敗したジョブの情報を一覧で表示してくれます

from redis import Redis
from rq import Queue
from rq.job import Job
from rq.registry import FailedJobRegistry

redis = Redis()
queue = Queue(connection=redis)
registry = FailedJobRegistry(queue=queue)

# Show all failed job IDs and the exceptions they caused during runtime
for job_id in registry.get_job_ids():
    job = Job.fetch(job_id, connection=redis)
    print(job_id, job.exc_info)

最後に

rq では基本はリトライせず失敗したジョブは別途管理されるようです

参考サイト

2024年5月2日木曜日

Mac で gcloud コマンドのタブ補完を有効にする方法

Mac で gcloud コマンドのタブ補完を有効にする方法

概要

zsh の場合はを紹介します

環境

  • macOS 11.7.10
  • google-cloud-sdk 468.0.0
  • Python 3.12.2

補完を有効にする方法

  • vim ~/.zshrc
source "$(brew --prefix)/share/google-cloud-sdk/path.zsh.inc"
source "$(brew --prefix)/share/google-cloud-sdk/completion.zsh.inc"

参考

brew info google-cloud-sdk を実行するとちゃんと表示されていました
bash などの方法も記載されています

brew info google-cloud-sdk
==> google-cloud-sdk: 470.0.0 (auto_updates)
https://cloud.google.com/sdk/
/usr/local/Caskroom/google-cloud-sdk/468.0.0 (129B)
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/g/google-cloud-sdk.rb
==> Name
Google Cloud SDK
==> Description
Set of tools to manage resources and applications hosted on Google Cloud
==> Artifacts
google-cloud-sdk/install.sh (Installer)
google-cloud-sdk/bin/git-credential-gcloud.sh -> git-credential-gcloud (Binary)
google-cloud-sdk/completion.zsh.inc -> /usr/local/share/zsh/site-functions/_google_cloud_sdk (Binary)
google-cloud-sdk/bin/gsutil (Binary)
google-cloud-sdk/bin/anthoscli (Binary)
google-cloud-sdk/bin/bq (Binary)
google-cloud-sdk/completion.bash.inc -> /usr/local/etc/bash_completion.d/google-cloud-sdk (Binary)
google-cloud-sdk/bin/docker-credential-gcloud (Binary)
google-cloud-sdk/bin/gcloud (Binary)
==> Caveats
To add gcloud components to your PATH, add this to your profile:

  for bash users
    source "$(brew --prefix)/share/google-cloud-sdk/path.bash.inc"

  for zsh users
    source "$(brew --prefix)/share/google-cloud-sdk/path.zsh.inc"
    source "$(brew --prefix)/share/google-cloud-sdk/completion.zsh.inc"

  for fish users
    source "$(brew --prefix)/share/google-cloud-sdk/path.fish.inc"

==> Analytics
install: 11,433 (30 days), 32,208 (90 days), 107,295 (365 days)

最後に

これでサブコマンドなどの補完が行えます

2024年5月1日水曜日

docker kics 超入門

docker kics 超入門

概要

kicsはIaC用のセキュリティチェックツールです
Dockerfile や k8s の YAML ファイルにセキュリティ的な脆弱性や記載がないかをチェックしてくれます

今回はとりあえず動かしてみました
docker で動かします

環境

  • macOS 11.7.10
  • docker 24.0.2
  • kics 1.7.13

コマンド

  • docker run -t -v $(pwd):/path checkmarx/kics:latest scan -p /path -o "/path/"

結果確認

ターミナルにも結果が表示されますが results.json というファイルでも保存されています

  • cat results.json
{
        "kics_version": "v1.7.13",
        "files_scanned": 2,
        "lines_scanned": 10,
        "files_parsed": 2,
        "lines_parsed": 10,
        "lines_ignored": 0,
        "files_failed_to_scan": 0,
        "queries_total": 291,
        "queries_failed_to_execute": 0,
        "queries_failed_to_compute_similarity_id": 0,
        "scan_id": "console",
        "severity_counters": {
                "HIGH": 0,
                "INFO": 0,
                "LOW": 0,
                "MEDIUM": 0,
                "TRACE": 0
        },
        "total_counter": 0,
        "total_bom_resources": 0,
        "start": "2024-04-17T01:07:50.40506235Z",
        "end": "2024-04-17T01:09:50.037978163Z",
        "paths": [
                "/path"
        ],
        "queries": []
}

再帰的に実行するには

オプションではないようです
-p オプションで複数のディレクトリを指定すれば複数のディレクトリに対してスキャンしてくれるようです

  • docker run -t -v $(pwd):/path checkmarx/kics:latest scan -p /path -p /path/archive -o "/path/"

脆弱性がある場合には

例えば Dockerfile に脆弱性がある場合は以下のようなエラーが表示されます

Missing User Instruction, Severity: HIGH, Results: 1
Description: A user should be specified in the dockerfile, otherwise the image will run as root
Platform: Dockerfile
CWE: 250
Learn more about this vulnerability: https://docs.kics.io/latest/queries/dockerfile-queries/fd54f200-402c-4333-a5a4-36ef6709af2f

        [1]: ../../path/Dockerfile:1

                001: FROM ruby:3.1.2
                002: 
                003: ADD . /home



Results Summary:
HIGH: 1
MEDIUM: 5
LOW: 4
INFO: 0
TOTAL: 10

Generating Reports: Done

最後に

IaC のコードのセキュリティチェックができる kics を試してみました
使うこと自体は簡単にできそうです

Query という機能を使って簡単に脆弱性ルールを追加することもできます

参考サイト

2024年4月30日火曜日

Traefik 超入門

Traefik 超入門

概要

Traefik は Host ヘッダベースのリバースプロキシです
ルーティングのルールを細かく設定できたりパスベースのルーティングも実現できます
設定ファイルも YAML で記載できる他正規表現などのルールも作成できます
今回は docker 上で簡単に動かしてみました

環境

  • macOS 11.7.10
  • docker 24.0.2
  • traefik 3.0

まずは traefik を起動する

リバースプロキシのみ起動します
このあとでアプリをぶら下げて Host ヘッダベースでバランシングできているか確認します

  • vim docker-compose.yml
version: '3'

services:
  reverse-proxy:
    image: traefik:v3.0
    command: --api.insecure=true --providers.docker
    ports:
      # The HTTP port
      - "80:80"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
  • docker-compose up -d

で localhost:8080 にアクセスすると traefik のダッシュボードを確認できます

この段階で localhost にアクセスしてもアプリがないので 404 が返ってきます

アプリをぶら下げる

traefik の下にアプリをぶら下げる設定を追加します

  • vim docker-compose.yml
version: '3'

services:
  reverse-proxy:
    image: traefik:v3.0
    command: --api.insecure=true --providers.docker
    ports:
      # The HTTP port
      - "80:80"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
  whoami:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

コンテナにラベルを振ることで Host ヘッダの値に応じてバランシングしてくれます
一度 down させて再度起動します
ちなみに traefik/whoami はただのデバッグ用のアプリになります

  • docker-compose down
  • docker-compose up -d
  • docker-compose ps
NAME                         IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
python-try-reverse-proxy-1   traefik:v3.0        "/entrypoint.sh --ap…"   reverse-proxy       25 seconds ago      Up 23 seconds       0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp
python-try-whoami-1          traefik/whoami      "/whoami"                whoami              25 seconds ago      Up 23 seconds       80/tcp

これで今度は Host ヘッダを付与してアプリにアクセスしてみます
するとちゃんと whoami アプリにアクセスできていることが確認できます

  • curl -H "Host: whoami.docker.localhost" localhost
Hostname: 716c5a018b13
IP: 127.0.0.1
IP: 172.19.0.2
RemoteAddr: 172.19.0.3:57016
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: curl/8.4.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.19.0.1
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: c8479f4b7c06
X-Real-Ip: 172.19.0.1

もう一台追加してバランシングされるか確認する

一台だと味気ないのでもう一台追加してちゃんと Host を変えたときに正しいアプリにバランシングされることを確認してみます
whoami アプリをもう一つ追加します

  • vim docker-compose.yml
version: '3'

services:
  reverse-proxy:
    image: traefik:v3.0
    command: --api.insecure=true --providers.docker
    ports:
      # The HTTP port
      - "80:80"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
  whoami:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
  whoami2:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.http.routers.whoami2.rule=Host(`whoami2.docker.localhost`)"

ラベルも whoami2 にして追加します
これで再作成してみます

  • docker-compose down
  • docker-compose up -d
  • docker-compose ps
NAME                         IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
python-try-reverse-proxy-1   traefik:v3.0        "/entrypoint.sh --ap…"   reverse-proxy       55 seconds ago      Up 54 seconds       0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp
python-try-whoami-1          traefik/whoami      "/whoami"                whoami              55 seconds ago      Up 54 seconds       80/tcp
python-try-whoami2-1         traefik/whoami      "/whoami"                whoami2             55 seconds ago      Up 54 seconds       80/tcp

そして再度 Host ヘッダを変更してアクセスすると別の whoami アプリにバランシングされていることが確認できます

  • curl -H "Host: whoami.docker.localhost" localhost
Hostname: 77c5ff6e72f4
IP: 127.0.0.1
IP: 172.21.0.4
RemoteAddr: 172.21.0.3:36418
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: curl/8.4.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.21.0.1
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 60057b9154e0
X-Real-Ip: 172.21.0.1
  • curl -H "Host: whoami2.docker.localhost" localhost
Hostname: e6cef80986c8
IP: 127.0.0.1
IP: 172.21.0.2
RemoteAddr: 172.21.0.3:47060
GET / HTTP/1.1
Host: whoami2.docker.localhost
User-Agent: curl/8.4.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.21.0.1
X-Forwarded-Host: whoami2.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 60057b9154e0
X-Real-Ip: 172.21.0.1

最後に

Traefik を使って Host ベースのアプリバランシングをしてみました
nginx などのリバースプロキシでも Host ベースのバランシングはできますがラベルにルール付やデフォルトで管理用のダッシュボードなどは用意されていません
また定義を YAML で書けるのも便利です
違いについてはこのあたりが非常にまとまっているので興味があれば見てみてください

また今回は紹介しませんが k8s との連携も簡単にできるのも特徴です

参考サイト

2024年4月29日月曜日

Outlook のマクロでメッセージの一覧を取得する方法

Outlook のマクロでメッセージの一覧を取得する方法

概要

メッセージの件数が長いと Outlook が固まるので注意しましょう

環境

  • Windows 10
  • Outlook 2302 build 16.0

サンプルコード

Option Explicit
Public Sub Outlook_mail_list()
    ' 変数定義
    Dim InboxFolder, i, n, k As Long
    Dim outlookObj As Outlook.Application
    Dim myNameSpace, objmailItem As Object
 
    ' 変数初期化
    Set outlookObj = CreateObject("Outlook.Application")
    Set myNameSpace = outlookObj.GetNamespace("MAPI")
    Set InboxFolder = myNameSpace.GetDefaultFolder(6)
    n = 2
 
    ' 現在のメールの数を取得、数が多い場合はループの数は固定したほうが良い
    Debug.Print InboxFolder.Items.Count
    ' For i = 1 To InboxFolder.Items.Count
    For i = 1 To 100
        Set objmailItem = InboxFolder.Items(i)
 
        ' メールの内容を表示、参照可能なプロパティはこちらを参照 https://learn.microsoft.com/ja-jp/office/vba/api/outlook.mailitem.senderemailaddress
        Debug.Print i
        Debug.Print "SenderEmailAddress: " + objmailItem.SenderEmailAddress
        Debug.Print "To" + objmailItem.To
        ' Stop
        n = n + 1
    Next
 
    ' 変数の削除
    Set outlookObj = Nothing
    Set myNameSpace = Nothing
    Set InboxFolder = Nothing
End Sub

最後に

マクロでメッセージの一覧を取得して見ました
エクセルのマクロでも動作するはずです

参考サイト

2024年4月28日日曜日

Apps Script で doGet を実装して http リクエストを受け取れるようにする

Apps Script で doGet を実装して http リクエストを受け取れるようにする

概要

Google Apps Script にはウェブアプリとしてデプロイできる機能がありこれを使うことで Apps Script の特定の関数を curl からコールできるようになります
今回はその方法を紹介します

環境

  • Google Apps Script (2024/04/22 時点)

doGet の実装

function doGet(e) {
  var params = JSON.stringify(e);
  return ContentService.createTextOutput(params).setMimeType(ContentService.MimeType.JSON);
}

アプリのデプロイ

curl で実行する場合には全公開する必要があります

ウェブアプリの URL が発行されるのでメモしておきます

動作確認

リダイレクトがあるので curl の場合は -L を付与します

  • curl -L "https://script.google.com/macros/s/xxxxxx/exec"
{"contextPath":"","parameter":{},"parameters":{},"contentLength":-1,"queryString":""}

クエリストリングも送れます

  • curl -L "https://script.google.com/macros/s/xxxxxx/exec?name=hawksnowlog"
{"contentLength":-1,"parameters":{"name":["hawksnowlog"]},"queryString":"name=hawksnowlog","parameter":{"name":"hawksnowlog"},"contextPath":""}

最後に

AppsScript で定義した関数を外部からコールできるようにしてみました
ショートカットにしておけばアクセスするだけで特定のデータを抽出したりできます

自分しかアクセスできないウェブアプリの場合はブラウザでしかアクセスできないので注意しましょう

参考サイト