彩り

私の作業が誰かの役に立つといいな。IT系のTech記事中心です。

Ansible Galaxy をローカルに構築してみる

はじめに

Ansible Collection用のモジュールを作成後、
・きちんとAnsible Galaxyのサイトにアップできるのかどうか
・アップしたファイルの内容を事前に確認したい

という目的で、社内環境にAnsible Galaxy を構築してみました。
参考にさせて頂いたサイトや構築時にハマった事などを共有したいと思います。

参考にさせて頂いた情報

ちょうど作業しているタイミングでRed Hat Tech Night というイベントがありまして、その中でAnsible Galaxy NGの構築手順のLTがあったので大変助かりました。

第4回 Red Hat Tech Night online 2021.1.14 - connpass

www2.slideshare.net

あとは、公式ドキュメント

https://www2.slideshare.net/h-saito/getting-started-ansible-galaxy-ng-241322669 galaxy.ansible.com

Qiitaに公開されている情報

qiita.com

です。

いずれも非常に助けられました。ありがとうございます!

内容

構築した環境

自宅ラボとかないので、社内環境に構築しました。 という事でProxy環境下での構築についてとなります。

OSはCentOS7です

CentOS Linux release 7.9.2009 (Core)

環境変数にProxyはきちんと設定している状態で、きちんと外に出られる状態です。

http_proxy=x.x.x.x:yy
https_proxy=x.x.x.x:yy
HTTP_PROXY=x.x.x.x:yy
HTTPS_PROXY=x.x.x.x:yy

/etc/profile でexportしてます。

Ansible Galaxy NG の構築

RHTNのLT資料を見ても、手順は非常に少なく感じました。
ただ最近は環境構築していると大体Proxy環境下という事でハマるのでそうならないといいなぁと思っていました。思っていました。

インストール環境の準備

ほぼ参考にさせて頂いた資料と同じなので恐縮ですが、、、

Ansibleのインストール

$ sudo yum install ansible
$ rpm -qa | grep ansible
ansible-2.9.16-1.el7.noarch
$ 

必要なコレクションのインストール

$ ansible-galaxy collection install pulp.pulp_installer
$ ansible-galaxy collection install ansible.galaxy_collection

インストール用Playbookの取得

$ git clone https://gist.github.com/629ba52d68301cc9798227b87704df84.git galaxy_ng

pulp_installerに必要なロールの取得

ansible-galaxy install -r ~/.ansible/collections/ansible_collections/pulp/pulp_installer/requirements.yml

インストールに必要なインベントリの作成

$ cat hosts
localhost       ansible_user=xxxx ansible_password=xxxx

[galaxyng]
localhost ansible_connection=local

[galaxyng:vars]
ansible_become=True
$ 

インストール

Ansibleでインストール

$ ansible-playbook enduser-install.yml -i hosts --extra-vars "@upstream-rpm-install-vars.yml" 

多分Proxy環境下でなければこれでインストール完了だと思います。

発生したエラーとその対処

その1

エラー内容

https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 にアクセスしようとしてタイムアウトになったようです。

"msg": "failed to fetch key at https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 , error was: Request failed: <urlopen error timed out>" 

エラー全文

TASK [pulp.pulp_installer.pulp_common : Import required EPEL RPM GPG keys] **************************************************************************************************************************
task path: /home/xxxx/.ansible/collections/ansible_collections/pulp/pulp_installer/roles/pulp_common/tasks/repos.yml:5
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: xxxx
<localhost> EXEC /bin/sh -c 'echo ~xxxx && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/xxxx/.ansible/tmp `"&& mkdir "` echo /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500 `" && echo ansible-tmp-1610628273.4-5587-188770266220500="` echo /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500 `" ) && sleep 0'
Using module file /usr/lib/python2.7/site-packages/ansible/modules/packaging/os/rpm_key.py
<localhost> PUT /home/xxxx/.ansible/tmp/ansible-local-48832fVMST/tmpywBx4d TO /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500/AnsiballZ_rpm_key.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500/ /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500/AnsiballZ_rpm_key.py && sleep 0'
<localhost> EXEC /bin/sh -c 'sudo -H -S -n  -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-iampiogeqfghcybbprtzzmacdrkcshcm ; DJANGO_SETTINGS_MODULE=pulpcore.app.settings /usr/bin/python /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500/AnsiballZ_rpm_key.py'"'"' && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /home/xxxx/.ansible/tmp/ansible-tmp-1610628273.4-5587-188770266220500/ > /dev/null 2>&1 && sleep 0'
fatal: [localhost]: FAILED! => {
    "changed": false, 
    "invocation": {
        "module_args": {
            "fingerprint": null, 
            "key": "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7", 
            "state": "present", 
            "validate_certs": true
        }
    }, 
    "msg": "failed to fetch key at https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 , error was: Request failed: <urlopen error timed out>" 
}

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

