configuration_service 3.0.0 → 4.0.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: e4a468a73fdaa5ac4d860611af3fe7f60bbb8533
4
- data.tar.gz: 1c7cd9e09bf66113b28950938b00299a420d0cc4
3
+ metadata.gz: 9022efdb20bd55a2a9f466600df663186ef5e068
4
+ data.tar.gz: f4050743be268be3f4c2127da10446209d5bdda2
5
5
  SHA512:
6
- metadata.gz: 7475e17b49bd4430c01850923eebd2ad3e4d1b5cf764e2c1f16d21552cefd5d854cf1c963edf2942568ad42b2d9917db052e0bf223f149fe27815878c97f90fc
7
- data.tar.gz: f024394e9df43fb5dfdc026c5cef4132f1529a85ae075af7c8205a264acb8d119f64eda80d646fc20e5950e5a5d9917276efcc5e88a0a9527c9320ca98711a2d
6
+ metadata.gz: 30da71e127b2c489218cf8b8b9aa0e95f4ad8784870cf1fda4fac1fdd123e2437e2c1604fd069a43ee7877127e02139e1d1494cfb7873fc8e1c1b3dbc3ab8b39
7
+ data.tar.gz: e56102407e1a649e409dffddc1a19483d48147336454ada41633f27967158fa02e1005c91b693e601cbe1ecaae4b6f67ead1ab81e9ac8e0a5e5ee24d87f2e03a
data/README.rdoc CHANGED
@@ -7,7 +7,7 @@ The configuration service provides
7
7
  of identified configuration data with metadata.
8
8
  The service supports {file:features/bootstrapping.feature bootstrapping}.
9
9
 
10
- A pluggable Ruby API is provided in {ConfigurationService::Base}.
10
+ A pluggable Ruby API is provided in {ConfigurationService::Client}.
11
11
 
12
12
  The declarative specification of the service is implemented with cucumber, using a pluggable imperative orchestration providers.
13
13
  This allows for implementations that are not providers to the Ruby API.
@@ -87,7 +87,7 @@ In practice, the administrative context would most likely come from the configur
87
87
 
88
88
  In the following example, the {ConfigurationService::Factory} defaults to using the
89
89
  {ConfigurationService::Factory::EnvironmentContext EnvironmentContext} to acquire application configuration
90
- from a non-administrative {ConfigurationService::Base} client.
90
+ from a non-administrative {ConfigurationService::Client} client.
91
91
  Part of the application configuration is then used as the context for an administrative {ConfigurationService::AdminClient},
92
92
  which is used as a model in the application.
93
93
 
@@ -127,7 +127,7 @@ If this configuration data was stored under the configuration identifier "acme",
127
127
 
128
128
  So this application would use the token "0b2...4af" to access its configuration data
129
129
  under the identifier "acme"
130
- with a non-administrative {ConfigurationService::Base} client.
130
+ with a non-administrative {ConfigurationService::Client} client.
131
131
  Part of its configuration data, in this case under the key "cs_config",
132
132
  provides {ConfigurationService::Factory::Context} for creating an administrative {ConfigurationService::AdminClient},
133
133
  which it would then use the token "c39...48a" to operate over multiple configuration identifiers on behalf of users.
@@ -11,23 +11,30 @@ module ConfigurationService
11
11
  # Interpretation of the credentials is provider-dependent; it is opaque to the API and client.
12
12
  # @param [Object] provider
13
13
  # a configured service provider instance, to which requests will be delegated.
14
- # @return [ConfigurationService::Client] client to interact with Configuration::Service
14
+ # @param [String] identifier
15
+ # unique configuration identifier (optional). If omitted, instance methods will require the +identifier+ argument.
15
16
  #
16
- def initialize(credentials, provider)
17
+ def initialize(credentials: nil, provider: nil, identifier: nil)
18
+ #raise(ArgumentError, "missing argument credentials") unless credentials
19
+ raise(ArgumentError, "missing argument provider") unless provider
17
20
  @credentials = credentials
18
21
  @provider = provider
22
+ @identifier = identifier
19
23
  end
20
24
 
21
25
  ##
22
26
  # Requests the configuration data and metadata
23
27
  # Delegates the request to the configured +provider+.
24
28
  #
25
- # @param [String] identifier unique identifier of configuration
29
+ # @param [String] identifier
30
+ # unique identifier of configuration. Required if the instance was initialized with a context that provided no +identifier+.
26
31
  # @return [ConfigurationService::Configuration] object containing the configuration data, metadata and identifier
