Add auth and remote connections support to MongoDB

Add options to provide admin user login and
password to be used while managing databases
and users.

Admin user should have at least permissions
'root' and 'restore'.

If there is no admin user mongo will work
in 'localhost exception' mode allowing
administration from the local interface.

Closes-Bug: 1354494

Change-Id: I253ee50523fba66586e7a42a7f0772adebe96e83
This commit is contained in:
Dmitry Ilyin 2014-08-11 20:43:14 +04:00 committed by Vladimir Kuklin
parent bce9efc948
commit 21e1efbe9c
8 changed files with 210 additions and 52 deletions

View File

@ -0,0 +1,61 @@
module MongoCommon
def mongo_local(cmd, database = @resource[:admin_database], username = @resource[:admin_username], password = @resource[:admin_password])
mongo_cmd = [
@resource[:mongo_path],
'--quiet',
'--eval',
cmd,
database,
]
output = Puppet::Util::Execution.execute(mongo_cmd, :failonfail => false, :combine => false)
rc = $?.exitstatus
Puppet.debug "Local Mongo: #{cmd} -> #{rc}: #{output}"
[output, rc]
end
def mongo_remote(cmd, database = @resource[:admin_database], username = @resource[:admin_username], password = @resource[:admin_password])
mongo_cmd = [
@resource[:mongo_path],
'--username',
username,
'--password',
password,
'--host',
@resource[:admin_host],
'--port',
@resource[:admin_port],
'--quiet',
'--eval',
cmd,
database,
]
output = Puppet::Util::Execution.execute(mongo_cmd, :failonfail => false, :combine => false)
rc = $?.exitstatus
Puppet.debug "Remote Mongo: #{cmd} -> #{rc}: #{output}"
[output, rc]
end
def mongo(cmd, database = @resource[:admin_database], username = @resource[:admin_username], password = @resource[:admin_password])
output, rc = mongo_remote(cmd, database,username,password)
return output if rc == 0
output, rc = mongo_local(cmd, database,username,password)
return output if rc == 0
raise Puppet::ExecutionFailure, output
end
def block_until_mongodb(tries = 10)
begin
mongo('db.getMongo()')
rescue => e
debug('MongoDB server not ready, retrying')
sleep 2
if (tries -= 1) > 0
retry
else
raise e
end
end
end
end

View File

@ -1,32 +1,26 @@
Puppet::Type.type(:mongodb_database).provide(:mongodb) do
require File.join(File.dirname(__FILE__), '..', 'common.rb')
desc "Manages MongoDB database."
defaultfor :kernel => 'Linux'
commands :mongo => 'mongo'
def block_until_mongodb(tries = 10)
begin
mongo('--quiet', '--eval', 'db.getMongo()')
rescue
debug('MongoDB server not ready, retrying')
sleep 2
retry unless (tries -= 1) <= 0
end
end
include MongoCommon
def create
mongo(@resource[:name], '--quiet', '--eval', "db.dummyData.insert({\"created_by_puppet\": 1})")
Puppet.debug "mongo_database: #{@resource[:name]} create"
mongo('db.dummyData.insert({"created_by_puppet": 1})', @resource[:name])
end
def destroy
mongo(@resource[:name], '--quiet', '--eval', 'db.dropDatabase()')
Puppet.debug "mongo_database: #{@resource[:name]} destroy"
mongo('db.dropDatabase()', @resource[:name])
end
def exists?
Puppet.debug "mongo_database: '#{@resource[:name]}' exists?"
block_until_mongodb(@resource[:tries])
mongo("--quiet", "--eval", 'db.getMongo().getDBNames()').split(",").include?(@resource[:name])
current_databases = mongo('db.getMongo().getDBNames()').strip.split(',')
exists = current_databases.include?(@resource[:name])
Puppet.debug "mongo_database: '#{@resource[:name]}' all: #{current_databases.inspect} '#{@resource[:name]}' exists? #{exists}"
exists
end
end

View File

