record_store 2.0.0 → 2.1.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: e96a230fae8c5a5a73e2c51a2097c5b14094f82d
4
- data.tar.gz: 55c913c54e64b78454624b0844ebf1e3ca74fa36
3
+ metadata.gz: b939adb80cff762bc3463596e80a684a8a4accc6
4
+ data.tar.gz: a97fdd41e9ef24859af390d2004ff3468911b637
5
5
  SHA512:
6
- metadata.gz: 512431b9f45815ee10a9b8b10228660b944b862a99be5e1ecb42705cab33fd069f8787971881e0a905722ddf20b127c121c091da61af93b93d1ee568b48f66f9
7
- data.tar.gz: d0f22e77f0a914a0c3ee11cef077cc8bd1e31eb4ce04acc8e351e01c43cff7218831e9621350ab631bcd9e62f9c943e2b690c1f275242be05479567ca36c5b75
6
+ metadata.gz: 187c99f674558e6032f722d9bc352acca2385380c981dacae81d1ae1e24b7f4893d6bc4e61e91d1eb1e4ffe028d42fe128c4ec8b7cd15cd2f9c56160085c6c02
7
+ data.tar.gz: 33e19e66a3d68da1f1af1eb0147dca02e430e769bee89617f199c3684509a2137f9eca5ff52fbf20e007a27c2399524e92ec9b3abf70af3ac05df22998afb34c
data/Gemfile CHANGED
@@ -8,7 +8,7 @@ gem 'ejson'
8
8
  gem 'fog'
9
9
  gem 'fog-json'
10
10
  gem 'fog-xml'
11
- gem 'fog-dynect'
11
+ gem 'fog-dynect', '~> 0.1.0'
12
12
 
13
13
  group :test do
14
14
  gem 'mocha'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- CFPropertyList (2.3.2)
4
+ CFPropertyList (2.3.3)
5
5
  activemodel (4.2.2)
6
6
  activesupport (= 4.2.2)
7
7
  builder (~> 3.1)
@@ -14,18 +14,17 @@ GEM
14
14
  builder (3.2.2)
15
15
  coderay (1.1.0)
16
16
  ejson (1.0.0)
17
- excon (0.45.4)
17
+ excon (0.52.0)
18
18
  fission (0.5.0)
19
19
  CFPropertyList (~> 2.2)
20
- fog (1.36.0)
21
- fog-aliyun (>= 0.1.0)
20
+ fog (1.33.0)
22
21
  fog-atmos
23
22
  fog-aws (>= 0.6.0)
24
23
  fog-brightbox (~> 0.4)
25
24
  fog-core (~> 1.32)
26
- fog-dynect (~> 0.0.2)
27
- fog-ecloud (~> 0.1)
28
- fog-google (<= 0.1.0)
25
+ fog-dynect
26
+ fog-ecloud (= 0.1.1)
27
+ fog-google (>= 0.0.2)
29
28
  fog-json
30
29
  fog-local
31
30
  fog-powerdns (>= 0.1.1)
@@ -39,59 +38,49 @@ GEM
39
38
  fog-terremark
40
39
  fog-vmfusion
41
40
  fog-voxel
42
- fog-xenserver
43
41
  fog-xml (~> 0.1.1)
44
42
  ipaddress (~> 0.5)
45
43
  nokogiri (~> 1.5, >= 1.5.11)
46
- fog-aliyun (0.1.0)
47
- fog-core (~> 1.27)
48
- fog-json (~> 1.0)
49
- ipaddress (~> 0.8)
50
- xml-simple (~> 1.1)
51
44
  fog-atmos (0.1.0)
52
45
  fog-core
53
46
  fog-xml
54
- fog-aws (0.7.6)
55
- fog-core (~> 1.27)
47
+ fog-aws (0.11.0)
48
+ fog-core (~> 1.38)
56
49
  fog-json (~> 1.0)
57
50
  fog-xml (~> 0.1)
58
51
  ipaddress (~> 0.8)
59
- fog-brightbox (0.9.0)
52
+ fog-brightbox (0.11.0)
60
53
  fog-core (~> 1.22)
61
54
  fog-json
62
55
  inflecto (~> 0.0.2)
63
- fog-core (1.32.1)
56
+ fog-core (1.42.0)
64
57
  builder
65
- excon (~> 0.45)
58
+ excon (~> 0.49)
66
59
  formatador (~> 0.2)
67
- mime-types
68
- net-scp (~> 1.1)
69
- net-ssh (>= 2.1.3)
70
- fog-dynect (0.0.2)
60
+ fog-dynect (0.1.0)
71
61
  fog-core
72
62
  fog-json
73
63
  fog-xml
74
- fog-ecloud (0.3.0)
64
+ fog-ecloud (0.1.1)
75
65
  fog-core
76
66
  fog-xml
77
- fog-google (0.1.0)
67
+ fog-google (0.4.0)
78
68
  fog-core
79
69
  fog-json
80
70
  fog-xml
81
71
  fog-json (1.0.2)
82
72
  fog-core (~> 1.0)
83
73
  multi_json (~> 1.10)
84
- fog-local (0.2.1)
74
+ fog-local (0.3.0)
85
75
  fog-core (~> 1.27)
86
76
  fog-powerdns (0.1.1)
87
77
  fog-core (~> 1.27)
88
78
  fog-json (~> 1.0)
89
79
  fog-xml (~> 0.1)
90
- fog-profitbricks (0.0.5)
91
- fog-core
92
- fog-xml
93
- nokogiri
94
- fog-radosgw (0.0.4)
80
+ fog-profitbricks (2.0.1)
81
+ fog-core (~> 1.42)
82
+ fog-json (~> 1.0)
83
+ fog-radosgw (0.0.5)
95
84
  fog-core (>= 1.21.0)
96
85
  fog-json
97
86
  fog-xml (>= 0.0.1)
@@ -99,13 +88,13 @@ GEM
99
88
  fog-core
100
89
  fog-json
101
90
  fog-xml
102
- fog-sakuracloud (1.4.0)
91
+ fog-sakuracloud (1.7.5)
103
92
  fog-core
104
93
  fog-json
105
94
  fog-serverlove (0.1.2)
106
95
  fog-core
107
96
  fog-json
108
- fog-softlayer (1.0.2)
97
+ fog-softlayer (1.1.4)
109
98
  fog-core
110
99
  fog-json
111
100
  fog-storm_on_demand (0.1.1)
@@ -120,30 +109,25 @@ GEM
120
109
  fog-voxel (0.1.0)
121
110
  fog-core
122
111
  fog-xml
123
- fog-xenserver (0.2.2)
124
- fog-core
125
- fog-xml
126
112
  fog-xml (0.1.2)
127
113
  fog-core
128
114
  nokogiri (~> 1.5, >= 1.5.11)
129
115
  formatador (0.2.5)
130
116
  i18n (0.7.0)
131
117
  inflecto (0.0.2)
132
- ipaddress (0.8.0)
118
+ ipaddress (0.8.3)
133
119
  json (1.8.3)
134
120
  metaclass (0.0.4)
135
121
  method_source (0.8.2)
136
- mime-types (2.6.1)
137
- mini_portile (0.6.2)
122
+ mini_portile2 (2.1.0)
138
123
  minitest (5.9.0)
139
124
  mocha (1.1.0)
140
125
  metaclass (~> 0.0.1)
141
- multi_json (1.11.2)
142
- net-scp (1.2.1)
143
- net-ssh (>= 2.6.5)
144
- net-ssh (2.9.2)
145
- nokogiri (1.6.6.2)
146
- mini_portile (~> 0.6.0)
126
+ multi_json (1.12.1)
127
+ nokogiri (1.6.8)
128
+ mini_portile2 (~> 2.1.0)
129
+ pkg-config (~> 1.1.7)
130
+ pkg-config (1.1.7)
147
131
  pry (0.10.1)
148
132
  coderay (~> 1.1.0)
149
133
  method_source (~> 0.8.1)
@@ -155,7 +139,6 @@ GEM
155
139
  tzinfo (1.2.2)
156
140
  thread_safe (~> 0.1)
157
141
  vcr (2.9.3)
158
- xml-simple (1.1.5)
159
142
 
160
143
  PLATFORMS
161
144
  ruby
@@ -165,7 +148,7 @@ DEPENDENCIES
165
148
  activesupport (~> 4.2)
166
149
  ejson
167
150
  fog
168
- fog-dynect
151
+ fog-dynect (~> 0.1.0)
169
152
  fog-json
170
153
  fog-xml
171
154
  mocha
@@ -175,4 +158,4 @@ DEPENDENCIES
175
158
  vcr
176
159
 
177
160
  BUNDLED WITH
178
- 1.11.2
161
+ 1.12.5
data/README.md CHANGED
@@ -48,9 +48,11 @@ The permissions required are broken into 2 groups:
48
48
  * WRITE: `RecordAdd`, `RecordDelete`, `ZonePublish`, `ZoneDiscardChangeset`, `ZoneFreeze`, `ZoneThaw`, `ZoneAddNode`,
49
49
  `ZoneRemoveNode`
50
50
 