27
- # @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the configured +identifier+
32
+ # @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the +identifier+
33
+ # @raise [ConfigurationService::Error] if no +identifier+ is given as an argument or supplied in the initialized context.
28
34
  # @raise [ConfigurationService::Error] if the request failed
29
35
  #
30
- def request_configuration(identifier)
36
+ def request_configuration(identifier: nil)
37
+ identifier = identifier_argument_or_instance_variable(identifier)
31
38
  @provider.request_configuration(identifier, @credentials) or
32
39
  raise ConfigurationNotFoundError, "configuration not found for identifier: #{identifier}"
33
40
  end
@@ -46,15 +53,17 @@ module ConfigurationService
46
53
  # and that values be limited to those that can be serialized to JSON.
47
54
  #
48
55
  # @param [String] identifier
49
- # unique configuration identifier
56
+ # unique identifier of configuration. Required if the instance was initialized with a context that provided no +identifier+.
50
57
  # @param [Hash] data
51
58
  # dictionary of probably sensitive configuration data intended for an application, which providers are expected to secure
52
59
  # @param [Hash] metadata
53
60
  # dictionary of data about the configuration data, which providers are not expected to secure
54
61
  # @return [ConfigurationService::Configuration] object containing the configuration data, decorated metadata and identifier
62
+ # @raise [ConfigurationService::Error] if no +identifier+ is given as an argument or supplied in the initialized context.
55
63
  # @raise [ConfigurationService::Error] if publication failed
56
64
  #
57
- def publish_configuration(identifier, data, metadata = {})
65
+ def publish_configuration(identifier: nil, data: nil, metadata: {})
66
+ identifier = identifier_argument_or_instance_variable(identifier)
58
67
  Utils.dictionary?(data) or raise ConfigurationService::Error, "data must be a dictionary"
59
68
  Utils.dictionary?(metadata) or raise ConfigurationService::Error, "metadata must be a dictionary"
60
69
 
@@ -67,16 +76,26 @@ module ConfigurationService
67
76
  # Authorize consumption of a configuration ie. get credentials to consume configurations ie. get a token to consume configurations
68
77
  #
69
78
  # @param [String] identifier
70
- # unique identifier of configuration
79
+ # unique identifier of configuration. Required if the instance was initialized with a context that provided no +identifier+.
71
80
  # @return [String] credentials allowing consumption of the provided configuration
72
81
  # @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the configured +identifier+
82
+ # @raise [ConfigurationService::Error] if no +identifier+ is given as an argument or supplied in the initialized context.
73
83
  # @raise [ConfigurationService::Error] if the request failed
74
84
  ##
75
- def authorize_consumption(identifier)
85
+ def authorize_consumption(identifier: nil)
86
+ identifier = identifier_argument_or_instance_variable(identifier)
76
87
  @provider.authorize_consumption(identifier, @credentials) or
77
88
  raise ConfigurationNotFoundError, "configuration not found for identifier: #{identifier}"
78
89
  end
79
90
 
91
+ private
92
+
93
+ def identifier_argument_or_instance_variable(identifier)
94
+ identifier ||= @identifier
95
+ raise(ConfigurationService::Error, "missing argument identifier (required when initialized without identifier)") unless identifier
96
+ identifier
97
+ end
98
+
80
99
  end
81
100
 
82
101
  end
@@ -10,7 +10,7 @@ module ConfigurationService
10
10
  # @attr_reader [Hash] metadata
11
11
  # dictionary of data about the configuration data, which providers are not expected to secure
12
12
  #
13
- # @see ConfigurationService::Base#publish_configuration
13
+ # @see ConfigurationService::Client#publish_configuration
14
14
  #
15
15
  class Configuration
16
16
 
@@ -7,11 +7,10 @@ module ConfigurationService
7
7
  ##
8
8
  # A factory context for static factory configuration
9
9
  #
10
- # The typical use case for this class is in constructing an {ConfigurationService::AdminClient AdminClient}
10
+ # The typical use case for this class is in constructing a multi-identifier {ConfigurationService::Client Client}
11
11
  # using a data structure acquired from a secure source that does not need to be scrubbed.
12
12
  #
13
13
  # @see ConfigurationService::Factory.create_client
14
- # @see ConfigurationService::Factory.create_admin_client
15
14
  #
16
15
  class Context
17
16
 
@@ -24,9 +23,9 @@ module ConfigurationService
24
23
  # The following keys are used by the {ConfigurationService::Factory}:
25
24
  #
26
25
  # [identifier] the unique identity of the configuration data
27
- # (see {ConfigurationService::Base#initialize})
26
+ # (see {ConfigurationService::Client#initialize})
28
27
  # [token] authorization token for the identified configuration data
