Ansible playbook to install NCPA agent on Windows - ansible

I am trying to install Nagios NCPA agent on Windows using Ansible play book. Here is my simple playbook
- name: Install NCPA
win_package:
path: https://assets.nagios.com/downloads/ncpa/ncpa-2.1.4.exe
- name: Copy the ncpa.cfg template
win_template:
src: ncpa.cfg.j2
dest: 'C:\Program Files (x86)\Nagios\NCPA\etc\ncpa.cfg'
- name: Restart NCPA
win_service:
name: ncpapassive
state: restarted
However I am getting the below error:
"msg": "product_id is required when the path is not an MSI or the path is an MSI but not local",
How to I find out the product_id for ncpa?

You can skip product_id if you add any of creates_* arguments to your first task, for example:
creates_path: C:\Program Files (x86)\Nagios\NCPA\___main_executable_file__.exe
Or you can search on a machine with your package istalled; per win_package manual:
product_id [ ]
You can find product ids for installed programs in the Windows registry editor either at HKLM:Software\Microsoft\Windows\CurrentVersion\Uninstall or for 32 bit programs at HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall.
This SHOULD be set when the package is not an MSI, or the path is a url or a network share and credential delegation is not being used. The creates_* options can be used instead but is not recommended.

Finally managed to make it work with a dummy product ID.
- name: Create download directory
win_file:
path: C:\\Temp
state: directory
- name: Copy the executable package to download directory
win_copy:
src: ncpa-2.1.4.exe
dest: 'C:\Temp\ncpa-2.1.4.exe'
#- name: Download NCPA executable
# win_get_url:
# url: https://assets.nagios.com/downloads/ncpa/ncpa-2.1.4.exe
# dest: C:\Temp\ncpa-2.1.4.exe
# force: no
# skip_certificate_validation: yes
- name: Install NCPA
win_package:
path: 'C:\Temp\ncpa-2.1.4.exe'
arguments: '/S /TOKEN=demo-token'
product_id: '{ncpa}'
ignore_errors: true
register: installmsi
failed_when: "'was installed' not in installmsi.msg"
- name: Copy the ncpa.cfg template
win_template:
src: ncpa.cfg.j2
dest: 'C:\Program Files (x86)\Nagios\NCPA\etc\ncpa.cfg'
- name: Restart NCPA
win_service:
name: ncpapassive
state: restarted

Related

ansible yum remove packages on first run, not on all after

I'm attempting to uninstall a list of packages from our RHEL servers. However, I need to account for servers where these packages to uninstall are needed for the application. An good example of this is httpd, which is listed on our uninstall list, but it is an dependency for the application running on the server. Basically I'm managing two states with one playbook.
So here is the list of packages to remove, which is in the role's defaults/main.yml
packagesRemove:
- telnet
- nfs
- nfs-server
- nfs-utils
- named
- httpd
- rsync
- postfix
- autofs
- cups
- smb
- squid
Currently, I'm doing something basic to uninstall the packages on the first run.
- name: Check for packageRemove file
stat:
path: /root/packageRemove.txt
register: stat_result
- name: remove packages not needed
yum:
name: "{{ packagesRemove }}"
autoremove: yes
register: packageRemove_output
when: not stat_result.stat.exists
- name: create packageRemove file
template:
src: output.txt.j2
dest: /root/packageRemove.txt
owner: root
group: root
mode: 0600
when: not stat_result.stat.exists
Basically if the /root/packageRemove.txt file exits, these tasks just get skipped. How can I make this more dynamic, and remove the need for the /root/packageRemove.txt file. I would like to make the packages that are needed into some sort of inventory variables.
Right now, I just have the following to gather a list of packages installed on the server.
- name: gather installed packages
dnf:
list: installed
no_log: true
register: yum_packages
- name: make installed packages a list
set_fact:
installed_packages: "{{ yum_packages.results | map(attribute='name') | list }}"
This is now where I'm stumped, and I'm not quite sure what my next step should be or if I'm on the right track. Any help would be great.

Packer Ansible provisioner is skipping tasks in Ansible playbook

I am using the Packer Ansible provisioner in a JSON file to download a zip file from the web that contains a program and have that program run at startup by editing the Windows Registry using the win_regedit Ansible module:
---
- hosts: default
tasks:
- name: Create Bginfo Directory
win_file:
path: C:\Bginfo
state: directory
- name: Download BgInfo64.zip
win_get_url:
url: https://download.sysinternals.com/files/BGInfo.zip
dest: C:\Bginfo\BgInfo64.zip
- name: Unzip BgInfo64.zip
win_unzip:
src: C:\Bginfo\BgInfo64.zip
dest: C:\Bginfo
delete_archive: true
- name: Run Bginfo at startup
win_regedit:
key: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
name: Bginfo
data: C:\Bginfo\Bginfo64.exe C:\BgInfo\default.bgi /timer:0 /nolicprompt
type: string
When I check the machine, the registry edits were not made and the archive is not deleted after un-zipping.
As per the logs, win_regedit is using module file Using module file /opt/ansible/ansible/lib/ansible/modules/windows/win_regedit.ps1
win_unzip is using /opt/ansible/ansible/lib/ansible/modules/windows/win_unzip.ps1
I looked up the PowerShell files online and everything I'm doing seems legal by Ansible standards so I'm unsure why those tasks are not completed.

how could I install a snap package via Ansible on an air-gapped system

Installing snap packages via Ansible on systems that are connected to internet is rather simple. EG:
- name: Install microk8s
become: yes
snap:
name: microk8s
classic: yes
channel: "{{ microk8s_version }}"
Now I would need to do the same on a set of nodes that are air-gapped (no direct connection to internet).
I can do a 'snap download' for the required packages, and move them to the target machine(s).
But then how to do this in Ansible? Is there any support for this? Or do I have to use the shell/command module ?
thx
I have not tested this, but this method works with other modules.
- name: install microk8s, file on local disk
become: yes
snap:
name: /path/to/file
using the hint of #Kevin C I was able to solve the problem using the following playbook
- name: copy microk8s snap to remote
copy:
src: "{{ item }}"
dest: "~/microk8s/"
remote_src: no
with_fileglob:
- "../files/microk8s/*"
- name: snap ack the new package
become: yes
shell: |
snap ack ~/microk8s/microk8s_1910.assert
snap ack ~/microk8s/core_10583.assert
- name: install microk8s, file on local disk
become: yes
snap:
name: "~/microk8s/core_10583.snap"
- name: install microk8s, file on local disk
become: yes
snap:
name: "~/microk8s/microk8s_1910.snap"
classic: yes
I hope this helps others also.
Would be nice to see this documented.
If you can get the packages onto the Ansible server, the following code will copy the file to the target(s). Something like the the following code should work.
- name: copy files/local/microk8s.deb
copy:
src: "files/local/microk8s.deb"
dest: "~/microk8s.deb"
remote_src: no
Where files/ is at the same level as the playbook.

Ansible: Handling temporary file idempotently and securely

In Ansible (RHEL 8 if it matters), I need to create a temporary file from a template with sensitive content. After a few other tasks are completed, it should be deleted. The temporary file is an answerfile for an installer that will run as a command. The installer needs a user name and password.
I can't figure out if there is a way to do this easily in Ansible.
The brute-force implementation of what I'm looking for would look similar to this:
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
creates: /somewhereelse/installedprogram
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
Of course, this code is not idempotent - the answer file would get created and destroyed on each run.
Is there a better way to do this?
Test the existence of the file. If it exists skip the block. For example
- stat:
path: /somewhereelse/installedprogram
register: st
- block:
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
when: not st.stat.exists
(not tested)
Taking the task "Delete answerfile" out of the block will make the code more secure. It will always make sure the credentials are not stored in the file. The task won't fail if the file is not present.
- stat:
path: /somewhereelse/installedprogram
register: st
- block:
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
when: not st.stat.exists
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
(not tested)
I think that this solution potentially represents a slight improvement on your solution.
With this solution the tasks which create and delete the answerfile will be skipped (rather than always run and reporting changed) if the program you're targeting is already installed.
I still don't love this solution as I don't really like skips.
# Try call the installedprogram. --version is arbitrary here.
# --help, or a simple `which installedprogram` could be alternatives.
- name: Try run installedprogram
command: '/somewhereelse/installedprogram --version'
register: installedprogram_exists
ignore_errors: yes
changed_when: False
# Only create answer file if installedprogram is not installed
- name: Create answer file
template:
src: answerfile.xml.j2
dest: /somewhere/answer.xml
owner: root
group: root
mode: '0600'
when: installedprogram_exists.rc != 0
- name: Install
command: /somewhere/myinstaller --answerfile /somewhere/answer.xml
creates: /somewhereelse/installedprogram
# Only delete answer file if installedprogram is not installed
- name: Delete answerfile
file:
path: /somewhere/answer.xml
state: absent
when: installedprogram_exists.rc != 0

Install rpm after copy, with ansible

I have an ansible playbook which will copy a file into a location on a remote server. It works fine. In this case, the file is an rpm. This is the way it works:
---
- hosts: my_host
tasks:
- name: mkdir /tmp/RPMS
file: path=/tmp/RPMS state=directory
- name: copy RPMs to /tmp/RPMS
copy:
src: "{{ item }}"
dest: /tmp/RPMS
mode: 0755
with_items:
[any_rpm-x86_64.rpm]
register: rpms_copied
Now, with the file successfully on the remote server, I need to start some new logic that will install the rpm that sits in /tmp/RPMS. I have run many different versions of the below (So this code is added onto the above block):
- name: install rpm from file
yum:
name: /tmp/RPMS/any_rpm-x86_64.rpm
state: present
become: true
I don't know if the formatting is incorrect, or if this is not the way. Can anyone advise as to how I can get the rpm in the directory /tmp/RPMS installed using a new few lines in the existing playbook?
Thanks.
I did not find this anywhere else, and it genuinely took me all of my working day to get to this point. For anyone else struggling:
- name: Install my package from a file on server
shell: rpm -ivh /tmp/RPMS/*.rpm
async: 1800
poll: 0
become_method: sudo
become: yes
become_user: root

Resources