$                : ok=39   changed=0    unreachable=0    failed=1    skipped=11   rescued=0    ignored=0   

対処

外部アクセス時のタイムアウトエラーは大体Proxyが原因という過去の経験より
対象のPlaybookに環境変数でProxyを追記しました。

--- repos.yml.bak       2021-01-14 21:57:41.320812541 +0900
+++ repos.yml   2021-01-14 21:59:39.139805575 +0900
@@ -3,6 +3,9 @@

 - name: Import required EPEL RPM GPG keys
+  environment:
+    http_proxy: x.x.x.x:yyyy
+    https_proxy: x.x.x.x:yyyy
   rpm_key:
     state: present
     key: https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-{{ ansible_facts.distribution_major_version }}

これで先に進みました。

その2

エラー内容
raise IDNAError('The label {0} is not a valid A-label'.format(label))\nidna.core.IDNAError: The label centos7_nedved is not a valid A-label\n", 
    "module_stdout": "", 
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", 
    "rc": 1

エラー全文

TASK [pulp.pulp_installer.pulp_webserver : Generate CA CSR] *******************************************************************************************************************************************************************************
task path: /home/xxxx/.ansible/collections/ansible_collections/pulp/pulp_installer/roles/pulp_webserver/tasks/generate_tls_certificates.yml:21
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: xxxx
<localhost> EXEC /bin/sh -c 'echo ~xxxx && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/xxxx/.ansible/tmp `"&& mkdir "` echo /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601 `" && echo ansible-tmp-1610629541.8-18196-180460235469601="` echo /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601 `" ) && sleep 0'
Using module file /usr/lib/python2.7/site-packages/ansible/modules/crypto/openssl_csr.py
<localhost> PUT /home/xxxx/.ansible/tmp/ansible-local-14498dKbVFf/tmp86hqnb TO /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/ /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py && sleep 0'
<localhost> EXEC /bin/sh -c 'sudo -H -S -n  -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-rxtnhhscpjnhifwlnurttrvekxivqilc ; DJANGO_SETTINGS_MODULE=pulpcore.app.settings /usr/bin/python /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py'"'"' && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py", line 102, in <module>
    _ansiballz_main()
  File "/home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py", line 94, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py", line 40, in invoke_module
    runpy.run_module(mod_name='ansible.modules.crypto.openssl_csr', init_globals=None, run_name='__main__', alter_sys=True)
  File "/usr/lib64/python2.7/runpy.py", line 176, in run_module
    fname, loader, pkg_name)
  File "/usr/lib64/python2.7/runpy.py", line 82, in _run_module_code
    mod_name, mod_fname, mod_loader, pkg_name)
  File "/usr/lib64/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py", line 1105, in <module>
  File "/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py", line 1088, in main
  File "/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py", line 541, in generate
  File "/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py", line 834, in _generate_csr
  File "/usr/lib64/python2.7/site-packages/cryptography/x509/base.py", line 393, in sign
    return backend.create_x509_csr(self, private_key, algorithm)
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/multibackend.py", line 395, in create_x509_csr
    return b.create_x509_csr(builder, private_key, algorithm)
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 793, in create_x509_csr
    gc=False
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1009, in _create_x509_extensions
    handlers, extension
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1040, in _create_x509_extension
    ext_struct = encode(self, extension.value)
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py", line 359, in _encode_alt_name
    general_names = _encode_general_names(backend, san)
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py", line 351, in _encode_general_names
    gn = _encode_general_name(backend, name)
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py", line 387, in _encode_general_name
    value = _idna_encode(name.value)
  File "/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py", line 376, in _idna_encode
    return idna.encode(value)
  File "/usr/lib/python2.7/site-packages/idna/core.py", line 355, in encode
    result.append(alabel(label))
  File "/usr/lib/python2.7/site-packages/idna/core.py", line 265, in alabel
    raise IDNAError('The label {0} is not a valid A-label'.format(label))
