soar-registry-directory 4.0.5 → 5.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: 028c696fe4354e757584a552ba8540d3e1aa222c
4
- data.tar.gz: 8f29ac83d07c6e88c7335a178d2a74b530155207
3
+ metadata.gz: f7534aad40030456e9a4b9fc88d8a58d52e2817a
4
+ data.tar.gz: 1afbcb2d7d1a1441eb2e0e5067399c237e3fb19f
5
5
  SHA512:
6
- metadata.gz: 99bbd361eff61065eb6f67002113464a576de434bb47168812c0669647617c2af2f189719ec3b6b3f19f81ae9cc47bf7c935711abe76aeb3740e064d99a30651
7
- data.tar.gz: 7f9d2e5506a53f05c4e45f73cc67ddd9ae8bb6bb90fb3d37ee17cdfe0d92f2a822c14716c2104ccf29e9970062aa58610d8e58396d5fa3520916bca1c3bce3cd
6
+ metadata.gz: 4ba850d7503dffb59cf24d74eff42a43acdb1b145d4920b7e2b053bfcbbf449d8c7ddc76986575b6b4725251b1fe867b3201c54275bd9729bfb9de6ff9337d7d
7
+ data.tar.gz: f567f1b47129a1a61997af5b08f29e19c12671dead9e6d8a38974847fa282d6701c4df17fe1709661c3d7f13f7e304953c9ad05a31513c8ab326f64fa017c1eb
data/README.md CHANGED
@@ -34,7 +34,9 @@ Create an instance of the stub provider by passing in the name, primary key and
34
34
  password: "secret"
35
35
  },
36
36
  table: "mytable",
