1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ansible で QNAP の qcli系の設定をする

Posted at

QNAPのQTSは、いろんな設定をするのにqcli系のコマンドを使う。qcliを引数なしで実行すると、いろんなコマンドがあることを教えてくれる。

[~] # qcli

  -v  --version,                             display the version of QCLI and exit.
  -h  --help,                                print this help.
  -l  --login,                               login to check authentication.

  qcli_admin,                                admin operations.
  qcli_volume,                               volume operations.
  qcli_pool,                                 pool operations.
  qcli_raid,                                 RAID operations.
  qcli_hdd,                                  HDD operations.
  qcli_cache,                                cache operations.

  qcli_iscsi,                                iSCSI operations.
  qcli_iscsiacl,                             iSCSI ACL operations.
  qcli_iscsibackup,                          iSCSI backup operations.
  qcli_virtualdisk,                          virtual disk operations.

  qcli_power,                                power operations.
  qcli_network,                              network operations.
  qcli_log,                                  log operations.
  qcli_backuprestore,                        backup/restore operations.
  qcli_firmwareupdate,                       firmware update operations.

  qcli_sharedfolder,                         shared folder operations.
  qcli_quota,                                quota operations.

  qcli_networkservice,                       network service operations.
  qcli_encrypt,                              encrypt operations.
  qcli_rsyncserver,                          rsync server operations.
  qcli_timemachine,                          time machine operations.
  qcli_nastonas,                             nas to nas operations.
  qcli_rsync,                                rsync operations.
  qcli_networkrecyclebin,                    network recycle bin operations.
  qcli_timezone,                             time zone operations.
  qcli_domainsecurity,                       domain security operations.
  qcli_users,                                users operations.
  qcli_usergroups,                           usergroups operations.
  qcli_ntp,                                  NTP service operations.
  qcli_hardware,                             hardware operations.
  qcli_systemstatus,                         system status operations.
  qcli_externaldevice,                       external device operations.
  qcli_mysqlserver,                          mysqlserver operations.

  qcli_volumesnapshot,                       volume snapshot operations.
  qcli_iscsisnapshot,                        iSCSI snapshot operations.

  qcli_domaincontroller,                     domain controller operations.

  qcli_snapreplica,                          SnapReplica operations.
  qcli_snapshotvault,                        Snapshot Vault operations.

QCLI 4.4.2 20200413, QNAP Systems, Inc.

これをAnsibleからcommandで叩けば……と思ったけれど、事はそれほど単純ではなかった。

qcli の実行手順

qcli系のコマンドを使うには、いったんログインしなくてはならず、そこで返ってくるSIDを各コマンドで入力しなくてはならない。

[~] # qcli -l user=admin pw=PASSWORD
Authentication success!
sid is 12345678
[~] # qcli_hardware -B sid=12345678
system_operation Disabled
system_events    Disabled

Ansibleのcommandをこの順番で実行して、結果を保存して……とやるよりは、モジュールを作る方が早い(本当にAnsibleのモジュールは簡単なので、whenとかregisterとかいろいろ考えるよりはモジュールの方がいいと思う)。

モジュールを作る

qcli_login でログインして、 qcli でコマンドを実行するようにする。例によって未テスト・ドキュメントなし・詰めは甘い。

qcli_login.py
#!/usr/bin/python

import re

ANSIBLE_METADATA = {
    'metadata_version': '1.1',
    'status': ['preview'],
    'supported_by': 'iwatam'
}

DOCUMENTATION = '''
'''

EXAMPLES = '''
'''

RETURN = '''
'''

from ansible.module_utils.basic import AnsibleModule

def main():
    module = AnsibleModule(
        argument_spec=dict(
            user=dict(type='str',required=False,default='admin'),
            password=dict(type='str',required=False,no_log=True)
        ),
        supports_check_mode=False
    )
    user=module.params['user']
    password=module.params['password']

    rc,out,err=module.run_command(['qcli','-l','user='+user,'pw='+password])
    m=re.search('sid is (\\w+)',out)
    if m is None:
        module.fail_json(msg='Commmand parse error or login failed.',
                         out=out)
    sid=m.groups()[0]

    module.exit_json(changed=False,
                     sid=sid,
                     output=out,
                     ansible_facts=dict(ansible_qcli_sid=sid))

if __name__ == '__main__':
    main()

user と password を渡して実行すると、ログインしてansible_qcli_sidという名前でfactとしてsidを格納する。必ずChanged=Falseで返る。

qcli.py
#!/usr/bin/python

import re

ANSIBLE_METADATA = {
    'metadata_version': '1.1',
    'status': ['preview'],
    'supported_by': 'iwatam'
}

DOCUMENTATION = '''
'''

EXAMPLES = '''
'''

RETURN = '''
'''

from ansible.module_utils.basic import AnsibleModule

def main():
    module = AnsibleModule(
        argument_spec=dict(
            query_cmd=dict(type='str',required=True),
            expects=dict(type='str',required=True),
            modify_cmd=dict(type='str',required=True),
            sid=dict(type='str',required=False)
        ),
        supports_check_mode=False
    )
    query_cmd=module.params['query_cmd']
    expects=module.params['expects']
    modify_cmd=module.params['modify_cmd']
    sid=module.params['sid']
    sidopt=" sid="+sid
    rc, out, err=module.run_command(query_cmd+sidopt,check_rc=True)
    changed=False
    if not re.fullmatch(expects,out):
        rc, out2, err=module.run_command(modify_cmd+sidopt,check_rc=True)
        changed=True
    module.exit_json(changed=changed,
                     sid=sid,
                     original_output=out,
                     ansible_facts=dict(ansible_qcli_sid=sid),
                     output='')

if __name__ == '__main__':
    main()

query_cmd, expects, modify_cmd, sid の4つを指定する。最初にquery_cmdを(後ろにsid=XXXXを付けて)実行して、その結果がexpectsで指定した正規表現と完全にマッチするならOK、しないならmodify_cmdを実行する。

Ansible のplaybookは以下のようになる。

- name: login to qcli
  qcli_login:
      password: "{{ password }}"

- name: add user
  qcli:
    query_cmd: "qcli_users -c username=iwatam"
    expects: 'User\s+name\s+exist!\s*'
    modify_cmd: "qcli_users -a username=iwatam password=PASSWORD passwordVerify=PASSWORD"
    sid: "{{ ansible_qcli_sid }}"

個人的なヤツなので、passwordが平文で書かれるのがどうとか面倒くさいことは言わない。

イケてないところ

  • いちいちsidを渡さないといけない。(モジュール呼び出しの間で値を共有する機構を発見できなかった)
  • passwordが平文で書かれるのはどうなのか
  • コマンドごとにモジュールを作るのが一番カッコイイんだろうけど、個人でやるには面倒すぎる。
  • というか、そういうモジュールは既にあるんじゃないかと思うんだけど。
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?