Create influxdb user using Ansible - ansible

How can I create a user in Influxdb using ansible module ?
In influxdb ansible docs , I could not find that how to create a user.
I am trying to create it via influxdb API, but have not got success in that.
- name: create user in influxdb
uri:
url: "http://localhost:8086/query"
method: POST
body: "--data-urlencode 'q=CREATE USER myuser WITH PASSWORD 'mypass' WITH ALL PRIVILEGES'"
body_format: raw
The response is,
fatal: [192.168.122.62]: FAILED! => {"changed": false, "connection": "close", "content": "{\"error\":\"missing required parameter \\\"q\\\"\"}\n", "content_length": "45", "content_type": "application/json", "date": "Wed, 05 Jul 2017 12:08:26 GMT", "failed": true, "json": {"error": "missing required parameter \"q\""}, "msg": "Status code was not [200]: HTTP Error 400: Bad Request", "redirected": false, "request_id": "a6c36bfd-617a-11e7-800c-000000000000", "status": 400, "url": "http://localhost:8086/query", "x_influxdb_version": "1.2.2"}

I had a nightmare with quotes... BUT this one worked for me:
- name: "[Centos7_InfluxDB] Create InfluxDB user"
command: 'influx -database {{item.database}} -execute "CREATE USER {{item.user}} WITH PASSWORD
{{item.pass}} WITH ALL PRIVILEGES"'
with_items:
- { database: "sample_database", user: "adminuser", pass: "'adminpass'" }

This code should work as you expect :
- name: create user in influxdb
uri:
url: "http://localhost:8086/query"
method: POST
body: "q=CREATE USER myuser WITH PASSWORD 'mypass' WITH ALL PRIVILEGES"

You can easily create a user using the command module.
- name: Create InfluxDB user
command: "influx -execute \"CREATE USER {{item.user}} WITH PASSWORD
'{{item.pass}}' WITH ALL PRIVILEGES\""
with_items:
- { user: 'admin', pass: 'admin' }
This should be a lot more efficient than using the REST api.

If anyone's wondering about that as well - just keep in mind that there are community modules for Ansible that already do everything you want, without having to do it with raw/command modules

Related

Ansible uri with faild_when and loop fails

I have a problem with a loop and failed_with in ansible. I don't know why.
The actual failed_when is much more complex, I know i could use status_code in this case.
It is my goal to parse the json response from a local api for multiple (dynamic list I got early from the api) objects and fail if it is not a response I expect.
- name: "get status for items"
uri:
url: https://{{inventory_hostname}}/status
method: POST
body_format: json
body: "{'index': {{item.index}}"
register: this
failed_when: "this.status != 200"
loop: "{{ item_list.json | json_query('[?state== `UNDEFINED`]') }}"
I get the error:
fatal: [localhost]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: 'this' is undefined
The error appears to be in '/home/blablup/Devel/ansible/roles/myrole/tasks/update.yml': line 48, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: "get status for items"
^ here
But if I read the documentation it should work this way. Also if I look at this: Using `failed_when` on a `with_items` task depending on return codes example, failed_when should be evaluated for every iteration.
I am unable to reproduce the behavior you've described. If I wrap your task in sufficient code to run it, like this:
- hosts: localhost
gather_facts: false
vars:
item_list:
json:
- state: UNDEFINED
index: 0
- state: okay
index: 1
- state: UNDEFINED
index: 2
tasks:
- name: "get status for items"
uri:
url: http://localhost:5000/status
method: POST
body_format: json
body: "{'index': {{item.index}}"
register: this
failed_when: "this.status != 200"
loop: "{{ item_list.json | json_query('[?state== `UNDEFINED`]') }}"
And provide a server that will return either a 200 or a 400 response:
from flask import Flask, request, make_response
app = Flask(__name__)
#app.route("/status", methods=["POST"])
def status():
if b"2" in request.data:
return make_response("failed", 400)
else:
return make_response("okay", 200)
Then running your playbook produces the expected behavior (it succeeds when the server delivers a 200 response, and fails when the server returns a non-200 response):
TASK [get status for items] *****************************************************************************
ok: [localhost] => (item={'name': 'foo', 'state': 'UNDEFINED', 'index': 0})
failed: [localhost] (item={'name': 'qux', 'state': 'UNDEFINED', 'index': 2}) => {"ansible_loop_var": "item", "changed": false, "connection": "close", "content_length": "6", "content_type": "text/html; charset=utf-8", "date": "Wed, 12 Oct 2022 00:10:05 GMT", "elapsed": 0, "failed_when_result": true, "item": {"index": 2, "name": "qux", "state": "UNDEFINED"}, "msg": "Status code was 400 and not [200]: HTTP Error 400: BAD REQUEST", "redirected": false, "server": "Werkzeug/2.2.2 Python/3.10.7", "status": 400, "url": "http://localhost:5000/status"}
I'm using Ansible core version 2.12.6.
Unrelated to your question, but this looks suspicious:
body: "{'index': {{item.index}}"
You're not delivering a JSON request body (JSON does not use single quotes and your brackets aren't balanced). You want something like this:
body: {
"index": "{{ item.index }}"
}

