【Ansible】CentOS 6 用「(libselinux-python) aren't installed!」解決 Playbook

皆様こんにちは。
つけ麺とパスタが発作的に食べたくなる システムソリューション部所属の なか です。

手動で管理していた CentOS 6 環境を Ansible で更新・変更しようとした時、「(libselinux-python) aren't installed!というエラーが発生しやすいです。

このエラーは手動で対応する事も多いかと思います。

ただ「数が多くて Ansible で管理したいのに、その前に全台手動で対応する必要がある」というのは手間ですよね。

であれば「それも Ansible で解決したら楽だよね」と考え、 Playbook を書きました。

今回は「 CentOS 6 用「(libselinux-python) aren't installed!」解決Playbook」を紹介&解説する内容となります。

前置き

  • CentOS 6 での運用を推奨している訳ではございません。
    あくまでもやむを得ない理由で存在する、CentOS 6 への応急対応用となります。
  • サポートがなくなったバージョンを利用しています。
    こちらも応急対応用であり、推奨する意図はございません。

基本的な原因

(libselinux-python) aren't installed!

ファイル操作といった変更のかかるモジュールを使用した際に、

  • ターゲット側の SELinux が完全に無効化されていない状態
  • かつ(※1) libselinux-python パッケージが入っていない(※2)

場合に発生するエラーです。

※1. SELinux が無効化されている場合は、このエラーは発生しません。
※2. Ansible は Python で動いているため、その Python が SELinux の操作を行うために必要な物。
※ Python 3 の場合は「python3-libselinux」ですが、 CentOS 6 向けには一般的に提供されていない模様です。

手動での解決法

# sudo yum install libselinux-python

「libselinux-python」をターゲット側に入れれば、基本的には解消されます。

※ Python 3 の場合は「python3-libselinux」

ただし、 CentOS 6 は EOL のため リポジトリがデフォルトのままだと yum が使えない可能性が高いです。

そうなると利用可能なリポジトリから、wget & rpm でローカルインストールを行う必要があります。

そのため、複数環境で手動対応は割と大変です。

Q. なぜ Playbook で変更させるの?

A.  Ansible で作業を行いたいのに、事前に手動作業をするのは面倒……という理由だけでなく
「手動が必要なら全部手動でやるか」となりやすいので、本末転倒になるのを防ぐためです。

ですので、「 Ansible で安定的に出来ることは積極的にそっちに寄せていきたい」というスタンスです。

Q. CentOS 7 には対応させないの?

A. バージョン差異対応は Playbook を分け、 include/import の段階で、判定 / 分岐させる方がスマートかなという考えです。

対応させるか悩みましたが、既に「yum」が使えない場合の分岐が含まれていて、少々複雑化しています。

リポジトリがOSバージョンによって、ディレクトリ階層名が変わる事があるため、更に分岐が増えます。

一つの Playbook 内でバージョン分岐を作ると、可読性と保守性が落ちると判断したため含めませんでした。

実行環境

■ Linux 環境
OS :AlmaLinux release 8.5(WSL2環境)
Shell:Bash
Docker :26.1.0, build 9714adc

■ Ansible 環境(WSL2内Dockerコンテナ)
OS:AlmaLinux release 8.9
Ansible:Ansible-core 2.12.10

■ Windows 環境
OS :Windows11 Pro(バージョン:23H2)
言語設定 :日本語に変更

■ CentOS 6 環境(Vagrant + VirtualBox)
OS: CentOS 6.9(bento / centos-6.9)
Vagrant :2.4.1
VirtualBox :7.0.18 r162988(Qt5.15.2)
IP :192.168.33.15

Ansible 2.12 環境の構築手順

CentOS 6 環境は Python のバージョンが古い事が基本のため、 Ansible は対応した旧バージョン(2.12)を利用します。

前々回の記事にて、 Ansible 2.12 の構築方法を解説しましたので、こちらをご参考ください。

【Ansible 2.12】CentOS 6用のAnsible実行環境を、WSL2内のDockerで構築

Playbook

CentOS 6 環境へ Playbook を実行する際、「一番最初に include/import しておけば、エラーを起こさずに実行できるという予防的に利用する事を意識した内容になっています。

※ 勿論、エラーが出てから事後的に、この Playbook を利用する事でも解決する事は可能です。

libselinux-python_wget.yml

main.yml 側で import_tasks 使って、この Playbook を読み込む形式です。
(筆者が再利用性・可読性・保守性を高めるために、役割事に Playbook を分けたい派のため)

---
## 変数default
#  wget_repo | default ("http://ftp.iij.ad.jp/pub/linux/centos-vault")
  - name: Check SELinux
    ansible.builtin.command:
      cmd: getenforce
    register: SELinux_result
  - ansible.builtin.debug:
      var: SELinux_result.stdout

  - name: Check libeselinux-python
    ansible.builtin.shell:
      cmd: rpm -aq | grep libselinux-python
    register: rpm_result
    ignore_errors: yes
  - ansible.builtin.debug:
      var: rpm_result.stdout

    # SELinuxがdisabledであれば、追加なしでAnsibleは実行可能なため実行しない
    # 合わせて、libselinux-python が既に導入されていれば実行しない
  - name: yum install libselinux-python
    ansible.builtin.yum:
      name: libselinux-python
      state: present
    register: yum_libselinux_result
    ignore_errors: yes
    when: not ( SELinux_result.stdout is search("disabled") ) and
          not ( rpm_result.stdout is search("libselinux-python*"))

    # yumでのインストールが失敗に終わった場合、wgetで導入する
  - name: Setup libselinux-python
    when: yum_libselinux_result is failed and
          not ( rpm_result.stdout is search("libselinux-python*"))
    block:
      # バージョン差異によって、パッケージ名も変わるためPackage一覧のHTMLを変数に格納
     -name: Get OS_version Packages
      ansible.builtin.uri:
      url: "{{ wget_repo | default('http://ftp.iij.ad.jp/pub/linux/centos-vault') }}/{{ ansible_distribution_version }}/os/x86_64/Packages/"
        method: GET
        return_content: yes
        register: packages_content

      # HTMLの中から「libselinux-python」のrpm名を取得
    - name: Extract rpm_name
      ansible.builtin.set_fact:
        rpm_name: "{{ packages_content.content | regex_search('libselinux-python-(.*?)\\.x86_64\\.rpm') }}"
    - ansible.builtin.debug:
        var: rpm_name

      # 取得したrpm名でダウンロード
    - name: Download libselinux-python
      ansible.builtin.get_url:
        url: "{{ wget_repo | default('http://ftp.iij.ad.jp/pub/linux/centos-vault') }}/{{ ansible_distribution_version }}/os/x86_64/Packages/{{ rpm_name }}"
        dest: "/tmp/{{ rpm_name }}"

      # yumが使えない状況用のため、rpmでインストール
    - name: Install libselinux-python
      ansible.builtin.command: rpm -ivh /tmp/"{{ rpm_name }}"

意図は大体コメントに書いてますが、下記でも説明いたします。

#  wget_repo:| default ("http://ftp.iij.ad.jp/pub/linux/centos-vault")

yum が使えない場合、直接リポジトリから libselinux-python を取得します。

その際に利用するリポジトリを変数で指定していますが、指定がない場合は、IIJ社の物を利用している事を最初にコメントで明記しています。

- name:Check SELinux
- name:Check libeselinux-python

SELinux が無効化されている環境では、「libselinux-python」無しで稼働するので不要です。
まずは状態を確認してから判定用の変数に入れています。

また、CentOS 6 が yum が使えない状態を考慮して、Shellモジュールから rpm を使ったインストール済かの確認を行います。
こちらも判定用に変数に保存しています。

- name:yum install libselinux-python

SELinux の状態が「disabled」以外かつ、「libselinux-python」がインストールされていない場合に実行します。

yum モジュールでインストールを試み、導入 or 既にインストール済となればOK。

「yum」が使えずに失敗した場合は「ignore_errors: yes」で続行しつつ、タスクが失敗した事を判定用の変数に入れ、以降のタスクで直接リポジトリから取得を試みます。

- name:Setup libselinux-python
when:yum_libselinux_result is failed
block:

「yum」でのインストールに失敗した場合に実行(when条件)。
直接リポジトリからパッケージを取得して、rpmでインストールするためのタスク群(Block)です。

まずは、 ansible_facts の「ansible_distribution_version」を利用して、OSのマイナーバージョンに一致したリポジトリのディレクトリ階層から、「libselinux-python」の正式なパッケージ名を取得し変数に保存。

その後、その変数を使って get_uri モジュールでダウンロードを行い、 command モジュール経由の rpm でローカルインストールを行います。

実行例

検証環境用インベントリファイル

CentOS 6(bento / centos-6.9) のデフォルトがパスワード認証だった事もありますが、パスワード認証(非推奨です)の環境は存在しうるため、今回はこの状態で検証。

--
all:
  vars:
    ansible_user: vagrant
  hosts:
    targetnode:
      ansible_host: 192.168.33.15
      ansible_ssh_pass: vagrant

main.yml

main.yml 側でタスクは記述せず、 import_tasks で Playbook を読み込ませる書き方にしています。
(筆者が再利用性・可読性・保守性を高めるために、役割事に Playbook を分けたい派のため)

- name: libselinux-python
  hosts: targetnode<
  become: yes
  vars:
    wget_repo: "http://ftp.iij.ad.jp/pub/linux/centos-vault"

  tasks
   - name: Include libeselinux-python(wget)
      ansible.builtin.import_tasks: libselinux-python_wget.yml

Playbook 実行

記事においては、以前の Ansible バージョンを搭載したコンテナ上から実行させます。

[root@筆者コンテナ環境 work]# ansible-playbook -i hosts main.yml

最後に

手間は掛かりますが、定型化できる作業を Ansible に落とし込んでみました。
以降は何度も再利用できますし、 Ansible に慣れていく意味でも勉強になったので良かったです。

CentOS 6 環境は「yum」が使えない確率も高く、 Ansible 導入のハードルが高くなりがちなので
この記事を読んだ方に、多少でも Ansible を触るキッカケや役に立つ知識 / 情報となれれば幸いです。

ここまで読んで頂きありがとうございました!

参考資料

ansible.builtin.yum module – Manages packages with the yum package manager
https://docs.ansible.com/ansible/9/collections/ansible/builtin/yum_module.html

8.6. SELinux
https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/considerations_in_adopting_rhel_8/selinux_security

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
4
読み込み中...
4 票, 平均: 1.00 / 14
665
X facebook はてなブックマーク pocket

この記事をかいた人

About the author

なか

ビヨンドに中途入社
システムソリューション部所属
LPIC-3 304とAWS SAAを一応は持っています