2021年11月30日火曜日

RaspberryPi4 の ds64-shell に python をインストールする

RaspberryPi4 の ds64-shell に python をインストールする

概要

ds64 環境にはデフォルトではインストールされていないのでインストールが必要です

環境

  • RaspberryPi4 8GRAM
  • RaspberryPiOS 5.10.17 armv7l

インストール

  • ds64-shell
  • sudo apt -y update
  • sudo apt -y install python3
  • sudo apt -y install python3-pip
  • pip3 install pigpio RPi.GPIO

ただ意味はないかも

「RuntimeError: Not running on a RPi!」というエラーになり gpio などの制御はできないようです

2021年11月29日月曜日

RaspberyPi でフルカラーLEDを制御してみた

RaspberyPi でフルカラーLEDを制御してみた

概要

PWM を使ってフルカラーLEDでいろんな色を点滅させてみました

環境

  • RaspberryPi4 8GRAM
  • RaspberryPiOS 5.10.17 armv7l
  • Python 2.7.16
    • pigpio 1.78

サンプルコード

後述でポイントを紹介しています
処理の概要はコメントにて記載しています

  • vim test_full_color_led.py
# -*- coding: utf-8 -*-
"""フルカラーのLEDを制御するモジュール."""
import RPi.GPIO as GPIO
import time
import logging

from logging import getLogger


class FullColorLEDTest():
    """フルカラーのLEDをテストするクラス."""

    # 各ピン定義
    RED = 11
    GREEN = 12
    BLUE = 13

    def __init__(self):
        """ピンを初期化します."""
        logging.basicConfig(level=logging.INFO)
        self.logger = getLogger(__name__)
        # RGB のカラーコードをここに記載します
        self.colors = [
            # red, green, blue, yellow, purple, cyan になります
            0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF
        ]
        pin_def = {
            self.RED: 2000,  # red
            self.GREEN: 2000,  # green
            self.BLUE: 5000,  # blue
        }
        GPIO.setmode(GPIO.BOARD)
        # 制御するピンを管理するdict
        self.pins = {
            self.RED: None,
            self.GREEN: None,
            self.BLUE: None,
        }
        # 各ピンの初期化
        for pin_num, freq in pin_def.items():
            GPIO.setup(pin_num, GPIO.OUT)
            pin = GPIO.PWM(pin_num, freq)
            pin.start(0)
            self.pins[pin_num] = pin
        self.logger.info('Started pwm pins for a full color led.')

    def calc_duty(self, x, in_min, in_max, out_min, out_max):
        """デューティー比を計算します."""
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

    def blink_color(self, col):
        """各ピンに色を設定し指定の色を光らせます."""
        # 左ビットシフト
        red = (col & 0x110000) >> 16
        green = (col & 0x001100) >> 8
        blue = (col & 0x000011) >> 0
        # デューティー比に変換 (0-100)
        red = self.calc_duty(red, 0, 255, 0, 100)
        green = self.calc_duty(green, 0, 255, 0, 100)
        blue = self.calc_duty(blue, 0, 255, 0, 100)
        # ピンにデューティー比を設定
        self.pins[self.RED].ChangeDutyCycle(red)
        self.pins[self.GREEN].ChangeDutyCycle(green)
        self.pins[self.BLUE].ChangeDutyCycle(blue)

    def blink(self):
        """フルカラーLEDを点滅させます."""
        try:
            self.logger.info('Started blinking a full color led.')
            while True:
                for col in self.colors:
                    self.blink_color(col)
                    time.sleep(0.5)
        except KeyboardInterrupt:
            pass
        finally:
            self.cleanup()

    def cleanup(self):
        """クリーンアップ処理を実行します."""
        for pin in self.pins.values():
            pin.stop()
        GPIO.cleanup()
        self.logger.info('The pin cleanup process was completed.')


if __name__ == "__main__":
    test = FullColorLEDTest()
    test.blink()

説明

今回使用したフルカラーLEDは赤青緑で3ピン必要になるのでピンを管理する dict を準備しました (この辺りはクラスにしてもいいかも)

ピンの情報と周波数も別途 dict で定義しています

init でピンの初期化を行ったあとは blink で各カラーを順番に点滅させます
点滅させたい色は self.colors で定義していので他の色を点滅させたい場合はここに追加していきます

定義したカラーコードを実際にはデューティー比に変換する必要があります
それは calc_duty で行っておりカラーコードを 0 から 100 の範囲に変換する処理を行っています

あとは変換した値を ChangeDutyCycle で各ピンに対して設定して上げれば OK です

回路

  • 11 -> 赤のピン
  • 12 -> 緑のピン
  • 13 -> 青のピン
  • 6 (GND) -> カソード

