I am executing some ansible playbooks via gitlab-ci and what I could see is
Ansible playbook executing successfully through pipeline, but it doesn't produce the output it is intended to do
When I retry the gitlab job, it produces the output I needed.
This is one of the many playbooks I am executing through gitlab:
1_ca.yaml
---
- hosts: 127.0.0.1
connection: local
tasks:
- name: Create ca-csr.json
become: true
copy:
dest: ca-csr.json
content: '{"CN":"Kubernetes","key":{"algo":"rsa","size":2048},"names":[{"C":"US","L":"Portland","O":"Kubernetes","OU":"CA","ST":"Oregon"}]}'
- name: Create ca-config.json
become: true
copy:
dest: ca-config.json
content: '{"signing":{"default":{"expiry":"8760h"},"profiles":{"kubernetes":{"usages":["signing","key encipherment","server auth","client auth"],"expiry":"8760h"}}}}'
- name: Create the ca.pem & ca-key.pem
# become: true
shell: |
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
Basically what does this do is, it creates some certs I needed.
But in the first attempt even though pipeline passes and it doesn't generate these certs. When I restart (running the same job for the second time) that particular job in gitlab it generates these certs.
Why this is happening?
This is how my .gitlab-ci.yaml looks like:
Create-Certificates:
stage: ansible-play-books-create-certs
retry:
max: 2
when:
- always
script:
- echo "Executing ansible playbooks for generating certficates"
- ansible-playbook ./ansible-playbooks/1_ca/1_ca.yaml
- ansible-playbook ./ansible-playbooks/1_ca/2_admin.yaml
- ansible-playbook ./ansible-playbooks/1_ca/3_kubelet.yaml
- ansible-playbook ./ansible-playbooks/1_ca/4_kube-controller.yaml
- ansible-playbook ./ansible-playbooks/1_ca/5_kube-proxy.yaml
- ansible-playbook ./ansible-playbooks/1_ca/6_kube-scheduler.yaml
- ansible-playbook ./ansible-playbooks/1_ca/7_kube-api-server.yaml
- ansible-playbook ./ansible-playbooks/1_ca/8_service-account.yaml
- ansible-playbook ./ansible-playbooks/1_ca/9_distribute-client-server-cert.yaml
# when: delayed
# start_in: 1 minutes
tags:
- banuka-gcp-k8s-hard-way
PS: These ansible playbooks are executing in the ansible host itself, not in remote servers. So I can log into the ansible master server and check if these files are created or not.
running your playbook without the last shell module produces the follwing output:
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [127.0.0.1] **************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [127.0.0.1]
TASK [Create ca-csr.json] *****************************************************************************************************************************************************************************************
[WARNING]: File './ca-csr.json' created with default permissions '600'. The previous default was '666'. Specify 'mode' to avoid this warning.
changed: [127.0.0.1]
TASK [Create ca-config.json] **************************************************************************************************************************************************************************************
[WARNING]: File './ca-config.json' created with default permissions '600'. The previous default was '666'. Specify 'mode' to avoid this warning.
changed: [127.0.0.1]
PLAY RECAP ********************************************************************************************************************************************************************************************************
127.0.0.1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
and checking the existence:
$ ls ca* -al
-rw------- 1 root root 155 Aug 17 02:48 ca-config.json
-rw------- 1 root root 129 Aug 17 02:48 ca-csr.json
so although it's quite dirty way of writing a playbook - it works.
Why is it dirty ? :
you're not using any inventory
you should use local_action and not connection: local for local tasks
you are misusing ansible that is multi-node configuration management to do a bash script task
so in conclusion - there's nothing wrong with your ansible playbook - or maybe the file permissions (?) and if it does not run - you should look more in the gitlab-ci direction.
you need to provide more details on Gitlab-CI setup but - maybe the stage is not correct ?
Related
My playbook has a task to copy a file from the local box to the remote box and the last task has to use sudo to root. I am not getting it to work.
In my inventory I am trying to use I am just trying to get it to work then I can lock it down with ansible vault. I just need to see it work first.
[logserver]
mylogserver ansible_ssh_user=myuser ansible_become_password=mypassword
In my playbook the last task using the -host param to do the work on the remote box, earlier task copies file to remote server but then I add a remote host to get the work done.
# Cat file and append destination file
- name: cat files to destination file
hosts: mylogserver
gather_facts: no
become_exe: "sudo su - root"
tasks:
- name: cat contents and append to destination file
shell:
cmd: /usr/bin/cat /var/tmp/test_file.txt >> /etc/some/target_file.txt
For example, the inventory
shell> cat hosts
test_11 ansible_ssh_user=User1 ansible_become_password=mypassword
[logserver]
test_11
and the playbook
shell> cat pb.yml
- hosts: logserver
gather_facts: false
become_method: su
become_exe: sudo su
become_user: root
become_flags: -l
tasks:
- command: whoami
become: true
register: result
- debug:
var: result.stdout
work as expected
shell> ansible-playbook -i hosts pb.yml
PLAY [logserver] ******************************************************************************
TASK [command] ********************************************************************************
changed: [test_11]
TASK [debug] **********************************************************************************
ok: [test_11] =>
result.stdout: root
PLAY RECAP ************************************************************************************
test_11: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notes:
Configuration of the method, e.g. become_method: su, is missing. See DEFAULT_BECOME_METHOD. The default is 'sudo'. For details see Using Become Plugins
See details of the plugin from the command line shell> ansible-doc -t become su
Use become_flags to specify options to pass to su, e.g. become_flags: -l
Use become_user to specify the user you 'become' to execute the task, e.g. become_user: root. This example is redundant. 'root' is the default
Specify become: true if the task shall use the configured escalation. The default is 'false'. See DEFAULT_BECOME
Configure sudoers, e.g.
- command: grep User1 /usr/local/etc/sudoers
become: true
register: result
- debug:
var: result.stdout
gives
TASK [debug] ***************************************************************
ok: [test_11] =>
result.stdout: User1 ALL=(ALL) ALL
Encrypt the password
Remove the password from inventory hosts and put it into a file, e.g. in host_vars
shell> cat hosts
test_11 ansible_ssh_user=User1
[logserver]
test_11
shell> cat host_vars/test_11/ansible_become_password.yml
ansible_become_password: mypassword
Encrypt the password
shell> ansible-vault encrypt host_vars/test_11/ansible_become_password.yml
Encryption successful
shell> cat host_vars/test_11/ansible_become_password.yml
$ANSIBLE_VAULT;1.1;AES256
35646364306161623262653632393833323662633738323639353539666231373165646238636236
3462386536666463323136396131326333636365663264350a383839333536313937353637373765
...
Test the playbook
shell> ansible-playbook -i hosts pb.yml
PLAY [logserver] ******************************************************************************
TASK [command] ********************************************************************************
changed: [test_11]
TASK [debug] **********************************************************************************
ok: [test_11] =>
result.stdout: root
...
So I created this Ansible playbook to:
copy a zip file and unzip it
copy a zip file and unzip it
make script inside the file executable
run the script
enable 2 services
- name: fideliplaybook
hosts: k8scluster
tasks:
- name: copying file with playbook
become: true
copy:
src: /home/lc/lc.zip
dest: /home/lc/
mode: 755
- name: Update apt cache and install unzip
become: true
command: apt install unzip
- name: unzip file
become: true
unarchive:
src: /home/lc/lc.zip
dest: /home/lc/
- name: make script executable
become: true
file: dest=/home/lc/lc/install.sh mode=755
- name: Execute the script
become: true
command: sh /home/lc/lc/install.sh
- name: Enable service 1
become: true
command: systemctl enable service1.service
- name: Enable service 2
become: true
command: systemctl enable service1.service
the issue that I am facing here that when ansible is trying to execut the script "install.sh"
it somehow fails becuse script cant find 2 other scripts although the other scripts are in the same file.
so 3 scripts are in lc.zip but when running install.sh with ansible it cant find the 2 other scripts.
I fixed the issue by typing the full path of the 2 scripts inside the first script.
but anyone have an idea why this issue occuers.
one more quistion when i used ansible hosts file to define hosts and variables it didnt worked with INI like this:
[webservers]
www[01:50].example.com
It only woks In YAML:
...
webservers:
hosts:
www[01:50].example.com:
Anyone know why?
About the script not finding the other two scripts, you should update the full path to the other two scripts if the path is always fixed OR if you want to use the relative path, you can try the following,
- name: Execute the script
become: true
command: sh install.sh
args:
chdir: /home/lc/lc/
And the inventory looks fine. Here is a test to confirm.
# cat test.ini
[webservers]
tstsrv[7:8]
# ansible-playbook -i test.ini test.yaml -u admin -k
SSH password:
PLAY [webservers] ***********************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************
ok: [tstsrv8]
ok: [tstsrv7]
TASK [print hostname] ***********************************************************************************************************************************************
changed: [tstsrv8]
changed: [tstsrv7]
PLAY RECAP **********************************************************************************************************************************************************
tstsrv7 : ok=2 changed=1 unreachable=0 failed=0
tstsrv8 : ok=2 changed=1 unreachable=0 failed=0
#
Consider script module dedicated for running scripts on targets, if possible.
With a personal user account (userx) I run the ansible playbook on all my specified hosts. In ansible.cfg the remote user (which can become root) to be used is:
remote_user = ansible
For the remote hosts this all works fine. It connects as the user Ansible, and executes all tasks as wished for, also changing information (like /etc/ssh/sshd_config) which requires root rights.
But now I also want to execute the playbook on the Ansible host itself. I put the following in my inventory file:
localhost ansible_connection=local
which now indeed executes on localhost. But as userx, and this results in "Access denied" for some task it needs to do.
This is of course somewhat expected, since remote_user tells something about remote, not the local user. But still, I expected that the playbook would --become locally too, to execute the tasks as root (e.g. sudo su -). It seems no to do that.
Running the playbook with --become -vvv tells me
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: userx
and it seems not to try to execute the tasks with sudo. And without using sudo, the task fails.
How can I tell ansible to to use sudo / become on the local connection too?
Nothing special is required. Proof:
The playbook:
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- command: whoami
register: whoami
- debug:
var: whoami.stdout
The execution line:
ansible-playbook playbook.yml --become
The result:
PLAY [localhost] ***************************************************************************************************
TASK [command] *****************************************************************************************************
changed: [localhost]
TASK [debug] *******************************************************************************************************
ok: [localhost] => {
"changed": false,
"whoami.stdout": "root"
}
PLAY RECAP *********************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
The ESTABLISH LOCAL CONNECTION FOR USER: message will always show the current user, as it the account used "to connect".
Later the command(s) called from the module get(s) executed with elevated permissions.
Of course, you can add become: yes on either play level or for individual tasks.
After running the the below Ansible Yaml file the output shows file is created and the content is changed
The YAML File
---
- hosts: all
gather_facts: yes
connection: local
tasks:
- name: Check the date on the server.
action: command touch /opt/b
- name: cat the Content
action: command cat /opt/b
Running the Playbook
root#my-ubuntu:/var/lib/awx/projects/test# ansible-playbook main.yml
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [ansible-ubuntu-1604-db]
TASK [Check the date on the server.] *******************************************
changed: [ansible-ubuntu-1604-db]
[WARNING]: Consider using file module with state=touch rather than running touch
TASK [cat the Content] *********************************************************
changed: [ansible-ubuntu-1604-db]
PLAY RECAP *********************************************************************
ansible-ubuntu-1604-db : ok=3 changed=2 unreachable=0 failed=0
The Message Display changed=2 and tasks doesnt created any file
ubuntu#ansible-ubuntu-1604-db:~$ ls -l /opt/
total 0
The Env
Ansible Controller on the MAC Local Desktop
Taget Node is on Cloud
With connection: local in your playbook, you tell Ansible to execute all tasks on your local ansible controller. So file is created on your local machine.
Remove connection: local and try again.
I have a playbook and I want to run it with sudo. It is my ansible playbook:
site.yml
---
- name: Server
hosts: node1
sudo: yes
roles:
- dbserver
When I run it I get this:
ansible-playbook -i hosts site.yml
PLAY [Server] *****************************************************************
GATHERING FACTS ***************************************************************
fatal: [node1] => Missing sudo password
TASK: [dbserver | installing server] ******************************************
FATAL: no hosts matched or all hosts have already failed -- aborting
PLAY RECAP ********************************************************************
to retry, use: --limit #/home/robe/site.retry
node1 : ok=0 changed=0 unreachable=1 failed=0
Then I add the ansible sudo pass on site.yml:
---
- name: Server
hosts: node1
sudo_pass: ubuntu
roles:
- dbserver
I get this error:
ERROR: sudo_pass is not a legal parameter at this level in an Ansible Playbook
Then my questions are:
Do I have add to each tasks the ansible sudo_pass attribute?
Is there any way to say sudo and sudo_pass in the playbook?
sudo_pass is not something Ansible knows. If you need to enter a sudo password on node1, then you keep sudo: yes in the playbook, and you'll have to give Ansible the sudo password on the commandline when running your playbook:
ansible-playbook -i hosts site.yml -K
Note the -K parameter. It will then ask you for the sudo password before the playbook starts.
(the long version is --ask-sudo-pass by the way. I had to look that up)