@ -1,48 +1,49 @@
Puppet::Type.type(:mongodb_user).provide(:mongodb) do
require File.join(File.dirname(__FILE__), '..', 'common.rb')
desc "Manage users for a MongoDB database."
defaultfor :kernel => 'Linux'
commands :mongo => 'mongo'
def block_until_mongodb(tries = 10)
begin
mongo('--quiet', '--eval', 'db.getMongo()')
rescue
debug('MongoDB server not ready, retrying')
sleep 2
retry unless (tries -= 1) <= 0
end
end
include MongoCommon
def create
mongo(@resource[:database], '--eval', "db.system.users.insert({user:\"#{@resource[:name]}\", pwd:\"#{@resource[:password_hash]}\", roles: #{@resource[:roles].inspect}})")
Puppet.debug "mongodb_user: #{@resource[:name]} database '#{@resource[:database]}' create"
mongo("db.getMongo().getDB('#{@resource[:database]}').system.users.insert({user:'#{@resource[:name]}', pwd:'#{@resource[:password_hash]}', roles: #{@resource[:roles].inspect}})")
end
def destroy
mongo(@resource[:database], '--quiet', '--eval', "db.removeUser(\"#{@resource[:name]}\")")
Puppet.debug "mongodb_user: #{@resource[:name]} database '#{@resource[:database]}' destroy"
mongo("db.getMongo().getDB('#{@resource[:database]}').removeUser('#{@resource[:name]}')")
end
def exists?
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' exists?"
block_until_mongodb(@resource[:tries])
mongo(@resource[:database], '--quiet', '--eval', "db.system.users.find({user:\"#{@resource[:name]}\"}).count()").strip.eql?('1')
exists = mongo("db.getMongo().getDB('#{@resource[:database]}').system.users.find({user:'#{@resource[:name]}'}).count()").strip.to_i > 0
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' exists? #{exists}"
exists
end
def password_hash
mongo(@resource[:database], '--quiet', '--eval', "db.system.users.findOne({user:\"#{@resource[:name]}\"})[\"pwd\"]").strip
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' password_hash get"
hash = mongo("db.getMongo().getDB('#{@resource[:database]}').system.users.findOne({user:'#{@resource[:name]}'})['pwd']").strip
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' password_hash: #{hash}"
hash
end
def password_hash=(value)
mongo(@resource[:database], '--quiet', '--eval', "db.system.users.update({user:\"#{@resource[:name]}\"}, { $set: {pwd:\"#{value}\"}})")
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' password_hash set #{value.inspect}"
mongo("db.getMongo().getDB('#{@resource[:database]}').system.users.update({user:'#{@resource[:name]}'}, { $set: {pwd:'#{value}'}})")
end
def roles
mongo(@resource[:database], '--quiet', '--eval', "db.system.users.findOne({user:\"#{@resource[:name]}\"})[\"roles\"]").strip.split(",").sort
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' roles get"
roles = mongo("db.getMongo().getDB('#{@resource[:database]}').system.users.findOne({user:'#{@resource[:name]}'})['roles']").strip.split(',').sort
Puppet.debug "mongodb_user: '#{@resource[:name]}' roles: #{roles.inspect}"
roles
end
def roles=(value)
mongo(@resource[:database], '--quiet', '--eval', "db.system.users.update({user:\"#{@resource[:name]}\"}, { $set: {roles: #{@resource[:roles].inspect}}})")
Puppet.debug "mongodb_user: '#{@resource[:name]}' database '#{@resource[:database]}' roles set #{value.inspect}"
mongo("db.getMongo().getDB('#{@resource[:database]}').system.users.update({user:'#{@resource[:name]}'}, { $set: {roles: #{@resource[:roles].inspect}}})")
end
end

View File

@ -8,6 +8,35 @@ Puppet::Type.newtype(:mongodb_database) do
newvalues(/^\w+$/)
end
newparam(:admin_username) do
desc "Administrator user login"
defaultto 'admin'
end
newparam(:admin_password) do
desc "Administrator user password"
end
newparam(:admin_host) do
desc "Connect to this host as an admin user"
defaultto 'localhost'
end
newparam(:admin_port) do
desc "Connect to this port as an admin user"
defaultto '27017'
end
newparam(:admin_database) do
desc "Connect to this database as an admin user"
defaultto 'admin'
end
newparam(:mongo_path) do
desc "Path to mongo binary"
defaultto '/usr/bin/mongo'
end
newparam(:tries) do
desc "The maximum amount of two second tries to wait MongoDB startup."
defaultto 10
@ -17,4 +46,11 @@ Puppet::Type.newtype(:mongodb_database) do
end
end
autorequire(:package) do
'mongodb'
end
autorequire(:service) do
'mongodb'
end
end

View File

@ -13,6 +13,35 @@ Puppet::Type.newtype(:mongodb_user) do
desc "The name of the user."
end
newparam(:admin_username) do
desc "Administrator user login"
defaultto 'admin'
end
newparam(:admin_password) do
desc "Administrator user password"
end
newparam(:admin_host) do
desc "Connect to this host as an admin user"
defaultto 'localhost'
end
newparam(:admin_port) do
desc "Connect to this port as an admin user"
defaultto '27017'
end
newparam(:mongo_path) do
desc "Path to mongo binary"
defaultto '/usr/bin/mongo'
end
newparam(:admin_database) do
desc "Connect to this database as an admin user"
defaultto 'admin'
end
newparam(:database) do
desc "The user's target database."
defaultto do
@ -53,4 +82,11 @@ Puppet::Type.newtype(:mongodb_user) do
newvalue(/^\w+$/)
end
autorequire(:package) do
'mongodb'
end
autorequire(:service) do
'mongodb'
end
end

View File

@ -16,12 +16,20 @@ define mongodb::db (
$password = false,
$roles = ['dbAdmin'],
$tries = 10,
$admin_username = undef,
$admin_password = undef,
$admin_host = undef,
$admin_database = undef,
) {
mongodb_database { $name:
ensure => present,
tries => $tries,
require => Class['mongodb::server'],
admin_username => $admin_username,
admin_password => $admin_password,
admin_host => $admin_host,
admin_database => $admin_database,
require => Class['mongodb::server'],
}
if $password_hash {
@ -29,7 +37,7 @@ define mongodb::db (
} elsif $password {
$hash = mongodb_password($user, $password)
} else {
fail("Parameter 'password_hash' or 'password' should be provided.")
fail("Parameter 'password_hash' or 'password' should be provided to mongodb::db.")
}
mongodb_user { $user:
@ -37,6 +45,10 @@ define mongodb::db (
password_hash => $hash,
database => $name,
roles => $roles,
admin_username => $admin_username,
admin_password => $admin_password,
admin_host => $admin_host,
admin_database => $admin_database,
require => Mongodb_database[$name],
}

View File

@ -12,9 +12,6 @@ class openstack::mongo (
$use_syslog = true,
) {
# notify {"MongoDB params: $ceilometer_user $ceilometer_database $ceilometer_db_password": }
class {'::mongodb::client':
} ->
@ -30,14 +27,32 @@ class openstack::mongo (
user => $ceilometer_user,
password => $ceilometer_db_password,
roles => ['readWrite', 'dbAdmin', 'dbOwner'],
admin_username => 'admin',
admin_password => $ceilometer_db_password,
admin_database => 'admin',
} ->
mongodb::db { 'admin':
user => 'admin',
password => $ceilometer_db_password,
roles => ['userAdmin','readWrite', 'dbAdmin', 'dbAdminAnyDatabase', 'readAnyDatabase', 'readWriteAnyDatabase', 'userAdminAnyDatabase', 'clusterAdmin', 'clusterManager', 'clusterMonitor', 'hostManager', 'root' ],
roles => [
'userAdmin',
'readWrite',
'dbAdmin',
'dbAdminAnyDatabase',
'readAnyDatabase',
'readWriteAnyDatabase',
'userAdminAnyDatabase',
'clusterAdmin',
'clusterManager',
'clusterMonitor',
'hostManager',
'root',
'restore',
],
admin_username => 'admin',
admin_password => $ceilometer_db_password,
admin_database => 'admin',
}
#notify {"mongo: $ceilometer_db_password": }
}

View File

@ -48,11 +48,10 @@ class openstack::mongo_primary (
mongodb::db { $ceilometer_database:
user => $ceilometer_user,
password => $ceilometer_db_password,
roles => [
'readWrite',
'dbAdmin',
'dbOwner'
],
roles => [ 'readWrite', 'dbAdmin', 'dbOwner' ],
admin_username => 'admin',
admin_password => $ceilometer_db_password,
admin_database => 'admin',
} ->
mongodb::db { 'admin':
@ -70,8 +69,12 @@ class openstack::mongo_primary (
'clusterManager',
'clusterMonitor',
'hostManager',
'root'
'root',
'restore',
],
admin_username => 'admin',
admin_password => $ceilometer_db_password,
admin_database => 'admin',
} ->
notify {"mongodb primary finished": }