に接続するだけです
各色を管理するピンは 220 オームの抵抗を挟んで接続しています

動作確認

  • python test_full_color_led.py

で実行しましょう
以下のように順番に点滅すれば成功です

最後に

フルカラーLED と PWM を使えば好きな色の LED を光らせることができます
少しお値段が高いのが難点ですが便利です

各ピンの出力周波数に関しては参考にさせていただいたサイトの値をそのまま拝借しているだけなのでフルカラーLED の種類によっては調整の必要があるかもしれません

参考サイト

2021年11月27日土曜日

Gitlab + AzureAD + SAML 連携

Gitlab + AzureAD + SAML 連携

概要

Gitlab の OmniAuth Provider を使って Azure AD と SAML 連携してみました
AzureAD の oauth2 連携の記事はよく見るのですが SAML 連携はあまり見ない気がします

ポイントは AzureAD でエンタープライズアプリケーション「Azure AD SAML Toolkit」を作成する点です

環境

  • Gitlab 14.3.4-ee
  • AzureAD (20211126 時点)

AzureAD で Azure AD SAML Toolkit エンタープライズアプリケーションの作成

まずは AzureAD でエンタープライズアプリケーションを作成します
Azure ポータルにログインしたら「Azue Active Directory」を選択します

AzureAD のトップページに来たら左メニューの「エンタープライズアプリケーション」を選択します

「新しいアプリケーション」からエンタープライズアプリケーションを作成します

検索窓で「Azure Toolkit」で検索しましょう
すると「Azure AD SAML Toolkit」が表示されるので選択します
右ペインで名前を入力できるので好きな名前を入力して「作成」しましょう

エンドポイントの確認

エンタープライズアプリケーションは普通のアプリとしても登録されています
左メニューの「アプリの登録」からアプリの一覧を確認できます

アプリの詳細を選択して「エンドポイント」を選択すると SAML ログインに必要な URL が表示さます
「SAML-P サインオンエンドポイント」に記載されている URL をメモしておきましょう

シングルサインオンの設定

作成されたエンタープライズアプリケーションを選択し詳細画面にいきます
先程は「アプリの登録」でアプリを確認しましたがエンタープライズアプリケーションは左メニューの「エンタープライズアプリケーション」から確認できます

一覧から作成した Azure AD SAML Toolkit のエンタープライズアプリケーションを選択しましょう

シングルサインオンの設定にある「作業の開始」を選択します

そして SAML を選択します

1 番の「基本的なSAML構成」を「編集」します
右ペインに必要な情報を入力します

  • 識別子・・・GitlabのURL
  • 応答 URL・・・GItlabのURLのコールバックURL
  • サインオンURL・・・先程アプリの登録のエンドポイントで確認したURL

入力したら「保存」しましょう

シングルサインオンから必要な情報をメモ

3 番に「SAML 署名証明書」があります
ここの「拇印」をメモしておきましょう

email 属性の追加

2 番に「属性とクレーム」があります
Gitlab と SAML 連携する場合には必ず email or mail という属性がレスポンスに含まれている必要があります

編集を選択します

  • 名前・・・email
  • 名前空間・・・空
  • ソース・・・属性
  • ソース属性・・・user.mail

と入力し「保存」します

アプリにユーザを登録する

左メニューの「ユーザとグループ」を選択します まだユーザはいないので「ユーザまたはグループの追加」を選択します

好きなユーザやグループを登録しましょう
Gitlab からログインできるユーザはここでエンタープライズアプリケーションに紐付けたユーザまたはグループのみになります

gitlab.rb の修正

あとは gitlab.rb を編集します
OmniAuth の部分を編集します

記載する箇所を5箇所です

  • assertion_consumer_service_url・・・Gitlabのコールバック用のURL
  • idp_cert_fingerprint・・・先程確認した拇印
  • idp_sso_target_url・・・エンドポイントで確認したSAMLサインオンURL
  • issuer・・・GitlabのURL
  • label・・・ログイン時に表示される文言

あと任意で変更して良さそうな名は omniauth_block_auto_created_users になります
true にすると SAML 経由でログインしたユーザは自動で登録されずに Gitlab の Admin ユーザの承認を待ってからログインすることができます
false になっていれば自動で承認されて使えるようになります

gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_auto_link_saml_user'] = true
gitlab_rails['omniauth_providers'] = [
  {
    name: "saml",
    label: "AzureAdTest",
    args: {
      assertion_consumer_service_url: "https://your.gitlab.example.com/users/auth/saml/callback",
      idp_cert_fingerprint: "3番で確認した拇印",
      idp_sso_target_url: "アプリ登録のエンドポイントで確認したSAMLサインオンURL",
      issuer: "https://your.gitlab.example.com",
      name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
    }
  }
]

