Skip package download if already installed - ansible

I am using ansible to install a deb package and I do not want to download the remote file if the package is already installed. Currently I am doing like this:
- name: Check if elasticsearch installed
become: true
stat: path=/etc/elasticsearch/elasticsearch.yml
register: st
- name: Install elasticsearch
become: yes
apt:
deb: https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.12.deb
update_cache: true
state: present
when: not st.stat.exists
Is there a better way to skip the download of the deb package if it is already installed?

You'll want package_facts or, of course, to just cheat and shell out something like command: dpkg --search elasticsearch
- name: gather installed packages
package_facts:
- name: Install elasticsearch
when: elasticsearch not in ansible_facts.packages
Unless your question is about how to do that when elasticsearch might have been installed by hand, and not through dpkg, in which case your stat: and register: approach is a sensible one. You may even want to use a with_items: to check a few places the file might have been installed, depending on your circumstance

Related

Static URL that always links to the latest Go binaries? [duplicate]

Is there is a permanent URL that points to current latest linux binary release of Go?
I am writing an ansible script which should download the latest Go release and install it. In the Go download site "https://golang.org/dl/" I could see only release specific download links.
I am wondering if there a link like "https://dl.google.com/go/latest.linux-amd64.tar.gz" available?
If not any suggestion on how to script fetching the latest golang version and install it?
You can download the latest stable Go version in one go :)
wget "https://dl.google.com/go/$(curl https://golang.org/VERSION?m=text).linux-amd64.tar.gz"
You can generate the latest url with :
https://dl.google.com/go{{ version }}.{{ os }}-{{ arch }}.tar.gz
os: linux, darwin, windows, freebsd
arch: amd64, 386, armv6l, arm64, s390, ppc64le
and for the latest stable version you can fetch the value with curl or something else from the url :
https://golang.org/VERSION?m=text
Here is an ansible playbook as an example :
---
- hosts: server
gather_facts: no
vars:
version : "latest"
arch: arm64
os: linux
latest_version_url: https://golang.org/VERSION?m=text
archive_name: "{{ filename_prefix }}.{{ os }}-{{ arch }}.tar.gz"
download_url: https://dl.google.com/go/{{ archive_name }}
bin_path: /usr/local/go/bin
tasks:
- name: Get filename prefix with latest version
set_fact:
filename_prefix: "{{ lookup('url', latest_version_url, split_lines=False) }}"
when: version == "latest"
- name: Get filename prefix with fixed version
set_fact:
filename_prefix: go{{ version }}
when: version != "latest"
- name: Try to get current go version installed
command: go version
register: result
changed_when: false
- name: Set current_version var to the current
set_fact:
current_version: "{{ result.stdout.split(' ')[2] }}"
when: result.failed == false
- name: Set current_version var to none
set_fact:
current_version: "none"
when: result.failed == true
- debug:
var: current_version
- name: Download and extract the archive {{ archive_name }}
become: true
unarchive:
src: "{{ download_url }}"
dest: /usr/local
remote_src: yes
when: current_version != filename_prefix
As found here, Google has a Linux installer to install Go on linux:
https://storage.googleapis.com/golang/getgo/installer_linux
This installer fetches the latest version of Go and installs it. Seems like this is the easiest way as of now to install the latest go version on Linux.
The newest official method to fetch the file and execute it is:
curl -LO https://get.golang.org/$(uname)/go_installer
chmod +x go_installer
./go_installer
rm go_installer
I use the below for Linux:
wget "https://go.dev/dl/$(curl 'https://go.dev/VERSION?m=text').linux-amd64.tar.gz" && sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go*.linux-amd64.tar.gz
There is also a cross-platform solution built by the Go Community:
curl -LO https://get.golang.org/$(uname)/go_installer && chmod +x go_installer && ./go_installer && rm go_installer
I would suggest to defer to something like jlund/ansible-go, or copy over the parts of that role that you need.

Ansible "apt cache update failed" during postgresql repo install

I'm trying to install postgresql on my remote host using Ansible.
I have 2 solutions, but both work only half as I expect them to work/turn out.
1. Solution one (using Ansible apt_repository module);
- name: Get Postgres latest repository release
become: yes
apt_repository:
repo: deb https://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main
state: present
filename: pgdg.list
This option first looks like it's successful on execution, but eventually gives an error (apt cache update failed):
2. Solution two (use shell module)
- name: Get Postgres latest repository release
become: yes
shell: sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
This accomplishes exactly the same (correct me if I'm wrong) and later gives some other exception (No package matching):
So I'm not getting any further with my playbook, any tips?
My play to install postgresql-13 (or 14):
- name: Install Postgres dependencies (if not installed)
become: yes
apt:
name:
- postgresql-{{ postgres_version }}
- postgresql-doc-{{ postgres_version }}
- postgresql-contrib
- zabbix-sql-scripts
when:
- "not 'postgresql-13' in ansible_facts.packages"
- "not 'postgresql-doc-13' in ansible_facts.packages"
- "not 'postgresql-contrib' in ansible_facts.packages"
- "not 'zabbix-sql-scripts' in ansible_facts.packages"
Repository keys are provided in another play and performs without errors.
This is executed on a host with Ubuntu 20.04LTS, Ansible version 2.9.6, Python version 3.8.10
I have searched for both individual problems but did not find a specific answer that solved my problem.
If if perform the same as Ansible manually, it all installs fine (commands used):
sudo sh -c ‘echo “deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main” > /etc/apt/sources.list.d/pgdg.list’
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install postgresql-13 postgresql-doc-13
Edit:
Seemed I also had a quote (") missing at the start of my repo link (before deb https://...).
I had: repo: deb https://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main"
Should be: "repo: deb https://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main"
Basically, it must be said that an Ansible module, such as apt_repository is generally preferable to the shell module.
However, you have a few mistakes in your approach.
As you can see, apt_repository automatically updates the package sources, i.e. the repository key must already exist. You can add the repository key with the apt_key module, but you need to have the gpg package installed, which you should ensure first.
From this follows:
install gpg
- name: Ensure gpg is installed
apt:
name: gpg
add repository key
- name: Add repository signing key
apt_key:
url: "https://www.postgresql.org/media/keys/ACCC4CF8.asc"
state: present
add repository source
- name: Add postgresql repository
apt_repository:
repo: "deb https://apt.postgresql.org/pub/repos/apt/ {{ ansible_distribution_release }}-pgdg main"
state: present
filename: pgdg
When using apt_repository one of your problems was that you left $(lsb_release -cs) unchanged, but this only works via the shell, instead you have to use the variable ansible_distribution_release when using Ansible. Also, the filename parameter does not need an extension (.list), as the documentation tells you: "The .list extension will be automatically added." Your specification creates the file pgdg.list.list.
Again, as a whole playbook:
- name: Database Server
hosts: databaseserver
become: yes
tasks:
- name: Ensure gpg is installed
apt:
name: gpg
- name: Add repository signing key
apt_key:
url: "https://www.postgresql.org/media/keys/ACCC4CF8.asc"
state: present
- name: Add postgresql repository
apt_repository:
repo: "deb https://apt.postgresql.org/pub/repos/apt/ {{ ansible_distribution_release }}-pgdg main"
state: present
filename: pgdg
Now you should be able to install the desired packages, if they are provided by the included repository.
Maybe this is what cause your problem: answer
Before to add the repository you need to:
Add the APT Key.
Add Repository.
Install Packages.

ansible yum packages displayed in both available and installed result

ansible yum list shows some packages as installed as well available. how this can be fixed. when i try run yum list package-name it displays either as installed/avaiable.
hosts: localhost
vars:
pkgs: [ 'python36', 'python38' ]
tasks:
- name: installed packages
yum:
list: installed
register: installed
- name: available packages
yum:
list: available
register: avlbl
When I see output of both register variable i can see python36 & python38 displayed in both register variable.

How to pass options to dnf when using Ansible

When installing packages through the Ansible's dnf module. How do I pass options like --nobest to dnf? Is there alternative to using raw shell commands.
I had similar problem (but i'm using yum package manager) and figured a work around here
The issue is that docker-ce has not been packaged for CentOS 8 yet.
An ugly workaround is to install containerd.io manually beforehand:
pre_tasks:
- yum:
name: https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
So, try to set full package url as package name and it should definitely work.
nobest can be passed as a parameter while using the DNF module in the playbook
You can refer here dnf_module for other options/parameters that can be passed to the dnf ansible module
For example :
- name: Install the latest version of Apache from the testing repo
dnf:
name: httpd
enablerepo: testing
state: present
- name: Install the latest version of Apache
dnf:
name: httpd
state: present
nobest: false

Ansible: prevent 'changed' when looping

I like this pattern in Ansible:
tasks:
- name: install packages
apt:
name: "{{ item }}"
update_cache: yes
cache_valid_time: 3600
state: latest
with_items:
- build-essential
- git
- libjpeg-dev
However, I get a changed notification every time, even though nothing has been installed. I don't want to set changed_when: False. Is there a way to get the proper changed status from this loop?
Update If anything was installed by apt, I want changed to be True. If everything was already installed, and apt did not do any work when looping over this list, then I want changed to be False.
I'm using Ansible 2.0.1.0.
The changed indication is due the apt cache (apt-get update) being executed each time the task is run. If you only want an indication of whether packages were installed then remove the update_cache: yes directive or set to update_cache: no.
Here's what it should be, after applying the accepted answer by #Petro026.
tasks:
- name: install packages
apt:
name: "{{ item }}"
state: latest
with_items:
- build-essential
- git
- libjpeg-dev

Resources