rubysync 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/HISTORY.txt +11 -0
- data/Manifest.txt +4 -1
- data/Rakefile +3 -4
- data/bin/rubysync +242 -152
- data/bin/rubysync.rb +242 -152
- data/lib/ruby_sync.rb +1 -1
- data/lib/ruby_sync/connectors/base_connector.rb +286 -378
- data/lib/ruby_sync/connectors/connector_event_processing.rb +24 -20
- data/lib/ruby_sync/connectors/csv_file_connector.rb +3 -5
- data/lib/ruby_sync/connectors/dbm_association_tracking.rb +88 -0
- data/lib/ruby_sync/connectors/dbm_change_tracking.rb +110 -0
- data/lib/ruby_sync/connectors/ldap_changelog_connector.rb +79 -78
- data/lib/ruby_sync/connectors/ldap_connector.rb +84 -57
- data/lib/ruby_sync/connectors/memory_association_tracking.rb +60 -0
- data/lib/ruby_sync/connectors/memory_change_tracking.rb +84 -0
- data/lib/ruby_sync/connectors/memory_connector.rb +3 -0
- data/lib/ruby_sync/connectors/xml_connector.rb +6 -2
- data/lib/ruby_sync/event.rb +73 -50
- data/lib/ruby_sync/operation.rb +3 -3
- data/lib/ruby_sync/pipelines/base_pipeline.rb +76 -48
- data/lib/ruby_sync/util/utilities.rb +72 -29
- data/test/tc_csv_file_connector.rb +2 -2
- data/test/tc_ldap_connector.rb +2 -2
- data/test/tc_memory_connectors.rb +0 -2
- data/test/tc_transformation.rb +14 -13
- data/test/tc_xml_connectors.rb +4 -2
- data/test/ts_rubysync.rb +1 -1
- metadata +102 -84
- metadata.gz.sig +0 -0
- data/lib/ruby_sync/connectors/ldap_associations.rb +0 -126
@@ -24,7 +24,7 @@ require 'csv'
|
|
24
24
|
|
25
25
|
|
26
26
|
class TestCsvFileConnector < RubySync::Connectors::CsvFileConnector
|
27
|
-
dbm_path "/tmp/rubysync_csv"
|
27
|
+
# dbm_path "/tmp/rubysync_csv"
|
28
28
|
field_names ['id', 'given name', 'last name', 'email']
|
29
29
|
path_field 'id'
|
30
30
|
in_path File.expand_path("~/rubysync/csv_test/in")
|
@@ -33,7 +33,7 @@ class TestCsvFileConnector < RubySync::Connectors::CsvFileConnector
|
|
33
33
|
end
|
34
34
|
|
35
35
|
class TestMemoryConnector < RubySync::Connectors::MemoryConnector
|
36
|
-
dbm_path "/tmp/rubysync_memory"
|
36
|
+
# dbm_path "/tmp/rubysync_memory"
|
37
37
|
end
|
38
38
|
|
39
39
|
|
data/test/tc_ldap_connector.rb
CHANGED
@@ -26,10 +26,10 @@ require 'ruby_sync/connectors/memory_connector'
|
|
26
26
|
class MyLdapConnector < RubySync::Connectors::LdapConnector
|
27
27
|
host 'any_ldap'
|
28
28
|
port 389
|
29
|
-
username 'cn=
|
29
|
+
username 'cn=admin,dc=9to5magic,dc=com,dc=au'
|
30
30
|
password 'secret'
|
31
31
|
search_filter "cn=*"
|
32
|
-
search_base "
|
32
|
+
search_base "dc=9to5magic,dc=com,dc=au"
|
33
33
|
end
|
34
34
|
|
35
35
|
class MyMemoryConnector < RubySync::Connectors::MemoryConnector; end
|
@@ -25,11 +25,9 @@ require 'ruby_sync/connectors/memory_connector'
|
|
25
25
|
|
26
26
|
|
27
27
|
class MemoryTestAConnector < RubySync::Connectors::MemoryConnector
|
28
|
-
dbm_path "/tmp/rubysync_a"
|
29
28
|
end
|
30
29
|
|
31
30
|
class MemoryTestBConnector < RubySync::Connectors::MemoryConnector
|
32
|
-
dbm_path "/tmp/rubysync_b"
|
33
31
|
end
|
34
32
|
|
35
33
|
class MemoryTestPipeline < RubySync::Pipelines::BasePipeline
|
data/test/tc_transformation.rb
CHANGED
@@ -24,11 +24,9 @@ require 'ruby_sync/connectors/xml_connector'
|
|
24
24
|
|
25
25
|
|
26
26
|
class TransformationVaultConnector < RubySync::Connectors::MemoryConnector
|
27
|
-
dbm_path "/tmp/rubysync_xml"
|
28
27
|
end
|
29
28
|
|
30
29
|
class TransformationClientConnector < RubySync::Connectors::MemoryConnector
|
31
|
-
dbm_path "/tmp/rubysync_memory"
|
32
30
|
end
|
33
31
|
|
34
32
|
|
@@ -39,22 +37,25 @@ class TransformationTestPipeline < RubySync::Pipelines::BasePipeline
|
|
39
37
|
allow_in :givenName, :sn, :interests
|
40
38
|
allow_out :first_name, :last_name
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# Conditional mapping
|
51
|
-
map(:password) {value_for(:givenName)} if type == :add
|
40
|
+
in_event_transform do
|
41
|
+
map :first_name, :givenName
|
42
|
+
map :last_name, :sn
|
43
|
+
# Calculated value
|
44
|
+
map(:hobbies) {values_for(:interests).join ':'}
|
45
|
+
# Constant string
|
46
|
+
map(:note) {"Created by RubySync"}
|
47
|
+
map(:shopping) {%w/fish milk bread/}
|
52
48
|
end
|
53
49
|
|
50
|
+
in_command_transform do
|
51
|
+
# Conditional mapping
|
52
|
+
map(:password) {value_for(:first_name)} if type == :add
|
53
|
+
end
|
54
|
+
|
54
55
|
in_place { "#{self.source_path}/path/in/vault"}
|
55
56
|
out_place { "#{self.source_path}".split('/')[0] }
|
56
57
|
|
57
|
-
dump_after :
|
58
|
+
dump_after :in_command_transform
|
58
59
|
end
|
59
60
|
|
60
61
|
class TcTransformation < Test::Unit::TestCase
|
data/test/tc_xml_connectors.rb
CHANGED
@@ -25,12 +25,14 @@ require 'ruby_sync/connectors/xml_connector'
|
|
25
25
|
|
26
26
|
|
27
27
|
class XmlTestAConnector < RubySync::Connectors::XmlConnector
|
28
|
-
|
28
|
+
track_changes_with :memory
|
29
29
|
filename "/tmp/rubysync_a.xml"
|
30
30
|
end
|
31
31
|
|
32
32
|
class XmlTestBConnector < RubySync::Connectors::XmlConnector
|
33
|
-
|
33
|
+
track_changes_with :memory
|
34
|
+
track_associations_with :memory
|
35
|
+
|
34
36
|
filename "/tmp/rubysync_b.xml"
|
35
37
|
end
|
36
38
|
|
data/test/ts_rubysync.rb
CHANGED
@@ -22,8 +22,8 @@ require 'tc_ldif'
|
|
22
22
|
require 'tc_base_pipeline'
|
23
23
|
require 'tc_xml_connectors'
|
24
24
|
require 'tc_transformation'
|
25
|
-
require 'tc_active_record_connector'
|
26
25
|
|
27
26
|
# The following require some setup on your computer before they'll work
|
28
27
|
|
29
28
|
#require 'tc_ldap_connector'
|
29
|
+
#require 'tc_active_record_connector'
|
metadata
CHANGED
@@ -1,29 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: rubysync
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
- lib
|
11
|
-
email: ritchiey@gmail.com
|
12
|
-
homepage: " by Ritchie Young"
|
13
|
-
rubyforge_project: rubysync
|
14
|
-
description: "You can configure RubySync to perform transformations on the data as it syncs. RubySync is designed both as a handy utility to pack into your directory management toolkit or as a fully-fledged provisioning system for your organization. == FEATURES/PROBLEMS: * Event-driven synchronization (if connector supports it) with fall-back to polling * Ruby DSL for \"configuration\" style event processing * Clean separation of connector details from data transformation * Connectors available for CSV files, XML, LDAP and RDBMS (via ActiveRecord) * Easy API for writing your own connectors == SYNOPSIS:"
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ritchie Young
|
15
8
|
autorequire:
|
16
|
-
default_executable:
|
17
9
|
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
25
|
-
platform: ruby
|
26
|
-
signing_key:
|
27
10
|
cert_chain:
|
28
11
|
- |
|
29
12
|
-----BEGIN CERTIFICATE-----
|
@@ -47,9 +30,76 @@ cert_chain:
|
|
47
30
|
+lEskbtv
|
48
31
|
-----END CERTIFICATE-----
|
49
32
|
|
50
|
-
|
51
|
-
|
52
|
-
|
33
|
+
date: 2008-06-11 00:00:00 +08:00
|
34
|
+
default_executable:
|
35
|
+
dependencies:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: ruby-net-ldap
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.0.4
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: activesupport
|
47
|
+
version_requirement:
|
48
|
+
version_requirements: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.4.0
|
53
|
+
version:
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: activerecord
|
56
|
+
version_requirement:
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.15.3
|
62
|
+
version:
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: simpleconsole
|
65
|
+
version_requirement:
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.1.1
|
71
|
+
version:
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: contacts
|
74
|
+
version_requirement:
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.0.7
|
80
|
+
version:
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: hoe
|
83
|
+
version_requirement:
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.5.1
|
89
|
+
version:
|
90
|
+
description: "== DESCRIPTION: RubySync is a tool for synchronizing part or all of your directory, database or application data with anything else. It's event driven so it will happily sit there monitoring changes and passing them on. Alternatively, you can run it in one-shot mode and simply sync A with B. You can configure RubySync to perform transformations on the data as it syncs. RubySync is designed both as a handy utility to pack into your directory management toolkit or as a fully-fledged provisioning system for your organization. == FEATURES/PROBLEMS: * Event-driven synchronization (if connector supports it) with fall-back to polling * Ruby DSL for \"configuration\" style event processing * Clean separation of connector details from data transformation * Connectors available for CSV files, XML, LDAP and RDBMS (via ActiveRecord) * Easy API for writing your own connectors == SYNOPSIS:"
|
91
|
+
email: ritchiey@gmail.com
|
92
|
+
executables:
|
93
|
+
- rubysync
|
94
|
+
- rubysync.rb
|
95
|
+
extensions: []
|
96
|
+
|
97
|
+
extra_rdoc_files:
|
98
|
+
- HISTORY.txt
|
99
|
+
- Manifest.txt
|
100
|
+
- README.txt
|
101
|
+
- examples/ar_webapp/public/robots.txt
|
102
|
+
- examples/csv_to_xml/transcript.txt
|
53
103
|
files:
|
54
104
|
- COPYING
|
55
105
|
- HISTORY.txt
|
@@ -175,11 +225,14 @@ files:
|
|
175
225
|
- lib/ruby_sync/connectors/connector_event_processing.rb
|
176
226
|
- lib/ruby_sync/connectors/csv_file_connector.rb
|
177
227
|
- lib/ruby_sync/connectors/file_connector.rb
|
178
|
-
- lib/ruby_sync/connectors/ldap_associations.rb
|
179
228
|
- lib/ruby_sync/connectors/ldap_changelog_connector.rb
|
180
229
|
- lib/ruby_sync/connectors/ldap_connector.rb
|
181
230
|
- lib/ruby_sync/connectors/memory_connector.rb
|
182
231
|
- lib/ruby_sync/connectors/xml_connector.rb
|
232
|
+
- lib/ruby_sync/connectors/dbm_association_tracking.rb
|
233
|
+
- lib/ruby_sync/connectors/dbm_change_tracking.rb
|
234
|
+
- lib/ruby_sync/connectors/memory_association_tracking.rb
|
235
|
+
- lib/ruby_sync/connectors/memory_change_tracking.rb
|
183
236
|
- lib/ruby_sync/event.rb
|
184
237
|
- lib/ruby_sync/operation.rb
|
185
238
|
- lib/ruby_sync/pipelines/base_pipeline.rb
|
@@ -209,67 +262,32 @@ files:
|
|
209
262
|
- test/tc_utilities.rb
|
210
263
|
- test/tc_xml_connectors.rb
|
211
264
|
- test/ts_rubysync.rb
|
212
|
-
|
213
|
-
|
265
|
+
has_rdoc: true
|
266
|
+
homepage: " by Ritchie Young"
|
267
|
+
post_install_message:
|
214
268
|
rdoc_options:
|
215
269
|
- --main
|
216
270
|
- README.txt
|
217
|
-
|
218
|
-
-
|
219
|
-
|
220
|
-
|
221
|
-
-
|
222
|
-
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
271
|
+
require_paths:
|
272
|
+
- lib
|
273
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
274
|
+
requirements:
|
275
|
+
- - ">="
|
276
|
+
- !ruby/object:Gem::Version
|
277
|
+
version: "0"
|
278
|
+
version:
|
279
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
280
|
+
requirements:
|
281
|
+
- - ">="
|
282
|
+
- !ruby/object:Gem::Version
|
283
|
+
version: "0"
|
284
|
+
version:
|
228
285
|
requirements: []
|
229
286
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
- !ruby/object:Gem::Version
|
238
|
-
version: 0.0.4
|
239
|
-
version:
|
240
|
-
- !ruby/object:Gem::Dependency
|
241
|
-
name: activesupport
|
242
|
-
version_requirement:
|
243
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
244
|
-
requirements:
|
245
|
-
- - ">="
|
246
|
-
- !ruby/object:Gem::Version
|
247
|
-
version: 1.4.0
|
248
|
-
version:
|
249
|
-
- !ruby/object:Gem::Dependency
|
250
|
-
name: activerecord
|
251
|
-
version_requirement:
|
252
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
253
|
-
requirements:
|
254
|
-
- - ">="
|
255
|
-
- !ruby/object:Gem::Version
|
256
|
-
version: 1.15.3
|
257
|
-
version:
|
258
|
-
- !ruby/object:Gem::Dependency
|
259
|
-
name: simpleconsole
|
260
|
-
version_requirement:
|
261
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
262
|
-
requirements:
|
263
|
-
- - ">="
|
264
|
-
- !ruby/object:Gem::Version
|
265
|
-
version: 0.1.1
|
266
|
-
version:
|
267
|
-
- !ruby/object:Gem::Dependency
|
268
|
-
name: hoe
|
269
|
-
version_requirement:
|
270
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
271
|
-
requirements:
|
272
|
-
- - ">="
|
273
|
-
- !ruby/object:Gem::Version
|
274
|
-
version: 1.3.0
|
275
|
-
version:
|
287
|
+
rubyforge_project: rubysync
|
288
|
+
rubygems_version: 1.0.1
|
289
|
+
signing_key:
|
290
|
+
specification_version: 2
|
291
|
+
summary: Event driven identity synchronization engine
|
292
|
+
test_files: []
|
293
|
+
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,126 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# Copyright (c) 2007 Ritchie Young. All rights reserved.
|
4
|
-
#
|
5
|
-
# This file is part of RubySync.
|
6
|
-
#
|
7
|
-
# RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
|
8
|
-
# as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
11
|
-
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
12
|
-
#
|
13
|
-
# You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
|
14
|
-
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
15
|
-
|
16
|
-
|
17
|
-
lib_path = File.dirname(__FILE__) + '/..'
|
18
|
-
$:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
|
19
|
-
|
20
|
-
require 'ruby_sync'
|
21
|
-
require 'ldap_connector'
|
22
|
-
$VERBOSE = false
|
23
|
-
require 'net/ldap'
|
24
|
-
$VERBOSE = true
|
25
|
-
|
26
|
-
|
27
|
-
RUBYSYNC_ASSOCIATION_ATTRIBUTE = "RubySyncAssociation"
|
28
|
-
RUBYSYNC_ASSOCIATION_CLASS = "RubySyncSynchable"
|
29
|
-
|
30
|
-
|
31
|
-
module LdapAssociations
|
32
|
-
|
33
|
-
|
34
|
-
def associate association, path
|
35
|
-
with_ldap do |ldap|
|
36
|
-
# todo: check and warn if path is outside of search_base
|
37
|
-
ldap.modify :dn=>path, :operations=>[
|
38
|
-
[:add, RUBYSYNC_ASSOCIATION_ATTRIBUTE, association.to_s]
|
39
|
-
]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def path_for_association association
|
44
|
-
with_ldap do |ldap|
|
45
|
-
filter = "#{RUBYSYNC_ASSOCIATION_ATTRIBUTE}=#{association.to_s}"
|
46
|
-
log.debug "Searching with filter: #{filter}"
|
47
|
-
results = ldap.search :base=>@search_base,
|
48
|
-
:filter=>filter,
|
49
|
-
:attributes=>[]
|
50
|
-
results or return nil
|
51
|
-
case results.length
|
52
|
-
when 0: return nil
|
53
|
-
when 1: return results[0].dn
|
54
|
-
else
|
55
|
-
raise Exception.new("Duplicate association found for #{association.to_s}")
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def associations_for path
|
61
|
-
with_ldap do |ldap|
|
62
|
-
results = ldap.search :base=>path,
|
63
|
-
:scope=>Net::LDAP::SearchScope_BaseObject,
|
64
|
-
:attributes=>[RUBYSYNC_ASSOCIATION_ATTRIBUTE]
|
65
|
-
unless results and results.length > 0
|
66
|
-
log.warn "Attempted association lookup on non-existent LDAP entry '#{path}'"
|
67
|
-
return []
|
68
|
-
end
|
69
|
-
associations = results[0][RUBYSYNC_ASSOCIATION_ATTRIBUTE]
|
70
|
-
return (associations)? as_array(associations) : []
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def remove_association association
|
75
|
-
path = path_for_association association
|
76
|
-
with_ldap do |ldap|
|
77
|
-
ldap.modify :dn=>path, :modifications=>[
|
78
|
-
[:delete, RUBYSYNC_ASSOCIATION_ATTRIBUTE, association.to_s]
|
79
|
-
]
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
# def associate_with_foreign_key key, path
|
85
|
-
# with_ldap do |ldap|
|
86
|
-
# ldap.add_attribute(path, association_attribute, key.to_s)
|
87
|
-
# end
|
88
|
-
# end
|
89
|
-
#
|
90
|
-
# def path_for_foreign_key key
|
91
|
-
# entry = entry_for_foreign_key key
|
92
|
-
# (entry)? entry.dn : nil
|
93
|
-
# end
|
94
|
-
#
|
95
|
-
# def foreign_key_for path
|
96
|
-
# entry = self[path]
|
97
|
-
# (entry)? entry.dn : nil # TODO: That doesn't look right. Should return an association key, not a path.
|
98
|
-
# end
|
99
|
-
#
|
100
|
-
# def remove_foreign_key key
|
101
|
-
# with_ldap do |ldap|
|
102
|
-
# entry = entry_for_foreign_key key
|
103
|
-
# if entry
|
104
|
-
# modify :dn=>entry.dn, :operations=>[ [:delete, association_attribute, key] ]
|
105
|
-
# end
|
106
|
-
# end
|
107
|
-
# end
|
108
|
-
#
|
109
|
-
# def find_associated foreign_key
|
110
|
-
# entry = entry_for_foreign_key key
|
111
|
-
# (entry)? operations_for_entry(entry) : nil
|
112
|
-
# end
|
113
|
-
|
114
|
-
private
|
115
|
-
|
116
|
-
def entry_for_foreign_key key
|
117
|
-
with_ldap do |ldap|
|
118
|
-
result = ldap.search :base=>search_base, :filter=>"#{association_attribute}=#{key}"
|
119
|
-
return nil if !result or result.size == 0
|
120
|
-
result[0]
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
|