Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

MySQLのインストール

ついこないだ、PostgreSQLをインストールしたところなんだけども。ごにょごにょ。

> brew install mysql
==> Downloading https://ghcr.io/v2/homebrew/core/openssl/1.1/manifests/1.1.1k
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/openssl/1.1/blobs/sha256:17d94c51ddfa8364baed5f3a754063e1ca75f807194f68
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:17d94c51ddfa8364baed5f3a754063e1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/protobuf/manifests/3.15.8
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/protobuf/blobs/sha256:48434534a8272ad371be138166687d9a1f1492c508c302ba8
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:48434534a8272ad371be138166687d9a
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/mysql/manifests/8.0.23_1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/mysql/blobs/sha256:9e9e4b5bfcad47adfbf7f2af7ebf2c2cc7411d2fb88a4a5155ea
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:9e9e4b5bfcad47adfbf7f2af7ebf2c2c
######################################################################## 100.0%
==> Installing dependencies for mysql: openssl@1.1 and protobuf
==> Installing mysql dependency: openssl@1.1
==> Pouring openssl@1.1--1.1.1k.big_sur.bottle.tar.gz
==> Regenerating CA certificate bundle from keychain, this may take a while...
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /usr/local/etc/openssl@1.1/certs

and run
  /usr/local/opt/openssl@1.1/bin/c_rehash

openssl@1.1 is keg-only, which means it was not symlinked into /usr/local,
because macOS provides LibreSSL.

If you need to have openssl@1.1 first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/openssl@1.1/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find openssl@1.1 you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/openssl@1.1/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/openssl@1.1/include"

For pkg-config to find openssl@1.1 you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/openssl@1.1/lib/pkgconfig"

==> Summary
🍺  /usr/local/Cellar/openssl@1.1/1.1.1k: 8,071 files, 18.5MB
==> Installing mysql dependency: protobuf
==> Pouring protobuf--3.15.8.big_sur.bottle.tar.gz
==> Caveats
Emacs Lisp files have been installed to:
  /usr/local/share/emacs/site-lisp/protobuf
==> Summary
🍺  /usr/local/Cellar/protobuf/3.15.8: 211 files, 17.7MB
==> Installing mysql
==> Pouring mysql--8.0.23_1.big_sur.bottle.tar.gz
==> /usr/local/Cellar/mysql/8.0.23_1/bin/mysqld --initialize-insecure --user=tambara --basedir=/usr/local/Cellar/mysql/8
==> Caveats
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -uroot

To have launchd start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  mysql.server start
==> Summary
🍺  /usr/local/Cellar/mysql/8.0.23_1: 298 files, 297.7MB
==> `brew cleanup` has not been run in 30 days, running now...
Removing: /Users/tambara/Library/Caches/Homebrew/ansible--3.0.0.big_sur.bottle.tar.gz... (63.3MB)
Removing: /usr/local/Cellar/apr/1.7.0... (59 files, 1.4MB)
Removing: /Users/tambara/Library/Caches/Homebrew/elixir--1.11.3.big_sur.bottle.tar.gz... (4.4MB)
Removing: /Users/tambara/Library/Caches/Homebrew/erlang--23.2.6.big_sur.bottle.tar.gz... (104.4MB)
Removing: /Users/tambara/Library/Caches/Homebrew/git--2.30.1.big_sur.bottle.tar.gz... (14.8MB)
Removing: /Users/tambara/Library/Caches/Homebrew/gradle--6.8.3.zip... (143.7MB)
Removing: /Users/tambara/Library/Caches/Homebrew/heroku--7.49.1.tar.xz... (7.3MB)
Removing: /Users/tambara/Library/Caches/Homebrew/lua--5.4.2.catalina.bottle.tar.gz... (130.8KB)
Removing: /usr/local/Cellar/openjdk/15.0.1... (614 files, 324.9MB)
Removing: /Users/tambara/Library/Caches/Homebrew/openjdk--15.0.1.big_sur.bottle.1.tar.gz... (190.9MB)
Removing: /usr/local/Cellar/openssl@1.1/1.1.1i... (8,067 files, 18.5MB)
Removing: /usr/local/Cellar/openssl@1.1/1.1.1j... (8,071 files, 18.5MB)
Removing: /Users/tambara/Library/Caches/Homebrew/openssl@1.1--1.1.1j.big_sur.bottle.tar.gz... (5.4MB)
Removing: /Users/tambara/Library/Caches/Homebrew/pandoc--2.11.4.big_sur.bottle.tar.gz... (27.7MB)
Removing: /usr/local/Cellar/perl/5.32.0... (2,458 files, 63.5MB)
Removing: /Users/tambara/Library/Caches/Homebrew/pyenv--1.2.23.big_sur.bottle.tar.gz... (650.8KB)
Removing: /Users/tambara/Library/Caches/Homebrew/python@3.8--3.8.8_1.big_sur.bottle.tar.gz... (17.0MB)
Removing: /Users/tambara/Library/Caches/Homebrew/python@3.9--setuptools--53.0.0.tar.gz... (2.0MB)
Removing: /Users/tambara/Library/Caches/Homebrew/python@3.9--3.9.2_1.big_sur.bottle.tar.gz... (17MB)
Removing: /Users/tambara/Library/Caches/Homebrew/python@3.9--3.9.2.tar.xz... (18MB)
Removing: /Users/tambara/Library/Caches/Homebrew/ruby--3.0.0_1.catalina.bottle.tar.gz... (10.8MB)
Removing: /Users/tambara/Library/Caches/Homebrew/ruby-build--20210119.tar.gz... (68.5KB)
Removing: /Users/tambara/Library/Caches/Homebrew/spring-boot--2.4.3.tar.gz... (11.2MB)
Removing: /Users/tambara/Library/Caches/Homebrew/sqlite--3.34.0.catalina.bottle.tar.gz... (2.0MB)
Removing: /Users/tambara/Library/Caches/Homebrew/tmux--3.1c_1.big_sur.bottle.tar.gz... (353.6KB)
Removing: /Users/tambara/Library/Caches/Homebrew/vim--8.2.2550.big_sur.bottle.tar.gz... (11.6MB)
Removing: /Users/tambara/Library/Logs/Homebrew/pyenv... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/vim... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/postgresql... (1.3KB)
Removing: /Users/tambara/Library/Logs/Homebrew/w3m... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/pandoc... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/ncurses... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/heroku... (114B)
Removing: /Users/tambara/Library/Logs/Homebrew/mpdecimal... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/elixir... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/bdw-gc... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/icu4c... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/perl... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/erlang... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/ruby-build... (2 files, 179B)
Removing: /Users/tambara/Library/Logs/Homebrew/gradle... (102B)
Removing: /Users/tambara/Library/Logs/Homebrew/ansible... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/openjdk... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/displayplacer... (2 files, 235B)
Removing: /Users/tambara/Library/Logs/Homebrew/krb5... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/tcl-tk... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/apr... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/tmux... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/pcre2... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/libevent... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/openssl@1.1... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/groovy... (102B)
Removing: /Users/tambara/Library/Logs/Homebrew/python@3.8... (3 files, 178.3KB)
Removing: /Users/tambara/Library/Logs/Homebrew/subversion... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/git... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/python@3.9... (3 files, 719.5KB)
Removing: /Users/tambara/Library/Logs/Homebrew/berkeley-db... (64B)
Removing: /Users/tambara/Library/Logs/Homebrew/spring-boot... (121B)
Pruned 0 symbolic links and 6 directories from /usr/local
==> Upgrading 9 dependents:
ansible 3.0.0 -> 3.2.0, erlang 23.2.6 -> 23.3.1, elixir 1.11.3 -> 1.11.4, pyenv 1.2.23 -> 1.2.26, python@3.8 3.8.8_1 -> 3.8.9, python@3.9 3.9.2_1 -> 3.9.4, ruby 3.0.0_1 -> 3.0.1, tmux 3.1c_1 -> 3.2, vim 8.2.2550 -> 8.2.2775
==> Upgrading python@3.8 3.8.8_1 -> 3.8.9 
==> Downloading https://ghcr.io/v2/homebrew/core/gdbm/manifests/1.19
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/gdbm/blobs/sha256:3581501b051db1c0d1acccc710fe04453b61777e4d67110485cec
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:3581501b051db1c0d1acccc710fe0445
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/sqlite/manifests/3.35.4
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/sqlite/blobs/sha256:861dc044ea531c39a2105010107feb95cf10977c3da94a4c4fc
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:861dc044ea531c39a2105010107feb95
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.8/manifests/3.8.9
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.8/blobs/sha256:6111e285226a59c3c3b0f684de2a810deb1b5b5b68e81fd
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:6111e285226a59c3c3b0f684de2a810d
######################################################################## 100.0%
==> Installing dependencies for python@3.8: gdbm and sqlite
==> Installing python@3.8 dependency: gdbm
==> Pouring gdbm--1.19.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/gdbm/1.19: 24 files, 791.3KB
==> Installing python@3.8 dependency: sqlite
==> Pouring sqlite--3.35.4.big_sur.bottle.tar.gz
==> Caveats
sqlite is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have sqlite first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/sqlite/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find sqlite you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/sqlite/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/sqlite/include"

