示例#1
0
        public async Task <IClusterNode> GetUnassignedNodeAsync(HostEndpoint endpoint)
        {
            var dnsResolver = ServiceProvider.GetRequiredService <IDnsResolver>();
            var ipAddress   = await dnsResolver.GetIpAddressAsync(endpoint.Host, CancellationToken).ConfigureAwait(false);

            return(Nodes.FirstOrDefault(
                       x => !x.IsAssigned && x.EndPoint.Address.Equals(ipAddress)));
        }
示例#2
0
        public void GetEndPoint_WithoutPort_ExpectedResult(string server, string expectedHost)
        {
            // Act

            var(hostName, port) = HostEndpoint.Parse(server);

            // Assert

            Assert.Equal(expectedHost, hostName);
            Assert.Null(port);
        }
示例#3
0
        public async Task <IClusterNode> CreateAndConnectAsync(HostEndpoint endPoint, CancellationToken cancellationToken = default)
        {
            var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(endPoint.Host, endPoint.Port.GetValueOrDefault(), cancellationToken).ConfigureAwait(false);

            var clusterNode = new ClusterNode(_clusterContext, _connectionPoolFactory, _logger,
                                              _transcoder, _circuitBreaker, _saslMechanismFactory, _redactor, ipEndPoint)
            {
                BootstrapEndpoint = endPoint
            };

            //ensure server calls are made to set the state
            await clusterNode.InitializeAsync().ConfigureAwait(false);

            return(clusterNode);
        }
        public async Task <IClusterNode> CreateAndConnectAsync(HostEndpoint endPoint, BucketType bucketType, NodeAdapter?nodeAdapter, CancellationToken cancellationToken = default)
        {
            var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(endPoint.Host, endPoint.Port.GetValueOrDefault(), cancellationToken).ConfigureAwait(false);

            //for recording k/v latencies per request
            var valueRecorder = _meter.ValueRecorder(OuterRequestSpans.ServiceSpan.Kv.Name);

            var clusterNode = new ClusterNode(_clusterContext, _connectionPoolFactory, _logger,
                                              _operationBuilderPool, _circuitBreaker, _saslMechanismFactory, _redactor, ipEndPoint, bucketType,
                                              nodeAdapter, _tracer, valueRecorder)
            {
                BootstrapEndpoint = endPoint
            };

            //ensure server calls are made to set the state
            await clusterNode.InitializeAsync().ConfigureAwait(false);

            return(clusterNode);
        }
示例#5
0
        public async Task ScopeAsync_Throws_NotSupportedException_When_Name_Is_Not_Default()
        {
            var localhost    = HostEndpoint.Parse("10.112.192.102:8091");
            var bucketConfig = ResourceHelper.ReadResource("mycache.json", InternalSerializationContext.Default.BucketConfig);

            bucketConfig.Nodes.RemoveAt(1);

            var mockClusterNode = new Mock <IClusterNode>();

            mockClusterNode.Setup(x => x.EndPoint).Returns(new HostEndpointWithPort("127.0.0.1", 8091));
            mockClusterNode.Setup(x => x.SelectBucketAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);

            var mockHttpClusterMap = new Mock <HttpClusterMapBase>();

            mockHttpClusterMap.Setup(x =>
                                     x.GetClusterMapAsync("default", localhost, CancellationToken.None)).
            Returns(Task.FromResult(bucketConfig));

            var bucket = CreateMemcachedBucket();
            await bucket.BootstrapAsync(mockClusterNode.Object).ConfigureAwait(false);

            Assert.Throws <NotSupportedException>(() => bucket.Scope("xxxx"));
        }
示例#6
0
        private async IAsyncEnumerable <IPEndPoint> GetIpEndPointsAsync(IEnumerable <string> serverList,
                                                                        [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            foreach (var server in serverList)
            {
                var(hostName, port) = HostEndpoint.Parse(server);
                if (port == null)
                {
                    // Should not happen with data from BucketConfig
                    ThrowHelper.ThrowInvalidOperationException("Server list is missing port numbers.");
                }

                var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(hostName, port.Value, cancellationToken)
                                 .ConfigureAwait(false);

                if (ipEndPoint == null)
                {
                    ThrowHelper.ThrowArgumentException($"Unable to resolve '{server}'.", nameof(serverList));
                }

                yield return(ipEndPoint);
            }
        }
 public Task <IClusterNode> CreateAndConnectAsync(HostEndpoint endPoint, BucketType bucketType, CancellationToken cancellationToken = default)
 {
     return(CreateAndConnectAsync(endPoint, bucketType, null, cancellationToken));
 }
示例#8
0
        public async Task BootstrapGlobalAsync()
        {
            if (ClusterOptions.ConnectionStringValue == null)
            {
                throw new InvalidOperationException("ConnectionString has not been set.");
            }

            if (ClusterOptions.ConnectionStringValue.IsValidDnsSrv())
            {
                try
                {
                    // Always try to use DNS SRV to bootstrap if connection string is valid
                    // It can be disabled by returning an empty URI list from IDnsResolver
                    var dnsResolver = ServiceProvider.GetRequiredService <IDnsResolver>();

                    var bootstrapUri = ClusterOptions.ConnectionStringValue.GetDnsBootStrapUri();
                    var servers      = (await dnsResolver.GetDnsSrvEntriesAsync(bootstrapUri, CancellationToken).ConfigureAwait(false)).ToList();
                    if (servers.Any())
                    {
                        _logger.LogInformation(
                            $"Successfully retrieved DNS SRV entries: [{_redactor.SystemData(string.Join(",", servers))}]");
                        ClusterOptions.ConnectionStringValue =
                            new ConnectionString(ClusterOptions.ConnectionStringValue, servers);
                    }
                }
                catch (Exception exception)
                {
                    _logger.LogInformation(exception, "Error trying to retrieve DNS SRV entries.");
                }
            }

            //Try to bootstrap each node in the servers list - either from DNS-SRV lookup or from client configuration
            foreach (var server in ClusterOptions.ConnectionStringValue.GetBootstrapEndpoints(ClusterOptions.EnableTls))
            {
                _logger.LogDebug("Bootstrapping with node {server}", server.Host);
                var node = await _clusterNodeFactory.
                           CreateAndConnectAsync(server, BucketType.Couchbase, CancellationToken).
                           ConfigureAwait(false);

                try
                {
                    GlobalConfig = await node.GetClusterMap().ConfigureAwait(false);
                }
                catch (CouchbaseException e)
                {
                    if (e.Context is KeyValueErrorContext ctx)
                    {
                        if (ctx.Status == ResponseStatus.BucketNotConnected)
                        {
                            AddNode(node); //GCCCP is not supported - pre-6.5 server fall back to CCCP like SDK 2
                            return;
                        }
                    }
                }

                try
                {
                    //Server is 6.5 and greater and supports GC3P so loop through the global config and
                    //create the nodes that are not associated with any buckets via Select Bucket.
                    GlobalConfig.IsGlobal          = true;
                    GlobalConfig.NetworkResolution = ClusterOptions.NetworkResolution;
                    foreach (var nodeAdapter in GlobalConfig.GetNodes()) //Initialize cluster nodes for global services
                    {
                        //log any alternate address mapping
                        _logger.LogInformation(nodeAdapter.ToString());

                        if (server.Host.Equals(nodeAdapter.Hostname)) //this is the bootstrap node so update
                        {
                            node.NodesAdapter   = nodeAdapter;
                            SupportsCollections = node.Supports(ServerFeatures.Collections);
                            AddNode(node);
                        }
                        else
                        {
                            var hostEndpoint = HostEndpoint.Create(nodeAdapter, ClusterOptions);
                            var newNode      = await _clusterNodeFactory
                                               .CreateAndConnectAsync(hostEndpoint, BucketType.Couchbase, nodeAdapter,
                                                                      CancellationToken).ConfigureAwait(false);

                            SupportsCollections = node.Supports(ServerFeatures.Collections);
                            AddNode(newNode);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.LogDebug("Attempted bootstrapping on endpoint {endpoint} has failed.", e, server);
                }
            }
        }
示例#9
0
 public IClusterNode GetUnassignedNode(HostEndpoint endpoint, BucketType bucketType)
 {
     return(Nodes.FirstOrDefault(
                x => !x.IsAssigned && x.BootstrapEndpoint.Equals(endpoint) && x.BucketType == bucketType));
 }
        public override async Task <BucketConfig> GetClusterMapAsync(string bucketName, HostEndpoint hostEndpoint,
                                                                     CancellationToken cancellationToken)
        {
            var uri = new UriBuilder
            {
                Scheme = _context.ClusterOptions.EffectiveEnableTls ? Uri.UriSchemeHttps : Uri.UriSchemeHttp,
                Host   = hostEndpoint.Host,
                Port   = _context.ClusterOptions.EffectiveEnableTls
                    ? _context.ClusterOptions.BootstrapHttpPortTls
                    : _context.ClusterOptions.BootstrapHttpPort,
                Path = Path + bucketName
            };

            using (var response = await _httpClient.GetAsync(uri.Uri, cancellationToken).ConfigureAwait(false))
            {
                response.EnsureSuccessStatusCode();
                var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                var bucketConfig = JsonConvert.DeserializeObject <BucketConfig>(json);
                bucketConfig.ReplacePlaceholderWithBootstrapHost(uri.Host);
                return(bucketConfig);
            }
        }
 public abstract Task <BucketConfig> GetClusterMapAsync(string bucketName, HostEndpoint hostEndpoint,
                                                        CancellationToken cancellationToken);
        public async Task <IConnection> CreateAndConnectAsync(IPEndPoint endPoint, HostEndpoint hostEndpoint,
                                                              CancellationToken cancellationToken = default)
        {
            var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                var connectTask = socket.ConnectAsync(endPoint);

                var whichTask = await Task
                                .WhenAny(connectTask, Task.Delay(_clusterOptions.KvConnectTimeout, cancellationToken))
                                .ConfigureAwait(false);

                if (whichTask != connectTask)
                {
                    // Was a timeout
                    const int connectionTimedOut = 10060;
                    throw new SocketException(connectionTimedOut);
                }
            }
            catch
            {
                socket.Dispose();
                throw;
            }

#if NETCOREAPP_GTE_3_0
            _multiplexLogger.LogDebug("Setting TCP Keep-Alives using SocketOptions - enable keep-alives {EnableTcpKeepAlives}, time {TcpKeepAliveTime}, interval {TcpKeepAliveInterval}.",
                                      _clusterOptions.EnableTcpKeepAlives, _clusterOptions.TcpKeepAliveTime, _clusterOptions.TcpKeepAliveInterval);

            if (!socket.TryEnableKeepAlives(_clusterOptions.EnableTcpKeepAlives,
                                            (int)_clusterOptions.TcpKeepAliveTime.TotalSeconds,
                                            (int)_clusterOptions.TcpKeepAliveInterval.TotalSeconds, out string setKeepAliveMessage)
                )
            {
                _multiplexLogger.LogWarning(setKeepAliveMessage);
            }
#else
            _multiplexLogger.LogDebug(
                "Setting TCP Keep-Alives using Socket.IOControl on {endpoint} - enable tcp keep-alives {EnableTcpKeepAlives}, time {TcpKeepAliveTime}, interval {TcpKeepAliveInterval}",
                endPoint, _clusterOptions.EnableTcpKeepAlives, _clusterOptions.TcpKeepAliveTime,
                _clusterOptions.TcpKeepAliveInterval);

            if (!socket.TrySetKeepAlives(_clusterOptions.EnableTcpKeepAlives,
                                         (uint)_clusterOptions.TcpKeepAliveTime.TotalMilliseconds,
                                         (uint)_clusterOptions.TcpKeepAliveInterval.TotalMilliseconds, out var setKeepAliveMessage)
                )
            {
                _multiplexLogger.LogWarning(setKeepAliveMessage);
            }
#endif

            if (_clusterOptions.EffectiveEnableTls)
            {
                var sslStream = new SslStream(new NetworkStream(socket, true), false,
                                              _clusterOptions.KvCertificateCallbackValidation);

                //Check if were using x509 auth, if so fetch the certificates
                X509Certificate2Collection?certs = null;
                if (_clusterOptions.X509CertificateFactory != null)
                {
                    certs = _clusterOptions.X509CertificateFactory.GetCertificates();
                    if (certs == null || certs.Count == 0)
                    {
                        throw new AuthenticationException(
                                  "No certificates matching the X509FindType and specified FindValue were found in the Certificate Store.");
                    }

                    if (_sslLogger.IsEnabled(LogLevel.Debug))
                    {
                        foreach (var cert in certs)
                        {
                            _sslLogger.LogDebug("Cert sent {cert.FriendlyName} - Thumbprint {cert.Thumbprint}",
                                                cert.FriendlyName, cert.Thumbprint);
                        }

                        _sslLogger.LogDebug("Sending {certs.Count} certificates to the server.", certs.Count);
                    }
                }

                //The endpoint we are connecting to
                var targetHost = _clusterOptions.ForceIpAsTargetHost
                    ? endPoint.Address.ToString()
                    : hostEndpoint.Host;

                //create the sslstream with appropriate authentication
                await sslStream.AuthenticateAsClientAsync(targetHost, certs,
                                                          SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
                                                          _clusterOptions.EnableCertificateRevocation)
                .ConfigureAwait(false);

                var isSecure = sslStream.IsAuthenticated && sslStream.IsSigned && sslStream.IsEncrypted;
                _sslLogger.LogDebug("IsAuthenticated {0} on {1}", sslStream.IsAuthenticated, targetHost);
                _sslLogger.LogDebug("IsSigned {0} on {1}", sslStream.IsSigned, targetHost);
                _sslLogger.LogDebug("IsEncrypted {0} on {1}", sslStream.IsEncrypted, targetHost);

                //punt if we cannot successfully authenticate
                if (!isSecure)
                {
                    throw new AuthenticationException($"The SSL/TLS connection could not be authenticated on [{targetHost}].");
                }

                return(new SslConnection(sslStream, socket.LocalEndPoint, socket.RemoteEndPoint,
                                         _sslLogger, _multiplexLogger));
            }

            return(new MultiplexingConnection(socket, _multiplexLogger));
        }
示例#13
0
        public async Task BootstrapGlobalAsync()
        {
            if (ClusterOptions.ConnectionStringValue == null)
            {
                throw new InvalidOperationException("ConnectionString has not been set.");
            }

            if (ClusterOptions.ConnectionStringValue.IsValidDnsSrv())
            {
                try
                {
                    // Always try to use DNS SRV to bootstrap if connection string is valid
                    // It can be disabled by returning an empty URI list from IDnsResolver
                    var dnsResolver = ServiceProvider.GetRequiredService <IDnsResolver>();

                    var bootstrapUri = ClusterOptions.ConnectionStringValue.GetDnsBootStrapUri();
                    var servers      = (await dnsResolver.GetDnsSrvEntriesAsync(bootstrapUri, CancellationToken).ConfigureAwait(false)).ToList();
                    if (servers.Any())
                    {
                        _logger.LogInformation(
                            $"Successfully retrieved DNS SRV entries: [{_redactor.SystemData(string.Join(",", servers))}]");
                        ClusterOptions.ConnectionStringValue =
                            new ConnectionString(ClusterOptions.ConnectionStringValue, servers);
                    }
                }
                catch (Exception exception)
                {
                    _logger.LogInformation(exception, "Error trying to retrieve DNS SRV entries.");
                }
            }

            foreach (var server in ClusterOptions.ConnectionStringValue.GetBootstrapEndpoints(ClusterOptions.EnableTls))
            {
                var node = await _clusterNodeFactory.CreateAndConnectAsync(server, CancellationToken).ConfigureAwait(false);

                GlobalConfig = await node.GetClusterMap().ConfigureAwait(false);

                if (GlobalConfig == null)
                {
                    AddNode(node); //GCCCP is not supported - pre-6.5 server fall back to CCCP like SDK 2
                }
                else
                {
                    GlobalConfig.IsGlobal = true;
                    foreach (var nodeAdapter in GlobalConfig.GetNodes()) //Initialize cluster nodes for global services
                    {
                        if (server.Host.Equals(nodeAdapter.Hostname))    //this is the bootstrap node so update
                        {
                            node.NodesAdapter   = nodeAdapter;
                            SupportsCollections = node.Supports(ServerFeatures.Collections);
                            AddNode(node);
                        }
                        else
                        {
                            var hostEndpoint = HostEndpoint.Create(nodeAdapter, ClusterOptions);
                            var newNode      = await _clusterNodeFactory.CreateAndConnectAsync(hostEndpoint, CancellationToken).ConfigureAwait(false);

                            newNode.NodesAdapter = nodeAdapter;
                            SupportsCollections  = node.Supports(ServerFeatures.Collections);
                            AddNode(newNode);
                        }
                    }
                }
            }
        }
 public Task <IConnection> CreateAndConnectAsync(IPEndPoint endPoint, HostEndpoint hostEndpoint, CancellationToken cancellationToken = default)
 {
     return(Task.FromResult <IConnection>(new MockConnection()));
 }