dse-driver 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|