必要な箇所が修正できたら reconfigure を実行しましょう

動作確認

Gitlab にアクセスするとログインフォームの下の方に Azure AD でログインするためのボタンが設置されます

ボタンを押すと MS のログイン画面に遷移するのでここで先程登録したユーザやグループに属するユーザでログインしてみましょう

トラブルシューティング

422 でログインできない場合は email 属性がちゃんと設定されているか確認しましょう

最後に

AzureAD + Gitlab + SAML 認証を試してみました

一番わかりづらかったのはエンタープライズアプリケーションを作る点でした
普通のアプリケーションだと SAML の設定項目がなく oauth2 しかできなさそうなので注意しましょう

今回は「Azure AD SAML Toolkit」を使いましたがもしかするとそのうちエンタープライズアプリケーションの一覧に「Gitlab」が登場するかもしれません

また今回やらなかったこととして他の属性の連携 (name) やユーザの2authの対応などはやりませんでした
この辺りもできそうなので興味があれば調べてみると良いかもしれません

参考サイト

2021年11月26日金曜日

RaspberryPi4 で PWM 入門 (Lフワ)

RaspberryPi4 で PWM 入門 (Lフワ)

概要

LED を PWM というアナログ信号を使ってゆっくり点滅させてみます
サンプルコードと回路を紹介します

環境

  • RaspberryPi4 8GRAM
  • RaspberryPiOS 5.10.17 armv7l
  • Python 2.7.16
    • pigpio 1.78

サンプルコード

後述でポイントを紹介しています
処理の概要はコメントにて記載しています

  • vim test_pwm.py
# -*- coding: utf-8 -*-
"""PWMのテストをするモジュール."""
import time
import RPi.GPIO as GPIO
import logging

from logging import getLogger


class TestPWM():
    """PWMのテストをするクラス."""

    def __init__(self):
        """GPIOやピン初期化を行います."""
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(12, GPIO.OUT)
        # channel=12 frequency=50Hz
        self.pin = GPIO.PWM(12, 50)
        logging.basicConfig(level=logging.INFO)
        self.logger = getLogger(__name__)

    def start(self):
        """pinをスタートさせます."""
        self.pin.start(0)
        self.logger.info('Started a pin for pwm.')

    def blink(self):
        """LEDをPWMで点滅させます."""
        self.logger.info('Started led blinking loop.')
        try:
            while True:
                # 5 刻みでデューティー比を変更します 0 -> 100
                for dc in range(0, 101, 5):
                    self.pin.ChangeDutyCycle(dc)
                    time.sleep(0.1)
                # 5 刻みでデューティー比を変更します 100 -> 0
                for dc in range(100, -1, -5):
                    self.pin.ChangeDutyCycle(dc)
                    time.sleep(0.1)
        except KeyboardInterrupt:
            pass
        finally:
            self.cleanup()

    def cleanup(self):
        """クリーンアップ処理をします."""
        self.pin.stop()
        GPIO.cleanup()
        self.logger.info('The pin cleanup process was completed.')


if __name__ == "__main__":
    pwm = TestPWM()
    pwm.start()
    pwm.blink()

ポイント

ピンを PWM 用として使う場合に GPIO.setup したあとに GPIO.PWM を呼び出します

周波数は高いほどより電力を必要とするアクチュエータなどを動かすことができます
今回は LED なので 50Hz ほどで十分です

ChangeDutyCycle で明るさを調整します
0 から 100 までで指定することができ 0 が暗くなり 100 が明るくなります
モーターなどの場合だと 0 が遅く、100 が速く回ります

処理が終了した際に必ずピンをもとに戻す必要があるので finally でクリーンアップしましょう

回路とサンプル動画

RaspberryPi の 6 ピンが GND になっています
12 ピンを LED のアノード側に 220 オームの抵抗を挟んで接続しています

実際にスクリプトを動作させると以下のように点滅するのが確認できると思います

最後に

RaspberryPi の場合ソフトウェア PWM という仕組みで PWM を出力しています
オシロスコープがある場合は波形を確認するとちゃんとした矩形波が出ていることが確認できると思います

自分は試していませんが RaspberryPi の周波数の上限は 8,000Hz ほどのようです
DC モーターなどは何とかなりそうですがステッピングモーターなど大きなモーターの場合にはモータドライバなどを使ったほうが良いでしょう

参考サイト

2021年11月25日木曜日

Gitlab CI でジョブが失敗したときに別のジョブを呼び出す方法

Gitlab CI でジョブが失敗したときに別のジョブを呼び出す方法

