dse-driver 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.yardopts +13 -0
- data/README.md +72 -0
- data/ext/gss_api_context/extconf.rb +27 -0
- data/ext/gss_api_context/gss_api_context.c +129 -0
- data/ext/gss_api_context/kerberosgss.c +407 -0
- data/ext/gss_api_context/kerberosgss.h +71 -0
- data/lib/dse.rb +104 -0
- data/lib/dse/auth/providers/gss_api.rb +160 -0
- data/lib/dse/auth/providers/password.rb +56 -0
- data/lib/dse/cluster.rb +99 -0
- data/lib/dse/geometry/line_string.rb +181 -0
- data/lib/dse/geometry/point.rb +179 -0
- data/lib/dse/geometry/polygon.rb +196 -0
- data/lib/dse/graph.rb +18 -0
- data/lib/dse/graph/duration.rb +131 -0
- data/lib/dse/graph/edge.rb +74 -0
- data/lib/dse/graph/options.rb +194 -0
- data/lib/dse/graph/path.rb +54 -0
- data/lib/dse/graph/result.rb +85 -0
- data/lib/dse/graph/result_set.rb +77 -0
- data/lib/dse/graph/statement.rb +118 -0
- data/lib/dse/graph/vertex.rb +107 -0
- data/lib/dse/graph/vertex_property.rb +66 -0
- data/lib/dse/load_balancing/policies/host_targeting.rb +102 -0
- data/lib/dse/session.rb +106 -0
- data/lib/dse/statements.rb +15 -0
- data/lib/dse/statements/host_targeting.rb +50 -0
- data/lib/dse/util.rb +12 -0
- data/lib/dse/util/endian_buffer.rb +37 -0
- data/lib/dse/version.rb +12 -0
- metadata +123 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2006-2016 Apple Inc. All rights reserved.
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
**/
|
16
|
+
|
17
|
+
#include <gssapi/gssapi.h>
|
18
|
+
#include <gssapi/gssapi_generic.h>
|
19
|
+
#include <gssapi/gssapi_krb5.h>
|
20
|
+
|
21
|
+
#define krb5_get_err_text(context,code) error_message(code)
|
22
|
+
|
23
|
+
#define AUTH_GSS_ERROR -1
|
24
|
+
#define AUTH_GSS_COMPLETE 1
|
25
|
+
#define AUTH_GSS_CONTINUE 0
|
26
|
+
|
27
|
+
#define GSS_AUTH_P_NONE 1
|
28
|
+
#define GSS_AUTH_P_INTEGRITY 2
|
29
|
+
#define GSS_AUTH_P_PRIVACY 4
|
30
|
+
|
31
|
+
typedef struct {
|
32
|
+
gss_ctx_id_t context;
|
33
|
+
gss_name_t server_name;
|
34
|
+
gss_OID mech_oid;
|
35
|
+
long int gss_flags;
|
36
|
+
gss_cred_id_t client_creds;
|
37
|
+
char* username;
|
38
|
+
char* response;
|
39
|
+
int responseLen;
|
40
|
+
int responseConf;
|
41
|
+
} gss_client_state;
|
42
|
+
|
43
|
+
typedef struct {
|
44
|
+
gss_ctx_id_t context;
|
45
|
+
gss_name_t server_name;
|
46
|
+
gss_name_t client_name;
|
47
|
+
gss_cred_id_t server_creds;
|
48
|
+
gss_cred_id_t client_creds;
|
49
|
+
char* username;
|
50
|
+
char* targetname;
|
51
|
+
char* response;
|
52
|
+
char* ccname;
|
53
|
+
} gss_server_state;
|
54
|
+
|
55
|
+
void authenticate_gss_client_init(
|
56
|
+
const char* service, const char* principal, const char* ticket_cache, long int gss_flags,
|
57
|
+
gss_server_state* delegatestate, gss_OID mech_oid, gss_client_state* state
|
58
|
+
);
|
59
|
+
int authenticate_gss_client_clean(
|
60
|
+
gss_client_state *state
|
61
|
+
);
|
62
|
+
int authenticate_gss_client_step(
|
63
|
+
gss_client_state *state, const char *challenge, int challenge_len
|
64
|
+
);
|
65
|
+
int authenticate_gss_client_unwrap(
|
66
|
+
gss_client_state* state, const char* challenge, int challenge_len
|
67
|
+
);
|
68
|
+
int authenticate_gss_client_wrap(
|
69
|
+
gss_client_state* state, const char* challenge, int challenge_len
|
70
|
+
);
|
71
|
+
void clear_response(gss_client_state* state);
|
data/lib/dse.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2016 DataStax Inc.
|
5
|
+
#
|
6
|
+
# This software can be used solely with DataStax Enterprise. Please consult the license at
|
7
|
+
# http://www.datastax.com/terms/datastax-dse-driver-license-terms
|
8
|
+
#++
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
if RUBY_ENGINE == 'jruby'
|
13
|
+
require 'challenge_evaluator'
|
14
|
+
else
|
15
|
+
require 'gss_api_context'
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'cassandra'
|
19
|
+
|
20
|
+
module Dse
|
21
|
+
# Creates a {Dse::Cluster Cluster instance}, which extends {http://dsdocs30/api/cassandra/cluster Cassandra::Cluster}.
|
22
|
+
# The API is identical, except that it returns a {Dse::Session Dse::Session} (see below). It takes all of the same
|
23
|
+
# options as Cassandra.cluster and the following extra options.
|
24
|
+
#
|
25
|
+
# @option options [Dse::Graph::Options] :graph_options options for the DSE graph statement handler. Takes
|
26
|
+
# priority over other `:graph_*` options specified below.
|
27
|
+
# @option options [String] :graph_name name of graph to use in graph statements
|
28
|
+
# @option options [String] :graph_source graph traversal source
|
29
|
+
# @option options [String] :graph_language language used in graph queries
|
30
|
+
# @option options [Cassandra::CONSISTENCIES] :graph_read_consistency read consistency level for graph statements.
|
31
|
+
# Overrides the standard statement consistency level
|
32
|
+
# @option options [Cassandra::CONSISTENCIES] :graph_write_consistency write consistency level for graph statements.
|
33
|
+
# Overrides the standard statement consistency level
|
34
|
+
#
|
35
|
+
# @example Connecting to localhost
|
36
|
+
# cluster = Dse.cluster
|
37
|
+
#
|
38
|
+
# @example Configuring {Dse::Cluster}
|
39
|
+
# cluster = Dse.cluster(
|
40
|
+
# username: username,
|
41
|
+
# password: password,
|
42
|
+
# hosts: ['10.0.1.1', '10.0.1.2', '10.0.1.3']
|
43
|
+
# )
|
44
|
+
#
|
45
|
+
# @return [Dse::Cluster] a cluster instance
|
46
|
+
def self.cluster(options = {})
|
47
|
+
cluster_async(options).get
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates a {Dse::Cluster Cluster instance}.
|
51
|
+
#
|
52
|
+
# @see Dse.cluster
|
53
|
+
#
|
54
|
+
# @return [Cassandra::Future<Dse::Cluster>] a future resolving to the
|
55
|
+
# cluster instance.
|
56
|
+
def self.cluster_async(options = {})
|
57
|
+
graph_options = if !options[:graph_options].nil?
|
58
|
+
Cassandra::Util.assert_instance_of(Dse::Graph::Options, options[:graph_options])
|
59
|
+
options[:graph_options]
|
60
|
+
else
|
61
|
+
Dse::Graph::Options.new(options)
|
62
|
+
end
|
63
|
+
username = options[:username]
|
64
|
+
password = options[:password]
|
65
|
+
options[:custom_types] ||= []
|
66
|
+
options[:custom_types] << Dse::Geometry::Point << Dse::Geometry::LineString << Dse::Geometry::Polygon
|
67
|
+
options, hosts = Cassandra.validate_and_massage_options(options)
|
68
|
+
|
69
|
+
# Use the DSE plain text authenticator if we have a username and password. The above validation already
|
70
|
+
# raises an error if one is given without the other.
|
71
|
+
options[:auth_provider] = Auth::Providers::Password.new(username, password) if username && password
|
72
|
+
rescue => e
|
73
|
+
futures = options.fetch(:futures_factory) { return Cassandra::Future::Error.new(e) }
|
74
|
+
futures.error(e)
|
75
|
+
else
|
76
|
+
options[:cluster_klass] = Dse::Cluster
|
77
|
+
driver = ::Cassandra::Driver.new(options)
|
78
|
+
|
79
|
+
# Wrap the load-balancing policy that we'd otherwise run with, with a host-targeting policy.
|
80
|
+
# We do this before driver.connect because driver.connect saves off the policy in the cluster
|
81
|
+
# registry and does a few other things.
|
82
|
+
|
83
|
+
lbp = driver.load_balancing_policy
|
84
|
+
driver.load_balancing_policy = Dse::LoadBalancing::Policies::HostTargeting.new(lbp)
|
85
|
+
future = driver.connect(hosts)
|
86
|
+
future.then do |cluster|
|
87
|
+
cluster.graph_options.merge!(graph_options)
|
88
|
+
cluster
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
require 'dse/cluster'
|
94
|
+
require 'dse/util/endian_buffer'
|
95
|
+
require 'dse/geometry/line_string'
|
96
|
+
require 'dse/geometry/point'
|
97
|
+
require 'dse/geometry/polygon'
|
98
|
+
require 'dse/session'
|
99
|
+
require 'dse/version'
|
100
|
+
require 'dse/graph'
|
101
|
+
require 'dse/load_balancing/policies/host_targeting'
|
102
|
+
require 'dse/statements'
|
103
|
+
require 'dse/auth/providers/gss_api'
|
104
|
+
require 'dse/auth/providers/password'
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2016 DataStax Inc.
|
5
|
+
#
|
6
|
+
# This software can be used solely with DataStax Enterprise. Please consult the license at
|
7
|
+
# http://www.datastax.com/terms/datastax-dse-driver-license-terms
|
8
|
+
#++
|
9
|
+
|
10
|
+
module Dse
|
11
|
+
module Auth
|
12
|
+
module Providers
|
13
|
+
# Auth provider to authenticate with Kerberos. Whenever the client connects to a DSE node,
|
14
|
+
# this provider will perform Kerberos authentication operations with it. By default, the provider
|
15
|
+
# takes the ip address of the node and uses `Socket#getnameinfo` to find its name in order to construct
|
16
|
+
# the full service address (e.g. service@host).
|
17
|
+
#
|
18
|
+
# @see #initialize
|
19
|
+
class GssApi < Cassandra::Auth::Provider
|
20
|
+
# @private
|
21
|
+
class NameInfoResolver
|
22
|
+
def resolve(host)
|
23
|
+
Socket.getnameinfo(['AF_INET', 0, host])[0]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @private
|
28
|
+
class NoOpResolver
|
29
|
+
def resolve(host)
|
30
|
+
host
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @private
|
35
|
+
class Authenticator
|
36
|
+
# Copied from kerberosgss.h
|
37
|
+
AUTH_GSS_COMPLETE = 1
|
38
|
+
|
39
|
+
def initialize(authentication_class, host, service, principal, ticket_cache)
|
40
|
+
@authentication_class = authentication_class
|
41
|
+
@host = host
|
42
|
+
@service = service
|
43
|
+
@principal = principal
|
44
|
+
@ticket_cache = ticket_cache
|
45
|
+
|
46
|
+
if RUBY_ENGINE == 'jruby'
|
47
|
+
@sasl_client = javax.security.sasl.Sasl.createSaslClient(['GSSAPI'],
|
48
|
+
nil,
|
49
|
+
service,
|
50
|
+
host,
|
51
|
+
{javax.security.sasl.Sasl::SERVER_AUTH => 'true',
|
52
|
+
javax.security.sasl.Sasl::QOP => 'auth'},
|
53
|
+
nil)
|
54
|
+
config = Dse::Auth::Providers::ChallengeEvaluator.make_configuration(principal, ticket_cache)
|
55
|
+
login = javax.security.auth.login.LoginContext.new('DseClient', nil, nil, config)
|
56
|
+
login.login
|
57
|
+
@subject = login.getSubject
|
58
|
+
else
|
59
|
+
@gss_context = GssApiContext.new("#{@service}@#{@host}", @principal, @ticket_cache)
|
60
|
+
end
|
61
|
+
rescue => e
|
62
|
+
raise Cassandra::Errors::AuthenticationError.new(
|
63
|
+
"Failed to authenticate: #{e.message}",
|
64
|
+
nil,
|
65
|
+
nil,
|
66
|
+
nil,
|
67
|
+
nil,
|
68
|
+
nil,
|
69
|
+
nil,
|
70
|
+
:one,
|
71
|
+
0
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def initial_response
|
76
|
+
@authentication_class == 'com.datastax.bdp.cassandra.auth.DseAuthenticator' ?
|
77
|
+
'GSSAPI' :
|
78
|
+
challenge_response('GSSAPI-START')
|
79
|
+
end
|
80
|
+
|
81
|
+
if RUBY_ENGINE == 'jruby'
|
82
|
+
def challenge_response(token)
|
83
|
+
if token == 'GSSAPI-START'
|
84
|
+
return '' unless @sasl_client.hasInitialResponse
|
85
|
+
token = ''
|
86
|
+
end
|
87
|
+
|
88
|
+
Dse::Auth::Providers::ChallengeEvaluator.evaluate(@sasl_client, @subject, token)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
def challenge_response(token)
|
92
|
+
if token == 'GSSAPI-START'
|
93
|
+
response = @gss_context.step('')[1]
|
94
|
+
elsif !@is_gss_complete
|
95
|
+
# Process the challenge as a next step in authentication until we have gotten
|
96
|
+
# AUTH_GSS_COMPLETE.
|
97
|
+
rc, response = @gss_context.step(token)
|
98
|
+
@is_gss_complete = true if rc == AUTH_GSS_COMPLETE
|
99
|
+
response ||= ''
|
100
|
+
else
|
101
|
+
# Ok, we went through all initial phases of auth and now the server is giving us a message
|
102
|
+
# to decode.
|
103
|
+
data = @gss_context.unwrap(token)
|
104
|
+
|
105
|
+
raise 'Bad response from server' if data.length != 4
|
106
|
+
parsed = data.unpack('>L').first
|
107
|
+
max_length = [parsed & 0xffffff, 65536].min
|
108
|
+
|
109
|
+
# Set up a response like this:
|
110
|
+
# byte 0: the selected qop. 1==auth
|
111
|
+
# byte 1-3: the max length for any buffer sent back and forth on this connection. (big endian)
|
112
|
+
# the rest of the buffer: the authorization user name in UTF-8 - not null terminated.
|
113
|
+
|
114
|
+
user_name = @gss_context.user_name
|
115
|
+
out = [max_length | 1 << 24].pack('>L') + user_name
|
116
|
+
response = @gss_context.wrap(out)
|
117
|
+
end
|
118
|
+
response
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def authentication_successful(token)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @param service [String] name of the kerberos service; defaults to 'dse'.
|
127
|
+
# @param host_resolver [Boolean, Object] whether to use a host-resolver. By default,
|
128
|
+
# `Socket#getnameinfo` is used. To disable host-resolution, specify a `false` value. You may also
|
129
|
+
# provide a custom resolver, which is an object that implements the `resolve(host_ip)` method.
|
130
|
+
# @param principal [String] The principal whose cached credentials are used to authenticate. Defaults
|
131
|
+
# to the first principal stored in the ticket cache.
|
132
|
+
# @param ticket_cache [String] The ticket cache containing the cached credential we seek. Defaults
|
133
|
+
# *on Linux* to /tmp/krb5cc_<uid> (where uid is the numeric uid of the user running the
|
134
|
+
# client program). In MRI only, the `KRB5CCNAME` environment variable supercedes this. On Mac,
|
135
|
+
# the default is a symbolic reference to a ticket-cache server process.
|
136
|
+
def initialize(service = 'dse', host_resolver = true, principal = nil, ticket_cache = nil)
|
137
|
+
@service = service
|
138
|
+
@host_resolver = case host_resolver
|
139
|
+
when false
|
140
|
+
NoOpResolver.new
|
141
|
+
when true
|
142
|
+
NameInfoResolver.new
|
143
|
+
else
|
144
|
+
host_resolver
|
145
|
+
end
|
146
|
+
Cassandra::Util.assert_responds_to(:resolve, @host_resolver,
|
147
|
+
'invalid host_resolver: it must have the :resolve method')
|
148
|
+
@principal = principal
|
149
|
+
@ticket_cache = ticket_cache
|
150
|
+
end
|
151
|
+
|
152
|
+
# @private
|
153
|
+
def create_authenticator(authentication_class, host)
|
154
|
+
Authenticator.new(authentication_class, @host_resolver.resolve(host.ip.to_s),
|
155
|
+
@service, @principal, @ticket_cache)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2016 DataStax Inc.
|
5
|
+
#
|
6
|
+
# This software can be used solely with DataStax Enterprise. Please consult the license at
|
7
|
+
# http://www.datastax.com/terms/datastax-dse-driver-license-terms
|
8
|
+
#++
|
9
|
+
|
10
|
+
module Dse
|
11
|
+
module Auth
|
12
|
+
module Providers
|
13
|
+
# Auth provider to authenticate with username/password for DSE's built-in authentication as well as LDAP.
|
14
|
+
#
|
15
|
+
# @note No need to instantiate this class manually, use `:username` and
|
16
|
+
# `:password` options when calling {Dse.cluster} and one will be
|
17
|
+
# created automatically for you.
|
18
|
+
|
19
|
+
class Password < Cassandra::Auth::Provider
|
20
|
+
# @private
|
21
|
+
class Authenticator
|
22
|
+
def initialize(authentication_class, username, password)
|
23
|
+
@authentication_class = authentication_class
|
24
|
+
@username = username
|
25
|
+
@password = password
|
26
|
+
end
|
27
|
+
|
28
|
+
def initial_response
|
29
|
+
@authentication_class == 'com.datastax.bdp.cassandra.auth.DseAuthenticator' ?
|
30
|
+
'PLAIN' :
|
31
|
+
challenge_response('PLAIN-START')
|
32
|
+
end
|
33
|
+
|
34
|
+
def challenge_response(token)
|
35
|
+
"\x00#{@username}\x00#{@password}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def authentication_successful(token)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param username [String] username to use for authentication to Cassandra
|
43
|
+
# @param password [String] password to use for authentication to Cassandra
|
44
|
+
def initialize(username, password)
|
45
|
+
@username = username
|
46
|
+
@password = password
|
47
|
+
end
|
48
|
+
|
49
|
+
# @private
|
50
|
+
def create_authenticator(authentication_class, host)
|
51
|
+
Authenticator.new(authentication_class, @username, @password)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/dse/cluster.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2016 DataStax Inc.
|
5
|
+
#
|
6
|
+
# This software can be used solely with DataStax Enterprise. Please consult the license at
|
7
|
+
# http://www.datastax.com/terms/datastax-dse-driver-license-terms
|
8
|
+
#++
|
9
|
+
|
10
|
+
module Dse
|
11
|
+
# Cluster represents a DSE cluster. It serves as a {Dse::Session session factory} and a collection of metadata.
|
12
|
+
# It wraps a {http://dsdocs30/api/cassandra/cluster Cassandra::Cluster} and exposes all of its functionality.
|
13
|
+
class Cluster
|
14
|
+
# @return [Dse::Graph::Options] default graph options used by queries on this cluster.
|
15
|
+
attr_reader :graph_options
|
16
|
+
|
17
|
+
# @private
|
18
|
+
def initialize(logger,
|
19
|
+
io_reactor,
|
20
|
+
executor,
|
21
|
+
control_connection,
|
22
|
+
cluster_registry,
|
23
|
+
cluster_schema,
|
24
|
+
cluster_metadata,
|
25
|
+
execution_options,
|
26
|
+
connection_options,
|
27
|
+
load_balancing_policy,
|
28
|
+
reconnection_policy,
|
29
|
+
retry_policy,
|
30
|
+
address_resolution_policy,
|
31
|
+
connector,
|
32
|
+
futures_factory,
|
33
|
+
timestamp_generator)
|
34
|
+
@delegate_cluster = Cassandra::Cluster.new(logger,
|
35
|
+
io_reactor,
|
36
|
+
executor,
|
37
|
+
control_connection,
|
38
|
+
cluster_registry,
|
39
|
+
cluster_schema,
|
40
|
+
cluster_metadata,
|
41
|
+
execution_options,
|
42
|
+
connection_options,
|
43
|
+
load_balancing_policy,
|
44
|
+
reconnection_policy,
|
45
|
+
retry_policy,
|
46
|
+
address_resolution_policy,
|
47
|
+
connector,
|
48
|
+
futures_factory,
|
49
|
+
timestamp_generator)
|
50
|
+
@graph_options = Dse::Graph::Options.new
|
51
|
+
|
52
|
+
# We need the futures factory ourselves for async error reporting and potentially for our
|
53
|
+
# own async processing independent of the C* driver.
|
54
|
+
@futures = futures_factory
|
55
|
+
end
|
56
|
+
|
57
|
+
# Delegates to {http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/api/cassandra/cluster/?local=true&nav=toc#connect_async-instance_method
|
58
|
+
# Cassandra::Cluster#connect_async}
|
59
|
+
# to connect asynchronously to a cluster, but returns a future that will resolve to a DSE session rather than
|
60
|
+
# Cassandra session.
|
61
|
+
#
|
62
|
+
# @param keyspace [String] optional keyspace to scope session to
|
63
|
+
#
|
64
|
+
# @return [Cassandra::Future<Dse::Session>]
|
65
|
+
def connect_async(keyspace = nil)
|
66
|
+
future = @delegate_cluster.connect_async(keyspace)
|
67
|
+
# We want to actually return a DSE session upon successful connection.
|
68
|
+
future.then do |cassandra_session|
|
69
|
+
Dse::Session.new(cassandra_session, @graph_options, @futures)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Synchronous variant of {#connect_async}.
|
74
|
+
#
|
75
|
+
# @param keyspace [String] optional keyspace to scope the session to
|
76
|
+
#
|
77
|
+
# @return [Dse::Session]
|
78
|
+
def connect(keyspace = nil)
|
79
|
+
connect_async(keyspace).get
|
80
|
+
end
|
81
|
+
|
82
|
+
#### The following methods handle arbitrary delegation to the underlying cluster object. ####
|
83
|
+
protected
|
84
|
+
|
85
|
+
# @private
|
86
|
+
def method_missing(method_name, *args, &block)
|
87
|
+
# If we get here, we don't have a method of our own. Forward the request to the delegate_cluster.
|
88
|
+
# If it returns itself, we will coerce the result to return our *self* instead.
|
89
|
+
|
90
|
+
result = @delegate_cluster.send(method_name, *args, &block)
|
91
|
+
(result == @delegate_cluster) ? self : result
|
92
|
+
end
|
93
|
+
|
94
|
+
# @private
|
95
|
+
def respond_to?(method, include_private = false)
|
96
|
+
super || @delegate_cluster.respond_to?(method, include_private)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|