For pkg-config to find sqlite you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/sqlite/lib/pkgconfig"

==> Summary
🍺  /usr/local/Cellar/sqlite/3.35.4: 11 files, 4.2MB
==> Installing python@3.8
==> Pouring python@3.8--3.8.9.big_sur.bottle.tar.gz
==> /usr/local/Cellar/python@3.8/3.8.9/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts
==> /usr/local/Cellar/python@3.8/3.8.9/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts
==> /usr/local/Cellar/python@3.8/3.8.9/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts
==> Caveats
Python has been installed as
  /usr/local/opt/python@3.8/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
  /usr/local/opt/python@3.8/libexec/bin

You can install Python packages with
  /usr/local/opt/python@3.8/bin/pip3 install <package>
They will install into the site-package directory
  /usr/local/lib/python3.8/site-packages

See: https://docs.brew.sh/Homebrew-and-Python

python@3.8 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have python@3.8 first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/python@3.8/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find python@3.8 you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/python@3.8/lib"

For pkg-config to find python@3.8 you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/python@3.8/lib/pkgconfig"

==> Summary
🍺  /usr/local/Cellar/python@3.8/3.8.9: 4,376 files, 71.4MB
Removing: /usr/local/Cellar/python@3.8/3.8.8_1... (4,375 files, 71.3MB)
==> Upgrading ruby 3.0.0_1 -> 3.0.1 
==> Downloading https://ghcr.io/v2/homebrew/core/ruby/manifests/3.0.1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/ruby/blobs/sha256:00daa93e4b30d3bbeac5089c1c34355315774e0d9fd1d9588402b
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:00daa93e4b30d3bbeac5089c1c343553
######################################################################## 100.0%
==> Pouring ruby--3.0.1.big_sur.bottle.tar.gz
==> Caveats
By default, binaries installed by gem will be placed into:
  /usr/local/lib/ruby/gems/3.0.0/bin

You may want to add this to your PATH.

ruby is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have ruby first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/ruby/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find ruby you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/ruby/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/ruby/include"

For pkg-config to find ruby you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/ruby/lib/pkgconfig"

==> Summary
🍺  /usr/local/Cellar/ruby/3.0.1: 16,358 files, 38.4MB
Removing: /usr/local/Cellar/ruby/3.0.0_1... (16,314 files, 37.6MB)
==> Upgrading elixir 1.11.3 -> 1.11.4 
==> Downloading https://ghcr.io/v2/homebrew/core/erlang/manifests/23.3.1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/erlang/blobs/sha256:4d17d85cc255934a3cc8786b6d1b0a1b4fed5b52ab2702d3092
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:4d17d85cc255934a3cc8786b6d1b0a1b
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/elixir/manifests/1.11.4
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/elixir/blobs/sha256:74bfd7543233a3ea0b1524fa1423410f33bac4e8ee7252508f1
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:74bfd7543233a3ea0b1524fa1423410f
######################################################################## 100.0%
==> Installing dependencies for elixir: erlang
==> Installing elixir dependency: erlang
==> Pouring erlang--23.3.1.big_sur.bottle.tar.gz
==> Caveats
Man pages can be found in:
  /usr/local/opt/erlang/lib/erlang/man

Access them with `erl -man`, or add this directory to MANPATH.
==> Summary
🍺  /usr/local/Cellar/erlang/23.3.1: 8,018 files, 461.5MB
==> Installing elixir
==> Pouring elixir--1.11.4.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/elixir/1.11.4: 433 files, 6.1MB
Removing: /usr/local/Cellar/elixir/1.11.3... (433 files, 6.1MB)
==> Upgrading pyenv 1.2.23 -> 1.2.26 
==> Downloading https://ghcr.io/v2/homebrew/core/m4/manifests/1.4.18-1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/m4/blobs/sha256:0df9083b268f76a3cda0c9f0d2ce84b51d21a8618d578740646fb61
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:0df9083b268f76a3cda0c9f0d2ce84b5
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/autoconf/manifests/2.71
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/autoconf/blobs/sha256:0aa64f171bac19ce6ac0c0ca697f30658db78cf175550dfde
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:0aa64f171bac19ce6ac0c0ca697f3065
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/pyenv/manifests/1.2.26
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:5c2c4b253c069c7461f9f657fdf8a526a6aedac5fed2263c65bb
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:5c2c4b253c069c7461f9f657fdf8a526
######################################################################## 100.0%
==> Installing dependencies for pyenv: m4 and autoconf
==> Installing pyenv dependency: m4
==> Pouring m4--1.4.18.big_sur.bottle.1.tar.gz
==> Caveats
m4 is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have m4 first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/m4/bin" $fish_user_paths' >> ~/.config/fish/config.fish

==> Summary
🍺  /usr/local/Cellar/m4/1.4.18: 13 files, 672.3KB
==> Installing pyenv dependency: autoconf
==> Pouring autoconf--2.71.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/autoconf/2.71: 71 files, 3.2MB
==> Installing pyenv
==> Pouring pyenv--1.2.26.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/pyenv/1.2.26: 747 files, 2.6MB
Removing: /usr/local/Cellar/pyenv/1.2.23... (738 files, 2.6MB)
==> Upgrading python@3.9 3.9.2_1 -> 3.9.4 
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.9/manifests/3.9.4
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.9/blobs/sha256:77ba90d10acfc70e57781aae7b8f48799bc4d521422c74f
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:77ba90d10acfc70e57781aae7b8f4879
######################################################################## 100.0%
==> Pouring python@3.9--3.9.4.big_sur.bottle.tar.gz
==> /usr/local/Cellar/python@3.9/3.9.4/bin/python3 -m ensurepip
==> /usr/local/Cellar/python@3.9/3.9.4/bin/python3 -m pip install -v --no-deps --no-index --upgrade --isolated --target=
==> Caveats
Python has been installed as
  /usr/local/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
  /usr/local/opt/python@3.9/libexec/bin

You can install Python packages with
  pip3 install <package>
They will install into the site-package directory
  /usr/local/lib/python3.9/site-packages

tkinter is no longer included with this formula, but it is available separately:
  brew install python-tk@3.9

See: https://docs.brew.sh/Homebrew-and-Python
==> Summary
🍺  /usr/local/Cellar/python@3.9/3.9.4: 3,047 files, 54.2MB
Removing: /usr/local/Cellar/python@3.9/3.9.2_1... (3,964 files, 66.2MB)
==> Upgrading tmux 3.1c_1 -> 3.2 
==> Downloading https://ghcr.io/v2/homebrew/core/tmux/manifests/3.2
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/tmux/blobs/sha256:f71d53c8050adaa30a80686879474421b8353c4edc9f0544823b8
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:f71d53c8050adaa30a80686879474421
######################################################################## 100.0%
==> Pouring tmux--3.2.big_sur.bottle.tar.gz
==> Caveats
Example configuration has been installed to:
  /usr/local/opt/tmux/share/tmux
==> Summary
🍺  /usr/local/Cellar/tmux/3.2: 9 files, 1MB
Removing: /usr/local/Cellar/tmux/3.1c_1... (9 files, 867.0KB)
==> Upgrading ansible 3.0.0 -> 3.2.0 
==> Downloading https://ghcr.io/v2/homebrew/core/ansible/manifests/3.2.0
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/ansible/blobs/sha256:822cc4694e6e5bc9856d5bdcfd58ce7714c7793c99938e897c
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:822cc4694e6e5bc9856d5bdcfd58ce77
######################################################################## 100.0%
==> Pouring ansible--3.2.0.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/ansible/3.2.0: 38,732 files, 345.4MB
Removing: /usr/local/Cellar/ansible/3.0.0... (39,808 files, 371.9MB)
==> Upgrading vim 8.2.2550 -> 8.2.2775 
==> Downloading https://ghcr.io/v2/homebrew/core/lua/manifests/5.4.3-1
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/lua/blobs/sha256:e59dc980047218242a11cd735216b5ec881c45c60f50fffd5edd68
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:e59dc980047218242a11cd735216b5ec
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/vim/manifests/8.2.2775
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/vim/blobs/sha256:2d48b73b8157241aef912e1fdc7e587837b60e4898f69d597b1f41
==> Downloading from https://pkg-containers-az.githubusercontent.com/ghcr1/blobs/sha256:2d48b73b8157241aef912e1fdc7e5878
######################################################################## 100.0%
==> Installing dependencies for vim: lua
==> Installing vim dependency: lua
==> Pouring lua--5.4.3.big_sur.bottle.1.tar.gz
==> Caveats
You may also want luarocks:
  brew install luarocks
==> Summary
🍺  /usr/local/Cellar/lua/5.4.3: 29 files, 743.6KB
==> Installing vim
==> Pouring vim--8.2.2775.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/vim/8.2.2775: 1,988 files, 33.8MB
Removing: /usr/local/Cellar/vim/8.2.2550... (1,970 files, 33.7MB)
==> Upgrading erlang 23.3.1 -> 23.3.1 
Removing: /usr/local/Cellar/erlang/23.2.6... (7,984 files, 460.8MB)
==> Checking for dependents of upgraded formulae...
==> No broken dependents found!
==> Caveats
==> openssl@1.1
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /usr/local/etc/openssl@1.1/certs

and run
  /usr/local/opt/openssl@1.1/bin/c_rehash

openssl@1.1 is keg-only, which means it was not symlinked into /usr/local,
because macOS provides LibreSSL.

If you need to have openssl@1.1 first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/openssl@1.1/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find openssl@1.1 you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/openssl@1.1/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/openssl@1.1/include"

For pkg-config to find openssl@1.1 you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/openssl@1.1/lib/pkgconfig"

==> protobuf
Emacs Lisp files have been installed to:
  /usr/local/share/emacs/site-lisp/protobuf
==> mysql
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -uroot

To have launchd start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  mysql.server start
==> sqlite
sqlite is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have sqlite first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/sqlite/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find sqlite you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/sqlite/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/sqlite/include"

For pkg-config to find sqlite you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/sqlite/lib/pkgconfig"

==> python@3.8
Python has been installed as
  /usr/local/opt/python@3.8/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
  /usr/local/opt/python@3.8/libexec/bin

You can install Python packages with
  /usr/local/opt/python@3.8/bin/pip3 install <package>
They will install into the site-package directory
  /usr/local/lib/python3.8/site-packages

See: https://docs.brew.sh/Homebrew-and-Python

python@3.8 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have python@3.8 first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/python@3.8/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find python@3.8 you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/python@3.8/lib"

For pkg-config to find python@3.8 you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/python@3.8/lib/pkgconfig"

==> ruby
By default, binaries installed by gem will be placed into:
  /usr/local/lib/ruby/gems/3.0.0/bin

You may want to add this to your PATH.

ruby is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have ruby first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/ruby/bin" $fish_user_paths' >> ~/.config/fish/config.fish

For compilers to find ruby you may need to set:
  set -gx LDFLAGS "-L/usr/local/opt/ruby/lib"
  set -gx CPPFLAGS "-I/usr/local/opt/ruby/include"

For pkg-config to find ruby you may need to set:
  set -gx PKG_CONFIG_PATH "/usr/local/opt/ruby/lib/pkgconfig"

==> erlang
Man pages can be found in:
  /usr/local/opt/erlang/lib/erlang/man

Access them with `erl -man`, or add this directory to MANPATH.
==> m4
m4 is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have m4 first in your PATH, run:
  echo 'set -g fish_user_paths "/usr/local/opt/m4/bin" $fish_user_paths' >> ~/.config/fish/config.fish

==> python@3.9
Python has been installed as
  /usr/local/bin/python3

Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
  /usr/local/opt/python@3.9/libexec/bin

You can install Python packages with
  pip3 install <package>
They will install into the site-package directory
  /usr/local/lib/python3.9/site-packages

tkinter is no longer included with this formula, but it is available separately:
  brew install python-tk@3.9

See: https://docs.brew.sh/Homebrew-and-Python
==> tmux
Example configuration has been installed to:
  /usr/local/opt/tmux/share/tmux
==> lua
You may also want luarocks:
  brew install luarocks

なんかいろいろとアップデートされた。opensslの影響?

起動してみる。

> mysql.server start
Starting MySQL
.. SUCCESS! 

うごいたっぽい?

> mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.23 Homebrew

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

繋がったのかしら。

Ansibleで遊んでみる(5) 〜 INJECT_FACTS_AS_VARS とはなんなのか

3回目でやった例を、もう一度見てみたい。

Unix OSでユーザーのグループを作る。以下の様なタスクを作ると、hogeグループをID=7777で作ることが出来る。

tasks:
  - name: Make groups
    group:
      name: hoge
      gid: 7777

複数のユーザーを作りたかったら、こう書けと入門書には書いてある。

vars:
- usergroups:
  - name: hoge
    gid: 7777
  - name: fuga
    gid: 8888

tasks:
  - name: Make groups
    group:
      name: "{{ item.name }}"
      gid: "{{ item.gid }}"
    loop: "{{ usergroups }}"

しかし、これはどう見ても冗長だ。

vars:
- usergroups:
  - name: hoge
    gid: 7777
  - name: fuga
    gid: 8888
tasks:
  - name: Make groups
    group: "{{ item }}"
    loop: "{{ usergroups }}"

これで良くないか?

というわけで試してみる。

TASK [usergroup : Make groups] *************************************************
[WARNING]: Using a variable for a task's 'args' is unsafe in some situations
(see
https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#argsplat-
unsafe)
changed: [inst] => (item={'name': 'hoge', 'gid': 7777})
changed: [inst] => (item={'name': 'fuga', 'gid': 8888})

ちゃんと動作するが、怒られる。「安全じゃ無い」らしい。「argsを使ったら、危ないよ」としてるのは、つまり、

group: dict_value

group:
  args: dict_value

と扱われるということらしい。

詳しくはこちら・・・と書いているので、そのFAQを見てみよう。

docs.ansible.com

ただし、 usermod_args に渡されるパラメーターや値が、 ウイルスなどに感染したターゲットマシンの host facts に含まれる悪意のある値で上書きされる可能性があるため、 このようなタスクの構築にはリスクがあります。

AnsibleのFactはあんまりよく理解できていない概念の1つなんだけども、つまり、操作対象システムの情報、例えばOSが何かとかバージョンが何かといういうものを変数と同じように参照できる仕組みのことだ。そして、それはまさに変数(Var)と同じスコープの中で同じように扱われる。

しかし、Ansibleというプログラムのことを考えたら、Factはシステムの外部から与えられたものなので信用できない情報が含まれることがある。例えば、Rubyにはtaintという仕組みが(あるが、有効に使うのが難しいので風前の灯火で)ある。コマンドライン引数などの文字列オブジェクトなどに汚染されてますよマークが付いて、そのマークが付いたオブジェクトで一部の動作が禁止されるというような仕組みだ。Ansibleはパラメータとして与えられた情報を元にroot権限でコマンドが実行されるような仕組みなので、コマンドの引数が汚染された情報でうっかり書き換えられると大変にマズい。それはなんとなく理解できる。

しかし、そもそも自分で定義したVarがFactで塗り替えられるかも知れないというのは、何かが間違っている。そもそも、AnsibleのVarは定義できる場所が多すぎてスコープがよくわからないんだけども。というわけで、Factは別の名前空間に押し込められることになった。Ansible 2.5でのこと。しかしながら、まだ移行期間なのでFactがVarを塗り替える状況は変わらない。現状は、INJECT_FACTS_AS_VARSをFalseに設定する(例えばANSIBLE_INJECT_FACT_VARSという環境変数をFalseに設定する)と将来的に予告されているとおりにVarの名前空間にFactは入ってこない動作になり、この警告の表示も消える。

しかし、タスクへのパラメータをdictを渡そうとすると、Factで上書きされる可能性が生じるのはなぜなのかは、やっぱりよくわからない。

Ansibleで遊んでみる(4)

できる限りやるべきではないと釘を刺されているけども、独自のモジュールを開発したいことはある。

Moleculeによるロール単位の開発をしている場合、そのロールで自分で実装したモジュールが欲しい場合どうすればいいのか実験する。

ロール直下にlibraryというディレクトリを作ると、そこにあるファイルをモジュールだと判断してくれるらしい。試してみよう。

Moleculeでロールを作成する。

> mol init role mymdl
INFO     Initializing new role mymdl...
No config file found; using defaults
- Role mymdl was created successfully
INFO     Initialized role in /Users/tambara/study/ansible_study/roles/mymdl successfully.

libraryディレクトリを作り、以下の様なPythonスクリプトを置く。

library/mymdl.py

#!/usr/bin/env python

from ansible.module_utils.basic import AnsibleModule

def run_module():
    module_args = dict(
        name=dict(type='str', required=True),
        new=dict(type='bool', required=False, default=False)
    )

    result = dict(
        changed=False,
        original_message='',
        message=''
    )

    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    if module.check_mode:
        module.exit_json(**result)

    result['original_message'] = module.params['name']
    result['message'] = 'goodbye'

    if module.params['new']:
        result['changed'] = True
    
    if module.params['name'] == 'fail me':
        module.fail_json(msg='You requested this to fail', **result)
    
    module.exit_json(**result)

def main():
    run_module()

if __name__ == '__main__':
    main()

AnsibleModule.check_modeはDRY RUNさせるとtrueになるもの。

これを

---
- name: test my module
  mymdl:
    name: hello
    new: true
  register: hoge
  ignore_errors: true
- name: debug
  debug:
    msg: "{{ hoge }}"

のように定義して実行してみる。

> mol converge
(略)

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include mymdl] ***********************************************************

TASK [mymdl : test my module] **************************************************
changed: [inst]

TASK [mymdl : debug] ***********************************************************
ok: [inst] => {
    "msg": {
        "changed": true,
        "failed": false,
        "message": "goodbye",
        "original_message": "hello"
    }
}

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ちゃんと動いている。

さて、このモジュールのテストをどうするか。

テストはlibraryの下に以下の様に置く

  • library/
    • mymdl.py
    • tests/
      • __init__.py
      • test_mymdl.py

この構成で、libraryディレクトリでpytestを実行すれば良い。

test_mymdl.pyでmymdlをimportするには

import mymdl

で、OK。ただし、__init__.pyがないとエラーになる。理由はよくわからない。

Ansibleで遊んでみる(3)

前回作ったロールはロール名に"-"が入っていて、これはどうも良くないらしいので名前を直した。

さて、前回はテスト用のタスクだったけど、今度はホントにgroupを作ってみよう。

実際にテストとして走らせるplaybookは、molecule/default/converge.ymlとなる。

---
- name: Converge
  hosts: all
  tasks:
    - name: "Include usergroup"
      include_role:
        name: "usergroup"
        vars_from: "test"

ここでテスト用の変数ファイルを読み込む様に指定する。

テスト用変数ファイル(vars/test.yml)はこんな感じ。

---
usergroups:
  - { name: "hoge", gid: 7777 }
  - { name: "fuga", gid: 8888 }

タスクを書いてみる。tasks/main.ymlはこんな感じ。

---
- name: Make groups
  group:
    name: "{{ item.name }}"
    gid: "{{ item.gid }}"
  loop: "{{ usergroups }}"

実行してみる。

> molecule converge
INFO     default scenario test matrix: dependency, create, prepare, converge
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > create
INFO     Sanity checks: 'docker'

PLAY [Create] ******************************************************************

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item={'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False', 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item', 'i': 0, 'ansible_index_var': 'i'})

TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:8)

TASK [Create docker network(s)] ************************************************

TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '506425403898.18190', 'results_file': '/Users/tambara/.ansible_async/506425403898.18190', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

INFO     Running default > prepare
WARNING  Skipping, prepare playbook not configured.
INFO     Running default > converge

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include usergroup] *******************************************************

TASK [usergroup : Make groups] *************************************************
changed: [inst] => (item={'name': 'hoge', 'gid': 7777})
changed: [inst] => (item={'name': 'fuga', 'gid': 8888})

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

確認する

> molecule login
INFO     Running default > login
[root@inst /]# cat /etc/group
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
(中略)
dbus:x:81:
input:x:999:
kvm:x:36:
render:x:998:
systemd-journal:x:190:
systemd-coredump:x:997:
systemd-resolve:x:193:
ssh_keys:x:996:
hoge:x:7777:
fuga:x:8888:

これに対するassertを書く。molecure/default/verify.ymlをこう書き換える。

---
# This is an example playbook to execute Ansible tests.

- name: Verify
  hosts: all
  gather_facts: false
  tasks:
  - shell: grep hoge /etc/group |grep -q 7777
    register: hoge
  - shell: grep fuga /etc/group |grep -q 8888
    register: fuga
  - name: Example assertion
    assert:
      that:
        - hoge.rc == 0
        - fuga.rc == 0

こんなんでいいのかな?

実行してみる。

> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
changed: [inst]

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
ok: [inst] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Verifier completed successfully.

わかりにくい・・・。

試しに、grep hoge...の行の最後の7777を8888に変えてみる。

実行するとテストがfailになる。

> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
fatal: [inst]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": "grep hoge /etc/group |grep -q 8888", "delta": "0:00:00.003928", "end": "2021-03-07 09:08:57.065460", "msg": "non-zero return code", "rc": 1, "start": "2021-03-07 09:08:57.061532", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

PLAY RECAP *********************************************************************
inst                       : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

CRITICAL Ansible return code was 2, command was: ansible-playbook --inventory /Users/tambara/.cache/molecule/usergroup/default/inventory --skip-tags molecule-notest,notest /Users/tambara/study/ansible_study/roles/usergroup/molecule/default/verify.yml

assertに入る前にエラーになってる。

ignore_errors: trueしてみる。

---
- name: Verify
  hosts: all
  gather_facts: false
  ignore_errors: true
  tasks:
  - shell: grep hoge /etc/group |grep -q 8888
    register: hoge
  - shell: grep fuga /etc/group |grep -q 8888
    register: fuga
  - name: Example assertion
    assert:
      that:
        - hoge.rc == 0
        - fuga.rc == 0

実行してみる。

> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
fatal: [inst]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": "grep hoge /etc/group |grep -q 8888", "delta": "0:00:00.005223", "end": "2021-03-07 09:21:12.978052", "msg": "non-zero return code", "rc": 1, "start": "2021-03-07 09:21:12.972829", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
fatal: [inst]: FAILED! => {
    "assertion": "hoge.rc == 0",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
...ignoring

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=2

INFO     Verifier completed successfully.

assertもignoreされた。これではダメだ。

shellモジュールに個別にignore_errors: trueを付けたら、上手くいったが、これはこれでテストの失敗がわかりづらい。

---
- name: Verify
  hosts: all
  gather_facts: false
  tasks:
  - shell: grep hoge /etc/group |grep -q 8888
    ignore_errors: true
    register: hoge
  - shell: grep fuga /etc/group |grep -q 8888
    ignore_errors: true
    register: fuga
  - name: Example assertion
    assert:
      that:
        - hoge.rc == 0
        - fuga.rc == 0
> molecule verify
INFO     default scenario test matrix: verify
INFO     Running default > verify
INFO     Running Ansible Verifier
INFO     Sanity checks: 'docker'

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
fatal: [inst]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": true, "cmd": "grep hoge /etc/group |grep -q 8888", "delta": "0:00:00.003725", "end": "2021-03-07 09:24:25.994889", "msg": "non-zero return code", "rc": 1, "start": "2021-03-07 09:24:25.991164", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
fatal: [inst]: FAILED! => {
    "assertion": "hoge.rc == 0",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=1

CRITICAL Ansible return code was 2, command was: ansible-playbook --inventory /Users/tambara/.cache/molecule/usergroup/default/inventory --skip-tags molecule-notest,notest /Users/tambara/study/ansible_study/roles/usergroup/molecule/default/verify.yml

とりあえず、これで全体を実行してみる。

> molecule test
INFO     default scenario test matrix: dependency, lint, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > lint
COMMAND: yamllint .
ansible-lint
flake8

./molecule/default/verify.yml
  17:1      error    too many blank lines (1 > 0)  (empty-lines)

WARNING  Listing 9 violation(s) that are fatal
You can skip specific rules or tags by adding them to your configuration file:

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ # .ansible-lint                                                                                                      │
│ warn_list:  # or 'skip_list' to silence them completely                                                              │
│   - '201'  # Trailing whitespace                                                                                     │
│   - '301'  # Commands should not change things if nothing needs doing                                                │
│   - '502'  # All tasks should be named                                                                               │
│   - '701'  # meta/main.yml should contain relevant info                                                              │
│   - '703'  # meta/main.yml default values should be changed                                                          │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
701 Role info should contain platforms
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: author
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: company
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: license
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/usergroup/meta/main.yml', 'skipped_rules': []}}

301 Commands should not change things if nothing needs doing
molecule/default/verify.yml:6
Task/Handler: shell grep hoge /etc/group |grep -q 7777

502 All tasks should be named
molecule/default/verify.yml:6
Task/Handler: shell grep hoge /etc/group |grep -q 7777

301 Commands should not change things if nothing needs doing
molecule/default/verify.yml:9
Task/Handler: shell grep fuga /etc/group |grep -q 8888

502 All tasks should be named
molecule/default/verify.yml:9
Task/Handler: shell grep fuga /etc/group |grep -q 8888

201 Trailing whitespace
molecule/default/verify.yml:14
      that:

INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy
INFO     Sanity checks: 'docker'

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '352555244554.23499', 'results_file': '/Users/tambara/.ansible_async/352555244554.23499', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

TASK [Delete docker network(s)] ************************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Running default > syntax

playbook: /Users/tambara/study/ansible_study/roles/usergroup/molecule/default/converge.yml
INFO     Running default > create

PLAY [Create] ******************************************************************

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item={'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False', 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item', 'i': 0, 'ansible_index_var': 'i'})

TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:8)

TASK [Create docker network(s)] ************************************************

TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True})

TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '929437985046.23918', 'results_file': '/Users/tambara/.ansible_async/929437985046.23918', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

INFO     Running default > prepare
WARNING  Skipping, prepare playbook not configured.
INFO     Running default > converge

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include usergroup] *******************************************************

TASK [usergroup : Make groups] *************************************************
changed: [inst] => (item={'name': 'hoge', 'gid': 7777})
changed: [inst] => (item={'name': 'fuga', 'gid': 8888})

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Running default > idempotence

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [inst]

TASK [Include usergroup] *******************************************************

TASK [usergroup : Make groups] *************************************************
ok: [inst] => (item={'name': 'hoge', 'gid': 7777})
ok: [inst] => (item={'name': 'fuga', 'gid': 8888})

PLAY RECAP *********************************************************************
inst                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Idempotence completed successfully.
INFO     Running default > side_effect
WARNING  Skipping, side effect playbook not configured.
INFO     Running default > verify
INFO     Running Ansible Verifier

PLAY [Verify] ******************************************************************

TASK [shell] *******************************************************************
changed: [inst]

TASK [shell] *******************************************************************
changed: [inst]

TASK [Example assertion] *******************************************************
ok: [inst] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY RECAP *********************************************************************
inst                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

INFO     Verifier completed successfully.
INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=inst)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '477983483623.24900', 'results_file': '/Users/tambara/.ansible_async/477983483623.24900', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'inst', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

TASK [Delete docker network(s)] ************************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Pruning extra files from scenario ephemeral directory

Lintはいっぱい怒られているけど、とりあえず、一通りは流れたようだ。

Ansibleで遊んでみる(2)

さて、ロールを作ってみよう。

molecule.readthedocs.io

これに従ってやってみる。

とりあえず、ユーザーグループを作るロールを作ってみよう。rolesというディレクトリを作って、その下で以下を実行する。

> molecule init role user-group --driver-name docker
INFO     Initializing new role user-group...
No config file found; using defaults
- Role user-group was created successfully
INFO     Initialized role in /Users/tambara/study/ansible_study/roles/user-group successfully.

user-groupディレクトリが作られて、その下にロールに必要なものが作られる。 このあたりはAnsibleのガイドライン通りが作られるが、それ以外にmoleculeというディレクトリが作られてそれがテストに関するものである。その下にdefaultというディレクトリがあって、これがデフォルトのテストケースにあたる。

Moleculeのgetting-startedには、defaultの下に4つのファイルが作られると書いてあるが3つしか作られなかった。作られなかった奴はインストドキュメントらしいんで気にしないことにする。

> ls
converge.yml  molecule.yml  verify.yml

molecule.ymlはこんな感じ

> cat molecule.yml
---
dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: instance
    image: docker.io/pycontribs/centos:8
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

docker run hello-worldしてdockerが動いてることが確認出来たら、テストを実行するインスタンス作成を試してみる。

> molecule create
INFO     default scenario test matrix: dependency, create, prepare
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > create
INFO     Sanity checks: 'docker'

PLAY [Create] ******************************************************************

TASK [Log into a Docker registry] **********************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True})

TASK [Check presence of custom Dockerfiles] ************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True})

TASK [Create Dockerfiles from image names] *************************************
skipping: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True})

TASK [Discover local Docker images] ********************************************
ok: [localhost] => (item={'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False', 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True}, 'ansible_loop_var': 'item', 'i': 0, 'ansible_index_var': 'i'})

TASK [Build an Ansible compatible image (new)] *********************************
skipping: [localhost] => (item=molecule_local/docker.io/pycontribs/centos:8)

TASK [Create docker network(s)] ************************************************

TASK [Determine the CMD directives] ********************************************
ok: [localhost] => (item={'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True})

TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) creation to complete] *******************************
FAILED - RETRYING: Wait for instance(s) creation to complete (300 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (299 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (298 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (297 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (296 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (295 retries left).
FAILED - RETRYING: Wait for instance(s) creation to complete (294 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '897685659497.84151', 'results_file': '/Users/tambara/.ansible_async/897685659497.84151', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

INFO     Running default > prepare
WARNING  Skipping, prepare playbook not configured.

大丈夫っぽい。

> molecule list
INFO     Running default > list
                ╷             ╷                  ╷               ╷         ╷
  Instance Name │ Driver Name │ Provisioner Name │ Scenario Name │ Created │ Converged
╶───────────────┼─────────────┼──────────────────┼───────────────┼─────────┼───────────╴
  instance      │ docker      │ ansible          │ default       │ true    │ false
                ╵             ╵                  ╵               ╵         ╵

ちゃんといる。

試しにタスクをいじってみる。

試しにタスクをいじってみる。

> cat tasks/main.yml
---
- name: Molecule Hello world!
  debug:
    msg: Hello, world!

実行する

> molecule converge
INFO     default scenario test matrix: dependency, create, prepare, converge
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > create
WARNING  Skipping, instances already created.
INFO     Running default > prepare
WARNING  Skipping, prepare playbook not configured.
INFO     Running default > converge
INFO     Sanity checks: 'docker'

PLAY [Converge] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [instance]

TASK [Include user-group] ******************************************************

TASK [user-group : Molecule Hello world!] **************************************
ok: [instance] => {
    "msg": "Hello, world!"
}

PLAY RECAP *********************************************************************
instance                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

出来たテストインスタンスにログインも簡単にできる。

> molecule login
INFO     Running default > login
[root@instance /]#
[root@instance /]# pwd
/
[root@instance /]# exit
exit

最後に、インスタンスを削除して終わり

> molecule destroy
INFO     default scenario test matrix: dependency, cleanup, destroy
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Running default > destroy
INFO     Sanity checks: 'docker'

PLAY [Destroy] *****************************************************************

TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)

TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item={'started': 1, 'finished': 0, 'ansible_job_id': '366507610977.86463', 'results_file': '/Users/tambara/.ansible_async/366507610977.86463', 'changed': True, 'failed': False, 'item': {'image': 'docker.io/pycontribs/centos:8', 'name': 'instance', 'pre_build_image': True}, 'ansible_loop_var': 'item'})

TASK [Delete docker network(s)] ************************************************

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

INFO     Pruning extra files from scenario ephemeral directory

さて、これだとLintが動いてない。デフォルトではLintが動かなくなったので、動かしたかったらmolecule.ymlを修正する。

とりあえず、公式にある通りだけど、set -eはfishではエラーになるので除いた。

> cat molecule/default/molecule.yml 
---
dependency:
  name: galaxy
lint: |
  yamllint .
  ansible-lint
  flake8
driver:
  name: docker
platforms:
  - name: instance
    image: docker.io/pycontribs/centos:8
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

実行してみる。

> molecule lint
INFO     default scenario test matrix: dependency, lint
INFO     Running default > dependency
WARNING  Skipping, missing the requirements file.
WARNING  Skipping, missing the requirements file.
INFO     Running default > lint
COMMAND: yamllint .
ansible-lint
flake8

WARNING  Listing 5 violation(s) that are fatal
You can skip specific rules or tags by adding them to your configuration file:

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ # .ansible-lint                                                                                                      │
│ warn_list:  # or 'skip_list' to silence them completely                                                              │
│   - '106'  # Role name {} does not match ``^[a-z][a-z0-9_]+$`` pattern                                               │
│   - '701'  # meta/main.yml should contain relevant info                                                              │
│   - '703'  # meta/main.yml default values should be changed                                                          │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
701 Role info should contain platforms
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: author
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: company
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml', 'skipped_rules': []}}

703 Should change default metadata: license
meta/main.yml:1
{'meta/main.yml': {'galaxy_info': {'author': 'your name', 'description': 'your role description', 'company': 'your company (optional)', 'license': 'license (GPL-2.0-or-later, MIT, etc)', 'min_ansible_version': 2.1, 'galaxy_tags': [], '__line__': 2, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml'}, 'dependencies': [], '__line__': 1, '__file__': '/Users/tambara/study/ansible_study/roles/user-group/meta/main.yml', 'skipped_rules': []}}

106 Role name user-group does not match ``^[a-z][a-z0-9_]+$`` pattern
tasks/main.yml:1
---

ロール名からしてルールに合ってないと言われてヘコんだ。

Ansibleで遊んでみる(1)

ちょっと仕事でAnsibleを使うことになったので勉強してみる。

コンピュータの性能が向上して、HWとしてのサーバ1台につき複数のOSを起動できるようになってきたのがゼロ年代の後半ぐらい。それまではインフラ担当者がセットアップしなければならいサーバというのは数台から十数台ぐらいまでだった。しかし、物理CPUを複数の論理CPUに分割してバーチャルマシン(VM)に割り当てられるようになると、それまで扱っていた数台のHWごとに10ぐらいのOSが起動するようになる。すると、インフラ担当者がセットアップするOSは一気に数十台規模になり、それまでと同じ手段でセットアップしていたのではやってられなくなった。

そこで、OSのセットアップ内容を記述したらそれで自動的にセットアップをしてくれる仕組みが登場した。ChefとかPuppetが代表的なものである。セットアップ内容を記述したものをプログラムコードと同じようにバージョン管理もできるようになった。さらに、ソフトウェア開発で当たり前になってきたCI/CDをこれらのセットアップコードに適用して、セットアップ内容のテストを自動化も出来るようになった。ChefやPuppetはRubyで書かれていたので、自然とこのテストはRubyのテストフレームワークであるRSpecで行うようになり、Serverspecというフレームワークが作られた。このようにソフトウェア開発と同じようにサーバ構成をCI/CDする手法を指して、Infrastracture as Code(IaC)と呼ばれるようになる。

さらに、時代はクラウドになり、サーバは欲しいときにいつでもプロビジョニングできるようになった。しかし、ChefやPuppetはあらかじめエージェントをインストールされたターゲットしか操作できない。自分で作ったVMイメージを使っている場合には問題にならないが、クラウドではそれは使いづらい。そこで、だいたいどこにでもあらかじめインストールされているPythonを使うことにした。コントロールサーバでPythonスクリプトを構成にあわせて生成し、SSHで送り込んで実行する。これがAnsibleである。

そして、IaCであるからには、Ansibleで作成した構成情報(Playbook)もCI/CDで管理されなければならない。そのためにはテストフレームワークが必要になるはずだ。

インフラから足を洗ったはずの私がなぜAnsibleをやっているプロジェクトに呼ばれたかというと、単にAnsibleのPlaybookを書いてくれというのではなく、CI/CDを前提としたIaCをAnsibleでやりたいのでソフトウェア開発の知見を活かして仕組みを組み立てて欲しいとのことだった。Ruby LoverなのでAnsibleに積極的ではなかったんでまるっと最初からお勉強しているところだ。

さっぱりわからないなりに数日ネットを彷徨った結果、AnsibleのテストフレームワークはMoleculeというものがあるらしい。2015年頃に出来たものなのでかなり新しめで、Playbookをロール(Playbookの構成要素)単位でテストすることが出来る。ものがインフラなので、普通のテストフレームワークのsetup/teardownをどうするかが問題になるわけだが、テスト実行単位でコンテナやVMを作るところまでセットでやってくれる。有り難い。

というわけで、まずはインストール。ひとまず、macOS上でテストにDockerを使う前提とする。 すべてPython上で動かすので、必要に応じてvirtualenvなどを使うこと。私は面倒でやらなかった。また今度泣くことにする。

よくわからないなりに順次いれていく。

まずは、ansible。pipで入れてもいいみたいだけど、Homebrewでいれた。brew install ansibleでOK。

次にmolecule。DockerとLintも使うので、pip install molecule[docker, lint]でOK。

先にAnsibleの疎通確認をしておこう。

qiita.com

これを参考にする。

とりあえずは、localhostを操作するようにするので、localhostsshできるようにする。

  • [システム環境設定] - [共有] でリモートログインにチェックを入れる
  • ssh-copy-id -i キー名 localhost
  • ssh localhostして接続出来ればOK

動作を確認。

> ansible-console --inventory localhost, --user tambara
Welcome to the ansible console.
Type help or ? to list commands.

tambara@all (1)[f:5]$ ping
[WARNING]: Platform darwin on host localhost is using the discovered Python interpreter at /usr/bin/python, but future
installation of another Python interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
localhost | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

ふむふむ

ヘルプ出してみる

tambara@all (1)[f:5]$ ?

Documented commands (type help <topic>):
========================================
EOF             dnf              include_role   service_facts      
add_host        dpkg_selections  include_tasks  set_fact           
apt             exit             include_vars   set_stats          
apt_key         expect           iptables       setup              
apt_repository  fail             known_hosts    shell              
assemble        fetch            lineinfile     slurp              
assert          file             list           stat               
async_status    find             meta           subversion         
async_wrapper   forks            package        systemd            
become          gather_facts     package_facts  sysvinit           
become_method   get_url          pause          tempfile           
become_user     getent           ping           template           
blockinfile     git              pip            unarchive          
cd              group            raw            uri                
check           group_by         reboot         user               
command         help             remote_user    verbosity          
copy            hostname         replace        wait_for           
cron            import_playbook  rpm_key        wait_for_connection
debconf         import_role      script         yum                
debug           import_tasks     serial         yum_repository     
diff            include          service      

tambara@all (1)[f:5]$ help user
Manage user accounts
Parameters:
  name Name of the user to create, remove or modify.
  uid Optionally sets the I(UID) of the user.
  comment Optionally sets the description (aka I(GECOS)) of user account.
  hidden macOS only, optionally hide the user from the login window and system preferences.
  non_unique Optionally when used with the -u option, this option allows to change the user ID to a non-unique value.
  seuser Optionally sets the seuser type (user_u) on selinux enabled systems.
  group Optionally sets the user's primary group (takes a group name).
  groups List of groups user will be added to. When set to an empty string C(''), the user is removed from all groups except the primary group.
  append If C(yes), add the user to the groups specified in C(groups).
  shell Optionally set the user's shell.
  home Optionally set the user's home directory.
  skeleton Optionally set a home skeleton directory.
  password Optionally set the user's password to this crypted value.
  state Whether the account should exist or not, taking action if the state is different from what is stated.
  create_home Unless set to C(no), a home directory will be made for the user when the account is created or if the home directory does not exist.
  move_home If set to C(yes) when used with C(home: ), attempt to move the user's old home directory to the specified directory if it isn't there already and the old home exists.
  system When creating an account C(state=present), setting this to C(yes) makes the user a system account.
  force This only affects C(state=absent), it forces removal of the user and associated directories on supported platforms.
  remove This only affects C(state=absent), it attempts to remove directories associated with the user.
  login_class Optionally sets the user's login class, a feature of most BSD OSs.
  generate_ssh_key Whether to generate a SSH key for the user in question.
  ssh_key_bits Optionally specify number of bits in SSH key to create.
  ssh_key_type Optionally specify the type of SSH key to generate.
  ssh_key_file Optionally specify the SSH key filename.
  ssh_key_comment Optionally define the comment for the SSH key.
  ssh_key_passphrase Set a passphrase for the SSH key.
  update_password C(always) will update passwords if they differ.
  expires An expiry time for the user in epoch, it will be ignored on platforms that do not support this.
  password_lock Lock the password (C(usermod -L), C(usermod -U), C(pw lock)).
  local Forces the use of "local" command alternatives on platforms that implement it.
  profile Sets the profile of the user.
  authorization Sets the authorization of the user.
  role Sets the role of the user.

なるほど。

F#で遊んでみる(1)

2年ぐらい前に、戯れにOCamlの勉強をしてみた。ML系の言語は、広く使われているとは言えないもののこれが必要な人にとっては他に換えがたいもののようである。その中で、OCamlという言語はMLとしては実用的な言語として開発母体もそこそこちゃんとしていて、それなりのエコシステムがあり、その手の人に広く使われているものらしい。

ところが、ここのところML系の言語の選択肢として、OCamlからMicrosoftのF#へと人気が移ってきているという記事をちらほらと見かけた。ホントなんだろうか。とりあえず、F#という言語が.net Frameworkのお仲間としてあるとは聞いているが、それはあのOCamlの代わりになるようなシロモノなんだろうか。

調べてみたら、そんなシロモノだった。というか、F#は.NETの上でOCamlすることが目的の言語で、むしろシンタックスはそっくりレベルのものだった。ただ、Visual Studio 2010に搭載されてデビューした当時は、MLを使いたいからといってそれだけの為に人はVSを買わなかっただろうし、VSを買う人が「せっかくだから」と使うわけもないし、私のような人には何のためにあるのかよくわかんない言語だと認識されていたように思う。しかし、そこから時は流れ、10年経ち、言語としてのF#は熟成が進み、ランタイムとしての.NETは.NET CoreとしてWindows以外の実行環境でもちゃんと動いて、かつ、無償で配布され、Visual Studio CodeによってVSがなくても、Windowsじゃなくても、全然問題なくなった。Linux上でF#を書いたり実行したり普通に出来て、ライブラリはMicrosoftの.Netエコシステムという非常に強力なものが使える。こりゃええわい・・・ということらしい。

そんじゃ、ま、とりあえず、Macの上でF#で気軽にコードを書いてみることができるのか。いや、関数型言語を気楽に書くような能力は私には全然ないわけだけども、とりあえず、どんな感じだか体感してみよう。

参考にするのは、この記事。

F# を知ってほしい - Qiita

さて、何はなくともインストール。Microsoftのサイトから、.NETのSDKを落としてくる。

dotnet.microsoft.com

ここで、.NET5を選べば良いのか、.NET Core 3.1を選べば良いのか・・・さっぱりわからない。.NET ⊇ .NET Core だと思う。たぶん、ASP.netが入っているかいないかとか、そういう差なんだと思うんだけど・・・わからない。ま、とりあえず、.NET 5をダウンロードして、インストーラーに従って入れてみる。

コマンドラインdotnetコマンド(これがnpmとかcargoみたいなものらしい)を実行してみよう。

> dotnet --info
.NET SDK (global.json を反映):
 Version:   5.0.102
 Commit:    71365b4d42

ランタイム環境:
 OS Name:     Mac OS X
 OS Version:  10.15
 OS Platform: Darwin
 RID:         osx.10.15-x64
 Base Path:   /usr/local/share/dotnet/sdk/5.0.102/

Host (useful for support):
  Version: 5.0.2
  Commit:  cb5f173b96

.NET SDKs installed:
  5.0.102 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 5.0.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 5.0.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

ほほぅ。

さて、察するにdotnetがcargoみたいなものだとしたら、dotnet newとかするとアプリのテンプレートを作ってくれたりするに違いない。--helpオプションを付けてヘルプを参照して、こんな感じかなって実行してみた。

> dotnet new console -lang F#
The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on /Users/tambara/study/fs_study/fs_study.fsproj...
  復元対象のプロジェクトを決定しています...
  /Users/tambara/study/fs_study/fs_study.fsproj を復元しました (3.58 sec)。
Restore succeeded.

> ls
Program.fs       fs_study.fsproj  obj/

なんか出来たぞ?

では、このディレクトリをVSCで開いてみよう。EXTENSIONSのRECOMMENDEDにIonide-fsharpというのが上がってくる。これをインストールすればいいらしい。とりあえず、シンタックスハイライトは出来ているし、これでいいのかな。

当然、runも出来るのだろう。

> dotnet run
Hello world from F#

これでとりあえずの準備は良さそうだ。