posgra 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 951beba5dfa0b044ea3b5467f856c20b475e373d
4
- data.tar.gz: 0ad1275dcb66c096037f2f8b3bf5a7817334288f
3
+ metadata.gz: 8af082dbe487f54a35c23d4c39947c58b12f403d
4
+ data.tar.gz: 9cb68ff5f9e321277c31246d6b2631bbfb0d67ce
5
5
  SHA512:
6
- metadata.gz: f5da29a44a9d95f2c9867df4154bebab2d954c54b7d285568bd91c8070fcfb7bfd8a4ef3057b9117357c1767c407c96952594b323a0d7055503ff3af4c1f268a
7
- data.tar.gz: 1cd71973a72a56835041229493e914b751822214ec291e64f81f4f206772a089c834560eace40a1c079cb84b1c35f84f6b99c0f6fc650e5d93b5151e39945e09
6
+ metadata.gz: e48736a442d4592ea2310dae9884ab1dac1d1de688596517f08504dae133e0da0c98aa4552f22287518a7fc35894581bb654259a90011fb304bc48d1f117415d
7
+ data.tar.gz: b811a332a01d8960f9c672b2afcb8a89aeaf70589d25616c162cdddeb1ff118e14f0f343de293c026ab84f5ca3239dcfd9110e9eddd6d8bb736476f01b4a7d42
@@ -1,19 +1,24 @@
1
- sudo: false
1
+ dist: trusty
2
+ sudo: required
2
3
  language: ruby
3
4
  rvm:
4
5
  - 2.0.0
5
6
  - 2.1.8
6
7
  - 2.2.4
7
8
  - 2.3.0
8
- before_install: gem install bundler -v 1.11.2
9
- script:
10
- - bundle install
11
- - bundle exec rake
12
- addons:
13
- postgresql: "9.4"
14
- apt:
15
- packages:
16
- - libgmp-dev
9
+ before_install:
10
+ - gem install bundler
11
+ - sudo service postgresql stop
12
+ before_script:
13
+ - docker-compose up -d
14
+ - function pg_ping { PGPASSWORD=password pg_isready -U postgres -h 127.0.0.1 > /dev/null 2> /dev/null; }
15
+ - for i in {1..60}; do pg_ping && break; sleep 1; done
17
16
  env:
18
17
  global:
19
18
  - POSGRA_TEST_USER=postgres
19
+ services:
20
+ - docker
21
+ addons:
22
+ apt:
23
+ packages:
24
+ - postgresql-client-9.4
data/README.md CHANGED
@@ -28,9 +28,10 @@ Or install it yourself as:
28
28
  ```sh
29
29
  $ posgra help
30
30
  Commands:
31
- posgra grant SUBCOMMAND # Manage grants
32
- posgra help [COMMAND] # Describe available commands or one specific command
33
- posgra role SUBCOMMAND # Manage roles
31
+ posgra database SUBCOMMAND # Manage database grants
32
+ posgra grant SUBCOMMAND # Manage grants
33
+ posgra help [COMMAND] # Describe available commands or one specific command
34
+ posgra role SUBCOMMAND # Manage roles
34
35
 
35
36
  Options:
36
37
  -h, [--host=HOST]
@@ -62,6 +63,13 @@ posgra grant apply --dry-run pg_grants.rb
62
63
  posgra grant apply pg_grants.rb
63
64
  ```
64
65
 
66
+ ```sh
67
+ posgra database export pg_dbgrants.rb
68
+ vi pg_dbgrants.rb
69
+ posgra database apply --dry-run pg_dbgrants.rb
70
+ posgra database apply pg_dbgrants.rb
71
+ ```
72
+
65
73
  ### for Redshift
66
74
 
67
75
  ```sh
@@ -106,6 +114,26 @@ role "bob" do
106
114
  end
107
115
  ```
108
116
 
117
+ ### DB Grant
118
+
119
+ ```ruby
120
+ role "alice" do
121
+ database "my_database" do
122
+ grant "CONNECT", :grantable => true
123
+ grant "CREATE"
124
+ grant "TEMPORARY"
125
+ end
126
+ end
127
+
128
+ role "bob" do
129
+ database "my_database" do
130
+ grant "CONNECT"
131
+ grant "CREATE"
132
+ grant "TEMPORARY"
133
+ end
134
+ end
135
+ ```
136
+
109
137
  ### Template
110
138
 
111
139
  ```ruby
@@ -138,3 +166,19 @@ role "bob" do
138
166
  end
139
167
  end
140
168
  ```
169
+
170
+ ## Running tests
171
+
172
+ ```sh
173
+ docker-compose up -d
174
+ bundle install
175
+ bundle exec rake
176
+ ```
177
+
178
+ ### on OS X (docker-machine & VirtualBox)
179
+
180
+ Port forwarding is required.
181
+
182
+ ```sh
183
+ VBoxManage controlvm default natpf1 "psql,tcp,127.0.0.1,5432,,5432"
184
+ ```
@@ -0,0 +1,6 @@
1
+ postgres:
2
+ image: "postgres:9.4"
3
+ ports:
4
+ - "5432:5432"
5
+ environment:
6
+ POSTGRES_PASSWORD: password
@@ -15,12 +15,16 @@ require 'posgra/utils'
15
15
  require 'posgra/cli'
16
16
  require 'posgra/cli'
17
17
  require 'posgra/cli/helper'
18
+ require 'posgra/cli/database'
18
19
  require 'posgra/cli/grant'
19
20
  require 'posgra/cli/role'
20
21
  require 'posgra/cli/app'
21
22
  require 'posgra/client'
22
23
  require 'posgra/driver'
23
24
  require 'posgra/dsl'
25
+ require 'posgra/dsl/database'
26
+ require 'posgra/dsl/database/role'
27
+ require 'posgra/dsl/database/role/database'
24
28
  require 'posgra/dsl/grants'
25
29
  require 'posgra/dsl/grants/role'
26
30
  require 'posgra/dsl/grants/role/schema'
@@ -13,4 +13,7 @@ class Posgra::CLI::App < Thor
13
13
 
14
14
  desc 'grant SUBCOMMAND', 'Manage grants'
15
15
  subcommand :grant, Posgra::CLI::Grant
16
+
17
+ desc 'database SUBCOMMAND', 'Manage database grants'
18
+ subcommand :database, Posgra::CLI::Database
16
19
  end
@@ -0,0 +1,70 @@
1
+ class Posgra::CLI::Database < Thor
2
+ include Posgra::CLI::Helper
3
+ include Posgra::Logger::Helper
4
+
5
+ DEFAULT_FILENAME = 'pg_dbgrants.rb'
6
+
7
+ class_option :'include-role'
8
+ class_option :'exclude-role'
9
+ class_option :'include-database'
10
+ class_option :'exclude-database'
11
+
12
+ desc 'apply FILE', 'Apply database grants'
13
+ option :'dry-run', :type => :boolean, :default => false
14
+ def apply(file)
15
+ check_fileanem(file)
16
+ updated = client.apply_databases(file)
17
+
18
+ unless updated
19
+ Posgra::Logger.instance.info('No change'.intense_blue)
20
+ end
21
+ end
22
+
23
+ desc 'export [FILE]', 'Export database grants'
24
+ option :split, :type => :boolean, :default => false
25
+ def export(file = nil)
26
+ check_fileanem(file)
27
+ dsl = client.export_databases
28
+
29
+ if options[:split]
30
+ file = DEFAULT_FILENAME unless file
31
+
32
+ log(:info, 'Export Database Grants')
33
+ requires = []
34
+
35
+ dsl.each do |user, content|
36
+ user = user.gsub(/\s+/, '_')
37
+ user = '_' if user.empty?
38
+ grant_file = "#{user}.rb"
39
+ requires << grant_file
40
+ log(:info, " write `#{grant_file}`")
41
+
42
+ open(grant_file, 'wb') do |f|
43
+ f.puts Posgra::CLI::MAGIC_COMMENT
44
+ f.puts content
45
+ end
46
+ end
47
+
48
+ log(:info, " write `#{file}`")
49
+
50
+ open(file, 'wb') do |f|
51
+ f.puts Posgra::CLI::MAGIC_COMMENT
52
+
53
+ requires.each do |grant_file|
54
+ f.puts "require '#{File.basename grant_file}'"
55
+ end
56
+ end
57
+ else
58
+ if file.nil? or file == '-'
59
+ puts dsl
60
+ else
61
+ log(:info, "Export Database Grants to `#{file}`")
62
+
63
+ open(file, 'wb') do |f|
64
+ f.puts Posgra::CLI::MAGIC_COMMENT
65
+ f.puts dsl
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,6 +1,7 @@
1
1
  class Posgra::Client
2
2
  DEFAULT_EXCLUDE_SCHEMA = /\A(?:pg_.*|information_schema)\z/
3
3
  DEFAULT_EXCLUDE_ROLE = /\A\z/
4
+ DEFAULT_EXCLUDE_DATABASE = /\A(?:template\d+|postgres)\z/
4
5
 
5
6
  def initialize(options = {})
6
7
  if options[:exclude_schema]
@@ -21,6 +22,15 @@ class Posgra::Client
21
22
  options[:exclude_role] = DEFAULT_EXCLUDE_ROLE
22
23
  end
23
24
 
25
+ if options[:exclude_database]
26
+ options[:exclude_database] = Regexp.union(
27
+ options[:exclude_database],
28
+ DEFAULT_EXCLUDE_DATABASE
29
+ )
30
+ else
31
+ options[:exclude_database] = DEFAULT_EXCLUDE_DATABASE
32
+ end
33
+
24
34
  @options = options
25
35
  @client = connect(options)
26
36
  @driver = Posgra::Driver.new(@client, options)
@@ -39,7 +49,6 @@ class Posgra::Client
39
49
  if options[:split]
40
50
  dsl_h = Hash.new {|hash, key| hash[key] = {} }
41
51
 
42
-
43
52
  exported.each do |role, schemas|
44
53
  dsl = Posgra::DSL.convert_grants({role => schemas}, options)
45
54
  dsl_h[role] = dsl
@@ -51,6 +60,24 @@ class Posgra::Client
51
60
  end
52
61
  end
53
62
 
63
+ def export_databases(options = {})
64
+ options = @options.merge(options)
65
+ exported = Posgra::Exporter.export_databases(@driver, options)
66
+
67
+ if options[:split]
68
+ dsl_h = Hash.new {|hash, key| hash[key] = {} }
69
+
70
+ exported.each do |role, databases|
71
+ dsl = Posgra::DSL.convert_databases({role => databases}, options)
72
+ dsl_h[role] = dsl
73
+ end
74
+
75
+ dsl_h
76
+ else
77
+ Posgra::DSL.convert_databases(exported, options)
78
+ end
79
+ end
80
+
54
81
  def apply_roles(file, options = {})
55
82
  options = @options.merge(options)
56
83
  walk_for_roles(file, options)
@@ -61,6 +88,11 @@ class Posgra::Client
61
88
  walk_for_grants(file, options)
62
89
  end
63
90
 
91
+ def apply_databases(file, options = {})
92
+ options = @options.merge(options)
93
+ walk_for_database_grants(file, options)
94
+ end
95
+
64
96
  def close
65
97
  @client.close
66
98
  end
@@ -87,6 +119,12 @@ class Posgra::Client
87
119
  walk_roles(expected, actual)
88
120
  end
89
121
 
122
+ def walk_for_database_grants(file, options)
123
+ expected = load_file(file, :parse_databases, options)
124
+ actual = Posgra::Exporter.export_databases(@driver, options)
125
+ walk_database_roles(expected, actual)
126
+ end
127
+
90
128
  def walk_users(expected, actual)
91
129
  updated = false
92
130
 
@@ -219,6 +257,60 @@ class Posgra::Client
219
257
  updated
220
258
  end
221
259
 
260
+ def walk_database_roles(expected, actual)
261
+ updated = false
262
+
263
+ expected.each do |expected_role, expected_databases|
264
+ actual_databases = actual.delete(expected_role) || {}
265
+ updated = walk_databases(expected_databases, actual_databases, expected_role) || updated
266
+ end
267
+
268
+ actual.each do |actual_role, actual_databases|
269
+ actual_databases.each do |database, _|
270
+ updated = @driver.revoke_all_on_database(actual_role, database) || updated
271
+ end
272
+ end
273
+
274
+ updated
275
+ end
276
+
277
+ def walk_databases(expected, actual, role)
278
+ updated = false
279
+
280
+ expected.each do |expected_database, expected_grants|
281
+ actual_grants = actual.delete(expected_database) || {}
282
+ updated = walk_database_grants(expected_grants, actual_grants, role, expected_database) || updated
283
+ end
284
+
285
+ actual.each do |actual_database, _|
286
+ updated = @driver.revoke_all_on_database(role, actual_database) || updated
287
+ end
288
+
289
+ updated
290
+ end
291
+
292
+ def walk_database_grants(expected, actual, role, database)
293
+ updated = false
294
+
295
+ expected.each do |expected_priv, expected_options|
296
+ actual_options = actual.delete(expected_priv)
297
+
298
+ if actual_options
299
+ if expected_options != actual_options
300
+ updated = @driver.update_database_grant_options(role, expected_priv, expected_options, database) || updated
301
+ end
302
+ else
303
+ updated = @driver.database_grant(role, expected_priv, expected_options, database) || updated
304
+ end
305
+ end
306
+
307
+ actual.each do |actual_priv, _|
308
+ updated = @driver.database_revoke(role, actual_priv, database) || updated
309
+ end
310
+
311
+ updated
312
+ end
313
+
222
314
  def load_file(file, method, options)
223
315
  if file.kind_of?(String)
224
316
  open(file) do |f|
@@ -5,6 +5,8 @@ class Posgra::Driver
5
5
  DEFAULT_ACL_PRIVS = ENV['POSGRA_DEFAULT_ACL_PRIVS'] || 'arwdDxt'
6
6
  DEFAULT_ACL = "{%s=#{DEFAULT_ACL_PRIVS}/%s}"
7
7
 
8
+ DEFAULT_DATABASE_ACL = "{%s=CTc/%s}"
9
+
8
10
  DEFAULT_ACL_BY_KIND = {
9
11
  'S' => '{%s=rwU/%s}'
10
12
  }
@@ -21,6 +23,7 @@ class Posgra::Driver
21
23
  'R' => 'RULE',
22
24
  'X' => 'EXECUTE',
23
25
  'C' => 'CREATE',
26
+ 'c' => 'CONNECT',
24
27
  'T' => 'TEMPORARY',
25
28
  }
26
29
 
@@ -143,6 +146,18 @@ class Posgra::Driver
143
146
  updated
144
147
  end
145
148
 
149
+ def revoke_all_on_database(role, database)
150
+ sql = "REVOKE ALL ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}"
151
+ log(:info, sql, :color => :green)
152
+
153
+ unless @options[:dry_run]
154
+ exec(sql)
155
+ updated = true
156
+ end
157
+
158
+ updated
159
+ end
160
+
146
161
  def grant(role, priv, options, schema, object)
147
162
  updated = false
148
163
 
@@ -216,6 +231,79 @@ class Posgra::Driver
216
231
  updated
217
232
  end
218
233
 
234
+ def database_grant(role, priv, options, database)
235
+ updated = false
236
+
237
+ sql = "GRANT #{priv} ON DATABASE #{@client.escape_identifier(database)} TO #{@client.escape_identifier(role)}"
238
+
239
+ if options['is_grantable']
240
+ sql << ' WITH GRANT OPTION'
241
+ end
242
+
243
+ log(:info, sql, :color => :green)
244
+
245
+ unless @options[:dry_run]
246
+ exec(sql)
247
+ updated = true
248
+ end
249
+
250
+ updated
251
+ end
252
+
253
+ def update_database_grant_options(role, priv, options, database)
254
+ updated = false
255
+
256
+ if options.fetch('is_grantable')
257
+ updated = grant_database_grant_option(role, priv, database)
258
+ else
259
+ updated = roveke_database_grant_option(role, priv, database)
260
+ end
261
+
262
+ updated
263
+ end
264
+
265
+ def grant_database_grant_option(role, priv, database)
266
+ updated = false
267
+
268
+ sql = "GRANT #{priv} ON DATABASE #{@client.escape_identifier(database)} TO #{@client.escape_identifier(role)} WITH GRANT OPTION"
269
+ log(:info, sql, :color => :green)
270
+
271
+ unless @options[:dry_run]
272
+ exec(sql)
273
+ updated = true
274
+ end
275
+
276
+ updated
277
+ end
278
+
279
+ def roveke_database_grant_option(role, priv, database)
280
+ updated = false
281
+
282
+ sql = "REVOKE GRANT OPTION FOR #{priv} ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}"
283
+ log(:info, sql, :color => :green)
284
+
285
+ unless @options[:dry_run]
286
+ exec(sql)
287
+ updated = true
288
+ end
289
+
290
+ updated
291
+ end
292
+
293
+ def database_revoke(role, priv, database)
294
+ updated = false
295
+
296
+ sql = "REVOKE #{priv} ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}"
297
+ log(:info, sql, :color => :green)
298
+
299
+ unless @options[:dry_run]
300
+ exec(sql)
301
+ updated = true
302
+ end
303
+
304
+ updated
305
+ end
306
+
219
307
  def describe_objects(schema)
220
308
  rs = exec <<-SQL
221
309
  SELECT
@@ -294,6 +382,7 @@ class Posgra::Driver
294
382
  SQL
295
383
 
296
384
  grants_by_role = {}
385
+
297
386
  rs.each do |row|
298
387
  relname = row.fetch('relname')
299
388
  nspname = row.fetch('nspname')
@@ -317,11 +406,52 @@ class Posgra::Driver
317
406
  grants_by_role
318
407
  end
319
408
 
409
+ def describe_databases
410
+ rs = exec <<-SQL
411
+ SELECT
412
+ pg_database.datname,
413
+ pg_database.datacl,
414
+ pg_user.usename
415
+ FROM
416
+ pg_database
417
+ INNER JOIN pg_user ON pg_database.datdba = pg_user.usesysid
418
+ SQL
419
+
420
+ database_grants_by_role = {}
421
+
422
+ rs.each do |row|
423
+ datname = row.fetch('datname')
424
+ datacl = row.fetch('datacl')
425
+ usename = row.fetch('usename')
426
+
427
+ next unless matched?(datname, @options[:include_database], @options[:exclude_database])
428
+
429
+ parse_database_aclitems(datacl, usename).each do |aclitem|
430
+ role = aclitem.fetch('grantee')
431
+ privs = aclitem.fetch('privileges')
432
+ next unless matched?(role, @options[:include_role], @options[:exclude_role])
433
+ database_grants_by_role[role] ||= {}
434
+ database_grants_by_role[role][datname] = privs
435
+ end
436
+ end
437
+
438
+ database_grants_by_role
439
+ end
440
+
320
441
  private
321
442
 
322
443
  def parse_aclitems(aclitems, owner, relkind)
323
444
  aclitems_fmt = DEFAULT_ACL_BY_KIND.fetch(relkind, DEFAULT_ACL)
324
445
  aclitems ||= aclitems_fmt % [owner, owner]
446
+ parse_aclitems0(aclitems)
447
+ end
448
+
449
+ def parse_database_aclitems(aclitems, owner)
450
+ aclitems ||= DEFAULT_DATABASE_ACL % [owner, owner]
451
+ parse_aclitems0(aclitems)
452
+ end
453
+
454
+ def parse_aclitems0(aclitems)
325
455
  aclitems = aclitems[1..-2].split(',')
326
456
 
327
457
  aclitems.map do |aclitem|
@@ -7,6 +7,10 @@ class Posgra::DSL
7
7
  Posgra::DSL::Converter.convert_grants(exported, options)
8
8
  end
9
9
 
10
+ def self.convert_databases(exported, options = {})
11
+ Posgra::DSL::Converter.convert_databases(exported, options)
12
+ end
13
+
10
14
  def self.parse_roles(dsl, path, options = {})
11
15
  Posgra::DSL::Roles.eval(dsl, path, options).result
12
16
  end
@@ -14,4 +18,8 @@ class Posgra::DSL
14
18
  def self.parse_grants(dsl, path, options = {})
15
19
  Posgra::DSL::Grants.eval(dsl, path, options).result
16
20
  end
21
+
22
+ def self.parse_databases(dsl, path, options = {})
23
+ Posgra::DSL::Database.eval(dsl, path, options).result
24
+ end
17
25
  end
@@ -7,6 +7,10 @@ class Posgra::DSL::Converter
7
7
  self.new(exported, options).convert_grants
8
8
  end
9
9
 
10
+ def self.convert_databases(exported, options = {})
11
+ self.new(exported, options).convert_databases
12
+ end
13
+
10
14
  def initialize(exported, options = {})
11
15
  @exported = exported
12
16
  @options = options
@@ -27,6 +31,11 @@ class Posgra::DSL::Converter
27
31
  output_roles(grants_by_role).strip
28
32
  end
29
33
 
34
+ def convert_databases
35
+ database_grants_by_role = @exported || {}
36
+ output_database_roles(database_grants_by_role).strip
37
+ end
38
+
30
39
  private
31
40
 
32
41
  def output_users(users)
@@ -117,10 +126,10 @@ end
117
126
  EOS
118
127
  end
119
128
 
120
- def output_grants(grants)
129
+ def output_grants(grants, indent = " ")
121
130
  grants.sort_by {|g| g.to_s }.map {|privilege_type, options|
122
131
  output_grant(privilege_type, options).strip
123
- }.join("\n ")
132
+ }.join("\n#{indent}")
124
133
  end
125
134
 
126
135
  def output_grant(privilege_type, options)
@@ -133,4 +142,45 @@ end
133
142
 
134
143
  out
135
144
  end
145
+
146
+ def output_database_roles(database_grants_by_role)
147
+ database_grants_by_role.sort_by {|r, _| r }.map {|role, grants_by_database|
148
+ output_database_role(role, grants_by_database)
149
+ }.join("\n")
150
+ end
151
+
152
+ def output_database_role(role, grants_by_database)
153
+ if grants_by_database.empty?
154
+ databases = "# no databases"
155
+ else
156
+ databases = output_databases(grants_by_database)
157
+ end
158
+
159
+ <<-EOS
160
+ role #{role.inspect} do
161
+ #{databases}
162
+ end
163
+ EOS
164
+ end
165
+
166
+ def output_databases(grants_by_database)
167
+ grants_by_database.sort_by {|s, _| s }.map {|database, grants|
168
+ output_database(database, grants).strip
169
+ }.join("\n ")
170
+ end
171
+
172
+ def output_database(database, grants)
173
+ if grants.empty?
174
+ grants = "# no grants"
175
+ else
176
+ grants = output_grants(grants, ' ')
177
+ end
178
+
179
+ <<-EOS
180
+ database #{database.inspect} do
181
+ #{grants}
182
+ end
183
+ EOS
184
+ end
185
+
136
186
  end
@@ -0,0 +1,53 @@
1
+ class Posgra::DSL::Database
2
+ include Posgra::Logger::Helper
3
+ include Posgra::TemplateHelper
4
+ include Posgra::Utils::Helper
5
+
6
+ def self.eval(dsl, path, options = {})
7
+ self.new(path, options) do
8
+ eval(dsl, binding, path)
9
+ end
10
+ end
11
+
12
+ attr_reader :result
13
+
14
+ def initialize(path, options = {}, &block)
15
+ @path = path
16
+ @options = options
17
+ @result = {}
18
+
19
+ @context = Hashie::Mash.new(
20
+ :path => path,
21
+ :options => options,
22
+ :templates => {},
23
+ )
24
+
25
+ instance_eval(&block)
26
+ end
27
+
28
+ private
29
+
30
+ def template(name, &block)
31
+ @context.templates[name.to_s] = block
32
+ end
33
+
34
+ def require(file)
35
+ pgrantfile = (file =~ %r|\A/|) ? file : File.expand_path(File.join(File.dirname(@path), file))
36
+
37
+ if File.exist?(pgrantfile)
38
+ instance_eval(File.read(pgrantfile), pgrantfile)
39
+ elsif File.exist?(pgrantfile + '.rb')
40
+ instance_eval(File.read(pgrantfile + '.rb'), pgrantfile + '.rb')
41
+ else
42
+ Kernel.require(file)
43
+ end
44
+ end
45
+
46
+ def role(name, &block)
47
+ name = name.to_s
48
+
49
+ if matched?(name, @options[:include_role], @options[:exclude_role])
50
+ @result[name] = Posgra::DSL::Database::Role.new(@context, name, @options, &block).result
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,23 @@
1
+ class Posgra::DSL::Database::Role
2
+ include Posgra::Logger::Helper
3
+ include Posgra::TemplateHelper
4
+ include Posgra::Utils::Helper
5
+
6
+ attr_reader :result
7
+
8
+ def initialize(context, role, options, &block)
9
+ @role = role
10
+ @options = options
11
+ @context = context.merge(:role => role)
12
+ @result = {}
13
+ instance_eval(&block)
14
+ end
15
+
16
+ def database(name, &block)
17
+ name = name.to_s
18
+
19
+ if matched?(name, @options[:include_database], @options[:exclude_database])
20
+ @result[name] = Posgra::DSL::Database::Role::Database.new(@context, name, @options, &block).result
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ class Posgra::DSL::Database::Role::Database
2
+ include Posgra::Logger::Helper
3
+ include Posgra::TemplateHelper
4
+
5
+ attr_reader :result
6
+
7
+ def initialize(context, database, options, &block)
8
+ @database = database
9
+ @options = options
10
+ @context = context.merge(:database => database)
11
+ @result = {}
12
+ instance_eval(&block)
13
+ end
14
+
15
+ def grant(name, options = {})
16
+ name = name.to_s
17
+
18
+ @result[name] = {
19
+ 'is_grantable' => !!options[:grantable]
20
+ }
21
+ end
22
+ end
@@ -1,10 +1,14 @@
1
1
  class Posgra::Exporter
2
- def self.export_roles(driver, options = {}, &block)
3
- self.new(driver, options).export_roles(&block)
2
+ def self.export_roles(driver, options = {})
3
+ self.new(driver, options).export_roles
4
4
  end
5
5
 
6
- def self.export_grants(driver, options = {}, &block)
7
- self.new(driver, options).export_grants(&block)
6
+ def self.export_grants(driver, options = {})
7
+ self.new(driver, options).export_grants
8
+ end
9
+
10
+ def self.export_databases(driver, options = {})
11
+ self.new(driver, options).export_databases
8
12
  end
9
13
 
10
14
  def initialize(driver, options = {})
@@ -22,4 +26,8 @@ class Posgra::Exporter
22
26
  def export_grants
23
27
  @driver.describe_grants
24
28
  end
29
+
30
+ def export_databases
31
+ @driver.describe_databases
32
+ end
25
33
  end
@@ -1,3 +1,3 @@
1
1
  module Posgra
2
- VERSION = "0.1.9"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posgra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - winebarrel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-02-08 00:00:00.000000000 Z
11
+ date: 2016-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -167,10 +167,12 @@ files:
167
167
  - Rakefile
168
168
  - bin/console
169
169
  - bin/setup
170
+ - docker-compose.yml
170
171
  - exe/posgra
171
172
  - lib/posgra.rb
172
173
  - lib/posgra/cli.rb
173
174
  - lib/posgra/cli/app.rb
175
+ - lib/posgra/cli/database.rb
174
176
  - lib/posgra/cli/grant.rb
175
177
  - lib/posgra/cli/helper.rb
176
178
  - lib/posgra/cli/role.rb
@@ -178,6 +180,9 @@ files:
178
180
  - lib/posgra/driver.rb
179
181
  - lib/posgra/dsl.rb
180
182
  - lib/posgra/dsl/converter.rb
183
+ - lib/posgra/dsl/database.rb
184
+ - lib/posgra/dsl/database/role.rb
185
+ - lib/posgra/dsl/database/role/database.rb
181
186
  - lib/posgra/dsl/grants.rb
182
187
  - lib/posgra/dsl/grants/role.rb
183
188
  - lib/posgra/dsl/grants/role/schema.rb