aerospike 0.1.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/lib/aerospike.rb +5 -0
  4. data/lib/aerospike/atomic/atomic.rb +3 -1
  5. data/lib/aerospike/client.rb +98 -32
  6. data/lib/aerospike/cluster/cluster.rb +25 -8
  7. data/lib/aerospike/cluster/connection.rb +1 -1
  8. data/lib/aerospike/cluster/node.rb +16 -3
  9. data/lib/aerospike/cluster/node_validator.rb +16 -4
  10. data/lib/aerospike/cluster/partition.rb +1 -1
  11. data/lib/aerospike/cluster/partition_tokenizer_new.rb +4 -2
  12. data/lib/aerospike/cluster/partition_tokenizer_old.rb +1 -1
  13. data/lib/aerospike/command/admin_command.rb +353 -0
  14. data/lib/aerospike/command/batch_command.rb +12 -42
  15. data/lib/aerospike/command/batch_command_exists.rb +1 -1
  16. data/lib/aerospike/command/batch_command_get.rb +1 -1
  17. data/lib/aerospike/command/batch_item.rb +1 -1
  18. data/lib/aerospike/command/batch_node.rb +1 -1
  19. data/lib/aerospike/command/command.rb +9 -14
  20. data/lib/aerospike/command/delete_command.rb +1 -1
  21. data/lib/aerospike/command/execute_command.rb +1 -1
  22. data/lib/aerospike/command/exists_command.rb +1 -1
  23. data/lib/aerospike/command/operate_command.rb +1 -1
  24. data/lib/aerospike/command/read_command.rb +12 -38
  25. data/lib/aerospike/command/read_header_command.rb +2 -2
  26. data/lib/aerospike/command/roles.rb +36 -0
  27. data/lib/aerospike/command/single_command.rb +1 -1
  28. data/lib/aerospike/command/touch_command.rb +1 -1
  29. data/lib/aerospike/command/write_command.rb +1 -1
  30. data/lib/aerospike/info.rb +1 -1
  31. data/lib/aerospike/loggable.rb +1 -1
  32. data/lib/aerospike/policy/admin_policy.rb +33 -0
  33. data/lib/aerospike/policy/batch_policy.rb +5 -5
  34. data/lib/aerospike/policy/client_policy.rb +15 -4
  35. data/lib/aerospike/policy/generation_policy.rb +0 -5
  36. data/lib/aerospike/policy/policy.rb +6 -6
  37. data/lib/aerospike/policy/query_policy.rb +2 -2
  38. data/lib/aerospike/policy/scan_policy.rb +6 -6
  39. data/lib/aerospike/policy/write_policy.rb +8 -8
  40. data/lib/aerospike/query/query_command.rb +1 -1
  41. data/lib/aerospike/query/scan_command.rb +1 -1
  42. data/lib/aerospike/query/stream_command.rb +1 -1
  43. data/lib/aerospike/record.rb +2 -3
  44. data/lib/aerospike/result_code.rb +11 -1
  45. data/lib/aerospike/user_role.rb +30 -0
  46. data/lib/aerospike/utils/buffer.rb +22 -2
  47. data/lib/aerospike/utils/epoc.rb +3 -1
  48. data/lib/aerospike/utils/pool.rb +1 -1
  49. data/lib/aerospike/value/value.rb +12 -13
  50. data/lib/aerospike/version.rb +1 -1
  51. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3befa3762779a41284c82d7d1c91071b2d808ba
4
- data.tar.gz: e68d7474c1cc4f87b2b4e1ae2dc1f9cf6ce5363b
3
+ metadata.gz: 60bb290526217118edd3256087baf8f3b1979229
4
+ data.tar.gz: 3298f8ddaa97c6d93294f8dfa1610f2b0770b7da
5
5
  SHA512:
6
- metadata.gz: 0670ec0132babe9a91821511c0303c866dd058d35c9e7e6dada688c20ce3d85ae44af4d29734200f8879d95530d94e8d2feff203ddce8f45f034ece463457d0f
7
- data.tar.gz: 6a7ec991acdee8ae19227a33ec72f73bf11a845533032e9555cd3538c362f2398c4e09c2ff0ad5fe55cb60bfcdcbc33a3ace4ab72c93e7c43464f42174772d48
6
+ metadata.gz: 8f0cbc5177d8c217583531fc0408ba07f99d379a66f21e8f723326b06d99aa48d2ab315a636f7fa1ec3497fd52b8aec677b43a195420b289fd091815e80f8a50
7
+ data.tar.gz: 2900d08848a56766a865080a07ad09df17f23f14374eea6a92f873baddb1ee9d172b737f87934f75cfde425822a9f1d0923abc5bb7252d0252df613563a57c36
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## Jan 26 2014 (1.0.0)
2
+
3
+ Major release. With this release, Ruby client graduates to version 1.
4
+
5
+ * **Breaking Changes**:
6
+
7
+ * All `policy` initialize signatures have changed. Using policies was not documented, so it shouldn't affect most code. It will however, break any code initializing policies.
8
+ * Removed `Record.dups` and `GenerationPolicy::DUPLICATE`
9
+
10
+ * **New Features**:
11
+
12
+ * Added Security Features: Please consult [Security Docs](https://www.aerospike.com/docs/guide/security.html) on Aerospike website.
13
+
14
+ * `ClientPolicy.User`, `ClientPolicy.Password`
15
+ * `Client.CreateUser()`, `Client.DropUser()`, `Client.ChangePassword()`
16
+ * `Client.GrantRoles()`, `Client.RevokeRoles()`, `Client.ReplaceRoles()`
17
+ * `Client.QueryUser()`, `Client.QueryUsers`
18
+
19
+ * **Fixes**:
20
+
21
+ * fixed size returned from `BytesValue.write`
22
+
1
23
  ## Dec 28 2014 (0.1.6)
2
24
 
3
25
  Minor features added, minor fixes and improvements.
data/lib/aerospike.rb CHANGED
@@ -5,6 +5,7 @@ require "monitor"
5
5
  require "timeout"
6
6
  require 'resolv'
7
7
  require 'msgpack'
8
+ require 'bcrypt'
8
9
 
9
10
  require 'aerospike/atomic/atomic'
10
11
 
@@ -35,6 +36,7 @@ require 'aerospike/command/touch_command'
35
36
  require 'aerospike/command/batch_command_exists'
36
37
  require 'aerospike/command/read_command'
37
38
  require 'aerospike/command/delete_command'
39
+ require 'aerospike/command/admin_command'
38
40
  require 'aerospike/key'
39
41
  require 'aerospike/operation'
40
42
 
@@ -48,6 +50,7 @@ require 'aerospike/policy/scan_policy'
48
50
  require 'aerospike/policy/query_policy'
49
51
  require 'aerospike/policy/consistency_level'
50
52
  require 'aerospike/policy/commit_level'
53
+ require 'aerospike/policy/admin_policy'
51
54
 
52
55
  require 'aerospike/cluster/connection'
53
56
  require 'aerospike/cluster/cluster'
@@ -65,6 +68,8 @@ require 'aerospike/info'
65
68
  require 'aerospike/udf'
66
69
  require 'aerospike/bin'
67
70
  require 'aerospike/aerospike_exception'
71
+ require 'aerospike/user_role'
72
+
68
73
  require 'aerospike/task/index_task'
69
74
  require 'aerospike/task/udf_remove_task'
70
75
  require 'aerospike/task/udf_register_task'
@@ -15,8 +15,10 @@
15
15
 
16
16
  module Aerospike
17
17
 
18
+ private
19
+
18
20
  # Container object for client policy command.
19
- class Atomic
21
+ class Atomic # :nodoc:
20
22
 
21
23
  def initialize(value)
22
24
  @value = value
@@ -36,13 +36,15 @@ module Aerospike
36
36
 
37
37
  class Client
38
38
 
39
- attr_accessor :default_policy, :default_write_policy
39
+ attr_accessor :default_policy, :default_write_policy,
40
+ :default_scan_policy, :default_query_policy, :default_admin_policy
40
41
 
41
42
  def initialize(host, port, options={})
42
43
  @default_policy = Policy.new
43
44
  @default_write_policy = WritePolicy.new
44
45
  @default_scan_policy = ScanPolicy.new
45
46
  @default_query_policy = QueryPolicy.new
47
+ @default_admin_policy = QueryPolicy.new
46
48
 
47
49
  policy = opt_to_client_policy(options)
48
50
 
@@ -594,7 +596,7 @@ module Aerospike
594
596
  begin
595
597
  command.execute
596
598
  rescue => e
597
- Aerospike.logger.error(e) unless e == Rescordset::SCAN_TERMINATED_EXCEPTION
599
+ Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
598
600
  recordset.cancel(e)
599
601
  ensure
600
602
  recordset.thread_finished
@@ -609,7 +611,7 @@ module Aerospike
609
611
  begin
610
612
  command.execute
611
613
  rescue => e
612
- Aerospike.logger.error(e) unless e == Rescordset::SCAN_TERMINATED_EXCEPTION
614
+ Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
613
615
  recordset.cancel(e)
614
616
  ensure
615
617
  recordset.thread_finished
@@ -644,7 +646,7 @@ module Aerospike
644
646
  begin
645
647
  command.execute
646
648
  rescue => e
647
- Aerospike.logger.error(e) unless e == Rescordset::SCAN_TERMINATED_EXCEPTION
649
+ Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
648
650
  recordset.cancel(e)
649
651
  ensure
650
652
  recordset.thread_finished
@@ -684,7 +686,7 @@ module Aerospike
684
686
  begin
685
687
  command.execute
686
688
  rescue => e
687
- Aerospike.logger.error(e) unless e == Rescordset::QUERY_TERMINATED_EXCEPTION
689
+ Aerospike.logger.error(e.backtrace.join("\n")) unless e == QUERY_TERMINATED_EXCEPTION
688
690
  recordset.cancel(e)
689
691
  ensure
690
692
  recordset.thread_finished
@@ -695,6 +697,82 @@ module Aerospike
695
697
  recordset
696
698
  end
697
699
 
700
+ #-------------------------------------------------------
701
+ # User administration
702
+ #-------------------------------------------------------
703
+
704
+ # Create user with password and roles. Clear-text password will be hashed using bcrypt
705
+ # before sending to server.
706
+ def create_user(user, password, roles, options={})
707
+ policy = opt_to_admin_policy(options)
708
+ hash = AdminCommand.hash_password(password)
709
+ command = AdminCommand.new
710
+ command.create_user(@cluster, policy, user, hash, roles)
711
+ end
712
+
713
+ # Remove user from cluster.
714
+ def drop_user(user, options={})
715
+ policy = opt_to_admin_policy(options)
716
+ command = AdminCommand.new
717
+ command.drop_user(@cluster, policy, user)
718
+ end
719
+
720
+ # Change user's password. Clear-text password will be hashed using bcrypt before sending to server.
721
+ def change_password(user, password, options={})
722
+ policy = opt_to_admin_policy(options)
723
+ if @cluster.user == ''
724
+ return NewAerospikeError(INVALID_USER)
725
+ end
726
+
727
+ hash = AdminCommand.hash_password(password)
728
+ command = AdminCommand.new
729
+
730
+ if user == @cluster.user
731
+ # Change own password.
732
+ command.change_password(@cluster, policy, user, hash)
733
+ else
734
+ # Change other user's password by user admin.
735
+ command.set_password(@cluster, policy, user, hash)
736
+ end
737
+
738
+ @cluster.change_password(user, hash)
739
+ end
740
+
741
+ # Add roles to user's list of roles.
742
+ def grant_roles(user, roles, options={})
743
+ policy = opt_to_admin_policy(options)
744
+ command = AdminCommand.new
745
+ command.grant_roles(@cluster, policy, user, roles)
746
+ end
747
+
748
+ # Remove roles from user's list of roles.
749
+ def revoke_roles(user, roles, options={})
750
+ policy = opt_to_admin_policy(options)
751
+ command = AdminCommand.new
752
+ command.revoke_roles(@cluster, policy, user, roles)
753
+ end
754
+
755
+ # Replace user's list of roles.
756
+ def replace_roles(user, roles, options={})
757
+ policy = opt_to_admin_policy(options)
758
+ command = AdminCommand.new
759
+ command.replace_roles(@cluster, policy, user, roles)
760
+ end
761
+
762
+ # Retrieve roles for a given user.
763
+ def query_user(user, options={})
764
+ policy = opt_to_admin_policy(options)
765
+ command = AdminCommand.new
766
+ command.query_user(@cluster, policy, user)
767
+ end
768
+
769
+ # Retrieve all users and their roles.
770
+ def query_users(options={})
771
+ policy = opt_to_admin_policy(options)
772
+ command = AdminCommand.new
773
+ command.query_users(@cluster, policy)
774
+ end
775
+
698
776
  private
699
777
 
700
778
  def send_info_command(policy, command)
@@ -720,11 +798,7 @@ module Aerospike
720
798
  elsif options.is_a?(ClientPolicy)
721
799
  options
722
800
  elsif options.is_a?(Hash)
723
- ClientPolicy.new(
724
- options[:timeout],
725
- options[:connection_queue_size],
726
- options[:fail_if_not_connected]
727
- )
801
+ ClientPolicy.new(options)
728
802
  end
729
803
  end
730
804
 
@@ -734,13 +808,7 @@ module Aerospike
734
808
  elsif options.is_a?(Policy)
735
809
  options
736
810
  elsif options.is_a?(Hash)
737
- Policy.new(
738
- options[:priority],
739
- options[:timeout],
740
- options[:max_retiries],
741
- options[:sleep_between_retries],
742
- options[:consistency_level]
743
- )
811
+ Policy.new(options)
744
812
  end
745
813
  end
746
814
 
@@ -750,14 +818,7 @@ module Aerospike
750
818
  elsif options.is_a?(WritePolicy)
751
819
  options
752
820
  elsif options.is_a?(Hash)
753
- WritePolicy.new(
754
- options[:record_exists_action],
755
- options[:gen_policy],
756
- options[:generation],
757
- options[:expiration],
758
- options[:send_key],
759
- options[:commit_level]
760
- )
821
+ WritePolicy.new(options)
761
822
  end
762
823
  end
763
824
 
@@ -767,12 +828,7 @@ module Aerospike
767
828
  elsif options.is_a?(ScanPolicy)
768
829
  options
769
830
  elsif options.is_a?(Hash)
770
- ScanPolicy.new(
771
- options[:scan_percent],
772
- options[:concurrent_nodes],
773
- options[:include_bin_data],
774
- options[:fail_on_cluster_change]
775
- )
831
+ ScanPolicy.new(options)
776
832
  end
777
833
  end
778
834
 
@@ -782,7 +838,17 @@ module Aerospike
782
838
  elsif options.is_a?(QueryPolicy)
783
839
  options
784
840
  elsif options.is_a?(Hash)
785
- QueryPolicy.new()
841
+ QueryPolicy.new(options)
842
+ end
843
+ end
844
+
845
+ def opt_to_admin_policy(options)
846
+ if options.nil? || options == {}
847
+ @default_admin_policy
848
+ elsif options.is_a?(AdminPolicy)
849
+ options
850
+ elsif options.is_a?(Hash)
851
+ AdminPolicy.new(options)
786
852
  end
787
853
  end
788
854
 
@@ -25,7 +25,7 @@ module Aerospike
25
25
 
26
26
  class Cluster
27
27
 
28
- attr_reader :connection_timeout, :connection_queue_size
28
+ attr_reader :connection_timeout, :connection_queue_size, :user, :password
29
29
 
30
30
  def initialize(policy, *hosts)
31
31
  @cluster_seeds = hosts
@@ -38,6 +38,12 @@ module Aerospike
38
38
  @closed = Atomic.new(false)
39
39
  @mutex = Mutex.new
40
40
 
41
+ # setup auth info for cluster
42
+ if policy.requires_authentication
43
+ @user = policy.user
44
+ @password = AdminCommand.hash_password(policy.password)
45
+ end
46
+
41
47
  wait_till_stablized
42
48
 
43
49
  if policy.fail_if_not_connected && !connected?
@@ -88,7 +94,8 @@ module Aerospike
88
94
  # Must copy array reference for copy on write semantics to work.
89
95
  node_array = nodes
90
96
  length = node_array.length
91
- for i in 0..length
97
+ i = 0
98
+ while i < length
92
99
  # Must handle concurrency with other non-tending threads, so node_index is consistent.
93
100
  index = (@node_index.update{|v| v+1} % node_array.length).abs
94
101
  node = node_array[index]
@@ -96,6 +103,8 @@ module Aerospike
96
103
  if node.active?
97
104
  return node
98
105
  end
106
+
107
+ i = i.succ
99
108
  end
100
109
  raise Aerospike::Exceptions::InvalidNode.new
101
110
  end
@@ -166,6 +175,11 @@ module Aerospike
166
175
  end
167
176
  end
168
177
 
178
+ def change_password(user, password)
179
+ # change password ONLY if the user is the same
180
+ @password = password if @user == user
181
+ end
182
+
169
183
  private
170
184
 
171
185
  def launch_tend_thread
@@ -210,7 +224,7 @@ module Aerospike
210
224
  refresh_count += 1
211
225
  friend_list.concat(friends) if friends
212
226
  rescue => e
213
- Aerospike.logger.error("Node `#{node}` refresh failed: #{e.to_s}")
227
+ Aerospike.logger.error("Node `#{node}` refresh failed: #{e.backtrace.join("\n")}")
214
228
  end
215
229
  end
216
230
  end
@@ -283,9 +297,9 @@ module Aerospike
283
297
 
284
298
  seed_array.each do |seed|
285
299
  begin
286
- seed_node_validator = NodeValidator.new(seed, @connection_timeout)
300
+ seed_node_validator = NodeValidator.new(self, seed, @connection_timeout)
287
301
  rescue => e
288
- Aerospike.logger.error("Seed #{seed.to_s} failed: #{e}")
302
+ Aerospike.logger.error("Seed #{seed.to_s} failed: #{e.backtrace.join("\n")}")
289
303
  next
290
304
  end
291
305
 
@@ -297,7 +311,7 @@ module Aerospike
297
311
  nv = seed_node_validator
298
312
  else
299
313
  begin
300
- nv = NodeValidator.new(aliass, @connection_timeout)
314
+ nv = NodeValidator.new(self, aliass, @connection_timeout)
301
315
  rescue Exection => e
302
316
  Aerospike.logger.error("Seed #{seed.to_s} failed: #{e}")
303
317
  next
@@ -345,7 +359,7 @@ module Aerospike
345
359
 
346
360
  hosts.each do |host|
347
361
  begin
348
- nv = NodeValidator.new(host, @connection_timeout)
362
+ nv = NodeValidator.new(self, host, @connection_timeout)
349
363
 
350
364
  # if node is already in cluster's node list,
351
365
  # or already included in the list to be added, we should skip it
@@ -432,12 +446,15 @@ module Aerospike
432
446
  partitions_list.each do |node_array|
433
447
  max = node_array.length
434
448
 
435
- for i in 0...max
449
+ i = 0
450
+ while i < max
436
451
  node = node_array[i]
437
452
  # Use reference equality for performance.
438
453
  if node == filter
439
454
  return true
440
455
  end
456
+
457
+ i = i.succ
441
458
  end
442
459
  end
443
460
  false
@@ -20,7 +20,7 @@ module Aerospike
20
20
 
21
21
  private
22
22
 
23
- class Connection
23
+ class Connection # :nodoc:
24
24
 
25
25
  def initialize(host, port, timeout = 30)
26
26
 
@@ -47,12 +47,25 @@ module Aerospike
47
47
  @connections = Pool.new(@cluster.connection_queue_size)
48
48
  @connections.create_block = Proc.new do
49
49
  while conn = Connection.new(@host.name, @host.port, @cluster.connection_timeout)
50
+
51
+ # need to authenticate
52
+ if @cluster.user && @cluster.user != ''
53
+ begin
54
+ command = AdminCommand.new
55
+ command.authenticate(conn, @cluster.user, @cluster.password)
56
+ rescue => e
57
+ # Socket not authenticated. Do not put back into pool.
58
+ conn.close if conn
59
+ raise e
60
+ end
61
+ end
62
+
50
63
  break if conn.connected?
51
64
  end
52
65
  conn
53
66
  end
54
67
 
55
- @connections.cleanup_block = Proc.new { |conn| conn.close }
68
+ @connections.cleanup_block = Proc.new { |conn| conn.close if conn }
56
69
  end
57
70
 
58
71
  # Request current status from server node, and update node with the result
@@ -65,7 +78,7 @@ module Aerospike
65
78
  rescue => e
66
79
  Aerospike.logger.error(e)
67
80
 
68
- conn.close
81
+ conn.close if conn
69
82
  decrease_health
70
83
 
71
84
  raise e
@@ -179,7 +192,7 @@ module Aerospike
179
192
  # drain connections and close all of them
180
193
  # non-blocking, does not call create_block when passed false
181
194
  while conn = @connections.poll(false)
182
- conn.close
195
+ conn.close if conn
183
196
  end
184
197
  end
185
198