idna.core.IDNAError: The label centos7_nedved is not a valid A-label
fatal: [localhost]: FAILED! => {
    "changed": false, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/xxxx/.ansible/tmp/ansible-tmp-1610629541.8-18196-180460235469601/AnsiballZ_openssl_csr.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible.modules.crypto.openssl_csr', init_globals=None, run_name='__main__', alter_sys=True)\n  File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\n    fname, loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\n    mod_name, mod_fname, mod_loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\n    exec code in run_globals\n  File \"/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py\", line 1105, in <module>\n  File \"/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py\", line 1088, in main\n  File \"/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py\", line 541, in generate\n  File \"/tmp/ansible_openssl_csr_payload_XSwXCN/ansible_openssl_csr_payload.zip/ansible/modules/crypto/openssl_csr.py\", line 834, in _generate_csr\n  File \"/usr/lib64/python2.7/site-packages/cryptography/x509/base.py\", line 393, in sign\n    return backend.create_x509_csr(self, private_key, algorithm)\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/multibackend.py\", line 395, in create_x509_csr\n    return b.create_x509_csr(builder, private_key, algorithm)\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py\", line 793, in create_x509_csr\n    gc=False\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py\", line 1009, in _create_x509_extensions\n    handlers, extension\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py\", line 1040, in _create_x509_extension\n    ext_struct = encode(self, extension.value)\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py\", line 359, in _encode_alt_name\n    general_names = _encode_general_names(backend, san)\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py\", line 351, in _encode_general_names\n    gn = _encode_general_name(backend, name)\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py\", line 387, in _encode_general_name\n    value = _idna_encode(name.value)\n  File \"/usr/lib64/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py\", line 376, in _idna_encode\n    return idna.encode(value)\n  File \"/usr/lib/python2.7/site-packages/idna/core.py\", line 355, in encode\n    result.append(alabel(label))\n  File \"/usr/lib/python2.7/site-packages/idna/core.py\", line 265, in alabel\n    raise IDNAError('The label {0} is not a valid A-label'.format(label))\nidna.core.IDNAError: The label centos7_nedved is not a valid A-label\n", 
    "module_stdout": "", 
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", 
    "rc": 1
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************************
localhost                  : ok=96   changed=32   unreachable=0    failed=1    skipped=38   rescued=0    ignored=0   

$ 

対処

centos7_nedvedというホスト名つけていたのですが、これが怒られていたみたいです。
特に他と連携しているサーバでもないので 素直にホスト名変更nedvedにしましたらサクッといきました。
アンダーバーがいけなかったのかも。。。

という事で

2つの対処で無事Playbookが全て通りました!

PLAY RECAP *******************************************************************************************************
localhost                  : ok=131  changed=30   unreachable=0    failed=0    skipped=43   rescued=0    ignored=0   

$ 

残すは

パッチ

/usr/lib/python3.6/site-packages/pulp_ansible/app/tasks/collections.py

--- collections.py.bak  2021-01-14 22:35:39.746677840 +0900
+++ collections.py      2021-01-14 22:38:41.434667099 +0900
@@ -243,6 +243,9 @@
         collection_version.is_highest = True
         last_highest.save()
         collection_version.save()
+    elif collection_version.is_highest and collection_version.version != last_highest.version:
+        collection_version.is_highest = False
+        collection_versioon_version.save()

 class AnsibleDeclarativeVersion(DeclarativeVersion):
@@ -585,7 +588,9 @@
                 continue
             collection_version = d_content.content
             docs_blob = d_content.extra_data.get("docs_blob", {})
+            if docs_blob:
+                collection_version.docs_blob = docs_blob

             for d_artifact in d_content.d_artifacts:
                 artifact = d_artifact.artifact

設定変更

/etc/pulp/settings.py

--- settings.py.bak     2021-01-14 22:41:13.378658116 +0900
+++ settings.py 2021-01-14 22:42:58.241651916 +0900
@@ -3,9 +3,11 @@
 X_PULP_API_PREFIX = "pulp_ansible/galaxy/automation-hub/api" 
 X_PULP_API_HOST = "127.0.0.1" 
 GALAXY_REQUIRE_CONTENT_APPROVAL = False
-TOKEN_SERVER = "https://nedved/token" 
+TOKEN_SERVER = "https://x.x.x.x/galaxy/token" 
 X_PULP_API_PORT = 24817
-CONTENT_ORIGIN = "https://localhost" 
+CONTENT_ORIGIN = "https://x.x.x.x" 
 DATABASES = {"default": {"ENGINE": "django.db.backends.postgresql", "HOST": "localhost", "PASSWORD": "pulp", "NAME": "pulp", "USER": "pulp"}}
 PRIVATE_KEY_PATH = "/etc/pulp/certs/token_private_key.pem" 
 X_PULP_API_PASSWORD = "password" 

ホスト名はDNS設定している訳ではなかったのでIP直接に変更

サービスリスタート

# systemctl restart pulpcore-worker@1
# systemctl restart pulpcore-worker@2
# systemctl restart pulpcore-resource-manager
# systemctl restart pulpcore-content
# systemctl restart pulpcore-api

アクセス

https://x.x.x.x
IDパスワードは変更していなければ デフォルト値(admin/password)でアクセス

f:id:naka-shin1:20210115215231j:plain
Ansible Galaxy NG のログイン画面

お疲れ様でした。

おまけ

Ansible Private Galaxy(旧)の構築

これですね。

github.com

https://github.com/ansible/galaxy/blob/devel/CONTRIBUTING.rst

当初、さいとうさんの LT資料でいう Ansible Private Galaxy(旧)を構築していました。 ただ、コンテナなのでデータ部分をローカルに保存するように変更しないとなぁ、、、と思っていました。

こちらは Galaxy NG とは違って、Dockerコンテナで構築する手順となっています。

参考:構築手順

qiita.com

こちらでも大変お世話になりました。

エラー内容

Step 11/22 : RUN curl -sL -o '/tmp/nodesource-release-el7-1.noarch.rpm'         'https://rpm.nodesource.com/pub_8.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'     && rpm -i --nosignature --force '/tmp/nodesource-release-el7-1.noarch.rpm'     && rm -f '/tmp/nodesource-release-el7-1.noarch.rpm'     && curl -sL -o '/etc/yum.repos.d/yarn.repo' 'https://dl.yarnpkg.com/rpm/yarn.repo'     && yum -y install nodejs yarn     && yum -y clean all     && rm -rf /var/cache/yum
 ---> Running in 8a7b06b0715f
The command '/bin/sh -c curl -sL -o '/tmp/nodesource-release-el7-1.noarch.rpm'         'https://rpm.nodesource.com/pub_8.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'     && rpm -i --nosignature --force '/tmp/nodesource-release-el7-1.noarch.rpm'     && rm -f '/tmp/nodesource-release-el7-1.noarch.rpm'     && curl -sL -o '/etc/yum.repos.d/yarn.repo' 'https://dl.yarnpkg.com/rpm/yarn.repo'     && yum -y install nodejs yarn     && yum -y clean all     && rm -rf /var/cache/yum' returned a non-zero code: 6
make: *** [build/docker-dev] エラー 6

docker自体にProxy設定はしていたのですが、インストール時に構築されるcentos7のコンテナがcurlyumを実行する際にProxy設定が必要なのでエラーとなっているようです。

対処

galaxy/scripts/docker/dev/Dockerfile

に直接環境変数でプロキシ設定を埋め込みました

FROM centos:7

ENV HTTP_PROXY http://x.x.x.x:yyyy  <--- 追記
ENV HTTPS_PROXY http://x.x.x.x:yyyy <--- 追記
ENV http_proxy http://x.x.x.x:yyyy  <--- 追記
ENV https_proxy http://x.x.x.x:yyyy <--- 追記

ENV LANG en_US.UTF-8

これでうまくいきました。

おまけ2

久々にブログ書きました。
普段はRedmineに色々と情報を残しているのですが、今年は少しずつブログで公開してみたいと思います。
今週『アウトプットしないのは知的な便秘』ってTLにも流れていましたね。
何か書くきっかけが欲しかったのでツイッタで呟いてみるのは とっても大事ですね(爆)

ちなみに nedvedは好きなサッカー選手の名前です。

謝辞

@ussvgrさん、@saito_hidekiさん
非常に参考にさせて頂きました、ありがとうございました。