record_store 5.0.4 → 5.0.5

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: 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