From 324c291b3f565e40daad4618567290678fff7cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Gali=C4=87?= Date: Fri, 4 Jul 2014 14:35:32 +0200 Subject: [PATCH] defined type for creating database schemas This defined type helps create database schemas, and assign them to an `owner`. It is closely modeled after Postgresql::Server::Tablespace. It uses PostgreSQL's builtin IF NOT EXISTS to guarantee idempotency. (>= 9.3, else it checks pg_namespace). n.b.: This defined type *requires* that a `db` is passed. This is a concious design decision, since we find it rather useless to create such schemas in the default `postgres` database, and if *were* useful, one can always "over-specify". This addresses MODULES-1098. --- README.md | 24 ++++++++++ manifests/server/schema.pp | 44 ++++++++++++++++++ spec/acceptance/server/schema_spec.rb | 61 +++++++++++++++++++++++++ spec/unit/defines/server/schema_spec.rb | 32 +++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 manifests/server/schema.pp create mode 100644 spec/acceptance/server/schema_spec.rb create mode 100644 spec/unit/defines/server/schema_spec.rb diff --git a/README.md b/README.md index e7e3e78..fd61d2d 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,7 @@ Resources: * [postgresql::server::database_grant](#resource-postgresqlserverdatabasegrant) * [postgresql::server::pg_hba_rule](#resource-postgresqlserverpghbarule) * [postgresql::server::role](#resource-postgresqlserverrole) +* [postgresql::server::schema](#resource-postgresqlserverschema) * [postgresql::server::table_grant](#resource-postgresqlservertablegrant) * [postgresql::server::tablespace](#resource-postgresqlservertablespace) * [postgresql::validate_db_connection](#resource-postgresqlvalidatedbconnection) @@ -735,6 +736,29 @@ Specifies how many concurrent connections the role can make. Defaults to `-1` me ####`username` The username of the role to create, defaults to `namevar`. +###Resource: postgresql::server::schema +This defined type can be used to create a schema. For example: + + postgresql::server::schema { 'isolated': + owner => 'jane', + db => 'janedb', + } + +It will create the schema `jane` in the database `janedb` if neccessary, +assigning the user `jane` ownership permissions. + +####`namevar` +The schema name to create. + +###`db` +Name of the database in which to create this schema. This must be passed. + +####`owner` +The default owner of the schema. + +####`schema` +Name of the schma. Defaults to `namevar`. + ###Resource: postgresql::server::table\_grant This defined type manages grant based access privileges for users. Consult the PostgreSQL documentation for `grant` for more information. diff --git a/manifests/server/schema.pp b/manifests/server/schema.pp new file mode 100644 index 0000000..ea05a97 --- /dev/null +++ b/manifests/server/schema.pp @@ -0,0 +1,44 @@ +# This defined types creates database schemas. See README.md for more details. +define postgresql::server::schema( + $db, + $owner = undef, + $schema = $title, +) { + $user = $postgresql::server::user + $group = $postgresql::server::group + $port = $postgresql::server::port + $psql_path = $postgresql::server::psql_path + $version = $postgresql::server::version + + Postgresql_psql { + db => $db, + psql_user => $user, + psql_group => $group, + psql_path => $psql_path, + port => $port, + } + + $schema_title = "Create Schema '${schema}'" + $authorization = $owner? { + undef => '', + default => "AUTHORIZATION \"${owner}\"", + } + + if(versioncmp($version, '9.3') >= 0) { + $schema_command = "CREATE SCHEMA IF NOT EXISTS \"${schema}\" ${authorization}" + $unless = undef + } else { + $schema_command = "CREATE SCHEMA \"${schema}\" ${authorization}" + $unless = "SELECT nspname FROM pg_namespace WHERE nspname='${schema}'" + } + + postgresql_psql { $schema_title: + command => $schema_command, + unless => $unless, + require => Class['postgresql::server'], + } + + if($owner != undef and defined(Postgresql::Server::Role[$owner])) { + Postgresql::Server::Role[$owner]->Postgresql_psql[$schema_title] + } +} diff --git a/spec/acceptance/server/schema_spec.rb b/spec/acceptance/server/schema_spec.rb new file mode 100644 index 0000000..d70e04e --- /dev/null +++ b/spec/acceptance/server/schema_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper_acceptance' + +describe 'postgresql::server::schema:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + after :all do + # Cleanup after tests have ran + apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true) + end + + it 'should create a schema for a user' do + begin + pp = <<-EOS.unindent + $db = 'schema_test' + $user = 'psql_schema_tester' + $password = 'psql_schema_pw' + + class { 'postgresql::server': } + + # Since we are not testing pg_hba or any of that, make a local user for ident auth + user { $user: + ensure => present, + } + + postgresql::server::role { $user: + password_hash => postgresql_password($user, $password), + } + + postgresql::server::database { $db: + owner => $user, + require => Postgresql::Server::Role[$user], + } + + # Create a rule for the user + postgresql::server::pg_hba_rule { "allow ${user}": + type => 'local', + database => $db, + user => $user, + auth_method => 'ident', + order => 1, + } + + postgresql::server::schema { $user: + db => $db, + owner => $user, + require => Postgresql::Server::Database[$db], + } + EOS + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the user can create a table in the database + psql('--command="create table psql_schema_tester.foo (foo int)" schema_test', 'psql_schema_tester') do |r| + expect(r.stdout).to match(/CREATE TABLE/) + expect(r.stderr).to eq('') + end + ensure + psql('--command="drop table psql_schema_tester.foo" schema_test', 'psql_schema_tester') + end + end + +end diff --git a/spec/unit/defines/server/schema_spec.rb b/spec/unit/defines/server/schema_spec.rb new file mode 100644 index 0000000..f5d106f --- /dev/null +++ b/spec/unit/defines/server/schema_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe 'postgresql::server::schema', :type => :define do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6.0', + :kernel => 'Linux', + :concat_basedir => tmpfilename('schema'), + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + } + end + + let :title do + 'test' + end + + let :params do + { + :owner => 'jane', + :db => 'janedb', + } + end + + let :pre_condition do + "class {'postgresql::server':}" + end + + it { should contain_postgresql__server__schema('test') } +end