I am trying to install Sublime Text (on Ubuntu) using Ansible. Here is the basic Ansible playbook I am trying to use for accomplishing this, based on:
bash commands here to install Sublime Text
Ansible docs apt-repository and apt-key
---
- hosts: all
vars:
- my_repos:
- ppa: https://download.sublimetext.com/
- ppa: [arch=amd64] http://dl.google.com/linux/chrome/deb/
- my_pkgs:
- sublime-text
- google-chrome-stable
tasks:
- Install GPG key
name: install GPG key for SubLimeText
???????
- name: Add specified repositories into sources list using specified filename
apt_repository: repo=deb {{ item }} stable main
state=present
filename='{{ item }}'
with_items:
- my_repos
- name: Install packages
apt: state=installed pkg={{ item }}
with_items:
- my_pkgs
The first task is to install the GPG key for SublimeText (per the 1st link above). I read the Ansible docs here, but I do not know how to translate that into the SublimeText case.
Questions:
In the SublimeText instructions, step 1: a direct link to the GPG key is specified. They say:
Install the GPG key: https://download.sublimetext.com/sublimehq-pub.gpg
but how do I add this using the Ansible apt_key module?
In step 2: Does the task to use apt_repository correspond to the bash command echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list
---
- hosts: all
vars:
- my_pkgs:
- sublime-text
- google-chrome-stable
tasks:
- name: Install GPG key for SubLimeText
apt_key:
url: https://download.sublimetext.com/sublimehq-pub.gpg
state: present
- name: Add specified repositories into sources list using specified filename
apt_repository:
repo: deb {{ item.repo }} {{ item.add }}
state: present
filename: "{{ item.file }}"
with_items:
- repo: https://download.sublimetext.com/
add: apt/stable/
file: sublime
- repo: '[arch=amd64] http://dl.google.com/linux/chrome/deb/'
add: stable main
file: google-chrome
- name: Install packages
apt:
state: installed
pkg: "{{ item }}"
update_cache: yes
with_items:
- "{{ my_pkgs }}"
For Fedora 32, the following works as part of my main.yaml. Of course, remove the ... and edit to your needs :-)
- hosts: fedora
become: true
tasks:
...
- name: Add Sublime repository
yum_repository:
name: sublime-text
description: Sublime Text x86_64 - stable
baseurl: https://download.sublimetext.com/rpm/stable/x86_64
enabled: yes
gpgcheck: yes
- name: Add Sublime Text
dnf:
name: sublime-text
state: present
...
Related
I'm trying create a Ansible playbook that will read contents of a file and use those contents to install packages on a target machine.
In simpler terms, I want to run this command converted to an ansible playbook
cat ./meta/install-list/apt | xargs apt install -y
./meta/install-list/apt
neofetch
tmux
git
./ansible/playbooks/apt.yaml
- hosts: all
become: true
tasks:
- name: Extract APT packages to install
command: cat ../../meta/install-list/apt
register: _pkgs
delegate_to: localhost
run_once: true
- name: Install APT packages
apt:
name: "{{ _pkgs.stdout_lines }}"
state: latest
./ansible.cfg
[defaults]
inventory = ./ansible/inventory/hosts.yaml
./ansible/inventory/hosts.yaml
---
all:
children:
group-machines:
hosts:
target-machine.local
Command to run playbook
ansible-playbook --ask-become-pass ./ansible/playbooks/apt.yaml --limit group-machine
When running the command, it gets stuck on Extract APT packages to install
NOTE:
these files mentioned above are to be only on machine that is running the command. If possible, I'd like to prevent copying files to target machines and then running the playbooks tasks
PS: new to ansible
I don't see anything in your "Extract APT packages to install" task that should cause it to get stuck... but you don't need that task in any case; you can combine your two tasks into a single task like this:
- hosts: all
become: true
tasks:
- name: Install APT packages
apt:
name: "{{ packages }}"
state: latest
vars:
packages: "{{ lookup('file', '../../meta/install-list/apt').splitlines() }}"
Here we're using a file lookup to read the contents of a file. Lookups always run on the local (control) host.
Note that you could write the above like this as well...
- hosts: all
become: true
tasks:
- name: Install APT packages
apt:
name: "{{ lookup('file', '../../meta/install-list/apt').splitlines() }}"
state: latest
...but I like to keep longer jinja expressions in vars in order to keep the rest of the arguments more readable.
The above answer is more than enough by #Zeitounator. But if you do some formatting to your original file of package list as below
packages:
- neofetch
- tmux
- git
After that you can simply run the playbook like below
- hosts: all
become: true
vars_files: ../../meta/install-list/apt
tasks:
- name: Install APT packages
apt:
name: "{{ packages }}"
state: latest
Now suppose if you are lazy enough to not want to do the formatting then below playbook also will do the trick. Its much cleaner and scalable in my opinion.
---
- name: SHow the packages list
hosts: localhost
become: true
tasks:
- name: View the packages list file
shell: cat ../../meta/install-list/apt
register: output
- name: Install the package
apt:
name: "{{ output.stdout_lines }}"
state: latest
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'm a fresher in the professional world as i just joined amid corona situation as being work from i have been involved to understand and write ansible codes and at some level i am growing up by watching through SO posts to get variety of ticks & tricks.
I have the below ansible playbooks..
1- One is custom_pkgs.yml which basically installing some custom build packages using yum command where it calling a pkgs.yml file which lists the packages to be install.
I somewhat understood the code but
$ vi custom_pkgs.yml
---
- name: Install License
hosts: all
become: yes
become_user: root
become_method: sudo
tasks:
- name: Include the variables to install the license software
include_vars:
file: "vars/pkg.yml"
name: license
- name: Install license software
shell: "yum install -y {{ license[ item ] | join(' ') }}"
with_items: "{{ license }}"
changed_when: True
when: item != "remove"
- name: Remove any unwanted RPMS
shell: "yum remove -y {{ license.remove | join(' ') }}"
changed_when: True
when: license.remove is defined
...
Below is the pkg.yml
$ cat pkg.yml
---
license:
- fenixlmd.noarch
- tmpwatch
- xorg-x11-deprecated-libs.i386
- Tasking.noarch
- rotate_fix.noarch
- plexim.noarch
- interrad.noarch
- idsd.noarch
- gsi.noarch
- java-1.8.0-openjdk
- java-1.8.0-openjdk-devel
- java-1.8.0-openjdk-debug
- flexnet_agent
- magillem.noarch
- redhat-lsb-printing
- redhat-lsb-printing.i686
- redhat-lsb-core
- redhat-lsb-core.i686
- redhat-lsb
- redhat-lsb.i686
- git
- gcc
- python-devel
...
What i would like to Know:
I am trying to understand about below two lines..
shell: "yum install -y {{ license[ item ] | join(' ') }}" and when: item != "remove"
I have went through all the basics of asking question in SO in case i've ask something out of way i would like to be excused as this is my first post.
Regards ..
Thanks for learning Ansible, this is an old Ansible code. The pkg.yml file defines a list variable called licence containing a list of yum package to install on the remote host using the Ansible shell module. with_items: "{{ license }}" tell the module to iterate on that variable items.
The When condition help to skip the package when his name is remove.
Read the Ansible conditional documentation: https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#the-when-statement
But as i told, it's an old code. On Ansible recent version, you will use a yum module to install yum package (create two lists of package: package_to_install and package_to_remove
- name: Install License
hosts: all
become: yes
become_user: root
become_method: sudo
tasks:
- name: Include the variables to install the license software
include_vars:
file: "vars/pkg.yml"
name: license
- name: Install license software
yum:
name: "{{ package_to_install }}"
changed_when: True
when: item != "remove"
- name: Remove any unwanted RPMS
yum:
name: "{{ package_to_remove }}"
state: absent
changed_when: True
Make sure to use a recent Ansible version (2.9).
Read the yum module documentation: https://docs.ansible.com/ansible/latest/modules/yum_module.html
You can Also defined only one list of package variable with two fields:
license:
- { name: fenixlmd.noarch, state: present }
- { name: tmpwatch, state: absent }
- { name: xorg-x11-deprecated-libs.i386, state: present }
.
.
.
And then use the yum module like that:
- name: Install License
hosts: all
become: yes
become_user: root
become_method: sudo
tasks:
- name: Include the variables to install the license software
include_vars:
file: "vars/pkg.yml"
name: license
- name: Remove any unwanted or install needs package RPMS
yum:
name: "{{ item.name }}"
state: "{{ item.state }}"
with_items: "{{ licence }}"
I have this task in Ansible:
- name: Install mongodb
yum:
name:
- "mongodb-org-{{ mongodb_version }}"
- "mongodb-org-server-{{ mongodb_version }}"
- "mongodb-org-mongos-{{ mongodb_version }}"
- "mongodb-org-shell-{{ mongodb_version }}"
- "mongodb-org-tools-{{ mongodb_version }}"
state: present
notify: Restart mongodb
Is there a way I can indicate the version without having to use a loop like this? What is a more "elegant" way of writing this?
- name: Install mongodb
yum:
name: "{{ item }}-{{ mongodb_version }}"
state: present
loop:
- mongodb-org-server
- mongodb-org-mongos
- mongodb-org-shell
- mongodb-org-tools
notify: Restart mongodb
To my surprise I didn't find the simplest solution in all the answers, so here it is. Referring to the question title Installing multiple packages in Ansible this is (using the yum module):
- name: Install MongoDB
yum:
name:
- mongodb-org-server
- mongodb-org-mongos
- mongodb-org-shell
- mongodb-org-tools
state: latest
update_cache: true
Or with the apt module:
- name: Install MongoDB
apt:
pkg:
- mongodb-org-server
- mongodb-org-mongos
- mongodb-org-shell
- mongodb-org-tools
state: latest
update_cache: true
Both modules support inline lists!
The second part of your question is how to integrate specific version numbers into the package lists. No problem - simply remove the state: latest (since using specific version numbers together with state: latest would raise errors) and add the version numbers to the package names using a preceding = like this:
- name: Install MongoDB
yum:
name:
- mongodb-org-server=1:3.6.3-0centos1.1
- mongodb-org-mongos=1:3.6.3-0centos1.1
- mongodb-org-shell=1:3.6.3-0centos1.1
- mongodb-org-tools=1:3.6.3-0centos1.1
update_cache: true
You could also optimize further and template the version numbers. In this case don't forget to add quotation marks :)
Make this into an Ansible Role called mongo, resulting in the directory structure:
playbook.yml
roles
|-- mongo
| |-- defaults
| | |-- main.yml
| |
| |-- tasks
| | |-- main.yml
| |
| |-- handlers
| | |-- main.yml
Add the required MongoDB packages and version into the default variables file roles/mongo/defaults/main.yml:
mongo_version: 4.0
mongo_packages:
- mongodb-org-server
- mongodb-org-mongos
- mongodb-org-shell
- mongodb-org-tools
Re-write the task in the roles/mongo/tasks/main.yml file:
- name: Install mongodb
yum:
name: "{{ item }}-{{ mongo_version }}"
state: present
with_items: "{{ mongo_packages }}"
notify: Restart mongodb
Add your handler logic to restart MongoDB in the file roles/mongo/handlers/main.yml.
Write a Playbook called playbook.yml that calls the role.
---
- hosts: all
roles:
- mongo
Some people have mentioned syntax that allows passing a list, but you don't need to special-case your code for apt or yum. Here is the command that uses the generic package manager module:
- name: Install packages
become: yes
package:
name:
- tmux
- rsync
- zsh
- rsync
- wget
state: present
(Or state: latest.) This feature is only documented for Ansible 2.9, so it may be new.
I think this is best way, but as the package names should not be hard coded, it is preferred to keep in vars/main.yml
e.g
mongodb_version: 5
packages:
- "mongodb-org-shell-{{ mongodb_version }}"
- "mongodb-org-server-{{ mongodb_version }}"
Call this inside your playbook as
- name: Install mongodb packages
yum: name={{ item }}
state=latest
with_items: "{{ packages}}"
Now yum module direct accept array of packages like this
vars:
pkgs:
- screen
- rubygems
- ksh
- strace
tasks:
- name: Install pre-requisite packages
yum: name={{ pkgs }} state=installed
A more elegant way, which doesn't keep re-checking each and every package if installed every time the script is run is to use something like this:
In vars/main.yml or similar:
packages_to_install:
- mongodb-org-server
- mongodb-org-mongos
- mongodb-org-shell
- mongodb-org-tools
In tasks/main.yml or similar:
- name: "Get installed packages"
yum:
list: "installed"
register: installed_packages
- name: "Install missing packages"
package:
state: "present"
name: "{{ item }}"
with_items: "{{ packages_to_install | difference(installed_packages | json_query('results[*].name')) }}"
Essentially this checks what is already installed and only installs missing packages. Counter-intuitively this is faster. You can also use dnf instead of yum.
I try to figure how I must to construct an ansible playbooks where I can do some action and undo them (I can install or remove same packages; place file or remove this file).
If I create two ansible playbooks: delete.yml and install.yml. There are may be problem's like:
I added to installation someting, but don't change deletion
Example:
install.yml:
---
- name: Add x2go repository
apt_repository: repo='deb http://ppa.launchpad.net/x2go/stable/ubuntu precise main' state=present
apt_repository: repo='deb-src http://ppa.launchpad.net/x2go/stable/ubuntu precise main' state=present
when: ansible_os_family == "Debian"
tags:
- remote-access-x2go
- name: Install x2go application
apt: name=x2goserver update_cache=yes state=present
apt: name=x2goserver-xsession update_cache=no state=present
when: ansible_os_family == "Debian"
tags:
- remote-access-x2go
delete.yml:
---
- name: Add x2go repository
apt_repository: repo='deb http://ppa.launchpad.net/x2go/stable/ubuntu precise main' state=absent
apt_repository: repo='deb-src http://ppa.launchpad.net/x2go/stable/ubuntu precise main' state=present
when: ansible_os_family == "Debian"
tags:
- remote-access-x2go
- name: Install x2go application
apt: name=x2goserver update_cache=yes state=absent
apt: name=x2goserver-xsession update_cache=no state=absent
when: ansible_os_family == "Debian"
tags:
- remote-access-x2go
This is a very interesting idea. I have personally never tried the 'undoing' workflow, but I can see the nice things about this idea and would like to use it sometime. Here is what I would do.
In my ansible-role/defaults/main.yml I would define a variable flag
# defaults file for ansible-role
flag_undo: false
In my ansible-role/tasks/main.yml I would have
- name: task foo bar
command: falana dhimaka
- name: undoing task foo bar
command: undo falana dhimaka
when: flag_undo=true
So by default our flag is always false. So when installing things I would us the first command below to run my plays. And to uninstall I would use the second command.
ansible-playbook foo-play.yml
ansible-playbook foo-play.yml --extra-vars "flag_undo=true"
One approach that I use in some cases is to simply have lists of packages that you want installed and lists you want removed, then iterate over each list. I use this basic method not only for packages but other things as well, like users, groups, etc. For example, I have a "packages" role that has the following files in it:
vars/main.yml:
---
installed_system_packages:
- telnet
- screen
- postfix
latest_system_packages:
- glibc
removed_packages:
- sendmail
tasks/main.yml:
---
- name: Install system packages (latest)
yum: pkg={{ item }} state=latest
with_items: latest_system_packages
- name: Install system packages
action: yum pkg={{ item }} state=installed
with_items: installed_system_packages
- name: Remove unwanted packages
action: yum pkg={{ item }} state=removed
with_items: removed_packages
This way, if I decide that I no longer want a package like telnet installed I can just move it from installed_system_packages to removed_packages. Or if I want to ensure I'm running the latest version of screen I would simply move it to the latest_system_packages list. Then it's just a matter of re-running the role to have the changes applied.