37
- index: ['uuid', 'email'],
37
+ index:
38
+ partition_key: 'uuid',
39
+ sort_key: 'role'
38
40
  config: {
39
41
  region: 'us-west-2'
40
42
  endpoint: 'http://localhost:8000'
@@ -116,6 +118,7 @@ $ cucumber
116
118
  ```bash
117
119
  docker-compose --file docker-compose.stub.yml --project-name soar-registry-directory-provider-stub up --abort-on-container-exit --remove-orphans --build --force-recreate
118
120
  EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryproviderstub_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
121
+ docker-compose --file docker-compose.stub.yml --project-name soar-registry-directory-provider-stub down --rmi local
119
122
  exit $EXIT_CODE
120
123
  ```
121
124
 
@@ -125,12 +128,14 @@ exit $EXIT_CODE
125
128
  ```bash
126
129
  $ docker-compose --file docker-compose.dynamo_db.yml up --remove-orphans
127
130
  $ CONFIG_FILE=config.dynamo_db.yml TEST_ORCHESTRATION_PROVIDER=DynamoDb cucumber
131
+ $ docker-compose --file docker-compose.dynamo_db.yml down local
128
132
  ```
129
133
 
130
134
  #### CI
131
135
  ```bash
132
136
  docker-compose --file docker-compose.ci.dynamo_db.yml --project-name soar-registry-directory-provider-dynamo_db up --abort-on-container-exit --remove-orphans --build --force-recreate
133
137
  EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryproviderdynamodb_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
138
+ docker-compose --file docker-compose.ci.dynamo_db.yml --project-name soar-registry-directory-provider-dynamo_db down --rmi local
134
139
  exit $EXIT_CODE
135
140
  ```
136
141
 
@@ -140,12 +145,14 @@ exit $EXIT_CODE
140
145
  ```bash
141
146
  $ docker-compose --file docker-compose.ldap.yml up --remove-orphans
142
147
  $ CONFIG_FILE=config.ldap.yml TEST_ORCHESTRATION_PROVIDER=Ldap cucumber
148
+ $ docker-compose --file docker-compose.ldap.yml down local
143
149
  ```
144
150
 
145
151
  #### CI
146
152
  ```bash
147
153
  docker-compose --file docker-compose.ci.ldap.yml --project-name soar-registry-directory-provider-ldap up --abort-on-container-exit --remove-orphans --build --force-recreate
148
154
  EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryproviderldap_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
155
+ docker-compose --file docker-compose.ci.ldap.yml --project-name soar-registry-directory-provider-ldap down --rmi local
149
156
  exit $EXIT_CODE
150
157
  ```
151
158
 
@@ -155,12 +162,14 @@ exit $EXIT_CODE
155
162
  ```bash
156
163
  $ docker-compose --file docker-compose.mysql.yml up --remove-orphans
157
164
  $ CONFIG_FILE=config.mysql.yml TEST_ORCHESTRATION_PROVIDER=Mysql cucumber
165
+ $ docker-compose --file docker-compose.mysql.yml down --rmi local
158
166
  ```
159
167
 
160
168
  #### CI
161
169
  ```bash
162
170
  docker-compose --file docker-compose.ci.mysql.yml --project-name soar-registry-directory-provider-mysql up --abort-on-container-exit --remove-orphans --build --force-recreate
163
171
  EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryprovidermysql_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
172
+ docker-compose --file docker-compose.ci.mysql.yml --project-name soar-registry-directory-provider-mysql down --rmi local
164
173
  exit $EXIT_CODE
165
174
  ```
166
175
 
@@ -2,9 +2,10 @@ module Soar
2
2
  module Registry
3
3
  module Directory
4
4
  module Error
5
- class NoEntriesFound < StandardError; end;
5
+ class NoEntriesFoundError < StandardError; end;
6
6
  class MultipleEntriesFound < StandardError; end;
7
7
  class NetworkingError < StandardError; end;
8
+ class DuplicateEntryError < StandardError; end;
8
9
  end
9
10
  end
10
11
  end
@@ -12,23 +12,24 @@ module Soar
12
12
  attr_reader :provider
13
13
 
14
14
  ##
15
- # @param provider [Soar::Registry::Directory::Provider::Stub, Soar::Registry::Directory::Provider::DynamoDb, Soar::Registry::Directory::Provider::Ldap, Soar::Registry::Directory::Provider::Mysql] object
15
+ # @param [Soar::Registry::Directory::Provider::Stub, Soar::Registry::Directory::Provider::DynamoDb, Soar::Registry::Directory::Provider::Ldap, Soar::Registry::Directory::Provider::Mysql] provider
16
16
  ##
17
17
  def initialize(provider)
18
18
  @provider = provider
19
19
  end
20
20
 
21
21
  ##
22
- # @param entity [Hash]
23
- # @raise [Soar::Registry::Directory::Error::NetworkingError]
22
+ # @param [Hash] entity
23
+ # @return [Boolean]
24
+ # @raise [Soar::Registry::Directory::Error::NetworkingError, Soar::Registry::Directory::Error::DuplicateEntryError]
24
25
  ##
25
26
  def put(entity)
26
27
  @provider.put(entity)
27
28
  end
28
29
 
29
30
  ##
30
- # @param primary_key [String]
31
- # @return [Hash] the identity
31
+ # @param [String] primary_key
32
+ # @return [Hash] entry
32
33
  # @raise [Soar::Registry:::Directory::Error::NoEntriesFound] if primary key not found
33
34
  # @raise [Soar::Registry::Directory::Error::NetworkingError]
34
35
  ##
@@ -37,17 +38,17 @@ module Soar
37
38
  end
38
39
 
39
40
  ##
40
- # @param key [String] attribute name
41
- # @param value [String] attribute value
41
+ # @param [String] key
42
+ # @param [String] value
42
43
  # @return [Array] list of entries
43
- # @raise [Soar::Registry::Directory::Error::NetworkingError]
44
+ # @raise [ArgumentError, Soar::Registry::Directory::Error::NetworkingError]
44
45
  ##
45
46
  def search(key, value)
46
47
  @provider.search(key, value)
47
48
  end
48
49
 
49
50
  ##
50
- # @return [Array] a list of primary keys and global secondary indexes
51
+ # @return [Array] a list of provider specific indexes
51
52
  # @raise [Soar::Registry::Directory::Error::NetworkingError]
52
53
  ##
53
54
  def index
@@ -12,54 +12,67 @@ module Soar
12
12
  attr_accessor :client
13
13
 
14
14
  ##
15
- # @param credentials [Hash] { username: 'username', password: 'secret'}
16
- # @param table [String]
17
- # @param index [Array] primary key should be the first item
18
- # @param configuration [Hash] { region: 'us-west-2', endpoint: 'http://localhost:8000' }
15
+ # @param [Hash] credentials
16
+ # @option credentials [String] :username
17
+ # @option credentials [String] :password
18
+ # @param [String] table table name
19
+ # @param [Hash] index
20
+ # @option index [String] :partition_key
21
+ # @option index [String] :sort_key
22
+ # @option index [Array] :global_secondary_indexes
23
+ # @param configuration [Hash]
24
+ # @option configuration [String] :region
25
+ # @option configuration [String] :endpoint
19
26
  ##
20
27
  def initialize(credentials: , table: , index: , configuration: )
21
28
  @table_name = table
22
- @primary_key = index[0]
23
- @index = index
29
+ @partition_key = index['partition_key']
30
+ @sort_key = index['sort_key'] if index.key?('sort_key')
31
+ @global_secondary_indexes = index['global_secondary_index'] if index.key?('global_secondary_index')
24
32
  @credentials = Hashie.symbolize_keys(credentials)
25
33
  configuration[:credentials] = Aws::Credentials.new(@credentials[:username], @credentials[:password])
26
34
  @client = Aws::DynamoDB::Client.new(Hashie.symbolize_keys(configuration))
27
35
  end
28
36
 
29
37
  ##
38
+ # @param [Hash] entry
39
+ # @return [Boolean]
40
+ # @raise [Soar::Registry::Directory::Error::DuplicateEntryError]
30
41
  ##
31
- def put(entity)
42
+ def put(entry)
32
43
  adapt_exceptions do
33
44
  @client.put_item({
34
45
  table_name: @table_name,
35
- item: entity
46
+ item: entry,
47
+ condition_expression: "attribute_not_exists(#{@partition_key})"
36
48
  })
49
+ return true
37
50
  end
38
51
  end
39
52
 
40
53
  ##
41
- # @param [String] identity_id primary key of the identity
42
- # @return [Hash] the identity
43
- # @raise [Soar::Registry::Staff::Directory::DynamoDb::Error::UniqueIdentifierNotFoundError] if primary key not found
54
+ # @param [Hash] primary_key
55
+ # @option primary_key [String] :partition_key required
56
+ # @option primary_key [String] :sort_key required only when defined in schema
57
+ # @return [Hash] a single matching entry
58
+ # @raise [Soar::Registry::Directory::Error::NoEntriesFoundError] if primary key not found
44
59
  ##
45
60
  def fetch(primary_key)
46
61
  adapt_exceptions do
47
62
  options = {
48
63
  table_name: @table_name,
49
- key: {
50
- "#{@primary_key}": primary_key
51
- }
64
+ key: primary_key
52
65
  }
53
66
  identity = @client.get_item(options)
54
- raise Soar::Registry::Directory::Error::NoEntriesFound, "No entries found for #{@primary_key} = #{primary_key}" if identity.item.nil?
67
+ raise Soar::Registry::Directory::Error::NoEntriesFoundError, "No entries found for #{@primary_key} = #{primary_key}" if identity.item.nil?
55
68
  identity.item
56
69
  end
57
70
  end
58
71
 
59
72
  ##
60
- # @param [String] identifier_attribute
61
- # @param [String] identifier_value
62
- # @return [Array] list of identities
73
+ # @param [String] key
74
+ # @param [String] value
75
+ # @return [Array] list of matching entries
63
76
  # @raise [ArgumentError] if query or index is not specified
64
77
  ##
65
78
  def search(key, value)
@@ -74,7 +87,7 @@ module Soar
74
87
  }
75
88
  }
76
89
 
77
- options.merge!({index_name: "#{key}-index"}) if @index.include?(key)
90
+ options.merge!({index_name: "#{key}-index"}) if @global_secondary_indexes.include?(key)
78
91
  identity = @client.query(options)
79
92
  identity.items.map { |item|
80
93
  Hashie.stringify_keys(item)
@@ -93,20 +106,23 @@ module Soar
93
106
  indexed_attributes = []
94
107
  resp['table']['key_schema'].each { |key_schema|
95
108
  indexed_attributes << key_schema['attribute_name']
96
- }
109
+ } if resp['table'].key?('key_schema')
110
+
97
111
  resp['table']['global_secondary_indexes'].each { |index|
98
112
  index['key_schema'].each { |key_schema|
99
113
  indexed_attributes << key_schema['attribute_name']
100
114
  }
101
- }
115
+ } if resp['table'].key?('global_secondary_indexes')
116
+
102
117
  indexed_attributes
103
118
  end
104
119
  end
105
120
 
106
121
  ##
107
122
  # Deletes existing table and creates a new one in its place
108
- # @param name [String] table name
109
- # @param structure [Hash] table structure
123
+ # @param [String] name the table name
124
+ # @param [Hash] structure table structure
125
+ # @return [Boolean]
110
126
  ##
111
127
  def recreate_table(name: nil, structure: nil)
112
128
 
@@ -117,6 +133,7 @@ module Soar
117
133
  })
118
134
  end
119
135
  @client.create_table(Hashie.symbolize_keys(structure))
136
+ return true
120
137
  end
121
138
 
122
139
  end
@@ -128,6 +145,8 @@ module Soar
128
145
  yield
129
146
  rescue Seahorse::Client::NetworkingError => e
130
147
  raise Soar::Registry::Directory::Error::NetworkingError, e.message
148
+ rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
149
+ raise Soar::Registry::Directory::Error::DuplicateEntryError, e.message
131
150
  end
132
151
  end
133
152
 
@@ -11,10 +11,14 @@ module Soar
11
11
  attr_accessor :client
12
12
 
13
13
  ##
14
- # @param config [Hash]
15
- # @param base [String] ldap tree base eg 'dc=hetzner,dc=co,dc=za'
16
- # @param attributes [Array] array of attributes to return for queries
17
- # @param credentials [Hash]
14
+ # @param [Hash] config
15
+ # @option config [String] :host
16
+ # @option config [Number] :port
17
+ # @param [String] base ldap tree base eg 'dc=hetzner,dc=co,dc=za'
18
+ # @param [Array] attributes array of attributes to return for queries
19
+ # @param [Hash] credentials
20
+ # @option credentials [String] :username
21
+ # @option credentials [String] :password
18
22
  ##
19
23
  def initialize(config: , base: , attributes: , index: , credentials: )
20
24
  adapt_exceptions do
@@ -37,29 +41,43 @@ module Soar
37
41
  end
38
42
  end
39
43
 
44
+ ##
45
+ # @param [Hash] entry
46
+ # @return [Boolean]
47
+ # @raise [Soar::Registry::Directory::Error::DuplicateEntryError]
48
+ ##
40
49
  def put(entry)
41
50
  adapt_exceptions do
51
+
52
+ @index.each { |index|
53
+ if (entry[:attributes].keys.include?(index))
54
+ result = search(index, entry[:attributes][index])
55
+ raise Soar::Registry::Directory::Error::DuplicateEntryError if result.length > 0
56
+ end
57
+ }
58
+
42
59
  @client.add({
43
60
  dn: entry[:dn],
44
61
  attributes: entry[:attributes]
45
62
  })
63
+ return true
46
64
  end
47
65
  end
48
66
 
49
67
  ##
50
- # @param [String] uuid primary key of the identity
51
- # @return [Hash] the identity
52
- # @raise [Soar::Registry::Directory::Error::NoEntriesFound] if primary key not found
68
+ # @param [String] primary key of the identity ie. the first index
69
+ # @return [Hash] single matching entry
70
+ # @raise [Soar::Registry::Directory::Error::NoEntriesFoundError] if primary key not found
53
71
  # @raise [Soar::Registry::Directory::Error::MultipleEntriesFound] if multiple matches found
54
72
  ##
55
- def fetch(uuid)
73
+ def fetch(primary_key)
56
74
  adapt_exceptions do
57
75
  result = @client.search({
58
76
  attributes: @attributes,
59
- filter: Net::LDAP::Filter.eq(@index[0], uuid),
77
+ filter: Net::LDAP::Filter.eq(@index[0], primary_key),
60
78
  return_result: true
61
79
  })
62
- raise Soar::Registry::Directory::Error::NoEntriesFound, "No entries found for #{@index[0]} = #{uuid}" if result.empty?
80
+ raise Soar::Registry::Directory::Error::NoEntriesFoundError, "No entries found for #{@index[0]} = #{primary_key}" if result.empty?
63
81
  raise Soar::Registry::Directory::Error::MultipleEntriesFound if result.length > 1
64
82
  response = {}
65
83
  @attributes.each { |attribute|
@@ -71,9 +89,9 @@ module Soar
71
89
 
72
90
 
73
91
  ##
74
- # @param key, named index [String]
75
- # @param value [String]
76
- # @return [Array] list of identities
92
+ # @param [String] key
93
+ # @param [String] value
94
+ # @return [Array] list of matching entries
77
95
  # @raise [ArgumentError] if value or named index is not specified
78
96
  ##
79
97
  def search(key, value)
@@ -97,7 +115,7 @@ module Soar
97
115
  end
98
116
 
99
117
  ##
100
- # @return [Array] a list of primary keys and global secondary indexes
118
+ # @return [Array] a list of indexes
101
119
  ##
102
120
  def index
103
121
  adapt_exceptions do
@@ -105,9 +123,14 @@ module Soar
105
123
  end
106
124
  end
107
125
 
126
+ ##
127
+ # @param [String] dn
128
+ # @return [Boolean]
129
+ ##
108
130
  def delete(dn)
109
131
  adapt_exceptions do
110
132
  @client.delete(dn: dn)
133
+ return true
111
134
  end
112
135
  end
113
136
 
@@ -10,10 +10,16 @@ module Soar
10
10
  attr_accessor :client
11
11
 
12
12
  ##
13
- # @param config [Hash]
14
- # @param base [String] ldap tree base eg 'dc=hetzner,dc=co,dc=za'
15
- # @param attributes [Array] array of attributes to return for queries
16
- # @param credentials [Hash]
13
+ # @param [Hash] config
14
+ # @option config [String] :host
15
+ # @option config [Number] :port
16
+ # @option config [String] :database name
17
+ # @option config [String] :table name
18
+ # @param [Array] attributes array of attributes to return for queries
19
+ # @param [Array] index array of indexes starting with the primary key
20
+ # @param [Hash] credentials
21
+ # @option credentials [String] :username
22
+ # @option credentials [String] :password
17
23
  ##
18
24
  def initialize(config: , attributes: '*', index: , credentials: )
19
25
  adapt_exceptions do
@@ -31,40 +37,45 @@ module Soar
31
37
  end
32
38
  end
33
39
 
40
+ ##
41
+ # @param [Hash] entry
42
+ # @return [Boolean]
43
+ ##
34
44
  def put(entry)
35
45
  adapt_exceptions do
36
46
  statement = @client.prepare("INSERT INTO #{@table} (#{entry.keys.join(', ')}) VALUES(#{entry.values.map { |s| "?" }.join(', ')})")
37
- return statement.execute(*entry.values)
47
+ statement.execute(*entry.values)
48
+ return true
38
49
  end
39
50
  end
40
51
 
41
52
  ##
42
- # @param [String] uuid primary key of the identity
43
- # @return [Hash] the identity
44
- # @raise [Soar::Registry::Directory::Error::NoEntriesFound] if primary key not found
53
+ # @param [String] primary key the first index
54
+ # @return [Hash] single matching entry
55
+ # @raise [Soar::Registry::Directory::Error::NoEntriesFoundError] if primary key not found
45
56
  # @raise [Soar::Registry::Directory::Error::MultipleEntriesFound] if multiple matches found
46
57
  ##
47
- def fetch(uuid)
58
+ def fetch(primary_key)
48
59
  adapt_exceptions do
49
60
  statement = @client.prepare("SELECT #{@attributes} FROM #{@table} WHERE #{@index[0]} = ? LIMIT 1")
50
- mysql_statement = statement.execute(uuid)
51
- raise Soar::Registry::Directory::Error::NoEntriesFound, "No entries found for #{@index[0]} = #{uuid}" if mysql_statement.num_rows == 0
61
+ mysql_statement = statement.execute(primary_key)
62
+ raise Soar::Registry::Directory::Error::NoEntriesFoundError, "No entries found for #{@index[0]} = #{primary_key}" if mysql_statement.num_rows == 0
52
63
  mysql_result = mysql_statement.result_metadata
53
64
  fields = mysql_result.fetch_fields
54
65
  field_names = fields.map { |field|
55
66
  field.name
56
67
  }
57
68
  result = mysql_statement.fetch
58
- Hash[result.map.with_index { |value, index|
69
+ result = Hash[result.map.with_index { |value, index|
59
70
  [field_names[index.to_i], value]
60
71
  }].symbolize_keys
61
72
  end
62
73
  end
63
74
 
64
75
  ##
65
- # @param key, named index [String]
66
- # @param value [String]
67
- # @return [Array] list of identities
76
+ # @param [String] key should be in indexed in db schema
77
+ # @param [String] value
78
+ # @return [Array] list of matching entries
68
79
  # @raise [ArgumentError] if value or named index is not specified
69
80
  ##
70
81
  def search(key, value)
@@ -87,7 +98,7 @@ module Soar
87
98
  end
88
99
 
89
100
  ##
90
- # @return [Array] a list of primary keys and global secondary indexes
101
+ # @return [Array] a list of indexes the first being the primary key
91
102
  ##
92
103
  def index
93
104
  adapt_exceptions do
@@ -10,9 +10,8 @@ module Soar
10
10
  class Stub
11
11
 
12
12
  ##
13
- # @param table [String] table name
14
- # @param primary_key [String]
15
- # @param index [Array] primary key should be the first item
13
+ # @param [String] table the table name
14
+ # @param [Array] indexes primary key should be the first item
16
15
  ##
17
16
  def initialize(table: , index: )
18
17
  @interface = Mince::HashyDb::Interface
@@ -23,31 +22,37 @@ module Soar
23
22
  end
24
23
 
25
24
  ##
26
- # @param entity [Hash]
25
+ # @param [Hash] entry
26
+ # @raise [Soar::Registry::Directory::Error::DuplicateEntryError]
27
+ # @return [Boolean]
27
28
  ##
28
- def put(entity)
29
+ def put(entry)
29
30
  adapt_exceptions do
30
- @interface.add(@table, entity)
31
+ if not @interface.get_for_key_with_value(@table, @primary_key, entry[@primary_key])
32
+ @interface.add(@table, entry)
33
+ return true
34
+ end
35
+ raise Soar::Registry::Directory::Error::DuplicateEntryError, "Unable to add duplicate entry for index #{@primary_key} with value #{entry[@primary_key]}"
31
36
  end
32
37
  end
33
38
 
34
39
  ##
35
- # @param uuid [String]
36
- # @return entry [Hash]
37
- # @raise [Soar::Registry:::Directory::Error::NoEntriesFound] if primary key not found
40
+ # @param [String] primary_key
41
+ # @return [Hash] entry
42
+ # @raise [Soar::Registry:::Directory::Error::NoEntriesFoundError] if primary key not found
38
43
  ##
39
44
  def fetch(primary_key)
40
45
  adapt_exceptions do
41
46
  entry = @interface.get_for_key_with_value(@table, @primary_key, primary_key)
42
- raise Soar::Registry::Directory::Error::NoEntriesFound, "No entries found for #{@primary_key} = #{primary_key}" if entry.nil?
47
+ raise Soar::Registry::Directory::Error::NoEntriesFoundError, "No entries found for #{@primary_key} = #{primary_key}" if entry.nil?
43
48
  entry
44
49
  end
45
50
  end
46
51
 
47
52
  ##
48
- # @param [String] identifier_attribute
49
- # @param [String] identifier_value
50
- # @return [Array] list of identities
53
+ # @param [String] key
54
+ # @param [String] value
55
+ # @return [Array] list of matching entries
51
56
  # @raise [ArgumentError] if query or index is not specified
52
57
  ##
53
58
  def search(key, value)
@@ -65,7 +70,7 @@ module Soar
65
70
  end
66
71
 
67
72
  ##
68
- # @return [Array] a list of primary keys and global secondary indexes
73
+ # @return [Array] a list of provider specific indexes
69
74
  ##
70
75
  def index
71
76
  adapt_exceptions do
@@ -1,56 +1,62 @@
1
1
  [
2
2
  {
3
- "uuid": "identity-62936e70-1815-439b-bf89-8492855a7e6b",
4
- "email": "test+publisher@hetzner.co.za",
5
- "roles": {
6
- "staff": {
7
- "department": "technical"
8
- },
9
- "configuration_publisher": {
10
- "configuration_identifiers": ["*"]
11
- }
12
- }
3
+ "partition_key": "62936e70-1815-439b-bf89-8492855a7e6b",
4
+ "sort_key": "staff",
5
+ "attributes" : {
6
+ "department": "technical"
7
+ },
8
+ "global_secondary_index1": "2160f6c31bb4c94e41bfcea8d04bba20"
13
9
  },
14
10
  {
15
- "uuid": "identity-43353f18-8afe-11e6-ae22-56b6b6499611",
16
- "email": "test+consumer@hetzner.co.za",
17
- "roles": {
18
- "staff": {},
19
- "configuration_consumer": {
20
- "configuration_identifiers": ["*"]
21
- }
22
-
23
- }
11
+ "partition_key": "62936e70-1815-439b-bf89-8492855a7e6b",
12
+ "sort_key": "configuration_publisher",
13
+ "attributes" : {
14
+ "configuration_identifiers": ["*"]
15
+ },
16
+ "global_secondary_index1": "d3db8f555418a0351d6c9b1e14f16c92"
24
17
  },
25
18
  {
26
- "uuid": "identity-820d5660-2204-4f7d-8c04-746313439b81",
27
- "email": "admin@hetzner.co.za",
28
- "roles": {
29
- "staff": {},
30
- "configuration_publisher": {
31
- "configuration_identifiers": ["*"]
32
- },
33
- "configuration_consumer": {
34
- "configuration_identifiers": ["*"]
35
- }
19
+ "partition_key": "43353f18-8afe-11e6-ae22-56b6b6499611",
20
+ "sort_key": "staff",
21
+ "global_secondary_index1": "c640072316e084efd14cfb811a3680e9"
22
+ },
23
+ {
24
+ "partition_key": "43353f18-8afe-11e6-ae22-56b6b6499611",
25
+ "sort_key": "configuration_consumer",
26
+ "attributes": {
27
+ "configuration_identifiers": ["*"]
28
+ },
29
+ "global_secondary_index1": "bf9b32d1d059c04f9ab4b2f0fda6dd05"
36
30
 
31
+ },
32
+ {
33
+ "partition_key": "820d5660-2204-4f7d-8c04-746313439b81",
34
+ "sort_key": "staff",
35
+ "global_secondary_index1": "d8450263f997a0b9e2131111ea20d659"
36
+ },
37
+ {
38
+ "partition_key": "820d5660-2204-4f7d-8c04-746313439b81",
39
+ "sort_key": "configuration_publisher",
40
+ "attributes": {
41
+ "configuration_identifiers": ["*"]
37
42
  },
38
- "address": {
39
- "detail": "Belvedere Office Park, Unit F",
40
- "street": "Bella Rosa Street",
41
- "suburb": "Tygervalley",
42
- "city": "Durbanville",
43
- "postal": "7550"
44
- }
43
+ "global_secondary_index1": "20b0db680941f5178bbfd3458c1ca909"
45
44
  },
46
45
  {
47
- "uuid": "identity-1ff472a6-8df3-4f13-82c3-89fde26db3cf",
48
- "email": "none@example.com",
49
- "client_nr": "C123456789",
50
- "roles": {
51
- "customer": {},
52
- "reseller": {}
53
- }
46
+ "partition_key": "820d5660-2204-4f7d-8c04-746313439b81",
47
+ "sort_key": "configuration_consumer",
48
+ "attributes": {
49
+ "configuration_identifiers": ["*"]
50
+ },
51
+ "global_secondary_index1": "3873523c6ff4c4803199aa757c271ed1"
52
+ },
53
+ {
54
+ "partition_key": "1ff472a6-8df3-4f13-82c3-89fde26db3cf",
55
+ "sort_key": "customer_profile",
56
+ "attributes": {
57
+ "owner": ["C123456789"]
58
+ },
59
+ "global_secondary_index1": "e72006881d15fc8747a85d05fa16b5cb"
54
60
  }
55
61
  ]
56
62
 
@@ -1,33 +1,40 @@
1
1
  {
2
- "table_name": "identities",
2
+ "table_name": "identity_roles",
3
3
  "key_schema": [
4
4
  {
5
- "attribute_name": "uuid",
5
+ "attribute_name": "partition_key",
6
6
  "key_type": "HASH"
7
+ },
8
+ {
9
+ "attribute_name": "sort_key",
10
+ "key_type": "RANGE"
7
11
  }
8
12
  ],
9
13
  "attribute_definitions": [
10
14
  {
11
- "attribute_name": "uuid",
15
+ "attribute_name": "partition_key",
16
+ "attribute_type": "S"
17
+ },
18
+ {
19
+ "attribute_name": "sort_key",
12
20
  "attribute_type": "S"
13
21
  },
14
22
  {
15
- "attribute_name": "email",
23
+ "attribute_name": "global_secondary_index1",
16
24
  "attribute_type": "S"
17
25
  }
18
26
  ],
19
27
  "global_secondary_indexes": [
20
28
  {
21
- "index_name": "email-index",
29
+ "index_name": "global_secondary_index1-index",
22
30
  "key_schema": [
23
- {
24
- "attribute_name": "email",
25
- "key_type": "HASH"
26
- }
31
+ {
32
+ "attribute_name": "global_secondary_index1",
33
+ "key_type": "HASH"
34
+ }
27
35
  ],
28
36
  "projection": {
29
37
  "projection_type": "ALL"
30
-
31
38
  },
32
39
  "provisioned_throughput": {
33
40
  "read_capacity_units": 10,
@@ -30,6 +30,10 @@ module Soar
30
30
  @provider.put_entry
31
31
  end
32
32
 
33
+ def put_duplicate_entry
34
+ @provider.put_duplicate_entry
35
+ end
36
+
33
37
  def search_for_entry
34
38
  @provider.search_for_entry
35
39
  end
@@ -42,6 +46,10 @@ module Soar
42
46
  @provider.request_index
43
47
  end
44
48
 
49
+ def duplicate_entry?
50
+ @provider.duplicate_entry?
51
+ end
52
+
45
53
  def persisted?
46
54
  @provider.persisted?
47
55
  end
@@ -44,19 +44,25 @@ module Soar
44
44
  @directory.provider.client = Aws::DynamoDB::Client.new(Hashie.symbolize_keys(@configuration['provider']['config']))
45
45
  end
46
46
 
47
+ def put_duplicate_entry
48
+ put_entry
49
+ end
50
+
47
51
  def put_entry
48
52
  begin
49
53
  @directory.put(@entries[0])
50
54
  rescue Soar::Registry::Directory::Error::NetworkingError => e
51
- @error = e.message
55
+ @error = e
56
+ rescue Soar::Registry::Directory::Error::DuplicateEntryError => e
57
+ @error = e
52
58
  end
53
59
  end
54
60
 
55
61
  def search_for_entry
56
62
  begin
57
- @result = @directory.search("email", @entries[0]['email'])
63
+ @result = @directory.search("global_secondary_index1", @entries[0]['global_secondary_index1'])
58
64
  rescue Soar::Registry::Directory::Error::NetworkingError => e
59
- @error = e.message
65
+ @error = e
60
66
  end
61
67
  end
62
68
 
@@ -64,20 +70,30 @@ module Soar
64
70
  begin
65
71
  @result = @directory.index
66
72
  rescue Soar::Registry::Directory::Error::NetworkingError => e
67
- @error = e.message
73
+ @error = e
68
74
  end
69
75
  end
70
76
 
71
77
  def fetch_entry
72
78
  begin
73
- @result = @directory.fetch(@entries[0]['uuid'])
74
- rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
75
- @error = e.message
79
+ @result = @directory.fetch({
80
+ @index.keys[0] => @entries[0]['partition_key'],
81
+ @index.keys[1] => @entries[0]['sort_key']
82
+ })
83
+ rescue Soar::Registry::Directory::Error::NoEntriesFoundError, Soar::Registry::Directory::Error::NetworkingError => e
84
+ @error = e
76
85
  end
77
86
  end
78
87
 
88
+ def duplicate_entry?
89
+ @error.is_a?(Soar::Registry::Directory::Error::DuplicateEntryError)
90
+ end
91
+
79
92
  def persisted?
80
- @entries[0] == @directory.fetch(@entries[0]["uuid"])
93
+ @entries[0] == @directory.fetch({
94
+ @index.keys[0] => @entries[0]['partition_key'],
95
+ @index.keys[1] => @entries[0]['sort_key']
96
+ })
81
97
  end
82
98
 
83
99
  def returned?
@@ -85,7 +101,11 @@ module Soar
85
101
  end
86
102
 
87
103
  def index?
88
- @index
104
+ @index == {
105
+ 'partition_key' => @index['partition_key'],
106
+ 'sort_key' => @index['sort_key'],
107
+ 'global_secondary_index' => @index['global_secondary_index']
108
+ }
89
109
  end
90
110
 
91
111
  def single_entry?
@@ -93,11 +113,11 @@ module Soar
93
113
  end
94
114
 
95
115
  def no_entries_found?
96
- !!(@error =~ /\ANo entries found for .+\z/)
116
+ @error.is_a?(Soar::Registry::Directory::Error::NoEntriesFoundError)
97
117
  end
98
118
 
99
119
  def networking_error?
100
- !!(@error =~ /\AFailed to open TCP connection to .+\z/)
120
+ @error.is_a?(Soar::Registry::Directory::Error::NetworkingError)
101
121
  end
102
122
 
103
123
  def no_matching_entries?
@@ -1,5 +1,6 @@
1
1
  require 'soar/registry/directory'
2
2
  require 'hashie'
3
+ require 'securerandom'
3
4
 
4
5
  module Soar
5
6
  module Registry
@@ -65,13 +66,21 @@ module Soar
65
66
 
66
67
  end
67
68
 
69
+ def put_duplicate_entry
70
+ begin
71
+ @directory.put(@entries[0])
72
+ rescue Soar::Registry::Directory::Error::DuplicateEntryError => e
73
+ @error = e
74
+ end
75
+ end
76
+
68
77
  def put_entry
69
78
  begin
70
79
  @directory.put(@entries[0])
71
80
  result = @directory.search("mail", @entries[0][:attributes][:mail])
72
81
  @entries[0][:attributes][:entryuuid] = result[0][@index[0]]
73
82
  rescue Soar::Registry::Directory::Error::NetworkingError => e
74
- @error = e.message
83
+ @error = e
75
84
  end
76
85
  end
77
86
 
@@ -79,7 +88,7 @@ module Soar
79
88
  begin
80
89
  @result = @directory.search("mail", @entries[0][:attributes][:mail])
81
90
  rescue Soar::Registry::Directory::Error::NetworkingError => e
82
- @error = e.message
91
+ @error = e
83
92
  end
84
93
  end
85
94
 
@@ -87,18 +96,22 @@ module Soar
87
96
  begin
88
97
  @result = @directory.index
89
98
  rescue Soar::Registry::Directory::Error::NetworkingError => e
90
- @error = e.message
99
+ @error = e
91
100
  end
92
101
  end
93
102
 
94
103
  def fetch_entry
95
104
  begin
96
105
  @result = @directory.fetch(@entries[0][:attributes][:entryuuid])
97
- rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
98
- @error = e.message
106
+ rescue Soar::Registry::Directory::Error::NoEntriesFoundError, Soar::Registry::Directory::Error::NetworkingError => e
107
+ @error = e
99
108
  end
100
109
  end
101
110
 
111
+ def duplicate_entry?
112
+ @error.is_a?(Soar::Registry::Directory::Error::DuplicateEntryError)
113
+ end
114
+
102
115
  def persisted?
103
116
  result = @directory.fetch(@entries[0][:attributes][:entryuuid])
104
117
  entry = @entries[0][:attributes]
@@ -113,7 +126,7 @@ module Soar
113
126
  end
114
127
 
115
128
  def index?
116
- @index
129
+ @index.is_a?(Array)
117
130
  end
118
131
 
119
132
  def single_entry?
@@ -123,7 +136,7 @@ module Soar
123
136
  end
124
137
 
125
138
  def no_entries_found?
126
- !!(@error =~ /\ANo entries found for .+\z/)
139
+ @error.is_a?(Soar::Registry::Directory::Error::NoEntriesFoundError)
127
140
  end
128
141
 
129
142
  def no_matching_entries?
@@ -131,7 +144,7 @@ module Soar
131
144
  end
132
145
 
133
146
  def networking_error?
134
- !!(@error =~ /\A(Invalid binding information|Connection refused).*\z/)
147
+ @error.is_a?(Soar::Registry::Directory::Error::NetworkingError)
135
148
  end
136
149
 
137
150
  end
@@ -16,9 +16,11 @@ module Soar
16
16
  @index = @configuration['provider']['config']['index']
17
17
  @attributes = @configuration['provider']['config']['attributes']
18
18
  @entries = [{
19
+ ID: 1,
19
20
  Client_Number: "C123456789",
20
21
  Notifyemail_Invoice: "johnconner@example.com"
21
22
  }, {
23
+ ID: 2,
22
24
  Client_Number: "C101112134",
23
25
  Notifyemail_Invoice: "sarahconnor@example.com"
24
26
  }]
@@ -50,9 +52,13 @@ module Soar
50
52
  @directory.provider.client.close
51
53
  end
52
54
 
55
+ def put_duplicate_entry
56
+ put_entry
57
+ end
58
+
53
59
  def put_entry
54
60
  begin
55
- @directory.put(@entries[0])
61
+ result = @directory.put(@entries[0])
56
62
  rescue Soar::Registry::Directory::Error::NetworkingError => e
57
63
  @error = e.message
58
64
  end
@@ -76,14 +82,14 @@ module Soar
76
82
 
77
83
  def fetch_entry
78
84
  begin
79
- @result = @directory.fetch(@entries[0][:Client_Number])
80
- rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
85
+ @result = @directory.fetch(@entries[0][:ID])
86
+ rescue Soar::Registry::Directory::Error::NoEntriesFoundError, Soar::Registry::Directory::Error::NetworkingError => e
81
87
  @error = e.message
82
88
  end
83
89
  end
84
90
 
85
91
  def persisted?
86
- @directory.fetch(@entries[0][:Client_Number]) == @entries[0]
92
+ @directory.fetch(@entries[0][:ID]) == @entries[0]
87
93
  end
88
94
 
89
95
  def returned?
@@ -91,11 +97,15 @@ module Soar
91
97
  end
92
98
 
93
99
  def index?
94
- @result
100
+ @result == @index
101
+ end
102
+
103
+ def duplicate_entry?
104
+ !!(@error =~ /\ADuplicate entry .+\z/)
95
105
  end
96
106
 
97
107
  def single_entry?
98
- @result == @entries[0]
108
+ @result == @entries[0]
99
109
  end
100
110
 
101
111
  def no_entries_found?
@@ -107,7 +117,7 @@ module Soar
107
117
  end
108
118
 
109
119
  def networking_error?
110
- patterns = [
120
+ patterns = [
111
121
  /\Aquery: not connected.*\z/,
112
122
  /\AMySQL server has gone away\z/,
113
123
  /\ACan't connect to local MySQL server through socket.*\z/,
@@ -32,11 +32,17 @@ module Soar
32
32
  @directory.provider.instance_variable_set(:@interface, Object.new)
33
33
  end
34
34
 
35
+ def put_duplicate_entry
36
+ put_entry
37
+ end
38
+
35
39
  def put_entry
36
40
  begin
37
41
  @directory.put(@@entry)
38
42
  rescue Soar::Registry::Directory::Error::NetworkingError => e
39
- @error = e.message
43
+ @error = e
44
+ rescue Soar::Registry::Directory::Error::DuplicateEntryError => e
45
+ @error = e
40
46
  end
41
47
  end
42
48
 
@@ -44,7 +50,7 @@ module Soar
44
50
  begin
45
51
  @entry = @directory.search("identifier", @@entry['identifier'])
46
52
  rescue Soar::Registry::Directory::Error::NetworkingError => e
47
- @error = e.message
53
+ @error = e
48
54
  end
49
55
  end
50
56
 
@@ -52,18 +58,22 @@ module Soar
52
58
  begin
53
59
  @index = @directory.index
54
60
  rescue Soar::Registry::Directory::Error::NetworkingError => e
55
- @error = e.message
61
+ @error = e
56
62
  end
57
63
  end
58
64
 
59
65
  def fetch_entry
60
66
  begin
61
67
  @entry = @directory.fetch(@@entry['uuid'])
62
- rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
63
- @error = e.message
68
+ rescue Soar::Registry::Directory::Error::NoEntriesFoundError, Soar::Registry::Directory::Error::NetworkingError => e
69
+ @error = e
64
70
  end
65
71
  end
66
72
 
73
+ def duplicate_entry?
74
+ @error.is_a?(Soar::Registry::Directory::Error::DuplicateEntryError)
75
+ end
76
+
67
77
  def persisted?
68
78
  @@entry == @directory.fetch(@@entry["uuid"])
69
79
  end
@@ -73,7 +83,7 @@ module Soar
73
83
  end
74
84
 
75
85
  def index?
76
- @index
86
+ @index.is_a?(Array)
77
87
  end
78
88
 
79
89
  def single_entry?
@@ -81,7 +91,7 @@ module Soar
81
91
  end
82
92
 
83
93
  def no_entries_found?
84
- !!(@error =~ /\ANo entries found for .+\z/)
94
+ @error.is_a?(Soar::Registry::Directory::Error::NoEntriesFoundError)
85
95
  end
86
96
 
87
97
  def no_matching_entries?
@@ -89,7 +99,7 @@ module Soar
89
99
  end
90
100
 
91
101
  def networking_error?
92
- !!(@error =~ /\ANetworking error\z/)
102
+ @error.is_a?(Soar::Registry::Directory::Error::NetworkingError)
93
103
  end
94
104
 
95
105
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soar-registry-directory
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.5
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Mulder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-25 00:00:00.000000000 Z
11
+ date: 2017-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashy_db
@@ -128,7 +128,6 @@ files:
128
128
  - lib/soar/registry/directory/provider/stub.rb
129
129
  - lib/soar/registry/directory/test/fixtures/data-dump.sql
130
130
  - lib/soar/registry/directory/test/fixtures/entries.json
131
- - lib/soar/registry/directory/test/fixtures/entries.ldif
132
131
  - lib/soar/registry/directory/test/fixtures/table_structure.json
133
132
  - lib/soar/registry/directory/test/orchestrator.rb
134
133
  - lib/soar/registry/directory/test/provider/dynamo_db.rb