概要

when: on_failure を使います
ジョブごとに失敗した場合の挙動を指定したい場合は needs と組み合わせます

環境

  • RaspberryPi4 8GRAM
  • RaspberryPiOS 5.10.17 armv7l
  • Gitlab Runner 14.5.0

サンプル .gitlab-ci.yml

cleanup_build_job が何かしらのジョブが失敗した場合にコールされるジョブになります
when: on_failure が指定されていることがわかります

stages:
  - stage1
  - cleanup

.echo1_script: &echo1_script
  - "export MSG=hello"
  - "echo ${MSG} >> msg.txt"
  - "export MSG=HELLO"

.echo2_script: &echo2_script
  - "hoge"
  - "echo ${MSG} >> msg.txt"

cleanup_build_job:
  stage: cleanup
  script:
    - "echo 'Succeed cleanup.' >> msg.txt"
  when: on_failure
  artifacts:
    paths:
      - msg.txt

echo:
  stage: stage1
  script:
    - *echo1_script
    - *echo2_script
  artifacts:
    paths:
      - msg.txt

ジョブごとに失敗した場合の挙動を設定する場合

needs と組み合わせます
これを失敗した場合に実行するジョブごとに指定してあげることでそれぞれで失敗した場合の挙動を変えることができます

stages:
  - stage1
  - stage2
  - cleanup

.echo1_script: &echo1_script
  - "export MSG=hello"
  - "echo ${MSG} >> msg.txt"
  - "export MSG=HELLO"

.echo2_script: &echo2_script
  - "hoge"
  - "echo ${MSG} >> msg.txt"

cleanup_build_job_for_echo1:
  stage: cleanup
  script:
    - "echo 'Succeed cleanup by echo1.' >> msg.txt"
  when: on_failure
  needs: ["echo1"]
  artifacts:
    paths:
      - msg.txt

cleanup_build_job_for_echo2:
  stage: cleanup
  script:
    - "echo 'Succeed cleanup by echo2.' >> msg.txt"
  when: on_failure
  needs: ["echo2"]
  artifacts:
    paths:
      - msg.txt

echo1:
  stage: stage1
  script:
    - *echo1_script
  artifacts:
    paths:
      - msg.txt

echo2:
  stage: stage2
  script:
    - *echo2_script
  artifacts:
    paths:
      - msg.txt

ジョブの流れは以下のようになります
echo2 が失敗した場合には cleanup_build_job_for_echo2 だけが実行されています

echo2 も常に実行したい場合には

ただこの場合だと以下のように echo2 は実行されないので echo2 も常に実行したほしい場合には when: always を指定します

stages:
  - stage1
  - stage2
  - cleanup

.echo1_script: &echo1_script
  - "hoge"
  - "export MSG=hello"
  - "echo ${MSG} >> msg.txt"
  - "export MSG=HELLO"

.echo2_script: &echo2_script
  - "echo ${MSG} >> msg.txt"

cleanup_build_job_for_echo1:
  stage: cleanup
  script:
    - "echo 'Succeed cleanup by echo1.' >> msg.txt"
  when: on_failure
  needs: ["echo1"]
  artifacts:
    paths:
      - msg.txt

cleanup_build_job_for_echo2:
  stage: cleanup
  script:
    - "echo 'Succeed cleanup by echo2.' >> msg.txt"
  when: on_failure
  needs: ["echo2"]
  artifacts:
    paths:
      - msg.txt

echo1:
  stage: stage1
  script:
    - *echo1_script
  artifacts:
    paths:
      - msg.txt

echo2:
  stage: stage2
  script:
    - *echo2_script
  when: always
  artifacts:
    paths:
      - msg.txt

こんな感じで echo1 が失敗しても echo2 が実行されていることがわかります

最後に

これで失敗した場合にも特定のスクリプトを実行することができるようになりました

また調べてみると expected_stage_fail や on_failure_script と言った書き方もでてきたのですが expected_stage_fail や on_failure_script はどうやら使えないようです
https://gitlab.com/gitlab-org/gitlab/-/issues/19400

参考サイト

2021年11月24日水曜日

RaspberryPi4 に gitlab-runner をインストールする方法

RaspberryPi4 に gitlab-runner をインストールする方法

概要

今回は shell-executor として登録します
基本は ds64 モードで勧めていますが aarch64 でもインストールできます

環境

  • RaspberryPi4 8GRAM
  • RaspberryPiOS 5.10.17 armv7l

ds64-shell の起動

作業は 64bit 環境で行います

  • ds64-shell

curl, wget のインストール

  • sudo apt -y install curl wget

証明書系のツールインストール

