Better way to install helm with Ansible? - ansible

The following recipe works, but I find the number of tasks being high and I'm wondering if there is a better way to install Helm while performing a checksum. Currently, I have to:
Check current installed helm version, if any
Download helm and notify the handler to unarchive the binary
Unarchive the binary, if needed
Delete downloaded file, if needed
roles/node/tasks/main.yaml:
- name: Set current helm version
ansible.builtin.command:
cmd: helm version --client --template={{ "'{{ .Version }}'" }}
changed_when: false
failed_when: false
register: current_helm_version
- name: Download helm archive
ansible.builtin.get_url:
url: https://get.helm.sh/helm-{{ helm_version }}-linux-arm64.tar.gz
checksum: sha256:https://get.helm.sh/helm-{{ helm_version }}-linux-arm64.tar.gz.sha256sum
dest: /tmp
owner: root
group: root
mode: 0644
notify: Unarchive helm binary
when: helm_version != current_helm_version.stdout | default(false)
- name: Flush handlers
ansible.builtin.meta: flush_handlers
- name: Delete helm archive
ansible.builtin.file:
path: /tmp/helm-{{ helm_version }}-linux-arm64.tar.gz
state: absent
roles/node/handlers/main.yaml:
- name: Unarchive helm binary
ansible.builtin.unarchive:
src: /tmp/helm-{{ helm_version }}-linux-arm64.tar.gz
dest: /usr/local/bin
extra_opts: "--strip-components=1"
owner: root
group: root
mode: 0755
remote_src: true

You can do it with one single task:
---
- hosts: localhost
tasks:
- name: Install helm if not exists
unarchive:
src: https://get.helm.sh/helm-v3.11.0-linux-amd64.tar.gz
dest: /usr/local/bin
extra_opts: "--strip-components=1"
owner: root
group: root
mode: 0755
remote_src: true
args:
creates: /usr/local/bin/helm
When /usr/local/bin/helm exists, it will not execute the task.

Related

How do I correct ansible playbook syntax error? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last year.
Improve this question
I am creating an ansible playbook in centos7. I get the syntax error every-time I adjust to the syntax error (I even checked spacing and still getting same error):
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: No JSON object could be decoded
Syntax Error while loading YAML.
could not find expected ':'
The error appears to be in '/etc/ansible/playbook.yml': line 121, column 5, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Install MySQL repo
^ here
hosts: local host
connection: local
vars: digital_ocean_token: ****
droplets:
- wordpress1
- wordpress2
tasks:
- name: Create SSH Key
user:
name: "{{ansible_user_id}}"
generate_ssh_key_type: rsa
ssh_key_type 4096
ssh_key_file .ssh/id_rsa
- name: Create Digital Ocean Key
community.digitalocean.digital_ocean:
state: present
command: droplet
name: "" "{{ item }}"
unique_name: yes
size_id: s-1vcpu-1gb
region_id: nyc
image_id: centos-7-x64
ssh_key_ids: "{{ my_ssh.ssh_key.id }}"
api_token: "{{ digital_ocean_token }}"
with_items: "{{droplets}}"
register: droplet_details
- name: Add doplets to /etc/ansible/hosts
add_host:
path: /etc/ansible/hosts
groups: droplets
name: "{{ item.droplet.ip_address }}"
with_items:: "{{ droplet_details.results }}"
- pause:
seconds: 45
- hosts: droplets
tasks:
- name: Disable SeLinux
selinux:
state: disabled
#Epel-Release
- name: Install epel-release
yum:
name: epel-release
state: present
- name: update
yum:
name: "*"
state: present
#Install Apache
- name: Install Apache
yum:
name: httpd
state: latest
- name: enable service to start on boot up
service:
name: httpd
state: started
#Install MariaDB
- name: Install MariaDB
yum:
name: mariadb
state: latest
- name: Install MariaDB Server
yum:
name: mariadb-server
state: latest
- name: Install Python2
yum:
name: python2
state: latest
- name: Install Python3
yum:
name: python3
state: latest
- name: Install pip
pip:
name: pip
extra_args: --upgrade
executable: pip3
#Install PHP
- name: Install Remi Repository
yum:
name: https://rpms.remirepo.net/enterprise/remi-release-7.rpm
state: present
- name: Install PHP
yum:
enablerepo: "remiremi-php80"
name:
- php
- php-common
- php-cli
- php-gd
- php-curl
- php-mysqlnd
- php-fpm
- php-mysqli
- php-json
state:latest
- name: Install MySQL repo
yum:
name: http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
state: present
- name: Install PyMySQL
yum:
pkg: ['mysql-community-server', 'mysql-community-client', 'MySQL-python']
# Start MySQL
- name: Start MySQL
service:
name: mysqld
state: started
enabled: yes
# Create MariaDB Database
- name: MySQL login
mysql_user:
user: ***
login_user: ***
login_password: "****"
state: present
- name: Create MariaDB username & password
mysql_user:
login_user: ****
login_password: "****!"
name: wordpressuser
password: ****
priv: "*.*;ALL,GRANT"
host: "localhost"
state: present
- name: Vreate MariaDB Database
mysql_db:
login_user: ***
login_password: "****"
state: present
- name: Restart MariaDB Database
service:
name: mysqld
state: restarted
# Install Wordpress
- name: Download Wordpress
get_url:
url=http://wordpress.org/latest.tar.gz
dest=/tmp/wordpress.latest.tar.gz
validate_certs=no
- name: unzip Wordpress
unarchive:
src=/tmp/wordpress.latest.tar.gz
dest=/var/www
copy=no
- name: Copy sample config file
command: mv /var/www/wordpress/wp-config-sample.php /var/www/wordpress/wp-config.php
- name: Update Wordpress config file
lineinfile:
path: /var/www/wordpress/wp-config.php
regexp: "{{item.regexp}}"
line: "{{item.line}}"
with_items:
- {'regexp': "define\\( 'DB_NAME', '(.)+' \\);", 'line': "define( 'DB_NAME'', 'wordpress');"}
- {'regexp': "define\\( 'DB_USER', '(.)+' \\);", 'line': "define( 'DB_USER', 'wordpressuser' );"}
- {'regexp': "define\\( 'DB_PASSWORD', '(.)+' \\);", 'line': "define( 'DB_PASSWORD', '***' );"}
- name: Give Ownership to Apache user
file:
path: /var/www/wordpress
state" directory
recurse: yes
owner: apache
group: apache
- name: Set correct permissions on Wordpress directories
command: find /var/www/wordpress/ -type d -exec chomd 755 {} \;
- name: Set correct permissions for Wordpress files
command: find /var/www/wordpress/ -type f -exec chomd 755 {} \;
- name: Restart Apache
service:
name: httpd
state: restarted
It looks from what you provided that you don't have a valid yaml format playbook.
You can do quick syntax checks using:
ansible-playbook playbook.yaml --syntax-check
The plays need to be one or more elements of a yaml list, under tasks.
I'd expect your playbook to look something like:
---
# YAML documents begin with the document separator ---
- hosts: hosta,hostb ...etc
tasks:
- name: install MySQL repo
yum:
name: http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
state: present
# Three dots indicate the end of a YAML document
...
There are other sections you might have in a playbook, but I've omitted those. The sections like vars, handlers or roles, would be list items at the same indention level as the hosts: and tasks: if you were to need those.
It looks like your issue is here:
name: Install PHP
yum:
enablerepo: "remiremi-php80"
name:
- php
- php-common
- php-cli
- php-gd
- php-curl
- php-mysqlnd
- php-fpm
- php-mysqli
- php-json
state: latest
Notice that state: has to be indented exactly at the same level as enablerepo and name. Make sure you have a space there between state: and latest.

I am having an issue with ansible where I am trying to sync /etc/yum.repos.d with other hosts

This is the ansible script. Its not copying all the files /etc/yum.respos.d to the other hosts.
- name: Sync System Files
hosts: all
tasks:
- name: Sync System Files
tags: sync-push
synchronize:
src: "{{ item }}"
dest: "/"
mode: push
recursive: yes
register: syncfile
with_items:
- "/etc/yum.repos.d"

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

Ansible get_url Fails If Destination File Does Not Exist

When using get_url, it fails if the destination file does not exist locally. If I us vi and create the file with nothing in it, then the call works and the file is replaced. I added force: yes to encourage it to write out the file, but every attempt failed until I created a dummy file.
Any help is appreciated.
Thank you!
---
- name: Download HashiCorp Installation Archive File
hosts: 127.0.0.1
vars:
vault:
distro: 'linux'
version: '1.5.4'
user:
group: 'rcouch'
name: 'rcouch'
tasks:
# https://releases.hashicorp.com/vault/1.5.4/vault_1.5.4_linux_amd64.zip
- name: Download Binary
get_url:
url: "https://releases.hashicorp.com/vault/{{ vault.version }}/vault_{{ vault.version }}_{{ vault.distro }}_amd64.zip"
checksum: "sha256:https://releases.hashicorp.com/vault/{{ vault.version }}/vault_{{ vault.version }}_SHA256SUMS"
force: yes
dest: "vault_{{ vault.version }}_{{ vault.distro }}_amd64.zip"
owner: "{{ user.group }}"
group: "{{ user.name }}"
mode: 0755
register: vault_download
- name: Display Vault Download
debug:
msg:
- "vault_download: {{ vault_download }}"
The get_url module takes an absolute path in dest. A small excerpt from the module's page. Try an absolute path like /tmp or ./.
| dest | Absolute path of where to download the file to. |
tasks:
- get_url:
url: https://releases.hashicorp.com/vault/1.5.4/vault_1.5.4_linux_amd64.zip
dest: ./vault_1.5.4_linux_amd64.zip

Ansible task for run Docker container from private registry

I have a private Docker registry runnning in 172.20.20.20 in port 5000. And I have pushed the image pruebasjeje to it.
Now, I need to pull and run the image using Ansible task:
- name: run container
docker:
registry: 172.20.20.20:5000
insecure_registry: true
image: pruebasjeje
state: reloaded
pull: always
ports:
- "8080:8080"
But when I execute it, I get this error:
fatal: [localhost]: FAILED! => {"changed": false, "changes":
["{\"status\":\"Pulling repository
docker.io/library/pruebasjeje\"}\r\n",
"{\"errorDetail\":{\"message\":\"Error: image
library/pruebasjeje:latest not found\"},\"error\":\"Error: image
library/pruebasjeje:latest not found\"}\r\n"], "failed": true, "msg":
"Unrecognized status from pull.", "status": ""}
It seems that is looking for the image in docker.io. How should I write my task in order to do what I want?
Thanks.
Not sure if it is how it should be done, but this is how I do it:
- name: run container
docker:
insecure_registry: true
image: 172.20.20.20:5000/pruebasjeje
state: reloaded
pull: always
ports:
- "8080:8080"
I just started with Docker myself. Here are the tasks I have for setting up Docker on my target host (CentOS 7):
- name: Install epel repo
yum:
name: "http://download.fedoraproject.org/pub/epel/{{ ansible_distribution_major_version }}/{{ ansible_userspace_architecture }}{{ '/' if ansible_distribution_major_version < '7' else '/e/' }}epel-release-{{ ansible_distribution_major_version }}-5.noarch.rpm"
state: present
become: yes
- name: Install Docker
yum:
name: "{{ item }}"
state: latest
enablerepo: epel
with_items:
- device-mapper
- docker-engine
- python-pip
become: yes
- name: Install docker-py
pip:
name: docker-py
become: yes
- name: Add registry cert
copy:
src: registry.crt
dest: /etc/docker/certs.d/{{ docker_registry_host }}/ca.crt
become: yes
- name: Allow access to insecure registry
lineinfile:
dest: /usr/lib/systemd/system/docker.service
regexp: ^ExecStart=
line: ExecStart=/usr/bin/docker daemon -H fd:// --insecure-registry {{ docker_registry_host }}:5000
become: yes
- name: Start Docker service
service:
name: docker
state: started
enabled: yes
become: yes

Resources