Cannot send Slack notification via Ansible

I'm trying to send a Slack notification via Ansible:
- name: Send a custom slack notification
run_once: true
slack:
#s3_backups Slack channel
token: token/stuff/here
attachments:
- text: "S3 Web Server Config Backup Complete."
title: S3 Web Server Backups
color: "#8FCC2C"
delegate_to: localhost
However, I'm getting a fatal error:
TASK [s3_fsn_backend_config_backup : Send a custom slack notification] ********************************************************************************************************************************************
Sorry, try again.
Sorry, try again.
fatal: [webserver-name -> localhost]: FAILED! => {"changed": false, "module_stderr": "[sudo via ansible, key=blahblahblahblahblah] password:[sudo via ansible, key=blahblahblahblahblah] password:sudo: 3 incorrect password attempts\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
Am I using incorrect syntax? I just want it to run from localhost. I definitely don't understand what the Sorry, try again message means.
You can try the following code snippet
- name: Send slack notifications
slack:
token: "{{ slack_token }}"
msg: "Hello World"
channel: "#general"
username: "Ansible"
icon_url: "https://www.ansible.com/favicon.ico"
link_names: 1
parse: "full"
color: "#00ff00"
attachments:
- text: "This is an attachment"
color: "#ff0000"
fields:
- title: "Field 1"
value: "This is an attachment"
short: false
- title: "Field 2"
value: "This is an attachment"
short: false
footer: "Footer"
footer_icon: "https://www.ansible.com/favicon.ico"
ts: 123456789
More details available at slack_module

ansible iam_user deletion does not work

I tried to delete an user by:
- name: "Remove user abc"
iam_user:
name: abc
state: absent
it gave me following error:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: DeleteConflictException: An error occurred (DeleteConflict) when calling the DeleteUser operation: Cannot delete entity, must delete access keys first.
fatal: [localhost]: FAILED! => {
"changed": false,
"error": {
"code": "DeleteConflict",
"message": "Cannot delete entity, must delete access keys first.",
"type": "Sender"
},
"response_metadata": {
"http_headers": {
"content-length": "298",
"content-type": "text/xml",
"date": "Thu, 12 Jul 2018 20:53:02 GMT",
"x-amzn-requestid": "91913df0-8615-11e8-b3e7-b16567885120"
},
"http_status_code": 409,
"request_id": "91913df0-8615-11e8-b3e7-b16567885120",
"retry_attempts": 0
}
}
MSG:
Unable to delete user intelerad-billing-mzhao-client-creator-user: An error occurred (DeleteConflict) when calling the DeleteUser operation: Cannot delete entity, must delete access keys first.
It seems there is even no ansible module to delete access key.
any hints?
AWS IAM APIs are finicky when it comes to user deletion. Deletion can be blocked if the user is assigned access keys or if the user's login profile doesn't exist.
Funny enough, Ansible has two modules that you can use to delete users: iam and iam_user, but one errors on access keys and the other errors on non-existant login profiles.
So let's go ahead and leverage AWS CLI for this one.
This playbook worked for me to create and delete a user with keys.
---
- name: Create / Delete IAM user with keys
hosts: localhost
connection: local
vars:
username: foo
tasks:
- name: Create user with keys
iam:
iam_type: user
name: "{{ username }}"
state: present
access_key_state: create
key_count: 2
- name: Get all the access keys
shell: aws iam list-access-keys --user-name {{ username }} --query 'AccessKeyMetadata[*].AccessKeyId'
register: access_key_list
- name: Delete each key
shell: aws iam delete-access-key --access-key-id {{ item }} --user-name {{ username }}
loop: "{{ access_key_list.stdout | from_json }}"
- name: Delete user
iam_user:
name: "{{ username }}"
state: absent
Note that the deletion task is iam_user. This is because plain iam will error if the user login profile doesn't exist.
Hope that helps!

Ansible error: with_items expects a list or a set

Here is the Ansible source code where with_items is linked to a dictionary type variable named "grafana_datasource_body". I always get an error message "ith_items expects a list or a set". Here is the source code and related output.
Ansible source code :
- name: Configure datasource creation http body
set_fact:
grafana_datasource_body:
name: "{{Ass_grafana_Datasource_Name}}"
type: "{{Ass_grafana_Datasource_Type}}"
isDefault: "{{Ass_grafana_Datasource_IsDefault}}"
access: "{{Ass_grafana_Datasource_Access}}"
basicAuth: "{{Ass_grafana_Datasource_BasicAuth}}"
url: "{{InfluxDB_Server}}:{{Ass_grafana_Datasource_Http_Port}}"
database: "{{Ass_grafana_Datasource_Db}}"
username: "{{Ass_grafana_Datasource_DbUser}}"
password: "{{Ass_grafana_Datasource_DbPassword}}"
when: Ass_grafana_Datasource_Name not in grafana_datasources_output.json|map(attribute='name')|list
- debug: msg="Datasource creation http body = {{grafana_datasource_body}}"
when: Ass_grafana_Datasource_Name not in grafana_datasources_output.json|map(attribute='name')|list
# Create non existing datasources
- name: datasource > Create datasource
register: grafana_datasources_create_output
failed_when: "'Datasource added' not in grafana_datasources_create_output|to_json"
uri:
url: "http://127.0.0.1:{{Ass_grafana_Listen_Http_Port}}/api/datasources"
method: POST
HEADER_Content-Type: application/json
body: '{{ item|to_json }}'
force_basic_auth: true
user: "{{Ass_grafana_Api_User}}"
password: "{{Ass_grafana_Api_Password}}"
status_code: 200
with_items: "{{grafana_datasource_body}}"
when: item.name not in grafana_datasources_output.json|map(attribute='name')|list
Output
TASK: [./grafana/grafana_Role | Configure datasource creation http body] ******
<10.0.20.7> ESTABLISH CONNECTION FOR USER: centos
ok: [10.0.20.7] => {"ansible_facts": {"grafana_datasource_body": {"access": "proxy", "basicAuth": "false", "database": "webcom-int", "isDefault": "true", "name": "MonTonton", "password": "webcom", "type": "influxdb", "url": "http://localhost:8086", "username": "webcom"}}}
TASK: [./grafana/grafana_Role | debug msg="Datasource creation http body = {{grafana_datasource_body}}"] ***
<10.0.20.7> ESTABLISH CONNECTION FOR USER: centos
ok: [10.0.20.7] => {
"msg": "Datasource creation http body = {'username': u'webcom', 'name': u'MonTonton', 'database': u'webcom-int', 'url': u'http://localhost:8086', 'basicAuth': u'false', 'access': u'proxy', 'password': u'webcom', 'type': u'influxdb', 'isDefault': u'true'}"
}
TASK: [./grafana/grafana_Role | datasource > Create datasource] ***************
fatal: [10.0.20.7] => with_items expects a list or a set
FATAL: all hosts have already failed -- aborting
Any real reason to use with_items loop here?
Replace
with_items: "{{grafana_datasource_body}}"
with
with_items: "{{ [grafana_datasource_body] }}"
this will work.
But you can use body: '{{ grafana_datasource_body|to_json }}' and don't use with_items.

Creating an Ubuntu user with Ansible on a Vagrant box fails to create a password

I am trying to create an new user deployer on a vagrant virtual machine that runs ubuntu-16.04 Xenial. The user creation seems to work( the user names are added to /etc/passwd)
$ cat /etc/passwd | grep deployer
deployer1:x:1001:1001::/home/deployer1:/bin/bash
deployer2:x:1002:1003::/home/deployer2:
deployer1000:x:1003:1004::/home/deployer1000:/bin/bash
deployershell:x:1004:1005::/home/deployershell:/bin/bash
However I'm unable to login neither directly via ssh:
$ ssh deployer#local-box-2
deployer#local-box-2's password:
Permission denied, please try again.
deployer#local-box-2's password:
Permission denied, please try again.
nor via su deployer after ssh-ing with an existing user vagrant:
vagrant#local-box-2:~$ su deployer
Password:
su: Authentication failure
I've tried to create the user by using both the ad-hoc ansible commands:
$ ansible all -m user -a 'name=deployer group=admin update_password=always password=rawpass2 state=present shell=/bin/bash force=yes' -u vagrant -b -vvvv
local-box-2 | SUCCESS => {
"append": false,
"changed": true,
"comment": "",
"group": 1001,
"home": "/home/deployer",
"invocation": {
"module_args": {
"append": false,
"comment": null,
"createhome": true,
"expires": null,
"force": true,
"generate_ssh_key": null,
"group": "admin",
"groups": null,
"home": null,
"login_class": null,
"move_home": false,
"name": "deployer1",
"non_unique": false,
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"remove": false,
"seuser": null,
"shell": "/bin/bash",
"skeleton": null,
"ssh_key_bits": 0,
"ssh_key_comment": "ansible-generated on local-box-2",
"ssh_key_file": null,
"ssh_key_passphrase": null,
"ssh_key_type": "rsa",
"state": "present",
"system": false,
"uid": null,
"update_password": "always"
},
"module_name": "user"
},
"move_home": false,
"name": "deployer",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/bash",
"state": "present",
"uid": 1001
}
and by running a playbook
$ ansible-playbook local-box.yml
- name: Add 'deployer' user
hosts: local-box-2
gather_facts: false
remote_user: vagrant
become: true
become_method: sudo
become_user: root
tasks:
- remote_user: vagrant
become: true
become_method: sudo
become_user: root
group:
name: admin
state: present
- remote_user: vagrant
become: true
become_method: sudo
become_user: root
user:
name: deployer
groups: admin
append: yes
shell: /bin/bash
password: rawpass2
state: present
Again, both create the users, but apparently none of them set the password.
What do you the cause might be?
Later Edit:
Apparently, if I pass the raw password to a hash filter then I will be able to login using the (unhashed) raw password. I would love an explaination on why that is the case.
password: "{{ 'rawpass2' | password_hash('sha512') }}"
Note:
This answer gave me the idea to try using filters .
ansible user password should be hashed. https://github.com/ansible/ansible-examples/blob/master/language_features/user_commands.yml
Please follow the document "http://docs.ansible.com/ansible/faq.html#how-do-i-generate-crypted-passwords-for-the-user-module" for has password generation in ansible
- remote_user: vagrant
become: true
become_method: sudo
become_user: root
user:
name: deployer
groups: admin
append: yes
shell: /bin/bash
password: hass_value_of_rawpass2
state: present
To create hash password of rawpass2 as Example:
cmadmin#ansible:~$ mkpasswd --method=sha-512
Password: <rawpass2>
$6dsdwqrc3124JsO9gVJZUWa$sgKxTKz4RbZnIZIvhotWHAHQL1o3/V5LTrrEJCe9DDkTW3Daut.nIpU9Qa0kDWdMZSaxvV1
Ansible is not failing to set the password; the issue is in how passwords work on linux.
A linux user password is stored in a hashed form, the cleartext is not stored anywhere on the system. When you login the password you enter is hashed and compared with the stored value.
When you specify a password during the user creation process in ansible, it must be the already hashed form as noted in the doc links in your question.
If you look at /etc/shadow on the system where you created the user you will see something like this (the second field is the password value):
deployer:rawpass2:17165:0:99999:7:::
which shows you that the string you supplied was used directly as the hashed password value. Of course when you try to login and specify rawpass2, the login code hashes that and compares it to the stored value and they don't match. This is why you have to pass the already hashed value to ansible.

Resources