[Ansible] 自作のコレクションを作ってGalaxyで公開するまで

本記事は「[Ansible Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ansible_01)」の16日目のエントリとなります。
先日別のアドベントカレンダーで公開した「[ESXi上でvim-cmdを使ってVM操作するAnsibleコレクション (無償ライセンス利用可)](https://qiita.com/zaki-lknr/items/2b958d90ad7aa1170287)」で紹介したコレクションをどうやって作って公開したか、という内容になります。

# 前置き

本記事では「モジュールの作り方」自体は説明しないので、基本的には「作成済みの自作モジュールをどうすればコレクションにできるのか」という観点の内容になります。

また、対象とするのはモジュールプラグインのみです。
(callbackやlookupなどは扱ってません)

# (準備) Ansible Galaxyにアカウントを作る

※ コレクションを作るのみで公開しないのであればGalaxyのアカウントは必要ではないです。

[Ansible Galaxy](https://galaxy.ansible.com/)

GitHubのアカウントが必要。

画面右上の「Login」から。
押下するとGitHubとの連携が要求されるのでアイコンを押下して連携します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/c4214513-0d0f-bc23-2359-4d6364c43301.png)

公開前提でないのであればアカウントを作る必要はないけれど、公開する__かもしれない__場合は、ネームスペースってどう決めるのかはアカウント作っておくとすぐわかるので、作った方が良いかも。

平たく言うと、個人作成の場合は`GitHubアカウント名.コレクション名`となります。
(コレクション名は機能などをベースに自由に決めてよい)

# namespaceの決め方

Ansible 2.10からモジュールなどにネームスペース(名前空間)という概念が標準機能に加わりました。
これは、コレクションがネームスペースで分類されているためです。

で、自作コレクションのネームスペースは自由に決めていいといえば良いと思いますが、Ansible Galaxyで公開前提にする場合はGalaxyのネームスペースと同じものにする必要があります。
なのでGitHubのアカウントでGalaxyのアカウントを作る(場合が個人ではほとんどな)ので、基本的には`GitHubアカウント名.コレクション名`で作るのが都合が良いということです。

> It is convenient if the organization and repository names on GitHub (or elsewhere) match your namespace and collection names on Ansible Galaxy, but it is not required. The plugin names you select, however, are always the same in your code repository and in your collection artifact on Galaxy.
>
> <https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_in_groups.html#naming-conventions>

ちなみに私の場合はGitHubのアカウント名は`zaki-lknr`でハイフンを含むのですが、コレクションのネームスペースに使用できる文字は`m/[a-zA-Z0-9_]/`のため、ハイフンはアンダーバーに変換します。
というかAnsible GalaxyにこのGitHubアカウント名でアカウント作ると、Ansible Galaxy上ではユーザー名は`zaki_lknr`になります。

GitHubアカウント名でなく専用のネームスペース(たとえば共同開発してるプロダクト名など)を作りたい場合は、[GalaxyのIssueで依頼する必要がある](https://github.com/ansible/galaxy/issues?q=label%3Aarea%2Fnamespace)っぽいです。

# コレクションの作成

## 作業用ディレクトリ作成

まずプレイブックのある場所でディレクトリ`collections/ansible_collections`を作成します。  
作成するコレクション自体のパスは任意だけど、作ったコレクションを手元のプレイブックから簡単に利用するために、このディレクトリ構造にしています。  
(実行時には「コレクションのパス」以下にある`ansible_collections/<namespace>/<collections>`というパスを認識するため)

```
(2.10) [zaki@cloud-dev esxi-ansible]$ mkdir -p collections/ansible_collections
```

※ `collections`というディレクトリは既定のものではないので特になんでも良いです。

## コレクション雛形の作成

`ansible-galaxy collection init`で作成できます。  
書式は`<namespace>.<collection>`を引数に指定します。  
オプション`--init-path collections`を付与して、前述の`collections/ansible_collections`ディレクトリ配下に作成しています。

```
(2.10) [zaki@cloud-dev esxi-ansible]$ ansible-galaxy collection init zaki_lknr.esxissh --init-path collections/ansible_collections
- Collection zaki_lknr.esxissh was created successfully
```

`--init-path collections`が未指定であれば実行時のカレントディレクトリに作成されます。

作成されるファイル群はこんな感じ。

```
(2.10) [zaki@cloud-dev esxi-ansible]$ find collections/
collections/
collections/ansible_collections
collections/ansible_collections/zaki_lknr
collections/ansible_collections/zaki_lknr/esxissh
collections/ansible_collections/zaki_lknr/esxissh/README.md
collections/ansible_collections/zaki_lknr/esxissh/galaxy.yml
collections/ansible_collections/zaki_lknr/esxissh/docs
collections/ansible_collections/zaki_lknr/esxissh/plugins
collections/ansible_collections/zaki_lknr/esxissh/plugins/README.md
collections/ansible_collections/zaki_lknr/esxissh/roles
```

これで`zaki_lknr.esxissh.hogehoge`とか`zaki_lknr.esxissh.foobar`という名前のモジュールを作っていくひな形ができました。

## Ansibleモジュールを作成

今回はコレクション配下にモジュールを作成します。  
コレクションはモジュールだけのものでなく、callbackプラグインやlookupプラグインなど、各種プラグインの集合体になっています。

これは、現在のAnsible Documentationサイトで「[Collection Index](https://docs.ansible.com/ansible/latest/collections/index.html)」から1件ピックアップすると「Plugin Index」になるのを見れば階層構造のイメージはつきやすいと思います。  
例えば標準のコレクションである「[ansible.builtin collection](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html)」を見ると、以下のように分類されています。

- Become Plugins
- Cache Plugins
- Callback Plugins
- Connection Plugins
- Inventory Plugins
- Lookup Plugins
- Modules
    - 今回これを作ります☆彡
- Shell Plugins
- Strategy Plugins
- Vars Plugins

詳しくは雛形として作成された`plugins/README.md`と、[Working With Plugins — Ansible Documentation](https://docs.ansible.com/ansible/latest/plugins/plugins.html)を参照。

ということで話を戻し、作成した`zaki_lknr.esxissh`コレクションに、ESXi上のゲストOSの電源on/offを行うための`esxissh_guest_power`Ansibleモジュールを作成してみます。

Ansibleモジュールのソースは、ひな形で作成されたディレクトリ群の中の`plugins`以下に`modules`というサブディレクトリを作成し、その配下に作成することでモジュールプラグインとして機能します。  
今回で言うと`collections/zaki_lknr/esxissh/plugins/modules`以下に`esxissh_guest_power.py`を作成。

```txt:完成予定のディレクトリ構造
/home/zaki/src/esxi-ansible/collections/
└── ansible_collections
    └── zaki_lknr
        └── esxissh
            ├── README.md
            ├── docs
            ├── galaxy.yml
            ├── plugins
            │   ├── README.md
            │   ├── module_utils
            │   │   └── esxissh.py
            │   └── modules
            │       ├── esxissh_guest.py
            │       └── esxissh_guest_power.py      <- これ
            └── roles
```

ここでは非コレクション環境での作成済みモジュール`library/esxissh_guest_power.py`を配置します。

```
(2.10) [zaki@cloud-dev esxi-ansible]$ mkdir collections/ansible_collections/zaki_lknr/esxissh/plugins/modules
(2.10) [zaki@cloud-dev esxi-ansible]$ cp sample-playbook/library/esxissh_guest_power.py collections/ansible_collections/zaki_lknr/esxissh/plugins/modules/
```

ここに配置したソースファイルのファイル名がモジュール名になります。

## モジュールからimportされるPythonパッケージ

Ansibleモジュールからimportされる外部ファイルに処理を実装する場合(例えば複数のAnsibleモジュールを作り、共通処理を外部ソースファイルに実装、など)、従来のAnsibleモジュールと同じように`module_utils`というディレクトリを`modules`と同じ階層に作成し、そこへソースファイルを配置すれば`import`できます。

```txt:完成予定のディレクトリ構造
/home/zaki/src/esxi-ansible/collections/
└── ansible_collections
    └── zaki_lknr
        └── esxissh
            ├── README.md
            ├── docs
            ├── galaxy.yml
            ├── plugins
            │   ├── README.md
            │   ├── module_utils
            │   │   └── esxissh.py                 <- これ
            │   └── modules
            │       ├── esxissh_guest.py
            │       └── esxissh_guest_power.py
            └── roles
```

```
(2.10) [zaki@cloud-dev esxi-ansible]$ mkdir collections/ansible_collections/zaki_lknr/esxissh/plugins/module_utils
(2.10) [zaki@cloud-dev esxi-ansible]$ cp sample-playbook/module_utils/esxissh.py collections/ansible_collections/zaki_lknr/esxissh/plugins/module_utils/
```

そして、`import`するときのパスときの書式は`from ansible_collections.<namespace>.<collection>.plugins.module_utils import <my-module>`となります。
(`from ansible.module_utils import <my-module>`になってるはずの部分を変更 → [変更サンプル](https://github.com/zaki-lknr/esxissh-ansible/commit/b37b3b76b9b1bf07f28d3e5a485b90439f88d8ea))

```python
from ansible_collections.zaki_lknr.esxissh.plugins.module_utils import esxissh
```

これで、コード部分は変更不要。

## モジュールのソース内のコメントからドキュメントファイル生成

`docs`というディレクトリが雛形として作成されていて、ここにコレクションの各プラグインのドキュメントを「モジュールのソース内の指定コメントとは別に」用意するわけですが、さすがに自動生成するべきだけどどうすればいいのかなーとちょっと保留していましたが、Ansibleアドカレ12日目でsky_jokerさんが素晴らしい記事を作成されています。

[Ansible Collectionsのモジュールドキュメントを自動生成する | 日常系エンジニアのTech Blog](https://sky-joker.tech/2020/12/12/ansible-collections%e3%81%ae%e3%83%a2%e3%82%b7%e3%82%99%e3%83%a5%e3%83%bc%e3%83%ab%e3%83%88%e3%82%99%e3%82%ad%e3%83%a5%e3%83%a1%e3%83%b3%e3%83%88%e3%82%92%e8%87%aa%e5%8b%95%e7%94%9f%e6%88%90%e3%81%99/)

[collection_prep](https://github.com/ansible-network/collection_prep)というツールを使ってrst形式でドキュメントを生成することができます。

ちなみに手元の環境では

```
docker run -itd --name py38 -v $PWD:/usr/src/work --rm python:3.8
```

として、コンテナ内でローカルのソースコード一式を参照できるようにボリューム設定してドキュメンテーションしましたが、root権限で動かした影響で生成されるファイルのownerがrootになるのでそういう点は注意。(gitでブランチ変えたときにファイル変更できなかったｗ)

生成したドキュメントはこちら。

<https://github.com/zaki-lknr/esxissh-ansible/tree/main/docs>

モジュールのソースコードへのコメント作成については以下を参照。

[Module format and documentation — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html)

# Ansible実行時のコレクションのローカル参照

これで`collections`ディレクトリ以下に`zaki_lknr.esxissh`というコレクションを配置し、このコレクションに`esxissh_guest_power`というモジュールができました。  
次はこのモジュールを使用するプレイブック修正と設定を行います。

## モジュールをFQCN指定

まず、既存モジュールを使っているプレイブックのモジュール指定部分をFQCNにします。
プレイブックの編集はこれで終わりです。

```diff
index 43b96ba..d76cb17 100644
--- a/sample-playbook/create_vm.yml
+++ b/sample-playbook/create_vm.yml
@@ -3,7 +3,7 @@
 
   tasks:
   - name: create vm
-    esxissh_guest:
+    zaki_lknr.esxissh.esxissh_guest:
       esxiaddress: '{{ esxiaddr }}'
       esxiusername: '{{ esxiuser }}'
       esxipassword: '{{ esxipass }}'
```

## コレクションのパス指定

ここまででコレクション本体と、コレクション配下のモジュールを指定するプレイブックはできました。  
肝心の「実行時にこのパスにあるコレクションを使用する」については、`ansible.cfg`に指定するのが簡単。

ちなみにコレクションは[デフォルトではAnsible実行時のユーザーの`$HOME/.ansible/collections`以下を見る設定](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths)になっています。  
これは特にvenv使用時に注意が必要で、venvで作った環境の外部を参照するため、デフォルトの状態だと「venvで環境を切り出したつもりが複数のvenv環境で同じ部分を見ていた」ということが起こり得て、パス設定を特に指定せずに`ansible-galaxy collection install`でインストールすると環境が混ざってしまう可能性があります。

ではどうすれば良いかと言うと、`ansible.cfg`に

```ini
collections_path = /home/zaki/src/esxi-ansible/collections/
```

のように記述しておけば、`$HOME/.ansible`でなく指定したパスのコレクションを参照するようになります。
ここで指定したパス以下は、`ansible_collections/<namespace>/<collectionname>/`と続き、その配下に`plugins/modules/<module-name>.py`という構成になります。

```
/home/zaki/src/esxi-ansible/collections/
└── ansible_collections
    └── zaki_lknr
        └── esxissh
            ├── README.md
            ├── docs
            ├── galaxy.yml
            ├── plugins
            │   ├── README.md
            │   ├── module_utils
            │   │   └── esxissh.py
            │   └── modules
            │       ├── esxissh_guest.py
            │       └── esxissh_guest_power.py
            └── roles
```

## 自作コレクションのモジュールを使ったAnsible Playbook実行

- playbookからFQCNでモジュール指定
- コレクションのパスを`ansible.cfg`の`collections_path`で指定

この2点でプレイブックからは任意のパスにあるコレクションのモジュールを参照できるので、自作コレクションのモジュールで`ansible-playbook`を実行できます。

# ここまでのまとめ

ここまでをまとめると以下のようになります。

- `ansible-galaxy collection init <namespace>.<collection> --init-path /path/to`でひな形作成
- `ansible.cfg`で`collections_path`を指定
- `collections_path`のパス以下にコレクションを配置
- PlaybookではFQCNでモジュール名を指定

個人環境などで、プレイブックの作成とコレクションの作成を並行してすすめる場合や、コレクションの配布など行わない場合はこれで良いと思います。

# 配布する

## コレクションをパッケージング

[配布用パッケージを作るには、`ansible-galaxy collection build`](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html#building-collections)を使用します。
引数にコレクションのパス(`<namespace>.<collection>/`まで。この直下に`galaxy.yml`があるパス)を指定します。(省略時はカレントディレクトリに`galaxy.yml`がある前提)

[Collection Galaxy metadata structure — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html)

また、パッケージングには`galaxy.yml`ファイルといういわゆるマニフェスト的な定義ファイルを作成(テンプレート作成されているので必要か所を記入)します。

内容については[中身を見るのが早い](https://github.com/zaki-lknr/esxissh-ansible/blob/main/galaxy.yml)と思いますが、GalaxyのページでリポジトリやIssueへのリンクや、コレクション名・バージョンなどの定義などを記述します。
パッケージング時に除外するファイルも指定できるので、環境固有の記述をしてるファイルとか中間ファイルとか`venv`ディレクトリなどを除いておくと良いです。

`galaxy.yml`の主な記述箇所は以下の通り。

| item         | description                    |
| ------------ | ------------------------------ |
| namespace    | Galaxy上のネームスペース(アカウント名)        |
| name         | コレクション名                        |
| version      | コレクションバージョン (数値で`x.y.z`形式)     |
| readme       | Galaxy用readmeファイルのパス           |
| author       | コレクション作成者(リスト形式)               |
| repository   | ソースのリポジトリURL                   |
| issues       | IssueのURL                      |
| build_ignore | `collectoin build`時に除くファイルパターン |

準備ができたら`ansible-galaxy collection build <path>`を実行します。

```
(2.10) [zaki@cloud-dev esxi-ansible (features/collections)]$ ansible-galaxy collection build collections/ansible_collections/zaki_lknr/esxissh/
Created collection for zaki_lknr.esxissh at /home/zaki/src/esxi-ansible/zaki_lknr-esxissh-1.0.0.tar.gz
```

成功すると、実行ディレクトリに`<namespace>-<collection>-<version>.tar.gz`という名前でコレクションが作成されます。(`--output-path /path/to`で出力先は変更可能)
ちなみに中身はこんな感じ。

```
(2.10) [zaki@cloud-dev esxi-ansible (features/collections)]$ tar tf zaki_lknr-esxissh-1.0.0.tar.gz 
MANIFEST.json
FILES.json
docs/
roles/
README.md
plugins/
plugins/README.md
plugins/module_utils/
plugins/module_utils/esxissh.py
plugins/modules/
plugins/modules/esxissh_guest.py
plugins/modules/esxissh_guest_power.py
```

## パッケージングされたコレクションをファイルからインストール

コレクションのインストールはAnsible Galaxyを使用しなくても、ローカルのファイルを指定してインストールできます。

```
 (venv) [zaki@cloud-dev esxissh]$ ansible-galaxy collection -h
usage: ansible-galaxy collection [-h] COLLECTION_ACTION ...

positional arguments:
  COLLECTION_ACTION
    ...

    install          Install collection(s) from file(s), URL(s) or Ansible
                     Galaxy
```

お試し用に、新しく別のパスに環境を作成してファイルを配置

```
(venv) [zaki@cloud-dev esxissh]$ ls -F
venv/  zaki_lknr-esxissh-1.0.0.tar.gz
(venv) [zaki@cloud-dev esxissh]$ which ansible-galaxy
~/src/tmp/esxissh/venv/bin/ansible-galaxy
```

インストール先を指定しないと前述の通り`$HOME/.ansible/`以下になってしまうため、ここでは`-p`でカレントの`collections`を指定します。

```
(venv) [zaki@cloud-dev esxissh]$ ansible-galaxy collection install zaki_lknr-esxissh-1.0.0.tar.gz -p collections
Starting galaxy collection install process
[WARNING]: The specified collections path '/home/zaki/src/tmp/esxissh/collections' is not part of the configured Ansible
collections paths '/home/zaki/.ansible/collections:/usr/share/ansible/collections'. The installed collection won't be picked up
in an Ansible run.
Process install dependency map
Starting collection install process
Installing 'zaki_lknr.esxissh:1.0.0' to '/home/zaki/src/tmp/esxissh/collections/ansible_collections/zaki_lknr/esxissh'
zaki_lknr.esxissh (1.0.0) was installed successfully
(venv) [zaki@cloud-dev esxissh]$ ls -F
collections/  venv/  zaki_lknr-esxissh-1.0.0.tar.gz
```

この通りインストールされました。

```
(venv) [zaki@cloud-dev esxissh]$ tree collections/
collections/
└── ansible_collections
    └── zaki_lknr
        └── esxissh
            ├── FILES.json
            ├── MANIFEST.json
            ├── README.md
            ├── docs
            ├── plugins
            │   ├── README.md
            │   ├── module_utils
            │   │   └── esxissh.py
            │   └── modules
            │       ├── esxissh_guest.py
            │       └── esxissh_guest_power.py
            └── roles

8 directories, 7 files
```

## 任意のHTTPサーバーからのインストール

例えば、ローカルネットワーク内webサーバー上に <http://192.168.0.19/ansible/zaki_lknr-esxissh-1.0.0.tar.gz> みたいな場所にコレクションファイルを配置しておけば、URL指定でインストールもできます。

```
(venv) [zaki@cloud-dev esxissh]$ ansible-galaxy collection install http://192.168.0.19/ansible/zaki_lknr-esxissh-1.0.0.tar.gz -p collections
Starting galaxy collection install process
[WARNING]: The specified collections path '/home/zaki/src/tmp/esxissh/collections' is not part of the configured Ansible
collections paths '/home/zaki/.ansible/collections:/usr/share/ansible/collections'. The installed collection won't be picked up
in an Ansible run.
Process install dependency map
Downloading http://192.168.0.19/ansible/zaki_lknr-esxissh-1.0.0.tar.gz to /home/zaki/.ansible/tmp/ansible-local-3625522b6vz_fk/tmpng661w25
Starting collection install process
Installing 'zaki_lknr.esxissh:1.0.0' to '/home/zaki/src/tmp/esxissh/collections/ansible_collections/zaki_lknr/esxissh'
zaki_lknr.esxissh (1.0.0) was installed successfully
(venv) [zaki@cloud-dev esxissh]$ ls
collections  venv
(venv) [zaki@cloud-dev esxissh]$ tree collections/
collections/
└── ansible_collections
    └── zaki_lknr
        └── esxissh
            ├── FILES.json
            ├── MANIFEST.json
            ├── README.md
            ├── docs
            ├── plugins
            │   ├── README.md
            │   ├── module_utils
            │   │   └── esxissh.py
            │   └── modules
            │       ├── esxissh_guest.py
            │       └── esxissh_guest_power.py
            └── roles

8 directories, 7 files
(venv) [zaki@cloud-dev esxissh]$ 
```

業務などで作成したコレクションをプライベートネットワーク上の複数ホストなどで利用するには簡単に使えると思います。

## Ansible Galaxyで公開

Ansible Galaxyの自分のネームスペースにアップロードすることで、全世界に公開することもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/8eb23044-093a-54f6-db74-d318fc122bda.png)

「Add Content」押下

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/6edef16c-c6f0-5079-3396-0cf94f4d7cbf.png)

「Import Role from GitHub」は、

> Legacy Role import. Does not support Collection format.

とのことで、コレクションのリポジトリ設定はできないみたい。
ということで「Upload New Collection」押下して、作成したコレクションのパッケージファイルを…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/dce2450c-acfb-628f-9c4c-6eca845c5e33.png)

なんか、何やっても「Invalid file format」と表示されてうまくいかん。。。

なのでCLIからのアップロードをやってみます。

これは`ansible-galaxy`コマンドを使ったアップロード操作で、アップロード用のトークンを指定します。
このトークンはログインした画面右上の「Preferences」から。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/6a796810-ce28-6f3b-8155-c93570484cad.png)

Preferences画面が開いたら、画面内の「Show API Key」ボタン押下で、APIキーが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/fd0c58c2-bb3b-0357-2587-971a7c144e7a.png)

あとはこのAPIキーを`--token=`というオプションで指定、`ansible-galaxy collection publish`でパッケージングしたtar.gzファイルを引数に実行します。

```
(2.10) [zaki@cloud-dev tmp (fix/collection-structure-dirs)]$ ansible-galaxy collection publish --token=${GALAXY_API_TOKEN} zaki_lknr-esxissh-1.0.0.tar.gz 
Publishing collection artifact '/home/zaki/src/esxi-ansible/tmp/zaki_lknr-esxissh-1.0.0.tar.gz' to default https://galaxy.ansible.com/api/
Collection has been published to the Galaxy server default https://galaxy.ansible.com/api/
Waiting until Galaxy import task https://galaxy.ansible.com/api/v2/collection-imports/6382/ has completed
Collection has been successfully published and imported to the Galaxy server default https://galaxy.ansible.com/api/
(2.10) [zaki@cloud-dev tmp (fix/collection-structure-dirs)]$ echo $?
0
```

アップロードできました。

![2020-11-28_19h07_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/d1d7e4a2-a7a8-0c06-f750-eea0f3f7a1e6.png)

実際のコレクションのページはこちら

<https://galaxy.ansible.com/zaki_lknr/esxissh>

このコレクションの使い方については、「[ESXi上でvim-cmdを使ってVM操作するAnsibleコレクション (無償ライセンス利用可)](https://qiita.com/zaki-lknr/items/2b958d90ad7aa1170287)」をご参考ください。

アップロードしてみるとわかりますが、画面右上の「Repo」や「Issue Tracker」のボタンのリンク先や、「Read Me」で表示される内容、「Content」にリストされる項目が、`galaxy.yml`や、コレクションに含まれるプラグイン類が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256859/1c02b592-2414-8310-9149-c8845ac874da.png)

### やらかし

Galaxyにアップロードしたコレクションは__ユーザーは削除することができません__。(多分)
少なくとも削除操作のためのボタンの類はどこにもなく、Issueを検索すると削除リクエストがいくつか見つかります。

なので、buildの際に含めてはいけないファイルが含まれていないか十分確認しましょう。。。(訳: `.gitignore`は設定してたけどgalaxyのbuildは関係ないのでうっかりやらかした、ということです←)

なお、[buildから除外するファイルは、`galaxy.yml`の`build_ignore:`で指定](https://github.com/zaki-lknr/esxissh-ansible/blob/b6ba99ce61a4910eb41e57fde0340f49ae7d140c/galaxy.yml#L63-L69)できます。
`venv`や`*.tmp`、`*.bak`なんかは指定しておきましょう。
(※ [アップロード可能なパッケージサイズは最大2MB](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html#building-collections)なので、`venv`を入れているとアップロードはまず間違いなく失敗します)

Issueの削除リクエストは1日で対応されることもあれば1週刊くらい管理者の目に留まらない？こともあるみたいなので、機微な情報をアップロードしないように気を付けましょう。約束ですよ！

あとおそらく削除時は指定バージョンだけでなくコレクション丸ごと削除しているように見えるのでほんとに気を付けましょう。(未確認情報)

---

# 参考にしたもの

公式ドキュメントと言いたいところだけど、頭から順に読むのって初めてはなかなか難しいので、実際に公開されているコレクションが参考になりました。
(GitHub上のソースのここがGalaxyのここに相当しているんだな、みたいな感じで)

その上で公式ドキュメントを確認すると理解しやすかったです。

- コレクションやドキュメントの実装例
    - F5
        - [Ansible Galaxy](https://galaxy.ansible.com/f5networks/f5_beacon)
        - [F5Networks/f5-beacon](https://github.com/F5Networks/f5-beacon)
    - netbox
        - [Ansible Galaxy](https://galaxy.ansible.com/netbox/netbox)
        - [netbox-community/ansible_modules: Netbox modules for Ansible using Ansible Collections](https://github.com/netbox-community/ansible_modules)
    - VMware
        - [Ansible Galaxy](https://galaxy.ansible.com/community/vmware)
        - [ansible-collections/community.vmware: Ansible Collection for VMWare](https://github.com/ansible-collections/community.vmware)
- Ansibleドキュメント
    - [Developer Guide — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
    - [Ansible module development: getting started — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html)
        - モジュール作成例
    - [Module format and documentation — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html)
        - モジュール作成時の書式やコメントの書き方
    - [Collection Galaxy metadata structure — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html)
        - `galaxy.yml`の書き方
    - [Creating a new collection — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_in_groups.html)
        - 命名規則など。。。ここはもしかするとコントリビュートするための情報かも
    - [Developing collections — Ansible Documentation](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html)
        - コレクションのディレクトリ構造やファイル、`ansible-galaxy`の使い方など、コレクション開発全般
    - [Galaxy Documentation — Ansible Documentation](https://galaxy.ansible.com/docs/)
        - Ansible Galaxyのドキュメント
    - [Sample Ansible setup — Ansible Documentation](https://docs.ansible.com/ansible/latest/user_guide/sample_setup.html)
        - 現verのAnsibleディレクトリ構造など

# 今回の成果物

- [Ansible Galaxy / esxissh - VM operation on ESXi with enabled SSH](https://galaxy.ansible.com/zaki_lknr/esxissh)
- [zaki-lknr/esxissh-ansible: sshを有効にしたESXiでVM操作するAnsibleモジュール](https://github.com/zaki-lknr/esxissh-ansible)