soar-registry-directory 3.0.0 → 4.0.3

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: 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: