I'm using ansible to install Apache, currently I have multiple httpd.conf files(test/dev/staging/production) in ansible repository, most of the content is same excepts some environment specific settings.
Is it possible to use one httpd.conf template file, and modify the file when send the httpd.conf to remote server?
Yes you can. With jinja2 and group_vars.
So what you do in your templates/ folder create a file like such:
templates/http.conf.j2
Say you have something like this in there:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName {{ subdomain }}.{{ domain }}
ServerAlias www.{{ subdomain }}.{{ domain }}
</VirtualHost>
Your layout should look like this:
├── group_vars
│ ├── all
│ │ └── config
│ ├── dev
│ │ └── config
│ └── test
│ └── config
├── inventory
│ ├── dev
│ │ └── hosts
│ └── test
│ └── hosts
├── site.yml
└── templates
└── http.conf.j2
In group_vars/all you would have domain: "example.com"
In group_vars/dev you would have subdomain: dev
In group_vars/test you would have subdomain: test
In your task, you'd have your ansible template command i.e.
- hosts: all
tasks:
- name: Copy http conf
template:
dest: /etc/apache2/http.conf
src: templates/http.conf.j2
owner: root
group: root
And run your playbook like this:
ansible-playbook -i inventory/test site.yml
The file should end up on the host looking like this:
<VirtualHost *:80>
ServerName test.example.com
ServerAlias www.test.example.com
</VirtualHost>
Related
I have an Ansible role that will provision an ubuntu server in Azure. The VM provisioning is working fine for me but I need to copy few files from my localhost to this VM how can I do this?
├── defaults
│ └── main.yml
├── files
│ ├── cloud-init.yaml
│ └── files.txt
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ ├── copyfile.yaml
│ ├── main.yml
│ ├── apachenic.yaml
│ └── apachevm.yaml
└── vars
└── main.yml
Here I have kept the file files.txt (the file I want to copy) in file folder and created a new task file (copyfile.yaml) for copying. Adding content of copy tasks below.
- name: copy certs
become: true
become_user: admin
ansible_sudo_password: pass123
copy:
src: files.txt
dest: /home/admin/
owner: admin
group: admin
I have tried multiple times re-arranging and creating a new task file getting the below error message.
ERROR! conflicting action statements: copy, ansible_sudo_password
for me looks like your YAML is malformed.
try this: (top level play, lets say, its copyFilesTXT.yml )
- hosts: all
become: true
become_user: admin
become_method: sudo
tasks:
- name: copy files.txt file to remote machine
copy:
src: files.txt
dest: /home/admin/
owner: admin
group: admin
mode: 0644
this task can be started by this console invocation
/bin/ansible-playbook --ask-become-pass -i hosts.ini copyFilesTXT.yml -vv
it will ask for sudo password from STDIN, so you can provide it.
Also, you can omit --ask-become-pass and add this variable in vars/main.yml
ansible_become_pass: pass123
so, sudo password will be loaded from vars/main.yml
I try to copy files from roles/common/files with fileglob, but ansible-playbook searchs them in roles/common/tasks/files
Using Roles documentation says:
Any copy, script, template or include tasks (in the role) can
reference files in roles/x/{files,templates,tasks}/ (dir depends on
task) without having to path them relatively or absolutely.
Playbook:
# ./ansible/roles/common/tasks/main.yml
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: setup bashrc
import_tasks: bashrc.yml
Task:
# ./ansible/roles/common/tasks/bashrc.yml
- name: try to find bashrc libs in roles/common/files/bashrc
copy:
src: "{{ item }}"
dest: /tmp
with_fileglob:
- bashrc/*.lib.sh
# Causes the same error:
# loop: "{{ lookup('fileglob', 'bashrc/*', wantlist=True) }}"
Files tree:
.
├── ansible
│ └── roles
│ └── common
│ ├── files
│ │ └── bashrc
│ │ ├── shell-aliases.lib.sh
│ │ ├── shell-functions.lib.sh
│ │ └── shell-settings.lib.sh
│ └── tasks
│ ├── bashrc.yml
│ ├── main.retry
│ └── main.yml
Run playbook:
$ ansible-playbook -vvvvv ./ansible/roles/common/tasks/main.yml
...
TASK [try to find bashrc libs in roles/common/files/bashrc] *******...
task path: /home/<user>/git/homedirsync/ansible/roles/common/tasks/bashrc.yml:1
looking for "bashrc" at "/home/<user>/git/homedirsync/ansible/roles/common/tasks/files/bashrc"
looking for "bashrc" at "/home/<user>/git/homedirsync/ansible/roles/common/tasks/bashrc"
looking for "bashrc" at "/home/<user>/git/homedirsync/ansible/roles/common/tasks/files/bashrc"
looking for "bashrc" at "/home/<user>/git/homedirsync/ansible/roles/common/tasks/bashrc"
[WARNING]: Unable to find 'bashrc' in expected paths
...
Ansible version:
ansible 2.6.1
config file = /home/<user>/.ansible.cfg
configured module search path = [u'/var/ansible/library']
ansible python module location = /usr/local/lib/python2.7/dist-packages/ansible
executable location = /usr/local/bin/ansible
python version = 2.7.6 (default, Nov 13 2018, 12:45:42) [GCC 4.8.4]
I saw a lot of examples where it works and issues where it doesn't, but I can't localize the root of problem in my case. Community, please help.
Q: "Unable to find subdir in expected paths with fileglob"
A: Quoting from fileglob's NOTES
"Matching is against local system files on the Ansible controller. "
Role's feature "Any copy, script, template or include tasks can reference files in roles/x/{files,templates,tasks} ..." does not apply to fileglob.
Instead, it's possible to use special variables. For example
with_fileglob:
- '{{ role_path }}/files/bashrc/*.lib.sh'
Ansible roles for a common sensible base configuration for all machines. Should support RHEL/Debian/SuSE/Solaris/HPUX/Ubuntu Linux.
The Base host configuration should perform the following tasks:
ntp – configure NTP settings based on common configuration
ssh – configure SSH security, service, key settings
Package Yum / repo – configure Operating System native package manager to operate against internal HPE resources and/or externally-available resources (like ftp.debian.org).
I am new to creating Ansible Roles. I haven't tried anything yet, looking for guidance.
- name: restart ntp
service:
name: ntp
state: restarted
- name: restart sshd
service:
name: sshd
state: restarted
To create your own role start with
$ ansible-galaxy init test
This "creates the skeleton framework of a role that complies with the galaxy metadata format"
> tree test
test
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
For details see Roles.
There is plenty of roles shared at Ansible Galaxy that you might want to search in the browser, or from the command line. For example roles with tags: Solaris, sshd will be listed by the command
$ ansible-galaxy search --galaxy-tags solaris,sshd
and installed locally
$ ansible-galaxy install <ROLE NAME>
I have my directory structure as this
└── digitalocean
├── README.md
├── play.yml
└── roles
├── bootstrap_server
│ └── tasks
│ └── main.yml
├── create_new_user
│ └── tasks
│ └── main.yml
├── update
│ └── tasks
│ └── main.yml
└── vimserver
├── files
│ └── vimrc_server
└── tasks
└── main.yml
When I am creating a user under the role create_new_user, I was hard coding the user name as
---
- name: Creating a user named username on the specified web server.
user:
name: username
state: present
shell: /bin/bash
groups: admin
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: .ssh/id_rsa
- name: Copy .ssh/id_rsa from host box to the remote box for user username
become: true
copy:
src: ~/.ssh/id_rsa.pub
dest: /home/usernmame/.ssh/authorized_keys
mode: 0600
owner: username
group: username
One way of solving this may be to create a var/main.yml and put the username there. But I wanted something through which I can specify the username at play.yml level. As I am also using the username in the role vimrcserver.
I am calling the roles using play.yml
---
- hosts: testdroplets
roles:
- update
- bootstrap_server
- create_new_user
- vimserver
Would a template work here in this case? Couldn't find much from these SO questions
I got it working by doing a
---
- hosts: testdroplets
roles:
- update
- bootstrap_server
- role: create_new_user
username: username
- role: vimserver
username: username
on play.yml
Although would love to see a different approach then this
Docs: http://docs.ansible.com/ansible/playbooks_roles.html#roles
EDIT
I finally settled with a directory structure like
$ tree
.
├── README.md
├── ansible.cfg
├── play.yml
└── roles
├── bootstrap_server
│ └── tasks
│ └── main.yml
├── create_new_user
│ ├── defaults
│ │ └── main.yml
│ └── tasks
│ └── main.yml
├── update
│ └── tasks
│ └── main.yml
└── vimserver
├── defaults
│ └── main.yml
├── files
│ └── vimrc_server
└── tasks
└── main.yml
Where I am creating a defaults/main.yml file inside the roles where I need the usage of {{username}}
If someone is interested in the code,
https://github.com/tasdikrahman/ansible-bootstrap-server
You should be able to put username in a vars entry in play.yml.
Variables can also be split out into separate files.
Here is an example which shows both options:
- hosts: all
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
tasks:
- name: this is just a placeholder
command: /bin/echo foo
https://docs.ansible.com/ansible/playbooks_variables.html#variable-file-separation
Ansible seems to delight in having different ways to do the same thing, without having either a nice comprehensive reference, or a rationale discussing the full implications of each different approach :). If you didn't remember the above was possible (I'd completely forgotten vars_files), the easiest option to find from the documentation might have been a third way, which is the most sophisticated one.
There's a prominent recommendation for ansible-examples. You can see a group_vars directory, with files which automatically provide values for hosts according to their groups, including the magic all group. The group_vars directory can be placed in the same directory as the playbook.
https://github.com/ansible/ansible-examples/tree/master/lamp_simple
Maybe this is what you want?
---
- hosts: testdroplets
roles:
- update
- bootstrap_server
- { role: create_new_user, username: 'foobar' }
- vimserver
https://docs.ansible.com/ansible/2.5/user_guide/playbooks_reuse_roles.html#using-roles
If you use include_role, variables can be passed like below.
- hosts: all_hosts
tasks:
- include_role:
name: "path/to/role"
vars:
var1: "var2_value"
var2: "var2_value"
Can't you just pass the variable from the command line with the -e parameter? So you can specifiy the variable even before execution. This also results in the strongest variable declaration which always takes precendence (see Variable precendence).
If you want to place it inside your playbook I suggest defining the username with the set_fact directive in the playbook. This variable is then available in all roles and included playbooks as well. Something like:
---
- hosts: testdroplets
pre_tasks:
- set_fact:
username: my_username
roles:
- update
- bootstrap_server
- create_new_user
- vimserver
It is all here: http://docs.ansible.com/ansible/playbooks_variables.html
while there are already some good answers, but I wanted to add mine because I've done this exact thing.
Here is the role I wrote: https://github.com/jmalacho/ansible-examples/tree/master/roles/users
And, I use hash_merge=true, and ansible's group_vars to make a dictionary of users: keys,groups so that adding a new user by host or by environment, and re-running is easy.
I also wrote up how my team uses group variables for environments once like this: "https://www.coveros.com/ansible-environment-design/"
I have two roles, one of which has a group_vars file that is vaulted, and another that is not. I would like to run the role that does not require any vaulted information, but ansible prompts me for a vault password anyway:
$ tree
├── deploy-home-secure.yml
├── deploy-home.yml
├── group_vars
│ ├── home
│ │ └── unvaulted
│ └── home-secure
│ ├── unvaulted
│ └── vaulted
├── hosts
└── roles
├── home
│ └── tasks
│ └── main.yaml
└── home-secure
└── tasks
└── main.yaml
$ ansible-playbook --version
ansible-playbook 1.8.2
configured module search path = None
$ ansible-playbook -i hosts deploy-home.yml
ERROR: A vault password must be specified to decrypt vaulttest/group_vars/home-secure/vaulted
$ ansible-playbook --vault-password-file=/dev/null -i hosts deploy-home.yml
ERROR: Decryption failed
I have something like this to solve this kind of problem (mine was not different roles, but different hosts, but I think the same principle applies):
This is the simplified file structure:
group_vars
development_vars
staging_vars
vaulted_vars
production_vars
This allows you to deploy development or staging without Ansible asking you to decrypt production_vars.
And then, the production playbook goes like this:
hosts: production
roles:
- role...
vars_files:
- vaulted_vars/production_vars
The vars_files line where you specify the path to the vaulted var is the key.
Ansible will try to load a group_vars file for any group it encounters in your inventory. If you split inventory file (hosts) into one for home group and another for home-secure then it will not try to decrypt vars it is not supposed to.
$ ansible-playbook -i hosts-home deploy-home.yml
$ ansible-playbook --ask-vault-password -i hosts-home-secure deploy-home-secure.yml
Here is another option if you don't always need your vaulted variables.
You can have a folder structure like this:
group_vars
├── all
├── prod
├── dev
│ └── vars.yml
└── dev-vault
└── vault.yml
You store vaulted variables in the '-vault' variant of that inventory.
Then your inventories might be something like the following:
dev:
[servers]
dev.bla.bla
[dev:children]
servers
dev-vault:
[servers]
dev.bla.bla
[dev:children]
servers
[dev-vault:children]
servers
So you're only saving sensitive data in the dev-vault vars, if in most cases you don't actually need passwords etc you can run playbooks without having extra options you're not really using, or storing the vault password in plaintext for convenience, etc.
So the "normal" command might be:
ansible-playbook -i dev some.yml
And the "vaulted" command could be:
ansible-playbook -i dev-vault some.yml --extra-vars="use_vault=true"
Or you could manage the "include vault variables" via tagging, including some.yml in some-vault.yml etc