libgnutls30 もインストールします
これがないと git clone 時にエラーになります

  • sudo apt -y install apt-transport-https ca-certificates libgnutls30

gitlab-runner のインストール

Gitlab の公式のリポジトリからインストールします
ds64 環境ではない 64bit 環境 (aarch64) ではこの手順から実行します

  • curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
  • sudo apt-get install gitlab-runner
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  docker-engine
The following NEW packages will be installed:
  gitlab-runner
0 upgraded, 1 newly installed, 0 to remove and 90 not upgraded.
Need to get 437 MB of archives.
After this operation, 476 MB of additional disk space will be used.
Get:1 https://packages.gitlab.com/runner/gitlab-runner/debian buster/main arm64 gitlab-runner arm64 14.5.0 [437 MB]
Fetched 437 MB in 2min 10s (3,375 kB/s)                                                                                                     
Selecting previously unselected package gitlab-runner.
(Reading database ... 38144 files and directories currently installed.)
Preparing to unpack .../gitlab-runner_14.5.0_arm64.deb ...
Unpacking gitlab-runner (14.5.0) ...
Setting up gitlab-runner (14.5.0) ...
GitLab Runner: creating gitlab-runner...
Home directory skeleton not used
Runtime platform                                    arch=arm64 os=linux pid=2632 revision=f0a95a76 version=14.5.0
gitlab-runner: the service is not installed
Runtime platform                                    arch=arm64 os=linux pid=2643 revision=f0a95a76 version=14.5.0
gitlab-ci-multi-runner: the service is not installed
Runtime platform                                    arch=arm64 os=linux pid=2673 revision=f0a95a76 version=14.5.0
Runtime platform                                    arch=arm64 os=linux pid=2721 revision=f0a95a76 version=14.5.0
INFO: Docker installation not found, skipping clear-docker-cache

runner の登録

Gitlab の URL とトークンを入力して登録します
executor は「shell」を入力しましょう

  • sudo gitlab-runner register

また gitlab-runner ユーザに gpio 関連を操作できるように権限を与えます

  • sudo usermod -aG gpio gitlab-runner

動作確認

プロジェクトに以下のような .gitlab-ci.yml を登録して成功するか確認しましょう

stages:
  - stage1
  - stage2

.echo1_script: &echo1_script
  - "export MSG=hello"
  - "echo ${MSG}"
  - "export MSG=HELLO"

.echo2_script: &echo2_script
  - "echo ${MSG}"

echo:
  image:
    name: alpine:latest
  stage: stage1
  script:
    - *echo1_script
    - *echo2_script

停止する場合は ds64-shell で

  • sudo systemctl stop gitlab-runner

再度起動する場合は ds64-shell で

  • sudo systemctl start gitlab-runner

します

トラブルシュート

server certificate verification failed. CAfile: 
/home/gitlab-runner/builds/QopMjzNB/0/root/project1.tmp/CI_SERVER_TLS_CA_FILE CRLfile: none

が出る場合は libgnutls30 がちゃんとインストールされているか確認しましょう
エラー文でググると証明書を自分で作成したりする記事が出てきますがそれだとダメなので気をつけましょう

Gitlab と通信できるようにファイアウォールなどの設定も確認しましょう

最後に

少しハマるポイントがありましたがインストールして動作しました

ds64 モードで紹介しましたが普通に armv7 でも動くかもしれません

参考サイト

2021年11月22日月曜日

波ダッシュと全角チルダの扱いに注意

波ダッシュと全角チルダの扱いに注意

概要

単純に違う文字になるので比較するときに注意しましょう

環境

  • Ruby 3.0.2p107

文字の比較と確認

irb で16進数の文字コードを確認してみます

irb(main):021:0> "〜".bytes.map {|b| b.to_s(16)}
=> ["e3", "80", "9c"]
irb(main):022:0> "~".bytes.map {|b| b.to_s(16)}
=> ["ef", "bd", "9e"]

上が波ダッシュで下が全角チルダです
見た目は一緒ですが Unicode は違うので当然比較すると false になります

irb(main):023:0> "~" == "〜"
=> false

自分が遭遇したケース

特定のサイトから取得した文字は全角チルダだったのですがそれを別のサービスの API を使ってサーバに保存し再度 GET API で取得すると波ダッシュになっていました

おそらく保存しているサーバ側では全角チルダを扱わずにすべて波ダッシュに変換して保存しているせいだと思われます

他の文字でも変換して保存している可能性がありサービス的に保存されたくない文字は変換やエスケープされている可能性があるので取り出すときに注意しましょう

2021年11月19日金曜日

AppScript「Logging output too large. Truncating output.」対策

AppScript「Logging output too large. Truncating output.」対策

概要

console.log だと出力の長さに制限があります
一番てっとり早いのは適当なセルに結果を出力してあげることです

環境

  • macOS 11.6
  • Chrome 91.0.4472.106
  • Google SpreadSheet
  • Apps Script

サンプルスクリプト

一部抜粋ですが console.log の箇所をセルに setValue するように変更するだけです

// console.log("var labels = ['" + labels.reverse().join("','") + "']");
// console.log("var amountData = [" + data.reverse().join(",") + "]");
// console.log("var calData = " + JSON.stringify(calData));
var labelResult = sheet.getRange("G12");
labelResult.setValue("var labels = ['" + labels.reverse().join("','") + "']");
var amountDataResult = sheet.getRange("G13");
amountDataResult.setValue("var amountData = [" + data.reverse().join(",") + "]");
var calDataResult = sheet.getRange("G14");
calDataResult.setValue("var calData = " + JSON.stringify(calData));

参考サイト

2021年11月18日木曜日

Gitlab の MergeRequest Approval Rule を試す

Gitlab の MergeRequest Approval Rule を試す

概要

Approval ルールはレビューが approval ボタンを押さないとマージボタンが有効にならない機能です
Gitlab のマージリクエストを間違ってマージしないようにするのに役に立ちます

環境

  • Gitlab EE 14.3.3

設定方法

まずは MergeRequest を作成します
そしてレビューの欄に「Approval rules」があるのでクリックします

すると「Add approval rule」というボタンが出てくるのでクリックします

Approval の名前と Approval の必要数そして Approval するレビュアーを選択します
ここで選択した人が approve しない限り MergeRequest をマージすることはできません

Approval Rule が作成されると以下のように Merge ボタンが disable になりマージできません
Draft がない状態でもマージボタンが押せないことが確認できると思います

最後に

approval 自体はフリープランでも使えますが approval settings と approval rule はプレミアプランしか使えないので注意しましょう

今回は MergeRequest ごとに作成する方法を紹介しましたがプロジェクトごとにルールの雛形を作成したりすることもできます
詳しくは参考サイトにある URL から確認してください

参考サイト

2021年11月17日水曜日

RaspberryPi4 (8GB RAM) で一ヶ月間 Monero をマイニングした結果

RaspberryPi4 (8GB RAM) で一ヶ月間 Monero をマイニングした結果

概要

タイトルの通りです
参考データとして紹介します

環境

  • RaspberryPi4 ModelB 8GB
  • RaspberryPiOS 5.10.17 armv7l
  • xmrig 6.15.2

結果

0.00049521 XMR

一日平均

0.00001597 XMR

稼働時間

ほぼ24時間
金曜日の一部 (約 7 時間ほど) だけ停止

稼働オプション

donate-level は 1 です
xmrig は直接 RaspberryPi 上で動作させています (docker 上ではないです)

arm7v アーキテクチャでは xmrig は動作しないので ds64 化して動かしています (参考)

平均ハッシュレート

120 hash/sec

下が 90 で上が 300 くらいブレがありそれを平均すると 100 - 130 ほどで推移していることになりました

交換可能になるまで

交換可能 XMR は執筆時点で 0.01 XMR です
これになるには一ヶ月 0.0005 XMR だとすると

  • 0.01 / 0.0005 = 20 ヶ月

になります
約 2 年ほどフル稼働させればようやく交換可能な値になります

最後に

電気代は計算していませんが1ヶ月100円ほどだとすると 20 ヶ月する稼働でも 2,000円ほどなので 0.01 XMR = 300円で余裕で赤字という結果になりました

将来的に Monero が跳ねれば話は別ですが、、

2021年11月16日火曜日

Windows10 で caps を ctrl に変更する方法 (ctrl2cap)

Windows10 で caps を ctrl に変更する方法 (ctrl2cap)

概要

ctrl2cap を使います

環境

  • Windows10

インストール方法

ここから zip ファイルをダウンロードし解凍します

コマンドプロンプトを管理者権限で開いて解凍したディレクトリに移動します

あとは以下のコマンドでインストールできます

  • ctrl2cap /install

アンインストール方法

  • ctrl2cap /uninstall

最後に

他のキーバインドも変えたい場合は別のアプリをインストールするのをオススメします

とりあえず caps だけ ctrl にしたい場合は簡単なのでオススメです

参考サイト

2021年11月15日月曜日

Alertmanager のサイレンス API を curl でコールするサンプル

Alertmanager のサイレンス API を curl でコールするサンプル

概要

過去に少し紹介しました
今回は一通りコールしてみたのでサンプルリクエストを紹介します

なお今回使用する API のバージョンは v2 になります

環境

  • Alertmanager 0.23.0

サイレンスとの登録

サンプルリクエスト

curl http://localhost:9093/api/v2/silences \
-H "content-type: application/json" \
-d @- << EOF
{
  "matchers": [
    {
      "name": "severity",
      "value": "critical",
      "isRegex": false
    }
  ],
  "startsAt": "`date -u +%Y-%m-%dT%H:%M:%S`",
  "endsAt": "`date -u -d '2 hours' +%Y-%m-%dT%H:%M:%S`",
  "createdBy": "api",
  "comment": "test silence"
}
EOF

サンプルレスポンス

{"silenceID":"274f9549-967a-4df6-8342-e82d57513237"}

date コマンドを使うことで実行した時間から 2 時間分のサイレンスを登録しています

2hours を 2days などにするとサイレンスの時間を延長することができます

サイレンス情報の取得

サンプルリクエスト

curl http://localhost:9093/api/v2/silence/274f9549-967a-4df6-8342-e82d57513237

サンプルレスポンス

{
  "id": "274f9549-967a-4df6-8342-e82d57513237",
  "status": {
    "state": "active"
  },
  "updatedAt": "2021-11-12T01:16:43.965Z",
  "comment": "test silence",
  "createdBy": "api",
  "endsAt": "2021-11-12T03:16:43.000Z",
  "matchers": [
    {
      "isEqual": true,
      "isRegex": false,
      "name": "severity",
      "value": "critical"
    }
  ],
  "startsAt": "2021-11-12T01:16:43.965Z"
}

単独のサイレンスを取得する場合は /silence/id を使います
すべてのサイレンス情報を取得したい場合は /silences を使います

curl http://localhost:9093/api/v2/silences

expire にする

サンプルリクエスト

curl -XDELETE http://localhost:9093/api/v2/silence/274f9549-967a-4df6-8342-e82d57513237

レスポンスボディはありません

最後に

ドキュメントが少ないので Github にある openapi のリファレンスを見るしかなさそうです

参考サイト

2021年11月12日金曜日

celery の s() と si() の使い分け

celery の s() と si() の使い分け

概要

s() は前のタスクの結果を受け取ります
si() は前のタスクの結果を受け取りません

環境

  • macOS 11.6.1
  • Python 3.8.12
    • celery 5.1.2

タスクの定義

  • vim sub_tasks.py
from celery import Celery

app = Celery('sub_tasks', backend='redis://localhost', broker='redis://localhost')

@app.task
def add(x, y):
    return x + y

@app.task
def multi(x, y):
    return x * y

s() を使う場合

まずは s() を使います
前のタスクの結果は次のタスクの第一引数に渡されます

from celery import chain
from sub_tasks import add, multi

tasks = chain(
    add.s(1, 2),
    multi.s(10)).apply_async()

print(tasks.get())

結果は 1+2=3 -> 3 x 10 = 30 になります

以下のような使い方はエラーになります

from celery import chain
from sub_tasks import add, multi

tasks = chain(
    add.s(1, 2),
    multi.s(10, 10)).apply_async()

print(tasks.get())

TypeError: multi() takes 2 positional arguments but 3 were given 前のタスクの結果と合わせて引数が足りないと言われてエラーになります

si() を使う場合

si() を使うことで前のタスクの結果を使わないようにできます

from celery import chain
from sub_tasks import add, multi

tasks = chain(
    add.s(1, 2),
    multi.si(10, 10)).apply_async()

print(tasks.get())

結果は 10 x 10 = 100 になります
1+2=3 の結果は使っていないことがわかります

以下の使い方はエラーになります

from celery import chain
from sub_tasks import add, multi

tasks = chain(
    add.s(1, 2),
    multi.si(10)).apply_async()

print(tasks.get())

TypeError: multi() missing 1 required positional argument: 'y'

前のタスクが None を返す場合は

None でも関係なく s() を使った場合は次のタスクの第一引数に入るので注意しましょう

どちらを使うのがいいのか

個人的には以下のようなルールで使うのがいいと思っています

  • 定義したタスクは必ず単独で使う -> si() を使う
  • 定義したタスクは前の結果を使う可能性がある -> s() を使う

前者の場合タスクを定義する際の引数に前のタスクの結果を受け取るための引数がなくなるので必ず si() を使い続ける必要があります

後者は前のタスクの結果を受け取るための引数がありながらもケースによっては引数を使わないこともできます
ただ使わない引数を定義することになるので少しコードが紛らわしくなる可能性があります

タスクとして柔軟なのは間違いなく後者です
例えば将来的に定義したタスクの前にタスクが来てその結果を使う場合には後者で実装しなければなりません
前にタスクが来てもタスクの結果を使うことがなければ si() でも OK です

最後に

si() = s() + immutable=True なので素直に s() を使うのがいいのかもしれません

タスクを定義する場合も必ず前のタスクを受け取るようにするのがいいのかもしれません

参考サイト

2021年11月11日木曜日

macOS で pdf ファイルを結合する方法

macOS で pdf ファイルを結合する方法

概要

poppler (pdfunite) を使います

環境

  • macOS
  • Ruby 3.0.2p107
    • pdfunite 0.5.0
    • poppler 21.11.0

poppler のインストール

  • brew install poppler

この段階で pdfunite コマンドは使えるようになっています

pdfunite のインストール

  • gem install pdfunite

サンプルコード

require 'pdfunite'

files = 200.times.map { |i| "/path/to/pdf/name_#{i}.pdf" }
pdf_data = Pdfunite.join(files)
File.open('./joined.pdf', 'wb') { |f| f << pdf_data }

注意

xpdf がすでにインストールされている場合はコマンドがコンフリクトし poppler がインストールできないので先に brew unlink xpdf しておきましょう

最後に

今回は Ruby から操作しましたが普通に pdfunite コマンドを使っても OK です

ファイルが多い場合は Ruby 経由のほうが簡単そうです

2021年11月10日水曜日

emacs で実行したコマンドの結果をカレントバッファに表示する方法

emacs で実行したコマンドの結果をカレントバッファに表示する方法

概要

shell-command を使えばミニバッファでコマンドを実行できますが結果もそのままミニバッファに表示されてしまいます

結果はカレントバッファに表示したい場合には別の方法でコマンドを実行します

環境

  • macOS 11.6
  • emacs 27.2

やり方

たとえば date コマンドの結果をカレントバッファに表示したい場合は以下のようにします

  • C-u M-! date RET

最後に

あとは date の部分を ls や pwd など好きなコマンドにすれば OK です

2021年11月9日火曜日

flymake の警告やエラーをバッファに表示する方法

flymake の警告やエラーをバッファに表示する方法

概要

いつも忘れるのでメモ

環境

  • macOS 11.6
  • emacs 27.2

方法

  • M-x flymake-show-diagnostics-buffer

最後に

popup とかと組み合わせるといちいちバッファを開かなくてもいいので便利かも

あとはショートカットキーに登録するもありかも

2021年11月8日月曜日

docker secret を使ってみる

docker secret を使ってみる

概要

docker を使ってパスワードなどの秘匿情報を使う場合に docker secret が使えます

ただ残念なことに Swarm 上でしか使えません

環境

  • Ubuntu18.04
  • docker 20.10.8

シークレットの作成

docker secret create コマンドを Swram のマネージャノードに対して実行します

  • printf "This is a secret" | docker -H swarm01:2376 secret create my_secret_data -
  • docker -H swarm01:2376 secret ls
ID                          NAME                DRIVER              CREATED              UPDATED
j7uusrvn44cczetr9qc3k5so7   my_secret_data                          About a minute ago   About a minute ago

シークレットを使ったサービスの作成

service create 時に --secret オプションを付与します
これもマネージャノードに対して実行します

  • docker -H swarm01:2376 service create --name redis --secret my_secret_data redis:alpine
  • docker -H swarm01:2376 service ps redis
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
hjfhde044own        redis.1             redis:alpine        swarm03      Running             Running 45 seconds ago

動作確認

docker exec を実行するのでコンテナが動作しているノードに直接実行しましょう
secret はファイルとしてマウントされているのでファイルの内容を確認しましょう

  • docker -H swarm03:2376 container exec $(docker -H swarm03:2376 ps --filter name=redis -q) cat /run/secrets/my_secret_data

This is a secret

マウントを解除する

service update で --secret-rm オプションを付与すると次に作成されるコンテナではシークレットをマウントしなくなります

  • docker -H swarm01:2376 service update --secret-rm my_secret_data redis
  • docker -H swarm03:2376 container exec $(docker -H swarm03:2376 ps --filter name=redis -q) cat /run/secrets/my_secret_data
cat: can't open '/run/secrets/my_secret_data': No such file or directory

シークレットを削除する

シークレットを使っているサービスがある場合はシークレットを削除できないので先にサービスを削除しましょう

  • docker -H swarm01:2376 service rm redis
  • docker -H swarm01:2376 secret rm my_secret_data

最後に

テキストファイルとしてマウントされるのでアプリ側でそれを展開する処理などが必要になるのが少し面倒な気はします

コンテナ作成時に環境変数などに展開してあげればアプリ内でも簡単に使えるかなと思います

次回は docker-compose で使う方法を紹介します

参考サイト