I've got a playbook that includes and tags various roles:
- name: base
hosts: "{{ host | default('localhost') }}"
roles:
- { role: apt, tags: [ 'base', 'apt', 'ubuntu']}
- { role: homebrew, tags: [ 'base', 'homebrew', osx' ]}
- { role: base16, tags: [ 'base', 'base16', 'osx' ]}
- { role: nodejs, tags: [ 'base', 'nodejs' ]}
- { role: tmux, tags: [ 'base', 'tmux' ]}
- { role: vim, tags: [ 'base', 'vim' ]}
- { role: virtualenv, tags: [ 'base', virtualenv', 'python' ]}
- { role: homebrew_cask, tags: [ 'desktop', 'homebrew_cask', osx' ]}
- { role: gnome_terminator, tags: [ 'desktop', 'gnome_terminator', ubuntu' ]}
Most of the tasks are using when clauses to determine which OS they should run on, for example:
- name: install base packages
when: ansible_distribution == 'MacOSX'
sudo: no
homebrew:
name: "{{ item.name }}"
state: latest
install_options: "{{ item.install_options|default() }}"
with_items: homebrew_packages
If I run ansible-playbook base.yml without specifying any tags, all the tasks run. If I specify a tag, for example ansible-playbook base.yml --tags='base', only the roles tagged with base run.
By default (if no tags are specified), I'd only like to run the roles tagged with 'base', and not the roles tagged with 'desktop'.
It would also be really nice to set a default 'os' tag, based on the current operating system, to avoid including all the tasks for the ubuntu when I'm running the playbook on OSX (and vice-versa).
Any ideas if this is possible, and how I might do it?
Since Ansible 2.5 there is a new feature which solves these kinds of situations.
Another special tag is never, which will prevent a task from running
unless a tag is specifically requested.
Example:
tasks:
- debug: msg='{{ showmevar}}'
tags: [ 'never', 'debug' ]
So your problem should be addressed like this:
- name: base
hosts: "{{ host | default('localhost') }}"
roles:
- { role: apt, tags: [ 'base', 'apt', 'ubuntu']}
- { role: homebrew, tags: [ 'base', 'homebrew', osx' ]}
- { role: base16, tags: [ 'base', 'base16', 'osx' ]}
- { role: nodejs, tags: [ 'base', 'nodejs' ]}
- { role: tmux, tags: [ 'base', 'tmux' ]}
- { role: vim, tags: [ 'base', 'vim' ]}
- { role: virtualenv, tags: [ 'base', virtualenv', 'python' ]}
- { role: homebrew_cask, tags: [ 'never','desktop', 'homebrew_cask', osx' ]}
- { role: gnome_terminator, tags: [ 'never','desktop', 'gnome_terminator', ubuntu' ]}
Unfortunately there is no such feature. Tag handling in Ansible currently is very limited. You can not set default tags and you can not exclude tags by default.
There are some threads on the Google user group and feature requests on github regarding this. But no outcome yet. The common answer so far is, you should create a shell script and place it in front of your playbook. This script then can set the --tags and --skip-tags accordingly to your needs. Very unpleasant but as far as I know the only option right now.
If I run ansible-playbook base.yml without specifying any tags, all the tasks run.
Yes, this is very dangerous.
If You forget to add '--tags=xxxxx' it may run unwanted tasks...
There is a workaround, it's nasty, but it would prevent running Your tasks when there are no tags in commandline.
You could use --extra-vars and use it in your playbook, then run:
ansible-playbook base.yml -e'SOMEVAR=TRUE'
And in Your playbook:
- hosts: localhost
tasks:
- name: some task
ping:
tags:
- sometag
- name: Register SOMEVARANS
set_fact: SOMEVARANS={{SOMEVAR | default('False')}}
tags:
- every_tag_you_know_since_there_is_no_ALL_option
- sometag
- debug: msg="{{SOMEVARANS}}"
tags:
- every_tag_you_know_since_there_is_no_ALL_option
- sometag
- debug: msg="run only with extravars SOMEVAR=True"
when: SOMEVARANS
tags:
- every_tag_you_know_since_there_is_no_ALL_option
- sometag
The result:
$ ansible-playbook -i /subsystem/ansible/etc/inventory-qa.ini tags.yml
PLAY [localhost] **************************************************************
TASK: [some task] *************************************************************
ok: [localhost]
TASK: [Register SOMEVARANS] ***************************************************
ok: [localhost]
TASK: [debug msg="{{SOMEVARANS}}"] ********************************************
ok: [localhost] => {
"msg": "False"
}
TASK: [debug msg="run only with extravars SOMEVAR=True"] **********************
skipping: [localhost]
PLAY RECAP ********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
WITH 'SOMEVAR=True'
$ ansible-playbook -i /subsystem/ansible/etc/inventory-qa.ini tags.yml -e 'SOMEVAR=True'
PLAY [localhost] **************************************************************
TASK: [some task] *************************************************************
ok: [localhost]
TASK: [Register SOMEVARANS] ***************************************************
ok: [localhost]
TASK: [debug msg="{{SOMEVARANS}}"] ********************************************
ok: [localhost] => {
"msg": "True"
}
TASK: [debug msg="run only with extravars SOMEVAR=True"] **********************
ok: [localhost] => {
"msg": "run only with extravars SOMEVAR=True"
}
PLAY RECAP ********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
ALL IN ONE :)
$ ansible-playbook -i /subsystem/ansible/etc/inventory-qa.ini tags.yml -e 'SOMEVAR=True' --tags=sometag
PLAY [localhost] **************************************************************
TASK: [some task] *************************************************************
ok: [localhost]
TASK: [Register SOMEVARANS] ***************************************************
ok: [localhost]
TASK: [debug msg="{{SOMEVARANS}}"] ********************************************
ok: [localhost] => {
"msg": "True"
}
TASK: [debug msg="run only with extravars SOMEVAR=True"] **********************
ok: [localhost] => {
"msg": "run only with extravars SOMEVAR=True"
}
PLAY RECAP ********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
I use command-line variable overrides (-e) to achieve this:
$ ansible-playbook playbook.xml -e desktop=true
Rather than define desktop as a tag, it could instead be defined as a variable with a default value of false. Then, for roles requiring desktop to be true, replace the tag with a when clause. The playbook posted in the question might be rewritten like this:
- name: base
hosts: "{{ host | default('localhost') }}"
# default value to prevent errors when not overridden
vars:
desktop: false
roles:
# no change to "base" roles
- { role: apt, tags: [ 'base', 'apt', 'ubuntu'] }
# ...
# "desktop" roles get a "when" clause
- role: homebrew_cask
when: desktop | bool
tags: [ 'homebrew_cask', 'osx' ]
- role: gnome_terminator
when: desktop | bool
tags: [ 'gnome_terminator', ubuntu' ]
This is probably just a simplified version of one of the existing answers. As stated elsewhere, tags aren't the answer at this time to defaulting some actions to not run unless something is explicitly specified. Variables, on the other hand, are perfect for this.
There are another 3 special keywords for tags, ‘tagged’, ‘untagged’ and ‘all’, which run only tagged, only untagged and all tasks respectively.
By default ansible runs as if ‘–tags all’ had been specified.
You can check the docs here: http://docs.ansible.com/ansible/playbooks_tags.html#special-tags
The reason to use default usually is: I want to type as less as possible in my most common use case. So I think what OP actually want is:
Are there ways to run 'base' tasks with as less arguments as possible.
As others pointed out, there are no "default" tag in ansible. But there are always ways.
First way is just use script to wrap it, like
writing a run.sh like this:
ansible-playbook -t base base.yml
It is much shorter to type ./run.sh instead of full command.
Second way is for the people that is looking for the pure ansible solution. You can have two playbooks like:
base.yml
- { role: apt, tags: [ 'base', 'apt', 'ubuntu']}
- { role: homebrew, tags: [ 'base', 'homebrew', osx' ]}
- { role: base16, tags: [ 'base', 'base16', 'osx' ]}
- { role: nodejs, tags: [ 'base', 'nodejs' ]}
- { role: tmux, tags: [ 'base', 'tmux' ]}
- { role: vim, tags: [ 'base', 'vim' ]}
- { role: virtualenv, tags: [ 'base', virtualenv', 'python' ]}
desktop.yml
- { role: homebrew_cask, tags: [ 'desktop', 'homebrew_cask', osx' ]}
- { role: gnome_terminator, tags: [ 'desktop', 'gnome_terminator', ubuntu' ]}
For base only tasks, run ansible-playbook base.yml;
for desktop only tasks, run ansible-playbook desktop.yml;
for all tasks, run ansible-playbook base.yml desktop.yml
It is also more error-prone than defining a 'default' tag.
OP also wants a default OS tag. It is easy to achieve that with when
- { role: some_role, when: "ansible_os_family == 'Debian'" }
with when, you don't need to do anything in command line, ansible detects the type and runs corresponding tasks for you.
Related
I always get this error trying to connect to the Mongodb
MongoDB Response
server selection error: server selection timeout, current topology: { Type: ReplicaSetN
oPrimary, Servers: [{ Addr: mongodb:27017, Type: Unknown, Last error: connection() error occured during connection handshake: dial tcp: lookup mongodb: no such host }, ] }
MongoDB Log
mongodb | 2022-03-08T06:40:26.387+0000 I NETWORK [conn14]
received client metadata from 172.25.0.1:39218 conn14: { driver: {
name: "mongo-go-driver", version: "v1.8.3" }, os: { type: "windows",
architecture: "amd64" }, platform: "go1.17.5" }
Here is how I set up
docker-compoes.yml
mongodb:
container_name: mongodb
build: ./mongo
ports:
- 27017:27017
environment:
- MONGODB_USER=debezium
- MONGODB_PASSWORD=dbz
networks:
- pg-es-synch_default
Dockerfile
FROM mongo:3.6
CMD ["mongod", "--replSet", "rs0", "--auth"]
Command
>> mongo localhost:27017/ecommerce_connect
rs.initiate({
_id: "rs0",
members: [ { _id: 0, host: "mongodb:27017" } ]
});
>> mongo localhost:27017/admin
db.createUser({ user: 'admin', pwd: 'admin', roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] });
>> mongo -u admin -p admin localhost:27017/admin
db.createUser({
user:
'debezium',
pwd: 'dbz',
roles: [
{ role: "readWrite", db: "ecommerce_connect" },
{ role: "readWrite", db: "local" },
{ role: "root", db: "admin" },
{ role: "readWrite", db: "config" },
]
});
When I login by user debezium outside Docker in the localhost I always got the error mentioned above.
But if I do this in CLI of Docker, It works
>> mongo -u debezium -p dbz --authenticationDatabase admin localhost:27017/ecommerce_connect
use ecommerce_connect;
db.product_info.insert([
{ _id : NumberLong("128"), name : 'scooter', description: 'Small 2-wheel scooter', weight : 3.14, quantity : NumberInt("3") }
]);
I connect to mongoDB by this URL:
"mongodb://debezium:dbz#localhost:27017"
I am trying to create a docker-compose file for MongoDB after checking out multiple examples on the web and this is my configuration. However after executing docker-compose up command, when trying to login using any of the below credentials in Compass at localhost:37017, I am getting the error:
UserNotFound: Could not file user "dbAdmin" for db "admin"
Folder structure
mongo [directory]
docker-entrypoint-initdb.d [directory]
mongo-init.js
mongo-volume [directory]
docker-compose.yml
docker-compose.yml content:
version: '3'
services:
mongoDB:
image: 'mongo:latest'
container_name: 'app-mongo'
environment:
- MONGO_INITDB_ROOT_USERNAME=dbAdmin
- MONGO_INITDB_ROOT_PASSWORD=TtUBhMjOIfeV
- MONGO_INITDB_DATABASE=admin
volumes:
- ./docker-entrypoint-initdb.d/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
- ./mongo-volume:/data/db
ports:
- '37017-37019:27017-27019'
mongo-init.js content
let admin = db.getSiblingDB("admin");
admin.createUser({
user : "appAdmin",
password: "TtUBhMjOIfeV",
db: "admin",
roles: [
{
role: "clusterAdmin",
db: "admin"
},
{
role: "userAdminAnyDatabase",
db: "admin"
}
]
});
admin.createCollection("users");
let adppDBName = db.getSiblingDB("appDBName");
appDBName.createUser({
user: "appOwner",
password: "EtMxw6ZY9jiG",
db: "admin",
roles: [
{
role: "readWrite",
db: "appDBName"
}
]
});
appDBName.createCollection("users");
You created a user named appAdmin but are apparently trying to use a user named dbAdmin.
How to create a mongodb user who can read write but not delete a document.
As mistakes can happen so some people may want to disable delete option for users. which can be achieved using the below tutorial.
It took me few minutes to find so sharing so it may reduce some peoples time in searching.
In order to do that we have to create a role.
Go to admin db
use admin
then execute the below command
db.createRole(
{
role: "customROle",
privileges: [
{ resource: { cluster: true }, actions: [ "addShard" ] },
{ resource: { db: "config", collection: "" }, actions: [ "find", "update", "insert"] },
{ resource: { db: "", collection: "" }, actions: [ "update", "insert", "find" ] }
],
roles: [
{ role: "readWrite", db: "admin" }
]
},
{ w: "majority" , wtimeout: 5000 }
)
Note: You can give a specific db access too and give only read access or something like that.
Then we can add the role to a user by using the below command.
db.createUser(
{ user: "gokul",
pwd: "gokul123",
roles:[{role: "customROle" , db:"admin"}]})
everyone,
I'm having a hard time setting up a MongoDB container to have root password and creating a new user with less privileges (that will be my application user) automatically.
Ideally I should have only some scripts and a docker-compose configuration.
I tried adding the MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD but they don't seem to work. They do something, because when I start the container like that, I can't just connect to the mongo shell and run all the commands (and passing username and password will throw unauthorized errors).
Then I thought about adding a script at /docker-entrypoint-initdb.d/ but they dont seem to run. They don't show on console. Besides, i just put a javascript like this and I am not sure whether they will work:
var db = connect("mongodb://localhost/admin");
db.createRole(
{
role: "somerole",
privileges: [
{
actions: [ "find", "update", "insert" ],
resource: { db: "mydb", collection: "" } <--- does it means all colections od database mydb?!?!
}
],
roles: [ ]
}
)
db.createUser(
{
user: "admin",
pwd: "adminpass",
roles: [ { role: "userAdminAnyDatabase", db: "mydb" } ]
}
)
db.createUser(
{
user: "system",
pwd: "systempass",
roles: [ { role: "somerole", db: "mydb" } ]
}
)
I would also want to create collections and insert documents. How do we do that? Shouldn't it be with entrypoints!?
MongoDb Documentation: Security Reference
Partial response 1
Partial response 2
1) Create the following structure of files:
2) Content of docker-compose.yml
version: "3"
services:
mongodb:
image: "mongo:4.1.1-xenial"
restart: "unless-stopped"
env_file:
- ".env"
ports:
- "27017:27017"
volumes:
- "./database/data:/data/db" # Database files
- "./database/fixtures:/docker-entrypoint-initdb.d" # To create Db at start
3) Content of default.js
/* Create a New user with "only READ" role */
db = db.getSiblingDB('admin');
db.createUser(
{
"user": "John",
"pwd": "MyPassword",
"roles": [
{ "role": "read", "db": "data" }
]
})
/* Misc - Other Data */
db = db.getSiblingDB('data');
db.data.save([
{
"name": "Frank",
"email": "email1#gmail.com",
},
{
"name": "Peter",
"email": "email2#gmail.com",
}
]);
4) Content of .env
MONGO_INITDB_ROOT_USERNAME=Robert
MONGO_INITDB_ROOT_PASSWORD=GoodPassword
5) Go to your terminal and at the level of the docker-compose.yml file, execute:sudo docker-compose up -d
6) Get the container's name:
Execute: sudo docker ps a
7) Go inside the container:
Execute: sudo docker exec -it <CONTAINER NAME> bash
8) Inside the container:
Execute: mongo --host localhost -u Robert -p GoodPassword --authenticationDatabase admin
NOTE: Take into account that we are specifying the "authentication database"
9) Select database:
Execute: use admin
10) Show users (You must find two users Robert and John):
Execute: show users
As you can see inside "data" directory are stored the files of the database.
And using the default.js file you can create collections frm the start.
IMPORTANT NOTE: If you make some changes and those are not reflected to the database, then you need to DELETE the content of "data" and run again: docker-compose up -d
We can say that, if "data" directory is not empty, then the "default.js" file will not be taked into account.
I changed a bit your configuration and it runs correctly:
docker-compose.yml:
version: '3.1'
services:
mongo:
image: mongo
restart: always
volumes:
- ./init.js:/docker-entrypoint-initdb.d/init.js
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: mydb
here I specify the database to be created initially and I also mount the init script.
init.js:
var db = connect("mongodb://localhost/mydb");
db.createRole(
{
role: "somerole",
privileges: [
{
actions: [ "find", "update", "insert" ],
resource: { db: "mydb", collection: "" }
}
],
roles: [ ]
}
)
db.createUser(
{
user: "admin",
pwd: "adminpass",
roles: [ { role: "somerole", db: "mydb" } ]
}
)
db.createUser(
{
user: "system",
pwd: "systempass",
roles: [ { role: "somerole", db: "mydb" } ]
}
)
The important part here is the first line, otherwise you create a role in the admin database while you look for it in mydb database.
With this setup I can start the database and connect to it.
First I tried db.eval() for my local mogodb server.It is working fine.I used this example
Then I tried the same thing with MongoLab.But I got this error message.
The error say not authorized to execute command.Can you explain why this error message.thanks
Eval is a powerfull, dangerous and deprecated action that mLab don't give.
In a local mongo db you should create a role:
use admin
db.createRole(
{
role: "dangerEval",
privileges : [
{ resource: {anyResource: true }, actions : ["anyAction"] },
// or this for grant anyAction only on a single db:
{ resource: {db: "myDb", collection: "" }, actions: [ "anyAction" ] }
],
roles: []
}
)
Then you can assign this role to a user:
db.createUser({
user: "temporaneyEvalUser",
pwd: "psw",
roles: [ { role: "dangerEval", db: "myDb" } ]
});
So you have to choose another way to archive your target or change mongo installation.