51
- All CI validations only require READ permissions; deplyoing requires a user with READ and WRITE permissions.
51
+ All CI validations only require READ permissions; deploying requires a user with READ and WRITE permissions.
52
52
 
53
- For a breakdown of what each permssion allows read through [DynECT's permissions guide](https://help.dyn.com/user-and-group-permissions/).
53
+ In addition, the `AliasService` permission is required to be able to read or write ALIAS records on DynECT.
54
+
55
+ For a breakdown of what each permission allows read through [DynECT's permissions guide](https://help.dyn.com/user-and-group-permissions/).
54
56
 
55
57
  ----
56
58
 
@@ -145,7 +147,7 @@ end
145
147
 
146
148
  #### Provider-Specific Records
147
149
 
148
- For provider-specific records (e.g. `ALIAS`), create the record model in `lib/record_store/record` as any other record. In the provider, extend `self.record_types` and append the custom record types to the `Set` returned by `Provider.record_types` (e.g. [`DNSimple.record_types`](https://github.com/Shopify/record_store/blob/1ec0d1410cf8bedf79bc63e8e4cdc7cdb0f1019b/lib/record_store/provider/dnsimple.rb#L5-L7)).
150
+ For provider-specific records (e.g. `ALIAS`), create the record model in `lib/record_store/record` as any other record. In the provider, extend `self.record_types` and append the custom record types to the `Set` returned by `Provider.record_types` (e.g. [`DNSimple.record_types`](https://github.com/Shopify/record_store/blob/368153106068800325b4e579483faa427afe7add/lib/record_store/provider/dnsimple.rb#L6)).
149
151
 
150
152
  #### Secrets
151
153
 
data/dev.yml CHANGED
@@ -5,6 +5,18 @@ up:
5
5
  - ruby: 2.3.1
6
6
  - bundler
7
7
 
8
+ commands:
9
+ test:
10
+ syntax:
11
+ argument: file
12
+ optional: args...
13
+ desc: 'run tests'
14
+ run: |
15
+ if [[ $# -eq 0 ]]; then
16
+ bundle exec rake test
17
+ else
18
+ bundle exec ruby -Itest "$@"
19
+ fi
20
+
8
21
  packages:
9
22
  - git@github.com:Shopify/dev-shopify.git
10
-
@@ -23,6 +23,7 @@ module RecordStore
23
23
  Set.new([
24
24
  'A',
25
25
  'AAAA',
26
+ 'ALIAS',
26
27
  'CNAME',
27
28
  'MX',
28
29
  'NS',
@@ -32,6 +33,10 @@ module RecordStore
32
33
  ])
33
34
  end
34
35
 
36
+ def self.supports_alias?
37
+ false
38
+ end
39
+
35
40
  def initialize(zone:)
36
41
  @zone_name = zone
37
42
  end
@@ -2,8 +2,8 @@ require 'fog/dnsimple'
2
2
 
3
3
  module RecordStore
4
4
  class Provider::DNSimple < Provider
5
- def self.record_types
6
- super.add('ALIAS')
5
+ def self.supports_alias?
6
+ true
7
7
  end
8
8
 
9
9
  def add(record)
@@ -19,7 +19,7 @@ module RecordStore
19
19
 
20
20
  if record.type == 'ALIAS'
21
21
  txt_alias = retrieve_current_records.detect do |rr|
22
- rr.type == 'TXT' && rr.fqdn == record.fqdn && rr.txtdata == "ALIAS for #{record.cname.gsub(/.\z/, '')}"
22
+ rr.type == 'TXT' && rr.fqdn == record.fqdn && rr.txtdata == "ALIAS for #{record.alias.chomp('.')}"
23
23
  end
24
24
  remove(txt_alias)
25
25
  end
@@ -93,7 +93,7 @@ module RecordStore
93
93
  when 'AAAA'
94
94
  record.merge!(address: api_record.fetch('content'))
95
95
  when 'ALIAS'
96
- record.merge!(cname: api_record.fetch('content'))
96
+ record.merge!(alias: api_record.fetch('content'))
97
97
  when 'CNAME'
98
98
  record.merge!(cname: api_record.fetch('content'))
99
99
  when 'MX'
@@ -124,7 +124,7 @@ module RecordStore
124
124
 
125
125
  def api_hash(record)
126
126
  record_hash = {
127
- name: record.fqdn.gsub("#{Record.ensure_ends_with_dot(@zone_name)}", '').gsub(/.\z/, ''),
127
+ name: record.fqdn.gsub("#{Record.ensure_ends_with_dot(@zone_name)}", '').chomp('.'),
128
128
  ttl: record.ttl,
129
129
  type: record.type,
130
130
  }
@@ -135,18 +135,18 @@ module RecordStore
135
135
  when 'AAAA'
136
136
  record_hash[:content] = record.address
137
137
  when 'ALIAS'
138
- record_hash[:content] = record.cname.gsub(/.\z/, '')
138
+ record_hash[:content] = record.alias.chomp('.')
139
139
  when 'CNAME'
140
- record_hash[:content] = record.cname.gsub(/.\z/, '')
140
+ record_hash[:content] = record.cname.chomp('.')
141
141
  when 'MX'
142
142
  record_hash[:prio] = record.preference
143
- record_hash[:content] = record.exchange.gsub(/.\z/, '')
143
+ record_hash[:content] = record.exchange.chomp('.')
144
144
  when 'NS'
145
- record_hash[:content] = record.nsdname.gsub(/.\z/, '')
145
+ record_hash[:content] = record.nsdname.chomp('.')
146
146
  when 'SPF'
147
147
  record_hash[:content] = record.txtdata
148
148
  when 'SRV'
149
- record_hash[:content] = "#{record.weight} #{record.port} #{record.target.gsub(/.\z/, '')}"
149
+ record_hash[:content] = "#{record.weight} #{record.port} #{record.target.chomp('.')}"
150
150
  record_hash[:prio] = record.priority
151
151
  when 'TXT'
152
152
  record_hash[:content] = record.txtdata
@@ -18,7 +18,16 @@ module RecordStore
18
18
  end
19
19
 
20
20
  def self.build_from_yaml_definition(yaml_definition)
21
- Record.const_get(yaml_definition.fetch(:type)).new(yaml_definition)
21
+ record_type = yaml_definition.fetch(:type)
22
+ # TODO: remove backward compatibility support for ALIAS records using cname attribute instead of alias
23
+ # REMOVE after merging https://github.com/Shopify/record-store/pull/781
24
+ case record_type
25
+ when 'ALIAS'
26
+ if yaml_definition.key?(:cname)
27
+ yaml_definition[:alias] = yaml_definition.delete(:cname)
28
+ end
29
+ end
30
+ Record.const_get(record_type).new(yaml_definition)
22
31
  end
23
32
 
24
33
  def log!(logger=STDOUT)
@@ -1,20 +1,20 @@
1
1
  module RecordStore
2
2
  class Record::ALIAS < Record
3
- attr_accessor :cname
3
+ attr_accessor :alias
4
4
 
5
- validates :cname, presence: true, format: { with: Record::CNAME_REGEX, message: 'is not a fully qualified domain name' }
5
+ validates :alias, presence: true, format: { with: Record::CNAME_REGEX, message: 'is not a fully qualified domain name' }
6
6
 
7
7
  def initialize(record)
8
8
  super
9
- @cname = Record.ensure_ends_with_dot(record.fetch(:cname))
9
+ @alias = Record.ensure_ends_with_dot(record.fetch(:alias))
10
10
  end
11
11
 
12
12
  def rdata
13
- { cname: cname }
13
+ { alias: self.alias }
14
14
  end
15
15
 
16
16
  def to_s
17
- "[ALIASRecord] #{fqdn} #{ttl} IN ALIAS #{cname}"
17
+ "[ALIASRecord] #{fqdn} #{ttl} IN ALIAS #{self.alias}"
18
18
  end
19
19
  end
20
20
  end
@@ -1,3 +1,3 @@
1
1
  module RecordStore
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -108,10 +108,12 @@ module RecordStore
108
108
  validate :validate_records
109
109
  validate :validate_config
110
110
  validate :validate_all_records_are_unique
111
- validate :validate_a_records_for_same_fqdn
112
111
  validate :validate_cname_records_for_same_fqdn
113
112
  validate :validate_cname_records_dont_point_to_root
113
+ validate :validate_same_ttl_for_records_sharing_fqdn_and_type
114
114
  validate :validate_provider_can_handle_zone_records
115
+ validate :validate_can_handle_alias_records
116
+ validate :validate_alias_points_to_root
115
117
 
116
118
  def self.from_yaml_definition(name, definition)
117
119
  new(name, definition.deep_symbolize_keys)
@@ -123,6 +125,7 @@ module RecordStore
123
125
  write(name, records: current_records, config: {
124
126
  provider: provider_name,
125
127
  ignore_patterns: [{type: "NS", fqdn: "#{name}."}],
128
+ supports_alias: current_records.map(&:type).include?('ALIAS') || nil
126
129
  }, **write_options)
127
130
  end
128
131
 
@@ -155,7 +158,7 @@ module RecordStore
155
158
  end
156
159
 
157
160
  def provider
158
- Provider.const_get(config.provider).new(zone: name.gsub(/\.\z/, ''))
161
+ Provider.const_get(config.provider).new(zone: name.chomp('.'))
159
162
  end
160
163
 
161
164
  def write(**write_options)
@@ -193,11 +196,12 @@ module RecordStore
193
196
  end
194
197
  end
195
198
 
196
- def validate_a_records_for_same_fqdn
197
- a_records = records.select { |record| record.is_a?(Record::A) }.group_by(&:fqdn)
198
- a_records.each do |fqdn, records|
199
- if records.map(&:ttl).uniq.size > 1
200
- errors.add(:records, "All A records for #{fqdn} should have the same TTL")
199
+ def validate_same_ttl_for_records_sharing_fqdn_and_type
200
+ records_sharing_fqdn_and_type = records.group_by { |record| [record.type, record.fqdn] }
201
+ records_sharing_fqdn_and_type.each do |(type, fqdn), matching_records|
202
+ all_ttls = matching_records.map(&:ttl).uniq
203
+ if all_ttls.length > 1
204
+ errors.add(:records, "All #{type} records for #{fqdn} should have the same TTL")
201
205
  end
202
206
  end
203
207
  end
@@ -245,5 +249,19 @@ module RecordStore
245
249
  errors.add(:records, "#{record_type} is a not a supported record type in #{config.provider}")
246
250
  end
247
251
  end
252
+
253
+ def validate_can_handle_alias_records
254
+ return unless records.any? { |record| record.is_a?(Record::ALIAS) }
255
+ return if config.supports_alias?
256
+ errors.add(:records, "#{config.provider} does not support ALIAS records for #{name.chomp('.')} zone")
257
+ end
258
+
259
+ def validate_alias_points_to_root
260
+ alias_record = records.find { |record| record.is_a?(Record::ALIAS) && record.fqdn != @name }
261
+
262
+ return unless alias_record
263
+
264
+ errors.add(:records, "ALIAS record should be defined on the root of the zone: #{alias_record}")
265
+ end
248
266
  end
249
267
  end
@@ -3,13 +3,18 @@ module RecordStore
3
3
  class Config
4
4
  include ActiveModel::Validations
5
5
 
6
- attr_reader :ignore_patterns, :provider
6
+ attr_reader :ignore_patterns, :provider, :supports_alias
7
7
 
8
8
  validate :validate_zone_config
9
9
 
10
- def initialize(ignore_patterns: [], provider: nil)
10
+ def initialize(ignore_patterns: [], provider: nil, supports_alias: nil)
11
11
  @ignore_patterns = ignore_patterns
12
12
  @provider = provider
13
+ @supports_alias = supports_alias
14
+ end
15
+
16
+ def supports_alias?
17
+ @supports_alias.nil? && valid_provider? ? Provider.const_get(provider).supports_alias? : @supports_alias
13
18
  end
14
19
 
15
20
  def to_hash
@@ -22,9 +27,11 @@ module RecordStore
22
27
  private
23
28
 
24
29
  def validate_zone_config
25
- unless Provider.constants.include?(provider.to_s.to_sym)
26
- errors.add(:provider, 'provider specified does not exist')
27
- end
30
+ errors.add(:provider, 'provider specified does not exist') unless valid_provider?
31
+ end
32
+
33
+ def valid_provider?
34
+ Provider.constants.include?(provider.to_s.to_sym)
28
35
  end
29
36
  end
30
37
  end
data/record_store.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_runtime_dependency 'fog'
26
26
  spec.add_runtime_dependency 'fog-json'
27
27
  spec.add_runtime_dependency 'fog-xml'
28
- spec.add_runtime_dependency 'fog-dynect'
28
+ spec.add_runtime_dependency 'fog-dynect', '~> 0.1.0'
29
29
  spec.add_runtime_dependency 'ejson'
30
30
 
31
31
  spec.add_development_dependency 'rake'
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: 2.0.0
4
+ version: 2.1.0
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: 2016-08-18 00:00:00.000000000 Z
12
+ date: 2016-09-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -99,16 +99,16 @@ dependencies:
99
99
  name: fog-dynect
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ">="
102
+ - - "~>"
103
103
  - !ruby/object:Gem::Version
104
- version: '0'
104
+ version: 0.1.0
105
105
  type: :runtime
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - ">="
109
+ - - "~>"
110
110
  - !ruby/object:Gem::Version
111
- version: '0'
111
+ version: 0.1.0
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: ejson
114
114
  requirement: !ruby/object:Gem::Requirement