2022年5月31日火曜日

シェルの結果をパイプを使ってRubyで受け取る方法

シェルの結果をパイプを使ってRubyで受け取る方法

概要

わざわざ Ruby スクリプトを書かないでも簡単に Ruby を使ってシェルの結果をパースしたりできます

環境

  • macOS 11.6.6
  • Ruby 3.1.1p18

echo を受け取る

とりえあずシェルの echo した文字列を Ruby の puts でそのまま出力する方法です

echo hoge | ruby -ne 'puts $_'

ポイント

  • $_ 最後に読み込んだ行になります
  • -ne はこの順番でなければなりません、n は結果を1行ごとに処理するオプションです、具体的には while gets … end で囲まれた状態で実行されています。e オプションは指定された Ruby スクリプトを実行するオプションです

ループさせる

シェルの結果がスペースで区切られた値を Ruby 側の Enumerator に変換して処理する場合などに使えます

echo hoge fuga | ruby -ne '$_.split(" ").each {|s| puts "Hello #{s}" }'

JSON をパースする

シェルの結果が JSON の場合に Ruby 側で受け取ってハッシュに変換して処理します

echo '{"name":"hawk","age":10}' | ruby -ne 'require "json"; JSON.parse($_).each {|k,v| puts "#{k} => #{v}" }'

もしくは -r オプションを使って require できます

echo '{"name":"hawk","age":10}' | ruby -rjson -ne 'JSON.parse($_).each {|k,v| puts "#{k} => #{v}" }'

最後に

慣れれば結構便利に使えます
そもそも ruby がインストールされていないケースが多いのでそこが何ともですが

2022年5月28日土曜日

macOS で cat や echo をクリップボードにコピーする方法

macOS で cat や echo をクリップボードにコピーする方法

環境

  • macOS 11.6.6

コマンド

基本はパイプで繋げば OK です

  • cat hoge | pbcopy

2022年5月27日金曜日

OpenAPI or Swagger ファイルを分割して管理する方法

OpenAPI or Swagger ファイルを分割して管理する方法

概要

今回は swagger-cli を使った方法を紹介します
どんなツールを使うにしろ最終的には分割した YAML ファイルを結合する処理が必要になります

環境

  • macOS 11.6.6
  • swagger-cli

swagger-cli のインストール

  • npm install -g @apidevtools/swagger-cli

分割前のファイル

共通部分などを各パートごとに分割します
以下は分割前のファイルになります

  • vim openapi.yaml
openapi: 3.0.0
info:
  title: split test
  version: 1.0.0
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of pets
          content:
            application/json:
              schema:
                type: "array"
                items:
                  type: object
                  required:
                    - id
                    - name
                  properties:
                    id:
                      type: integer
                      format: int64
                    name:
                      type: string
                    tag:
                      type: string
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - name
                properties:
                  id:
                    type: integer
                    format: int64
                  name:
                    type: string
                  tag:
                    type: string

schemas/pet.yaml の作成

レスポンスで使用するオブジェクトが共通なので分割します
schemas/pet.yaml として切り出します

  • vim schemas/pet.yaml
type: object
required:
  - id
  - name
properties:
id:
  type: integer
  format: int64
name:
  type: string
tag:
  type: string

あとはこれを ref で参照します

  • vim openapi.yaml
openapi: 3.0.0
info:
  title: split test
  version: 1.0.0
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of pets
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "./schemas/pet.yaml"
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "./schemas/pet.yaml"

parameters の分割

今度は少し応用テクニックを紹介します
parameters の役割で分割して管理しやすくしてみます
まず定義した parameters をすべて読み込むファイルを作成します

  • vim parameters/_index.yaml
petId:
  $ref: './petId.yaml'
limit:
  $ref: './limit.yaml'

パラメータはそれぞれ個別ファイルに定義します

  • vim parameters/petId.yaml
name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
  type: string
  • vim parameters/limit.yaml
name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
  type: integer
  format: int32

あとはそれぞれのファイルをメインのファイルから参照するように変更します

  • vim openapi.yaml
openapi: 3.0.0
info:
  title: split test
  version: 1.0.0
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - $ref: "./parameters/limit.yaml"
      responses:
        '200':
          description: A paged array of pets
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "./schemas/pet.yaml"
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - $ref: "./parameters/petId.yaml"
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "./schemas/pet.yaml"
components:
  parameters:
    $ref: "./parameters/_index.yaml"

ファイルを結合して動作確認

ファイルの結合には swagger-cli を使います

  • swagger-cli bundle openapi.yaml --outfile _build/openapi.yaml --type yaml

これで _build/openapi.yaml が出来上がるので swagger ui などで確認するとちゃんと分割前と同じ情報が確認できると思います

できあたがったファイルを見ると ref 先をファイルに埋め込んでパスで無理やり参照しています

また今回の分割後のファイル構成は以下のようになっています

% tree .                     
.
├── _build
│   └── openapi.yaml
├── openapi.yaml
├── parameters
│   ├── _index.yaml
│   ├── limit.yaml
│   └── petId.yaml
└── schemas
    └── pet.yaml

3 directories, 6 file

最後に

基本は分割して ref で参照して結合するだけです
分割の仕方はいろいろありますが基本的には共通部分や役割ごとに分割すると良いと思います

参考サイトにあるように parameters, responses, schemas で分割してあとは paths ごとにもファイルを作成すると管理しやすそうです

参考サイト

2022年5月20日金曜日

Ubuntu でユーザを追加してノンパス sudo できるようにするまでの流れ

Ubuntu でユーザを追加してノンパス sudo できるようにするまでの流れ

概要

ユーザを追加してノンパス sudo できるようにする一連の流れをメモ
作業は root ユーザで行っています

環境

  • Ubuntu 18.04

ユーザ追加

  • adduser test

sudo 追加

  • gpasswd -a test sudo

sudo ノンパス化

  • visudo
#includedir /etc/sudoers.d
test  ALL=(ALL) NOPASSWD:ALL

おまけ: root グループ追加

  • usermod -aG root test

最後に

あとは各種 git の設定や言語の設定は作成したユーザで個別に行う必要があります

2022年5月18日水曜日

(Python) nifcloud と botocore を共存させる方法

(Python) nifcloud と botocore を共存させる方法

概要

nifcloud が botocore にパッチを当てているため使うたびに reload で切り替える必要がある

環境

  • Python 3.10.2
  • nifcloud 1.0.3
  • botocore 1.21.43

サンプルコード

nifcloud が import されている状態で nifcloud を再度 reload しようとすると無限ループになるので botocore のときに nifcloud に戻すように条件分岐する必要がある

import importlib

import botocore
import nifcloud

# nifcloud モードへ
if botocore.session.Session().user_agent_name != 'nifcloud':
    importlib.reload(nifcloud.session)
    importlib.reload(nifcloud.loaders)
from nifcloud import session

client = session.get_session().create_client(
    "computing",
    region_name="jp-east-1",
    nifcloud_access_key_id="xxx",
    nifcloud_secret_access_key="xxx")
client.describe_instances()

# botocore モードへ
importlib.reload(botocore.session)
importlib.reload(botocore.loaders)
from botocore import session

client = session.get_session().create_client(
    's3',
    aws_access_key_id='xxx',
    aws_secret_access_key='xxx',
)
client.list_buckets()

# 再度 nifcloud モードへ
if botocore.session.Session().user_agent_name != 'nifcloud':
    importlib.reload(nifcloud.session)
    importlib.reload(nifcloud.loaders)
from nifcloud import session

client = session.get_session().create_client(
    "computing",
    region_name="jp-east-1",
    nifcloud_access_key_id="xxx",
    nifcloud_secret_access_key="xxx")
client.describe_instances()

同一プロセスないで両方使う場合は上記のようにしないとダメなようです
面倒な場合は別プロセスにしても OK です

2022年5月17日火曜日

(Python) because these package versions have conflicting dependencies

(Python) because these package versions have conflicting dependencies

概要

pipenv install 時に依存関係を解決できずに発生するエラーです
バージョンを固定している場合に発生するケースが多い印象です

環境

  • macOS 11.6.5
  • Python 3.10.2

エラー概要

ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/user_guide/#fixing-conflicting-dependencies となり pipenv install できない

原因

新規でインストールしようとしているパッケージが依存しているパッケージがすでにインストールされておりすでにインストールされているパッケージのバージョンと新規でインストールしようとしてるパッケージのバージョンに互換がなくエラーになっている

対策

新規でインストールしようとしているパッケージはバージョン指定せずに pipenv 側に一旦まかせる

  • pipenv install xxx

これで自動的にインストール可能なバージョンがインストールされるのでその後 Pipfile を編集してバージョン情報を記載する

xxx = "==1.2.3"

ただこの場合だとすでにインストールされているパッケージのバージョンに依存して新規のパッケージがインストールされるので必ずしも最新場のパッケージがインストールされるとは限りません

もし最新のバージョンをインストールしたい場合は依存しているパッケージのバージョンを最新にしてからインストールする必要があります

2022年5月12日木曜日

Ruby でセマンティクスバージョンニングの比較をする方法

Ruby でセマンティクスバージョンニングの比較をする方法

概要

Ruby でセマンティクスバージョニングを比較する場合は標準で使える Gem::Version クラスを使います

環境

  • macOS 11.6.5
  • Ruby 3.1.1p18

サンプルコード

puts Gem::Version.new('0.3.2') < Gem::Version.new('0.10.1')
puts Gem::Version.new('0.3.2-pre') < Gem::Version.new('0.3.2')
puts Gem::Version.new('14.7.7-ee.0') < Gem::Version.new('14.6.8-ee.0')

新しいバージョンが true になります

2022年5月11日水曜日

Python でセマンティクスバージョンニングの比較をする方法

Python でセマンティクスバージョンニングの比較をする方法

概要

バージョンを比較をコード内で行いたいときに便利なパッケージを紹介します

環境

  • macOS 11.6.5
  • Python 3.10.2
    • packaging 21.3

インストール

  • pipenv install packaging

サンプルコード

  • vim app.py
from packaging import version

print(version.parse("2.3.1") < version.parse("10.1.2"))
print(version.parse("14.6.8-ee.0") < version.parse("14.7.7-ee.0"))
  • pipenv run python app.py

バージョンが新しいほうが True になります

最後に

基本は PEP440 に準拠しています
他にもメジャーバージョンの部分だけ取得したりプレリリースかどうかの判定もできます
詳細は公式のドキュメントを御覧ください

https://packaging.pypa.io/en/latest/version.html

2022年5月10日火曜日

docker-compose で起動した Gitlab で Rails Console を起動する

docker-compose で起動した Gitlab で Rails Console を起動する

概要

タイトルの通りです

環境

  • docker 20.10.4
  • Gitlab-ee 14.7.7

コマンド

  • docker-compose exec gitlab gitlab-rails console

起動までにしばらくかかるので待ちましょう

irb(main):001:0> Gitlab.version_info
=> #<Gitlab::VersionInfo:0x00007fcddd00b3a8 @major=14, @minor=7, @patch=7>
irb(main):002:0> Gitlab.version_info.major
=> 14

-it コマンドは不要です

2022年5月9日月曜日

ElasticSearch8 を docker で起動する

ElasticSearch8 を docker で起動する

概要

いろいろと起動方法が変わっていたので試してみました

環境

  • Ubuntu 18.04
  • docker 20.10.7
  • ElasticSearch 8.1.3
  • Kibana 8.1.3

max_map_count 変更

ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. というエラーが発生して ElasticSearch が起動しないので事前に変更します

  • sudo sysctl -w vm.max_map_count=262144

ElasticSearch 起動

シングルノードで起動します

  • docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --name es docker.elastic.co/elasticsearch/elasticsearch:8.1.3

elastic ユーザのパスワードリセット

ElasticSearch にアクセスする elastic ユーザのパスワードを作成します
ターミナルに表示されたパスワードをメモしておきましょう

  • docker exec -it es /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -a

ここで ElasticSearch にアクセスできるか確認

一旦アクセスできるか確認します
自動で生成されるクライアント証明書は localhost アクセス用のなので注意してください

  • docker cp es:/usr/share/elasticsearch/config/certs/http_ca.crt .
  • curl --cacert http_ca.crt -u elastic https://localhost:9200

Enrollment token の作成

Kibana が ElasticSearch にアクセスするためのトークンを生成します
ターミナルに表示される eyxxx という文字列をコピーしておきます

  • docker exec -it es /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana --url "https://localhost:9200"

Kibana の起動

  • docker run -d -p 5601:5601 --name kibana docker.elastic.co/kibana/kibana:8.1.3

動作確認

アクセスする URL は以下で確認できます

  • docker logs kibana

URL の後ろに code が含まれている URL にアクセスしましょう

http://192.168.100.10:5601/?code=xxxx

事前に取得した Enrollment token を入力します
Kibana -> ElasticSearch のアクセス経路は docker 内のネットワークを使用しているようなので ElasticSearch と Kibana は必ず同じネットワークに所属させるようにしてください (今回は default ネットワークを使っています)

設定が完了してログイン画面が表示されれば OK です

elastic ユーザでログインできることを確認しましょう

最後に

セキュリティ面がだいぶ強化されログインや Kibana からの接続時に証明書や認証が含まれるようになっていました

各種 SDK を使っている場合もいろいろとその辺りの変更が入っているかなと思います

参考サイト

2022年5月6日金曜日

fluent コンテナは root ユーザでは動作しないが FLUENT_UID を使えば fluent ユーザの UID を変更できる

fluent コンテナは root ユーザでは動作しないが FLUENT_UID を使えば fluent ユーザの UID を変更できる

概要

fleunt コンテナでホスト領域をマウントする場合にはマウントする領域の権限に合わせて FLUENT_UID を使って uid を変更する必要があります

環境

  • Ubuntu 18.04
  • docker 20.10.4
  • fluent 1.3.2

動作確認

# docker run --rm -e FLUENT_UID=998 fluent/fluentd id fluent
uid=998(fluent) gid=998(fluent) groups=998(fluent)

# docker run --rm fluent/fluentd id fluent
uid=1000(fluent) gid=1000(fluent) groups=1000(fluent)

2022年5月2日月曜日

Gitlab で 2FA を有効にする方法

Gitlab で 2FA を有効にする方法

概要

root ユーザでログインして GUI からできますが今回はコマンドで有効/無効を切り替える方法を紹介します

環境

  • Ubuntu 18.04
  • docker 20.10.7
  • Gitlab-ee 14.7.7

GUI の場合

Admin area -> Settings -> General -> Sign-in restrictions -> Two-factor authentication

のチェックをオンにします

Rails Console を使う

有効にする場合は require_two_factor_authentication を true にします
無効にしたい場合は false にします

# docker-compose exec gitlab gitlab-rails console
--------------------------------------------------------------------------------
 Ruby:         ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-linux]
 GitLab:       14.7.7-ee (6d5453caf44) EE
 GitLab Shell: 13.22.2
 PostgreSQL:   12.7
--------------------------------------------------------------------------------
Loading production environment (Rails 6.1.4.4)
irb(main):001:0> Gitlab::CurrentSettings.update!('require_two_factor_authentication': true)
=> true

注意点

一度 2FA を有効にしすでに設定しているユーザは上記のコマンドで無効にしても 2FA が続いています
これも無効にしたい場合は対象のユーザでログインしてから 2FA を無効にする必要があります

参考サイト