configuration_service 0.0.1 → 1.0.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 +4 -4
- data/configuration_service.gemspec +1 -1
- data/lib/configuration_service/base.rb +26 -24
- data/lib/configuration_service/configuration.rb +5 -2
- data/lib/configuration_service/provider/broken.rb +2 -2
- data/lib/configuration_service/provider/stub.rb +18 -33
- data/lib/configuration_service/test/orchestration_provider.rb +22 -36
- data/lib/configuration_service/test/orchestration_provider_registry.rb +1 -1
- data/lib/configuration_service/test/orchestrator.rb +0 -25
- data/lib/configuration_service/test/stub_orchestration_provider.rb +2 -4
- data/lib/configuration_service.rb +4 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 013e070f4e04c050a8fdd8232cac7fb22cb652b1
|
4
|
+
data.tar.gz: 3d329fe8548014c9e43e1553a1e506d5438c6a7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 226d8f3472c3a62716ced933186f5f926388575f29ab8ce91527d8b6ef19d5f9080409519dd8ecf37e405854705c17f7942ad6f994d8d4c76690866cc3438be9
|
7
|
+
data.tar.gz: df846414184710ca2d20903e017f1712897e4df8c97dc569f3296eb8bf1ce5a5224586ed531dc8e00985822f42e4405020b89232e54e9b59ba2171ba8f3f2754
|
@@ -12,32 +12,44 @@ module ConfigurationService
|
|
12
12
|
class Base
|
13
13
|
|
14
14
|
##
|
15
|
-
# Creates a new API instance for the +provider+
|
15
|
+
# Creates a new API instance for the service +provider+
|
16
16
|
#
|
17
|
-
|
17
|
+
# The +identifier+ is a string that uniquely identifies some configuration data and associated metadata.
|
18
|
+
# It might be the name of a service or service component. It might include an environment label (e.g.
|
19
|
+
# production, staging, etc.) For example:
|
20
|
+
#
|
21
|
+
# * billing.acme.com
|
22
|
+
# * billing-web1.acme.com
|
23
|
+
# * billing/production/web1
|
24
|
+
#
|
25
|
+
# The +token+ is a string that authorizes the client to access the configuration data and associated metadata.
|
26
|
+
# Interpretation of the +token+ is provider-dependent; it is opaque to the API and client.
|
27
|
+
#
|
28
|
+
# The +provider+ is a configured service provider instance.
|
29
|
+
#
|
30
|
+
def initialize(identifier, token, provider)
|
31
|
+
@identifier = identifier
|
32
|
+
@token = token
|
18
33
|
@provider = provider
|
19
34
|
end
|
20
35
|
|
21
36
|
##
|
22
|
-
# Requests configuration data and metadata
|
37
|
+
# Requests the configuration data and metadata for the +identifier+
|
23
38
|
#
|
24
|
-
# Delegates the request to the provider.
|
25
|
-
# may be supplied to restrict access to, for example, a specific revision
|
26
|
-
# of the configuration.
|
39
|
+
# Delegates the request to the provider.
|
27
40
|
#
|
28
41
|
# Returns a Configuration object or raises an Error on failure.
|
29
42
|
# Returns +nil+ if no matching configuration was found.
|
30
43
|
#
|
31
|
-
def request_configuration
|
32
|
-
@provider.request_configuration(
|
44
|
+
def request_configuration
|
45
|
+
@provider.request_configuration(@identifier, @token)
|
33
46
|
end
|
34
47
|
|
35
48
|
##
|
36
49
|
# Publishes configuration +data+ and optional +metadata+
|
37
50
|
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# copy of the +metadata+ decorated with the following keys:
|
51
|
+
# The +data+ and the +metadata+ (if specified) must be dictionaries (responding to #to_hash or #to_h).
|
52
|
+
# The provider receives a a Configuration object, whose +metadata+ is decorated with the following keys:
|
41
53
|
#
|
42
54
|
# * "timestamp" - the current UTC time in ISO8601 format
|
43
55
|
# * "revision" - a UUID for this publication
|
@@ -50,19 +62,9 @@ module ConfigurationService
|
|
50
62
|
dictionary?(data) or raise ConfigurationService::Error, "data must be a dictionary"
|
51
63
|
dictionary?(metadata) or raise ConfigurationService::Error, "metadata must be a dictionary"
|
52
64
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
##
|
57
|
-
# True if the +metadata+ matches the +metadata_filter+
|
58
|
-
#
|
59
|
-
# The +metadata+ matches the +metadata_filter+ if every key in the +metadata_filter+
|
60
|
-
# is present in the +metadata+, and the values of both keys are equal (==).
|
61
|
-
#
|
62
|
-
# This is a utility method intended for use by providers.
|
63
|
-
#
|
64
|
-
def self.metadata_matches_filter?(metadata, metadata_filter)
|
65
|
-
metadata_filter.all? { |k, v| v == metadata[k] }
|
65
|
+
metadata = decorate(metadata)
|
66
|
+
configuration = Configuration.new(@identifier, data, metadata)
|
67
|
+
@provider.publish_configuration(configuration, @token)
|
66
68
|
end
|
67
69
|
|
68
70
|
private
|
@@ -3,6 +3,7 @@ module ConfigurationService
|
|
3
3
|
##
|
4
4
|
# Encapsulates configuration +data+ and its +metadata+
|
5
5
|
#
|
6
|
+
# * +identifier is the string identifier of the data and metadata.
|
6
7
|
# * +data+ is a dictionary of (possibly sensitive) configuration data,
|
7
8
|
# which providers are expected to secure.
|
8
9
|
# * +metadata+ is a dictionary of data about the configuration data,
|
@@ -13,12 +14,14 @@ module ConfigurationService
|
|
13
14
|
#
|
14
15
|
class Configuration
|
15
16
|
|
16
|
-
|
17
|
+
# TODO consider removing :revision as an attr
|
18
|
+
attr_reader :identifier, :data, :metadata, :revision # :nodoc:
|
17
19
|
|
18
20
|
##
|
19
21
|
# Returns a new Configuration
|
20
22
|
#
|
21
|
-
def initialize(data, metadata)
|
23
|
+
def initialize(identifier, data, metadata)
|
24
|
+
@identifier = identifier
|
22
25
|
@data = data
|
23
26
|
@metadata = metadata
|
24
27
|
@revision = metadata["revision"]
|
@@ -12,14 +12,14 @@ module ConfigurationService
|
|
12
12
|
##
|
13
13
|
# Raises Error
|
14
14
|
#
|
15
|
-
def publish_configuration(
|
15
|
+
def publish_configuration(configuration, token)
|
16
16
|
raise ConfigurationService::Error, "error requested by test"
|
17
17
|
end
|
18
18
|
|
19
19
|
##
|
20
20
|
# Raises Error
|
21
21
|
#
|
22
|
-
def request_configuration(
|
22
|
+
def request_configuration(identifier, token)
|
23
23
|
raise ConfigurationService::Error, "error requested by test"
|
24
24
|
end
|
25
25
|
|
@@ -3,7 +3,6 @@ require "securerandom"
|
|
3
3
|
|
4
4
|
require "configuration_service"
|
5
5
|
|
6
|
-
require_relative "broken"
|
7
6
|
require_relative "stub_store"
|
8
7
|
|
9
8
|
module ConfigurationService
|
@@ -29,12 +28,7 @@ module ConfigurationService
|
|
29
28
|
##
|
30
29
|
# Returns a new Stub
|
31
30
|
#
|
32
|
-
|
33
|
-
# authorization +token+ and holds a reference to the singleton StubStore.
|
34
|
-
#
|
35
|
-
def initialize(identifier, token)
|
36
|
-
@identifier = identifier
|
37
|
-
@token = token
|
31
|
+
def initialize
|
38
32
|
@configurations = StubStore.instance
|
39
33
|
end
|
40
34
|
|
@@ -43,50 +37,41 @@ module ConfigurationService
|
|
43
37
|
#
|
44
38
|
# See Base#request_configuration.
|
45
39
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# An optional +metadata_filter+ may be supplied to restrict access to, for
|
49
|
-
# example, a specific revision of the configuration.
|
40
|
+
# Fetches configuration from the singleton StubStore.
|
50
41
|
#
|
51
42
|
# Returns a Configuration object or raises AuthorizationError if the
|
52
|
-
#
|
53
|
-
# Returns +nil+ if no matching configuration was found.
|
43
|
+
# +token+ is not for the +:consumer+ role.
|
54
44
|
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
45
|
+
# Returns +nil+ if no configuration was found for the +identifier+.
|
46
|
+
#
|
47
|
+
def request_configuration(identifier, token)
|
48
|
+
authorize_request(:consumer, token)
|
49
|
+
data, metadata = @configurations.fetch(identifier)
|
50
|
+
Configuration.new(identifier, data, metadata)
|
61
51
|
rescue KeyError
|
62
52
|
nil
|
63
53
|
end
|
64
54
|
|
65
55
|
##
|
66
|
-
# Publishes configuration
|
56
|
+
# Publishes configuration
|
67
57
|
#
|
68
58
|
# See Base#publish_configuration.
|
69
59
|
#
|
70
|
-
#
|
71
|
-
# (responding to #to_hash or #to_h). The provider receives a copy of the
|
72
|
-
# +metadata+ decorated with the following keys:
|
73
|
-
#
|
74
|
-
# * "timestamp" - the current UTC time in ISO8601 format
|
75
|
-
# * "revision" - a UUID for this publication
|
60
|
+
# +configuration+ should be a Configuration object or similar.
|
76
61
|
#
|
77
62
|
# Returns a Configuration object or raises an Error on failure.
|
78
63
|
#
|
79
|
-
def publish_configuration(
|
80
|
-
authorize_request(:publisher)
|
81
|
-
@configurations.store(
|
82
|
-
|
64
|
+
def publish_configuration(configuration, token)
|
65
|
+
authorize_request(:publisher, token)
|
66
|
+
@configurations.store(configuration.identifier, configuration.data, configuration.metadata)
|
67
|
+
configuration
|
83
68
|
end
|
84
69
|
|
85
70
|
private
|
86
71
|
|
87
|
-
def authorize_request(role)
|
88
|
-
raise AuthorizationError.new("missing token") unless
|
89
|
-
raise AuthorizationError.new("authorization failed") unless
|
72
|
+
def authorize_request(role, token)
|
73
|
+
raise AuthorizationError.new("missing token") unless token
|
74
|
+
raise AuthorizationError.new("authorization failed") unless token == BUILTIN_TOKENS[role]
|
90
75
|
end
|
91
76
|
|
92
77
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'cucumber/errors'
|
1
2
|
require 'configuration_service'
|
2
3
|
|
3
4
|
module ConfigurationService
|
@@ -65,13 +66,6 @@ module ConfigurationService
|
|
65
66
|
@metadata = {"version" => "1.0"}
|
66
67
|
end
|
67
68
|
|
68
|
-
##
|
69
|
-
# See Orchestrator#given_metadata_filter
|
70
|
-
#
|
71
|
-
def given_metadata_filter
|
72
|
-
@metadata_filter = {"revision" => "d4d40eab-cf66-4af5-9a77-d956a11682de"}
|
73
|
-
end
|
74
|
-
|
75
69
|
##
|
76
70
|
# See Orchestrator#given_existing_configuration
|
77
71
|
#
|
@@ -98,22 +92,6 @@ module ConfigurationService
|
|
98
92
|
end
|
99
93
|
end
|
100
94
|
|
101
|
-
##
|
102
|
-
# See Orchestrator#given_existing_configuration_matching_metadata_filter
|
103
|
-
#
|
104
|
-
def given_existing_configuration_matching_metadata_filter
|
105
|
-
@metadata_matching_filter = (@metadata || {}).merge(@metadata_filter)
|
106
|
-
given_existing_configuration
|
107
|
-
end
|
108
|
-
|
109
|
-
##
|
110
|
-
# See Orchestrator#given_existing_configuration_not_matching_metadata_filter
|
111
|
-
#
|
112
|
-
def given_existing_configuration_not_matching_metadata_filter
|
113
|
-
@metadata_matching_filter = {}
|
114
|
-
given_existing_configuration
|
115
|
-
end
|
116
|
-
|
117
95
|
##
|
118
96
|
# See Orchestrator#existing_configuration
|
119
97
|
#
|
@@ -135,11 +113,7 @@ module ConfigurationService
|
|
135
113
|
#
|
136
114
|
def request_configuration
|
137
115
|
wrap_response do
|
138
|
-
|
139
|
-
service.request_configuration(@metadata_filter)
|
140
|
-
else
|
141
|
-
service.request_configuration
|
142
|
-
end
|
116
|
+
service.request_configuration
|
143
117
|
end
|
144
118
|
end
|
145
119
|
|
@@ -152,8 +126,6 @@ module ConfigurationService
|
|
152
126
|
wrap_response do
|
153
127
|
if @metadata
|
154
128
|
service.publish_configuration(configuration, @metadata)
|
155
|
-
elsif @metadata_matching_filter
|
156
|
-
service.publish_configuration(configuration, @metadata_matching_filter)
|
157
129
|
else
|
158
130
|
service.publish_configuration(configuration)
|
159
131
|
end
|
@@ -216,17 +188,31 @@ module ConfigurationService
|
|
216
188
|
raise NotImplementedError, "#{self.class} must implement token_for(role)"
|
217
189
|
end
|
218
190
|
|
191
|
+
##
|
192
|
+
# Raise a Cucumber::Pending exception
|
193
|
+
#
|
194
|
+
# This allows incomplete implementations to mark features as pending
|
195
|
+
#
|
196
|
+
def pending(message = nil) # :doc:
|
197
|
+
if message
|
198
|
+
raise Cucumber::Pending, message
|
199
|
+
else
|
200
|
+
raise Cucumber::Pending
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
219
204
|
def configuration
|
220
205
|
@configuration ||= {"verbose" => true}
|
221
206
|
end
|
222
207
|
|
223
208
|
def service
|
224
|
-
if @fail_next
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
209
|
+
provider = if @fail_next
|
210
|
+
@fail_next = false
|
211
|
+
broken_service_provider
|
212
|
+
else
|
213
|
+
service_provider
|
214
|
+
end
|
215
|
+
ConfigurationService.new(@identifier, @token, provider)
|
230
216
|
end
|
231
217
|
|
232
218
|
def authorized_as(role)
|
@@ -29,7 +29,7 @@ module ConfigurationService
|
|
29
29
|
##
|
30
30
|
# Return the +provider+ identified by the string +identifier+
|
31
31
|
#
|
32
|
-
# The +provider must already have been registered with #register,
|
32
|
+
# The +provider+ must already have been registered with #register,
|
33
33
|
# and should be a class with a default (nullary) constructor.
|
34
34
|
#
|
35
35
|
# Returns +nil+ if no provider has been registered with the given
|
@@ -44,13 +44,6 @@ module ConfigurationService
|
|
44
44
|
@provider.given_metadata
|
45
45
|
end
|
46
46
|
|
47
|
-
##
|
48
|
-
# Include a metadata filter in the next consuming operation
|
49
|
-
#
|
50
|
-
def given_metadata_filter
|
51
|
-
@provider.given_metadata_filter
|
52
|
-
end
|
53
|
-
|
54
47
|
##
|
55
48
|
# Arrange a published configuration fixture
|
56
49
|
def given_existing_configuration
|
@@ -71,24 +64,6 @@ module ConfigurationService
|
|
71
64
|
@provider.given_missing_configuration
|
72
65
|
end
|
73
66
|
|
74
|
-
##
|
75
|
-
# Arrange a published configuration fixture
|
76
|
-
#
|
77
|
-
# Use a metadata filter that matches the fixture's metadata in the next consuming operation.
|
78
|
-
#
|
79
|
-
def given_existing_configuration_matching_metadata_filter
|
80
|
-
@provider.given_existing_configuration_matching_metadata_filter
|
81
|
-
end
|
82
|
-
|
83
|
-
##
|
84
|
-
# Arrange a published configuration fixture
|
85
|
-
#
|
86
|
-
# Use a metadata filter that does not match the fixture's metadata in the next consuming operation.
|
87
|
-
#
|
88
|
-
def given_existing_configuration_not_matching_metadata_filter
|
89
|
-
@provider.given_existing_configuration_not_matching_metadata_filter
|
90
|
-
end
|
91
|
-
|
92
67
|
##
|
93
68
|
# Return a published configuration fixture
|
94
69
|
#
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "configuration_service/provider/broken"
|
1
2
|
require "configuration_service/provider/stub"
|
2
3
|
require "configuration_service/test"
|
3
4
|
|
@@ -17,11 +18,8 @@ module ConfigurationService
|
|
17
18
|
##
|
18
19
|
# Returns a new Stub
|
19
20
|
#
|
20
|
-
# The object is initialized with the currently #authorize'd +token+
|
21
|
-
# and consistently used configuration +identifier+.
|
22
|
-
#
|
23
21
|
def service_provider # :doc:
|
24
|
-
ConfigurationService::Provider::Stub.new
|
22
|
+
ConfigurationService::Provider::Stub.new
|
25
23
|
end
|
26
24
|
|
27
25
|
##
|
@@ -10,8 +10,10 @@ module ConfigurationService
|
|
10
10
|
##
|
11
11
|
# Creates a new ConfigurationService::Base for the +provider+
|
12
12
|
#
|
13
|
-
|
14
|
-
|
13
|
+
# See ConfigurationService::Base#initialize.
|
14
|
+
#
|
15
|
+
def self.new(identifier, token, provider)
|
16
|
+
ConfigurationService::Base.new(identifier, token, provider)
|
15
17
|
end
|
16
18
|
|
17
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configuration_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sheldon Hearn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -119,3 +119,4 @@ signing_key:
|
|
119
119
|
specification_version: 4
|
120
120
|
summary: Configuration service
|
121
121
|
test_files: []
|
122
|
+
has_rdoc:
|