record_store 5.0.4 → 5.0.5

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: 3e8f21e1bb405e185727380fc0c7760116ef5deb
4
- data.tar.gz: 29bed06e5aa2e8a4e3f78690015ee3bcc5f96c92
3
+ metadata.gz: 8898e68756f44cc7777bfbbff84d9806eeace0ed
4
+ data.tar.gz: 861fc60403a348b1c2c2fe0bf551a935e1a747ff
5
5
  SHA512:
6
- metadata.gz: d72af6c709460b9b81c44722e6ddd13cfa7f89f18659c7341f7512a6486c44e28364f512d49fee9f16d21240db229d16df07936447f6214356e76a64df862a02
7
- data.tar.gz: 35ae3d3718486153cdd9d763de16ca4ef478e0a58f283fd43f6a39a537455547a75687f02daacc8add2db21c3415df42a26308fe08d7ba6691816eb8a551cdb5
6
+ metadata.gz: fbc65b2ee1998c5f13bd28025892b1433716e0c74c1e7e44a50b6e5550ecb66913acda076224a85c4059dcc878835bb02ec195adc80460a9c1177b8c46408d2d
7
+ data.tar.gz: ea7ab36879e1c6cae29573f9d51140a00e4f7a447563764f877dc4556b23f4f81bffe2f193137587f2c359011d72239ccb8a3b38750cd3163743540881917b86
data/CHANGELOG.md CHANGED
@@ -1,6 +1,17 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 5.0.5
4
+ - Output progress messages for GoogleCloudDNS provider too. [BUGFIX]
5
+ - Fix quoting/escaping for TXT records. [BUGFIX]
6
+ - Make implementation-specific methods of Provider private. [REFACTOR]
7
+ - DRY up SPF support to use TXT superclass implementation. [REFACTOR]
8
+
3
9
  ## 5.0.4
4
- - Replaces fog-dnsimple with dnsimple-ruby gem.
10
+ - Replaces fog-dnsimple with dnsimple-ruby gem. [REFACTOR]
11
+
12
+ ## 5.0.0
13
+ - Use DNSimple API v2 (via fog-dnsimple gem update).
14
+
15
+ ## 4.0.7
5
16
 
6
- ## ¯\_(ツ)_/¯
17
+ - Fix issue updating records with same FQDN. [BUGFIX]
data/README.md CHANGED
@@ -96,28 +96,6 @@ Provider API interactions are tested with [VCR](https://github.com/vcr/vcr). To
96
96
  Outline of [`Provider`](lib/record_store/provider.rb):
97
97
  ```ruby
98
98
  class Provider
99
- # Creates a new record to the zone. It is expected this call modifies external state.
100
- #
101
- # Arguments:
102
- # record - a kind of `Record`
103
- def add(record)
104
- end
105
-
106
- # Deletes an existing record from the zone. It is expected this call modifies external state.
107
- #
108
- # Arguments:
109
- # record - a kind of `Record`
110
- def remove(record)
111
- end
112
-
113
- # Updates an existing record in the zone. It is expected this call modifies external state.
114
- #
115
- # Arguments:
116
- # id - provider specific ID of record to update
117
- # record - a kind of `Record` which the record with `id` should be updated to
118
- def update(id, record)
119
- end
120
-
121
99
  # Downloads all the records from the provider.
122
100
  #
123
101
  # Returns: an array of `Record` for each record in the provider's zone
@@ -141,6 +119,35 @@ class Provider
141
119
  # Unlocks the zone to allow making changes (see `Provider#freeze_zone`).
142
120
  def thaw
143
121
  end
122
+
123
+ private
124
+
125
+ ######## NOTE ########
126
+ # The following methods only need to be implemented if you are using the base provider's
127
+ # implementation of apply_changeset to manage the contents of the changeset (or transaction).
128
+ ######################
129
+
130
+ # Creates a new record to the zone. It is expected this call modifies external state.
131
+ #
132
+ # Arguments:
133
+ # record - a kind of `Record`
134
+ def add(record)
135
+ end
136
+
137
+ # Deletes an existing record from the zone. It is expected this call modifies external state.
138
+ #
139
+ # Arguments:
140
+ # record - a kind of `Record`
141
+ def remove(record)
142
+ end
143
+
144
+ # Updates an existing record in the zone. It is expected this call modifies external state.
145
+ #
146
+ # Arguments:
147
+ # id - provider specific ID of record to update
148
+ # record - a kind of `Record` which the record with `id` should be updated to
149
+ def update(id, record)
150
+ end
144
151
  end
145
152
  ```
146
153
 
data/dev.yml CHANGED
@@ -2,7 +2,7 @@
2
2
  name: recordstore
3
3
 
4
4
  up:
5
- - ruby: 2.3.1
5
+ - ruby: 2.4.3
6
6
  - bundler
7
7
 
8
8
  commands:
@@ -57,7 +57,11 @@ module RecordStore
57
57
  end
58
58
 
59
59
  def apply
60
+ puts "Applying #{additions.size} additions, #{removals.size} removals, and #{updates.size} updates..."
61
+
60
62
  provider.apply_changeset(self)
63
+
64
+ puts "Published #{zone} changes to #{provider}\n\n"
61
65
  end
62
66
 
63
67
  def unchanged
@@ -55,40 +55,22 @@ module RecordStore
55
55
  raise NotImplementedError
56
56
  end
57
57
 
58
- def add(record)
59
- raise NotImplementedError
60
- end
61
-
62
- def remove(record)
63
- raise NotImplementedError
64
- end
65
-
66
- def update(id, record)
67
- raise NotImplementedError
68
- end
69
-
70
58
  # Applies changeset to provider
71
59
  def apply_changeset(changeset, stdout = $stdout)
72
- begin
73
- stdout.puts "Applying #{changeset.additions.size} additions, #{changeset.removals.size} removals, & #{changeset.updates.size} updates..."
74
-
75
- changeset.changes.each do |change|
76
- case change.type
77
- when :removal;
78
- stdout.puts "Removing #{change.record}..."
79
- remove(change.record, changeset.zone)
80
- when :addition;
81
- stdout.puts "Creating #{change.record}..."
82
- add(change.record, changeset.zone)
83
- when :update;
84
- stdout.puts "Updating record with ID #{change.id} to #{change.record}..."
85
- update(change.id, change.record, changeset.zone)
86
- else
87
- raise ArgumentError, "Unknown change type #{change.type.inspect}"
88
- end
60
+ changeset.changes.each do |change|
61
+ case change.type
62
+ when :removal
63
+ stdout.puts "Removing #{change.record}..."
64
+ remove(change.record, changeset.zone)
65
+ when :addition
66
+ stdout.puts "Creating #{change.record}..."
67
+ add(change.record, changeset.zone)
68
+ when :update
69
+ stdout.puts "Updating record with ID #{change.id} to #{change.record}..."
70
+ update(change.id, change.record, changeset.zone)
71
+ else
72
+ raise ArgumentError, "Unknown change type #{change.type.inspect}"
89
73
  end
90
-
91
- puts "\nPublished #{changeset.zone} changes to #{changeset.provider.to_s}\n"
92
74
  end
93
75
  end
94
76
 
@@ -116,6 +98,20 @@ module RecordStore
116
98
  def to_s
117
99
  self.name.demodulize
118
100
  end
101
+
102
+ private
103
+
104
+ def add(record)
105
+ raise NotImplementedError
106
+ end
107
+
108
+ def remove(record)
109
+ raise NotImplementedError
110
+ end
111
+
112
+ def update(id, record)
113
+ raise NotImplementedError
114
+ end
119
115
  end
120
116
  end
121
117
  end
@@ -7,6 +7,25 @@ module RecordStore
7
7
  true
8
8
  end
9
9
 
10
+ # returns an array of Record objects that match the records which exist in the provider
11
+ def retrieve_current_records(zone:, stdout: $stdout)
12
+ session.zones.all_records(account_id, zone).data.map do |record|
13
+ begin
14
+ build_from_api(record, zone)
15
+ rescue StandardError
16
+ stdout.puts "Cannot build record: #{record}"
17
+ raise
18
+ end
19
+ end.compact
20
+ end
21
+
22
+ # Returns an array of the zones managed by provider as strings
23
+ def zones
24
+ session.zones.all_zones(account_id).data.map(&:name)
25
+ end
26
+
27
+ private
28
+
10
29
  def add(record, zone)
11
30
  record_hash = api_hash(record, zone)
12
31
  res = session.zones.create_record(account_id, zone, record_hash)
@@ -29,25 +48,6 @@ module RecordStore
29
48
  session.zones.update_record(account_id, zone, id, api_hash(record, zone))
30
49
  end
31
50
 
32
- # returns an array of Record objects that match the records which exist in the provider
33
- def retrieve_current_records(zone:, stdout: $stdout)
34
- session.zones.all_records(account_id, zone).data.map do |record|
35
- begin
36
- build_from_api(record, zone)
37
- rescue StandardError
38
- stdout.puts "Cannot build record: #{record}"
39
- raise
40
- end
41
- end.compact
42
- end
43
-
44
- # Returns an array of the zones managed by provider as strings
45
- def zones
46
- session.zones.all_zones(account_id).data.map(&:name)
47
- end
48
-
49
- private
50
-
51
51
  def session
52
52
  @dns ||= Dnsimple::Client.new(
53
53
  base_url: secrets.fetch('base_url'),
@@ -85,7 +85,7 @@ module RecordStore
85
85
  when 'NS'
86
86
  record.merge!(nsdname: api_record.content)
87
87
  when 'SPF', 'TXT'
88
- record.merge!(txtdata: api_record.content.gsub(';', '\;'))
88
+ record.merge!(txtdata: Record::TXT.unescape(api_record.content).gsub(';', '\;'))
89
89
  when 'SRV'
90
90
  weight, port, host = api_record.content.split(' ')
91
91
 
@@ -124,7 +124,7 @@ module RecordStore
124
124
  when 'NS'
125
125
  record_hash[:content] = record.nsdname.chomp('.')
126
126
  when 'SPF', 'TXT'
127
- record_hash[:content] = record.txtdata.gsub('\;', ';')
127
+ record_hash[:content] = Record::TXT.escape(record.txtdata).gsub('\;', ';')
128
128
  when 'SRV'
129
129
  record_hash[:content] = "#{record.weight} #{record.port} #{record.target.chomp('.')}"
130
130
  record_hash[:priority] = record.priority
@@ -11,35 +11,21 @@ module RecordStore
11
11
  session.put_zone(zone, thaw: true)
12
12
  end
13
13
 
14
- def add(record, zone)
15
- session.post_record(record.type, zone, record.fqdn, record.rdata, 'ttl' => record.ttl)
16
- end
17
-
18
- def remove(record, zone)
19
- session.delete_record(record.type, zone, record.fqdn, record.id)
20
- end
21
-
22
- def update(id, record, zone)
23
- session.put_record(record.type, zone, record.fqdn, record.rdata, 'ttl' => record.ttl, 'record_id' => id)
24
- end
25
-
26
14
  def publish(zone)
27
15
  session.put_zone(zone, publish: true)
28
16
  end
29
17
 
30
18
  # Applies changeset to provider
31
19
  def apply_changeset(changeset, stdout = $stdout)
32
- begin
33
- thaw_zone(changeset.zone)
34
- super
35
- publish(changeset.zone)
36
- rescue StandardError
37
- puts "An exception occurred while applying DNS changes, deleting changeset"
38
- discard_change_set(changeset.zone)
39
- raise
40
- ensure
41
- freeze_zone(changeset.zone)
42
- end
20
+ thaw_zone(changeset.zone)
21
+ super
22
+ publish(changeset.zone)
23
+ rescue StandardError
24
+ puts "An exception occurred while applying DNS changes, deleting changeset"
25
+ discard_change_set(changeset.zone)
26
+ raise
27
+ ensure
28
+ freeze_zone(changeset.zone)
43
29
  end
44
30
 
45
31
  # returns an array of Record objects that match the records which exist in the provider
@@ -62,6 +48,18 @@ module RecordStore
62
48
 
63
49
  private
64
50
 
51
+ def add(record, zone)
52
+ session.post_record(record.type, zone, record.fqdn, api_rdata(record), 'ttl' => record.ttl)
53
+ end
54
+
55
+ def remove(record, zone)
56
+ session.delete_record(record.type, zone, record.fqdn, record.id)
57
+ end
58
+
59
+ def update(id, record, zone)
60
+ session.put_record(record.type, zone, record.fqdn, api_rdata(record), 'ttl' => record.ttl, 'record_id' => id)
61
+ end
62
+
65
63
  def discard_change_set(zone)
66
64
  session.request(expects: 200, method: :delete, path: "ZoneChanges/#{zone}")
67
65
  end
@@ -84,16 +82,28 @@ module RecordStore
84
82
  super.fetch('dynect')
85
83
  end
86
84
 
85
+ def api_rdata(record)
86
+ case record.type
87
+ when 'TXT'
88
+ { txtdata: record.rdata_txt }
89
+ else
90
+ record.rdata
91
+ end
92
+ end
93
+
87
94
  def build_from_api(api_record)
88
- record = api_record.merge(api_record.fetch('rdata')).slice!('rdata').symbolize_keys
95
+ rdata = api_record.fetch('rdata')
96
+ record = api_record.merge(rdata).slice!('rdata').symbolize_keys
89
97
 
90
- return if record.fetch(:record_type) == 'SOA'
98
+ type = record.fetch(:record_type)
99
+ return if type == 'SOA'
91
100
 
92
- unless record.fetch(:fqdn).ends_with?('.')
93
- record[:fqdn] = "#{record.fetch(:fqdn)}."
94
- end
101
+ record[:txtdata] = Record::TXT.unescape(record[:txtdata]) if %w[SPF TXT].include?(type)
102
+
103
+ fqdn = record.fetch(:fqdn)
104
+ record[:fqdn] = "#{fqdn}." unless fqdn.ends_with?('.')
95
105
 
96
- Record.const_get(record.fetch(:record_type)).new(record)
106
+ Record.const_get(type).new(record)
97
107
  end
98
108
  end
99
109
  end
@@ -9,7 +9,7 @@ module RecordStore
9
9
  deletions = convert_records_to_gcloud_record_sets(zone, changeset.current_records)
10
10
  additions = convert_records_to_gcloud_record_sets(zone, changeset.desired_records)
11
11
 
12
- # The Google API library will handle applying the changeset transactioanlly
12
+ # The Google API library will handle applying the changeset transactionally
13
13
  zone.update(additions, deletions)
14
14
  end
15
15
 
@@ -98,7 +98,8 @@ module RecordStore
98
98
  when 'NS'
99
99
  record_params.merge!(nsdname: record.data[0])
100
100
  when 'SPF', 'TXT'
101
- record_params.merge!(txtdata: record.data[0].gsub(';', '\;'))
101
+ txtdata = Record::TXT.unquote(record.data[0]).gsub(';', '\;')
102
+ record_params.merge!(txtdata: txtdata)
102
103
  when 'SRV'
103
104
  priority, weight, port, target = record.data[0].split(' ')
104
105
 
@@ -35,7 +35,7 @@ module RecordStore
35
35
  end
36
36
 
37
37
  def type
38
- self.class.name.split('::').last
38
+ self.class.name.demodulize
39
39
  end
40
40
 
41
41
  def ==(other)
@@ -65,8 +65,7 @@ module RecordStore
65
65
  end
66
66
 
67
67
  def to_s
68
- rr_type = self.class.name.demodulize
69
- "[#{rr_type}Record] #{fqdn} #{ttl} IN #{rr_type} #{rdata_txt}"
68
+ "[#{type}Record] #{fqdn} #{ttl} IN #{type} #{rdata_txt}"
70
69
  end
71
70
 
72
71
  protected
@@ -1,24 +1,8 @@
1
1
  module RecordStore
2
- class Record::SPF < Record
3
- attr_accessor :txtdata
4
-
5
- validates :txtdata, presence: true, length: { maximum: 255 }
6
-
2
+ class Record::SPF < Record::TXT
7
3
  def initialize(record)
4
+ STDERR.puts "SPF record type is deprecated (See RFC 7208 Section 14.1)"
8
5
  super
9
- @txtdata = record.fetch(:txtdata)
10
- end
11
-
12
- def to_s
13
- "[SPFRecord] #{fqdn} #{ttl} IN SPF \"#{rdata_txt}\""
14
- end
15
-
16
- def rdata
17
- { txtdata: txtdata }
18
- end
19
-
20
- def rdata_txt
21
- txtdata
22
6
  end
23
7
  end
24
8
  end
@@ -5,21 +5,35 @@ module RecordStore
5
5
  validates :txtdata, presence: true, length: { maximum: 255 }
6
6
  validate :escaped_semicolons
7
7
 
8
+ class << self
9
+ def escape(value)
10
+ value.gsub('"', '\"')
11
+ end
12
+
13
+ def quote(value)
14
+ %("#{escape(value)}")
15
+ end
16
+
17
+ def unescape(value)
18
+ value.gsub('\"', '"')
19
+ end
20
+
21
+ def unquote(value)
22
+ unescape(value.sub(/\A"(.*)"\z/, '\1'))
23
+ end
24
+ end
25
+
8
26
  def initialize(record)
9
27
  super
10
28
  @txtdata = record.fetch(:txtdata)
11
29
  end
12
30
 
13
- def to_s
14
- "[TXTRecord] #{fqdn} #{ttl} IN TXT \"#{rdata_txt}\""
15
- end
16
-
17
31
  def rdata
18
32
  { txtdata: txtdata }
19
33
  end
20
34
 
21
35
  def rdata_txt
22
- txtdata
36
+ Record::TXT.quote(txtdata)
23
37
  end
24
38
 
25
39
  private
@@ -1,3 +1,3 @@
1
1
  module RecordStore
2
- VERSION = '5.0.4'.freeze
2
+ VERSION = '5.0.5'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: record_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.4
4
+ version: 5.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Bergen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-02-21 00:00:00.000000000 Z
12
+ date: 2018-04-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor