soar-registry-directory 3.0.0 → 4.0.3

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: 7a61da3957b7f33045f60bf7ac5dddd9d726d80b
4
- data.tar.gz: 5524c36351bfa5556b9e8aa104171b5639d949dc
3
+ metadata.gz: 1c1833707950e957a90a1f7e4efe9b4694d74b93
4
+ data.tar.gz: 88ca6da07fd9378960eb968d8abe22c61da0a196
5
5
  SHA512:
6
- metadata.gz: 267d7e64a4fcd9b4d1db8aed8c0215ea4c3fcb1198d738542e3456f12b665dba531edcf401d6830ba416b3b21c19be3d048194ecd8272671b363cbeb8fd4e21f
7
- data.tar.gz: c7b15f5f7b810f33ee57477dd23e517a3fb37077ce02231ffbf770a269ed8d3bd4e6a704139793a59ee988d6ef26b6f26d6f4fab907b55d993be6837543f27f9
6
+ metadata.gz: a46377eb1b9158b9717c99e020f12843578ae880ce2a7b4489f4bf8748bde02b6620206ba1005a23d4218bdbc48d25284e2946097917bcca2d204e398135cbc1
7
+ data.tar.gz: 65254344d7334aa49ae4c03ea70de0d1faa18544a9cb9c02fa5138ea149feb42d6a782f81f52cbfdfedfd8179a1cba4410c3fcd09692cdda0da8781392ec36c2
data/README.md CHANGED
@@ -43,14 +43,41 @@ Create an instance of the stub provider by passing in the name, primary key and
43
43
 
44
44
  ```
45
45
 
46
+ ### MySQL/MariaDB Provider
47
+
48
+ Requires libmysqlclient-dev before running bundler.
49
+ ```bash
50
+ $ sudo apt-get install libmysqlclient-dev
51
+ ```
52
+
53
+ ```ruby
54
+ > provider = Soar::Registry::Directory::Provider::Mysql.new({
55
+ index: ['Client_Number', 'Notifyemail_Invoice', 'Login'],
56
+ config: {
57
+ database: 'konsoleh_genie'
58
+ table: 'Client'
59
+ host: '0.0.0.0'
60
+ port: 3306
61
+ },
62
+ attributes: ['Client_Number', 'Notifyemail_Invoice'],
63
+ credentials: {
64
+ username: 'genie'
65
+ password: 'secret'
66
+ }
67
+ })
68
+ ```
69
+
70
+ Please note: The mysql dump of the genie database structure is out of date. Updating it should probably be automated. Since the directory is currently only used to search for Client_Number, it's not a priority.
71
+
46
72
  ### LDAP Provider
73
+
47
74
  ```ruby
48
75
  > provider = Soar::Registry::Directory::Provider::Ldap.new({
49
76
  base: 'dc=hetzner,dc=co,dc=za',
50
77
  index: [:entryuuid, :mail],
51
78
  config: {
52
79
  host: 'localhost',
53
- port: 389
80
+ port: 636
54
81
  },
55
82
  attributes: ['entryuuid', 'cn', 'mail', 'sn'],
56
83
  credentials: {
@@ -59,7 +86,17 @@ Create an instance of the stub provider by passing in the name, primary key and
59
86
  }
60
87
  })
61
88
  ```
62
- Please note: Primary key is assumed to be the first element of index array. Index array elements need to be symbols for Ldap.
89
+ Please note: Primary key is assumed to be the first element of index array.
90
+
91
+ Command to test secure LDAP connection from terminal.
92
+ ```bash
93
+ $ ldapsearch -H ldaps://ldap2.cpt1.host-h.net:636 -x -D "genieUser=charles.mulder@hetzner.co.za,ou=people,dc=hetzner,dc=co,dc=za" -b "ou=people,dc=hetzner,dc=co,dc=za" -s sub "(objectclass=*)" -W -v -d 5
94
+ ```
95
+
96
+ Command to test LDAP connection from terminal.
97
+ ```bash
98
+ $ ldapsearch -h ldapadmin.hetzner.co.za -p 389 -x -D "genieUser=charles.mulder@hetzner.co.za,ou=people,dc=hetzner,dc=co,dc=za" -b "dc=hetzner,dc=co,dc=za" -W
99
+ ```
63
100
 
64
101
  ### The Model
65
102
  ```ruby
@@ -77,8 +114,8 @@ $ cucumber
77
114
 
78
115
  #### CI
79
116
  ```bash
80
- docker-compose --file docker-compose.stub.yml up --abort-on-container-exit --remove-orphans --build --force-recreate
81
- EXIT_CODE=$(docker ps -a -f "name=soar-registry-directory-test-provider-stub" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
117
+ 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
+ EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryproviderstub_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
82
119
  exit $EXIT_CODE
83
120
  ```
84
121
 
@@ -92,8 +129,8 @@ $ CONFIG_FILE=config.dynamo_db.yml TEST_ORCHESTRATION_PROVIDER=DynamoDb cucumber
92
129
 
93
130
  #### CI
94
131
  ```bash
95
- docker-compose --file docker-compose.ci.dynamo_db.yml up --abort-on-container-exit --remove-orphans --build --force-recreate
96
- EXIT_CODE=$(docker ps -a -f "name=soar-registry-directory-test-provider-dynamo_db" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
132
+ 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
+ EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryproviderdynamodb_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
97
134
  exit $EXIT_CODE
98
135
  ```
99
136
 
@@ -107,8 +144,23 @@ $ CONFIG_FILE=config.ldap.yml TEST_ORCHESTRATION_PROVIDER=Ldap cucumber
107
144
 
108
145
  #### CI
109
146
  ```bash
110
- docker-compose --file docker-compose.ci.ldap.yml up --abort-on-container-exit --remove-orphans --build --force-recreate
111
- EXIT_CODE=$(docker ps -a -f "name=soar-registry-directory-test-provider-ldap" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
147
+ 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
+ EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryproviderldap_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
149
+ exit $EXIT_CODE
150
+ ```
151
+
152
+ ### MySQL provider
153
+
154
+ #### Local
155
+ ```bash
156
+ $ docker-compose --file docker-compose.mysql.yml up --remove-orphans
157
+ $ CONFIG_FILE=config.mysql.yml TEST_ORCHESTRATION_PROVIDER=Mysql cucumber
158
+ ```
159
+
160
+ #### CI
161
+ ```bash
162
+ 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
+ EXIT_CODE=$(docker ps -a -f "name=soarregistrydirectoryprovidermysql_tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
112
164
  exit $EXIT_CODE
113
165
  ```
114
166
 
@@ -4,6 +4,7 @@ module Soar
4
4
  module Error
5
5
  class NoEntriesFound < StandardError; end;
6
6
  class MultipleEntriesFound < StandardError; end;
7
+ class NetworkingError < StandardError; end;
7
8
  end
8
9
  end
9
10
  end
@@ -2,6 +2,7 @@ require 'soar/registry/directory/error'
2
2
  require 'soar/registry/directory/provider/stub'
3
3
  require 'soar/registry/directory/provider/dynamo_db'
4
4
  require 'soar/registry/directory/provider/ldap'
5
+ require 'soar/registry/directory/provider/mysql'
5
6
 
6
7
  module Soar
7
8
  module Registry
@@ -11,7 +12,7 @@ module Soar
11
12
  attr_reader :provider
12
13
 
13
14
  ##
14
- # @param provider [Soar::Registry::Directory::Provider::Stub|Soar::Registry::Directory::Provider::DynamoDb] object
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
16
  ##
16
17
  def initialize(provider)
17
18
  @provider = provider
@@ -19,6 +20,7 @@ module Soar
19
20
 
20
21
  ##
21
22
  # @param entity [Hash]
23
+ # @raise [Soar::Registry::Directory::Error::NetworkingError]
22
24
  ##
23
25
  def put(entity)
24
26
  @provider.put(entity)
@@ -28,6 +30,7 @@ module Soar
28
30
  # @param primary_key [String]
29
31
  # @return [Hash] the identity
30
32
  # @raise [Soar::Registry:::Directory::Error::NoEntriesFound] if primary key not found
33
+ # @raise [Soar::Registry::Directory::Error::NetworkingError]
31
34
  ##
32
35
  def fetch(primary_key)
33
36
  @provider.fetch(primary_key)
@@ -37,6 +40,7 @@ module Soar
37
40
  # @param key [String] attribute name
38
41
  # @param value [String] attribute value
39
42
  # @return [Array] list of entries
43
+ # @raise [Soar::Registry::Directory::Error::NetworkingError]
40
44
  ##
41
45
  def search(key, value)
42
46
  @provider.search(key, value)
@@ -44,6 +48,7 @@ module Soar
44
48
 
45
49
  ##
46
50
  # @return [Array] a list of primary keys and global secondary indexes
51
+ # @raise [Soar::Registry::Directory::Error::NetworkingError]
47
52
  ##
48
53
  def index
49
54
  @provider.index
@@ -9,7 +9,7 @@ module Soar
9
9
  class DynamoDb
10
10
 
11
11
  LIMIT = 10
12
- attr_reader :client
12
+ attr_accessor :client
13
13
 
14
14
  ##
15
15
  # @param credentials [Hash] { username: 'username', password: 'secret'}
@@ -29,10 +29,12 @@ module Soar
29
29
  ##
30
30
  ##
31
31
  def put(entity)
32
- @client.put_item({
33
- table_name: @table_name,
34
- item: entity
35
- })
32
+ adapt_exceptions do
33
+ @client.put_item({
34
+ table_name: @table_name,
35
+ item: entity
36
+ })
37
+ end
36
38
  end
37
39
 
38
40
  ##
@@ -41,15 +43,17 @@ module Soar
41
43
  # @raise [Soar::Registry::Staff::Directory::DynamoDb::Error::UniqueIdentifierNotFoundError] if primary key not found
42
44
  ##
43
45
  def fetch(primary_key)
44
- options = {
45
- table_name: @table_name,
46
- key: {
47
- "#{@primary_key}": primary_key
46
+ adapt_exceptions do
47
+ options = {
48
+ table_name: @table_name,
49
+ key: {
50
+ "#{@primary_key}": primary_key
51
+ }
48
52
  }
49
- }
50
- identity = @client.get_item(options)
51
- raise Soar::Registry::Directory::Error::NoEntriesFound if identity.item.nil?
52
- identity.item
53
+ identity = @client.get_item(options)
54
+ raise Soar::Registry::Directory::Error::NoEntriesFound, "No entries found for #{@primary_key} = #{primary_key}" if identity.item.nil?
55
+ identity.item
56
+ end
53
57
  end
54
58
 
55
59
  ##
@@ -59,40 +63,44 @@ module Soar
59
63
  # @raise [ArgumentError] if query or index is not specified
60
64
  ##
61
65
  def search(key, value)
62
- options = {
63
- table_name: @table_name,
64
- select: 'ALL_ATTRIBUTES',
65
- limit: LIMIT,
66
- key_condition_expression: "#{key} = :value",
67
- expression_attribute_values: {
68
- ":value": value
66
+ adapt_exceptions do
67
+ options = {
68
+ table_name: @table_name,
69
+ select: 'ALL_ATTRIBUTES',
70
+ limit: LIMIT,
71
+ key_condition_expression: "#{key} = :value",
72
+ expression_attribute_values: {
73
+ ":value": value
74
+ }
69
75
  }
70
- }
71
76
 
72
- options.merge!({index_name: "#{key}-index"}) if @index.include?(key)
73
- identity = @client.query(options)
74
- identity.items.map { |item|
75
- Hashie.stringify_keys(item)
76
- }
77
+ options.merge!({index_name: "#{key}-index"}) if @index.include?(key)
78
+ identity = @client.query(options)
79
+ identity.items.map { |item|
80
+ Hashie.stringify_keys(item)
81
+ }
82
+ end
77
83
  end
78
84
 
79
85
  ##
80
86
  # @return [Array] a list of primary keys and global secondary indexes
81
87
  ##
82
88
  def index
83
- resp = @client.describe_table({
84
- table_name: @table_name
85
- })
86
- indexed_attributes = []
87
- resp['table']['key_schema'].each { |key_schema|
88
- indexed_attributes << key_schema['attribute_name']
89
- }
90
- resp['table']['global_secondary_indexes'].each { |index|
91
- index['key_schema'].each { |key_schema|
89
+ adapt_exceptions do
90
+ resp = @client.describe_table({
91
+ table_name: @table_name
92
+ })
93
+ indexed_attributes = []
94
+ resp['table']['key_schema'].each { |key_schema|
92
95
  indexed_attributes << key_schema['attribute_name']
93
96
  }
94
- }
95
- indexed_attributes
97
+ resp['table']['global_secondary_indexes'].each { |index|
98
+ index['key_schema'].each { |key_schema|
99
+ indexed_attributes << key_schema['attribute_name']
100
+ }
101
+ }
102
+ indexed_attributes
103
+ end
96
104
  end
97
105
 
98
106
  ##
@@ -102,12 +110,25 @@ module Soar
102
110
  ##
103
111
  def recreate_table(name: nil, structure: nil)
104
112
 
105
- if @client.list_tables.table_names.include?(name)
106
- @client.delete_table({
107
- table_name: name
108
- })
113
+ adapt_exceptions do
114
+ if @client.list_tables.table_names.include?(name)
115
+ @client.delete_table({
116
+ table_name: name
117
+ })
118
+ end
119
+ @client.create_table(Hashie.symbolize_keys(structure))
120
+ end
121
+
122
+ end
123
+
124
+ private
125
+
126
+ def adapt_exceptions
127
+ begin
128
+ yield
129
+ rescue Seahorse::Client::NetworkingError => e
130
+ raise Soar::Registry::Directory::Error::NetworkingError, e.message
109
131
  end
110
- @client.create_table(Hashie.symbolize_keys(structure))
111
132
  end
112
133
 
113
134
  end
@@ -8,6 +8,8 @@ module Soar
8
8
  module Provider
9
9
  class Ldap
10
10
 
11
+ attr_accessor :client
12
+
11
13
  ##
12
14
  # @param config [Hash]
13
15
  # @param base [String] ldap tree base eg 'dc=hetzner,dc=co,dc=za'
@@ -15,27 +17,34 @@ module Soar
15
17
  # @param credentials [Hash]
16
18
  ##
17
19
  def initialize(config: , base: , attributes: , index: , credentials: )
18
- @base = base
19
- @index = index.map { |x| x.to_sym }
20
- @attributes = attributes
21
- @config = {
22
- host: config[:host],
23
- port: config[:port],
24
- auth: {
25
- method: :simple,
26
- username: credentials[:username],
27
- password: credentials[:password]
28
- }
29
- }
30
- @ldap = Net::LDAP.new(@config)
31
- @ldap.bind
20
+ adapt_exceptions do
21
+ @index = index.map { |x| x.to_sym }
22
+ @attributes = attributes
23
+ @config = {
24
+ host: config[:host],
25
+ port: config[:port],
26
+ base: base,
27
+ auth: {
28
+ method: :simple,
29
+ username: credentials[:username],
30
+ password: credentials[:password]
31
+ },
32
+ encryption: {
33
+ method: :simple_tls
34
+ }
35
+ }
36
+ @client = Net::LDAP.new(@config)
37
+ @client.bind
38
+ end
32
39
  end
33
40
 
34
41
  def put(entry)
35
- @ldap.add({
36
- dn: entry[:dn],
37
- attributes: entry[:attributes]
38
- })
42
+ adapt_exceptions do
43
+ @client.add({
44
+ dn: entry[:dn],
45
+ attributes: entry[:attributes]
46
+ })
47
+ end
39
48
  end
40
49
 
41
50
  ##
@@ -45,19 +54,20 @@ module Soar
45
54
  # @raise [Soar::Registry::Directory::Error::MultipleEntriesFound] if multiple matches found
46
55
  ##
47
56
  def fetch(uuid)
48
- result = @ldap.search({
49
- base: @base,
50
- attributes: @attributes,
51
- filter: Net::LDAP::Filter.eq(@index[0], uuid),
52
- return_result: true
53
- })
54
- raise Soar::Registry::Directory::Error::NoEntriesFound if result.empty?
55
- raise Soar::Registry::Directory::Error::MultipleEntriesFound if result.length > 1
56
- response = {}
57
- @attributes.each { |attribute|
58
- response[attribute.to_sym] = result[0][attribute.to_sym][0]
59
- }
60
- response
57
+ adapt_exceptions do
58
+ result = @client.search({
59
+ attributes: @attributes,
60
+ filter: Net::LDAP::Filter.eq(@index[0], uuid),
61
+ return_result: true
62
+ })
63
+ raise Soar::Registry::Directory::Error::NoEntriesFound, "No entries found for #{@index[0]} = #{uuid}" if result.empty?
64
+ raise Soar::Registry::Directory::Error::MultipleEntriesFound if result.length > 1
65
+ response = {}
66
+ @attributes.each { |attribute|
67
+ response[attribute.to_sym] = result[0][attribute.to_sym][0]
68
+ }
69
+ response
70
+ end
61
71
  end
62
72
 
63
73
 
@@ -68,33 +78,49 @@ module Soar
68
78
  # @raise [ArgumentError] if value or named index is not specified
69
79
  ##
70
80
  def search(key, value)
71
- result = []
72
- entries = @ldap.search({
73
- base: @base,
74
- filter: Net::LDAP::Filter.eq(key, value),
75
- attributes: @attributes,
76
- return_result: true
77
- })
81
+ adapt_exceptions do
82
+ result = []
83
+ entries = @client.search({
84
+ filter: Net::LDAP::Filter.eq(key, value),
85
+ attributes: @attributes,
86
+ return_result: true
87
+ })
78
88
 
79
- entries.each { |entry|
80
- response = {}
81
- @attributes.each { |attribute|
82
- response[attribute.to_sym] = entry[attribute.to_sym][0]
89
+ entries.each { |entry|
90
+ response = {}
91
+ @attributes.each { |attribute|
92
+ response[attribute.to_sym] = entry[attribute.to_sym][0]
93
+ }
94
+ result << response
83
95
  }
84
- result << response
85
- }
86
- return result
96
+ return result
97
+ end
87
98
  end
88
99
 
89
100
  ##
90
101
  # @return [Array] a list of primary keys and global secondary indexes
91
102
  ##
92
103
  def index
93
- @index
104
+ adapt_exceptions do
105
+ @client.bind
106
+ @index
107
+ end
94
108
  end
95
109
 
96
110
  def delete(dn)
97
- @ldap.delete(dn: dn)
111
+ adapt_exceptions do
112
+ @client.delete(dn: dn)
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def adapt_exceptions
119
+ begin
120
+ yield
121
+ rescue Net::LDAP::BindingInformationInvalidError, Net::LDAP::ConnectionRefusedError, Errno::ECONNREFUSED => e
122
+ raise Soar::Registry::Directory::Error::NetworkingError, e.message
123
+ end
98
124
  end
99
125
 
100
126
  end
@@ -0,0 +1,116 @@
1
+ require 'soar/registry/directory/error'
2
+ require 'mysql'
3
+
4
+ module Soar
5
+ module Registry
6
+ module Directory
7
+ module Provider
8
+ class Mysql
9
+
10
+ attr_accessor :client
11
+
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]
17
+ ##
18
+ def initialize(config: , attributes: '*', index: , credentials: )
19
+ adapt_exceptions do
20
+ @attributes = attributes.kind_of?(Array) ? attributes.join(', ') : attributes
21
+ @index = index
22
+ @table = config[:table]
23
+ @config = {
24
+ host: config[:host],
25
+ port: config[:port],
26
+ database: config[:database],
27
+ username: credentials[:username],
28
+ password: credentials[:password]
29
+ }
30
+ @client = ::Mysql.new(@config[:host], @config[:username], @config[:password], @config[:database])
31
+ end
32
+ end
33
+
34
+ def put(entry)
35
+ adapt_exceptions do
36
+ statement = @client.prepare("INSERT INTO #{@table} (#{entry.keys.join(', ')}) VALUES(#{entry.values.map { |s| "?" }.join(', ')})")
37
+ return statement.execute(*entry.values)
38
+ end
39
+ end
40
+
41
+ ##
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
45
+ # @raise [Soar::Registry::Directory::Error::MultipleEntriesFound] if multiple matches found
46
+ ##
47
+ def fetch(uuid)
48
+ adapt_exceptions do
49
+ 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
52
+ mysql_result = mysql_statement.result_metadata
53
+ fields = mysql_result.fetch_fields
54
+ field_names = fields.map { |field|
55
+ field.name
56
+ }
57
+ result = mysql_statement.fetch
58
+ Hash[result.map.with_index { |value, index|
59
+ [field_names[index.to_i], value]
60
+ }].symbolize_keys
61
+ end
62
+ end
63
+
64
+ ##
65
+ # @param key, named index [String]
66
+ # @param value [String]
67
+ # @return [Array] list of identities
68
+ # @raise [ArgumentError] if value or named index is not specified
69
+ ##
70
+ def search(key, value)
71
+ adapt_exceptions do
72
+ statement = @client.prepare("SELECT #{@attributes} FROM #{@table} WHERE #{key} = ?")
73
+ mysql_statement = statement.execute(value)
74
+ mysql_result = mysql_statement.result_metadata
75
+ fields = mysql_result.fetch_fields
76
+ field_names = fields.map { |field|
77
+ field.name
78
+ }
79
+ result = []
80
+ mysql_statement.each { |entry|
81
+ result << Hash[entry.map.with_index { |value, index|
82
+ [field_names[index.to_i], value]
83
+ }].symbolize_keys
84
+ }
85
+ result
86
+ end
87
+ end
88
+
89
+ ##
90
+ # @return [Array] a list of primary keys and global secondary indexes
91
+ ##
92
+ def index
93
+ adapt_exceptions do
94
+ index = []
95
+ @client.query("SHOW INDEX FROM Client").each_hash { |entry|
96
+ index << entry['Column_name']
97
+ }
98
+ index
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ def adapt_exceptions
105
+ begin
106
+ yield
107
+ rescue ::Mysql::Error => e
108
+ raise Soar::Registry::Directory::Error::NetworkingError, e.message
109
+ end
110
+ end
111
+
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -9,25 +9,26 @@ module Soar
9
9
  module Provider
10
10
  class Stub
11
11
 
12
- @@interface = Mince::HashyDb::Interface
13
-
14
12
  ##
15
13
  # @param table [String] table name
16
14
  # @param primary_key [String]
17
15
  # @param index [Array] primary key should be the first item
18
16
  ##
19
17
  def initialize(table: , index: )
18
+ @interface = Mince::HashyDb::Interface
20
19
  @table = table
21
20
  @primary_key = index[0]
22
21
  @index = index
23
- @@interface.clear
22
+ @interface.clear
24
23
  end
25
24
 
26
25
  ##
27
26
  # @param entity [Hash]
28
27
  ##
29
28
  def put(entity)
30
- @@interface.add(@table, entity)
29
+ adapt_exceptions do
30
+ @interface.add(@table, entity)
31
+ end
31
32
  end
32
33
 
33
34
  ##
@@ -36,9 +37,11 @@ module Soar
36
37
  # @raise [Soar::Registry:::Directory::Error::NoEntriesFound] if primary key not found
37
38
  ##
38
39
  def fetch(primary_key)
39
- entry = @@interface.get_for_key_with_value(@table, @primary_key, primary_key)
40
- raise Soar::Registry::Directory::Error::NoEntriesFound if entry.nil?
41
- entry
40
+ adapt_exceptions do
41
+ 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?
43
+ entry
44
+ end
42
45
  end
43
46
 
44
47
  ##
@@ -48,23 +51,40 @@ module Soar
48
51
  # @raise [ArgumentError] if query or index is not specified
49
52
  ##
50
53
  def search(key, value)
51
- identities = []
52
- @@interface.find_all(@table).each { |identity|
53
- if identity[key] == value
54
- identities << identity
55
- else
56
- next
57
- end
58
- }
59
- identities
54
+ adapt_exceptions do
55
+ identities = []
56
+ @interface.find_all(@table).each { |identity|
57
+ if identity[key] == value
58
+ identities << identity
59
+ else
60
+ next
61
+ end
62
+ }
63
+ identities
64
+ end
60
65
  end
61
66
 
62
67
  ##
63
68
  # @return [Array] a list of primary keys and global secondary indexes
64
69
  ##
65
70
  def index
66
- @index
71
+ adapt_exceptions do
72
+ [@interface.primary_key.to_s]
73
+ @index
74
+ end
75
+ end
76
+
77
+
78
+ private
79
+
80
+ def adapt_exceptions
81
+ begin
82
+ yield
83
+ rescue NoMethodError => e
84
+ raise Soar::Registry::Directory::Error::NetworkingError, 'Networking error'
85
+ end
67
86
  end
87
+
68
88
  end
69
89
 
70
90
  end
@@ -0,0 +1,91 @@
1
+ DROP TABLE IF EXISTS `Client`;
2
+ CREATE TABLE `Client` (
3
+ `ID` int(11) NOT NULL AUTO_INCREMENT,
4
+ `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
5
+ `Client_Number` varchar(15) NOT NULL DEFAULT '',
6
+ `Privil` varchar(15) NOT NULL DEFAULT '',
7
+ `Active` enum('0','1') NOT NULL DEFAULT '0',
8
+ `ActiveUntil` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
9
+ `MaxDomains` int(11) NOT NULL DEFAULT '100',
10
+ `Title` varchar(10) DEFAULT NULL,
11
+ `First_Name` varchar(70) DEFAULT NULL,
12
+ `Surname` varchar(70) DEFAULT NULL,
13
+ `Company` varchar(70) DEFAULT NULL,
14
+ `Street` varchar(70) DEFAULT NULL,
15
+ `Postal_Code` varchar(10) DEFAULT NULL,
16
+ `Suburb` varchar(70) NOT NULL DEFAULT '',
17
+ `Country` varchar(70) NOT NULL DEFAULT '0',
18
+ `City` varchar(70) NOT NULL DEFAULT '',
19
+ `CountryGroup` enum('0','1','2') NOT NULL DEFAULT '0',
20
+ `Telephone` varchar(50) DEFAULT NULL,
21
+ `Cellphone` varchar(50) NOT NULL DEFAULT '',
22
+ `ID_Number` varchar(30) DEFAULT NULL,
23
+ `Date_Of_Birth` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
24
+ `Fax` varchar(50) DEFAULT NULL,
25
+ `RipeHandle` varchar(16) NOT NULL DEFAULT '',
26
+ `Login` varchar(15) DEFAULT NULL,
27
+ `Password` varchar(30) DEFAULT NULL,
28
+ `FromEmail1` varchar(40) NOT NULL DEFAULT '',
29
+ `FromEmail2` varchar(40) DEFAULT NULL,
30
+ `FromEmail3` varchar(40) DEFAULT NULL,
31
+ `PublicKey` mediumtext NOT NULL,
32
+ `Newsletter` enum('0','1') NOT NULL DEFAULT '0',
33
+ `Notice` enum('0','1') NOT NULL DEFAULT '1',
34
+ `Notifyemail` varchar(100) DEFAULT NULL,
35
+ `Notifyemail_Robot` varchar(100) NOT NULL DEFAULT '',
36
+ `Notifyemail_Traffic` varchar(100) DEFAULT NULL,
37
+ `Notifyemail_Invoice` text,
38
+ `FreeTraffic` decimal(4,2) DEFAULT NULL,
39
+ `Bank_Branch_Code` varchar(8) DEFAULT NULL,
40
+ `Bank_Account_Number` varchar(30) DEFAULT NULL,
41
+ `Bank_Account_Holder` varchar(60) DEFAULT NULL,
42
+ `Bank_Account_Type` enum('0','1','2','3','4','5') NOT NULL DEFAULT '0',
43
+ `Bank_Name` varchar(60) NOT NULL DEFAULT '',
44
+ `Bank_Branch_Location` varchar(60) NOT NULL DEFAULT '',
45
+ `Reseller` enum('0','1') NOT NULL DEFAULT '0',
46
+ `Reseller_Proof` varchar(60) NOT NULL DEFAULT '',
47
+ `CreditCardNumber` varchar(30) NOT NULL DEFAULT '',
48
+ `CreditCardExpiration` varchar(6) NOT NULL DEFAULT '',
49
+ `CreditCardName` varchar(15) NOT NULL DEFAULT '',
50
+ `payment_method` enum('Unspecified','Cash','Debit Order') NOT NULL DEFAULT 'Unspecified',
51
+ `Mother_ID` varchar(12) NOT NULL DEFAULT '',
52
+ `ChargeVAT` enum('0','1') NOT NULL DEFAULT '1',
53
+ `Summary_Invoice` enum('0','1') NOT NULL DEFAULT '0',
54
+ `Separate_Invoice` enum('0','1') NOT NULL DEFAULT '0',
55
+ `Email_Format` enum('0','1','2','3') NOT NULL DEFAULT '1',
56
+ `Dedi_Graph` enum('0','1') NOT NULL DEFAULT '1',
57
+ `TaxID` varchar(20) NOT NULL DEFAULT '',
58
+ `Discount` decimal(4,2) DEFAULT NULL,
59
+ `ChargeRobotSetup` enum('0','1','2') DEFAULT NULL,
60
+ `ClientCreated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
61
+ `Comment` text,
62
+ `Advice` mediumtext NOT NULL,
63
+ `Vat_Number` varchar(30) DEFAULT NULL,
64
+ `Rejection_Counter` tinyint(11) DEFAULT '0',
65
+ `Marketing` enum('Print','Brainstorm','ComputerActive','Google','ITWeb','Mouth','Website','Search','Designer','Hetzner','Other','SA Computer Magazine','Entrepreneur Magazine','Financial Mail') DEFAULT NULL,
66
+ `Marketing_other` mediumtext,
67
+ `Billing_First_Name` varchar(70) NOT NULL DEFAULT '',
68
+ `Billing_Surname` varchar(70) NOT NULL DEFAULT '',
69
+ `Billing_Telephone` varchar(50) NOT NULL DEFAULT '',
70
+ `Billing_Cellphone` varchar(50) NOT NULL DEFAULT '',
71
+ `Tech_First_Name` varchar(70) NOT NULL DEFAULT '',
72
+ `Tech_Surname` varchar(70) NOT NULL DEFAULT '',
73
+ `Notifyemail_Tech` varchar(100) NOT NULL DEFAULT '',
74
+ `Tech_Telephone` varchar(50) NOT NULL DEFAULT '',
75
+ `Tech_Cellphone` varchar(50) NOT NULL DEFAULT '',
76
+ `Verified` enum('0','1') NOT NULL DEFAULT '1',
77
+ `mass_update_notification_sent` enum('1','2','3','more','no') NOT NULL DEFAULT 'no',
78
+ `mass_update_submission_sent` enum('yes','no') NOT NULL DEFAULT 'no',
79
+ `contact_Confirmed` enum('True','False') NOT NULL DEFAULT 'True',
80
+ `is_test_profile` enum('0','1') DEFAULT '0',
81
+ `Google` enum('None','Eligible','Emailed','Issued') NOT NULL DEFAULT 'None',
82
+ `Google_Value_ID` int(11) NOT NULL DEFAULT '0',
83
+ `Google_Expiry` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
84
+ `app_installer_active` tinyint(1) DEFAULT '1',
85
+ PRIMARY KEY (`ID`),
86
+ KEY `Login` (`Login`),
87
+ KEY `Password` (`Password`),
88
+ KEY `Notifyemail_Invoice` (`Notifyemail_Invoice`(20)),
89
+ KEY `Client_Number` (`Client_Number`)
90
+ ) ENGINE=InnoDB AUTO_INCREMENT=185532 DEFAULT CHARSET=latin1;
91
+
@@ -1,4 +1,5 @@
1
1
  require 'soar/registry/directory/test/provider/stub'
2
+ require 'soar/registry/directory/test/provider/mysql'
2
3
  require 'soar/registry/directory/test/provider/dynamo_db'
3
4
  require 'soar/registry/directory/test/provider/ldap'
4
5
 
@@ -21,6 +22,10 @@ module Soar
21
22
  @provider.given_configured_directory
22
23
  end
23
24
 
25
+ def sabotage_network
26
+ @provider.sabotage_network
27
+ end
28
+
24
29
  def put_entry
25
30
  @provider.put_entry
26
31
  end
@@ -61,6 +66,10 @@ module Soar
61
66
  @provider.no_matching_entries?
62
67
  end
63
68
 
69
+ def networking_error?
70
+ @provider.networking_error?
71
+ end
72
+
64
73
  end
65
74
  end
66
75
  end
@@ -1,4 +1,7 @@
1
1
  require 'soar/registry/directory'
2
+ require 'aws-sdk'
3
+ require 'hashie'
4
+ require 'soar/registry/directory/error'
2
5
 
3
6
  module Soar
4
7
  module Registry
@@ -8,6 +11,7 @@ module Soar
8
11
  class DynamoDb
9
12
 
10
13
  def initialize
14
+ @retries = 5
11
15
  @configuration = YAML.load_file("config/#{ENV['CONFIG_FILE']}")
12
16
  @table = @configuration['provider']['table']['name']
13
17
  @index = @configuration['provider']['table']['index']
@@ -34,23 +38,41 @@ module Soar
34
38
  }
35
39
  end
36
40
 
41
+ def sabotage_network
42
+ @configuration['provider']['config'][:credentials] = Aws::Credentials.new(@configuration['provider']['credentials']['username'], @configuration['provider']['credentials']['password'])
43
+ @configuration['provider']['config']['endpoint'] = 'http://does-not-exist'
44
+ @directory.provider.client = Aws::DynamoDB::Client.new(Hashie.symbolize_keys(@configuration['provider']['config']))
45
+ end
46
+
37
47
  def put_entry
38
- @directory.put(@entries[0])
48
+ begin
49
+ @directory.put(@entries[0])
50
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
51
+ @error = e.message
52
+ end
39
53
  end
40
54
 
41
55
  def search_for_entry
42
- @result = @directory.search("email", @entries[0]['email'])
56
+ begin
57
+ @result = @directory.search("email", @entries[0]['email'])
58
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
59
+ @error = e.message
60
+ end
43
61
  end
44
62
 
45
63
  def request_index
46
- @result = @directory.index
64
+ begin
65
+ @result = @directory.index
66
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
67
+ @error = e.message
68
+ end
47
69
  end
48
70
 
49
71
  def fetch_entry
50
72
  begin
51
73
  @result = @directory.fetch(@entries[0]['uuid'])
52
- rescue Soar::Registry::Directory::Error::NoEntriesFound
53
- @error = true
74
+ rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
75
+ @error = e.message
54
76
  end
55
77
  end
56
78
 
@@ -63,7 +85,7 @@ module Soar
63
85
  end
64
86
 
65
87
  def index?
66
- @result == @index
88
+ @index
67
89
  end
68
90
 
69
91
  def single_entry?
@@ -71,7 +93,11 @@ module Soar
71
93
  end
72
94
 
73
95
  def no_entries_found?
74
- @error
96
+ !!(@error =~ /\ANo entries found for .+\z/)
97
+ end
98
+
99
+ def networking_error?
100
+ !!(@error =~ /\AFailed to open TCP connection to .+\z/)
75
101
  end
76
102
 
77
103
  def no_matching_entries?
@@ -52,25 +52,50 @@ module Soar
52
52
  }
53
53
  end
54
54
 
55
+ def sabotage_network
56
+ @directory.provider.client = Net::LDAP.new({
57
+ host: 'localhost',
58
+ port: @configuration['provider']['config']['config']['port'],
59
+ auth: {
60
+ method: :simple,
61
+ username: @configuration['provider']['config']['credentials']['username'],
62
+ password: @configuration['provider']['config']['credentials']['password']
63
+ }
64
+ })
65
+
66
+ end
67
+
55
68
  def put_entry
56
- @directory.put(@entries[0])
57
- result = @directory.search("mail", @entries[0][:attributes][:mail])
58
- @entries[0][:attributes][:entryuuid] = result[0][@index[0]]
69
+ begin
70
+ @directory.put(@entries[0])
71
+ result = @directory.search("mail", @entries[0][:attributes][:mail])
72
+ @entries[0][:attributes][:entryuuid] = result[0][@index[0]]
73
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
74
+ @error = e.message
75
+ end
59
76
  end
60
77
 
61
78
  def search_for_entry
62
- @result = @directory.search("mail", @entries[0][:attributes][:mail])
79
+ begin
80
+ @result = @directory.search("mail", @entries[0][:attributes][:mail])
81
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
82
+ @error = e.message
83
+ end
63
84
  end
64
85
 
65
86
  def request_index
66
- @result = @directory.index
87
+ begin
88
+ @result = @directory.index
89
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
90
+ @error = e.message
91
+ end
67
92
  end
68
93
 
69
94
  def fetch_entry
70
95
  begin
71
96
  @result = @directory.fetch(@entries[0][:attributes][:entryuuid])
72
- rescue Soar::Registry::Directory::Error::NoEntriesFound
73
- @error = true
97
+ rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
98
+ @error = e.message
74
99
  end
75
100
  end
76
101
 
@@ -88,7 +113,7 @@ module Soar
88
113
  end
89
114
 
90
115
  def index?
91
- @result == @index
116
+ @index
92
117
  end
93
118
 
94
119
  def single_entry?
@@ -98,13 +123,17 @@ module Soar
98
123
  end
99
124
 
100
125
  def no_entries_found?
101
- @error == true
126
+ !!(@error =~ /\ANo entries found for .+\z/)
102
127
  end
103
128
 
104
129
  def no_matching_entries?
105
130
  @result == []
106
131
  end
107
132
 
133
+ def networking_error?
134
+ !!(@error =~ /\A(Invalid binding information|Connection refused).*\z/)
135
+ end
136
+
108
137
  end
109
138
  end
110
139
  end
@@ -0,0 +1,137 @@
1
+ require 'soar/registry/directory'
2
+ require 'mysql'
3
+ # http://zetcode.com/db/mysqlrubytutorial/
4
+
5
+ module Soar
6
+ module Registry
7
+ module Directory
8
+ module Test
9
+ module Provider
10
+ class Mysql
11
+
12
+ PATH_TO_DATABASE_STRUCTURE_DUMP = "lib/soar/registry/directory/test/fixtures/data-dump.sql"
13
+
14
+ def initialize
15
+ @configuration = YAML.load_file("config/#{ENV['CONFIG_FILE']}")
16
+ @index = @configuration['provider']['config']['index']
17
+ @attributes = @configuration['provider']['config']['attributes']
18
+ @entries = [{
19
+ Client_Number: "C123456789",
20
+ Notifyemail_Invoice: "johnconner@example.com"
21
+ }, {
22
+ Client_Number: "C101112134",
23
+ Notifyemail_Invoice: "sarahconnor@example.com"
24
+ }]
25
+ end
26
+
27
+ def given_configured_directory
28
+ recreate_table({
29
+ host: @configuration['provider']['config']['config']['host'],
30
+ username: @configuration['provider']['config']['credentials']['username'],
31
+ password: @configuration['provider']['config']['credentials']['password'],
32
+ filepath: PATH_TO_DATABASE_STRUCTURE_DUMP
33
+ })
34
+ provider_class = Object.const_get(@configuration['provider']['class'])
35
+ provider = provider_class.new(Hashie.symbolize_keys(@configuration['provider']['config']))
36
+ @directory = Soar::Registry::Directory.new(provider)
37
+ end
38
+
39
+ ##
40
+ # Adds @entries to datastore using ldap protocol
41
+ # Adds entryuuid to @entries
42
+ ##
43
+ def given_existing_data
44
+ @entries.each{ |entry|
45
+ @directory.put(entry)
46
+ }
47
+ end
48
+
49
+ def sabotage_network
50
+ @directory.provider.client.close
51
+ end
52
+
53
+ def put_entry
54
+ begin
55
+ @directory.put(@entries[0])
56
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
57
+ @error = e.message
58
+ end
59
+ end
60
+
61
+ def search_for_entry
62
+ begin
63
+ @result = @directory.search("Notifyemail_Invoice", @entries[0][:Notifyemail_Invoice])
64
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
65
+ @error = e.message
66
+ end
67
+ end
68
+
69
+ def request_index
70
+ begin
71
+ @result = @directory.index
72
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
73
+ @error = e.message
74
+ end
75
+ end
76
+
77
+ def fetch_entry
78
+ begin
79
+ @result = @directory.fetch(@entries[0][:Client_Number])
80
+ rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
81
+ @error = e.message
82
+ end
83
+ end
84
+
85
+ def persisted?
86
+ @directory.fetch(@entries[0][:Client_Number]) == @entries[0]
87
+ end
88
+
89
+ def returned?
90
+ @result == [@entries[0]]
91
+ end
92
+
93
+ def index?
94
+ @result
95
+ end
96
+
97
+ def single_entry?
98
+ @result == @entries[0]
99
+ end
100
+
101
+ def no_entries_found?
102
+ !!(@error =~ /\ANo entries found for .+\z/)
103
+ end
104
+
105
+ def no_matching_entries?
106
+ @result == []
107
+ end
108
+
109
+ def networking_error?
110
+ patterns = [
111
+ /\Aquery: not connected.*\z/,
112
+ /\AMySQL server has gone away\z/,
113
+ /\ACan't connect to local MySQL server through socket.*\z/,
114
+ /\AERROR 2003 (HY000): Can't connect to MySQL server on.*\z/,
115
+ /\ALost connection to MySQL server.*\z/
116
+ ]
117
+ patterns.any? { |pattern|
118
+ break true if !!(@error =~ pattern)
119
+ }
120
+ end
121
+
122
+ private
123
+
124
+ ##
125
+ # Execute command using mysql client on terminal
126
+ ##
127
+ def recreate_table(host:, username:, password:, filepath:)
128
+ `mysql -h #{host} -u#{username} -p#{password} konsoleh_genie < '#{filepath}'`
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ end
137
+ end
@@ -1,4 +1,6 @@
1
1
  require 'soar/registry/directory'
2
+ require 'mince'
3
+ require 'hashy_db'
2
4
 
3
5
  module Soar
4
6
  module Registry
@@ -26,23 +28,39 @@ module Soar
26
28
  @directory.put(@@entry)
27
29
  end
28
30
 
31
+ def sabotage_network
32
+ @directory.provider.instance_variable_set(:@interface, Object.new)
33
+ end
34
+
29
35
  def put_entry
30
- @directory.put(@@entry)
36
+ begin
37
+ @directory.put(@@entry)
38
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
39
+ @error = e.message
40
+ end
31
41
  end
32
42
 
33
43
  def search_for_entry
34
- @entry = @directory.search("identifier", @@entry['identifier'])
44
+ begin
45
+ @entry = @directory.search("identifier", @@entry['identifier'])
46
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
47
+ @error = e.message
48
+ end
35
49
  end
36
50
 
37
51
  def request_index
38
- @index = @directory.index
52
+ begin
53
+ @index = @directory.index
54
+ rescue Soar::Registry::Directory::Error::NetworkingError => e
55
+ @error = e.message
56
+ end
39
57
  end
40
58
 
41
59
  def fetch_entry
42
60
  begin
43
61
  @entry = @directory.fetch(@@entry['uuid'])
44
- rescue Soar::Registry::Directory::Error::NoEntriesFound
45
- @error = true
62
+ rescue Soar::Registry::Directory::Error::NoEntriesFound, Soar::Registry::Directory::Error::NetworkingError => e
63
+ @error = e.message
46
64
  end
47
65
  end
48
66
 
@@ -55,7 +73,7 @@ module Soar
55
73
  end
56
74
 
57
75
  def index?
58
- @index == @@index
76
+ @index
59
77
  end
60
78
 
61
79
  def single_entry?
@@ -63,13 +81,17 @@ module Soar
63
81
  end
64
82
 
65
83
  def no_entries_found?
66
- @error
84
+ !!(@error =~ /\ANo entries found for .+\z/)
67
85
  end
68
86
 
69
87
  def no_matching_entries?
70
88
  @entry == []
71
89
  end
72
90
 
91
+ def networking_error?
92
+ !!(@error =~ /\ANetworking error\z/)
93
+ end
94
+
73
95
  end
74
96
  end
75
97
  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: 3.0.0
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Mulder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-01 00:00:00.000000000 Z
11
+ date: 2017-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashy_db
@@ -59,59 +59,59 @@ dependencies:
59
59
  - !ruby/object:Gem::Version
60
60
  version: 2.6.6
61
61
  - !ruby/object:Gem::Dependency
62
- name: aws-sdk-core
62
+ name: hashie
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '2.6'
67
+ version: '3.4'
68
68
  - - ">="
69
69
  - !ruby/object:Gem::Version
70
- version: 2.6.38
70
+ version: 3.4.6
71
71
  type: :runtime
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  requirements:
75
75
  - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: '2.6'
77
+ version: '3.4'
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
- version: 2.6.38
80
+ version: 3.4.6
81
81
  - !ruby/object:Gem::Dependency
82
- name: hashie
82
+ name: net-ldap
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '3.4'
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- version: 3.4.6
87
+ version: 0.15.0
91
88
  type: :runtime
92
89
  prerelease: false
93
90
  version_requirements: !ruby/object:Gem::Requirement
94
91
  requirements:
95
92
  - - "~>"
96
93
  - !ruby/object:Gem::Version
97
- version: '3.4'
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- version: 3.4.6
94
+ version: 0.15.0
101
95
  - !ruby/object:Gem::Dependency
102
- name: net-ldap
96
+ name: mysql
103
97
  requirement: !ruby/object:Gem::Requirement
104
98
  requirements:
105
99
  - - "~>"
106
100
  - !ruby/object:Gem::Version
107
- version: 0.15.0
101
+ version: '2.9'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 2.9.1
108
105
  type: :runtime
109
106
  prerelease: false
110
107
  version_requirements: !ruby/object:Gem::Requirement
111
108
  requirements:
112
109
  - - "~>"
113
110
  - !ruby/object:Gem::Version
114
- version: 0.15.0
111
+ version: '2.9'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 2.9.1
115
115
  description: Directories for soar registries
116
116
  email: charles.mulder@hetzner.co.za
117
117
  executables: []
@@ -124,13 +124,16 @@ files:
124
124
  - lib/soar/registry/directory/model.rb
125
125
  - lib/soar/registry/directory/provider/dynamo_db.rb
126
126
  - lib/soar/registry/directory/provider/ldap.rb
127
+ - lib/soar/registry/directory/provider/mysql.rb
127
128
  - lib/soar/registry/directory/provider/stub.rb
129
+ - lib/soar/registry/directory/test/fixtures/data-dump.sql
128
130
  - lib/soar/registry/directory/test/fixtures/entries.json
129
131
  - lib/soar/registry/directory/test/fixtures/entries.ldif
130
132
  - lib/soar/registry/directory/test/fixtures/table_structure.json
131
133
  - lib/soar/registry/directory/test/orchestrator.rb
132
134
  - lib/soar/registry/directory/test/provider/dynamo_db.rb
133
135
  - lib/soar/registry/directory/test/provider/ldap.rb
136
+ - lib/soar/registry/directory/test/provider/mysql.rb
134
137
  - lib/soar/registry/directory/test/provider/stub.rb
135
138
  homepage: https://gitlab.host-h.net/registries/directory
136
139
  licenses: