soar-registry-directory 4.0.5 → 5.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 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