posgra 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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