29
- # (see {ConfigurationService::Base#initialize})
28
+ # (see {ConfigurationService::Client#initialize})
30
29
  # [provider_id] the unique identity of the service provider
31
30
  # (see {ConfigurationService::ProviderRegistry})
32
31
  # [provider_config] configuration options for the service provider
@@ -39,12 +38,18 @@ module ConfigurationService
39
38
  ##
40
39
  # The unique identity of the configuration data
41
40
  #
42
- # Required for {ConfigurationService::Base}. Not used by {ConfigurationService::AdminClient}.
43
- #
44
41
  def identifier
45
42
  @env[:identifier]
46
43
  end
47
44
 
45
+ ##
46
+ #
47
+ # Whether the context includes an +identifier+
48
+ #
49
+ def identifier?
50
+ @env.include?(:identifier)
51
+ end
52
+
48
53
  ##
49
54
  # Authorization token for the identified configuration data
50
55
  #
@@ -39,9 +39,9 @@ module ConfigurationService
39
39
  # The sources are scanned for {#prefix} matches, within which the following variables are used:
40
40
  #
41
41
  # [IDENTIFIER] the unique identity of the configuration data
42
- # (see {ConfigurationService::Base#initialize})
42
+ # (see {ConfigurationService::Client#initialize})
43
43
  # [TOKEN] authorization token for the identified configuration data
44
- # (see {ConfigurationService::Base#initialize})
44
+ # (see {ConfigurationService::Client#initialize})
45
45
  # [PROVIDER] the unique identity of the service provider
46
46
  # (see {ConfigurationService::ProviderRegistry})
47
47
  # [PROVIDER_*] configuration options for the service provider
@@ -19,9 +19,9 @@ module ConfigurationService
19
19
  # The environment is scanned for {EnvironmentContext#prefix} matches, within which the following variables are used:
20
20
  #
21
21
  # [IDENTIFIER] the unique identity of the configuration data
22
- # (see {ConfigurationService::Base#initialize})
22
+ # (see {ConfigurationService::Client#initialize})
23
23
  # [TOKEN] authorization token for the identified configuration data
24
- # (see {ConfigurationService::Base#initialize})
24
+ # (see {ConfigurationService::Client#initialize})
25
25
  # [PROVIDER] the unique identity of the service provider
26
26
  # (see {ConfigurationService::ProviderRegistry})
27
27
  # [PROVIDER_*] configuration options for the service provider
@@ -34,13 +34,13 @@ module ConfigurationService
34
34
  # A service provider instance is then constructed with a dictionary of the +PROVIDER_*+ variables,
35
35
  # in which the keys are the name of the variable without +PROVIDER_+, downcased and intern'd.
36
36
  #
37
- # Then a service {ConfigurationService::Base} is constructed with the +IDENTIFIER+, +TOKEN+ and service provider instance.
37
+ # Then a service {ConfigurationService::Client} is constructed with the +IDENTIFIER+, +TOKEN+ and service provider instance.
38
38
  #
39
39
  # And finally, the environment is scrubbed of the variables used, to protect them from accidental exposure
40
40
  # (e.g. in an exception handler that prints the environment). On JRuby, system properties are scrubbed of variables used as well,
41
41
  # regardless of whether they were overridden by environment variables.
42
42
  #
43
- # @return [ConfigurationService::Base] the configuration service instance created
43
+ # @return [ConfigurationService::Client] the configuration service instance created
44
44
  # @raise [ProviderNotFoundError] if no service provider has been registered with the name given by +PROVIDER+
45
45
  #
46
46
  # @deprecated Use {ConfigurationService::Factory} instead.
@@ -33,15 +33,18 @@ module ConfigurationService
33
33
  # configuraton = configuration_service.request_configuration
34
34
  # AcmeApplication.new(configuration.data).run
35
35
  #
36
- # @example Creating an {ConfigurationService::AdminClient AdminClient} with static bootstrap configuration
36
+ # @example Creating a multi-identifier client with static bootstrap configuration
37
37
  #
38
- # admin_client = ConfigurationService::Factory.create_admin_client(
38
+ # admin_client = ConfigurationService::Factory.create_client(
39
39
  # "token" => "c3935418-f621-40de-ada3-cc8169f1348a",
40
+ # # Note: no identifier provided
40
41
  # "provider_id" => "vault",
41
42
  # "provider_config" => {
42
43
  # "address" => "http://127.0.0.1:8200"
43
44
  # }
44
45
  # )
46
+ # acme_config = admin_client.request_configuration(identifier: "acme")
47
+ # wile_config = admin_client.request_configuration(identifier: "wile")
45
48
  #
46
49
  module Factory
47
50
 
@@ -50,19 +53,21 @@ module ConfigurationService
50
53
  #
51
54
  # @param [ConfigurationService::Factory::EnvironmentContext, ConfigurationService::Factory::Context, Hash] context
52
55
  # the factory context
53
- # @return [ConfigurationService::Base] the configuration service client created
56
+ # @return [ConfigurationService::Client] the configuration service client created
54
57
  #
55
58
  # When the +context+ is a Hash, it is wrapped in a {ConfigurationService::Factory::Context}, which does not scrub
56
59
  # sources after the configuration service client is created. For this reason, the process +ENV+ should never
57
60
  # be given as the +context+; rather give no +context+, so that the default {ConfigurationService::Factory::EnvironmentContext}
58
61
  # will be used to safely scrub the process +ENV+ and (on JRuby) system properties after the configuration service client is created.
59
62
  #
60
- # The context must provide an +identifier+ property.
63
+ # If the context does not provide an +identifier+ property, the instance methods on the client object will require
64
+ # an +identifier+ argument.
61
65
  #
62
66
  def self.create_client(context = EnvironmentContext.new)
63
67
  context = Context.new(context) if context.is_a?(Hash)
64
68
  provider = create_provider(context)
65
- ConfigurationService::Client.new(context.token, provider)
69
+ identifier = context.identifier? ? context.identifier : nil
70
+ ConfigurationService::Client.new(credentials: context.token, provider: provider, identifier: identifier)
66
71
  ensure
67
72
  context.scrub!
68
73
  end
@@ -3,7 +3,7 @@ module ConfigurationService
3
3
  module Provider
4
4
 
5
5
  ##
6
- # A stub broken {ConfigurationService::Base} service provider
6
+ # A stub broken {ConfigurationService::Client} service provider
7
7
  #
8
8
  # Used to validate the test framework architecture.
9
9
  #
@@ -50,7 +50,7 @@ module ConfigurationService
50
50
  # @return [nil] if not found
51
51
  # @raise [ConfigurationService::AuthorizationError] if not authorized for the +:consumer+ role
52
52
  #
53
- # @see ConfigurationService::Base#request_configuration
53
+ # @see ConfigurationService::Client#request_configuration
54
54
  #
55
55
  def request_configuration(identifier, credentials)
56
56
  authorize_request(:consumer, credentials)
@@ -71,7 +71,7 @@ module ConfigurationService
71
71
  # @return [ConfigurationService::Configuration] published configuration
72
72
  # @raise [ConfigurationService::Error] on failure.
73
73
  #
74
- # @see ConfigurationService::Base#publish_configuration
74
+ # @see ConfigurationService::Client#publish_configuration
75
75
  #
76
76
  def publish_configuration(configuration, credentials)
77
77
  authorize_request(:publisher, credentials)
@@ -2,7 +2,7 @@ module ConfigurationService
2
2
 
3
3
  ##
4
4
  # A configuration service provider is an imperative implementation of the configuration service API,
5
- # to be plugged into a {ConfigurationService::Base}.
5
+ # to be plugged into a {ConfigurationService::Client}.
6
6
  #
7
7
  # A {ConfigurationService::Provider::Stub} implementation is provided to validate the test framework architecture.
8
8
  #
@@ -11,7 +11,7 @@ module ConfigurationService
11
11
  #
12
12
  # Extend this class if you want your test orchestration provider toconstrain your implementation's interface
13
13
  # to work as a configuration service provider.
14
- # If you have no intention of plugging your implementation into {ConfigurationService::Base},
14
+ # If you have no intention of plugging your implementation into {ConfigurationService::Client},
15
15
  # build your own test orchestration provider from scratch, using {ConfigurationService::Test::Orchestrator}
16
16
  # and {ConfigurationService::Test::StubOrchestrationProvider} as a guide.
17
17
  #
@@ -63,7 +63,7 @@ module ConfigurationService
63
63
  ##
64
64
  # The service provider under test
65
65
  #
66
- # @return [Object] a provider to be plugged into {ConfigurationService::Base}
66
+ # @return [Object] a provider to be plugged into {ConfigurationService::Client}
67
67
  #
68
68
  def service_provider
69
69
  raise NotImplementedError, "#{self.class} must implement service_provider"
@@ -72,7 +72,7 @@ module ConfigurationService
72
72
  ##
73
73
  # A broken service provider
74
74
  #
75
- # @return [Object] a provider to be plugged into {ConfigurationService::Base}.
75
+ # @return [Object] a provider to be plugged into {ConfigurationService::Client}.
76
76
  # The service provider's +publish_configuration+ and +request_configuration+ methods
77
77
  # must raise an {ConfigurationService::Error} other than {ConfigurationService::AuthorizationError}.
78
78
  #
@@ -175,11 +175,11 @@ module ConfigurationService
175
175
  #
176
176
  # @return [ConfigurationService::Test::Response]
177
177
  #
178
- # @see ConfigurationService::Base#request_configuration
178
+ # @see ConfigurationService::Client#request_configuration
179
179
  #
180
180
  def request_configuration
181
181
  wrap_response do
182
- @requested_configuration = service.request_configuration(@identifier)
182
+ @requested_configuration = service.request_configuration(identifier: @identifier)
183
183
  end
184
184
  end
185
185
 
@@ -189,7 +189,7 @@ module ConfigurationService
189
189
  # @return [String] credentials allowing consumption of a configuration
190
190
  ##
191
191
  def authorize_consumption
192
- @credentials = service.authorize_consumption(@identifier)
192
+ @credentials = service.authorize_consumption(identifier: @identifier)
193
193
  end
194
194
 
195
195
  def credentials_allow_consumption?
@@ -210,14 +210,14 @@ module ConfigurationService
210
210
  #
211
211
  # @return [ConfigurationService::Test::Response]
212
212
  #
213
- # @see ConfigurationService::Base#publish_configuration
213
+ # @see ConfigurationService::Client#publish_configuration
214
214
  #
215
215
  def publish_configuration
216
216
  wrap_response do
217
217
  if @metadata
218
- service.publish_configuration(@identifier, configuration, @metadata)
218
+ service.publish_configuration(identifier: @identifier, data: configuration, metadata: @metadata)
219
219
  else
220
- service.publish_configuration(@identifier, configuration)
220
+ service.publish_configuration(identifier: @identifier, data: configuration)
221
221
  end
222
222
  end
223
223
  end
@@ -272,7 +272,7 @@ module ConfigurationService
272
272
  provider = broken_service_provider
273
273
  end
274
274
 
275
- ConfigurationService::Client.new(@credentials, provider)
275
+ ConfigurationService::Client.new(credentials: @credentials, provider: provider)
276
276
  end
277
277
 
278
278
  def authorized_as(role)
@@ -14,11 +14,11 @@ module ConfigurationService
14
14
  # It keeps no domain state, because that would couple it to the
15
15
  # service implementation. By making no assumptions at all about the API
16
16
  # or data, it allows implementors to produce service implementations
17
- # that do not adhere to the anticipated {ConfigurationService::Base} API,
17
+ # that do not adhere to the anticipated {ConfigurationService::Client} API,
18
18
  # by writing their own test orchestration provider from scratch
19
19
  # instead of extending {ConfigurationService::Test::OrchestrationProvider}.
20
20
  #
21
- # However, implementors who are trying to produce {ConfigurationService::Base}
21
+ # However, implementors who are trying to produce {ConfigurationService::Client}
22
22
  # providers should extend {ConfigurationService::Test::OrchestrationProvider},
23
23
  # which anticipates a compatible provider API.
24
24
  #
@@ -280,7 +280,7 @@ module ConfigurationService
280
280
  #
281
281
  def bootstrapped_configuration_service_functional?
282
282
  response = begin
283
- ConfigurationService::Test::Response::Success.new(@service.request_configuration('test'))
283
+ ConfigurationService::Test::Response::Success.new(@service.request_configuration(identifier: 'test'))
284
284
  rescue ConfigurationService::Error => e
285
285
  ConfigurationService::Test::Response::Failure.new(e)
286
286
  end
@@ -1,5 +1,5 @@
1
1
  module ConfigurationService
2
2
 
3
- VERSION = "3.0.0"
3
+ VERSION = "4.0.0"
4
4
 
5
5
  end
@@ -15,6 +15,7 @@ module ConfigurationService
15
15
  # Creates a new {ConfigurationService::Base}
16
16
  #
17
17
  # @see ConfigurationService::Base#initialize
18
+ # @deprecated use ConfigurationService::Client instead
18
19
  #
19
20
  def self.new(identifier, token, provider)
20
21
  ConfigurationService::Base.new(identifier, token, provider)
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: 3.0.0
4
+ version: 4.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: 2016-08-15 00:00:00.000000000 Z
11
+ date: 2016-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -158,3 +158,4 @@ signing_key:
158
158
  specification_version: 4
159
159
  summary: Configuration service
160
160
  test_files: []
161
+ has_rdoc: